kylet has asked for the wisdom of the Perl Monks concerning the following question:

Hello all, I recently stumbled upon this Perl script: http://forums.cacti.net/about14410.html It is designed to connect to a Cisco PIX firewall via telnet, execute a show command, and then count the number of lines in that output that contain the word 'authenticated' I gave it a whirl and entered in the parameters (IP and the 2 passwords). I even broke out wireshark to see the telnet connection and the commands getting sent. It appears that Perl successfully authenticates with the PIX, but then I'm unsure whether it gets any further. The code for this script is:
#!/usr/bin/perl use Getopt::Std; # So we can do the processing of the command line opt +ions use IO::Socket; # For the connection $port = '23'; #telnet port $timeout=20; #connection timeout # Process the command line options die "Usage: $0 -r <router> -u <username> -p <password> -e <enable pass +word>\n" if (@ARGV < 6); exit if (!getopts('r:u:p:e:')); $username=$opt_u; $password=$opt_p; $enpassword=$opt_e; $router=$opt_r; main(); sub main(){ $i=0; # create a tcp connection to the specified host and port $handle = IO::Socket::INET->new(Proto => "tcp", PeerAddr => $router, PeerPort => $port, Timeout => $timeout) or return (print "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!\nCan't connect to port $port on $router\n!!!!!!!!!!!!!!!!!!!!!!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); # split the program into two processes, identical twins die "can't fork: $!" unless defined($childpid = fork()); # the if{} block runs only in the parent process if ($childpid) { # copy the socket to array while (defined ($line = <$handle>)) { @strings[$i] = $line; $i++; } kill("TERM", $childpid); } # the else{} block runs only in the child process else { print $handle $username."\n" if $username; # Use a use +rname only if there is one; print $handle $password."\n"; print $handle "enable\n"; print $handle $enpassword."\n"; print $handle "sh uauth\n"; print $handle "exit\n"; close ($handle); exit; } #calculate the connected users $i=0; { foreach (@strings) {$i++ if /authenticated/; } print $i; } }
The goal is to have a value returned which is equal to the amount of authenticated users (indicated by the amount of lines in the 'show uauth' command. Is there any glaring errors which may be stopping this script from completing successfully? I always seem to get a '0' returned, but I believe that is just the detault. Any help would be a huge help. Thanks Monks. Regards, Kyle
  • Comment on Cisco PIX show command via telnet - unable to retrieve correct value
  • Download Code

Replies are listed 'Best First'.
Re: Cisco PIX show command via telnet - unable to retrieve correct value
by hippo (Archbishop) on Mar 06, 2013 at 23:23 UTC

    I have two simple suggestions.

    1. Why not put a debugging statement inside the while loop which sets @strings[$i]? If you add a simple print $line; in there it will give you a much better idea of what your script is receiving back from the router. This may or may not be different from what wireshark is telling you that the router is sending back.
    2. Your script has no use strict; and does not have warnings enabled. As a consequence you may be accidentally setting or not using some of the global variables.

    Hopefully use of these two modifications will shine a light on what's actually happening.

      Thanks for the reponse Hippo. I added in the 'print $line' statement and now the script returns:
       ¹&#9829; ¹&#9786; ¹&#9829; ¹&#9786; User Access Verification Password: Password: Password: 0
      I really am completely new to Perl so I think I need to go away and do my homework. Any other advise would be great though. Regards, Kyle
Re: Cisco PIX show command via telnet - unable to retrieve correct value
by kcott (Archbishop) on Mar 08, 2013 at 01:43 UTC

    G'day kylet,

    "The goal is to have a value returned which is equal to the amount of authenticated users ..."

    The first thing you should do is add strict and warnings to the start of your script. If you don't understand the messages they're outputting, also use diagnostics. Your script should start like this:

    #!/usr/bin/perl use strict; use warnings; #use diagnostics; # optional use Getopt::Std; ...

    Next, you should declare your variables. In most cases, my should be fine.

    @strings[$i] (in @strings[$i] = $line;) is an array slice of only one element - almost certainly not what you want here! I'd recommend using push. I'd also recommend a more meaningful variable name.

    For counting the lines containing the string "authenticated", you can simply use grep. However, be aware that the regexp /authenticated/ matches the strings: "authenticated", "unauthenticated", "not authenticated" and so on - you may want to be a bit more specific with what exactly you're matching.

    Here's a skeleton example of the type of code you might want to use:

    $ perl -Mstrict -Mwarnings -E ' my @in_strings; while (<>) { push @in_strings, $_; } my $count = grep /authenticated/ => @in_strings; say "count = $count"; ' qwerty asdfgh zxcvbn authenticated unauthenticated not authenticated count = 3

    -- Ken