#!\usr\bin\perl # Written by Richard Graves # # # ARGV[0] = Device # ARGV[1] = Command list file # ARGV[2] = Username # ARGV[3] = Password # ARGV[4] = Enable Password # ARGV[5] = Output Filename # # Please remember that you MUST use the 'wr mem' and 'wr net' command # from the command file. These commands will not run automatically!!! #-------------------------------------------------------------------------- use strict; use Net::SSH::Perl; use Net::SSH::Perl::Constants qw( :msg ); use strict; no warnings 'uninitialized'; my ($session, $host, $file, $SSHUSER, $SSHPWD, $ENBPWD, $OutputFile); $host=$ARGV[0]; $file=$ARGV[1]; $SSHUSER=$ARGV[2]; $SSHPWD=$ARGV[3]; $ENBPWD=$ARGV[4]; $OutputFile=$ARGV[5]; print ("\nDevice: $host"); #let me know what device I am working on #-------------------------------------------------------------------------------------------- my (@CONFIGVAR, $CONFIGVAR); my ($cntr, $line); if (-e $file && -r $file) #if file exists and is readable { open(IN, "$file"); #open the file using the IN filehandle } while($line=) #while data is coming in from file { unless($line=~ m/^\!+/) #unless the line starts with # do the following.. { $cntr++; if ($cntr > 20) { die "Please limit number of commands to 20!"; } else { push (@CONFIGVAR, $line); } } } close(IN); #close the filehandle #close the filehandle #-------------------------------------------------------------------------------------------- my ($Site, $Region, %devices); open(OUTPUT, ">>$OutputFile"); use Net::Telnet::Cisco; #use the telnet::cisco module if ($host =~ m/\d+\.(\d+)\.(\d+)\.\d+/ ) #break out region and site subnets { $Region = $1; $Site = $2; } print (OUTPUT "\n$host"); #-------------------------------------------------------------------------------------------- $|++; use constant SKIP_PROMPT => 1; # pix prints login prompt twice, skip first 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 $cfg_prompt = qr/(?:[a-zA-Z0-9]+\(config\)#)\s*/; # alphanumeric followed by '(config)#' 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($SSHUSER,$SSHPWD); 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("$ENBPWD\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('' . "\n"); $packet->send; $prompt_cnt++; } elsif ( $str =~ /$enb_prompt$/ && $prompt_cnt == 1 ) { # go into config mode my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA); $packet->put_str('conf t' . "\n"); $packet->send; $prompt_cnt++; } elsif ( $str =~ /$cfg_prompt$/ && $prompt_cnt == 2) { # issue desired command in config mode my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA); $packet->put_str(join ("", @CONFIGVAR) . "\n"); $packet->send; $prompt_cnt++; } elsif ( $str =~ /$cfg_prompt$/ && $prompt_cnt == 3 ) { # exit config mode my $packet = $ssh->packet_start(SSH_CMSG_STDIN_DATA); $packet->put_str('exit' . "\n"); $packet->send; $prompt_cnt++; $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 talking to $host.\n" : "Unexpected eval err: $@.\n" ) : undef; print (OUTPUT "\tSuccessful"); #print to file print ("\tSuccessful\n"); #print to screen close(OUTPUT); =head1 NAME Combined Cisco Script =head1 DESCRIPTION This script is used to issue config commands to a cisco device using either telnet or SSHv1. This is the SSH script, the other two scripts CCS_sub_telnet.pl and CCS_main.pl are also required =head1 README =head1 PREREQUISITES This script requires: Perl 5.8 or higher Net::SSH::Perl Net::SSH::Perl::Constants Net::Telnet Net::Telnet::Cisco =head1 COREQUISITES CCS_sub_telnet.pl CCS_main.pl =pod OSNAMES any =pod SCRIPT CATEGORIES Networking =cut