AIX

AIX

Connect with fellow AIX users and experts to gain knowledge, share insights, and solve problems.

 View Only
Expand all | Collapse all

bash script - exit from telnet in 'trying' state

  • 1.  bash script - exit from telnet in 'trying' state

    Posted Tue September 15, 2015 05:22 AM

    Originally posted by: libeccio


    Hallo all
    I'm writing a little shellscript in aix 5.3 in order to test connection (via telnet) from a client to a specific server (ip-port). I'm using the sleep|telnet combination. All works great if connection is open.. But if telnet connection are in trying state (that is, fw is blocking it) ... It doesn't exit anymore, and all the rest of the script remains un-executed. How can I send a break signal from a telnet prompt (in "trying" status), via shell-script? Thanks all For Your support



  • 2.  Re: bash script - exit from telnet in 'trying' state

    Posted Tue September 15, 2015 02:30 PM

    Originally posted by: GarlandJoseph


    http://www.unix.com/linux/126657-telnet-timeout.html



  • 3.  Re: bash script - exit from telnet in 'trying' state

    Posted Tue September 15, 2015 02:49 PM

    Originally posted by: libeccio


    Thanks for your reply,

    unfortunately I don't have 'expect' command on my aix 5.3



  • 4.  Re: bash script - exit from telnet in 'trying' state

    Posted Thu September 17, 2015 07:01 AM

    Originally posted by: Wouter Liefting


    If all you want is to test whether the port is open, closed or filtered, you don't need to use telnet per se. Anything that opens a TCP connection would do.

    As you don't seem to have expect, I'm assuming you don't have the ability to install it, or anything else. So you will have to misuse anything else that is on your system, creates a TCP connection and handles timeouts decently. And feeds the result back via an exit code. Just a few suggestions:

    - Write your own C, perl or python program. Probably less than three lines of code.

    - Use nmap

    - Use SSH - it's got loads more options to handle timeouts than telnet

    - Use netcat (nc), ttcp or stunnel

     

    perl is installed on AIX by default and is probably your best bet. Here's a page that seems to do exactly what you want to achieve:

    http://www.binarytides.com/perl-port-scanner-code/

    The code on that page actually scans a range of ports. So in your case, if you just want to check one port, you only need to use the inner loop.



  • 5.  Re: bash script - exit from telnet in 'trying' state

    Posted Fri September 18, 2015 12:20 PM

    Originally posted by: libeccio


    Thans for your reply.. since I'm not a Perl-pro, I proceeded with bash script... I found this solution.. (it worked for me.. although it isn't so 'strong').. Any comments will be appreciated. Thanks for your help.

     

    #!/bin/ksh
    touch myips.txt myports.txt result.txt
    rm myips.txt myports.txt result.txt

    read ip1?"insert dest ip: "
    read p1?"insert first port of the range (or the unique one): "
    read pn?"insert last port of the range (or the unique one): "

    echo $ip1 >> myips.txt

    echo $p1 $pn | awk '{ for (i=$1;i<=$2;i++) { print i} }'>> myports.txt

    for ip in $('cat' myips.txt)

    do
    for port in $('cat' myports.txt)
    do
    echo ""
    echo ""
    echo "telnet $ip $port" >> result.txt
    sleep 1 | telnet $ip $port >> result.txt 2>&1 &
    echo "Telnet in progress..saving results to "result.txt""

    PID=$!
    sleep 2
    if [ $(ps -efa | grep $PID |grep -v grep|grep -v defunct| wc -l) -eq 1 ]; then

    TMOUT_CONN=$(ps -efa | grep $PID |grep -v grep|grep -v defunct| awk '{print $9,$10}')
    kill -9 $PID
    echo "PID $PID still UP after 2 seconds, connection to $TMOUT_CONN is in Trying state.\nSubprocess Killed"

    fi
    done
    done



  • 6.  Re: bash script - exit from telnet in 'trying' state

    Posted Fri September 18, 2015 01:23 PM

    Originally posted by: Wouter Liefting


    That is a very convoluted way of doing things. Furthermore, I can point out at least one fundamental logic flaw in your code, plus two fundamental scripting errors in that code, plus several efficiency improvements. I would not do it that way at all.

    Like I said, it's three lines of code in perl. I used a few more for readability. Just dump the code below in a file and make it executable. (Do a "which perl" first to find the location of the perl binary. It might not be in /usr/bin, so you might need to modify the first line.)

     

    #!/usr/bin/perl

    # TCP Port scanner

    # Usage: portscan <host> <port>

    # Return code zero means port is open, one means closed or filtered.

     

    use IO::Socket;

     

    # flush the print buffer immediately
    $| = 1;

     

    # Get command line parameters

    $target = shift;
    $port = shift;

     

    # Connect to host/port
    $socket = IO::Socket::INET->new(PeerAddr => $target , PeerPort => $port , Proto => 'tcp' , Timeout => 2);

     

    # Check connection
    if( $socket )
    {
         print "Port $port is open.\n" ;
         $socket->close();
         exit( 0 );
    }
    else
    {
        print "Port $port is closed or filtered.\n" ;
        exit( 1 );
    }

    # Should never reach this...
    exit( 2 );

     

     

    If necessary, you can wrap this in a shell script if you need to test multiple IPs or ports. Or you can call this script first to check the port is open, and only then continue with the rest of your script.

     

    Oh, and remember that connections that are opened and then immediately closed, are considered suspect behavior for things like IDSs and logfile analyzers. 



  • 7.  Re: bash script - exit from telnet in 'trying' state

    Posted Mon September 21, 2015 08:20 AM

    Originally posted by: libeccio


    Thank you very much Wouter, your script works perfectly.. (even if my goal is to locate three types of behaviour: open // closed by fw // open but service port down) ..

    Maybe i should examine in depth Perl, whereas it is so powerful.

    Please Could you tell me about errors on the bash script (Obviously I'm a beginner).

    Thank a lot for your time, you had a part in the solution of my issue.



  • 8.  Re: bash script - exit from telnet in 'trying' state

    Posted Mon September 21, 2015 10:39 AM

    Originally posted by: Wouter Liefting


    You can always look at the error value ($! in perl) to see what's causing the error. Here's the modified script that looks at the two errors you're interested in, and exits accordingly.

     

    #!/usr/bin/perl

    # TCP Port scanner

    use IO::Socket;
    use Errno;

    # flush the print buffer immediately
    $| = 1;

    $target = shift;
    $port = shift;

    #Connect to port number
    $socket = IO::Socket::INET->new(PeerAddr => $target , PeerPort => $port , Proto => 'tcp' , Timeout => 1);

    #Check connection
    if( $socket )
    {
         print "Port $port is open.\n" ;
         $socket->close();
         exit( 0 );
    }
    else
    {
        if( $! == Errno::ETIMEDOUT )
        {
            print "Port $port is filtered (timeout).\n" ;
            exit( 1 );
        } elsif ( $! == Errno::ECONNREFUSED ) {
            print "Port $port is closed (connection refused).\n" ;
            exit( 2 );
        } else {
            print "Unknown error: $!\n";
            exit( 3 );
        }
    }

    # Should never reach this...
    exit( 4 );

     

    Obviously there are more errors that may be generated. You may also want to check for "network unreachable" (Errno::ENETUNREACH), for instance. This is triggered if any intermediate gateway/router doesn't know how to reach the target network.

    Note that, in perl, $! returns a number if evaluated in a numeric context (as in $! == Errno::ETIMEDOUT), and returns a string if evaluated in a string context (as in print "Unknown error: $!\n").



  • 9.  Re: bash script - exit from telnet in 'trying' state

    Posted Mon September 21, 2015 11:54 AM

    Originally posted by: libeccio


    Thank you, very useful post !

     



  • 10.  Re: bash script - exit from telnet in 'trying' state

    Posted Mon September 21, 2015 11:32 AM

    Originally posted by: Wouter Liefting


    As far as the errors in your script are concerned, here's a list of things that I stumbled upon.

     

    #!/bin/ksh

    ^^^^ That's actually very good practice. Particularly since you're using the "print" statement later on, which is exclusive to ksh.


    touch myips.txt myports.txt result.txt
    rm myips.txt myports.txt result.txt

    ^^^^ Why touch the files and then delete them? If you want to make sure they're writable, you need some error handling as well. I always declare a function die():

    die()

    {

      print "$@"

      exit 1

    }

     

    Error handling then becomes:

    touch myips.txt || die ("Cannot create myips.txt")

     

    Furthermore, it's good practice to put the filenames in variables, and use these variables throughout the script. Much easier if you need to change the filename or directory later on. And it's good practice to create them in /tmp instead of the current working directory, give them a name that's unique even if two instances of your script run in parallel (use $$ as part of the filename, or use mktemp), and delete them afterwards. So your code becomes:

    myips=/tmp/myips.txt.$$

    [ -f "$myips" ] && die "File $myips already exists"

    touch "$myips" || die "Cannot create $myips"

    ...

    echo "bla bla bla" >> "$myips"

    ...

    rm -f "$myips" || die "Cannot delete $myips"

     

    read ip1?"insert dest ip: "
    read p1?"insert first port of the range (or the unique one): "
    read pn?"insert last port of the range (or the unique one): "

    ^^^ Why read from the command line? Why not use the script arguments $1, $2, $3 and so forth. Do need to add a proper usage statement though, in case the parameters are not what you expected.

     

    echo $ip1 >> myips.txt

    echo $p1 $pn | awk '{ for (i=$1;i<=$2;i++) { print i} }'>> myports.txt

    for ip in $('cat' myips.txt)

    do
    for port in $('cat' myports.txt)

    ^^^^ First, it doesn't make sense to enclose cat in single quotes. They don't add anything here. However, it is good practice to either set the $PATH variable yourself to a sensible value, or hard-code the path with the command (/bin/cat). Now you're completely depending on the user setting an appropriate $PATH variable.

    Furthermore, the use of these temporary files is not needed at all. You could have done this as well:

    for ip in $ip1

    do

      for port in $( echo "$p1" "$pn" | awk '{ for (i=$1;i<=$2;i++) { print i} }' )

      do 

      .... 

      done

    done

    And I personally prefer to use the tool "seq" for this instead of awk, but seq might not be available on AIX (can't check right now). Still, you could have avoided the convoluted use of awk with a while loop:

    for ip in $ip1

    do

    curport="$p1"

    while [ "$curport" -lt "$pn" ]

    do

     ....

     curport=$(( "$curport" + 1 ))

    done

    done

    (Also note that the $ip1 is deliberately not enclosed in double quotes. This is because this shell variable might contain multiple IP addresses, separated by spaces, and I want to interpret this as multiple IP addresses, not as a single value. It's one of the very few exceptions to the double-quotes rule.)


    do
    echo ""
    echo ""
    echo "telnet $ip $port" >> result.txt

    ^^^ You're displaying good practice here. Anytime you refer to a shell variable, you do so within double quotes. That saves the structure, even if the shell variable contains spaces. Keep it up.

     

    sleep 1 | telnet $ip $port >> result.txt 2>&1 &

    ^^^ Well, never mind. You forgot the double quotes here already... telnet "$ip" "$port" would've been better although it doesn't matter in this particular case. But if you start doing the same thing with filenames that possibly contain spaces (the dreaded My Documents for instance) then you're screwed.


    echo "Telnet in progress..saving results to "result.txt""

    ^^^ Lucky for you this did not generate a syntax error. But the quotes around result.txt are not printed, and in other situations this might actually have caused errors. Next time, try this instead:

    echo "Telnet in progress... Saving results to \"result.txt\"."

     

    PID=$!

    ^^^^If you do anything with variables $!, $? and such, it's good practice to recall and store them straightaway, before running any other command which could possibly alter their values. So swap the PID=$! and echo lines.

    Furthermore, user shell variables are normally written in lowercase, to avoid confusion/conflict with system shell variables which are always in uppercase.

     

    sleep 2
    if [ $(ps -efa | grep $PID |grep -v grep|grep -v defunct| wc -l) -eq 1 ]; then

    TMOUT_CONN=$(ps -efa | grep $PID |grep -v grep|grep -v defunct| awk '{print $9,$10}')

    ^^^^ Very, very inefficient. You call ps twice and grep six times. All this can be done in one line:

    TMOUT_CONN=$(ps -efa | awk -v pid=$PID '$2 == pid {print $9 $10 }')

    The "-v pid=$PID" assigns the awk variable pid the value of shell variable PID. From then one you can use the awk variable pid inside the single quotes. Otherwise you'd have to use the shell variable $PID inside the awk code block, but that's quoted with single quotes so shell variable expansion doesn't work. You can circumvent that, but it makes for very messy code. This is much cleaner.

    The '$2 == pid {print $9 $10}' block means: evaluate each line. If the second column equals the pid variable, then print column 9 and 10. As the second column from ps -efa contains the pid, you can be sure to match the correct PID. You don't need to filter out the accidental inclusion of the "grep $PID" command for instance.

     

     

    kill -9 $PID

    ^^^ Normally not a good idea to kill something with a -9 straight away. Better to do a -15 first, then wait a few seconds, then a -9. But I can see the logic here.


    echo "PID $PID still UP after 2 seconds, connection to $TMOUT_CONN is in Trying state.\nSubprocess Killed"

    fi
    done
    done

     

    The logic error here is that the script will only detect a filtered port (timeout). It doesn't do anything with the exit value of telnet, which would possibly give you enough information to distinguish between an open and a closed port. To retrieve the return code of telnet, you'd have to insert a 'wait' statement somewhere along the line.

    But having said that, I don't think telnet distinguishes between the three situation (port was open but the connection was closed because stdin closed, port was filtered leading to a timeout and telnet was killed with a -9 signal, port was closed and telnet exited by itself). In fact, with a kill -9 telnet would not be able to leave a sensible exit code in any case. So I would not build my script around telnet in any case.



  • 11.  Re: bash script - exit from telnet in 'trying' state

    Posted Tue September 22, 2015 04:08 AM

    Originally posted by: libeccio


    Thanks ! A very precious post :) ... I'll try to take all your advices .. :)  Hope to read you again. Bye, Luigi