Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| #! @PERLV_PATH@ | |
| ## | |
| ## $Id: rancid.in,v 1.193 2005/08/14 22:29:29 heas Exp $ | |
| ## | |
| ## @PACKAGE@ @VERSION@ | |
| ## Copyright (C) 1997-2004 by Terrapin Communications, Inc. | |
| ## All rights reserved. | |
| ## | |
| ## This software may be freely copied, modified and redistributed | |
| ## without fee for non-commerical purposes provided that this license | |
| ## remains intact and unmodified with any RANCID distribution. | |
| ## | |
| ## There is no warranty or other guarantee of fitness of this software. | |
| ## It is provided solely "as is". The author(s) disclaim(s) all | |
| ## responsibility and liability with respect to this software's usage | |
| ## or its effect upon hardware, computer systems, other software, or | |
| ## anything else. | |
| ## | |
| ## Except where noted otherwise, rancid was written by and is maintained by | |
| ## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. | |
| ## | |
| # | |
| # RANCID - Really Awesome New Cisco confIg Differ | |
| # | |
| # Dell mods by: Jeremy Singletary | |
| # drancid - Dell power connect plugin for rancid | |
| # | |
| # usage: drancid [-dV] [-l] [-f filename | $host] | |
| # | |
| use Getopt::Std; | |
| getopts('dflV'); | |
| if ($opt_V) { | |
| print "@PACKAGE@ @VERSION@\n"; | |
| exit(0); | |
| } | |
| $log = $opt_l; | |
| $debug = $opt_d; | |
| $file = $opt_f; | |
| $host = $ARGV[0]; | |
| $clean_run = 0; | |
| $found_end = 0; | |
| $found_env = 0; | |
| $found_diag = 0; | |
| $timeo = 90; # dlogin timeout in seconds | |
| my(@commandtable, %commands, @commands);# command lists | |
| my($filter_commstr); # SNMP community string filtering | |
| my(%filter_pwds); # password filtering mode | |
| # This routine is used to print out the router configuration | |
| sub ProcessHistory { | |
| my($new_hist_tag,$new_command,$command_string,@string) = (@_); | |
| if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) | |
| && scalar(%history)) { | |
| print eval "$command \%history"; | |
| undef %history; | |
| } | |
| if (($new_hist_tag) && ($new_command) && ($command_string)) { | |
| if ($history{$command_string}) { | |
| $history{$command_string} = "$history{$command_string}@string"; | |
| } else { | |
| $history{$command_string} = "@string"; | |
| } | |
| } elsif (($new_hist_tag) && ($new_command)) { | |
| $history{++$#history} = "@string"; | |
| } else { | |
| print "@string"; | |
| } | |
| $hist_tag = $new_hist_tag; | |
| $command = $new_command; | |
| 1; | |
| } | |
| sub numerically { $a <=> $b; } | |
| # This is a sort routine that will sort numerically on the | |
| # keys of a hash as if it were a normal array. | |
| sub keynsort { | |
| local(%lines) = @_; | |
| local($i) = 0; | |
| local(@sorted_lines); | |
| foreach $key (sort numerically keys(%lines)) { | |
| $sorted_lines[$i] = $lines{$key}; | |
| $i++; | |
| } | |
| @sorted_lines; | |
| } | |
| # This is a sort routine that will sort on the | |
| # keys of a hash as if it were a normal array. | |
| sub keysort { | |
| local(%lines) = @_; | |
| local($i) = 0; | |
| local(@sorted_lines); | |
| foreach $key (sort keys(%lines)) { | |
| $sorted_lines[$i] = $lines{$key}; | |
| $i++; | |
| } | |
| @sorted_lines; | |
| } | |
| # This is a sort routine that will sort on the | |
| # values of a hash as if it were a normal array. | |
| sub valsort{ | |
| local(%lines) = @_; | |
| local($i) = 0; | |
| local(@sorted_lines); | |
| foreach $key (sort values %lines) { | |
| $sorted_lines[$i] = $key; | |
| $i++; | |
| } | |
| @sorted_lines; | |
| } | |
| # This is a numerical sort routine (ascending). | |
| sub numsort { | |
| local(%lines) = @_; | |
| local($i) = 0; | |
| local(@sorted_lines); | |
| foreach $num (sort {$a <=> $b} keys %lines) { | |
| $sorted_lines[$i] = $lines{$num}; | |
| $i++; | |
| } | |
| @sorted_lines; | |
| } | |
| # This is a sort routine that will sort on the | |
| # ip address when the ip address is anywhere in | |
| # the strings. | |
| sub ipsort { | |
| local(%lines) = @_; | |
| local($i) = 0; | |
| local(@sorted_lines); | |
| foreach $addr (sort sortbyipaddr keys %lines) { | |
| $sorted_lines[$i] = $lines{$addr}; | |
| $i++; | |
| } | |
| @sorted_lines; | |
| } | |
| # These two routines will sort based upon IP addresses | |
| sub ipaddrval { | |
| my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); | |
| $a[3] + 256 * ($a[2] + 256 * ($a[1] +256 * $a[0])); | |
| } | |
| sub sortbyipaddr { | |
| &ipaddrval($a) <=> &ipaddrval($b); | |
| } | |
| # This routine parses "show version" | |
| sub ShowVersion { | |
| print STDERR " In ShowVersion: $_" if ($debug); | |
| while (<INPUT>) { | |
| warn "ShowVersion: $_" if ($debug); # lets see every line for debug | |
| tr/\015//d; | |
| if (/^$prompt/) { warn "FOUND PROMPT: $prompt\n" if ($debug); last;} | |
| next if(/^(\s*|\s*$cmd\s*)$/); | |
| return(1) if /^% Unrecognized command/; | |
| # the pager can not be disabled per-session on the dell | |
| s/^More: <space>.+<return> \033\[\K//; | |
| s/^More: <space>.+<return>\s*//; | |
| s/^\s*--More-- or \(q\)uit\s*//; | |
| /^(Machine )?Type:\s+(.*)$/ | |
| && ProcessHistory("COMMENTS","keysort","A1", "!TYPE: $2\n") | |
| && next; | |
| next if /System.*Up Time/; | |
| /^System\s+(.*)$/ | |
| && ProcessHistory( "COMMENTS", "keysort", "B1", "!SYSTEM $1\n" ) | |
| && next; | |
| # 6248 has "Burned In MAC Address" not "System MAC Address" | |
| /^Burned In\s+(.*)$/ | |
| && ProcessHistory("COMMENTS","keysort","B1", "!SYSTEM $1\n") | |
| && next; | |
| # for 5324 | |
| /^HW version\s+(.*)$/ | |
| && ProcessHistory( "COMMENTS", "keysort", "C1", "!HW: $1\n" ) | |
| && next; | |
| /^SW version\s+(.*)$/ | |
| && ProcessHistory( "COMMENTS", "keysort", "C2", "!SW: $1\n" ) | |
| && next; | |
| /^Boot version\s+(.*)$/ | |
| && ProcessHistory( "COMMENTS", "keysort", "C3", "!BOOT: $1\n" ) | |
| && next; | |
| # for 6248 (SW only) | |
| /^\s+\d+\s+([^\s]+)\s+([^\s]+)\s+image(\d)/ | |
| && ProcessHistory("COMMENTS","keysort","C2", "!SW: ", $3=="1" && $1 || $2, "\n") | |
| && next; | |
| /^(Serial [Nn]umber|Service [Tt]ag)\s*:\s+(.*)$/ | |
| && ProcessHistory( "COMMENTS", "keysort", "A2", "!$_" ) | |
| && next; | |
| } | |
| ProcessHistory("COMMENTS","keysort","D1","!\n"); | |
| return(0); | |
| } | |
| # This routine parses "show vlan" | |
| sub ShowVLAN { | |
| print STDERR " In ShowVLAN: $_" if ($debug); | |
| while (<INPUT>) { | |
| warn "ShowVLAN: $_" if ($debug); # lets see every line for debug | |
| tr/\015//d; | |
| last if (/^$prompt/); | |
| next if (/^(\s*|\s*$cmd\s*)$/); | |
| return(1) if /^% Unrecognized command/; | |
| # the pager can not be disabled per-session on the dell | |
| s/^More: <space>.+<return> \033\[\K//; | |
| s/^More: <space>.+<return>\s*//; | |
| s/^\s*--More-- or \(q\)uit\s*//; | |
| ProcessHistory("","","","!$_"); | |
| } | |
| ProcessHistory("","","","!\n"); | |
| ProcessHistory("","","","!\n"); | |
| return(0); | |
| } | |
| # This routine processes a "write term" | |
| sub WriteTerm { | |
| print STDERR " In WriteTerm: $_" if ($debug); | |
| while (<INPUT>) { | |
| warn "WriteTerm: $_" if ($debug); # lets see every line for debug | |
| tr/\015//d; | |
| if (/$prompt\s?exit/) { warn "left WriteTerm on: $_" if ($debug); $clean_run=1;last; } | |
| next if (/^(\s*|\s*$cmd\s*)$/); | |
| return(1) if /^% Unrecognized command/; | |
| # the pager can not be disabled per-session on the dell | |
| s/^More: <space>.+<return> \033\[\K//; | |
| s/^More: <space>.+<return>\s*//; | |
| s/^\s*--More-- or \(q\)uit\s*//; | |
| if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { | |
| ProcessHistory("ENABLE","","","!$1$2$3 <removed>\n"); | |
| next; | |
| } | |
| if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { | |
| if ($filter_pwds >= 2) { | |
| ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n"); | |
| } elsif ($filter_pwds >= 1 && $4 ne "5"){ | |
| ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n"); | |
| } else { | |
| ProcessHistory("USER","keysort","$1","$_"); | |
| } | |
| next; | |
| } | |
| if (/^(snmp-server community) (\S+)/) { | |
| if ($filter_commstr) { | |
| ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 <removed>$'") && next; | |
| } else { | |
| ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; | |
| } | |
| } | |
| # prune tacacs/radius server keys | |
| if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 key <removed>\n"); next; | |
| } | |
| if (/^((tacacs-server|radius-server) host \S+ key) / && | |
| $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| ProcessHistory("","","","$_"); | |
| } | |
| $found_end = 1; # no config end marker, just hard set this. | |
| ProcessHistory("","","","end\n"); | |
| return(0); | |
| } | |
| # dummy function | |
| sub DoNothing {print STDOUT;} | |
| # Main | |
| @commandtable = ( | |
| {'show system id' => 'ShowVersion'}, | |
| {'show system' => 'ShowVersion'}, | |
| {'show version' => 'ShowVersion'}, | |
| {'show vlan' => 'ShowVLAN'}, | |
| {'show running-config' => 'WriteTerm'}, | |
| ); | |
| # Use an array to preserve the order of the commands and a hash for mapping | |
| # commands to the subroutine and track commands that have been completed. | |
| @commands = map(keys(%$_), @commandtable); | |
| %commands = map(%$_, @commandtable); | |
| $cisco_cmds=join(";",@commands); | |
| $cmds_regexp=join("|",@commands); | |
| if (length($host) == 0) { | |
| if ($file) { | |
| print(STDERR "Too few arguments: file name required\n"); | |
| exit(1); | |
| } else { | |
| print(STDERR "Too few arguments: host name required\n"); | |
| exit(1); | |
| } | |
| } | |
| open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; | |
| select(OUTPUT); | |
| # make OUTPUT unbuffered if debugging | |
| if ($debug) { $| = 1; } | |
| if ($file) { | |
| warn "opening file $host\n" if ($debug); | |
| print STDOUT "opening file $host\n" if ($log); | |
| open(INPUT,"<$host") || die "open failed for $host: $!\n"; | |
| warn "opened $host\n" if ($debug); | |
| } else { | |
| print STDERR "executing dlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); | |
| print STDOUT "executing dlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); | |
| if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { | |
| system "dlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "dlogin failed for $host: $!\n"; | |
| open(INPUT, "< $host.raw") || die "dlogin failed for $host: $!\n"; | |
| warn "opened $host.raw\n" if ($debug); | |
| } else { | |
| open(INPUT,"dlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "dlogin failed for $host: $!\n"; | |
| warn "opened network stream from $host" if ($debug); | |
| } | |
| } | |
| # determine community string filtering mode | |
| if (defined($ENV{"NOCOMMSTR"}) && | |
| ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) { | |
| $filter_commstr = 1; | |
| } else { | |
| $filter_commstr = 0; | |
| } | |
| # determine password filtering mode | |
| if ($ENV{"FILTER_PWDS"} =~ /no/i) { | |
| $filter_pwds = 0; | |
| } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { | |
| $filter_pwds = 2; | |
| } else { | |
| $filter_pwds = 1; | |
| } | |
| ProcessHistory("","","","!RANCID-CONTENT-TYPE: Dell\n!\n"); | |
| ProcessHistory("COMMENTS","keysort","B0","!\n"); | |
| #ProcessHistory("COMMENTS","keysort","D0","!\n"); | |
| #ProcessHistory("COMMENTS","keysort","F0","!\n"); | |
| #ProcessHistory("COMMENTS","keysort","G0","!\n"); | |
| TOP: while(<INPUT>) { | |
| tr/\015//d; | |
| if (/[>#]\s?exit$/) { | |
| $clean_run=1; | |
| last; | |
| } | |
| if (/^Error:/) { | |
| print STDOUT ("$host dlogin error: $_"); | |
| print STDERR ("$host dlogin error: $_") if ($debug); | |
| $clean_run=0; | |
| last; | |
| } | |
| while (/#\s*($cmds_regexp)\s*$/) { | |
| $cmd = $1; | |
| if (!defined($prompt)) { | |
| $prompt = ($_ =~ /^([^#]+#)/)[0]; | |
| $prompt =~ s/([][}{)(\\])/\\$1/g; | |
| $prompt =~ tr/\033\\\[K//d; | |
| print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); | |
| } | |
| print STDERR ("HIT COMMAND:$_") if ($debug); | |
| if (! defined($commands{$cmd})) { | |
| print STDERR "$host: found unexpected command - \"$cmd\"\n"; | |
| $clean_run = 0; | |
| last TOP; | |
| } | |
| $rval = &{$commands{$cmd}}; | |
| delete($commands{$cmd}); | |
| if ($rval == -1) { | |
| $clean_run = 0; | |
| last TOP; | |
| } | |
| } | |
| } | |
| print STDOUT "Done $logincmd: $_\n" if ($log); | |
| # Flush History | |
| ProcessHistory("","","",""); | |
| # Cleanup | |
| close(INPUT); | |
| close(OUTPUT); | |
| if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { | |
| unlink("$host.raw") if (! $debug); | |
| } | |
| # check for completeness | |
| if (scalar(%commands) || !$clean_run || !$found_end) { | |
| if (scalar(%commands)) { | |
| printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))) unless ($debug); | |
| printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); | |
| } | |
| if (!$clean_run || !$found_end) { | |
| warn "found_end = $found_end, clean_run = $clean_run\n"; # jeremys debug | |
| print STDOUT "$host: End of run not found\n" unless ($debug); | |
| print STDERR "$host: End of run not found\n" if ($debug); | |
| system("/usr/bin/tail -1 $host.new"); | |
| } | |
| unlink "$host.new" if (! $debug); | |
| } |