Firewall Wizards mailing list archives

pulling configs from pixes over ssh script


From: Vladimir Parkhaev <vladimir () arobas net>
Date: Wed, 28 May 2003 09:28:55 -0400

Well, I see that a lot of people out there still manage their firewall 
via telnet.  It is a no-no in my books but not all products out there 
have decent SSH daemons... Cisco PIX has one (SSH1), but automating 
tasks like pulling configs or getting failover status seemed still 
impossible.

Being a perl dude, I tried Net::SSH::Perl module but 
'perldoc Net::SSH::Perl' said:

"NOTE: the SSH-1 protocol does not support running multiple
       commands per connection, unless those commands are chained
       together so that the remote shell can evaluate them.
       Because of this, a new socket connection is created each
       time you call cmd, and disposed of afterwords."

Basically you cannot go into enable mode - you get disconnected.

I knew there had to be a (at least one) way  to do it :) And there is!
I was able to use this method with both Cisco PIXes and Routers.
Anyway to make a long story short, I just want to share my code.
You can adapt it to your needs if you are familiar with basics
of programming...



#!/usr/local/bin/perl -w
# This script pulls config from Cisco PIX device over SSH1.
# Written by Vladimir Parkhaev
# This code is free as a bird.
# If you have any questions run:
# perl -e 'print scalar reverse "ten.sabora\@rimidalv"' to get my email.
# Special mention to Benjamin::Trott- Net::SSH::Perl and Net::SFTP rock!
#
# Steps:
# 1. login
# 2. go to enable mode ('en')
# 3. execute 'no pager' to disable paging
# 4. execute 'show conf'
# 5. read the config
# 6. logout
# 7. deal with config
# Looks like config arrives as one line at the time
#
$|++;
use strict;
use Net::SSH::Perl;
use Net::SSH::Perl::Constants qw( :msg );
use constant SKIP_PROMPT => 1;   # pix prints login prompt twice, skip first 

my $host       = shift || die "Usage: $0 pix_name\n";
my $time2login = 10;
my $time2run   = 20;

# modify these in case of prompt (hostname) changes
# assuming alphanumeric characters only:
# [a-zA-Z0-9] is actually \w, but some hosts have '_' or '-' in their names
my $enb_prompt  = qr/(?:[a-zA-Z0-9]+#)\s*/;  # alphanumeric followed by '#'
my $reg_prompt  = qr/(?:[a-zA-Z0-9]+>)\s*/;  # alphanumeric followed by '>'
my $pass_prompt = qr/Password:\s*/;

my ($prompt_cnt,$save,$done)  = (0,0,0);
my ($ssh, @config);

# login on the device
eval {
   local $SIG{'ALRM'} = sub { die 'TimedouT' };
   alarm $time2login;
   $ssh = Net::SSH::Perl->new($host, protocol=>1, cipher=>'DES', port=>22);
   $ssh->login('pix','PASSWD_HERE');
   alarm 0;
};

($@)? ( die '[',scalar localtime,'] ', ($@ =~ /TimedouT/)? 
                                       "Takes too long to login on $host.\n" :
                                       "Unexpected eval err: $@.\n" 
      ) : undef;


# set up handler and intercept everything that goes to STDOUT

$ssh->register_handler(SSH_SMSG_STDOUT_DATA, sub {
   my($ssh, $packet) = @_;
   my $str = $packet->get_str;

   if ( $save )  {                       # reading config 

      if ( $str =~ /$enb_prompt$/ ) {    # last line of the config + prompt
         my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA);
         $packet->put_str('exit ' . "\n");
         $packet->send;
         $done++;
      }

      $str =~ s/\cM//g;
      chomp $str;
       
      # skip echo of the command and logout sequence
      push @config, $str unless ( $done        || $str =~ /^(\w|\s)$/ || 
                                  $str =~ /^:/ || $str eq '' );
    }
    else {                             # login part
       if ($str =~ /$reg_prompt$/)  {  # go to enable mode
          $prompt_cnt++;               # pix prints login prompt twice, remember
          return unless $prompt_cnt > SKIP_PROMPT;
          my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA);
          $packet->put_str('enable' . "\n");
          $packet->send;
          $prompt_cnt = 0;             # will resuse it in enable mode
       }
       elsif ( $str =~ /$pass_prompt$/ ) {    
          # going into enable mode....
          my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA);
          $packet->put_str("ENABLED PWD HERE\n");
          $packet->send;
       }
       elsif ( $str =~ /$enb_prompt$/ && !$prompt_cnt ) { 
          # exec first command in enable mode
          my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA);
          $packet->put_str('no pager' . "\n");
          $packet->send;
          $prompt_cnt++;
       }
       elsif ( $str =~ /$enb_prompt$/ && $prompt_cnt ) {  
          # exec second command in enable mode, ready to rock
          my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA);
          $packet->put_str('show conf' . "\n");
          $packet->send;
          $save++;
       }
       else { 
          # Uncomment this for debug purposes
          # print "Useless data: $str\n";
       }
   }

});

eval {
   local $SIG{'ALRM'} = sub { die 'TimedouT' };
   alarm $time2run;
   $ssh->cmd('');              # thaaaat's right, nothing at all
   alarm 0;
};

($@)? ( die '[',scalar localtime,'] ', ($@ =~ /TimedouT/)? 
                                       "Timed out while pulling from $host.\n" :
                                       "Unexpected eval err: $@.\n" 
      ) : undef;

pop   @config if $config[-1] =~ /^Cryptochecksum/;   # who needs it?
shift @config if $config[0]  =~ /^PIX/;              # and version too....

# at this point you have config in @config 
# do whatever you need to do with it
print join "\n", @config, '';

__END__

-- 
.signature: No such file or directory
_______________________________________________
firewall-wizards mailing list
firewall-wizards () honor icsalabs com
http://honor.icsalabs.com/mailman/listinfo/firewall-wizards


Current thread: