From a2ae6db314a800aca2db382423a486ba288ea535 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Sat, 16 Jan 2016 11:41:34 -0500 Subject: [PATCH 01/38] Change "router" to "device" in email subjects and commit messages This more accurately reflects the expanded capabilities of RANCID. It's not just for routers anymore. --- bin/control_rancid.in | 8 ++++---- man/rancid_intro.1 | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/control_rancid.in b/bin/control_rancid.in index 3d50b6e..5808a62 100644 --- a/bin/control_rancid.in +++ b/bin/control_rancid.in @@ -318,10 +318,10 @@ if [ $RALL -ne 0 -o $RDOWN -ne 0 -o $RUP -ne 0 ] ; then cd $DIR/configs - # Add new routers to the CVS structure. + # Add new devices to the CVS structure. for router in `comm -13 $DIR/routers.up $DIR/routers.up.new | cut -d: -f1` do - message="new router $router in group $GROUP" + message="new device $router in group $GROUP" touch $router case $RCSSYS in cvs ) @@ -538,9 +538,9 @@ do done if [ $alt_mailrcpt -eq 1 ] ; then - subject="router config diffs - courtesy of $mailrcpt $ALT_COMMIT" + subject="device config diffs - courtesy of $mailrcpt $ALT_COMMIT" else - subject="router config diffs $ALT_COMMIT" + subject="device config diffs $ALT_COMMIT" fi if [ "X$device" != "X" ] ; then message="updates of group $GROUP - courtesy of $mailrcpt $ALT_COMMIT" diff --git a/man/rancid_intro.1 b/man/rancid_intro.1 index fb5eb0f..662a1ea 100644 --- a/man/rancid_intro.1 +++ b/man/rancid_intro.1 @@ -47,7 +47,7 @@ a lost configuration. See .BR rancid.conf (5) for more information on s. .PP -After filtering, a uni-diff (see +After filtering, a uni-diff (see .BR diff (1)) of the result is produced for each of the devices in a group against that of the previous run of @@ -69,11 +69,11 @@ for the device named dfw.shrubbery.net, which happens to be a Cisco GSR. .PP .ft CW .nf -From: rancid +From: rancid To: rancid-shrubbery@shrubbery.net -Subject: shrubbery router config diffs +Subject: device config diffs Precedence: bulk - + Index: configs/dfw.shrubbery.net =================================================================== retrieving revision 1.144 @@ -126,7 +126,7 @@ Run o Update the system's mail aliases file .IR /etc/aliases -(see +(see .BR rancid.conf (5)). .\" .SH "SEE ALSO" From 566b4e38757a768b2ebc5fcb25a9a4e96d560bcc Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Fri, 29 Jan 2016 14:48:29 -0500 Subject: [PATCH 02/38] Add dependencies to spec file --- rancid-git.spec | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rancid-git.spec b/rancid-git.spec index 26f11d4..1b67739 100644 --- a/rancid-git.spec +++ b/rancid-git.spec @@ -33,8 +33,14 @@ Requires: shadow-utils Requires: findutils Requires: expect >= 5.40 Requires: perl +Requires: perl-CGI +Requires: perl-LockFile-Simple +Requires: perl-MailTools Requires: iputils Requires: logrotate +Requires: git +Requires: python-pip +Requires: diffstat %description RANCID monitors a router's (or more generally a device's) configuration, From 8255404e79f2ea933b0378e044894aa84e44bb5c Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 2 Feb 2016 11:12:03 -0500 Subject: [PATCH 03/38] Fix regexp for scrubbing ASA/PIX keys --- bin/rancid.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/rancid.in b/bin/rancid.in index 552aeeb..665acf0 100644 --- a/bin/rancid.in +++ b/bin/rancid.in @@ -2115,7 +2115,7 @@ sub WriteTerm { next; } # ASA/PIX keys in more system:running-config - if (/^( pre-shared-key | key |failover key ).*/ && $filter_pwds >= 1) { + if (/^(( ikev1)? pre-shared-key | key |failover key ).*/ && $filter_pwds >= 1) { ProcessHistory("","","","!$1 $'"); next; } # ASA/PIX keys in more system:running-config From ee82bc280b2cb310570603b312d6d38ccae6dc89 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Wed, 3 Feb 2016 11:55:20 -0500 Subject: [PATCH 04/38] =?UTF-8?q?Bump=20version:=202.3.9-4=20=E2=86=92=202?= =?UTF-8?q?.3.9-4.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update specfile and changelog. --- rancid-git.spec | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/rancid-git.spec b/rancid-git.spec index 1b67739..722dbe5 100644 --- a/rancid-git.spec +++ b/rancid-git.spec @@ -1,9 +1,9 @@ -%global commit 89deb1cac7306c385c669a5a6b6744f6e08c054e +%global commit cc801e15d45280624e192389e2e242c0bf961b87 %global shortcommit %(c=%{commit}; echo ${c:0:7}) Name: rancid-git Version: 2.3.9 -Release: 3%{?dist} +Release: 4.1%{?dist} Summary: Really Awesome New Cisco confIg Differ (w/ git support) Group: Applications/Internet @@ -39,6 +39,7 @@ Requires: perl-MailTools Requires: iputils Requires: logrotate Requires: git +Requires: perl-Socket6 Requires: python-pip Requires: diffstat @@ -128,6 +129,21 @@ fi %changelog +* Wed Feb 03 2016 Sam Doran 2.3.9-4.1 +- Modify email subject and commit messages so they make more sense +- Correct regexp for removing ASA/PIX keys + +* Tue Feb 02 2016 Sam Doran 2.3.9-4 +- Use inet_pton from Socket6 module to preserve CentOS 6 compatibility. + See https://bugzilla.redhat.com/show_bug.cgi?id=1224143 for details. + +* Wed Jan 20 2016 Frank Fegert 2.3.9-4 +- Merged changes from upstream rancid (version 3.2). +- Improved handling of Dell PowerConnect M-Series switch devices. + +* Mon Nov 16 2015 Ryan Chapman 2.3.9-4 +- Improved ip address sorting (from upstream v3.2). + * Fri Oct 30 2015 John Siegrist 2.3.9-3 - Add make as missing BuildRequires dependency From 2c3666d80e394f36694b34b46f53191106afc694 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Sat, 16 Jan 2016 11:41:34 -0500 Subject: [PATCH 05/38] A more complete replacement of "router" to "device" Also update commit messages and log messages. --- bin/control_rancid.in | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/control_rancid.in b/bin/control_rancid.in index 5808a62..935506e 100644 --- a/bin/control_rancid.in +++ b/bin/control_rancid.in @@ -308,7 +308,7 @@ if [ $RALL -ne 0 -o $RDOWN -ne 0 -o $RUP -ne 0 ] ; then if [ -s routers.mail ] ; then ( echo "To: $adminmailrcpt" - echo "Subject: changes in $GROUP routers" + echo "Subject: changes in $GROUP devices" echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' echo "" cat routers.mail @@ -370,7 +370,7 @@ for router in `cut -d: -f1 ../routers.up` ; do if [ $? -eq 0 ]; then touch $router cvs add -ko $router - echo "$RCSSYS added missing router $router" + echo "$RCSSYS added missing device $router" fi ;; svn ) @@ -378,7 +378,7 @@ for router in `cut -d: -f1 ../routers.up` ; do if [ $? -eq 0 ]; then touch $router svn add $router - echo "$RCSSYS added missing router $router" + echo "$RCSSYS added missing device $router" fi ;; git | git-remote ) @@ -388,9 +388,9 @@ for router in `cut -d: -f1 ../routers.up` ; do ( flock -x 200 git add $router - git commit -m "added missing router $router" + git commit -m "added missing device $router" ) 200>$BASEDIR/.lockfile - echo "$RCSSYS added missing router $router" + echo "$RCSSYS added missing device $router" fi ;; esac @@ -404,13 +404,13 @@ for router in `find . \( -name \*.new -prune -o -name CVS -prune -o -name .cvsig case $RCSSYS in cvs | svn ) $RCSSYS delete $router - $RCSSYS commit -m "deleted router $router" $router + $RCSSYS commit -m "deleted device $router" $router ;; git | git-remote ) ( flock -x 200 git rm $router - git commit -m "deleted router $router" + git commit -m "deleted device $router" ) 200>$BASEDIR/.lockfile ;; esac @@ -489,12 +489,12 @@ do if [ -f $DIR/routers.up.missed ] ; then echo "=====================================" - echo "Getting missed routers: round $round." + echo "Getting missed devices: round $round." @bindir@/rancid_par -q -n $PAR_COUNT -c "rancid-fe \{}" $DIR/routers.up.missed rm -f $DIR/routers.up.missed round=`expr $round + 1` else - echo "All routers sucessfully completed." + echo "All devices sucessfully completed." round=`expr $pass + 1` fi done @@ -1003,7 +1003,7 @@ if [ -s $DIR/routers.failed ] ; then echo "Subject: config fetcher problems - $GROUP" echo "$MAILHEADERS" | awk '{L = "";LN = $0;while (LN ~ /\\n/) { I = index(LN,"\\n");L = L substr(LN,0,I-1) "\n";LN = substr(LN,I+2,length(LN)-I-1);}print L LN;}' echo "" - echo "The following routers have not been successfully contacted for" + echo "The following devices have not been successfully contacted for" echo "more than $OLDTIME hours." cat $DIR/routers.failed From e412564d190d76734ba28f0e789970e34f1ead9e Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 2 Feb 2016 14:51:11 -0500 Subject: [PATCH 06/38] Use inet_pton from Socket6 module to preserve CentOS 6 compatibility The Socket module included with the version of Perl in CentOS 6 does not include inet_pton (or the version is too old). Using inet_pton from Socket6 solves this issue. See this bug report for more details https://bugzilla.redhat.com/show_bug.cgi?id=1224143 --- bin/rancid.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/rancid.in b/bin/rancid.in index 665acf0..1612715 100644 --- a/bin/rancid.in +++ b/bin/rancid.in @@ -45,7 +45,8 @@ # usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; -use Socket qw(AF_INET AF_INET6 inet_pton); +use Socket qw(AF_INET); +use Socket6 qw(AF_INET6 inet_pton); getopts('dflV'); if ($opt_V) { print "@PACKAGE@ @VERSION@\n"; From 01e4b52ceecf435d73ec3a75c7174bcc06b81c33 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Fri, 29 Jan 2016 15:14:24 -0500 Subject: [PATCH 07/38] Fix bug in update-spec.sh Modify the regexp so it will match point release like '3.2' and not just an integer. --- update-spec.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update-spec.sh b/update-spec.sh index 2ac4672..9f7c36f 100755 --- a/update-spec.sh +++ b/update-spec.sh @@ -47,7 +47,7 @@ update_version_in_spec() { } update_release_in_spec() { - perl -pi -e 's/(^Release: )(\d)+/$1$ENV{RELEASE}/g' $spec_file + perl -pi -e 's/(^Release: )(\d(\.)?)+(\d)?/$1$ENV{RELEASE}/g' $spec_file } create_archive() { From 238d8a389ecea35e00ce4b9eaf31433a61f92b6f Mon Sep 17 00:00:00 2001 From: Petter Aksnes Helset Date: Wed, 30 Dec 2015 14:45:56 +0100 Subject: [PATCH 08/38] fixed typo --- bin/f10rancid.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/f10rancid.in b/bin/f10rancid.in index e338f72..5c7fe49 100644 --- a/bin/f10rancid.in +++ b/bin/f10rancid.in @@ -261,7 +261,7 @@ sub ShowChassis { next if (/^----+$/); # S4048-ON /^(Unit\s+Bay\s+Status\s+Type\s+FanStatus)\s+FanSpeed/ && ProcessHistory("COMMENTS", - keysort","CHASSIS","!Chassis: $1\n") && + "keysort","CHASSIS","!Chassis: $1\n") && next; /^(\s+\d+\s+\d+\s+(absent|\S+\s+\S+)\s+\S+)\s+\d+/ && ProcessHistory("COMMENTS","keysort","CHASSIS", @@ -274,7 +274,7 @@ sub ShowChassis { ProcessHistory("COMMENTS","keysort","CHASSIS", "!Chassis: $1\n") && next; print STDERR " In ShowChassis: $_" if ($debug); - ) + } } From b9113c6d7ac98a7683487caa84ed4828e27d9d2e Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 4 Feb 2016 11:08:55 -0500 Subject: [PATCH 09/38] Properly remove community strings in new version of ASA This change is from the 3.2 upstream. --- bin/rancid.in | 20 ++++++++++++-------- rancid-git.spec | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bin/rancid.in b/bin/rancid.in index 1612715..e6c608d 100644 --- a/bin/rancid.in +++ b/bin/rancid.in @@ -2221,14 +2221,18 @@ sub WriteTerm { } next; } - if (/^(snmp-server community) (\S+)/) { - if ($filter_commstr) { - ProcessHistory("SNMPSERVERCOMM","keysort","$_", - "!$1 $'") && next; - } else { - ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; - } - } + # For ASA version 8.x and higher, the format changed a little. It is + # 'snmp-server host {interface {hostname | ip_address}} [trap | poll] + # [community 0 | 8 community-string] [version {1 | 2c | 3 username}] + # [udp-port port] ' + if (/^(snmp-server .*community) ([08] )?(\S+)/) { + if ($filter_commstr) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_", + "!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } # prune tacacs/radius server keys if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\S+/ && $filter_pwds >= 1) { diff --git a/rancid-git.spec b/rancid-git.spec index 722dbe5..33d2db4 100644 --- a/rancid-git.spec +++ b/rancid-git.spec @@ -132,6 +132,7 @@ fi * Wed Feb 03 2016 Sam Doran 2.3.9-4.1 - Modify email subject and commit messages so they make more sense - Correct regexp for removing ASA/PIX keys +- Properly remove ASA community strings in ASA 8.x * Tue Feb 02 2016 Sam Doran 2.3.9-4 - Use inet_pton from Socket6 module to preserve CentOS 6 compatibility. From 5ade3bfe04c3fc0313a4a408d1a842e355bfa308 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Wed, 3 Feb 2016 17:43:35 -0500 Subject: [PATCH 10/38] Filter out messages that change every time from show flash On certain routers, Load and Time showup in the output and change every time. This creates noisy diffs. --- bin/rancid.in | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bin/rancid.in b/bin/rancid.in index e6c608d..42e63dc 100644 --- a/bin/rancid.in +++ b/bin/rancid.in @@ -732,6 +732,8 @@ sub ShowFlash { next if (/^(\s*|\s*$cmd\s*)$/); next if (/coredumpinfo\/coredump\.cfg$/); next if (/\.dat$/); + next if (/Load for five secs/); + next if (/Time source is/); return(1) if ($type =~ /^(12[40]|7)/); return(1) if ($ios eq "XE"); return(1) if (/^\s*\^\s*$/); @@ -986,6 +988,8 @@ sub ShowDebug { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); + next if (/Load for five secs/); + next if (/Time source is/); return(1) if (/Line has invalid autocommand /); return(1) if (/(Invalid (input|command) detected|Type help or )/i); return(-1) if (/command authorization failed/i); @@ -1407,6 +1411,8 @@ sub ShowInventory { while () { tr/\015//d; return if (/^\s*\^$/); + next if (/Load for five secs/); + next if (/Time source is/); last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if (/Line has invalid autocommand /); @@ -1609,6 +1615,8 @@ sub ShowVTP { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); + next if (/Load for five secs/); + next if (/Time source is/); return(1) if /^\s*\^\s*$/; return(1) if (/Line has invalid autocommand /); return(1) if (/(Invalid (input|command) detected|Type help or )/i); @@ -1835,6 +1843,8 @@ sub ShowVLAN { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); + next if (/Load for five secs/); + next if (/Time source is/); return(1) if /^\s*\^\s*$/; return(1) if (/Line has invalid autocommand /); return(1) if (/(Invalid (input|command) detected|Type help or )/i); From c577a2fff9b0ccb62f797a2340405edf0b6c850b Mon Sep 17 00:00:00 2001 From: Sebastien Badia Date: Sat, 13 Feb 2016 11:55:51 +0100 Subject: [PATCH 11/38] debian: Fix packaging issues and updates --- debian/changelog | 4 ++-- debian/control | 38 +++++++++++++++++++++++++++++--------- debian/rules | 3 ++- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/debian/changelog b/debian/changelog index c1d86b8..df734bc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -rancid-git (2.3.9-0) UNRELEASED; urgency=low +rancid-git (2.3.9-4) unstable; urgency=low [ Vincent Bernat ] * Unofficial package. @@ -11,4 +11,4 @@ rancid-git (2.3.9-0) UNRELEASED; urgency=low * Added support for Ubiquiti AirOS radios and ToughSwitch (ubnt) * Updated looking glass (rancid-cgi). - -- Vincent Bernat Mon, 18 Aug 2014 10:05:05 +0200 + -- Vincent Bernat Sat, 13 Feb 2016 11:17:37 +0100 diff --git a/debian/control b/debian/control index 7a0420f..3c3bc13 100644 --- a/debian/control +++ b/debian/control @@ -2,21 +2,41 @@ Source: rancid-git Section: net Priority: optional Maintainer: Roland Rosenfeld -Build-Depends: debhelper (>= 9), expect, perl, automake, autoconf -Standards-Version: 3.9.4 +Build-Depends: automake, + autotools-dev, + cvs, + debhelper (>= 9), + dh-autoreconf, + exim4 | mail-transport-agent, + expect, + iputils-ping | ping, + openssh-client, + perl, + po-debconf, + telnet +Standards-Version: 3.9.6 Homepage: http://www.shrubbery.net/rancid/ Package: rancid-git Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, expect, perl, - cvs | subversion | git, passwd, openssh-client | ssh, inetutils-ping | ping, - debconf (>= 0.2.26) | debconf-2.0, adduser, exim4 | mail-transport-agent, - libperl4-corelibs-perl | perl (<< 5.12.3-7) +Depends: adduser, + cvs | subversion | git, + debconf (>= 0.2.26) | debconf-2.0, + exim4 | mail-transport-agent, + expect, + iputils-ping | ping, + libperl4-corelibs-perl | perl (<< 5.12.3-7), + openssh-client | ssh, + passwd, + perl, + ${misc:Depends}, + ${perl:Depends}, + ${shlibs:Depends} Suggests: diffstat -Provides: rancid-core, rancid-util, rancid +Provides: rancid, rancid-core, rancid-util Replaces: rancid-core (<< 2.3.5), rancid-util (<< 2.3.5) Breaks: rancid-core (<< 2.3.5), rancid-util (<< 2.3.5) -Conflicts: rancid, par +Conflicts: par, rancid Description: Really Awesome New Cisco confIg Differ This is a popular ISP toolkit, based on expect and shell scripts, for managing router configurations. @@ -27,7 +47,7 @@ Description: Really Awesome New Cisco confIg Differ Package: rancid-cgi Architecture: all -Depends: ${misc:Depends}, ${perl:Depends}, rancid-git, liblockfile-simple-perl +Depends: liblockfile-simple-perl, rancid-git, ${misc:Depends}, ${perl:Depends} Suggests: apache2 | httpd-cgi Description: looking glass CGI for rancid This is a popular ISP toolkit, based on expect and shell scripts, diff --git a/debian/rules b/debian/rules index 34d17e3..206c0b3 100755 --- a/debian/rules +++ b/debian/rules @@ -12,7 +12,7 @@ DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) %: - dh $@ + dh $@ --with autotools_dev --with autoreconf override_dh_auto_configure: aclocal @@ -29,6 +29,7 @@ override_dh_auto_configure: --sysconfdir=\$${prefix}etc/rancid \ --exec-prefix=\$${prefix}usr/lib/rancid \ --localstatedir=\$${prefix}var/lib/rancid \ + --libdir=\$${prefix}usr/share/perl5 \ --with-git override_dh_auto_install: From 6409aa92997d1e09dcd4a658845d7d5de0a90d44 Mon Sep 17 00:00:00 2001 From: dsx Date: Mon, 15 Feb 2016 10:27:03 -0500 Subject: [PATCH 12/38] Added h3c files of unknown origin --- bin/h3clogin.in | 946 +++++++++++++++++++++++++++++++++++++++++++++++ bin/h3crancid.in | 562 ++++++++++++++++++++++++++++ 2 files changed, 1508 insertions(+) create mode 100755 bin/h3clogin.in create mode 100755 bin/h3crancid.in diff --git a/bin/h3clogin.in b/bin/h3clogin.in new file mode 100755 index 0000000..abcf6a0 --- /dev/null +++ b/bin/h3clogin.in @@ -0,0 +1,946 @@ +#! /usr/bin/expect -- +## +## $Id: $ +## +## @PACKAGE@ @VERSION@ +## Copyright (c) 1997-2009 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# The expect login scripts were based on Erik Sherk's gwtn, by permission. + +# +# h3clogin - H3C login +# +# h3clogin covers the following product ranges: +# +# * 3Com SuperStack 4 (post-joint venture with Huawei) +# * H3C +# * HP Networking ('A' & some 'E' portfolio, post 2010 3Com acquitision) +# +# It may also work with some Huawei equipment. +# + +# Set to 1 to enable some debugging, or pass "-d" on command line +exp_internal 0 + +# Usage line +set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set avenable 1 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 +set do_saveconfig 0 +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeoutdflt 45 +# +set send_human {.1 .3 .7 .05 2} + +# H3C: some models don't like "3des"; specify "aes128-cbc" in .cloginrc +set default_cyphertype "3des" + +# H3C: command to elevate priviges (aka "enable") is different +set enacmd "super" + +# H3C: command to exit from device +set exitcmd "quit" + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ] } { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Expect debug mode + -d* { + exp_internal 1 + # Username + } -u* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -p* { + if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # ssh passphrase + } -r* { + if {! [ regexp .\[rR\](.+) $arg ignore passphrase]} { + incr i + set vapassphrase [ lindex $argv $i ] + } + # VTY Password + } -v* { + if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [ lindex $argv $i ] + } + set do_passwd 0 + # Version string + } -V* { + send_user "@PACKAGE@ @VERSION@\n" + exit 0 + # Enable Username + } -w* { + if {! [ regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [ lindex $argv $i ] + } + # Environment variable to pass to -s scripts + } -E* { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* { + if {! [ regexp .\[e\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [ lindex $argv $i ] + } + set do_enapasswd 0 + # Command to run. + } -c* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # save config on exit + } -S* { + set do_saveconfig 1 + # 'ssh -c' cypher type + } -y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + # Timeout + } -t* { + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeoutdflt [ lindex $argv $i ] + } + # Command file + } -x* { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + set avenable 0 + # Does tacacs automatically enable us? + } -autoenable { + set avautoenable 1 + set avenable 0 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +# returns: 0 on success, 1 on failure, -1 if rsh was used successfully +proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } { + global spawn_id in_proc do_command do_script platform passphrase + global prompt prompt_match u_prompt p_prompt e_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + incr progs -1 + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn telnet $router} reason ] + } else { + set retval [ catch {spawn telnet $router $port} reason ] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + return 1 + } + } elseif [string match "ssh*" $prog] { + # ssh to the router & try to login with or without an identfile. + regexp {ssh(:([^[:space:]]+))*} $prog command suffix port + set cmd [join [lindex $sshcmd 0] " "] + if {"$port" != ""} { + set cmd "$cmd -p $port" + } + if {"$identfile" != ""} { + set cmd "$cmd -i $identfile" + } + set retval [ catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason ] + if { $retval } { + send_user "\nError: $sshcmd failed: $reason\n" + return 1 + } + } elseif ![string compare $prog "rsh"] { + if { ! $do_command } { + if { [llength $cmethod] == 1 } { + send_user "\nError: rsh is an invalid method for -x and " + send_user "interactive logins\n" + } + if { $progs == 0 } { + return 1 + } + continue; + } + + set commands [split $command \;] + set num_commands [llength $commands] + set rshfail 0 + for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { + log_user 0 + set retval [ catch {spawn rsh $user@$router [lindex $commands $i] } reason ] + if { $retval } { + send_user "\nError: rsh failed: $reason\n" + log_user 1; return 1 + } + send_user "$router# [lindex $commands $i]\n" + + # rcmd does not get a pager and no prompts, so we just have to + # look for failures & lines. + expect { + "Connection refused" { catch {close}; catch {wait}; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; catch {wait}; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; catch {wait}; + send_user "\nError: Unknown host\ + $router\n" + set rshfail 1 + } + -re "\b+" { exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + timeout { catch {close}; catch {wait}; + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; catch {wait}; } + } + log_user 1 + } + if { $rshfail } { + if { !$progs } { + return 1 + } else { + continue + } + } + # fake the end of the session for rancid. + send_user "$router# exit\n" + # return rsh "success" + return -1 + } else { + puts "\nError: unknown connection method: $prog" + return 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection closed ($prog): $router\n" + return 1 + } + } + eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } + -nocase "unknown host\r" { + send_user "\nError: Unknown host $router\n"; wait; return 1 + catch {close}; catch {wait}; + return 1 + } + "Host is unreachable" { + send_user "\nError: Host Unreachable: $router\n"; + catch {close}; catch {wait}; + return 1 + } + "No address associated with name" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue + } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "Offending key for .* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "(denied|Sorry)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Login failed" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + -re "% (Bad passwords|Authentication failed)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Press any key to continue." { + # send_user "Pressing the ANY key\n" + send "\r" + exp_continue + } + -re "Enter Selection: " { + # Catalyst 1900s have some lame menu. Enter + # K to reach a command-line. + send "K\r" + exp_continue; + } + -re "Last login:" { + exp_continue; + } + -re "@\[^\r\n]+ $p_prompt" { + # ssh pwd prompt + sleep 1 + send "$userpswd\r" + exp_continue + } + -re "Enter passphrase.*: " { + # sleep briefly to allow time for stty -echo + sleep .3 + send -- "$passphrase\r" + exp_continue + } + -re "$u_prompt" { + send -- "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send -- "$userpswd\r" + } else { + send -- "$passwd\r" + } + exp_continue + } + -re "$prompt" { + set prompt_match $expect_out(0,string); + break; + } + "Login invalid" { + send_user "\nError: Invalid login: $router\n"; + catch {close}; catch {wait}; return 1 + } + } + } + + set in_proc 0 + return 0 +} + +# Enable +proc do_enable { enauser enapasswd } { + global prompt in_proc + global prompt u_prompt e_prompt + global enacmd + set in_proc 1 + + send -h "$enacmd\r" + expect { + -re "$u_prompt" { send -h -- "$enauser\r"; exp_continue} + -re "$e_prompt" { send -h -- "$enapasswd\r"; exp_continue} + -re ">" { set prompt ">" } + "% Password is not set." { + send_user "\nError: No 'super' password set for device\n" + return 1 + } + "% Authenticate failed." { + send_user "\nError: Check your enable password for 'super'\n" + return 1 + } +# "#" { set prompt "#" } +# "(enable)" { set prompt "> \\(enable\\) " } + #-re "(denied|Sorry|Incorrect)" { + # # % Access denied - from local auth and poss. others + # send_user "\nError: Check your Enable passwd\n"; + # return 1 + # } + #"% Error in authentication" { + # send_user "\nError: Check your Enable passwd\n" + # return 1 + # } + #"% Bad passwords" { + # send_user "\nError: Check your Enable passwd\n" + # return 1 + # } + } + # We set the prompt variable (above) so script files don't need + # to know what it is. + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global do_saveconfig in_proc platform + global exitcmd + set in_proc 1 + + # clogin has this beast: + #regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt + # escape any parens in the prompt, such as "(enable)" + regsub -all {[][)(]} $prompt {\\&} reprompt + + expect { + -re $reprompt {} + -re "\[\n\r]+" { exp_continue } + } + + # this is the only way i see to get rid of more prompts in o/p..grrrrr + log_user 0 + + set commands [split $command \;] + set num_commands [llength $commands] + # The pager can not be turned off on some 3Com/H3C, so we have to look + # for the "More" prompt. + for {set i 0} {$i < $num_commands} { incr i} { + send -- "[subst -nocommands [lindex $commands $i]]\r" + expect { + -re "\b+" { exp_continue } + -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue } + -re "^ ---- More ----.*\[^\n\r]*" { + # H3C pager prompt + sleep 0.1 + send " " + exp_continue } + } + + } + + log_user 1 + + send -h "$exitcmd\r" + + # H3C: the exit command leaves the switch completely; it does not + # prompt to save if the config has been modified + expect { +# -re "^\[^\n\r *]*$reprompt" { +# # H3C products +# # return to non-enabled mode +# # on exit in enabled mode. +# send -h "$exitcmd\r" +# exp_continue; +# } +# TODO: we will need to do this too: +# "Do you wish to save your configuration changes" { +# send -h "n\r" +# exp_continue +# } + -re "\[\n\r]+" { exp_continue } +# hwlogin+mod: + -re "\[^\n\r *]Note:" { return 0 } + timeout { catch {close}; catch {wait}; + return 0 + } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +set exitval 0 +set prompt_match "" +set enable 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # device timeout + set timeout [find timeout $router] + if { [llength $timeout] == 0 } { + set timeout $timeoutdflt + } + + # Default prompt. + #set prompt "(>|#| \\(enable\\))" + set prompt ">\a?" + + # look for noenable option in .cloginrc + if { [find noenable $router] == "1" } { + set enable 0 + } + + # Figure out passwords + if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user "\nError: no password for $router in $password_file.\n" + continue + } + if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { + send_user "\nError: no enable password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(Username|Login|login|user name|User):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { + set e_prompt "\[Pp]assword:" + } else { + set e_prompt [join [lindex $e_prompt 0] ""] + } + + # Figure out identity file to use + set identfile [join [lindex [find identity $router] 0] ""] + + # Figure out passphrase to use + if {[info exists avpassphrase]} { + set passphrase $avpassphrase + } else { + set passphrase [join [lindex [find passphrase $router] 0] ""] + } + if { ! [string length "$passphrase"]} { + set passphrase $passwd + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "$default_cyphertype" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} { + incr exitval + # if login failed or rsh was unsuccessful, move on to the next device + continue + } + + # Figure out the prompt. + +# H3C: this is what we used to have, now should be obsolete: +# # Since autoenable is off by default, if we have it defined, it +# # was done on the command line. If it is not specifically set on the +# # command line, check the password file. +# if $avautoenable { +# set autoenable 1 +# set enable 0 +## hwlogin: +# #set prompt "(#| \\(enable\\))" +# set prompt ">\a?" +# } else { +# set ae [find autoenable $router] +# if { "$ae" == "1" } { +# set autoenable 1 +# set enable 0 +## hwlogin: +# set prompt ">\a?" +# } else { +# set autoenable 0 +# set enable $avenable +# set prompt ">\a?" +# } +# } +# +# # look for noenable option in .cloginrc +# if { [find noenable $router] == "1" } { +# set enable 0 +# } +## clogin has: +## # look for noenable option in .cloginrc +## if | [find noenable $router] != "" | { +## set enable 0 +## } + + # !! H3C does not appear to have a different prompt between lower + # privilege and higher privilege users, so the following test is + # not applicable +# if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } { +# set enable 0 +# } else { + if { $avenable == 0 } { + set enable 0 + } else { + set ne [find noenable $router] + set ae [find autoenable $router] + if { "$ne" == "1" || "$ae" == "1" || $avautoenable } { + set enable 0 + } else { + set enable 1 + } + } +# } + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + incr exitval + catch {close}; catch {wait}; + continue + } + } + } + # we are logged in, now figure out the full prompt + send "\r" + expect { + -re "\[\r\n]+" { exp_continue; } +# -re "^(.+\[:.])1 ($prompt)" { # stoopid extreme cmd-line numbers and +# # prompt based on state of config changes, +# # which may have an * at the beginning. +# set junk $expect_out(1,string) +# regsub -all "^\\\* " $expect_out(1,string) {} junk +# regsub -all "\[\]\[\(\)]" $junk {\\&} junk; +# set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; +# set platform "extreme" +# } + -re "^.+$prompt" { set junk $expect_out(0,string); + regsub -all "\[\]\[\(\)]" $junk {\\&} prompt; + } + } + + # H3C: Disable log junk being sent to terminal: must be done before + # $enacmd is run. It would be nice for this to be setable in .cloginrc + send -h "undo terminal monitor\r" + expect -re $prompt {} + + # Turn session paging off + # Comware 5 only. + # Comware 3 models have a screen-length command that only works on + # a vty basis + # clogin does this only within the do_script clause below, but I can't + # see why you wouldn't want it here, covering do_command too + send -h "screen-length disable\r" + #expect -re $prompt {} + + if { $do_command } { + if {[run_commands $prompt $command]} { + incr exitval + continue + } + } elseif { $do_script } { + expect -re $prompt {} + source $sfile + catch {close}; + } else { + label $router + log_user 1 + interact + } + + # End of for each router + catch {wait}; + sleep 0.3 +} +exit $exitval + diff --git a/bin/h3crancid.in b/bin/h3crancid.in new file mode 100755 index 0000000..28c5d46 --- /dev/null +++ b/bin/h3crancid.in @@ -0,0 +1,562 @@ +#! /usr/bin/perl +## +## $Id: $ +## +## @PACKAGE@ @VERSION@ +## Copyright (c) 1997-2009 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# RANCID - Really Awesome New Cisco confIg Differ +# + +# +# h3crancid +# +# h3clogin/h3crancid covers the following product ranges: +# +# * 3Com SuperStack 4 (post-joint venture with Huawei) +# * H3C +# * HP Networking ('A' & some 'E' portfolio, post 2010 3Com acquitision) +# +# They may also work with some Huawei equipment. +# +# https://sites.google.com/site/jrbinks/code/rancid/h3c +# + +# +# Usage: h3crancid [-dV] [-l] [-f filename | hostname] +# + +# Notable changes from standard *rancid programs: +# +# * abstracted to path to the 'tail' utility +# * altered "cisco_cmds" to be "device_cmds" +# * define and use $logincmd +# + +# TODO: +# +# It may be useful to pull common subroutines like the sorting ones into +# a library for use by all the *rancid programs. +# + +############################################################################ +# END-USER TWEAKS + +# The login program to use. If no path is given, $PATH is searched: +#my $logincmd = "h3clogin99"; +my $logincmd = "h3clogin"; +#my $logincmd = "/usr/local/libexec/h3clogin"; +# +# Enable display of the FIB: +my $display_fib = 1; +# +# Enable display of the routing table: +# (no-op) +#my $display_iproutes = 1; + +# END OF END-USER TWEAKS +############################################################################# + +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; +#$timeo = 90; # login command timeout in seconds +$timeo = 20; # login command timeout in seconds + +my $TAIL = "/usr/bin/tail"; + +my(@commandtable, %commands, @commands);# command lists +my($aclsort) = ("ipsort"); # ACL sorting mode +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)) + && defined %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); +} + +sub filter_lines { + my ($l) = (@_); +# print STDERR " In filterlines: $l\n" if ($debug); + + # Filter out some ANSI crud as a result of us not being able to turn + # off per-session terminal paging: + # h3c: + #s/^\033\[42D +\033\[42D(.+)$/$1/; + # hwlogin+mods: + #s/\033\133\064\062\104\s*\033\133\064\062\104//g; + $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g; + $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g; + $l =~ s/\033\133\064\062\104//g; + $l =~ s/\033\133\061\062\104//g; + # Probably not needed: + $l =~ s/\s*---- More ----\s*//; +# print STDERR "out: $l\n" if ($debug); + return $l; +} + +sub DisplayFib { + ## We should probably guarantee that the FIB is sorted properly + print STDERR " In DisplayFib: $_" if ($debug); + + return(1) if $display_fib == 0; + chomp; + + # Display the command we're processing in the output: + s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + ProcessHistory("COMMENTS","keysort","A0","! $_\n!\n"); + + while () { + tr/\015//d; + last if(/^$prompt/); + chomp; + # skip blank lines + return(1) if /^\s+\^$/; + $_ = filter_lines($_); + + # make this a subroutine: + return(1) if /% Too many parameters found at '\^' position/; + return(1) if /% Unrecognized command found at '\^' position/; + return(1) if /% Wrong parameter found at '\^' position/; + return(1) if /% Wrong device .+/; + + # Chop out some detail that changes over time: + s/(\s+)TimeStamp\s+/$1/; + s/(\s+)t\[\d+\]\s+/$1/; + + ProcessHistory("COMMENTS","ipsort","A0","! $_\n"); + #ProcessHistory("COMMENTS","keysort","A0","! $_\n"); + } + ProcessHistory("COMMENTS","keysort","A0","! \n"); + return(0); +} + + +# This routine processes general output of "display" commands +sub CommentOutput { + print STDERR " In CommentOutput: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + ProcessHistory("","","","! $_\n!\n"); + + # eat the header line +# $junk = ; + # now just copy it mostly verbatim to the history file + while () { + tr/\015//d; + + # If we find the prompt, we're done + #last if(/^<.*>/); + last if(/^$prompt/); + chomp; + + # skip blank lines + return(1) if /^\s+\^$/; + + $_ = filter_lines($_); + + # Filter out some ANSI crud as a result of us not being able to turn + # off per-session terminal paging: + # h3c: + #s/^\033\[42D +\033\[42D(.+)$/$1/; + # hwlogin+mods: + #s/\033\133\064\062\104\s*\033\133\064\062\104//g; +# s/\033\133\064\062\104\s+\033\133\064\062\104//g; +# s/\033\133\061\066\104\s+\033\133\061\066\104//g; + #s/\033\133\064\062\104//g; + # Probably not needed: +# s/\s*---- More ----\s*//; + + # make this a subroutine: + # Some commands are not supported on some models or versions + # of code. These lines simply remove the associated error + # messages: + return(1) if /% Too many parameters found at '\^' position/; + return(1) if /% Unrecognized command found at '\^' position/; + return(1) if /% Wrong parameter found at '\^' position/; + return(1) if /% Wrong device .+/; + + # Parts of the output of some commands changes over time, but we don't + # want these changes to trigger a rancid notification, so we + # filter them out: + + # This is part of one line, just cut it out: + s/\s+Current AccessNum:.+$//; + + if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/) { + next; + } + + s/(.*)uptime.*days*.*hours*.*minutes*(.*)/$1 $2/; + + ProcessHistory("","","","! $_\n"); + } + + ProcessHistory("","","","! \n"); + return(0); +} + +## This routine processes a "display current" +sub DisplayCurrent { + print STDERR " In DisplayCurrent: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + + $_ = filter_lines($_); + + # Filter out some ANSI crud as a result of us not being able to turn + # off per-session terminal paging: + # h3c: + #s/^\033\[42D +\033\[42D(.+)$/$1/; + # hwlogin+mods: + #s/\033\133\064\062\104\s*\033\133\064\062\104//g; +# s/\033\133\064\062\104\s+\033\133\064\062\104//g; +# s/\033\133\061\066\104\s+\033\133\061\066\104//g; +# s/\033\133\064\062\104//g; + # Probably not needed: +# s/\s*---- More ----\s*//; + + # Filter out some sensitive data: + if (/^( ?snmp-agent community (read|write) )(\S+)/ && + $filter_commstr == 0) { + ProcessHistory("","","","!$1$'"); + next; + } + + ProcessHistory("","","","$_"); + + # end of config + + if (/^return/) { + $found_end = 1; + return(0); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +## Not all commands are supported on all models and code versions +## Not all of these should necessarily be included +@commandtable = ( + {'display version' => 'CommentOutput'}, + {'display boot-loader' => 'CommentOutput'}, + {'dir /all unit1>flash:/' => 'CommentOutput'}, + {'dir /all unit2>flash:/' => 'CommentOutput'}, + {'dir /all unit3>flash:/' => 'CommentOutput'}, + {'dir /all unit4>flash:/' => 'CommentOutput'}, + {'dir /all unit5>flash:/' => 'CommentOutput'}, + {'dir /all unit6>flash:/' => 'CommentOutput'}, + {'dir /all unit7>flash:/' => 'CommentOutput'}, + {'dir /all unit8>flash:/' => 'CommentOutput'}, + {'display device' => 'CommentOutput'}, + {'display device manuinfo' => 'CommentOutput'}, + {'display irf' => 'CommentOutput'}, + {'display xrn-fabric' => 'CommentOutput'}, + {'display ftm topology-database' => 'CommentOutput'}, + {'display fan' => 'CommentOutput'}, + {'display power' => 'CommentOutput'}, + {'display poe powersupply' => 'CommentOutput'}, + {'display poe temperature-protection' => 'CommentOutput'}, + {'display cluster' => 'CommentOutput'}, + {'display domain' => 'CommentOutput'}, + {'display local-user' => 'CommentOutput'}, + {'display password-control' => 'CommentOutput'}, + {'display password-control super' => 'CommentOutput'}, + {'display ssh server status' => 'CommentOutput'}, + {'display fib' => 'DisplayFib'}, + {'display vlan all' => 'CommentOutput'}, + {'display ip routing-table' => 'CommentOutput'}, + {'display lacp sys' => 'CommentOutput'}, + {'display link-aggregation summary' => 'CommentOutput'}, + {'display link-aggregation verbose' => 'CommentOutput'}, + {'display mirror all' => 'CommentOutput'}, + {'display current-configuration' => 'DisplayCurrent'}, +); + +# 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); + +$device_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) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($debug); + print STDOUT "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { +# system "$logincmd -noenable -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n"; +# system "$logincmd -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n"; + system "$logincmd -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "$logincmd failed for $host: $!\n"; + } else { +# open(INPUT,"$logincmd -noenable -t $timeo -c \"$device_cmds\" $host ) { + tr/\015//d; +# h3c: +# Look for the command at the end of the output +# if (/\#exit$/) { +# if (/\#quit$/) { +# h3c: + if (/[\]>]\a?\s*quit/) { +# if (/^[\[<].*[\]>]\a?\s?quit/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host $logincmd error: $_"); + print STDERR ("$host $logincmd error: $_") if ($debug); + $clean_run=0; + last; + } +# while (/#\s*($cmds_regexp)\s*$/) { +# h3c: + while (/[\]>]\a?\s*($cmds_regexp)\s*$/) { +# while (/^[\[<].*[\]>]\a?\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + # h3c: + # Extract the prompt: look for something not [ or < at the start + # of the line, until either ] or > is reached: + #$prompt = ($_ =~ /^([^#]+#)/)[0]; + #$prompt =~ s/([][}{)(\\])/\\$1/g; + #$prompt = ($_ =~ /^([^\]>]+[\]>]\007?)/)[0]; + $prompt = ($_ =~ /^([^\]>]+[\]>]\a?)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + 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); +} + +printf(STDOUT "$host: clean_run=$clean_run found_end=$found_end\n") 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))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("$TAIL -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} From 62237ad0705f1e2fe700037611cc54c7ae5ce863 Mon Sep 17 00:00:00 2001 From: dsx Date: Mon, 15 Feb 2016 11:27:59 -0500 Subject: [PATCH 13/38] Added h3c handling --- bin/Makefile.am | 2 +- bin/Makefile.in | 10 ++++++++-- bin/rancid-fe.in | 3 ++- configure | 8 ++++++++ configure.ac | 2 ++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/bin/Makefile.am b/bin/Makefile.am index a7c5c1c..4601a64 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -57,7 +57,7 @@ bin_SCRIPTS = agmrancid alogin arancid arrancid avologin avorancid blogin \ nxrancid rancid_par pflogin pfrancid prancid rancid rivlogin rivrancid rrancid srancid \ telcorancid tlogin tntlogin tntrancid trancid ubnt-es-rancid urancid ucsrancid \ xrancid xrrancid zrancid zyrancid dlogin drancid shelllogin shellrancid \ - vlogin vrancid + vlogin vrancid h3clogin h3crancid bin_SCRIPTS += lg.cgi lgform.cgi rancid-cvs rancid-fe rancid-run control_rancid EXTRA_DIST= lg.cgi.in lgform.cgi.in rancid-cvs.in rancid-fe.in rancid-run.in \ diff --git a/bin/Makefile.in b/bin/Makefile.in index cf778a7..2b8fe4d 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -116,6 +116,7 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/vlogin.in $(srcdir)/vrancid.in \ $(srcdir)/xrancid.in $(srcdir)/xrrancid.in \ $(srcdir)/zrancid.in $(srcdir)/zyrancid.in \ + $(srcdir)/h3clogin.in $(srcdir)/h3crancid.in \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ @@ -133,7 +134,8 @@ CONFIG_CLEAN_FILES = agmrancid alogin arancid arrancid avologin \ nxrancid pflogin pfrancid prancid rancid_par rivlogin \ rivrancid rrancid shellrancid shelllogin srancid tlogin \ tntlogin tntrancid telcorancid trancid ubnt-es-rancid \ - ucsrancid urancid vlogin vrancid xrancid xrrancid zrancid zyrancid + ucsrancid urancid vlogin vrancid xrancid xrrancid zrancid zyrancid \ + h3clogin h3crancid CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) @@ -358,7 +360,7 @@ bin_SCRIPTS = agmrancid alogin arancid arrancid avologin avorancid \ telcorancid tlogin tntlogin tntrancid trancid ubnt-es-rancid \ urancid ucsrancid vlogin vrancid xrancid xrrancid zrancid zyrancid \ dlogin drancid shelllogin shellrancid lg.cgi lgform.cgi rancid-cvs \ - rancid-fe rancid-run control_rancid + rancid-fe rancid-run control_rancid h3clogin h3crancid EXTRA_DIST = lg.cgi.in lgform.cgi.in rancid-cvs.in rancid-fe.in rancid-run.in \ control_rancid.in @@ -564,6 +566,10 @@ zrancid: $(top_builddir)/config.status $(srcdir)/zrancid.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ zyrancid: $(top_builddir)/config.status $(srcdir)/zyrancid.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +h3clogin: $(top_builddir)/config.status $(srcdir)/h3clogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +h3crancid: $(top_builddir)/config.status $(srcdir)/h3crancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ diff --git a/bin/rancid-fe.in b/bin/rancid-fe.in index c4432b2..dcdc864 100644 --- a/bin/rancid-fe.in +++ b/bin/rancid-fe.in @@ -96,7 +96,8 @@ $vendor =~ tr/[A-Z]/[a-z]/; 'ubnt-es' => 'ubnt-es-rancid', 'vyos' => 'vrancid', 'zebra' => 'zrancid', - 'zyxel' => 'zyrancid' + 'zyxel' => 'zyrancid', + 'h3c' => 'h3crancid' ); if ($vendortable{$vendor} eq "") { diff --git a/configure b/configure index 327edb9..04997c9 100755 --- a/configure +++ b/configure @@ -6098,6 +6098,10 @@ ac_config_files="$ac_config_files bin/zrancid" ac_config_files="$ac_config_files bin/zyrancid" +ac_config_files="$ac_config_files bin/h3clogin" + +ac_config_files="$ac_config_files bin/h3crancid" + ac_config_files="$ac_config_files share/rtrfilter" @@ -6909,6 +6913,8 @@ do "bin/xrrancid") CONFIG_FILES="$CONFIG_FILES bin/xrrancid" ;; "bin/zrancid") CONFIG_FILES="$CONFIG_FILES bin/zrancid" ;; "bin/zyrancid") CONFIG_FILES="$CONFIG_FILES bin/zyrancid" ;; + "bin/h3clogin") CONFIG_FILES="$CONFIG_FILES bin/h3clogin" ;; + "bin/h3crancid") CONFIG_FILES="$CONFIG_FILES bin/h3crancid" ;; "share/rtrfilter") CONFIG_FILES="$CONFIG_FILES share/rtrfilter" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; @@ -7662,6 +7668,8 @@ $as_echo X"$file" | "bin/xrrancid":F) chmod a+x $ac_file ;; "bin/zrancid":F) chmod a+x $ac_file ;; "bin/zyrancid":F) chmod a+x $ac_file ;; + "bin/h3clogin":F) chmod a+x $ac_file ;; + "bin/h3crancid":F) chmod a+x $ac_file ;; "share/rtrfilter":F) chmod a+x $ac_file ;; esac diff --git a/configure.ac b/configure.ac index a5f00eb..fc1f5c2 100644 --- a/configure.ac +++ b/configure.ac @@ -512,6 +512,8 @@ AC_CONFIG_FILES(bin/xrancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/xrrancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/zrancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/zyrancid, [chmod a+x $ac_file]) +AC_CONFIG_FILES(bin/h3clogin, [chmod a+x $ac_file]) +AC_CONFIG_FILES(bin/h3crancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(share/rtrfilter, [chmod a+x $ac_file]) AC_OUTPUT() From 7da3a08d6707f783957c6045b397ee7242df51d4 Mon Sep 17 00:00:00 2001 From: dsx Date: Thu, 21 Jul 2016 15:30:48 -0400 Subject: [PATCH 14/38] New version of h3c --- bin/h3clogin.in | 293 ++++++++++++++--------- bin/h3crancid.in | 610 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 632 insertions(+), 271 deletions(-) diff --git a/bin/h3clogin.in b/bin/h3clogin.in index abcf6a0..68bd2f8 100755 --- a/bin/h3clogin.in +++ b/bin/h3clogin.in @@ -3,7 +3,7 @@ ## $Id: $ ## ## @PACKAGE@ @VERSION@ -## Copyright (c) 1997-2009 by Terrapin Communications, Inc. +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. ## All rights reserved. ## ## This code is derived from software contributed to and maintained by @@ -43,15 +43,17 @@ # The expect login scripts were based on Erik Sherk's gwtn, by permission. # -# h3clogin - H3C login +# h3clogin # -# h3clogin covers the following product ranges: +# h3clogin/h3crancid covers the following product ranges: # # * 3Com SuperStack 4 (post-joint venture with Huawei) # * H3C # * HP Networking ('A' & some 'E' portfolio, post 2010 3Com acquitision) # -# It may also work with some Huawei equipment. +# They may also work with some Huawei equipment. +# +# https://sites.google.com/site/jrbinks/code/rancid/h3c # # Set to 1 to enable some debugging, or pass "-d" on command line @@ -73,7 +75,7 @@ set password_file $env(HOME)/.cloginrc set do_command 0 set do_script 0 # The default is to automatically enable -set avenable 1 +set avenable 0 # The default is that you login non-enabled (tacacs can have you login already # enabled) set avautoenable 0 @@ -81,38 +83,55 @@ set avautoenable 0 # tracks if we receive them on the command line. set do_passwd 1 set do_enapasswd 1 +# Save config, if prompted set do_saveconfig 0 # Sometimes routers take awhile to answer (the default is 10 sec) set timeoutdflt 45 # set send_human {.1 .3 .7 .05 2} +# spawn tty options +set spawnopts {} + +# H3C: set the platform +# Platform switching: +# If we explcitly want to state the platform, then set default_platform. +# If we want the script to do magic to try and work it out, then set it +# to "". +# We might also consider passing the platform as a command-line parameter, +# or by reading it as a hint from .cloginrc. +set default_platform "h3c" # H3C: some models don't like "3des"; specify "aes128-cbc" in .cloginrc set default_cyphertype "3des" -# H3C: command to elevate priviges (aka "enable") is different +# H3C: most H3C-derived models use "super" to elevate privileges +# However MA5600 uses "enable" set enacmd "super" +set enacmd_alt "enable" # H3C: command to exit from device set exitcmd "quit" # Find the user in the ENV, or use the unix userid. -if {[ info exists env(CISCO_USER) ] } { +if {[info exists env(CISCO_USER)]} { set default_user $env(CISCO_USER) -} elseif {[ info exists env(USER) ]} { +} elseif {[info exists env(USER)]} { set default_user $env(USER) -} elseif {[ info exists env(LOGNAME) ]} { +} elseif {[info exists env(LOGNAME)]} { set default_user $env(LOGNAME) } else { # This uses "id" which I think is portable. At least it has existed # (without options) on all machines/OSes I've been on recently - # unlike whoami or id -nu. - if [ catch {exec id} reason ] { + if [catch {exec id} reason] { send_error "\nError: could not exec id: $reason\n" exit 1 } regexp {\(([^)]*)} "$reason" junk default_user } +if {[info exists env(CLOGINRC)]} { + set password_file $env(CLOGINRC) +} # Process the command line for {set i 0} {$i < $argc} {incr i} { @@ -124,28 +143,28 @@ for {set i 0} {$i < $argc} {incr i} { exp_internal 1 # Username } -u* { - if {! [ regexp .\[uU\](.+) $arg ignore user]} { + if {! [regexp .\[uU\](.+) $arg ignore user]} { incr i - set username [ lindex $argv $i ] + set username [lindex $argv $i] } # VTY Password } -p* { - if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { incr i - set userpasswd [ lindex $argv $i ] + set userpasswd [lindex $argv $i] } set do_passwd 0 # ssh passphrase } -r* { - if {! [ regexp .\[rR\](.+) $arg ignore passphrase]} { + if {! [regexp .\[rR\](.+) $arg ignore passphrase]} { incr i - set vapassphrase [ lindex $argv $i ] + set vapassphrase [lindex $argv $i] } # VTY Password } -v* { - if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { + if {! [regexp .\[vV\](.+) $arg ignore passwd]} { incr i - set passwd [ lindex $argv $i ] + set passwd [lindex $argv $i] } set do_passwd 0 # Version string @@ -154,13 +173,13 @@ for {set i 0} {$i < $argc} {incr i} { exit 0 # Enable Username } -w* { - if {! [ regexp .\[wW\](.+) $arg ignore enauser]} { + if {! [regexp .\[wW\](.+) $arg ignore enauser]} { incr i - set enausername [ lindex $argv $i ] + set enausername [lindex $argv $i] } # Environment variable to pass to -s scripts } -E* { - if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { set E$varname $varvalue } else { send_user "\nError: invalid format for -E in $arg\n" @@ -168,25 +187,25 @@ for {set i 0} {$i < $argc} {incr i} { } # Enable Password } -e* { - if {! [ regexp .\[e\](.+) $arg ignore enapasswd]} { + if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { incr i - set enapasswd [ lindex $argv $i ] + set enapasswd [lindex $argv $i] } set do_enapasswd 0 # Command to run. } -c* { - if {! [ regexp .\[cC\](.+) $arg ignore command]} { + if {! [regexp .\[cC\](.+) $arg ignore command]} { incr i - set command [ lindex $argv $i ] + set command [lindex $argv $i] } set do_command 1 # Expect script to run. } -s* { - if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + if {! [regexp .\[sS\](.+) $arg ignore sfile]} { incr i - set sfile [ lindex $argv $i ] + set sfile [lindex $argv $i] } - if { ! [ file readable $sfile ] } { + if { ! [file readable $sfile] } { send_user "\nError: Can't read $sfile\n" exit 1 } @@ -196,29 +215,29 @@ for {set i 0} {$i < $argc} {incr i} { set do_saveconfig 1 # 'ssh -c' cypher type } -y* { - if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + if {! [regexp .\[eE\](.+) $arg ignore cypher]} { incr i - set cypher [ lindex $argv $i ] + set cypher [lindex $argv $i] } # alternate cloginrc file } -f* { - if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + if {! [regexp .\[fF\](.+) $arg ignore password_file]} { incr i - set password_file [ lindex $argv $i ] + set password_file [lindex $argv $i] } # Timeout } -t* { - if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + if {! [regexp .\[tT\](.+) $arg ignore timeout]} { incr i - set timeoutdflt [ lindex $argv $i ] + set timeoutdflt [lindex $argv $i] } # Command file } -x* { - if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { incr i - set cmd_file [ lindex $argv $i ] + set cmd_file [lindex $argv $i] } - if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + if [catch {set cmd_fd [open $cmd_file r]} reason] { send_user "\nError: $reason\n" exit 1 } @@ -268,7 +287,7 @@ proc label { host } { } # take host from ENV(TERM) if [info exists env(TERM)] { - if [regexp \^(xterm|vs) $env(TERM) ignore ] { + if [regexp \^(xterm|vs) $env(TERM) ignore] { send_user "\033]1;[lindex [split $host "."] 0]\a" send_user "\033]2;$host\a" } @@ -284,7 +303,7 @@ proc add {var args} { global int_$var ; lappend int_$var $args} proc include {args} { global env regsub -all "(^{|}$)" $args {} args - if { [ regexp "^/" $args ignore ] == 0 } { + if { [regexp "^/" $args ignore] == 0 } { set args $env(HOME)/$args } source_password_file $args @@ -294,7 +313,7 @@ proc find {var router} { upvar int_$var list if { [info exists list] } { foreach line $list { - if { [string match [lindex $line 0] $router ] } { + if { [string match [lindex $line 0] $router] } { return [lrange $line 1 end] } } @@ -318,7 +337,7 @@ proc source_password_file { password_file } { send_user "\nError: $password_file must not be world readable/writable\n" exit 1 } - if [ catch {source $password_file} reason ] { + if [catch {source $password_file} reason] { send_user "\nError: $reason\n" exit 1 } @@ -327,8 +346,8 @@ proc source_password_file { password_file } { # Log into the router. # returns: 0 on success, 1 on failure, -1 if rsh was used successfully proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } { - global spawn_id in_proc do_command do_script platform passphrase - global prompt prompt_match u_prompt p_prompt e_prompt sshcmd + global command spawn_id in_proc do_command do_script platform passphrase + global prompt prompt_match u_prompt p_prompt e_prompt sshcmd spawnopts set in_proc 1 set uprompt_seen 0 @@ -337,29 +356,32 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile foreach prog [lrange $cmethod 0 end] { incr progs -1 if [string match "telnet*" $prog] { - regexp {telnet(:([^[:space:]]+))*} $prog command suffix port + regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port if {"$port" == ""} { - set retval [ catch {spawn telnet $router} reason ] + #set retval [catch {spawn telnet $router} reason] + set cmd "telnet $router" } else { - set retval [ catch {spawn telnet $router $port} reason ] + #set retval [catch {spawn telnet $router $port} reason] + set cmd "telnet $router $port" } + set retval [catch {eval spawn $spawnopts [split $cmd { }]} reason] if { $retval } { send_user "\nError: telnet failed: $reason\n" return 1 } } elseif [string match "ssh*" $prog] { # ssh to the router & try to login with or without an identfile. - regexp {ssh(:([^[:space:]]+))*} $prog command suffix port - set cmd [join [lindex $sshcmd 0] " "] + regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port + set cmd $sshcmd if {"$port" != ""} { set cmd "$cmd -p $port" } if {"$identfile" != ""} { set cmd "$cmd -i $identfile" } - set retval [ catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason ] + set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason] if { $retval } { - send_user "\nError: $sshcmd failed: $reason\n" + send_user "\nError: $cmd failed: $reason\n" return 1 } } elseif ![string compare $prog "rsh"] { @@ -379,7 +401,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile set rshfail 0 for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { log_user 0 - set retval [ catch {spawn rsh $user@$router [lindex $commands $i] } reason ] + set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason] if { $retval } { send_user "\nError: rsh failed: $reason\n" log_user 1; return 1 @@ -435,7 +457,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile # return rsh "success" return -1 } else { - puts "\nError: unknown connection method: $prog" + send_user "\nError: unknown connection method: $prog\n" return 1 } sleep 0.3 @@ -469,6 +491,11 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile # then it will just send the passwd. # if telnet fails with connection refused, try ssh expect { + -re "^<-+ More -+>\[^\n\r]*" { + # ASA will use the pager for long banners + send " "; + exp_continue + } -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { catch {close}; catch {wait}; if !$progs { @@ -485,7 +512,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } -nocase "unknown host\r" { - send_user "\nError: Unknown host $router\n"; wait; return 1 + send_user "\nError: Unknown host $router\n"; catch {close}; catch {wait}; return 1 } @@ -499,18 +526,22 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile catch {close}; catch {wait}; return 1 } - -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { + -re "(Host key not found |The authenticity of host .* be established).* \\(yes\/no\\)\\?" { send "yes\r" send_user "\nHost $router added to the list of known hosts.\n" exp_continue } - -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes\/no\\)\\?" { send "no\r" send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" catch {close}; catch {wait}; return 1 } - -re "Offending key for .* \(yes\/no\)\?" { + -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" { + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 + } + -re "Offending key for .* \\(yes\/no\\)\\?" { send "no\r" send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" catch {close}; catch {wait}; @@ -528,7 +559,7 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile send_user "\nError: Check your passwd for $router\n" catch {close}; catch {wait}; return 1 } - "Press any key to continue." { + "Press any key to continue" { # send_user "Pressing the ANY key\n" send "\r" exp_continue @@ -537,15 +568,15 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile # Catalyst 1900s have some lame menu. Enter # K to reach a command-line. send "K\r" - exp_continue; + exp_continue } -re "Last login:" { - exp_continue; + exp_continue } -re "@\[^\r\n]+ $p_prompt" { # ssh pwd prompt sleep 1 - send "$userpswd\r" + send -- "$userpswd\r" exp_continue } -re "Enter passphrase.*: " { @@ -585,39 +616,50 @@ proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile # Enable proc do_enable { enauser enapasswd } { - global prompt in_proc + global do_saveconfig in_proc global prompt u_prompt e_prompt - global enacmd + global enacmd enacmd_alt set in_proc 1 + # Try and determine a bit more about this device to modify behaviour. + # We are careful to use "dis version " rather than the full length + # "display version" to prevent h3crancid matching it. + # (Thx Andrea Gabellini) + send -h "$enacmd\r" expect { - -re "$u_prompt" { send -h -- "$enauser\r"; exp_continue} - -re "$e_prompt" { send -h -- "$enapasswd\r"; exp_continue} + -re "Please input the password to change the privilege level, press CTRL_C to abort.\n" { + exp_continue + } + -re "$u_prompt" { send -h -- "$enauser\r"; exp_continue } + -re "$e_prompt" { send -h -- "$enapasswd\r"; exp_continue } -re ">" { set prompt ">" } - "% Password is not set." { + -re "#" { set prompt "#" } # MA5600 + "% Password is not set." { # H3C send_user "\nError: No 'super' password set for device\n" return 1 } - "% Authenticate failed." { + "% Authenticate failed." { # H3C send_user "\nError: Check your enable password for 'super'\n" return 1 } + +# ciscoisms: # "#" { set prompt "#" } # "(enable)" { set prompt "> \\(enable\\) " } - #-re "(denied|Sorry|Incorrect)" { - # # % Access denied - from local auth and poss. others - # send_user "\nError: Check your Enable passwd\n"; - # return 1 - # } - #"% Error in authentication" { - # send_user "\nError: Check your Enable passwd\n" - # return 1 - # } - #"% Bad passwords" { - # send_user "\nError: Check your Enable passwd\n" - # return 1 - # } +# -re "(denied|Sorry|Incorrect)" { +# # % Access denied - from local auth and poss. others +# send_user "\nError: Check your Enable passwd\n"; +# return 1 +# } +# "% Error in authentication" { +# send_user "\nError: Check your Enable passwd\n" +# return 1 +# } +# "% Bad passwords" { +# send_user "\nError: Check your Enable passwd\n" +# return 1 +# } } # We set the prompt variable (above) so script files don't need # to know what it is. @@ -631,15 +673,29 @@ proc run_commands { prompt command } { global exitcmd set in_proc 1 - # clogin has this beast: - #regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt - # escape any parens in the prompt, such as "(enable)" - regsub -all {[][)(]} $prompt {\\&} reprompt + # clogin has this beast: + #regsub -all {^(.{1,11}).*([#>])$} $prompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt + # If platform H3C: + # Note that if the "system-view" command is sent to go into configuration + # mode, the prompt changes from to [prompt], so we need to ensure + # that $reprompt will handle either. + send_user -- "Prompt: $prompt\n" + # Strip inital and leading <> + regsub -all {^<} $prompt {} prompt + regsub -all {>\a?$} $prompt {} prompt + #send_user -- "Prompt: $prompt\n" + # Escape special characters to be treated as literals + regsub -all {[][)(]} $prompt {\\&} prompt + # Prefix and suffix with regexps to match the sets <[ and ]> + set xlist [list {.*} $prompt {.*\a?}] + set reprompt [join $xlist ""] + send_user -- "REPrompt: $reprompt\n" + send_user -- "Prompt: $prompt\n" - expect { - -re $reprompt {} - -re "\[\n\r]+" { exp_continue } - } + expect { + -re ($reprompt|$prompt) { } + -re "\[\n\r]+" { exp_continue } + } # this is the only way i see to get rid of more prompts in o/p..grrrrr log_user 0 @@ -652,32 +708,39 @@ proc run_commands { prompt command } { send -- "[subst -nocommands [lindex $commands $i]]\r" expect { -re "\b+" { exp_continue } - -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" + -re "^\[^\n\r *]*($reprompt|$prompt)" { send_user -- "$expect_out(buffer)" } -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" exp_continue } -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" exp_continue } - -re "^ ---- More ----.*\[^\n\r]*" { + -re "^ {0,2}-+ More .*-+.*\[^\n\r]*" { # H3C pager prompt sleep 0.1 send " " exp_continue } + -re "^---- More ----\[^\n\r]*" { + # Comware7 pager prompt + sleep 0.1 + send " " + exp_continue } } - } +# clogin has introduced this change to the "\[\n\r]+" clause above in r2313 +# June2011: +# "trying to make sure it pulls full lines each time." +# -re "\[^\r\n]*\[\n\r]+" log_user 1 send -h "$exitcmd\r" - # H3C: the exit command leaves the switch completely; it does not - # prompt to save if the config has been modified expect { # -re "^\[^\n\r *]*$reprompt" { -# # H3C products -# # return to non-enabled mode -# # on exit in enabled mode. +# # H3C: +# # they return to non-enabled +# # mode with "exit" from +# # enabled mode. # send -h "$exitcmd\r" # exp_continue; # } @@ -687,7 +750,7 @@ proc run_commands { prompt command } { # exp_continue # } -re "\[\n\r]+" { exp_continue } -# hwlogin+mod: +# variant from hwlogin: -re "\[^\n\r *]Note:" { return 0 } timeout { catch {close}; catch {wait}; return 0 @@ -705,6 +768,12 @@ set in_proc 0 set exitval 0 set prompt_match "" set enable 0 +# if we have dont have a tty, we need some additional terminal settings +if [catch {stty} reason] { + # no tty, ie: cron + set spawnopts "-nottycopy" + set stty_init "cols 132" +} foreach router [lrange $argv $i end] { set router [string tolower $router] # attempt at platform switching. @@ -719,6 +788,9 @@ foreach router [lrange $argv $i end] { # Default prompt. #set prompt "(>|#| \\(enable\\))" + # H3C: Could we be logged in already in a privilged ("super") mode, + # with the "[....]" prompt? If so, then this might be: + #set prompt "(>|])\a?" set prompt ">\a?" # look for noenable option in .cloginrc @@ -730,11 +802,11 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] if { [llength $pswd] == 0 } { - send_user "\nError: no password for $router in $password_file.\n" + send_user -- "\nError: no password for $router in $password_file.\n" continue } if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { - send_user "\nError: no enable password for $router in $password_file.\n" + send_user -- "\nError: no enable password for $router in $password_file.\n" continue } set passwd [join [lindex $pswd 0] ""] @@ -774,7 +846,7 @@ foreach router [lrange $argv $i end] { # Figure out prompts set u_prompt [find userprompt $router] if { "$u_prompt" == "" } { - set u_prompt "(Username|Login|login|user name|User):" + set u_prompt "(Username|Login|login|user name|User|User name):" } else { set u_prompt [join [lindex $u_prompt 0] ""] } @@ -818,7 +890,7 @@ foreach router [lrange $argv $i end] { if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } # Figure out the SSH executable name - set sshcmd [find sshcmd $router] + set sshcmd [join [lindex [find sshcmd $router] 0] ""] if { "$sshcmd" == "" } { set sshcmd {ssh} } # Login to the router @@ -827,10 +899,8 @@ foreach router [lrange $argv $i end] { # if login failed or rsh was unsuccessful, move on to the next device continue } - # Figure out the prompt. - -# H3C: this is what we used to have, now should be obsolete: + # H3C: this is what we used to have, now should be obsolete: # # Since autoenable is off by default, if we have it defined, it # # was done on the command line. If it is not specifically set on the # # command line, check the password file. @@ -882,6 +952,7 @@ foreach router [lrange $argv $i end] { } } # } + if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { @@ -895,22 +966,14 @@ foreach router [lrange $argv $i end] { send "\r" expect { -re "\[\r\n]+" { exp_continue; } -# -re "^(.+\[:.])1 ($prompt)" { # stoopid extreme cmd-line numbers and -# # prompt based on state of config changes, -# # which may have an * at the beginning. -# set junk $expect_out(1,string) -# regsub -all "^\\\* " $expect_out(1,string) {} junk -# regsub -all "\[\]\[\(\)]" $junk {\\&} junk; -# set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; -# set platform "extreme" -# } -re "^.+$prompt" { set junk $expect_out(0,string); regsub -all "\[\]\[\(\)]" $junk {\\&} prompt; } } - # H3C: Disable log junk being sent to terminal: must be done before - # $enacmd is run. It would be nice for this to be setable in .cloginrc + # H3C: + # Disable log junk being sent to terminal: must be done before $enacmd + # is run. It would be nice for this to be setable in .cloginrc send -h "undo terminal monitor\r" expect -re $prompt {} @@ -920,7 +983,7 @@ foreach router [lrange $argv $i end] { # a vty basis # clogin does this only within the do_script clause below, but I can't # see why you wouldn't want it here, covering do_command too - send -h "screen-length disable\r" + send -h "screen-length 0 temporary\r" #expect -re $prompt {} if { $do_command } { diff --git a/bin/h3crancid.in b/bin/h3crancid.in index 28c5d46..e7a7501 100755 --- a/bin/h3crancid.in +++ b/bin/h3crancid.in @@ -3,7 +3,7 @@ ## $Id: $ ## ## @PACKAGE@ @VERSION@ -## Copyright (c) 1997-2009 by Terrapin Communications, Inc. +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. ## All rights reserved. ## ## This code is derived from software contributed to and maintained by @@ -43,57 +43,76 @@ # RANCID - Really Awesome New Cisco confIg Differ # -# # h3crancid # # h3clogin/h3crancid covers the following product ranges: # -# * 3Com SuperStack 4 (post-joint venture with Huawei) +# * 3Com SuperStack 4 (from 'joint venture' with Huawei) # * H3C -# * HP Networking ('A' & some 'E' portfolio, post 2010 3Com acquitision) +# * HP Networking ('A' & some 'E' portfolio, post-2010 3Com acquitision) # # They may also work with some Huawei equipment. # # https://sites.google.com/site/jrbinks/code/rancid/h3c -# # -# Usage: h3crancid [-dV] [-l] [-f filename | hostname] +# Usage: h3crancid [-dltCV] [-f filename | hostname] # +# You can modify the behaviour by changing the variables listed in +# 'END-USER TWEAKS', below. + # Notable changes from standard *rancid programs: # -# * abstracted to path to the 'tail' utility +# * abstracted path to the 'tail' utility # * altered "cisco_cmds" to be "device_cmds" # * define and use $logincmd -# +# * abstracted $rancid_type # TODO: # # It may be useful to pull common subroutines like the sorting ones into # a library for use by all the *rancid programs. # +# abstract the comment-out char (i.e., '!' here and cisco, '#' on Juniper) +# to a variable. + +# NOTES: +# +# * the dir commands need a user greater than at least level 1 on some +# platforms ############################################################################ # END-USER TWEAKS # The login program to use. If no path is given, $PATH is searched: -#my $logincmd = "h3clogin99"; my $logincmd = "h3clogin"; #my $logincmd = "/usr/local/libexec/h3clogin"; # +my $TAIL = "/usr/bin/tail"; +# # Enable display of the FIB: -my $display_fib = 1; +my $display_fib = 0; # # Enable display of the routing table: -# (no-op) -#my $display_iproutes = 1; +my $display_iproutes = 0; +# +# Enable display of the vlans: +my $display_vlan_all = 0; +# +# Enable display of STP root: +my $display_stproot = 0; +# +# Enable display of transceiver interface: +my $display_xcvr_int = 0; # END OF END-USER TWEAKS ############################################################################# +my $rancid_type = 'h3c'; + use Getopt::Std; -getopts('dflV'); +getopts('dflt:CV'); if ($opt_V) { print "@PACKAGE@ @VERSION@\n"; exit(0); @@ -107,8 +126,6 @@ $found_end = 0; #$timeo = 90; # login command timeout in seconds $timeo = 20; # login command timeout in seconds -my $TAIL = "/usr/bin/tail"; - my(@commandtable, %commands, @commands);# command lists my($aclsort) = ("ipsort"); # ACL sorting mode my($filter_commstr); # SNMP community string filtering @@ -118,20 +135,20 @@ my($filter_pwds); # password filtering mode sub ProcessHistory { my($new_hist_tag,$new_command,$command_string,@string)=(@_); if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) - && defined %history) { - print eval "$command \%history"; - undef %history; + && 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"; - } + 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"; + $history{++$#history} = "@string"; } else { - print "@string"; + print "@string"; } $hist_tag = $new_hist_tag; $command = $new_command; @@ -147,8 +164,8 @@ sub keynsort { local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { - $sorted_lines[$i] = $lines{$key}; - $i++; + $sorted_lines[$i] = $lines{$key}; + $i++; } @sorted_lines; } @@ -160,8 +177,8 @@ sub keysort { local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { - $sorted_lines[$i] = $lines{$key}; - $i++; + $sorted_lines[$i] = $lines{$key}; + $i++; } @sorted_lines; } @@ -185,8 +202,8 @@ sub numsort { local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { - $sorted_lines[$i] = $lines{$num}; - $i++; + $sorted_lines[$i] = $lines{$num}; + $i++; } @sorted_lines; } @@ -199,8 +216,8 @@ sub ipsort { local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { - $sorted_lines[$i] = $lines{$addr}; - $i++; + $sorted_lines[$i] = $lines{$addr}; + $i++; } @sorted_lines; } @@ -208,19 +225,40 @@ sub ipsort { # 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])); + $a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0])); } sub sortbyipaddr { &ipaddrval($a) <=> &ipaddrval($b); } +# This is a sort routine that will sort on the +# ip route when the ip route is anywhere in +# the strings. +sub iproutesort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $iproute (sort sortbyiproute keys %lines) { + $sorted_lines[$i] = $lines{$iproute}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP route +sub iprouteval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#); + $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0]))); +} +sub sortbyiproute { + &iprouteval($a) <=> &iprouteval($b); +} + sub filter_lines { my ($l) = (@_); -# print STDERR " In filterlines: $l\n" if ($debug); # Filter out some ANSI crud as a result of us not being able to turn # off per-session terminal paging: - # h3c: #s/^\033\[42D +\033\[42D(.+)$/$1/; # hwlogin+mods: #s/\033\133\064\062\104\s*\033\133\064\062\104//g; @@ -228,113 +266,330 @@ sub filter_lines { $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g; $l =~ s/\033\133\064\062\104//g; $l =~ s/\033\133\061\062\104//g; + $l =~ s/.*\[37D(.*)/$1/g; # MA5600 # Probably not needed: $l =~ s/\s*---- More ----\s*//; -# print STDERR "out: $l\n" if ($debug); + $l =~ s/^ //; # Comware7 + $l =~ s/Synchronization is finished.//g; return $l; } sub DisplayFib { - ## We should probably guarantee that the FIB is sorted properly + print STDERR " In DisplayFib: $_" if ($debug); - return(1) if $display_fib == 0; chomp; # Display the command we're processing in the output: - s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; - ProcessHistory("COMMENTS","keysort","A0","! $_\n!\n"); + #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + ProcessHistory("FIB","","","!\n! '$cmd':\n!\n"); while () { tr/\015//d; - last if(/^$prompt/); + last if(/^\s*$prompt/); chomp; - # skip blank lines - return(1) if /^\s+\^$/; $_ = filter_lines($_); + return(1) if ( + /^\s+\^$/ || + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ || + /Permission denied\./ + ); + + next if /^$/; + next if /^Destination count: \d+ FIB entry count: \d+/; + + # Chop out some detail that changes over time (Comware 3): + s/(\s+)TimeStamp\s+/$1/; # TimeStamp column heading + + ProcessHistory("FIB","","","! $_\n"); + + if ( m,Destination/Mask, ) { + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + # Chop out some detail that changes over time (Comware 3): + s/(\s+)t\[\d+\]\s+/$1/; # TimeStamp data + + # "display fib" on comware7 shows host entries for things + # learned via arp too. For a distribution router, that's all + # the devices on subnets routed by it! + # If we filter out all "UH" entries that are NOT InLoop, we + # get acceptable output. + # + # So we want to keep: + # + # 0.0.0.0/32 127.0.0.1 UH InLoop0 Null + # + # but reject: + # + # 130.159.44.161/32 130.159.44.161 UH Vlan44 Null + # + # However I've a feeling that this is a problematic + # solution, and some object to the notion that rancid + # should be representing such potentially dynamic data in + # the first place, which is why we created the + # $display_fib flag. + + ($dest, $nexthop, $flag, $outint, $label) = split; + next if ( $flag eq 'UH' && $outint !~ /InLoop/ ); + ProcessHistory("FIB", "iproutesort", "$dest", "! $_\n"); + } + + ProcessHistory("FIB", "", "", "!\n"); + + # return here to ensure that we don't keep swallowing the + # next command's output by returning to the surrounding + # while loop + return(0); + } + } + return(0); +} - # make this a subroutine: - return(1) if /% Too many parameters found at '\^' position/; - return(1) if /% Unrecognized command found at '\^' position/; - return(1) if /% Wrong parameter found at '\^' position/; - return(1) if /% Wrong device .+/; +sub DisplayIPRoutes { + print STDERR " In DisplayIPRoutes: $_" if ($debug); - # Chop out some detail that changes over time: - s/(\s+)TimeStamp\s+/$1/; - s/(\s+)t\[\d+\]\s+/$1/; + chomp; + + # Display the command we're processing in the output: + #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + ProcessHistory("IPR","","","!\n! '$cmd':\n!\n"); - ProcessHistory("COMMENTS","ipsort","A0","! $_\n"); - #ProcessHistory("COMMENTS","keysort","A0","! $_\n"); + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + return(1) if ( + /^\s+\^$/ || + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ || + /Permission denied\./ + ); + + ProcessHistory("IPR","","","! $_\n"); + + if ( m,Destination/Mask, ) { + my $lastkey = ""; + my $lastspaces = ""; + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + # If the key is blank, indicating multiple nexthops for + # a particular route, then we use the previous one + if ( m/^\s+(.+)/ ) { + $key = $lastkey; + $line = $key . $lastspaces . $1; + ProcessHistory("IPR", "iproutesort", "$key", "! $line\n"); + # $lastkey and $lastspaces are retained in case + # they are needed for an additional line + } + if ( m/^(\S+)(\s+).+/ ) { + $key = $1; + $line = $_; + $spaces = $2; + ProcessHistory("IPR", "iproutesort", "$key", "! $line\n"); + $lastkey = $key; + $lastspaces = $spaces; + } + } + +# This isn't quite right; for example, it messes up oddities like this: +# ... +# 130.159.2.84/30 OSPF 10 1010 10.159.2.53 Vlan3660 +# 130.159.2.88/30 OSPF 10 1100 10.159.2.53 Vlan3660 +# OSPF 10 1100 10.159.2.49 Vlan3661 +# 130.159.2.92/30 OSPF 10 1015 10.159.2.53 Vlan3660 +# ... + + ProcessHistory("IPR", "", "", "!\n"); + + # return here to ensure that we don't keep swallowing the + # next command's output by returning to the surrounding + # while loop + return(0); + } } - ProcessHistory("COMMENTS","keysort","A0","! \n"); return(0); } +#sub DisplayTransInt { +# print STDERR " In DisplayTransInt: $_" if ($debug); +# +# chomp; +# +# # Display the command we're processing in the output: +# s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; +# ProcessHistory("TRINT","","","! $_\n!\n"); +# +# while () { +# tr/\015//d; +# last if(/^\s*$prompt/); +# chomp; +# $_ = filter_lines($_); +# return(1) if ( +# /^\s+\^$/ || +# /% Too many parameters found at '\^' position/ || +# /% Unrecognized command found at '\^' position/ || +# /(% )?Wrong parameter found at '\^' position/ || +# /% Wrong device .+/ || +# /Permission denied\./ +# ); +# +# +# ProcessHistory("TRINT","","","! $_\n"); +# } +# ProcessHistory("TRINT","","","!\n"); +# return(0); +#} + +#sub DisplayNTPStatus { +# print STDERR " In DisplayNTPStatus: $_" if ($debug); +# +# chomp; +# +# # Display the command we're processing in the output: +# s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; +# ProcessHistory("NTP","","","! $_\n!\n"); +# +# while () { +# tr/\015//d; +# last if(/^\s*$prompt/); +# chomp; +# $_ = filter_lines($_); +# return(1) if ( +# /^\s+\^$/ || +# /% Too many parameters found at '\^' position/ || +# /% Unrecognized command found at '\^' position/ || +# /(% ?)Wrong parameter found at '\^' position/ || +# /% Wrong device .+/ || +# /Permission denied\./ +# ); +# +# next unless m/(Clock status|Clock stratum|Reference clock ID)/; +# +# ProcessHistory("NTP","","","! $_\n"); +# } +# ProcessHistory("NTP","","","!\n"); +# return(0); +#} -# This routine processes general output of "display" commands +## This routine processes general output of "display" commands sub CommentOutput { print STDERR " In CommentOutput: $_" if ($debug); chomp; # Display the command we're processing in the output: - s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; - ProcessHistory("","","","! $_\n!\n"); + #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + #ProcessHistory("COMMENTS", "", "", "! $_\n!\n"); + #(my $cmd = $_) =~ s/^[\[<].*?[\]>]\a?\s?(.*)/$1/g; + ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n"); - # eat the header line -# $junk = ; - # now just copy it mostly verbatim to the history file while () { tr/\015//d; # If we find the prompt, we're done - #last if(/^<.*>/); - last if(/^$prompt/); + # Ordinarily this matches from the start of the line, however + # we've seen circumstances at least in Comware7 where the + # prompt is preceded by whitespace, like so: + # ^M^M ^Mdisplay boot-loader^M + last if(/^\s*$prompt/); chomp; - # skip blank lines - return(1) if /^\s+\^$/; - + # filter out some junk $_ = filter_lines($_); - # Filter out some ANSI crud as a result of us not being able to turn - # off per-session terminal paging: - # h3c: - #s/^\033\[42D +\033\[42D(.+)$/$1/; - # hwlogin+mods: - #s/\033\133\064\062\104\s*\033\133\064\062\104//g; -# s/\033\133\064\062\104\s+\033\133\064\062\104//g; -# s/\033\133\061\066\104\s+\033\133\061\066\104//g; - #s/\033\133\064\062\104//g; - # Probably not needed: -# s/\s*---- More ----\s*//; - - # make this a subroutine: # Some commands are not supported on some models or versions # of code. These lines simply remove the associated error # messages: - return(1) if /% Too many parameters found at '\^' position/; - return(1) if /% Unrecognized command found at '\^' position/; - return(1) if /% Wrong parameter found at '\^' position/; - return(1) if /% Wrong device .+/; + return(1) if ( + /^\s+\^$/ || + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ || + /Permission denied\./ + ); + + # Now we skip or modify some lines from various commands to + # remove irrelevant content, or to avoid insignificant diffs + + # 'display local-user': + s/\s+Current AccessNum:.+$//; - # Parts of the output of some commands changes over time, but we don't - # want these changes to trigger a rancid notification, so we - # filter them out: + # 'display version': + next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/); + # No longer necessary since skipping the whole Uptime line: + # Mangle these lines: + #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/; + #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/; + + # MSRs display a 'last reboot' time, but sometimes the seconds + # vary by one or two (presumably internal rounding), so simply make + # the last digit a fixed '0'. It would probably be safer to make + # the last two digits a fixed '00'. + # (Thx Alexander Belokopytov) + s/(^Last reboot.+)\d$/${1}0/; + + # 'dir ' commands + if ( $cmd =~ /^dir / ) { + # First field is just an index number, chop it out + s/^\s+\d+\s+(.+)/ $1/; + # Remove filenames that are updated frequently + next if ( + /logfile\.log$/ || + /lauth\.dat$/ || + /ifindex\.dat$/ || + /startup\.mdb$/ || + /private-data\.txt$/ || + /.+ KB total \(.+ KB free/ || + /.+ KB total \(.+ KB free/ || + /\.trash/ + ); + } - # This is part of one line, just cut it out: - s/\s+Current AccessNum:.+$//; + # 'display ospf brief'/'display ospf' + if ( $cmd =~ 'display ospf( brief)?' ) { + #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/); + next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i); + } - if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/) { - next; + if ( $cmd eq 'display power' ) { + next if (/^(\s+Input Power).+$/); + } + + if ( $cmd eq 'display poe powersupply' ) { + next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/); } - s/(.*)uptime.*days*.*hours*.*minutes*(.*)/$1 $2/; + if ( $cmd eq 'display ntp-service status' ) { + next unless m/(Clock status|Clock stratum|Reference clock ID)/i; + } + + if ( $cmd eq 'display transceiver interface' ) { + s/^(\S+ transceiver information:).+$/$1/; # filter random garbage + s/^Error: The transceiver is absent.$/ No transceiver present./; + s/^Error: The combo port is inactive.$/ Inactive combo port./; + } - ProcessHistory("","","","! $_\n"); + # Add the processed lines to the output buffer: + ProcessHistory("COMMENTS","","","! $_\n"); } - ProcessHistory("","","","! \n"); + # Add a blank comment line to the output buffer + ProcessHistory("COMMENTS", "", "", "!\n"); return(0); } @@ -342,39 +597,43 @@ sub CommentOutput { sub DisplayCurrent { print STDERR " In DisplayCurrent: $_" if ($debug); + # We aren't chomping these lines + while () { - tr/\015//d; - last if(/^$prompt/); + tr/\015//d; + last if(/^\s*$prompt/); $_ = filter_lines($_); + return(0) if ($found_end); - # Filter out some ANSI crud as a result of us not being able to turn - # off per-session terminal paging: - # h3c: - #s/^\033\[42D +\033\[42D(.+)$/$1/; - # hwlogin+mods: - #s/\033\133\064\062\104\s*\033\133\064\062\104//g; -# s/\033\133\064\062\104\s+\033\133\064\062\104//g; -# s/\033\133\061\066\104\s+\033\133\061\066\104//g; -# s/\033\133\064\062\104//g; - # Probably not needed: -# s/\s*---- More ----\s*//; + # Filter out some sensitive data: + if ( $filter_commstr && + /^ ?(snmp-agent (usm-user|community (read|write)) )(\S+)/ + ) { + ProcessHistory("","","","! $1$'"); + next; + } + if ( $filter_pwds >= 1 && + /^ ?(password (?:simple|cipher) )(\S+)/ || + /^ ?(super password( level \d)? (cipher|simple)) (\S+)/ || + /^ ?(set authentication password (cipher|simple)) (\S+)/ || + /^ ?(key (?:authentication|accounting) )(\S+)/ + ) { + ProcessHistory("","","","! $1$'"); + next; + } - # Filter out some sensitive data: - if (/^( ?snmp-agent community (read|write) )(\S+)/ && - $filter_commstr == 0) { - ProcessHistory("","","","!$1$'"); - next; - } + # Filter mac addresses dynamically added to config + next if (/^ ?mac-address security.+$/); - ProcessHistory("","","","$_"); + ProcessHistory("", "", "", "$_"); - # end of config + # end of config - if (/^return/) { - $found_end = 1; - return(0); - } + if (/^return/) { + $found_end = 1; + return(0); + } } return(0); } @@ -386,48 +645,80 @@ sub DoNothing {print STDOUT;} ## Not all commands are supported on all models and code versions ## Not all of these should necessarily be included @commandtable = ( +# Commands relating to the operating system/version: {'display version' => 'CommentOutput'}, - {'display boot-loader' => 'CommentOutput'}, - {'dir /all unit1>flash:/' => 'CommentOutput'}, - {'dir /all unit2>flash:/' => 'CommentOutput'}, - {'dir /all unit3>flash:/' => 'CommentOutput'}, - {'dir /all unit4>flash:/' => 'CommentOutput'}, - {'dir /all unit5>flash:/' => 'CommentOutput'}, - {'dir /all unit6>flash:/' => 'CommentOutput'}, - {'dir /all unit7>flash:/' => 'CommentOutput'}, - {'dir /all unit8>flash:/' => 'CommentOutput'}, +# {'display boot-loader' => 'CommentOutput'}, + {'display startup' => 'CommentOutput'}, + {'dir /all /all-filesystems' => 'CommentOutput'}, +# {'dir /all unit2>flash:/' => 'CommentOutput'}, +# {'dir /all slot2#flash:/' => 'CommentOutput'}, +# {'dir /all unit3>flash:/' => 'CommentOutput'}, +# {'dir /all slot3#flash:/' => 'CommentOutput'}, +# {'dir /all unit4>flash:/' => 'CommentOutput'}, +# {'dir /all slot4#flash:/' => 'CommentOutput'}, +# {'dir /all unit5>flash:/' => 'CommentOutput'}, +# {'dir /all slot5#flash:/' => 'CommentOutput'}, +# {'dir /all unit6>flash:/' => 'CommentOutput'}, +# {'dir /all slot6#flash:/' => 'CommentOutput'}, +# {'dir /all unit7>flash:/' => 'CommentOutput'}, +# {'dir /all slot7#flash:/' => 'CommentOutput'}, +# {'dir /all unit8>flash:/' => 'CommentOutput'}, +# {'dir /all slot8#flash:/' => 'CommentOutput'}, +# Commands relating to the hardware: {'display device' => 'CommentOutput'}, - {'display device manuinfo' => 'CommentOutput'}, - {'display irf' => 'CommentOutput'}, - {'display xrn-fabric' => 'CommentOutput'}, - {'display ftm topology-database' => 'CommentOutput'}, +# {'display device manuinfo' => 'CommentOutput'}, {'display fan' => 'CommentOutput'}, {'display power' => 'CommentOutput'}, - {'display poe powersupply' => 'CommentOutput'}, - {'display poe temperature-protection' => 'CommentOutput'}, - {'display cluster' => 'CommentOutput'}, +# {'display poe powersupply' => 'CommentOutput'}, +# {'display poe temperature-protection' => 'CommentOutput'}, +# {'display transceiver interface' => 'CommentOutput'}, +# Commands relating to authentication: +# {'display cluster' => 'CommentOutput'}, {'display domain' => 'CommentOutput'}, {'display local-user' => 'CommentOutput'}, - {'display password-control' => 'CommentOutput'}, - {'display password-control super' => 'CommentOutput'}, +# {'display password-control' => 'CommentOutput'}, +# {'display password-control super' => 'CommentOutput'}, {'display ssh server status' => 'CommentOutput'}, - {'display fib' => 'DisplayFib'}, - {'display vlan all' => 'CommentOutput'}, - {'display ip routing-table' => 'CommentOutput'}, - {'display lacp sys' => 'CommentOutput'}, - {'display link-aggregation summary' => 'CommentOutput'}, - {'display link-aggregation verbose' => 'CommentOutput'}, - {'display mirror all' => 'CommentOutput'}, +# Commands relating to system state: +# {'display irf' => 'CommentOutput'}, +# {'display xrn-fabric' => 'CommentOutput'}, +# {'display ftm topology-database' => 'CommentOutput'}, +# {'display fib' => 'DisplayFib'}, +# {'display ip routing-table' => 'DisplayIPRoutes'}, +# {'display ospf' => 'CommentOutput'}, +# {'display ospf brief' => 'CommentOutput'}, +# {'display vlan all' => 'CommentOutput'}, +# {'display lacp sys' => 'CommentOutput'}, +# {'display link-aggregation summary' => 'CommentOutput'}, +# {'display link-aggregation verbose' => 'CommentOutput'}, +# {'display mirror all' => 'CommentOutput'}, + {'display ntp-service status' => 'CommentOutput'}, +# {'display stp root' => 'CommentOutput'}, +# And the system config itself: {'display current-configuration' => 'DisplayCurrent'}, ); +# Remove some commands from the comman table if the user has toggled the +# options not to execute them +if ($display_fib == 0) + { grep(delete $$_{'display fib'} , @commandtable) }; +if ($display_iproutes == 0) + { grep(delete $$_{'display ip routing-table'} , @commandtable) }; +if ($display_vlan_all == 0) + { grep(delete $$_{'display vlan all'} , @commandtable) }; +if ($display_stproot == 0) + { grep(delete $$_{'display stp root'} , @commandtable) }; +if ($display_xcvr_int == 0) + { grep(delete $$_{'display transceiver interface'} , @commandtable) }; + # 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); +$commandcnt = scalar(keys %commands); $device_cmds=join(";",@commands); -$cmds_regexp=join("|",@commands); +$cmds_regexp=join("|", map quotemeta($_), @commands); if (length($host) == 0) { if ($file) { @@ -438,6 +729,10 @@ if (length($host) == 0) { exit(1); } } +if ($opt_C) { + print "$logincmd -t $timeo -c\'$commandstr\' $host\n"; + exit(0); +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -481,7 +776,7 @@ if ($ENV{"FILTER_PWDS"} =~ /no/i) { $filter_pwds = 1; } -ProcessHistory("","","","!RANCID-CONTENT-TYPE: h3c\n!\n"); +ProcessHistory("","","","!RANCID-CONTENT-TYPE: $rancid_type\n!\n"); #ProcessHistory("COMMENTS","keysort","B0","!\n"); #ProcessHistory("COMMENTS","keysort","D0","!\n"); #ProcessHistory("COMMENTS","keysort","F0","!\n"); @@ -493,7 +788,7 @@ TOP: while() { # if (/\#exit$/) { # if (/\#quit$/) { # h3c: - if (/[\]>]\a?\s*quit/) { + if (/[\]>#]\a?\s*quit/) { # if (/^[\[<].*[\]>]\a?\s?quit/) { $clean_run=1; last; @@ -506,27 +801,28 @@ TOP: while() { } # while (/#\s*($cmds_regexp)\s*$/) { # h3c: - while (/[\]>]\a?\s*($cmds_regexp)\s*$/) { + while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) { # while (/^[\[<].*[\]>]\a?\s*($cmds_regexp)\s*$/) { $cmd = $1; if (!defined($prompt)) { # h3c: # Extract the prompt: look for something not [ or < at the start - # of the line, until either ] or > is reached: + # of the line, until either ] or > or # is reached: #$prompt = ($_ =~ /^([^#]+#)/)[0]; #$prompt =~ s/([][}{)(\\])/\\$1/g; #$prompt = ($_ =~ /^([^\]>]+[\]>]\007?)/)[0]; - $prompt = ($_ =~ /^([^\]>]+[\]>]\a?)/)[0]; + $prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; $prompt =~ s/([][}{)(\\])/\\$1/g; 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}}; + $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd); delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; @@ -549,14 +845,16 @@ printf(STDOUT "$host: clean_run=$clean_run found_end=$found_end\n") 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))); - printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + if (scalar(keys %commands) eq $commandcnt) { + printf(STDERR "$host: missed cmd(s): all commands\n"); + } elsif (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); } if (!$clean_run || !$found_end) { - print STDOUT "$host: End of run not found\n"; - print STDERR "$host: End of run not found\n" if ($debug); - system("$TAIL -1 $host.new"); + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("$TAIL -1 $host.new"); } unlink "$host.new" if (! $debug); } From e3a4dce49e3a0af90f4005b56a9eb43ea8bad250 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 18 Feb 2016 11:49:26 -0500 Subject: [PATCH 15/38] Merge in changes to nxrancid.in from upstream 3.3 The main additions are additional error checking for invalid commands that caused the run to fail on certain Nexus devices. Remove commented out and unnecessary code. --- bin/nxrancid.in | 761 +++++++++++++++++++++--------------------------- 1 file changed, 339 insertions(+), 422 deletions(-) diff --git a/bin/nxrancid.in b/bin/nxrancid.in index fa27d84..62a9f00 100644 --- a/bin/nxrancid.in +++ b/bin/nxrancid.in @@ -3,7 +3,7 @@ ## $Id: nxrancid.in 2321 2011-07-29 20:40:40Z heas $ ## ## @PACKAGE@ @VERSION@ -## Copyright (c) 1997-2008 by Terrapin Communications, Inc. +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. ## All rights reserved. ## ## This code is derived from software contributed to and maintained by @@ -169,57 +169,73 @@ sub ShowVersion { print STDERR " In ShowVersion: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - if (/^Cisco Nexus Operating System/) { $type = "NXOS";} - if (/^Software$/) { - while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^\s*$cmd\s*$/); + if (/^Cisco Nexus Operating System/) { $type = "NXOS";} + if (/^Software$/) { + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^\s*$cmd\s*$/); - if (/^$/) { - goto EndSoftware; - } - /\s*([^:]*:)\s*(.*)$/ && ProcessHistory("COMMENTS","keysort","C1", "!Software: $1 $2\n") && next; - } - } + if (/^$/) { + goto EndSoftware; + } + /\s*([^:]*:)\s*(.*)$/ && + ProcessHistory("COMMENTS","keysort","C1", + "!Software: $1 $2\n") && next; + } + } EndSoftware: - if (/^Hardware$/) { - while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^\s*$cmd\s*$/); - - if (/^$/) { - goto EndHardware; - } - if (/^\s*(.*) CPU\s*with (\d*) kB(.*)$/) { - my($tmp) = int($2 / 1024); - ProcessHistory("COMMENTS","keysort","A2", "!Hardware: $1 CPU with $tmp MB$3\n"); - next; - } - if (/^\s*(.*)\s*with (\d*) kB(.*)$/) { - my($tmp) = int($2 / 1024); - ProcessHistory("COMMENTS","keysort","A2", "!Hardware: $1with $tmp MB$3\n"); - next; - } - /^\s*(.*)$/ && ProcessHistory("COMMENTS","keysort","A2", "!Hardware: $1\n") && next; - } - } + if (/^Hardware$/) { + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^\s*$cmd\s*$/); + + if (/^\s*cisco (Nexus[ \d]+) /) { + # cisco Nexus7000 C7010 (10 Slot) Chassis ("Supervisor module-1X") + # cisco Nexus7000 C7018 (18 Slot) Chassis ("Supervisor module-1X") + # cisco Nexus5548 Chassis ("O2 32X10GE/Modular Supervisor") + # cisco Nexus 4000 Chassis ("20x10GE/supervisor") + $proc = $1; + } + + if (/^$/) { + goto EndHardware; + } + if (/^\s*(.*) CPU\s*with (\d*) kB(.*)$/) { + my($tmp) = int($2 / 1024); + ProcessHistory("COMMENTS","keysort","A2", + "!Hardware: $1 CPU with $tmp MB$3\n"); + next; + } + if (/^\s*(.*)\s*with (\d*) kB(.*)$/) { + my($tmp) = int($2 / 1024); + ProcessHistory("COMMENTS","keysort","A2", + "!Hardware: $1with $tmp MB$3\n"); + next; + } + /^\s*(.*)$/ && + ProcessHistory("COMMENTS","keysort","A2", + "!Hardware: $1\n") && next; + } + } EndHardware: - if (/^\s+(bootflash|slot0):\s+(\d+) kB(.*)$/) { - my($tmp) = int($2 / 1024); - ProcessHistory("COMMENTS","keysort","B1", "!Memory: $1: $tmp MB$3\n"); - next; - } + if (/^\s+(bootflash|slot0):\s+(\d+) kB(.*)$/) { + my($tmp) = int($2 / 1024); + ProcessHistory("COMMENTS","keysort","B1", + "!Memory: $1: $tmp MB$3\n"); + next; + } } @@ -242,6 +258,7 @@ sub ShowVersionBuild { return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -265,6 +282,7 @@ sub ShowLicense { next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -287,6 +305,7 @@ sub ShowRedundancy { return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -305,13 +324,27 @@ sub ShowEnv { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^\s*\^\s*$/); return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); s/ +$//; # Drop trailing ' ' + next if (/Fan Zone Speed:/); + if (/(control temperature|monitor temperature)/i) { + ProcessHistory("COMMENTS","","","!Env: $_"); + while (<$INPUT>) { + if (/(.*\s+\d+\s+\d+\s+)(\d+)(.*$)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } + ProcessHistory("COMMENTS","","","!Env: $_"); + last if (/^\s*$/); + } + next; + } ProcessHistory("COMMENTS","","","!Env: $_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -323,26 +356,43 @@ sub ShowEnvTemp { print STDERR " In ShowEnvTemp: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - -# Cut out CurTemp - drop the 2nd to last field. -#-------------------------------------------------------------------- -#Module Sensor MajorThresh MinorThres CurTemp Status -# (Celsius) (Celsius) (Celsius) -#5 Outlet1 (s1) 125 125 33 Ok -#5 QEng1Sn1(s10) 115 105 39 Ok - s/^(.+\s)(\S+\s+)(\S+\s*)$/$1$3/; - - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Env: $_"); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Invalid command at /); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + s/ +$//; # Drop trailing ' ' + + # Cut out CurTemp - drop the 2nd to last field. + #-------------------------------------------------------------------- + #Module Sensor MajorThresh MinorThres CurTemp Status + # (Celsius) (Celsius) (Celsius) + #5 Outlet1 (s1) 125 125 33 Ok + #5 QEng1Sn1(s10) 115 105 39 Ok + if (/(control temperature|monitor temperature)/i) { + ProcessHistory("COMMENTS","","","!Env: $_"); + while () { + if (/(.*\s+\d+\s+\d+\s+)(\d+)(.*$)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } + ProcessHistory("COMMENTS","","","!Env: $_"); + last if (/^\s*$/); + } + next; + } else { + next if (/INTAKE/); + next if (/ASIC/); + s/^(.+\s)(\S+\s+)(\S+\s*)$/$1$3/; + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Env: $_"); + } } + ProcessHistory("COMMENTS","","","!\n"); return(0); } @@ -352,41 +402,70 @@ sub ShowEnvPower { print STDERR " In ShowEnvPower: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - next if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); -# Cut out Actual Output/Draw. -#Power Actual Total -#Supply Model Output Capacity Status -# (Watts ) (Watts ) -#------- ------------------- ----------- ----------- -------------- -#1 ------------ 0 W 0 W Absent -#3 749 W 5480 W Ok -# Actual Power -#Module Model Draw Allocated Status -# (Watts ) (Watts ) -#------- ------------------- ----------- ----------- -------------- -#2 NURBURGRING N/A 573 W Powered-Up -#fan1 N/A 720 W Powered-Up - s/ Actual / /; - s/ Output / /; - s/ \(Watts \) / /; - s/ Draw / /; - s/ ----------- / /; - s/ N\/A / / || - s/ \d+ W / /; # Does not chop enough to line up. - - /actual draw/ && next; # Drop changing total power output. + # Filter Actual Output/Draw. + #Power Actual Total + #Supply Model Output Capacity Status + # (Watts ) (Watts ) + #------- ------------------- ----------- ----------- -------------- + #1 ------------ 0 W 0 W Absent + #3 749 W 5480 W Ok + # Actual Power + #Module Model Draw Allocated Status + # (Watts ) (Watts ) + #------- ------------------- ----------- ----------- -------------- + #2 NURBURGRING N/A 573 W Powered-Up + #fan1 N/A 720 W Powered-Up + # + # ELSE + # + # nexus# sh environment power + # Power Supply: + # Voltage: 12 Volts + # Power Actual Actual Total + # Supply Model Output Input Capacity Status + # (Watts ) (Watts ) (Watts ) + # ------- ------------------- ---------- ---------- ---------- + # -------------- + # 1 N9K-PAC-650W-B 65 W 76 W 649 W Ok + # 2 N9K-PAC-650W-B 70 W 84 W 649 W Ok + # + # + # Power Usage Summary: + # -------------------- + # Power Supply redundancy mode (configured) PS-Redundant + # Power Supply redundancy mode (operational) PS-Redundant + # + # Total Power Capacity (based on configured mode) 649.92 W + # Total Grid-A (first half of PS slots) Power Capacity 649.92 W + # Total Grid-B (second half of PS slots) Power Capacity 649.92 W + # Total Power of all Inputs (cumulative) 1299.84 W + # Total Power Output (actual draw) 136.00 W + # Total Power Input (actual draw) 161.00 W + # Total Power Allocated (budget) N/A + # Total Power Available for additional modules N/A + # + # nexus# + if ( /(.* +)(\d+ W)( +\d+ W.*)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } elsif ( /(.* +)(\d+ W)( +\d+ W.*)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Env: $_"); + /actual draw/ && next; # Drop changing total power output. + + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Env: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -405,6 +484,7 @@ sub ShowBoot { return(1) if /(Invalid input detected|Type help or )/; return(1) if /Ambiguous command/i; return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -431,6 +511,7 @@ sub DirSlotN { return(1) if (/\% Invalid command at /); return(1) if /(No such device|Error Sending Request)/i; return(1) if /\%Error: No such file or directory/; + return(1) if /No such file or directory/; return(1) if /No space information available/; return(1) if / is either not present or not formatted/; return(-1) if /\%Error calling/; @@ -439,6 +520,26 @@ sub DirSlotN { return(-1) if (/command authorization failed/i); return(1) if /(Open device \S+ failed|Error opening \S+:)/; + # Drop ee.log + /\s+ee\.log(?:\..*)?$/ && next; + + # Drop accounting.log + /\s+accounting\.log$/ && next; + + next if (/BufferMonitor-1HourData/); + if (/ log\/$/) { + # change + # 8192 Jan 08 14:05:05 2015 log/ + # to + # log/ + if (/(\s*\d+\s+)(\S+ \d+\s+\d+:\d+:\d+ \d+)(.*)/) { + my($a, $dt, $rem) = ($1, $2, $3); + my($dtl) = length($dt); + my($fmt) = "%s%-". $dtl ."s%s\n"; + $_ = sprintf($fmt, $a, "", $rem); + } + } + if (/^\s*(\d+) bytes /) { next if $dev eq 'logflash'; my($tmp) = int($1 / (1024 * 1024)); @@ -462,6 +563,7 @@ sub ShowModule { last if (/^$prompt/); next if (/^\s*$cmd\s*$/); return(1) if (/\% Invalid command at /); + return(1) if (/\% Invalid number at /); return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -487,6 +589,7 @@ sub ShowInventory { return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -530,8 +633,14 @@ sub ShowEngineID { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if (/(Invalid (input|command) detected|Type help or )/i); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); + next if (/^Configuration last modified by/); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -541,11 +650,11 @@ sub ShowEngineID { ProcessHistory("ENGINEID","","","!SNMP engineID: $1\n"); $EngineId++; next; - } } - if ($EngineId) { ProcessHistory("ENGINEID","","","!\n"); } + } + if ($EngineId) { ProcessHistory("ENGINEID","","","!\n"); } - return(0); + return(0); } # This routine parses "show vtp status" @@ -560,6 +669,7 @@ sub ShowVTP { return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); next if (/^Configuration last modified by/); @@ -569,6 +679,9 @@ sub ShowVTP { s/^$1\s{$len}//; } + if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { + $DO_SHOW_VLAN = 1; + } ProcessHistory("COMMENTS","","","!VTP: $_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -583,14 +696,16 @@ sub ShowInterface { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - #return(1) if ($type !~ /^(2900XL|3500XL|6000)$/); - return(-1) if (/command authorization failed/i); - next if (/^Configuration last modified by/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -652,14 +767,16 @@ sub ShowIPInterface { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - #return(1) if ($type !~ /^(2900XL|3500XL|6000)$/); - return(-1) if (/command authorization failed/i); - next if (/^Configuration last modified by/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -685,14 +802,16 @@ sub ShowIPv6Interface { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - #return(1) if ($type !~ /^(2900XL|3500XL|6000)$/); - return(-1) if (/command authorization failed/i); - next if (/^Configuration last modified by/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -717,14 +836,16 @@ sub ShowHSRP { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - #return(1) if ($type !~ /^(2900XL|3500XL|6000)$/); - return(-1) if (/command authorization failed/i); - next if (/^Configuration last modified by/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -763,6 +884,8 @@ sub PrintHSRP { sub ShowVLAN { print STDERR " In ShowVLAN: $_" if ($debug); + ($_ = , return(1)) if (!$DO_SHOW_VLAN); + while () { tr/\015//d; last if (/^$prompt/); @@ -801,8 +924,13 @@ sub ShowDebug { return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/\% Invalid command at /); - return(-1) if (/\% Permission denied/); + return(-1) if (/No token match at /); # 1000v return(-1) if (/command authorization failed/i); + return(-1) if (/could not retrieve info/i); + # XXX return(-1) if (/\% Permission denied/); + # NX 5000 bug? "show debug" generates + # "Permission denied" when using command authorization. -Per-Olof Olsson + next if (/\% Permission denied/); /^No matching debug flags set$/ && next; /^No debug flags set$/ && next; @@ -823,9 +951,11 @@ sub ShowCores { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if (/^\s*\^\s*$/); return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -835,6 +965,28 @@ sub ShowCores { return(0); } +# This routine parses "show fex" and "show module fex" +sub ShowFex { + print STDERR " In ShowFex: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/% Invalid number at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","","","!FEX: $_"); + } + ProcessHistory("COMMENTS","","","!\n"); + return(0); +} + # This routine parses "show processes log" sub ShowProcLog { print STDERR " In ShowProcLog: $_" if ($debug); @@ -845,7 +997,8 @@ sub ShowProcLog { next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /Line has invalid autocommand /; return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); + return(1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); @@ -866,91 +1019,61 @@ sub WriteTerm { return(1) if /Line has invalid autocommand /; return(1) if (/(Invalid input detected|Type help or )/i); return(-1) if (/\% Invalid command at /); - return(0) if ($found_end); # Only do this routine once + return(-1) if (/No token match at /); # 1000v return(-1) if (/\% Permission denied/); return(-1) if (/command authorization failed/i); + return(0) if ($found_end); # Only do this routine once -# /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked $linecnt++; $lineauto = 0 if (/^[^ ]/); -# # skip the crap -# if (/^(##+$|(Building|Current) configuration)/i) { -# while () { -# next if (/^Current configuration\s*:/i); -# next if (/^:/); -# next if (/^([%!].*|\s*)$/); -# next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S -# last; -# } -# if (defined($config_register)) { -# ProcessHistory("","","","!\nconfig-register $config_register\n"); -# } -# tr/\015//d; -# } -# # some versions have other crap mixed in with the bits in the -# # block above -# /^! (Last configuration|NVRAM config last)/ && next; - -# # skip consecutive comment lines to avoid oscillating extra comment -# # line on some access servers. grrr. -# if (/^!/) { -# next if ($comment); -# ProcessHistory("","","",$_); -# $comment++; -# next; -# } -# $comment = 0; # Dog gone Cool matches to process the rest of the config /^!Command: show running-config/ && next; # kill this junk - /^!Time: / && next; # kill this junk -# /^tftp-server flash / && next; # kill any tftp remains -# /^ntp clock-period / && next; # kill ntp clock-period -# /^ length / && next; # kill length on serial lines -# /^ width / && next; # kill width on serial lines -# $lineauto = 1 if /^ modem auto/; -# /^ speed / && $lineauto && next; # kill speed on serial lines -# /^ clockrate / && next; # kill clockrate on serial interfaces -# if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { -# ProcessHistory("ENABLE","","","!$1$2$3 \n"); -# next; -# } -# if (/^(enable secret) / && $filter_pwds >= 2) { -# ProcessHistory("ENABLE","","","!$1 \n"); -# next; -# } -# if (/^username (\S+)(\s.*)? secret /) { -# if ($filter_pwds >= 2) { -# ProcessHistory("USER","keysort","$1","!username $1$2 secret \n"); -# } else { -# ProcessHistory("USER","keysort","$1","$_"); -# } -# next; -# } + /^!Time: / && next; # kill this junk + # Sort username and delete passwords. if (/^username (\S+) password (\d) (\S+)(\s.*)$/) { if ($filter_pwds >= 2) { - ProcessHistory("USER","keysort","$1","!username $1 password $4\n"); + ProcessHistory("USER","keysort","$1", + "!username $1 password $4\n"); } elsif ($filter_pwds >= 1 && $2 ne "5") { - ProcessHistory("USER","keysort","$1","!username $1 password $4\n"); + ProcessHistory("USER","keysort","$1", + "!username $1 password $4\n"); } else { ProcessHistory("USER","keysort","$1","$_"); } next; } # Sort any other username info. - /^username (\S+) .*$/ && ProcessHistory("USER","keysort","$1","$_") && next; + /^username (\S+) .*$/ && + ProcessHistory("USER","keysort","$1","$_") && next; + if (/^\s*(.*?neighbor \S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! $1 password \n"); + next; + } + # Why was this commented out? It shows up in the raw text... + if (/^(snmp-server community) (\S+)/) { + if ($filter_commstr) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_", + "!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + # Sort snmp user and delete passwords. if (/^snmp-server user (\S+) (\S+) auth md5 (\S+) priv (\S+) localizedkey$/) { if ($filter_pwds >= 2) { - ProcessHistory("SNMP-USER","keysort","$1","!snmp-server user $1 $2 auth md5 priv localizedkey\n"); + ProcessHistory("SNMP-USER","keysort","$1", + "!snmp-server user $1 $2 auth md5 priv localizedkey\n"); } else { ProcessHistory("SNMP-USER","keysort","$1","$_"); } next; } # Sort any other snmp user info. - /^snmp-server user (\S+) .*$/ && ProcessHistory("SNMP-USER","keysort","$1","$_") && next; + /^snmp-server user (\S+) .*$/ && + ProcessHistory("SNMP-USER","keysort","$1","$_") && next; # Delete bgp passwords. if (/^(\s*)password (\d) (\S+)(\s.*)?$/) { if ($filter_pwds >= 2) { @@ -962,227 +1085,20 @@ sub WriteTerm { } next; } -# # cisco AP w/ IOS -# if (/^(wlccp \S+ username (\S+)(\s.*)? password) (\d \S+|\S+)/) { -# if ($filter_pwds >= 1) { -# ProcessHistory("USER","keysort","$2","!$1 \n"); -# } else { -# ProcessHistory("USER","keysort","$2","$_"); -# } -# next; -# } -# if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1\n"); -# next; -# } -# if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1\n"); -# next; -# } -# if (/^(\s*)password / && $filter_pwds >= 1) { -# ProcessHistory("LINE-PASS","","","!$1password \n"); -# next; -# } -# if (/^(\s*)secret / && $filter_pwds >= 2) { -# ProcessHistory("LINE-PASS","","","!$1secret \n"); -# next; -# } -# if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { -# ProcessHistory("","","","! neighbor $1 password \n"); -# next; -# } -# if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# if (/^(ip ftp password) / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# # isis passwords appear to be completely plain-text -# if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!isis password $2\n"); next; -# } -# if (/^\s+(domain-password|area-password) (\S+)( .*)?/ -# && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 $3\n"); next; -# } -# # this is reversable, despite 'md5' in the cmd -# if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# # this is also reversable, despite 'md5 encrypted' in the cmd -# if (/^( message-digest-key \d+ md5 (7|encrypted)) / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 $'"); next; -# } -# # filter HSRP passwords -# if (/^(\s+standby \d+ authentication) / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# # this appears in "measurement/sla" images -# if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# # i am told these are plain-text on the PIX -# if (/^(vpdn username (\S+) password)/) { -# if ($filter_pwds >= 1) { -# ProcessHistory("USER","keysort","$2","!$1 \n"); -# } else { -# ProcessHistory("USER","keysort","$2","$_"); -# } -# next; -# } -# if (/^( cable shared-secret )/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); -# next; -# } -# /fair-queue individual-limit/ && next; -# # sort ip explicit-paths. -# if (/^ip explicit-path name (\S+)/) { -# my($key) = $1; -# my($expath) = $_; -# while () { -# tr/\015//d; -# last if (/^$prompt/); -# last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); -# if (/^ip explicit-path name (\S+)/) { -# ProcessHistory("EXPATH","keysort","$key","$expath"); -# $key = $1; -# $expath = $_; -# } else { -# $expath .= $_; -# } -# } -# ProcessHistory("EXPATH","keysort","$key","$expath"); -# } -# # sort route-maps -# if (/^route-map (\S+)/) { -# my($key) = $1; -# my($routemap) = $_; -# while () { -# tr/\015//d; -# last if (/^$prompt/ || ! /^(route-map |[ !])/); -# if (/^route-map (\S+)/) { -# ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); -# $key = $1; -# $routemap = $_; -# } else { -# $routemap .= $_; -# } -# } -# ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); -# } -# # filter out any RCS/CVS tags to avoid confusing local CVS storage -# s/\$(Revision|Id):/ $1:/; -# # order access-lists -# /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && -# ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next; -# # order extended access-lists -# /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && -# ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; -# /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && -# ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; -# /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && -# ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next; -# # order arp lists -# /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && -# ProcessHistory("ARP","$aclsort","$1","$_") && next; -# /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && -# ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n") -# && next; -# # order logging statements -# /^logging (\d+\.\d+\.\d+\.\d+)/ && -# ProcessHistory("LOGGING","ipsort","$1","$_") && next; + + # prune tacacs/radius server keys: + # tacacs-server host 196.23.0.13 key 7 "xxxxxxx" port 50 timeout 10 + if (/^((tacacs|radius)-server.*?\bkey\b.*?) ".*?"(.*)/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $3\n"); next; + } + # order cli alias names /^cli alias name (\S+) .*$/ && ProcessHistory("CLI-ALIAS","keysort","$1","$_") && next; # order snmp-server enable trap statements /^snmp-server enable traps (.*)$/ && ProcessHistory("SNMP-TRAPS","keysort","$1","$_") && next; -# # order/prune snmp-server host statements -# # we only prune lines of the form -# # snmp-server host a.b.c.d -# if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { -# if ($filter_commstr) { -# my($ip) = $1; -# my($line) = "snmp-server host $ip"; -# my(@tokens) = split(' ', $'); -# my($token); -# while ($token = shift(@tokens)) { -# if ($token eq 'version') { -# $line .= " " . join(' ', ($token, shift(@tokens))); -# if ($token eq '3') { -# $line .= " " . join(' ', ($token, shift(@tokens))); -# } -# } elsif ($token eq 'vrf') { -# $line .= " " . join(' ', ($token, shift(@tokens))); -# } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { -# $line .= " " . $token; -# } else { -# $line = "!$line " . join(' ', ("", join(' ',@tokens))); -# last; -# } -# } -# ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); -# } else { -# ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); -# } -# next; -# } -# if (/^(snmp-server community) (\S+)/) { -# if ($filter_commstr) { -# ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 $'") && next; -# } else { -# ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; -# } -# } -# # prune tacacs/radius server keys -# if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\w+/ -# && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 $'"); next; -# } -# # order clns host statements -# /^clns host \S+ (\S+)/ && -# ProcessHistory("CLNS","keysort","$1","$_") && next; -# # order alias statements -# /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; -# # delete ntp auth password - this md5 is a reversable too -# if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { -# ProcessHistory("","","","!$1 \n"); next; -# } -# # order ntp peers/servers -# if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { -# $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); -# ProcessHistory("NTP","keysort",$sortkey,"$_"); -# next; -# } -# # order ip host statements -# /^ip host (\S+) / && -# ProcessHistory("IPHOST","keysort","$1","$_") && next; -# # order ip nat source static statements -# /^ip nat (\S+) source static (\S+)/ && -# ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; -# # order atm map-list statements -# /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ && -# ProcessHistory("ATM map-list","ipsort","$1","$_") && next; -# # order ip rcmd lines -# /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next; -# -# # system controller -# /^syscon address (\S*) (\S*)/ && -# ProcessHistory("","","","!syscon address $1 \n") && -# next; -# if (/^syscon password (\S*)/ && $filter_pwds >= 1) { -# ProcessHistory("","","","!syscon password \n"); -# next; -# } # catch anything that wasnt matched above. ProcessHistory("","","","$_"); @@ -1193,9 +1109,9 @@ sub WriteTerm { } } # The ContentEngine lacks a definitive "end of config" marker. If we - # know that it is a CE, SAN, or NXOS and we have seen at least 5 lines + # know that it is NXOS and we have seen at least 5 lines # of write term output, we can be reasonably sure that we got the config. - if (($type == "CE" || $type == "SAN" || $type == "NXOS" ) && $linecnt > 5) { + if (($type eq "NXOS") && $linecnt > 5) { $found_end = 1; return(0); } @@ -1234,12 +1150,11 @@ sub DoNothing {print STDOUT;} {'show license usage' => 'ShowLicense'}, {'show license host-id' => 'ShowLicense'}, {'show system redundancy status' => 'ShowRedundancy'}, -# Disabling these since they are volatile and generate a lot of noise -# {'show environment clock' => 'ShowEnv'}, -# {'show environment fan' => 'ShowEnv'}, -# {'show environment fex all fan' => 'ShowEnv'}, -# {'show environment temperature' => 'ShowEnvTemp'}, -# {'show environment power' => 'ShowEnvPower'}, + {'show environment clock' => 'ShowEnv'}, + {'show environment fan' => 'ShowEnv'}, + {'show environment fex all fan' => 'ShowEnv'}, + {'show environment temperature' => 'ShowEnvTemp'}, + {'show environment power' => 'ShowEnvPower'}, {'show boot' => 'ShowBoot'}, {'dir bootflash:' => 'DirSlotN'}, {'dir debug:' => 'DirSlotN'}, @@ -1251,17 +1166,19 @@ sub DoNothing {print STDOUT;} {'show module' => 'ShowModule'}, {'show module xbar' => 'ShowModule'}, {'show inventory' => 'ShowInventory'}, - {'show snmp engineID' => 'ShowEngineID'}, + {'show snmp engineID' => 'ShowEngineID'}, {'show vtp status' => 'ShowVTP'}, {'show vlan' => 'ShowVLAN'}, - {'show hsrp' => 'ShowHSRP'}, + {'show hsrp' => 'ShowHSRP'}, {'show interface' => 'ShowInterface'}, {'show ip interface' => 'ShowIPInterface'}, {'show ipv6 interface' => 'ShowIPv6Interface'}, {'show debug' => 'ShowDebug'}, {'show cores vdc-all' => 'ShowCores'}, {'show processes log vdc-all' => 'ShowProcLog'}, - {'show running-config vdc-all' => 'WriteTerm'}, + {'show module fex' => 'ShowFex'}, + {'show fex' => 'ShowFex'}, + {'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. From 922af27d04fe609569ec4674dbbec27592d62309 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 18 Feb 2016 18:06:33 -0500 Subject: [PATCH 16/38] Indent using spaces --- bin/nxrancid.in | 908 ++++++++++++++++++++++++------------------------ 1 file changed, 454 insertions(+), 454 deletions(-) diff --git a/bin/nxrancid.in b/bin/nxrancid.in index 62a9f00..c572357 100644 --- a/bin/nxrancid.in +++ b/bin/nxrancid.in @@ -56,32 +56,32 @@ $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds $DO_SHOW_VLAN = 1; my(@commandtable, %commands, @commands);# command lists -my($aclsort) = ("ipsort"); # ACL sorting mode -my($filter_commstr); # SNMP community string filtering -my($filter_pwds); # password filtering mode +my($aclsort) = ("ipsort"); # ACL sorting mode +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; + && 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"; - } + 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"; + $history{++$#history} = "@string"; } else { - print "@string"; + print "@string"; } $hist_tag = $new_hist_tag; $command = $new_command; @@ -97,8 +97,8 @@ sub keynsort { local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { - $sorted_lines[$i] = $lines{$key}; - $i++; + $sorted_lines[$i] = $lines{$key}; + $i++; } @sorted_lines; } @@ -110,8 +110,8 @@ sub keysort { local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { - $sorted_lines[$i] = $lines{$key}; - $i++; + $sorted_lines[$i] = $lines{$key}; + $i++; } @sorted_lines; } @@ -123,8 +123,8 @@ sub valsort { local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } @@ -135,8 +135,8 @@ sub numsort { local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { - $sorted_lines[$i] = $lines{$num}; - $i++; + $sorted_lines[$i] = $lines{$num}; + $i++; } @sorted_lines; } @@ -149,8 +149,8 @@ sub ipsort { local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { - $sorted_lines[$i] = $lines{$addr}; - $i++; + $sorted_lines[$i] = $lines{$addr}; + $i++; } @sorted_lines; } @@ -252,21 +252,21 @@ sub ShowVersionBuild { print STDERR " In ShowVersionBuild: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - /^Built By / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^On Date / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^From Tree / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^Base Tag / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^Release for / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^Built By / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^On Date / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^From Tree / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^Base Tag / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^Release for / && ProcessHistory("COMMENTS","","", "!Build: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -277,18 +277,18 @@ sub ShowLicense { print STDERR " In ShowLicense: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - /^-+$/ && next; # Skip lines of all dashes. - s/ Grace .+$/ Grace/; # Drop anything after Grace. - ProcessHistory("COMMENTS","","", "!LIC: $_"); + /^-+$/ && next; # Skip lines of all dashes. + s/ Grace .+$/ Grace/; # Drop anything after Grace. + ProcessHistory("COMMENTS","","", "!LIC: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -299,18 +299,18 @@ sub ShowRedundancy { print STDERR " In ShowRedundancy: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Red: $_"); + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Red: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -321,18 +321,18 @@ sub ShowEnv { print STDERR " In ShowEnv: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); next if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/ +$//; # Drop trailing ' ' + s/ +$//; # Drop trailing ' ' next if (/Fan Zone Speed:/); if (/(control temperature|monitor temperature)/i) { ProcessHistory("COMMENTS","","","!Env: $_"); @@ -345,7 +345,7 @@ sub ShowEnv { } next; } - ProcessHistory("COMMENTS","","","!Env: $_"); + ProcessHistory("COMMENTS","","","!Env: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -356,15 +356,15 @@ sub ShowEnvTemp { print STDERR " In ShowEnvTemp: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Invalid command at /); - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Invalid command at /); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); s/ +$//; # Drop trailing ' ' @@ -476,20 +476,20 @@ sub ShowBoot { print STDERR " In ShowBoot: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if /Ambiguous command/i; - return(-1) if (/\% Invalid command at /); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if /Ambiguous command/i; + return(-1) if (/\% Invalid command at /); return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/ variable = / = /; - ProcessHistory("COMMENTS","","","!Variable: $_"); + s/ variable = / = /; + ProcessHistory("COMMENTS","","","!Variable: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -502,23 +502,23 @@ sub DirSlotN { my($dev) = (/\s([^\s]+):/); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if /(No such device|Error Sending Request)/i; - return(1) if /\%Error: No such file or directory/; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if /(No such device|Error Sending Request)/i; + return(1) if /\%Error: No such file or directory/; return(1) if /No such file or directory/; - return(1) if /No space information available/; - return(1) if / is either not present or not formatted/; - return(-1) if /\%Error calling/; - return(-1) if /(: device being squeezed|ATA_Status time out)/i; # busy - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - return(1) if /(Open device \S+ failed|Error opening \S+:)/; + return(1) if /No space information available/; + return(1) if / is either not present or not formatted/; + return(-1) if /\%Error calling/; + return(-1) if /(: device being squeezed|ATA_Status time out)/i; # busy + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + return(1) if /(Open device \S+ failed|Error opening \S+:)/; # Drop ee.log /\s+ee\.log(?:\..*)?$/ && next; @@ -540,13 +540,13 @@ sub DirSlotN { } } - if (/^\s*(\d+) bytes /) { - next if $dev eq 'logflash'; - my($tmp) = int($1 / (1024 * 1024)); - s/$1 bytes /$tmp MB /; - } + if (/^\s*(\d+) bytes /) { + next if $dev eq 'logflash'; + my($tmp) = int($1 / (1024 * 1024)); + s/$1 bytes /$tmp MB /; + } - ProcessHistory("COMMENTS","","","!Flash: $dev: $_"); + ProcessHistory("COMMENTS","","","!Flash: $dev: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -557,20 +557,20 @@ sub ShowModule { print STDERR " In ShowModule: $_" if ($debug); while () { - tr/\015//d; - return if (/^\s*\^$/); - last if (/online diag status/i); - last if (/^$prompt/); - next if (/^\s*$cmd\s*$/); - return(1) if (/\% Invalid command at /); + tr/\015//d; + return if (/^\s*\^$/); + last if (/online diag status/i); + last if (/^$prompt/); + next if (/^\s*$cmd\s*$/); + return(1) if (/\% Invalid command at /); return(1) if (/\% Invalid number at /); - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/(.*) \*$/$1/; # Drop a trailing '*' - /^\* this terminal session/ && next; - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Mod: $_"); + s/(.*) \*$/$1/; # Drop a trailing '*' + /^\* this terminal session/ && next; + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Mod: $_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -582,43 +582,43 @@ sub ShowInventory { print STDERR " In ShowInventory: $_" if ($debug); while () { - tr/\015//d; - return if (/^\s*\^$/); - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); + tr/\015//d; + return if (/^\s*\^$/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - - if (/^(NAME: "[^"]*",)\s+(DESCR: "[^"]+")/) { - ProcessHistory("COMMENTS","","", sprintf("!%-30s %s\n", $1, $2)); - next; - } - # split PID/VID/SN line - if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*,\s+SN: (\S*)\s*$/) { - my($entries) = ""; - $entries .= "!PID: $1\n" if ($1); - $entries .= "!VID: $2\n" if ($2); - $entries .= "!SN: $3\n" if ($3); - ProcessHistory("COMMENTS","","", "$entries"); - next; - } - # split broken PID/VID/SN lines. - if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*$/) { - my($entries) = ""; - $entries .= "!PID: $1\n" if ($1); - $entries .= "!VID: $2\n" if ($2); - ; - tr/\015//d; - /^\s*,\s+SN: (\S*)\s*$/; - $entries .= "!SN: $1\n" if ($1); - ProcessHistory("COMMENTS","","", "$entries"); - next; - } - ProcessHistory("COMMENTS","","","!$_"); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + if (/^(NAME: "[^"]*",)\s+(DESCR: "[^"]+")/) { + ProcessHistory("COMMENTS","","", sprintf("!%-30s %s\n", $1, $2)); + next; + } + # split PID/VID/SN line + if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*,\s+SN: (\S*)\s*$/) { + my($entries) = ""; + $entries .= "!PID: $1\n" if ($1); + $entries .= "!VID: $2\n" if ($2); + $entries .= "!SN: $3\n" if ($3); + ProcessHistory("COMMENTS","","", "$entries"); + next; + } + # split broken PID/VID/SN lines. + if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*$/) { + my($entries) = ""; + $entries .= "!PID: $1\n" if ($1); + $entries .= "!VID: $2\n" if ($2); + ; + tr/\015//d; + /^\s*,\s+SN: (\S*)\s*$/; + $entries .= "!SN: $1\n" if ($1); + ProcessHistory("COMMENTS","","", "$entries"); + next; + } + ProcessHistory("COMMENTS","","","!$_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -662,27 +662,27 @@ sub ShowVTP { print STDERR " In ShowVTP: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - next if (/^Configuration last modified by/); - # the pager can not be disabled per-session on the PIX - if (/^(<-+ More -+>)/) { - my($len) = length($1); - s/^$1\s{$len}//; - } - - if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { - $DO_SHOW_VLAN = 1; - } - ProcessHistory("COMMENTS","","","!VTP: $_"); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + next if (/^Configuration last modified by/); + # the pager can not be disabled per-session on the PIX + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + + if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { + $DO_SHOW_VLAN = 1; + } + ProcessHistory("COMMENTS","","","!VTP: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -696,16 +696,16 @@ sub ShowInterface { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -767,16 +767,16 @@ sub ShowIPInterface { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -802,16 +802,16 @@ sub ShowIPv6Interface { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -836,16 +836,16 @@ sub ShowHSRP { while () { tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX if (/^(<-+ More -+>)/) { my($len) = length($1); @@ -872,12 +872,12 @@ sub ShowHSRP { } sub PrintHSRP { - my $hsrp = shift; + my $hsrp = shift; - my $toReturn = "$hsrp->{'interface'}, Group: $hsrp->{'group'}"; - $toReturn .= ", IP: $hsrp->{'ip'}" if (exists $hsrp->{'ip'}); - $toReturn .= ", State: $hsrp->{'state'}" if (exists $hsrp->{'state'}); - return $toReturn; + my $toReturn = "$hsrp->{'interface'}, Group: $hsrp->{'group'}"; + $toReturn .= ", IP: $hsrp->{'ip'}" if (exists $hsrp->{'ip'}); + $toReturn .= ", State: $hsrp->{'state'}" if (exists $hsrp->{'state'}); + return $toReturn; } # This routine parses "show vlan" @@ -918,27 +918,27 @@ sub ShowDebug { my($lines) = 0; while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/command authorization failed/i); - return(-1) if (/could not retrieve info/i); - # XXX return(-1) if (/\% Permission denied/); - # NX 5000 bug? "show debug" generates - # "Permission denied" when using command authorization. -Per-Olof Olsson - next if (/\% Permission denied/); - - /^No matching debug flags set$/ && next; - /^No debug flags set$/ && next; - ProcessHistory("COMMENTS","","","!DEBUG: $_"); - $lines++; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/command authorization failed/i); + return(-1) if (/could not retrieve info/i); + # XXX return(-1) if (/\% Permission denied/); + # NX 5000 bug? "show debug" generates + # "Permission denied" when using command authorization. -Per-Olof Olsson + next if (/\% Permission denied/); + + /^No matching debug flags set$/ && next; + /^No debug flags set$/ && next; + ProcessHistory("COMMENTS","","","!DEBUG: $_"); + $lines++; } if ($lines) { - ProcessHistory("COMMENTS","","","!\n"); + ProcessHistory("COMMENTS","","","!\n"); } return(0); } @@ -948,18 +948,18 @@ sub ShowCores { print STDERR " In ShowCores: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - - ProcessHistory("COMMENTS","","","!CORES: $_"); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","","","!CORES: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -970,18 +970,18 @@ sub ShowFex { print STDERR " In ShowFex: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/% Invalid number at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - - ProcessHistory("COMMENTS","","","!FEX: $_"); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/% Invalid number at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","","","!FEX: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -992,17 +992,17 @@ sub ShowProcLog { print STDERR " In ShowProcLog: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - - ProcessHistory("COMMENTS","","","!PROC_LOGS: $_"); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","","","!PROC_LOGS: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -1014,106 +1014,106 @@ sub WriteTerm { my($lineauto,$comment,$linecnt) = (0,0,0); while () { - tr/\015//d; - last if (/^$prompt/); - return(1) if /Line has invalid autocommand /; - return(1) if (/(Invalid input detected|Type help or )/i); - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - return(0) if ($found_end); # Only do this routine once - - $linecnt++; - $lineauto = 0 if (/^[^ ]/); - - # Dog gone Cool matches to process the rest of the config - /^!Command: show running-config/ && next; # kill this junk - /^!Time: / && next; # kill this junk - - # Sort username and delete passwords. - if (/^username (\S+) password (\d) (\S+)(\s.*)$/) { - if ($filter_pwds >= 2) { - ProcessHistory("USER","keysort","$1", - "!username $1 password $4\n"); - } elsif ($filter_pwds >= 1 && $2 ne "5") { - ProcessHistory("USER","keysort","$1", - "!username $1 password $4\n"); - } else { - ProcessHistory("USER","keysort","$1","$_"); - } - next; - } - # Sort any other username info. - /^username (\S+) .*$/ && - ProcessHistory("USER","keysort","$1","$_") && next; - if (/^\s*(.*?neighbor \S*) password / && $filter_pwds >= 1) { - ProcessHistory("","","","! $1 password \n"); - next; - } - # Why was this commented out? It shows up in the raw text... - if (/^(snmp-server community) (\S+)/) { - if ($filter_commstr) { - ProcessHistory("SNMPSERVERCOMM","keysort","$_", - "!$1 $'") && next; - } else { - ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; - } - } - - # Sort snmp user and delete passwords. - if (/^snmp-server user (\S+) (\S+) auth md5 (\S+) priv (\S+) localizedkey$/) { - if ($filter_pwds >= 2) { - ProcessHistory("SNMP-USER","keysort","$1", - "!snmp-server user $1 $2 auth md5 priv localizedkey\n"); - } else { - ProcessHistory("SNMP-USER","keysort","$1","$_"); - } - next; - } - # Sort any other snmp user info. - /^snmp-server user (\S+) .*$/ && - ProcessHistory("SNMP-USER","keysort","$1","$_") && next; - # Delete bgp passwords. - if (/^(\s*)password (\d) (\S+)(\s.*)?$/) { - if ($filter_pwds >= 2) { - ProcessHistory("","","","!$1password $4"); - } elsif ($filter_pwds >= 1 && $2 ne "5") { - ProcessHistory("","","","!$1password $4"); - } else { - ProcessHistory("","","","$_"); - } - next; - } - - # prune tacacs/radius server keys: - # tacacs-server host 196.23.0.13 key 7 "xxxxxxx" port 50 timeout 10 - if (/^((tacacs|radius)-server.*?\bkey\b.*?) ".*?"(.*)/ - && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $3\n"); next; - } - - # order cli alias names - /^cli alias name (\S+) .*$/ && - ProcessHistory("CLI-ALIAS","keysort","$1","$_") && next; - # order snmp-server enable trap statements - /^snmp-server enable traps (.*)$/ && - ProcessHistory("SNMP-TRAPS","keysort","$1","$_") && next; - - # catch anything that wasnt matched above. - ProcessHistory("","","","$_"); - # end of config. the ": " game is for the PIX - if (/^(: +)?end$/) { - $found_end = 1; - return(0); - } + tr/\015//d; + last if (/^$prompt/); + return(1) if /Line has invalid autocommand /; + return(1) if (/(Invalid input detected|Type help or )/i); + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + return(0) if ($found_end); # Only do this routine once + + $linecnt++; + $lineauto = 0 if (/^[^ ]/); + + # Dog gone Cool matches to process the rest of the config + /^!Command: show running-config/ && next; # kill this junk + /^!Time: / && next; # kill this junk + + # Sort username and delete passwords. + if (/^username (\S+) password (\d) (\S+)(\s.*)$/) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!username $1 password $4\n"); + } elsif ($filter_pwds >= 1 && $2 ne "5") { + ProcessHistory("USER","keysort","$1", + "!username $1 password $4\n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + # Sort any other username info. + /^username (\S+) .*$/ && + ProcessHistory("USER","keysort","$1","$_") && next; + if (/^\s*(.*?neighbor \S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! $1 password \n"); + next; + } + # Why was this commented out? It shows up in the raw text... + if (/^(snmp-server community) (\S+)/) { + if ($filter_commstr) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_", + "!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + + # Sort snmp user and delete passwords. + if (/^snmp-server user (\S+) (\S+) auth md5 (\S+) priv (\S+) localizedkey$/) { + if ($filter_pwds >= 2) { + ProcessHistory("SNMP-USER","keysort","$1", + "!snmp-server user $1 $2 auth md5 priv localizedkey\n"); + } else { + ProcessHistory("SNMP-USER","keysort","$1","$_"); + } + next; + } + # Sort any other snmp user info. + /^snmp-server user (\S+) .*$/ && + ProcessHistory("SNMP-USER","keysort","$1","$_") && next; + # Delete bgp passwords. + if (/^(\s*)password (\d) (\S+)(\s.*)?$/) { + if ($filter_pwds >= 2) { + ProcessHistory("","","","!$1password $4"); + } elsif ($filter_pwds >= 1 && $2 ne "5") { + ProcessHistory("","","","!$1password $4"); + } else { + ProcessHistory("","","","$_"); + } + next; + } + + # prune tacacs/radius server keys: + # tacacs-server host 196.23.0.13 key 7 "xxxxxxx" port 50 timeout 10 + if (/^((tacacs|radius)-server.*?\bkey\b.*?) ".*?"(.*)/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $3\n"); next; + } + + # order cli alias names + /^cli alias name (\S+) .*$/ && + ProcessHistory("CLI-ALIAS","keysort","$1","$_") && next; + # order snmp-server enable trap statements + /^snmp-server enable traps (.*)$/ && + ProcessHistory("SNMP-TRAPS","keysort","$1","$_") && next; + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config. the ": " game is for the PIX + if (/^(: +)?end$/) { + $found_end = 1; + return(0); + } } # The ContentEngine lacks a definitive "end of config" marker. If we # know that it is NXOS and we have seen at least 5 lines # of write term output, we can be reasonably sure that we got the config. if (($type eq "NXOS") && $linecnt > 5) { - $found_end = 1; - return(0); + $found_end = 1; + return(0); } return(0); @@ -1124,10 +1124,10 @@ sub RunCommand { print STDERR " In RunCommand: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - return(1) if /Line has invalid autocommand /; - return(1) if (/(Invalid input detected|Type help or )/i); + tr/\015//d; + last if (/^$prompt/); + return(1) if /Line has invalid autocommand /; + return(1) if (/(Invalid input detected|Type help or )/i); } return(0); } @@ -1143,42 +1143,42 @@ sub DoNothing {print STDOUT;} # Main @commandtable = ( - {'term no monitor-force' => 'RunCommand'}, - {'show version' => 'ShowVersion'}, - {'show version build-info all' => 'ShowVersionBuild'}, - {'show license' => 'ShowLicense'}, - {'show license usage' => 'ShowLicense'}, - {'show license host-id' => 'ShowLicense'}, - {'show system redundancy status' => 'ShowRedundancy'}, - {'show environment clock' => 'ShowEnv'}, - {'show environment fan' => 'ShowEnv'}, - {'show environment fex all fan' => 'ShowEnv'}, - {'show environment temperature' => 'ShowEnvTemp'}, - {'show environment power' => 'ShowEnvPower'}, - {'show boot' => 'ShowBoot'}, - {'dir bootflash:' => 'DirSlotN'}, - {'dir debug:' => 'DirSlotN'}, - {'dir logflash:' => 'DirSlotN'}, - {'dir slot0:' => 'DirSlotN'}, - {'dir usb1:' => 'DirSlotN'}, - {'dir usb2:' => 'DirSlotN'}, - {'dir volatile:' => 'DirSlotN'}, - {'show module' => 'ShowModule'}, - {'show module xbar' => 'ShowModule'}, - {'show inventory' => 'ShowInventory'}, - {'show snmp engineID' => 'ShowEngineID'}, - {'show vtp status' => 'ShowVTP'}, - {'show vlan' => 'ShowVLAN'}, - {'show hsrp' => 'ShowHSRP'}, - {'show interface' => 'ShowInterface'}, - {'show ip interface' => 'ShowIPInterface'}, - {'show ipv6 interface' => 'ShowIPv6Interface'}, - {'show debug' => 'ShowDebug'}, - {'show cores vdc-all' => 'ShowCores'}, - {'show processes log vdc-all' => 'ShowProcLog'}, + {'term no monitor-force' => 'RunCommand'}, + {'show version' => 'ShowVersion'}, + {'show version build-info all' => 'ShowVersionBuild'}, + {'show license' => 'ShowLicense'}, + {'show license usage' => 'ShowLicense'}, + {'show license host-id' => 'ShowLicense'}, + {'show system redundancy status' => 'ShowRedundancy'}, + {'show environment clock' => 'ShowEnv'}, + {'show environment fan' => 'ShowEnv'}, + {'show environment fex all fan' => 'ShowEnv'}, + {'show environment temperature' => 'ShowEnvTemp'}, + {'show environment power' => 'ShowEnvPower'}, + {'show boot' => 'ShowBoot'}, + {'dir bootflash:' => 'DirSlotN'}, + {'dir debug:' => 'DirSlotN'}, + {'dir logflash:' => 'DirSlotN'}, + {'dir slot0:' => 'DirSlotN'}, + {'dir usb1:' => 'DirSlotN'}, + {'dir usb2:' => 'DirSlotN'}, + {'dir volatile:' => 'DirSlotN'}, + {'show module' => 'ShowModule'}, + {'show module xbar' => 'ShowModule'}, + {'show inventory' => 'ShowInventory'}, + {'show snmp engineID' => 'ShowEngineID'}, + {'show vtp status' => 'ShowVTP'}, + {'show vlan' => 'ShowVLAN'}, + {'show hsrp' => 'ShowHSRP'}, + {'show interface' => 'ShowInterface'}, + {'show ip interface' => 'ShowIPInterface'}, + {'show ipv6 interface' => 'ShowIPv6Interface'}, + {'show debug' => 'ShowDebug'}, + {'show cores vdc-all' => 'ShowCores'}, + {'show processes log vdc-all' => 'ShowProcLog'}, {'show module fex' => 'ShowFex'}, {'show fex' => 'ShowFex'}, - {'show running-config' => 'WriteTerm'}, + {'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. @@ -1190,11 +1190,11 @@ $cmds_regexp = join("|", map quotemeta($_), @commands); if (length($host) == 0) { if ($file) { - print(STDERR "Too few arguments: file name required\n"); - exit(1); + print(STDERR "Too few arguments: file name required\n"); + exit(1); } else { - print(STDERR "Too few arguments: host name required\n"); - exit(1); + print(STDERR "Too few arguments: host name required\n"); + exit(1); } } open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; @@ -1210,10 +1210,10 @@ if ($file) { print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { - system "clogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; - open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + system "clogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; } else { - open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host ) { tr/\015//d; if (/[>#]\s?exit$/) { - print STDERR ("$host: found exit\n") if ($debug); - $clean_run = 1; - last; + print STDERR ("$host: found exit\n") if ($debug); + $clean_run = 1; + last; } if (/^Error:/) { - print STDOUT ("$host clogin error: $_"); - print STDERR ("$host clogin error: $_") if ($debug); - $clean_run = 0; - last; + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run = 0; + last; } while (/#\s*($cmds_regexp)\s*$/) { - $cmd = $1; - if (!defined($prompt)) { - $prompt = ($_ =~ /^([^#]+#)/)[0]; - $prompt =~ s/([][}{)(\\])/\\$1/g; - 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; - print STDERR ("$host: $cmd failed: $rval\n") if ($debug); - last TOP; - } - if (/[>#]\s?exit$/) { - print STDERR ("$host: found exit\n") if ($debug); - $clean_run = 1; - last TOP; - } + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + 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; + print STDERR ("$host: $cmd failed: $rval\n") if ($debug); + last TOP; + } + if (/[>#]\s?exit$/) { + print STDERR ("$host: found exit\n") if ($debug); + $clean_run = 1; + last TOP; + } } } print STDOUT "Done $logincmd: $_\n" if ($log); @@ -1293,14 +1293,14 @@ if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { # check for completeness if (scalar(%commands) || !$clean_run || !$found_end) { if (scalar(%commands)) { - printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); - printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); } if (!$clean_run || !$found_end) { - print STDOUT "$host: End of run not found\n"; - print STDERR "$host: End of run not found\n" if ($debug); - print STDERR "$host: clean: $clean_run, end: $found_end\n" if ($debug); - system("/usr/bin/tail -1 $host.new"); + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + print STDERR "$host: clean: $clean_run, end: $found_end\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); } unlink "$host.new" if (! $debug); } From 944f1d43eb0c098676b48295db8ab35d8c2588d2 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 18 Feb 2016 18:18:55 -0500 Subject: [PATCH 17/38] Indent while and if statements consistently --- bin/nxrancid.in | 950 ++++++++++++++++++++++++------------------------ 1 file changed, 475 insertions(+), 475 deletions(-) diff --git a/bin/nxrancid.in b/bin/nxrancid.in index c572357..268fa7e 100644 --- a/bin/nxrancid.in +++ b/bin/nxrancid.in @@ -252,21 +252,21 @@ sub ShowVersionBuild { print STDERR " In ShowVersionBuild: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - /^Built By / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^On Date / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^From Tree / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^Base Tag / && ProcessHistory("COMMENTS","","", "!Build: $_"); - /^Release for / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^Built By / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^On Date / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^From Tree / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^Base Tag / && ProcessHistory("COMMENTS","","", "!Build: $_"); + /^Release for / && ProcessHistory("COMMENTS","","", "!Build: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -277,18 +277,18 @@ sub ShowLicense { print STDERR " In ShowLicense: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - /^-+$/ && next; # Skip lines of all dashes. - s/ Grace .+$/ Grace/; # Drop anything after Grace. - ProcessHistory("COMMENTS","","", "!LIC: $_"); + /^-+$/ && next; # Skip lines of all dashes. + s/ Grace .+$/ Grace/; # Drop anything after Grace. + ProcessHistory("COMMENTS","","", "!LIC: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -299,18 +299,18 @@ sub ShowRedundancy { print STDERR " In ShowRedundancy: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Red: $_"); + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Red: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -321,31 +321,31 @@ sub ShowEnv { print STDERR " In ShowEnv: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - next if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/ +$//; # Drop trailing ' ' - next if (/Fan Zone Speed:/); - if (/(control temperature|monitor temperature)/i) { - ProcessHistory("COMMENTS","","","!Env: $_"); - while (<$INPUT>) { - if (/(.*\s+\d+\s+\d+\s+)(\d+)(.*$)/) { - $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + s/ +$//; # Drop trailing ' ' + next if (/Fan Zone Speed:/); + if (/(control temperature|monitor temperature)/i) { + ProcessHistory("COMMENTS","","","!Env: $_"); + while (<$INPUT>) { + if (/(.*\s+\d+\s+\d+\s+)(\d+)(.*$)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } + ProcessHistory("COMMENTS","","","!Env: $_"); + last if (/^\s*$/); + } + next; } ProcessHistory("COMMENTS","","","!Env: $_"); - last if (/^\s*$/); - } - next; - } - ProcessHistory("COMMENTS","","","!Env: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -402,70 +402,70 @@ sub ShowEnvPower { print STDERR " In ShowEnvPower: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - next if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + next if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - # Filter Actual Output/Draw. - #Power Actual Total - #Supply Model Output Capacity Status - # (Watts ) (Watts ) - #------- ------------------- ----------- ----------- -------------- - #1 ------------ 0 W 0 W Absent - #3 749 W 5480 W Ok - # Actual Power - #Module Model Draw Allocated Status - # (Watts ) (Watts ) - #------- ------------------- ----------- ----------- -------------- - #2 NURBURGRING N/A 573 W Powered-Up - #fan1 N/A 720 W Powered-Up - # - # ELSE - # - # nexus# sh environment power - # Power Supply: - # Voltage: 12 Volts - # Power Actual Actual Total - # Supply Model Output Input Capacity Status - # (Watts ) (Watts ) (Watts ) - # ------- ------------------- ---------- ---------- ---------- - # -------------- - # 1 N9K-PAC-650W-B 65 W 76 W 649 W Ok - # 2 N9K-PAC-650W-B 70 W 84 W 649 W Ok - # - # - # Power Usage Summary: - # -------------------- - # Power Supply redundancy mode (configured) PS-Redundant - # Power Supply redundancy mode (operational) PS-Redundant - # - # Total Power Capacity (based on configured mode) 649.92 W - # Total Grid-A (first half of PS slots) Power Capacity 649.92 W - # Total Grid-B (second half of PS slots) Power Capacity 649.92 W - # Total Power of all Inputs (cumulative) 1299.84 W - # Total Power Output (actual draw) 136.00 W - # Total Power Input (actual draw) 161.00 W - # Total Power Allocated (budget) N/A - # Total Power Available for additional modules N/A - # - # nexus# - if ( /(.* +)(\d+ W)( +\d+ W.*)/) { - $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); - } elsif ( /(.* +)(\d+ W)( +\d+ W.*)/) { - $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); - } + # Filter Actual Output/Draw. + #Power Actual Total + #Supply Model Output Capacity Status + # (Watts ) (Watts ) + #------- ------------------- ----------- ----------- -------------- + #1 ------------ 0 W 0 W Absent + #3 749 W 5480 W Ok + # Actual Power + #Module Model Draw Allocated Status + # (Watts ) (Watts ) + #------- ------------------- ----------- ----------- -------------- + #2 NURBURGRING N/A 573 W Powered-Up + #fan1 N/A 720 W Powered-Up + # + # ELSE + # + # nexus# sh environment power + # Power Supply: + # Voltage: 12 Volts + # Power Actual Actual Total + # Supply Model Output Input Capacity Status + # (Watts ) (Watts ) (Watts ) + # ------- ------------------- ---------- ---------- ---------- + # -------------- + # 1 N9K-PAC-650W-B 65 W 76 W 649 W Ok + # 2 N9K-PAC-650W-B 70 W 84 W 649 W Ok + # + # + # Power Usage Summary: + # -------------------- + # Power Supply redundancy mode (configured) PS-Redundant + # Power Supply redundancy mode (operational) PS-Redundant + # + # Total Power Capacity (based on configured mode) 649.92 W + # Total Grid-A (first half of PS slots) Power Capacity 649.92 W + # Total Grid-B (second half of PS slots) Power Capacity 649.92 W + # Total Power of all Inputs (cumulative) 1299.84 W + # Total Power Output (actual draw) 136.00 W + # Total Power Input (actual draw) 161.00 W + # Total Power Allocated (budget) N/A + # Total Power Available for additional modules N/A + # + # nexus# + if ( /(.* +)(\d+ W)( +\d+ W.*)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } elsif ( /(.* +)(\d+ W)( +\d+ W.*)/) { + $_ = sprintf("%s%-". length($2)."s%s\n", $1, "", $3); + } - /actual draw/ && next; # Drop changing total power output. + /actual draw/ && next; # Drop changing total power output. - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Env: $_"); + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Env: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -476,20 +476,20 @@ sub ShowBoot { print STDERR " In ShowBoot: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if /Ambiguous command/i; - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if /Ambiguous command/i; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/ variable = / = /; - ProcessHistory("COMMENTS","","","!Variable: $_"); + s/ variable = / = /; + ProcessHistory("COMMENTS","","","!Variable: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -502,51 +502,51 @@ sub DirSlotN { my($dev) = (/\s([^\s]+):/); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if /(No such device|Error Sending Request)/i; - return(1) if /\%Error: No such file or directory/; - return(1) if /No such file or directory/; - return(1) if /No space information available/; - return(1) if / is either not present or not formatted/; - return(-1) if /\%Error calling/; - return(-1) if /(: device being squeezed|ATA_Status time out)/i; # busy - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - return(1) if /(Open device \S+ failed|Error opening \S+:)/; - - # Drop ee.log - /\s+ee\.log(?:\..*)?$/ && next; - - # Drop accounting.log - /\s+accounting\.log$/ && next; - - next if (/BufferMonitor-1HourData/); - if (/ log\/$/) { - # change - # 8192 Jan 08 14:05:05 2015 log/ - # to - # log/ - if (/(\s*\d+\s+)(\S+ \d+\s+\d+:\d+:\d+ \d+)(.*)/) { - my($a, $dt, $rem) = ($1, $2, $3); - my($dtl) = length($dt); - my($fmt) = "%s%-". $dtl ."s%s\n"; - $_ = sprintf($fmt, $a, "", $rem); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if /(No such device|Error Sending Request)/i; + return(1) if /\%Error: No such file or directory/; + return(1) if /No such file or directory/; + return(1) if /No space information available/; + return(1) if / is either not present or not formatted/; + return(-1) if /\%Error calling/; + return(-1) if /(: device being squeezed|ATA_Status time out)/i; # busy + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + return(1) if /(Open device \S+ failed|Error opening \S+:)/; + + # Drop ee.log + /\s+ee\.log(?:\..*)?$/ && next; + + # Drop accounting.log + /\s+accounting\.log$/ && next; + + next if (/BufferMonitor-1HourData/); + if (/ log\/$/) { + # change + # 8192 Jan 08 14:05:05 2015 log/ + # to + # log/ + if (/(\s*\d+\s+)(\S+ \d+\s+\d+:\d+:\d+ \d+)(.*)/) { + my($a, $dt, $rem) = ($1, $2, $3); + my($dtl) = length($dt); + my($fmt) = "%s%-". $dtl ."s%s\n"; + $_ = sprintf($fmt, $a, "", $rem); + } } - } - if (/^\s*(\d+) bytes /) { - next if $dev eq 'logflash'; - my($tmp) = int($1 / (1024 * 1024)); - s/$1 bytes /$tmp MB /; - } + if (/^\s*(\d+) bytes /) { + next if $dev eq 'logflash'; + my($tmp) = int($1 / (1024 * 1024)); + s/$1 bytes /$tmp MB /; + } - ProcessHistory("COMMENTS","","","!Flash: $dev: $_"); + ProcessHistory("COMMENTS","","","!Flash: $dev: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -557,20 +557,20 @@ sub ShowModule { print STDERR " In ShowModule: $_" if ($debug); while () { - tr/\015//d; - return if (/^\s*\^$/); - last if (/online diag status/i); - last if (/^$prompt/); - next if (/^\s*$cmd\s*$/); - return(1) if (/\% Invalid command at /); - return(1) if (/\% Invalid number at /); - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + return if (/^\s*\^$/); + last if (/online diag status/i); + last if (/^$prompt/); + next if (/^\s*$cmd\s*$/); + return(1) if (/\% Invalid command at /); + return(1) if (/\% Invalid number at /); + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - s/(.*) \*$/$1/; # Drop a trailing '*' - /^\* this terminal session/ && next; - s/ +$//; # Drop trailing ' ' - ProcessHistory("COMMENTS","","","!Mod: $_"); + s/(.*) \*$/$1/; # Drop a trailing '*' + /^\* this terminal session/ && next; + s/ +$//; # Drop trailing ' ' + ProcessHistory("COMMENTS","","","!Mod: $_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -582,43 +582,43 @@ sub ShowInventory { print STDERR " In ShowInventory: $_" if ($debug); while () { - tr/\015//d; - return if (/^\s*\^$/); - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - - if (/^(NAME: "[^"]*",)\s+(DESCR: "[^"]+")/) { - ProcessHistory("COMMENTS","","", sprintf("!%-30s %s\n", $1, $2)); - next; - } - # split PID/VID/SN line - if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*,\s+SN: (\S*)\s*$/) { - my($entries) = ""; - $entries .= "!PID: $1\n" if ($1); - $entries .= "!VID: $2\n" if ($2); - $entries .= "!SN: $3\n" if ($3); - ProcessHistory("COMMENTS","","", "$entries"); - next; - } - # split broken PID/VID/SN lines. - if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*$/) { - my($entries) = ""; - $entries .= "!PID: $1\n" if ($1); - $entries .= "!VID: $2\n" if ($2); - ; tr/\015//d; - /^\s*,\s+SN: (\S*)\s*$/; - $entries .= "!SN: $1\n" if ($1); - ProcessHistory("COMMENTS","","", "$entries"); - next; - } - ProcessHistory("COMMENTS","","","!$_"); + return if (/^\s*\^$/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + + if (/^(NAME: "[^"]*",)\s+(DESCR: "[^"]+")/) { + ProcessHistory("COMMENTS","","", sprintf("!%-30s %s\n", $1, $2)); + next; + } + # split PID/VID/SN line + if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*,\s+SN: (\S*)\s*$/) { + my($entries) = ""; + $entries .= "!PID: $1\n" if ($1); + $entries .= "!VID: $2\n" if ($2); + $entries .= "!SN: $3\n" if ($3); + ProcessHistory("COMMENTS","","", "$entries"); + next; + } + # split broken PID/VID/SN lines. + if (/^PID: (\S*)\s*,\s+VID: (\S*)\s*$/) { + my($entries) = ""; + $entries .= "!PID: $1\n" if ($1); + $entries .= "!VID: $2\n" if ($2); + ; + tr/\015//d; + /^\s*,\s+SN: (\S*)\s*$/; + $entries .= "!SN: $1\n" if ($1); + ProcessHistory("COMMENTS","","", "$entries"); + next; + } + ProcessHistory("COMMENTS","","","!$_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -662,27 +662,27 @@ sub ShowVTP { print STDERR " In ShowVTP: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - next if (/^Configuration last modified by/); - # the pager can not be disabled per-session on the PIX - if (/^(<-+ More -+>)/) { - my($len) = length($1); - s/^$1\s{$len}//; - } + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + next if (/^Configuration last modified by/); + # the pager can not be disabled per-session on the PIX + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } - if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { - $DO_SHOW_VLAN = 1; - } - ProcessHistory("COMMENTS","","","!VTP: $_"); + if (/^VTP Operating Mode\s+:\s+(Transparent|Server)/) { + $DO_SHOW_VLAN = 1; + } + ProcessHistory("COMMENTS","","","!VTP: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -695,51 +695,51 @@ sub ShowInterface { my $interface; while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - # the pager can not be disabled per-session on the PIX - if (/^(<-+ More -+>)/) { - my($len) = length($1); - s/^$1\s{$len}//; - } - if (/^([\w\/\.\-]+) is ([\w\s]+)(?:\s\(.*\))?/) { - ProcessHistory("INT","keysort",$interface->{'name'},"!Interface: " . PrintInterface($interface) . "\n") if (defined $interface); - $interface = { - name => $1, - operState => $2, - }; - # Trim trailing spaces - $interface->{'operState'} =~ s/\s+$//; - next; - } - if (/^admin state is ([\w\s]+),/) { - $interface->{'adminState'} = $1; - chomp($interface->{'adminState'}); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^([\w\/\.\-]+) is ([\w\s]+)(?:\s\(.*\))?/) { + ProcessHistory("INT","keysort",$interface->{'name'},"!Interface: " . PrintInterface($interface) . "\n") if (defined $interface); + $interface = { + name => $1, + operState => $2, + }; + # Trim trailing spaces + $interface->{'operState'} =~ s/\s+$//; + next; + } + if (/^admin state is ([\w\s]+),/) { + $interface->{'adminState'} = $1; + chomp($interface->{'adminState'}); + next; + } + if (/^\s+Description: (.+)/) { + $interface->{'description'} = $1; + chomp($interface->{'description'}); + next; + } + if (/^\s+Hardware is ([\w\s]+), address is ([0-9a-f\.]+)/) { + $interface->{'type'} = $1; + $interface->{'mac'} = $2; + next; + } + if (/^\s+MTU (\d+) bytes/) { + $interface->{'mtu'} = $1; next; } - if (/^\s+Description: (.+)/) { - $interface->{'description'} = $1; - chomp($interface->{'description'}); - next; - } - if (/^\s+Hardware is ([\w\s]+), address is ([0-9a-f\.]+)/) { - $interface->{'type'} = $1; - $interface->{'mac'} = $2; - next; - } - if (/^\s+MTU (\d+) bytes/) { - $interface->{'mtu'} = $1; - next; - } } ProcessHistory("INT","keysort",$interface->{'name'},"!Interface: " . PrintInterface($interface) . "\n") if (defined $interface); return(0); @@ -766,30 +766,30 @@ sub ShowIPInterface { my $interface; while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - # the pager can not be disabled per-session on the PIX - if (/^(<-+ More -+>)/) { - my($len) = length($1); - s/^$1\s{$len}//; - } - if (/^([\w\/\.\-]+), Interface status:/) { - $interface = $1; - next; - } - if (/^\s+IP address: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) { - ProcessHistory("IP","ipsort",$1,"!IPv4 Address: $1 on $interface\n") if (defined $interface); - next; - } + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^([\w\/\.\-]+), Interface status:/) { + $interface = $1; + next; + } + if (/^\s+IP address: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) { + ProcessHistory("IP","ipsort",$1,"!IPv4 Address: $1 on $interface\n") if (defined $interface); + next; + } } return(0); } @@ -801,29 +801,29 @@ sub ShowIPv6Interface { my $interface; while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^\s*\^\s*$/; - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(1) if /Ambiguous command/i; - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - # the pager can not be disabled per-session on the PIX - if (/^(<-+ More -+>)/) { - my($len) = length($1); - s/^$1\s{$len}//; - } - if (/^([\w\/\.\-]+), Interface status:/) { - $interface = $1; - next; - } - if (/^\s+IPv6 address:\s+([0-9a-f:]+)/) { - ProcessHistory("IPv6","ipsort",$1,"!IPv6 Address: $1 on $interface\n") if (defined $interface); - } + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(1) if /Ambiguous command/i; + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + # the pager can not be disabled per-session on the PIX + if (/^(<-+ More -+>)/) { + my($len) = length($1); + s/^$1\s{$len}//; + } + if (/^([\w\/\.\-]+), Interface status:/) { + $interface = $1; + next; + } + if (/^\s+IPv6 address:\s+([0-9a-f:]+)/) { + ProcessHistory("IPv6","ipsort",$1,"!IPv6 Address: $1 on $interface\n") if (defined $interface); + } } return(0); } @@ -918,24 +918,24 @@ sub ShowDebug { my($lines) = 0; while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/command authorization failed/i); - return(-1) if (/could not retrieve info/i); - # XXX return(-1) if (/\% Permission denied/); - # NX 5000 bug? "show debug" generates - # "Permission denied" when using command authorization. -Per-Olof Olsson - next if (/\% Permission denied/); - - /^No matching debug flags set$/ && next; - /^No debug flags set$/ && next; - ProcessHistory("COMMENTS","","","!DEBUG: $_"); - $lines++; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/command authorization failed/i); + return(-1) if (/could not retrieve info/i); + # XXX return(-1) if (/\% Permission denied/); + # NX 5000 bug? "show debug" generates + # "Permission denied" when using command authorization. -Per-Olof Olsson + next if (/\% Permission denied/); + + /^No matching debug flags set$/ && next; + /^No debug flags set$/ && next; + ProcessHistory("COMMENTS","","","!DEBUG: $_"); + $lines++; } if ($lines) { ProcessHistory("COMMENTS","","","!\n"); @@ -948,18 +948,18 @@ sub ShowCores { print STDERR " In ShowCores: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - ProcessHistory("COMMENTS","","","!CORES: $_"); + ProcessHistory("COMMENTS","","","!CORES: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -970,18 +970,18 @@ sub ShowFex { print STDERR " In ShowFex: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if (/^\s*\^\s*$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(1) if (/% Invalid number at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if (/^\s*\^\s*$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(1) if (/% Invalid number at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - ProcessHistory("COMMENTS","","","!FEX: $_"); + ProcessHistory("COMMENTS","","","!FEX: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -992,17 +992,17 @@ sub ShowProcLog { print STDERR " In ShowProcLog: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /Line has invalid autocommand /; - return(1) if /(Invalid input detected|Type help or )/; - return(1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /Line has invalid autocommand /; + return(1) if /(Invalid input detected|Type help or )/; + return(1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); - ProcessHistory("COMMENTS","","","!PROC_LOGS: $_"); + ProcessHistory("COMMENTS","","","!PROC_LOGS: $_"); } ProcessHistory("COMMENTS","","","!\n"); return(0); @@ -1014,106 +1014,106 @@ sub WriteTerm { my($lineauto,$comment,$linecnt) = (0,0,0); while () { - tr/\015//d; - last if (/^$prompt/); - return(1) if /Line has invalid autocommand /; - return(1) if (/(Invalid input detected|Type help or )/i); - return(-1) if (/\% Invalid command at /); - return(-1) if (/No token match at /); # 1000v - return(-1) if (/\% Permission denied/); - return(-1) if (/command authorization failed/i); - return(0) if ($found_end); # Only do this routine once - - $linecnt++; - $lineauto = 0 if (/^[^ ]/); - - # Dog gone Cool matches to process the rest of the config - /^!Command: show running-config/ && next; # kill this junk - /^!Time: / && next; # kill this junk - - # Sort username and delete passwords. - if (/^username (\S+) password (\d) (\S+)(\s.*)$/) { - if ($filter_pwds >= 2) { - ProcessHistory("USER","keysort","$1", - "!username $1 password $4\n"); - } elsif ($filter_pwds >= 1 && $2 ne "5") { - ProcessHistory("USER","keysort","$1", - "!username $1 password $4\n"); - } else { - ProcessHistory("USER","keysort","$1","$_"); + tr/\015//d; + last if (/^$prompt/); + return(1) if /Line has invalid autocommand /; + return(1) if (/(Invalid input detected|Type help or )/i); + return(-1) if (/\% Invalid command at /); + return(-1) if (/No token match at /); # 1000v + return(-1) if (/\% Permission denied/); + return(-1) if (/command authorization failed/i); + return(0) if ($found_end); # Only do this routine once + + $linecnt++; + $lineauto = 0 if (/^[^ ]/); + + # Dog gone Cool matches to process the rest of the config + /^!Command: show running-config/ && next; # kill this junk + /^!Time: / && next; # kill this junk + + # Sort username and delete passwords. + if (/^username (\S+) password (\d) (\S+)(\s.*)$/) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!username $1 password $4\n"); + } elsif ($filter_pwds >= 1 && $2 ne "5") { + ProcessHistory("USER","keysort","$1", + "!username $1 password $4\n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; } - next; - } - # Sort any other username info. - /^username (\S+) .*$/ && - ProcessHistory("USER","keysort","$1","$_") && next; - if (/^\s*(.*?neighbor \S*) password / && $filter_pwds >= 1) { - ProcessHistory("","","","! $1 password \n"); - next; - } - # Why was this commented out? It shows up in the raw text... - if (/^(snmp-server community) (\S+)/) { - if ($filter_commstr) { - ProcessHistory("SNMPSERVERCOMM","keysort","$_", - "!$1 $'") && next; - } else { - ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + # Sort any other username info. + /^username (\S+) .*$/ && + ProcessHistory("USER","keysort","$1","$_") && next; + if (/^\s*(.*?neighbor \S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! $1 password \n"); + next; + } + # Why was this commented out? It shows up in the raw text... + if (/^(snmp-server community) (\S+)/) { + if ($filter_commstr) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_", + "!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } } - } - # Sort snmp user and delete passwords. - if (/^snmp-server user (\S+) (\S+) auth md5 (\S+) priv (\S+) localizedkey$/) { - if ($filter_pwds >= 2) { - ProcessHistory("SNMP-USER","keysort","$1", - "!snmp-server user $1 $2 auth md5 priv localizedkey\n"); - } else { - ProcessHistory("SNMP-USER","keysort","$1","$_"); + # Sort snmp user and delete passwords. + if (/^snmp-server user (\S+) (\S+) auth md5 (\S+) priv (\S+) localizedkey$/) { + if ($filter_pwds >= 2) { + ProcessHistory("SNMP-USER","keysort","$1", + "!snmp-server user $1 $2 auth md5 priv localizedkey\n"); + } else { + ProcessHistory("SNMP-USER","keysort","$1","$_"); + } + next; } - next; - } - # Sort any other snmp user info. - /^snmp-server user (\S+) .*$/ && - ProcessHistory("SNMP-USER","keysort","$1","$_") && next; - # Delete bgp passwords. - if (/^(\s*)password (\d) (\S+)(\s.*)?$/) { - if ($filter_pwds >= 2) { - ProcessHistory("","","","!$1password $4"); - } elsif ($filter_pwds >= 1 && $2 ne "5") { - ProcessHistory("","","","!$1password $4"); - } else { - ProcessHistory("","","","$_"); + # Sort any other snmp user info. + /^snmp-server user (\S+) .*$/ && + ProcessHistory("SNMP-USER","keysort","$1","$_") && next; + # Delete bgp passwords. + if (/^(\s*)password (\d) (\S+)(\s.*)?$/) { + if ($filter_pwds >= 2) { + ProcessHistory("","","","!$1password $4"); + } elsif ($filter_pwds >= 1 && $2 ne "5") { + ProcessHistory("","","","!$1password $4"); + } else { + ProcessHistory("","","","$_"); + } + next; } - next; - } - # prune tacacs/radius server keys: - # tacacs-server host 196.23.0.13 key 7 "xxxxxxx" port 50 timeout 10 - if (/^((tacacs|radius)-server.*?\bkey\b.*?) ".*?"(.*)/ - && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $3\n"); next; - } + # prune tacacs/radius server keys: + # tacacs-server host 196.23.0.13 key 7 "xxxxxxx" port 50 timeout 10 + if (/^((tacacs|radius)-server.*?\bkey\b.*?) ".*?"(.*)/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $3\n"); next; + } - # order cli alias names - /^cli alias name (\S+) .*$/ && - ProcessHistory("CLI-ALIAS","keysort","$1","$_") && next; - # order snmp-server enable trap statements - /^snmp-server enable traps (.*)$/ && - ProcessHistory("SNMP-TRAPS","keysort","$1","$_") && next; - - # catch anything that wasnt matched above. - ProcessHistory("","","","$_"); - # end of config. the ": " game is for the PIX - if (/^(: +)?end$/) { - $found_end = 1; - return(0); - } + # order cli alias names + /^cli alias name (\S+) .*$/ && + ProcessHistory("CLI-ALIAS","keysort","$1","$_") && next; + # order snmp-server enable trap statements + /^snmp-server enable traps (.*)$/ && + ProcessHistory("SNMP-TRAPS","keysort","$1","$_") && next; + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config. the ": " game is for the PIX + if (/^(: +)?end$/) { + $found_end = 1; + return(0); + } } # The ContentEngine lacks a definitive "end of config" marker. If we # know that it is NXOS and we have seen at least 5 lines # of write term output, we can be reasonably sure that we got the config. if (($type eq "NXOS") && $linecnt > 5) { - $found_end = 1; - return(0); + $found_end = 1; + return(0); } return(0); @@ -1124,10 +1124,10 @@ sub RunCommand { print STDERR " In RunCommand: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - return(1) if /Line has invalid autocommand /; - return(1) if (/(Invalid input detected|Type help or )/i); + tr/\015//d; + last if (/^$prompt/); + return(1) if /Line has invalid autocommand /; + return(1) if (/(Invalid input detected|Type help or )/i); } return(0); } From 47ce367d901dd95c1601d4f9c8275de93987848e Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Thu, 18 Feb 2016 18:19:33 -0500 Subject: [PATCH 18/38] Update spec file --- rancid-git.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rancid-git.spec b/rancid-git.spec index 33d2db4..78ef88f 100644 --- a/rancid-git.spec +++ b/rancid-git.spec @@ -3,7 +3,7 @@ Name: rancid-git Version: 2.3.9 -Release: 4.1%{?dist} +Release: 4.2%{?dist} Summary: Really Awesome New Cisco confIg Differ (w/ git support) Group: Applications/Internet @@ -129,6 +129,10 @@ fi %changelog +* Thu Feb 18 2016 Sam Doran 2.3.9-4.2 +- Account for date in prompt when processing Arista configs (from upstream 3.2) +- Improve processing of Nexus devices (from upstream 3.3) + * Wed Feb 03 2016 Sam Doran 2.3.9-4.1 - Modify email subject and commit messages so they make more sense - Correct regexp for removing ASA/PIX keys From 822f4b2514290d385060951c54ecd0795a9dd037 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 9 Feb 2016 11:12:19 -0500 Subject: [PATCH 19/38] Update COPYYEARS --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fc1f5c2..41f8277 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ VERSION=`sed -n 's/.*version.*"\(.*\)".*/\1/p' $srcdir/include/version.h.in|tr - PACKAGE=`sed -n 's/.*package.*"\(.*\)".*/\1/p' $srcdir/include/version.h.in|tr -d ' '` AC_SUBST(VERSION) AC_SUBST(PACKAGE) -COPYYEARS="1997-2011" +COPYYEARS="1997-2016" AC_SUBST(COPYYEARS) AM_INIT_AUTOMAKE($PACKAGE, $VERSION, rancid@shrubbery.net) From 8437cca98a93677983216587c8cb36b6d3bb23b6 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 9 Feb 2016 11:18:13 -0500 Subject: [PATCH 20/38] Correct Arista processing bug From Upsteam 3.2 --- bin/arrancid.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/arrancid.in b/bin/arrancid.in index c2fc4c3..f4e5c6c 100644 --- a/bin/arrancid.in +++ b/bin/arrancid.in @@ -41,7 +41,7 @@ ## POSSIBILITY OF SUCH DAMAGE. # # RANCID - Really Awesome New ConfIg Differ -# +# # Rancid for Arista Networks' switches; cisco mode works but # Arista mode is better. # Initial version by Bill Fenner @@ -706,6 +706,8 @@ TOP: while() { if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; $prompt =~ s/([][}{)(\\])/\\$1/g; + # "time in prompt" hack: + $prompt =~ s/\d+:\d+:\d+/\\d+:\\d+:\\d+/; print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); From bb27c991ff06a6691236499ec3e6629336134562 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 9 Feb 2016 11:19:14 -0500 Subject: [PATCH 21/38] Merge in changes to arrancid.in from upstream 3.2 --- bin/arrancid.in | 180 +++++++++++++++++------------------------------- 1 file changed, 65 insertions(+), 115 deletions(-) diff --git a/bin/arrancid.in b/bin/arrancid.in index f4e5c6c..defff51 100644 --- a/bin/arrancid.in +++ b/bin/arrancid.in @@ -3,7 +3,7 @@ ## $Id$ ## ## @PACKAGE@ @VERSION@ -## Copyright (c) 1997-2009 by Terrapin Communications, Inc. +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. ## All rights reserved. ## ## This code is derived from software contributed to and maintained by @@ -46,10 +46,10 @@ # Arista mode is better. # Initial version by Bill Fenner # -# usage: arrancid [-dV] [-l] [-f filename | hostname] +# usage: arrancid [-dltCV] [-f filename | hostname] # use Getopt::Std; -getopts('dflV'); +getopts('dflt:CV'); if ($opt_V) { print "@PACKAGE@ @VERSION@\n"; exit(0); @@ -195,6 +195,27 @@ sub ShowVersion { return(0); } +sub DiffConfig { + print STDERR " In DiffConfig: $_" if ($debug); + my($havediffs) = 0; + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + + ProcessHistory("DIFFS","keysort","BB","!$_"); + $havediffs = 1; + } + if ($havediffs) { + ProcessHistory("DIFFS","keysort","AA","!*****************************\n"); + ProcessHistory("DIFFS","keysort","AB","!*** unsaved changes exist ***\n"); + ProcessHistory("DIFFS","keysort","AC","!*****************************\n"); + ProcessHistory("DIFFS","keysort","CC","!\n"); + } + return; +} + # This routine parses "show env all" sub ShowEnv { print STDERR " In ShowEnv: $_" if ($debug); @@ -225,7 +246,7 @@ sub ShowEnv { $supplies = 1; next; } - $supplies && /^\s*(\d+)\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+(\S+)/ && + $supplies && /^\s*(\d+)\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+(.+)/ && ProcessHistory("COMMENTS","keysort","E2","!Power Supply $1: $2 $3 $4\n" ) && next; } ProcessHistory("COMMENTS","","","!\n"); @@ -304,7 +325,13 @@ sub ShowFlash { # persist changes constantly if you're running ntp, so # skip its updates. /\spersist$/ && next; - /bytes free\)$/ && next; + + # Scheduled commands can cause free space to constantly + # change. Even the trick of summarizing the free space + # doesn't help, since it can oscillate, e.g., between + # 1006MB and 1007MB. Just skip the free space. + /.*\((\d+) bytes free\)/ && next; + ProcessHistory("FLASH","","","!Flash: $_"); } ProcessHistory("","","","!\n"); @@ -329,6 +356,23 @@ sub ShowInventory { return(0); } +# This routine parses "show tech ribd running" for Ribd sub-code commands running. +sub WriteRibd { + print STDERR " In WriteRibd: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; + return(0) if /^% Error displaying /; # Only do this routine once + + ProcessHistory("RIBD","","","!Ribd: $_"); + } + ProcessHistory("RIBD","","","!\n"); + return(0); +} + # This routine processes a "write term" sub WriteTerm { print STDERR " In WriteTerm: $_" if ($debug); @@ -348,7 +392,7 @@ sub WriteTerm { $lineauto = 1 if /^ modem auto/; /^ speed / && $lineauto && next; # kill speed on serial lines /^ clockrate / && next; # kill clockrate on serial interfaces - /^! Time: / && next; # EOS displays the time that a "show run" command was issued + /^! Time: / && next; # EOS gives the time that a "show running" command was run if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { ProcessHistory("ENABLE","","","!$1$2$3 \n"); next; @@ -378,42 +422,18 @@ sub WriteTerm { } next; } - # cisco AP w/ IOS - if (/^(wlccp \S+ username (\S+)(\s.*)? password) (\d \S+|\S+)/) { - if ($filter_pwds >= 1) { - ProcessHistory("USER","keysort","$2","!$1 \n"); - } else { - ProcessHistory("USER","keysort","$2","$_"); - } - next; - } - if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1\n"); - next; - } - if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/ - && $filter_pwds >= 1) { - ProcessHistory("","","","!$1\n"); - next; - } if (/^(\s*)password / && $filter_pwds >= 1) { - ProcessHistory("LINE-PASS","","","!$1password \n"); + ProcessHistory("","","","!$1password \n"); next; } if (/^(\s*)secret / && $filter_pwds >= 2) { - ProcessHistory("LINE-PASS","","","!$1secret \n"); + ProcessHistory("","","","!$1secret \n"); next; } if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { ProcessHistory("","","","! neighbor $1 password \n"); next; } - if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - if (/^(ip ftp password) / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { ProcessHistory("","","","!$1 \n"); next; } @@ -434,57 +454,6 @@ sub WriteTerm { && $filter_pwds >= 1) { ProcessHistory("","","","!$1 \n"); next; } - if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $'"); next; - } - # filter HSRP passwords - if (/^(\s+standby \d+ authentication) / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - # this appears in "measurement/sla" images - if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - # i am told these are plain-text on the PIX - if (/^(vpdn username (\S+) password)/) { - if ($filter_pwds >= 1) { - ProcessHistory("USER","keysort","$2","!$1 \n"); - } else { - ProcessHistory("USER","keysort","$2","$_"); - } - next; - } - # ASA/PIX keys in more system:running-config - if (/^( pre-shared-key |failover key ).*/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $'"); next; - } - # - if (/^( cable shared-secret )/ && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); - next; - } - /fair-queue individual-limit/ && next; - # sort ip explicit-paths. - if (/^ip explicit-path name (\S+)/) { - my($key) = $1; - my($expath) = $_; - while () { - tr/\015//d; - last if (/^$prompt/); - last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); - if (/^ip explicit-path name (\S+)/) { - ProcessHistory("EXPATH","keysort","$key","$expath"); - $key = $1; - $expath = $_; - } else { - $expath .= $_; - } - } - ProcessHistory("EXPATH","keysort","$key","$expath"); - } # sort route-maps if (/^route-map (\S+)/) { my($key) = $1; @@ -567,9 +536,6 @@ sub WriteTerm { && $filter_pwds >= 1) { ProcessHistory("","","","!$1 $'"); next; } - # order clns host statements - /^clns host \S+ (\S+)/ && - ProcessHistory("CLNS","keysort","$1","$_") && next; # order alias statements /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; # delete ntp auth password - this md5 is a reversable too @@ -582,28 +548,6 @@ sub WriteTerm { ProcessHistory("NTP","keysort",$sortkey,"$_"); next; } - # order ip host statements - /^ip host (\S+) / && - ProcessHistory("IPHOST","keysort","$1","$_") && next; - # order ip nat source static statements - /^ip nat (\S+) source static (\S+)/ && - ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; - # order atm map-list statements - /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ && - ProcessHistory("ATM map-list","ipsort","$1","$_") && next; - # order ip rcmd lines - /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next; - - # system controller - /^syscon address (\S*) (\S*)/ && - ProcessHistory("","","","!syscon address $1 \n") && - next; - if (/^syscon password (\S*)/ && $filter_pwds >= 1) { - ProcessHistory("","","","!syscon password \n"); - next; - } - - /^ *Cryptochecksum:/ && next; # catch anything that wasnt matched above. ProcessHistory("","","","$_"); @@ -617,9 +561,6 @@ sub WriteTerm { return(0); } -# dummy function -sub DoNothing {print STDOUT;} - # Main @commandtable = ( {'show version' => 'ShowVersion'}, @@ -629,12 +570,15 @@ sub DoNothing {print STDOUT;} {'show inventory' => 'ShowInventory'}, {'show boot-extensions' => 'ShowBootExt'}, {'show extensions' => 'ShowExt'}, + {'diff startup-config running-config' => 'DiffConfig'}, + #{'show tech ribd running' => 'WriteRibd'}, {'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); +$commandcnt = scalar(keys %commands); $arista_cmds = join(";",@commands); $cmds_regexp = join("|", map quotemeta($_), @commands); @@ -648,6 +592,10 @@ if (length($host) == 0) { exit(1); } } +if ($opt_C) { + print "clogin -t $timeo -c\'$arista_cmds\' $host\n"; + exit(0); +} open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; select(OUTPUT); # make OUTPUT unbuffered if debugging @@ -706,8 +654,8 @@ TOP: while() { if (!defined($prompt)) { $prompt = ($_ =~ /^([^#]+#)/)[0]; $prompt =~ s/([][}{)(\\])/\\$1/g; - # "time in prompt" hack: - $prompt =~ s/\d+:\d+:\d+/\\d+:\\d+:\\d+/; + # "time in prompt" hack: + $prompt =~ s/\d+:\d+:\d+/\\d+:\\d+:\\d+/; print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); } print STDERR ("HIT COMMAND:$_") if ($debug); @@ -716,7 +664,7 @@ TOP: while() { $clean_run = 0; last TOP; } - $rval = &{$commands{$cmd}}; + $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd); delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; @@ -737,7 +685,9 @@ if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { # check for completeness if (scalar(%commands) || !$clean_run || !$found_end) { - if (scalar(%commands)) { + if (scalar(keys %commands) eq $commandcnt) { + printf(STDERR "$host: missed cmd(s): all commands\n"); + } elsif (scalar(%commands)) { printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); } From bbe8913a4ede77a2a1c69102df4b261f066c651d Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 9 Feb 2016 11:20:02 -0500 Subject: [PATCH 22/38] Indent using spaces --- bin/arrancid.in | 624 ++++++++++++++++++++++++------------------------ 1 file changed, 312 insertions(+), 312 deletions(-) diff --git a/bin/arrancid.in b/bin/arrancid.in index defff51..9fb401d 100644 --- a/bin/arrancid.in +++ b/bin/arrancid.in @@ -64,31 +64,31 @@ $found_end = 0; $found_version = 0; $found_env = 0; $found_diag = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # clogin timeout in seconds my(@commandtable, %commands, @commands);# command lists -my($aclsort) = ("ipsort"); # ACL sorting mode -my($filter_commstr); # SNMP community string filtering -my($filter_pwds); # password filtering mode +my($aclsort) = ("ipsort"); # ACL sorting mode +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; + && 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"; - } + 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"; + $history{++$#history} = "@string"; } else { - print "@string"; + print "@string"; } $hist_tag = $new_hist_tag; $command = $new_command; @@ -104,8 +104,8 @@ sub keynsort { local($i) = 0; local(@sorted_lines); foreach $key (sort numerically keys(%lines)) { - $sorted_lines[$i] = $lines{$key}; - $i++; + $sorted_lines[$i] = $lines{$key}; + $i++; } @sorted_lines; } @@ -117,8 +117,8 @@ sub keysort { local($i) = 0; local(@sorted_lines); foreach $key (sort keys(%lines)) { - $sorted_lines[$i] = $lines{$key}; - $i++; + $sorted_lines[$i] = $lines{$key}; + $i++; } @sorted_lines; } @@ -130,8 +130,8 @@ sub valsort{ local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } @@ -142,8 +142,8 @@ sub numsort { local($i) = 0; local(@sorted_lines); foreach $num (sort {$a <=> $b} keys %lines) { - $sorted_lines[$i] = $lines{$num}; - $i++; + $sorted_lines[$i] = $lines{$num}; + $i++; } @sorted_lines; } @@ -156,8 +156,8 @@ sub ipsort { local($i) = 0; local(@sorted_lines); foreach $addr (sort sortbyipaddr keys %lines) { - $sorted_lines[$i] = $lines{$addr}; - $i++; + $sorted_lines[$i] = $lines{$addr}; + $i++; } @sorted_lines; } @@ -176,11 +176,11 @@ sub ShowVersion { print STDERR " In ShowVersion: $_" if ($debug); while () { - tr/\015//d; - if (/^$prompt/) { $found_version = 1; last}; - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; - return(0) if ($found_version); # Only do this routine once + tr/\015//d; + if (/^$prompt/) { $found_version = 1; last}; + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; + return(0) if ($found_version); # Only do this routine once ( $key, $val ) = split( /:\s+/, $_, 2 ); if ( ! $val ) { @@ -200,18 +200,18 @@ sub DiffConfig { my($havediffs) = 0; while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); - ProcessHistory("DIFFS","keysort","BB","!$_"); - $havediffs = 1; + ProcessHistory("DIFFS","keysort","BB","!$_"); + $havediffs = 1; } if ($havediffs) { - ProcessHistory("DIFFS","keysort","AA","!*****************************\n"); - ProcessHistory("DIFFS","keysort","AB","!*** unsaved changes exist ***\n"); - ProcessHistory("DIFFS","keysort","AC","!*****************************\n"); - ProcessHistory("DIFFS","keysort","CC","!\n"); + ProcessHistory("DIFFS","keysort","AA","!*****************************\n"); + ProcessHistory("DIFFS","keysort","AB","!*** unsaved changes exist ***\n"); + ProcessHistory("DIFFS","keysort","AC","!*****************************\n"); + ProcessHistory("DIFFS","keysort","CC","!\n"); } return; } @@ -223,18 +223,18 @@ sub ShowEnv { $fans = 0; $supplies = 0; while () { - tr/\015//d; - if (/^$prompt/) { $found_env = 1; last}; - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; - return(0) if ($found_env); # Only do this routine once - - if (!defined($E0)) { - $E0 = 1; - ProcessHistory("COMMENTS","keysort","E0","!\n"); - } + tr/\015//d; + if (/^$prompt/) { $found_env = 1; last}; + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; + return(0) if ($found_env); # Only do this routine once + + if (!defined($E0)) { + $E0 = 1; + ProcessHistory("COMMENTS","keysort","E0","!\n"); + } /^(System \S+ status is|Action on overheat|Airflow)/ && - ProcessHistory("COMMENTS","keysort","E0","!$_") && next; + ProcessHistory("COMMENTS","keysort","E0","!$_") && next; if ( /^Fan\s+Status\s+/ ) { $fans = 1; next; @@ -258,14 +258,14 @@ sub ShowBoot { print STDERR " In ShowBoot: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; - - if (!defined($B0)) { - $B0 = 1; ProcessHistory("COMMENTS","","","!\n"); - } + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; + + if (!defined($B0)) { + $B0 = 1; ProcessHistory("COMMENTS","","","!\n"); + } ProcessHistory("COMMENTS","","","!$_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -277,15 +277,15 @@ sub ShowBootExt { print STDERR " In ShowBootExt: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; return(0) if /^% Error displaying /; - if (!defined($C0)) { - $C0 = 1; ProcessHistory("COMMENTS","","","!\n"); - } + if (!defined($C0)) { + $C0 = 1; ProcessHistory("COMMENTS","","","!\n"); + } ProcessHistory("COMMENTS","","","!BootExtension: $_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -297,15 +297,15 @@ sub ShowExt { print STDERR " In ShowExt: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; return(0) if /^No extensions are available/; - if (!defined($D0)) { - $D0 = 1; ProcessHistory("COMMENTS","","","!Extensions:\n"); - } + if (!defined($D0)) { + $D0 = 1; ProcessHistory("COMMENTS","","","!Extensions:\n"); + } ProcessHistory("COMMENTS","","","!$_"); } ProcessHistory("COMMENTS","","","!\n"); @@ -317,22 +317,22 @@ sub ShowFlash { print STDERR " In ShowFlash: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; # persist changes constantly if you're running ntp, so # skip its updates. /\spersist$/ && next; - # Scheduled commands can cause free space to constantly - # change. Even the trick of summarizing the free space - # doesn't help, since it can oscillate, e.g., between - # 1006MB and 1007MB. Just skip the free space. - /.*\((\d+) bytes free\)/ && next; + # Scheduled commands can cause free space to constantly + # change. Even the trick of summarizing the free space + # doesn't help, since it can oscillate, e.g., between + # 1006MB and 1007MB. Just skip the free space. + /.*\((\d+) bytes free\)/ && next; - ProcessHistory("FLASH","","","!Flash: $_"); + ProcessHistory("FLASH","","","!Flash: $_"); } ProcessHistory("","","","!\n"); return; @@ -343,13 +343,13 @@ sub ShowInventory { print STDERR " In ShowInventory: $_" if ($debug); while () { - tr/\015//d; - return if (/^\s*\^$/); - last if (/^$prompt/); - next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if /^% Invalid input/; + tr/\015//d; + return if (/^\s*\^$/); + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^% Invalid input/; - ProcessHistory("INVENTORY","","","!$_"); + ProcessHistory("INVENTORY","","","!$_"); } ProcessHistory("INVENTORY","","","!\n"); @@ -378,184 +378,184 @@ sub WriteTerm { print STDERR " In WriteTerm: $_" if ($debug); while () { - tr/\015//d; - last if (/^$prompt/); - return(1) if /^% Invalid input/; - return(0) if ($found_end); # Only do this routine once + tr/\015//d; + last if (/^$prompt/); + return(1) if /^% Invalid input/; + return(0) if ($found_end); # Only do this routine once - # Dog gone Cool matches to process the rest of the config + # Dog gone Cool matches to process the rest of the config # Lots of Cisco-specific stuff here, but leaving it alone for now. - /^tftp-server flash / && next; # kill any tftp remains - /^ntp clock-period / && next; # kill ntp clock-period - /^ length / && next; # kill length on serial lines - /^ width / && next; # kill width on serial lines - $lineauto = 1 if /^ modem auto/; - /^ speed / && $lineauto && next; # kill speed on serial lines - /^ clockrate / && next; # kill clockrate on serial interfaces - /^! Time: / && next; # EOS gives the time that a "show running" command was run - if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { - ProcessHistory("ENABLE","","","!$1$2$3 \n"); - next; - } - if (/^(enable secret) / && $filter_pwds >= 2) { - ProcessHistory("ENABLE","","","!$1 \n"); - next; - } - if (/^username (\S+)(\s.*)? secret /) { - if ($filter_pwds >= 2) { - ProcessHistory("USER","keysort","$1", - "!username $1$2 secret \n"); - } else { - ProcessHistory("USER","keysort","$1","$_"); - } - next; - } - if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { - if ($filter_pwds >= 2) { - ProcessHistory("USER","keysort","$1", - "!username $1$2 password \n"); - } elsif ($filter_pwds >= 1 && $4 ne "5"){ - ProcessHistory("USER","keysort","$1", - "!username $1$2 password \n"); - } else { - ProcessHistory("USER","keysort","$1","$_"); - } - next; - } - if (/^(\s*)password / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1password \n"); - next; - } - if (/^(\s*)secret / && $filter_pwds >= 2) { - ProcessHistory("","","","!$1secret \n"); - next; - } - if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { - ProcessHistory("","","","! neighbor $1 password \n"); - next; - } - if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - # isis passwords appear to be completely plain-text - if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) { - ProcessHistory("","","","!isis password $2\n"); next; - } - if (/^\s+(domain-password|area-password) (\S+)( .*)?/ - && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $3\n"); next; - } - # this is reversable, despite 'md5' in the cmd - if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - # this is also reversable, despite 'md5 encrypted' in the cmd - if (/^( message-digest-key \d+ md5 (7|encrypted)) / - && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - # sort route-maps - if (/^route-map (\S+)/) { - my($key) = $1; - my($routemap) = $_; - while () { - tr/\015//d; - last if (/^$prompt/ || ! /^(route-map |[ !])/); - if (/^route-map (\S+)/) { - ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); - $key = $1; - $routemap = $_; - } else { - $routemap .= $_; - } - } - ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); - } - # filter out any RCS/CVS tags to avoid confusing local CVS storage - s/\$(Revision|Id):/ $1:/; - # order access-lists - /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && - ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next; - # order extended access-lists - /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && - ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; - /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && - ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; - /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && - ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next; - # order arp lists - /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && - ProcessHistory("ARP","$aclsort","$1","$_") && next; - /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && - ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n") - && next; - # order logging statements - /^logging (\d+\.\d+\.\d+\.\d+)/ && - ProcessHistory("LOGGING","ipsort","$1","$_") && next; - # order/prune snmp-server host statements - # we only prune lines of the form - # snmp-server host a.b.c.d - if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { - if ($filter_commstr) { - my($ip) = $1; - my($line) = "snmp-server host $ip"; - my(@tokens) = split(' ', $'); - my($token); - while ($token = shift(@tokens)) { - if ($token eq 'version') { - $line .= " " . join(' ', ($token, shift(@tokens))); - if ($token eq '3') { - $line .= " " . join(' ', ($token, shift(@tokens))); - } - } elsif ($token eq 'vrf') { - $line .= " " . join(' ', ($token, shift(@tokens))); - } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { - $line .= " " . $token; - } else { - $line = "!$line " . join(' ', ("", - join(' ',@tokens))); - last; - } - } - ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); - } else { - ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); - } - next; - } - if (/^(snmp-server community) (\S+)/) { - if ($filter_commstr) { - ProcessHistory("SNMPSERVERCOMM","keysort","$_", - "!$1 $'") && next; - } else { - ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; - } - } - # prune tacacs/radius server keys - if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\w+/ - && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 $'"); next; - } - # order alias statements - /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; - # delete ntp auth password - this md5 is a reversable too - if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { - ProcessHistory("","","","!$1 \n"); next; - } - # order ntp peers/servers - if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { - $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); - ProcessHistory("NTP","keysort",$sortkey,"$_"); - next; - } - - # catch anything that wasnt matched above. - ProcessHistory("","","","$_"); - # end of config. - if (/^end$/) { - $found_end = 1; - return(0); - } + /^tftp-server flash / && next; # kill any tftp remains + /^ntp clock-period / && next; # kill ntp clock-period + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines + $lineauto = 1 if /^ modem auto/; + /^ speed / && $lineauto && next; # kill speed on serial lines + /^ clockrate / && next; # kill clockrate on serial interfaces + /^! Time: / && next; # EOS gives the time that a "show running" command was run + if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { + ProcessHistory("ENABLE","","","!$1$2$3 \n"); + next; + } + if (/^(enable secret) / && $filter_pwds >= 2) { + ProcessHistory("ENABLE","","","!$1 \n"); + next; + } + if (/^username (\S+)(\s.*)? secret /) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!username $1$2 secret \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { + if ($filter_pwds >= 2) { + ProcessHistory("USER","keysort","$1", + "!username $1$2 password \n"); + } elsif ($filter_pwds >= 1 && $4 ne "5"){ + ProcessHistory("USER","keysort","$1", + "!username $1$2 password \n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + if (/^(\s*)password / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1password \n"); + next; + } + if (/^(\s*)secret / && $filter_pwds >= 2) { + ProcessHistory("","","","!$1secret \n"); + next; + } + if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { + ProcessHistory("","","","! neighbor $1 password \n"); + next; + } + if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # isis passwords appear to be completely plain-text + if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) { + ProcessHistory("","","","!isis password $2\n"); next; + } + if (/^\s+(domain-password|area-password) (\S+)( .*)?/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $3\n"); next; + } + # this is reversable, despite 'md5' in the cmd + if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # this is also reversable, despite 'md5 encrypted' in the cmd + if (/^( message-digest-key \d+ md5 (7|encrypted)) / + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # sort route-maps + if (/^route-map (\S+)/) { + my($key) = $1; + my($routemap) = $_; + while () { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map (\S+)/) { + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + $key = $1; + $routemap = $_; + } else { + $routemap .= $_; + } + } + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + } + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + # order access-lists + /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && + ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next; + # order extended access-lists + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && + ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && + ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && + ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next; + # order arp lists + /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && + ProcessHistory("ARP","$aclsort","$1","$_") && next; + /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && + ProcessHistory("PACL $1 $3","$aclsort","$4","ip prefix-list $1 $3 $4$5\n") + && next; + # order logging statements + /^logging (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("LOGGING","ipsort","$1","$_") && next; + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d + if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { + if ($filter_commstr) { + my($ip) = $1; + my($line) = "snmp-server host $ip"; + my(@tokens) = split(' ', $'); + my($token); + while ($token = shift(@tokens)) { + if ($token eq 'version') { + $line .= " " . join(' ', ($token, shift(@tokens))); + if ($token eq '3') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } + } elsif ($token eq 'vrf') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . join(' ', ("", + join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if ($filter_commstr) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_", + "!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + # prune tacacs/radius server keys + if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\w+/ + && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 $'"); next; + } + # order alias statements + /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; + # delete ntp auth password - this md5 is a reversable too + if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { + ProcessHistory("","","","!$1 \n"); next; + } + # order ntp peers/servers + if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { + $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); + ProcessHistory("NTP","keysort",$sortkey,"$_"); + next; + } + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + # end of config. + if (/^end$/) { + $found_end = 1; + return(0); + } } return(0); @@ -563,16 +563,16 @@ sub WriteTerm { # Main @commandtable = ( - {'show version' => 'ShowVersion'}, - {'show boot-config' => 'ShowBoot'}, - {'show env all' => 'ShowEnv'}, - {'dir flash:' => 'ShowFlash'}, - {'show inventory' => 'ShowInventory'}, - {'show boot-extensions' => 'ShowBootExt'}, - {'show extensions' => 'ShowExt'}, - {'diff startup-config running-config' => 'DiffConfig'}, - #{'show tech ribd running' => 'WriteRibd'}, - {'show running-config' => 'WriteTerm'}, + {'show version' => 'ShowVersion'}, + {'show boot-config' => 'ShowBoot'}, + {'show env all' => 'ShowEnv'}, + {'dir flash:' => 'ShowFlash'}, + {'show inventory' => 'ShowInventory'}, + {'show boot-extensions' => 'ShowBootExt'}, + {'show extensions' => 'ShowExt'}, + {'diff startup-config running-config' => 'DiffConfig'}, + #{'show tech ribd running' => 'WriteRibd'}, + {'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. @@ -585,11 +585,11 @@ $cmds_regexp = join("|", map quotemeta($_), @commands); if (length($host) == 0) { if ($file) { - print(STDERR "Too few arguments: file name required\n"); - exit(1); + print(STDERR "Too few arguments: file name required\n"); + exit(1); } else { - print(STDERR "Too few arguments: host name required\n"); - exit(1); + print(STDERR "Too few arguments: host name required\n"); + exit(1); } } if ($opt_C) { @@ -609,10 +609,10 @@ if ($file) { print STDERR "executing clogin -t $timeo -c\"$arista_cmds\" $host\n" if ($debug); print STDOUT "executing clogin -t $timeo -c\"$arista_cmds\" $host\n" if ($log); if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { - system "clogin -t $timeo -c \"$arista_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; - open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + system "clogin -t $timeo -c \"$arista_cmds\" $host $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; } else { - open(INPUT,"clogin -t $timeo -c \"$arista_cmds\" $host ) { tr/\015//d; if (/[>#]\s?exit$/) { - $clean_run = 1; - last; + $clean_run = 1; + last; } if (/^Error:/) { - print STDOUT ("$host clogin error: $_"); - print STDERR ("$host clogin error: $_") if ($debug); - $clean_run = 0; - last; + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run = 0; + last; } while (/#\s*($cmds_regexp)\s*$/) { - $cmd = $1; - if (!defined($prompt)) { - $prompt = ($_ =~ /^([^#]+#)/)[0]; - $prompt =~ s/([][}{)(\\])/\\$1/g; - # "time in prompt" hack: - $prompt =~ s/\d+:\d+:\d+/\\d+:\\d+:\\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}}(*INPUT, *OUTPUT, $cmd); - delete($commands{$cmd}); - if ($rval == -1) { - $clean_run = 0; - last TOP; - } + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + # "time in prompt" hack: + $prompt =~ s/\d+:\d+:\d+/\\d+:\\d+:\\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}}(*INPUT, *OUTPUT, $cmd); + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } } } print STDOUT "Done $logincmd: $_\n" if ($log); @@ -686,15 +686,15 @@ if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { # check for completeness if (scalar(%commands) || !$clean_run || !$found_end) { if (scalar(keys %commands) eq $commandcnt) { - printf(STDERR "$host: missed cmd(s): all commands\n"); + printf(STDERR "$host: missed cmd(s): all commands\n"); } elsif (scalar(%commands)) { - printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); - printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); } if (!$clean_run || !$found_end) { - print STDOUT "$host: End of run not found\n"; - print STDERR "$host: End of run not found\n" if ($debug); - system("/usr/bin/tail -1 $host.new"); + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); } unlink "$host.new" if (! $debug); } From 2b73d5ebd4b40f8154591b1352ebf97a82fba9c9 Mon Sep 17 00:00:00 2001 From: dsx Date: Thu, 21 Jul 2016 15:38:58 -0400 Subject: [PATCH 23/38] Local changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index df734bc..3623f96 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +rancid-git (2.3.9-5) unstable; urgency=low + [ Egor Miadzvedzeu ] + * Unofficial package + * Added Huawei config + + -- Egor Miadzvedzeu Thu, 21 Jul 2016 15:38:26 -0400 rancid-git (2.3.9-4) unstable; urgency=low [ Vincent Bernat ] From b27cee9ba50f1692f905c021a2cc80a71c31d30b Mon Sep 17 00:00:00 2001 From: manyax Date: Wed, 13 Jan 2016 14:20:09 +0100 Subject: [PATCH 24/38] rancid files for hp1910 and zte zrx10 --- bin/hp1910login | 908 ++++++++++++++++++++++++++++++++++++++++++++++ bin/hp1910rancid | 843 +++++++++++++++++++++++++++++++++++++++++++ bin/ztelogin | 922 +++++++++++++++++++++++++++++++++++++++++++++++ bin/zterancid | 324 +++++++++++++++++ 4 files changed, 2997 insertions(+) create mode 100644 bin/hp1910login create mode 100644 bin/hp1910rancid create mode 100644 bin/ztelogin create mode 100644 bin/zterancid diff --git a/bin/hp1910login b/bin/hp1910login new file mode 100644 index 0000000..25d52cf --- /dev/null +++ b/bin/hp1910login @@ -0,0 +1,908 @@ +#! /usr/bin/expect -- +## +## $Id: clogin.in 3057 2015-03-13 20:32:14Z heas $ +## +## rancid 3.2 +## Copyright (c) 1997-2015 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# The expect login scripts were based on Erik Sherk's gwtn, by permission. +# +# clogin - Cisco login +# +# Most options are intuitive for logging into a Cisco router. +# The default is to enable (thus -noenable). Some folks have +# setup tacacs to have a user login at priv-lvl = 15 (enabled) +# so the -autoenable flag was added for this case (don't go through +# the process of enabling and the prompt will be the "#" prompt. +# The default username password is the same as the vty password. +# + +# Usage line +set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set avenable 1 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 +# Save config, if prompted +set do_saveconfig 0 +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeoutdflt 45 +# Some CLIs having problems if we write too fast (Extreme, PIX, Cat) +set send_human {.2 .1 .4 .2 1} + +# Find the user in the ENV, or use the unix userid. +if {[info exists env(CISCO_USER)]} { + set default_user $env(CISCO_USER) +} elseif {[info exists env(USER)]} { + set default_user $env(USER) +} elseif {[info exists env(LOGNAME)]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [catch {exec id} reason] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} +if {[info exists env(CLOGINRC)]} { + set password_file $env(CLOGINRC) +} + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Expect debug mode + -d* { + exp_internal 1 + # Username + } -u* { + if {! [regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [lindex $argv $i] + } + # VTY Password + } -p* { + if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [lindex $argv $i] + } + set do_passwd 0 + # ssh passphrase + } -r* { + if {! [regexp .\[rR\](.+) $arg ignore passphrase]} { + incr i + set avpassphrase [lindex $argv $i] + } + # VTY Password + } -v* { + if {! [regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [lindex $argv $i] + } + set do_passwd 0 + # Version string + } -V* { + send_user "rancid 3.2\n" + exit 0 + # Enable Username + } -w* { + if {! [regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [lindex $argv $i] + } + # Environment variable to pass to -s scripts + } -E* { + if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* { + if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [lindex $argv $i] + } + set do_enapasswd 0 + # Command to run. + } -c* { + if {! [regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [lindex $argv $i] + } + set do_command 1 + # Expect script to run. + } -s* { + if {! [regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [lindex $argv $i] + } + if { ! [file readable $sfile] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # save config on exit + } -S* { + set do_saveconfig 1 + # 'ssh -c' cypher type + } -y* { + if {! [regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [lindex $argv $i] + } + # alternate cloginrc file + } -f* { + if {! [regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [lindex $argv $i] + } + # Timeout + } -t* { + if {! [regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeoutdflt [lindex $argv $i] + } + # Command file + } -x* { + if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [lindex $argv $i] + } + if [catch {set cmd_fd [open $cmd_file r]} reason] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + set avenable 0 + # Does tacacs automatically enable us? + } -autoenable { + set avautoenable 1 + set avenable 0 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [regexp "^/" $args ignore] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match -nocase [lindex $line 0] $router] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [catch {source $password_file} reason] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +# returns: 0 on success, 1 on failure, -1 if rsh was used successfully +proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } { + global command spawn_id in_proc do_command do_script platform passphrase + global prompt prompt_match u_prompt p_prompt e_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + incr progs -1 + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port + if {"$port" == ""} { + set retval [catch {spawn telnet $router} reason] + } else { + set retval [catch {spawn telnet $router $port} reason] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + return 1 + } + } elseif [string match "ssh*" $prog] { + # ssh to the router & try to login with or without an identfile. + regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port + set cmd $sshcmd + if {"$port" != ""} { + set cmd "$cmd -p $port" + } + if {"$identfile" != ""} { + set cmd "$cmd -i $identfile" + } + set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason] + if { $retval } { + send_user "\nError: $cmd failed: $reason\n" + return 1 + } + } elseif ![string compare $prog "rsh"] { + if { ! $do_command } { + if { [llength $cmethod] == 1 } { + send_user "\nError: rsh is an invalid method for -x and " + send_user "interactive logins\n" + } + if { $progs == 0 } { + return 1 + } + continue; + } + + # handle escaped ;s in commands, and ;; and ^; + regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand + regsub {^;} $esccommand "\u002;" command + set sep "\\1\u001" + regsub -all {([^\\])\;} $command "$sep" esccommand + set sep "\u001" + set commands [split $esccommand $sep] + set num_commands [llength $commands] + set rshfail 0 + for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { + log_user 0 + set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason] + if { $retval } { + send_user "\nError: rsh failed: $reason\n" + log_user 1; return 1 + } + send_user "$router# [lindex $commands $i]\n" + + # rcmd does not get a pager and no prompts, so we just have to + # look for failures & lines. + expect { + "Connection refused" { catch {close}; catch {wait}; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; catch {wait}; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; catch {wait}; + send_user "\nError: Unknown host\ + $router\n" + set rshfail 1 + } + -re "\b+" { exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + timeout { catch {close}; catch {wait}; + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; catch {wait}; } + } + log_user 1 + } + if { $rshfail } { + if { !$progs } { + return 1 + } else { + continue + } + } + # fake the end of the session for rancid. + send_user "$router# exit\n" + # return rsh "success" + return -1 + } else { + send_user "\nError: unknown connection method: $prog\n" + return 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + -re "^<-+ More -+>\[^\n\r]*" { + # ASA will use the pager for long banners + send " "; + exp_continue + } + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection closed ($prog): $router\n" + return 1 + } + } + eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } + -nocase "unknown host\r" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + "Host is unreachable" { + send_user "\nError: Host Unreachable: $router\n"; + catch {close}; catch {wait}; + return 1 + } + "No address associated with name" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue + } + -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" { + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 + } + -re "Offending key for .* \\(yes/no\\)\\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "(denied|Sorry)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Login failed" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + -re "% (Bad passwords|Authentication failed)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Press any key to continue" { + # send_user "Pressing the ANY key\n" + send "\r" + exp_continue + } + -re "Enter Selection: " { + # Catalyst 1900s have some lame menu. Enter + # K to reach a command-line. + send "K\r" + exp_continue + } + -re "Last login:" { + exp_continue + } + -re "Press the key \[^\r\n]+\[\r\n]+" { + exp_continue + } + -re "@\[^\r\n]+ $p_prompt" { + # ssh pwd prompt + sleep 1 + send -- "$userpswd\r" + exp_continue + } + -re "Enter passphrase.*: " { + # sleep briefly to allow time for stty -echo + sleep .3 + send -- "$passphrase\r" + exp_continue + } + -re "$u_prompt" { + send -- "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send -- "$userpswd\r" + } else { + send -- "$passwd\r" + } + exp_continue + } + -re "$prompt" { + set prompt_match $expect_out(0,string); + break; + } + "Login invalid" { + send_user "\nError: Invalid login: $router\n"; + catch {close}; catch {wait}; return 1 + } + -re "\[^\r\n]*\[\r\n]+" { exp_continue; } + } + } + + set in_proc 0 + return 0 +} + +# Enable +proc do_enable { enauser enapasswd } { + global do_saveconfig in_proc + global prompt u_prompt e_prompt enacmd + set in_proc 1 + + send "$enacmd\r" + expect { + -re "$u_prompt" { send -- "$enauser\r"; exp_continue} + -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} + "#" { set prompt "#" } + "(enable)" { set prompt "> \\(enable\\) " } + "% Invalid input" { + send_user "\nError: Unrecognized command, check your enable command\n"; + return 1 + } + -re "(denied|Sorry|Incorrect)" { + # % Access denied - from local auth and poss. others + send_user "\nError: Check your Enable passwd\n"; + return 1 + } + "% Error in authentication" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + "% Bad passwords" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + } + # We set the prompt variable (above) so script files don't need + # to know what it is. + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global do_saveconfig in_proc platform + set in_proc 1 + + if { [string compare "extreme" "$platform"] } { + # match cisco config mode prompts too, such as router(config-if)#, + # but catalyst does not change in this fashion. + regsub -lineanchor -- {^(.{1,11}).*([#>])$} $prompt {\1} reprompt + regsub -all -- {[\\]$} $reprompt {} reprompt + append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} + } else { + set reprompt $prompt + } + + # this is the only way i see to get rid of more prompts in o/p..grrrrr + log_user 0 + + # handle escaped ;s in commands, and ;; and ^; + regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand + regsub {^;} $esccommand "\u002;" command + set sep "\\1\u001" + regsub -all {([^\\]);} $command "$sep" esccommand + set sep "\u001" + set commands [split $esccommand $sep] + set num_commands [llength $commands] + # the pager can not be turned off on the PIX, so we have to look + # for the "More" prompt. the extreme is equally obnoxious in pre-12.3 XOS, + # with a global switch in the config. + for {set i 0} {$i < $num_commands} { incr i} { + send -- "[subst -nocommands [lindex $commands $i]]\r" + expect { + -re "\b+" { exp_continue } + -re "^\[^\n\r *]*($reprompt|$prompt)" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue } + -re "^ {0,2}-+ More .*-+.*\[^\n\r]*" { + # H3C pager prompt + sleep 0.1 + send " " + exp_continue } + -re "^---- More ----\[^\n\r]*" { + # Comware7 pager prompt + sleep 0.1 + send " " + exp_continue } + } + } + log_user 1 + + send -h "quit\r" + + expect { + -re "\[\n\r]+" { exp_continue } + -re "\[^\n\r *]Note:" { return 0 } + timeout { catch {close}; catch {wait}; + return 0 + } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +set exitval 0 +set prompt_match "" +foreach router [lrange $argv $i end] { + set router [string tolower $router] + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # device timeout + set timeout [find timeout $router] + if { [llength $timeout] == 0 } { + set timeout $timeoutdflt + } + + # Default prompt. + set prompt [join [find prompt $router] ""] + if { [llength $prompt] == 0 } { + set prompt "(>|#| \\(enable\\))" + } + + # look for autoenable option in .cloginrc & cmd-line + set ae [find autoenable $router] + if { "$ae" == "1" || $avautoenable } { + set autoenable 1 + } else { + set autoenable 0 + } + # look for enable options in .cloginrc & cmd-line + if { $avenable == 0 } { + set enable 0 + } else { + set ne [find noenable $router] + if { "$ne" == "1" || "$autoenable" == "1" } { + set enable 0 + } else { + set enable 1 + } + } + + # Figure out passwords + if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user -- "\nError: no password for $router in $password_file.\n" + continue + } + if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { + send_user -- "\nError: no enable password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out enable command + set enacmd [join [find enablecmd $router] ""] + if { "$enacmd" == "" } { set enacmd "enable" } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(\[Uu]sername|Login|login|user name|User):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { + set e_prompt "\[Pp]assword:" + } else { + set e_prompt [join [lindex $e_prompt 0] ""] + } + + # Figure out identity file to use + set identfile [join [lindex [find identity $router] 0] ""] + + # Figure out passphrase to use + if {[info exists avpassphrase]} { + set passphrase $avpassphrase + } else { + set passphrase [join [lindex [find passphrase $router] 0] ""] + } + if { ! [string length "$passphrase"]} { + set passphrase $passwd + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [join [lindex [find sshcmd $router] 0] ""] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} { + incr exitval + # if login failed or rsh was unsuccessful, move on to the next device + continue + } + # Figure out the prompt. + if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } { + set enable 0 + } + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + incr exitval + catch {close}; catch {wait}; + continue + } + } + } + # we are logged in, now figure out the full prompt + send "\r" + regsub -all {^(\^*)(.*)} $prompt {\2} reprompt + expect { + -re "\[\r\n]+" { exp_continue; } + -re "^(.+\[:.])1 ($reprompt)" { # stoopid extreme cmd-line numbers and + # prompt based on state of config changes, + # which may have an * at the beginning. + set junk $expect_out(1,string) + regsub -all "^\\\* " $expect_out(1,string) {} junk + regsub -all "\[\]\[\(\)]" $junk {\\&} junk; + set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; + set platform "extreme" + } + -re "^.+$reprompt" { set junk $expect_out(0,string); + regsub -all "\[\]\[\(\)+]" $junk {\\&} prompt; + } + } + if { $do_command || $do_script } { + send "_cmdline-mode on\r" + expect { + -re "All commands can be displayed*" {send -- "Y\r"; exp_continue} + -re "Please input password:" {send -- "512900\r"; exp_continue} + ">" { set prompt ">" } + -re "Error: Invalid password." { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + -re $prompt {} + } + } + if { $do_command } { + if {[run_commands $prompt $command]} { + incr exitval + continue + } + } elseif { $do_script } { + source $sfile + catch {close}; + } else { + label $router + log_user 1 + interact + } + + # End of for each router + catch {wait}; + sleep 0.3 +} +exit $exitval diff --git a/bin/hp1910rancid b/bin/hp1910rancid new file mode 100644 index 0000000..1167782 --- /dev/null +++ b/bin/hp1910rancid @@ -0,0 +1,843 @@ +#! /usr/bin/perl +## +## +## rancid 3.2 +## Copyright (c) 1997-2015 by Terrapin Communications, Inc. +## All rights reserved. +## +# HP1910rancid - adapted for HP 1910 ethernet switches by Alexandru Musat +# +# Modified from h3crancid for use with HP 1910 1/9/2016 +# +# h3crancid +# +# h3clogin/h3crancid covers the following product ranges: +# +# * 3Com SuperStack 4 (from 'joint venture' with Huawei) +# * H3C +# * HP Networking ('A' & some 'E' portfolio, post-2010 3Com acquitision) +# +# They may also work with some Huawei equipment. +# +# https://sites.google.com/site/jrbinks/code/rancid/h3c + +# +# Usage: h3crancid [-dltCV] [-f filename | hostname] +# + +# You can modify the behaviour by changing the variables listed in +# 'END-USER TWEAKS', below. + +# Notable changes from standard *rancid programs: +# +# * abstracted path to the 'tail' utility +# * altered "cisco_cmds" to be "device_cmds" +# * define and use $logincmd +# * abstracted $rancid_type + +# TODO: +# +# It may be useful to pull common subroutines like the sorting ones into +# a library for use by all the *rancid programs. +# +# abstract the comment-out char (i.e., '!' here and cisco, '#' on Juniper) +# to a variable. + +# NOTES: +# +# * the dir commands need a user greater than at least level 1 on some +# platforms + +############################################################################ +# END-USER TWEAKS + +# The login program to use. If no path is given, $PATH is searched: +my $logincmd = "hp1910login"; +#my $logincmd = "/usr/local/libexec/h3clogin"; +# +my $TAIL = "/usr/bin/tail"; +# +# Enable display of the FIB: +my $display_fib = 0; +# +# Enable display of the IRF: +my $display_irf = 0; +# +# Enable display of the FTM: +my $display_ftm = 0; +# +# Enable display of the routing table: +my $display_iproutes = 1; +# +# Enable display of the vlans: +my $display_vlan_all = 1; +# +# Enable display of STP root: +my $display_stproot = 1; +# +# Enable display of : xrn-fabric: +my $display_xrn = 0; +# +# Enable display of transceiver interface: +my $display_xcvr_int = 0; + +# END OF END-USER TWEAKS +############################################################################# + +my $rancid_type = 'HP 1910'; + +use Getopt::Std; +getopts('dflt:CV'); +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; +#$timeo = 90; # login command timeout in seconds +$timeo = 20; # login command timeout in seconds + +my(@commandtable, %commands, @commands);# command lists +my($aclsort) = ("ipsort"); # ACL sorting mode +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 is a sort routine that will sort on the +# ip route when the ip route is anywhere in +# the strings. +sub iproutesort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $iproute (sort sortbyiproute keys %lines) { + $sorted_lines[$i] = $lines{$iproute}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP route +sub iprouteval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#); + $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0]))); +} +sub sortbyiproute { + &iprouteval($a) <=> &iprouteval($b); +} + +sub filter_lines { + my ($l) = (@_); + + # Filter out some ANSI crud as a result of us not being able to turn + # off per-session terminal paging: + #s/^\033\[42D +\033\[42D(.+)$/$1/; + # hwlogin+mods: + #s/\033\133\064\062\104\s*\033\133\064\062\104//g; + $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g; + $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g; + $l =~ s/\033\133\064\062\104//g; + $l =~ s/\033\133\061\062\104//g; + $l =~ s/.*\[37D(.*)/$1/g; # MA5600 + # Probably not needed: + $l =~ s/\s*---- More ----\s*//; + $l =~ s/^ //; # Comware7 + $l =~ s/Synchronization is finished.//g; + return $l; +} + +sub DisplayFib { + + print STDERR " In DisplayFib: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + ProcessHistory("FIB","","","!\n! '$cmd':\n!\n"); + + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + return(1) if ( + /^\s+\^$/ || + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ || + /Permission denied\./ + ); + + next if /^$/; + next if /^Destination count: \d+ FIB entry count: \d+/; + + # Chop out some detail that changes over time (Comware 3): + s/(\s+)TimeStamp\s+/$1/; # TimeStamp column heading + + ProcessHistory("FIB","","","! $_\n"); + + if ( m,Destination/Mask, ) { + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + # Chop out some detail that changes over time (Comware 3): + s/(\s+)t\[\d+\]\s+/$1/; # TimeStamp data + + # "display fib" on comware7 shows host entries for things + # learned via arp too. For a distribution router, that's all + # the devices on subnets routed by it! + # If we filter out all "UH" entries that are NOT InLoop, we + # get acceptable output. + # + # So we want to keep: + # + # 0.0.0.0/32 127.0.0.1 UH InLoop0 Null + # + # but reject: + # + # 130.159.44.161/32 130.159.44.161 UH Vlan44 Null + # + # However I've a feeling that this is a problematic + # solution, and some object to the notion that rancid + # should be representing such potentially dynamic data in + # the first place, which is why we created the + # $display_fib flag. + + ($dest, $nexthop, $flag, $outint, $label) = split; + next if ( $flag eq 'UH' && $outint !~ /InLoop/ ); + ProcessHistory("FIB", "iproutesort", "$dest", "! $_\n"); + } + + ProcessHistory("FIB", "", "", "!\n"); + + # return here to ensure that we don't keep swallowing the + # next command's output by returning to the surrounding + # while loop + return(0); + } + } + return(0); +} + +sub DisplayIPRoutes { + print STDERR " In DisplayIPRoutes: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + ProcessHistory("IPR","","","!\n! '$cmd':\n!\n"); + + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + return(1) if ( + /^\s+\^$/ || + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ || + /Permission denied\./ + ); + + ProcessHistory("IPR","","","! $_\n"); + + if ( m,Destination/Mask, ) { + my $lastkey = ""; + my $lastspaces = ""; + while () { + tr/\015//d; + last if(/^\s*$prompt/); + chomp; + $_ = filter_lines($_); + + # If the key is blank, indicating multiple nexthops for + # a particular route, then we use the previous one + if ( m/^\s+(.+)/ ) { + $key = $lastkey; + $line = $key . $lastspaces . $1; + ProcessHistory("IPR", "iproutesort", "$key", "! $line\n"); + # $lastkey and $lastspaces are retained in case + # they are needed for an additional line + } + if ( m/^(\S+)(\s+).+/ ) { + $key = $1; + $line = $_; + $spaces = $2; + ProcessHistory("IPR", "iproutesort", "$key", "! $line\n"); + $lastkey = $key; + $lastspaces = $spaces; + } + } + +# This isn't quite right; for example, it messes up oddities like this: +# ... +# 130.159.2.84/30 OSPF 10 1010 10.159.2.53 Vlan3660 +# 130.159.2.88/30 OSPF 10 1100 10.159.2.53 Vlan3660 +# OSPF 10 1100 10.159.2.49 Vlan3661 +# 130.159.2.92/30 OSPF 10 1015 10.159.2.53 Vlan3660 +# ... + + ProcessHistory("IPR", "", "", "!\n"); + + # return here to ensure that we don't keep swallowing the + # next command's output by returning to the surrounding + # while loop + return(0); + } + } + return(0); +} + +#sub DisplayTransInt { +# print STDERR " In DisplayTransInt: $_" if ($debug); +# +# chomp; +# +# # Display the command we're processing in the output: +# s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; +# ProcessHistory("TRINT","","","! $_\n!\n"); +# +# while () { +# tr/\015//d; +# last if(/^\s*$prompt/); +# chomp; +# $_ = filter_lines($_); +# return(1) if ( +# /^\s+\^$/ || +# /% Too many parameters found at '\^' position/ || +# /% Unrecognized command found at '\^' position/ || +# /(% )?Wrong parameter found at '\^' position/ || +# /% Wrong device .+/ || +# /Permission denied\./ +# ); +# +# +# ProcessHistory("TRINT","","","! $_\n"); +# } +# ProcessHistory("TRINT","","","!\n"); +# return(0); +#} + +#sub DisplayNTPStatus { +# print STDERR " In DisplayNTPStatus: $_" if ($debug); +# +# chomp; +# +# # Display the command we're processing in the output: +# s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; +# ProcessHistory("NTP","","","! $_\n!\n"); +# +# while () { +# tr/\015//d; +# last if(/^\s*$prompt/); +# chomp; +# $_ = filter_lines($_); +# return(1) if ( +# /^\s+\^$/ || +# /% Too many parameters found at '\^' position/ || +# /% Unrecognized command found at '\^' position/ || +# /(% ?)Wrong parameter found at '\^' position/ || +# /% Wrong device .+/ || +# /Permission denied\./ +# ); +# +# next unless m/(Clock status|Clock stratum|Reference clock ID)/; +# +# ProcessHistory("NTP","","","! $_\n"); +# } +# ProcessHistory("NTP","","","!\n"); +# return(0); +#} + +## This routine processes general output of "display" commands +sub CommentOutput { + print STDERR " In CommentOutput: $_" if ($debug); + + chomp; + + # Display the command we're processing in the output: + #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g; + #ProcessHistory("COMMENTS", "", "", "! $_\n!\n"); + #(my $cmd = $_) =~ s/^[\[<].*?[\]>]\a?\s?(.*)/$1/g; + ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n"); + + while () { + tr/\015//d; + + # If we find the prompt, we're done + # Ordinarily this matches from the start of the line, however + # we've seen circumstances at least in Comware7 where the + # prompt is preceded by whitespace, like so: + # ^M^M ^Mdisplay boot-loader^M + last if(/^\s*$prompt/); + chomp; + + # filter out some junk + $_ = filter_lines($_); + + # Some commands are not supported on some models or versions + # of code. These lines simply remove the associated error + # messages: + return(1) if ( + /^\s+\^$/ || + /% Too many parameters found at '\^' position/ || + /% Unrecognized command found at '\^' position/ || + /(% )?Wrong parameter found at '\^' position/ || + /% Wrong device .+/ || + /Permission denied\./ + ); + + # Now we skip or modify some lines from various commands to + # remove irrelevant content, or to avoid insignificant diffs + + # 'display local-user': + s/\s+Current AccessNum:.+$//; + + # 'display version': + next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/); + # No longer necessary since skipping the whole Uptime line: + # Mangle these lines: + #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/; + #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/; + + # MSRs display a 'last reboot' time, but sometimes the seconds + # vary by one or two (presumably internal rounding), so simply make + # the last digit a fixed '0'. It would probably be safer to make + # the last two digits a fixed '00'. + # (Thx Alexander Belokopytov) + s/(^Last reboot.+)\d$/${1}0/; + + # 'dir ' commands + if ( $cmd =~ /^dir / ) { + # First field is just an index number, chop it out + s/^\s+\d+\s+(.+)/ $1/; + # Remove filenames that are updated frequently + next if ( + /logfile\.log$/ || + /lauth\.dat$/ || + /ifindex\.dat$/ || + /startup\.mdb$/ || + /private-data\.txt$/ || + /.+ KB total \(.+ KB free/ || + /.+ KB total \(.+ KB free/ || + /\.trash/ + ); + } + + # 'display ospf brief'/'display ospf' + if ( $cmd =~ 'display ospf( brief)?' ) { + #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/); + next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i); + } + + if ( $cmd eq 'display power' ) { + next if (/^(\s+Input Power).+$/); + } + + if ( $cmd eq 'display poe powersupply' ) { + next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/); + } + + if ( $cmd eq 'display ntp-service status' ) { + next unless m/(Clock status|Clock stratum|Reference clock ID)/i; + } + + if ( $cmd eq 'display transceiver interface' ) { + s/^(\S+ transceiver information:).+$/$1/; # filter random garbage + s/^Error: The transceiver is absent.$/ No transceiver present./; + s/^Error: The combo port is inactive.$/ Inactive combo port./; + } + + # Add the processed lines to the output buffer: + ProcessHistory("COMMENTS","","","! $_\n"); + } + + # Add a blank comment line to the output buffer + ProcessHistory("COMMENTS", "", "", "!\n"); + return(0); +} + +## This routine processes a "display current" +sub DisplayCurrent { + print STDERR " In DisplayCurrent: $_" if ($debug); + + # We aren't chomping these lines + + while () { + tr/\015//d; + last if(/^\s*$prompt/); + + $_ = filter_lines($_); + return(0) if ($found_end); + + # Filter out some sensitive data: + if ( $filter_commstr && + /^ ?(snmp-agent (usm-user|community (read|write)) )(\S+)/ + ) { + ProcessHistory("","","","! $1$'"); + next; + } + if ( $filter_pwds >= 1 && + /^ ?(password (?:simple|cipher) )(\S+)/ || + /^ ?(super password( level \d)? (cipher|simple)) (\S+)/ || + /^ ?(set authentication password (cipher|simple)) (\S+)/ || + /^ ?(key (?:authentication|accounting) )(\S+)/ + ) { + ProcessHistory("","","","! $1$'"); + next; + } + + # Filter mac addresses dynamically added to config + next if (/^ ?mac-address security.+$/); + + ProcessHistory("", "", "", "$_"); + + # end of config + + if (/^return/) { + $found_end = 1; + return(0); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +## Not all commands are supported on all models and code versions +## Not all of these should necessarily be included +@commandtable = ( +# Commands relating to the operating system/version: + {'display version' => 'CommentOutput'}, + {'display boot-loader' => 'CommentOutput'}, + {'display startup' => 'CommentOutput'}, + {'dir /all' => 'CommentOutput'}, +# {'dir /all unit2>flash:/' => 'CommentOutput'}, +# {'dir /all slot2#flash:/' => 'CommentOutput'}, +# {'dir /all unit3>flash:/' => 'CommentOutput'}, +# {'dir /all slot3#flash:/' => 'CommentOutput'}, +# {'dir /all unit4>flash:/' => 'CommentOutput'}, +# {'dir /all slot4#flash:/' => 'CommentOutput'}, +# {'dir /all unit5>flash:/' => 'CommentOutput'}, +# {'dir /all slot5#flash:/' => 'CommentOutput'}, +# {'dir /all unit6>flash:/' => 'CommentOutput'}, +# {'dir /all slot6#flash:/' => 'CommentOutput'}, +# {'dir /all unit7>flash:/' => 'CommentOutput'}, +# {'dir /all slot7#flash:/' => 'CommentOutput'}, +# {'dir /all unit8>flash:/' => 'CommentOutput'}, +# {'dir /all slot8#flash:/' => 'CommentOutput'}, +# Commands relating to the hardware: + {'display device' => 'CommentOutput'}, + {'display device manuinfo' => 'CommentOutput'}, + {'display poe device' => 'CommentOutput'}, + {'display poe pse' => 'CommentOutput'}, + {'display poe interface' => 'CommentOutput'}, + {'display transceiver interface' => 'CommentOutput'}, +# Commands relating to authentication: + {'display cluster' => 'CommentOutput'}, + {'display domain' => 'CommentOutput'}, + {'display local-user' => 'CommentOutput'}, + {'display password-control' => 'CommentOutput'}, + {'display password-control super' => 'CommentOutput'}, + {'display ssh server status' => 'CommentOutput'}, +# Commands relating to system state: + {'display irf' => 'CommentOutput'}, + {'display xrn-fabric' => 'CommentOutput'}, + {'display ftm topology-database' => 'CommentOutput'}, + {'display fib' => 'DisplayFib'}, + {'display ip routing-table' => 'DisplayIPRoutes'}, + {'display ospf' => 'CommentOutput'}, + {'display ospf brief' => 'CommentOutput'}, + {'display vlan all' => 'CommentOutput'}, + {'display lacp sys' => 'CommentOutput'}, + {'display link-aggregation summary' => 'CommentOutput'}, + {'display link-aggregation verbose' => 'CommentOutput'}, + {'display mirror all' => 'CommentOutput'}, + {'display ntp-service status' => 'CommentOutput'}, + {'display stp root' => 'CommentOutput'}, +# And the system config itself: + {'display current-configuration' => 'DisplayCurrent'}, +); + +# Remove some commands from the comman table if the user has toggled the +# options not to execute them +if ($display_fib == 0) + { grep(delete $$_{'display fib'} , @commandtable) }; +if ($display_iproutes == 0) + { grep(delete $$_{'display ip routing-table'} , @commandtable) }; +if ($display_vlan_all == 0) + { grep(delete $$_{'display vlan all'} , @commandtable) }; +if ($display_stproot == 0) + { grep(delete $$_{'display stp root'} , @commandtable) }; +if ($display_irf == 0) + { grep(delete $$_{'display irf'} , @commandtable) }; +if ($display_xrn == 0) + { grep(delete $$_{'display xrn-fabric'} , @commandtable) }; +if ($display_ftm == 0) + { grep(delete $$_{'display ftm topology-database'} , @commandtable) }; +if ($display_ospf == 0) + { grep(delete $$_{'display ospf'} , @commandtable) }; +if ($display_xcvr_int == 0) + { grep(delete $$_{'display transceiver interface'} , @commandtable) }; + +# 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); +$commandcnt = scalar(keys %commands); + +$device_cmds=join(";",@commands); +$cmds_regexp=join("|", map quotemeta($_), @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); + } +} +if ($opt_C) { + print "$logincmd -t $timeo -c\'$commandstr\' $host\n"; + exit(0); +} +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) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($debug); + print STDOUT "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) { +# system "$logincmd -noenable -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n"; +# system "$logincmd -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n"; + system "$logincmd -t $timeo -c \"$device_cmds\" $host $host.raw 2>&1" || die "$logincmd failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "$logincmd failed for $host: $!\n"; + } else { +# open(INPUT,"$logincmd -noenable -t $timeo -c \"$device_cmds\" $host ) { + tr/\015//d; +# h3c: +# Look for the command at the end of the output +# if (/\#exit$/) { +# if (/\#quit$/) { +# h3c: + if (/[\]>#]\a?\s*quit/) { +# if (/^[\[<].*[\]>]\a?\s?quit/) { + $clean_run=1; + last; + } + if (/^Error:/) { + print STDOUT ("$host $logincmd error: $_"); + print STDERR ("$host $logincmd error: $_") if ($debug); + $clean_run=0; + last; + } +# while (/#\s*($cmds_regexp)\s*$/) { +# h3c: + while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) { +# while (/^[\[<].*[\]>]\a?\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + # h3c: + # Extract the prompt: look for something not [ or < at the start + # of the line, until either ] or > or # is reached: + #$prompt = ($_ =~ /^([^#]+#)/)[0]; + #$prompt =~ s/([][}{)(\\])/\\$1/g; + #$prompt = ($_ =~ /^([^\]>]+[\]>]\007?)/)[0]; + $prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + 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}}(*INPUT, *OUTPUT, $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); +} + +printf(STDOUT "$host: clean_run=$clean_run found_end=$found_end\n") if ($debug); + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(keys %commands) eq $commandcnt) { + printf(STDERR "$host: missed cmd(s): all commands\n"); + } elsif (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("$TAIL -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} + diff --git a/bin/ztelogin b/bin/ztelogin new file mode 100644 index 0000000..c7f9156 --- /dev/null +++ b/bin/ztelogin @@ -0,0 +1,922 @@ +#! /usr/bin/expect -- +# + +# Usage line +set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-r passphrase\] \[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set avenable 1 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 +# Save config, if prompted +set do_saveconfig 0 +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeoutdflt 45 +# Some CLIs having problems if we write too fast (Extreme, PIX, Cat) +set send_human {.2 .1 .4 .2 1} + +# Find the user in the ENV, or use the unix userid. +if {[info exists env(CISCO_USER)]} { + set default_user $env(CISCO_USER) +} elseif {[info exists env(USER)]} { + set default_user $env(USER) +} elseif {[info exists env(LOGNAME)]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [catch {exec id} reason] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} +if {[info exists env(CLOGINRC)]} { + set password_file $env(CLOGINRC) +} + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Expect debug mode + -d* { + exp_internal 1 + # Username + } -u* { + if {! [regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [lindex $argv $i] + } + # VTY Password + } -p* { + if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [lindex $argv $i] + } + set do_passwd 0 + # ssh passphrase + } -r* { + if {! [regexp .\[rR\](.+) $arg ignore passphrase]} { + incr i + set avpassphrase [lindex $argv $i] + } + # VTY Password + } -v* { + if {! [regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [lindex $argv $i] + } + set do_passwd 0 + # Version string + } -V* { + send_user "rancid 3.2\n" + exit 0 + # Enable Username + } -w* { + if {! [regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [lindex $argv $i] + } + # Environment variable to pass to -s scripts + } -E* { + if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* { + if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [lindex $argv $i] + } + set do_enapasswd 0 + # Command to run. + } -c* { + if {! [regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [lindex $argv $i] + } + set do_command 1 + # Expect script to run. + } -s* { + if {! [regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [lindex $argv $i] + } + if { ! [file readable $sfile] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # save config on exit + } -S* { + set do_saveconfig 1 + # 'ssh -c' cypher type + } -y* { + if {! [regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [lindex $argv $i] + } + # alternate cloginrc file + } -f* { + if {! [regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [lindex $argv $i] + } + # Timeout + } -t* { + if {! [regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeoutdflt [lindex $argv $i] + } + # Command file + } -x* { + if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [lindex $argv $i] + } + if [catch {set cmd_fd [open $cmd_file r]} reason] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + set avenable 0 + # Does tacacs automatically enable us? + } -autoenable { + set avautoenable 1 + set avenable 0 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [regexp "^/" $args ignore] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match -nocase [lindex $line 0] $router] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [catch {source $password_file} reason] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +# returns: 0 on success, 1 on failure, -1 if rsh was used successfully +proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } { + global command spawn_id in_proc do_command do_script platform passphrase + global prompt prompt_match u_prompt p_prompt e_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + incr progs -1 + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port + if {"$port" == ""} { + set retval [catch {spawn telnet $router} reason] + } else { + set retval [catch {spawn telnet $router $port} reason] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + return 1 + } + } elseif [string match "ssh*" $prog] { + # ssh to the router & try to login with or without an identfile. + regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port + set cmd $sshcmd + if {"$port" != ""} { + set cmd "$cmd -p $port" + } + if {"$identfile" != ""} { + set cmd "$cmd -i $identfile" + } + set retval [catch {eval spawn [split "$cmd -c $cyphertype -x -l $user $router" { }]} reason] + if { $retval } { + send_user "\nError: $cmd failed: $reason\n" + return 1 + } + } elseif ![string compare $prog "rsh"] { + if { ! $do_command } { + if { [llength $cmethod] == 1 } { + send_user "\nError: rsh is an invalid method for -x and " + send_user "interactive logins\n" + } + if { $progs == 0 } { + return 1 + } + continue; + } + + # handle escaped ;s in commands, and ;; and ^; + regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand + regsub {^;} $esccommand "\u002;" command + set sep "\\1\u001" + regsub -all {([^\\])\;} $command "$sep" esccommand + set sep "\u001" + set commands [split $esccommand $sep] + set num_commands [llength $commands] + set rshfail 0 + for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { + log_user 0 + set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason] + if { $retval } { + send_user "\nError: rsh failed: $reason\n" + log_user 1; return 1 + } + send_user "$router# [lindex $commands $i]\n" + + # rcmd does not get a pager and no prompts, so we just have to + # look for failures & lines. + expect { + "Connection refused" { catch {close}; catch {wait}; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; catch {wait}; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; catch {wait}; + send_user "\nError: Unknown host\ + $router\n" + set rshfail 1 + } + -re "\b+" { exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + timeout { catch {close}; catch {wait}; + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; catch {wait}; } + } + log_user 1 + } + if { $rshfail } { + if { !$progs } { + return 1 + } else { + continue + } + } + # fake the end of the session for rancid. + send_user "$router# exit\n" + # return rsh "success" + return -1 + } else { + send_user "\nError: unknown connection method: $prog\n" + return 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + -re "^<-+ More -+>\[^\n\r]*" { + # ASA will use the pager for long banners + send " "; + exp_continue + } + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection closed ($prog): $router\n" + return 1 + } + } + eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } + -nocase "unknown host\r" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + "Host is unreachable" { + send_user "\nError: Host Unreachable: $router\n"; + catch {close}; catch {wait}; + return 1 + } + "No address associated with name" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + -re "(Host key not found |The authenticity of host .* be established).* \\(yes/no\\)\\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue + } + -re "HOST IDENTIFICATION HAS CHANGED.* \\(yes/no\\)\\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "HOST IDENTIFICATION HAS CHANGED\[^\n\r]+" { + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 + } + -re "Offending key for .* \\(yes/no\\)\\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "(denied|Sorry)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Login failed" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + -re "% (Bad passwords|Authentication failed)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Press any key to continue" { + # send_user "Pressing the ANY key\n" + send "\r" + exp_continue + } + -re "Enter Selection: " { + # Catalyst 1900s have some lame menu. Enter + # K to reach a command-line. + send "K\r" + exp_continue + } + -re "Last login:" { + exp_continue + } + -re "Press the key \[^\r\n]+\[\r\n]+" { + exp_continue + } + -re "@\[^\r\n]+ $p_prompt" { + # ssh pwd prompt + sleep 1 + send -- "$userpswd\r" + exp_continue + } + -re "Enter passphrase.*: " { + # sleep briefly to allow time for stty -echo + sleep .3 + send -- "$passphrase\r" + exp_continue + } + -re "$u_prompt" { + send -- "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send -- "$userpswd\r" + } else { + send -- "$passwd\r" + } + exp_continue + } + -re "$prompt" { + set prompt_match $expect_out(0,string); + break; + } + "Login invalid" { + send_user "\nError: Invalid login: $router\n"; + catch {close}; catch {wait}; return 1 + } + -re "\[^\r\n]*\[\r\n]+" { exp_continue; } + } + } + + set in_proc 0 + return 0 +} + +# Enable +proc do_enable { enauser enapasswd } { + global do_saveconfig in_proc + global prompt u_prompt e_prompt enacmd + set in_proc 1 + + send "$enacmd\r" + expect { + -re "$u_prompt" { send -- "$enauser\r"; exp_continue} + -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} + "#" { set prompt "#" } + "(enable)" { set prompt "> \\(enable\\) " } + "% Invalid input" { + send_user "\nError: Unrecognized command, check your enable command\n"; + return 1 + } + -re "(denied|Sorry|Incorrect)" { + # % Access denied - from local auth and poss. others + send_user "\nError: Check your Enable passwd\n"; + return 1 + } + "% Error in authentication" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + "% Bad passwords" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + } + # We set the prompt variable (above) so script files don't need + # to know what it is. + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global do_saveconfig in_proc platform + set in_proc 1 + + if { [string compare "extreme" "$platform"] } { + # match cisco config mode prompts too, such as router(config-if)#, + # but catalyst does not change in this fashion. + regsub -lineanchor -- {^(.{1,11}).*([#>])$} $prompt {\1} reprompt + regsub -all -- {[\\]$} $reprompt {} reprompt + append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} + } else { + set reprompt $prompt + } + + # this is the only way i see to get rid of more prompts in o/p..grrrrr + log_user 0 + + # handle escaped ;s in commands, and ;; and ^; + regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand + regsub {^;} $esccommand "\u002;" command + set sep "\\1\u001" + regsub -all {([^\\]);} $command "$sep" esccommand + set sep "\u001" + set commands [split $esccommand $sep] + set num_commands [llength $commands] + # the pager can not be turned off on the PIX, so we have to look + # for the "More" prompt. the extreme is equally obnoxious in pre-12.3 XOS, + # with a global switch in the config. + for {set i 0} {$i < $num_commands} { incr i} { + if { [lindex $commands $i] == "\u002" } { + send -- "\r" + } else { + send -- "[subst -nocommands [lindex $commands $i]]\r" + } + expect { + -re "\b+" { exp_continue } + -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue + } + -re "^--More--\[\r\n]+" { # specific match c1900 pager + send " " + exp_continue + } + -re "\[^\r\n]*\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + -re "\[^\r\n]*Press to cont\[^\r\n]*" { + send " " + # bloody ^[[2K after " " + expect { + -re "^\[^\r\n]*\r" {} + } + exp_continue + } + -re "\[^\r\n]*----- more -----\[^\r\n]*" { + send " " + exp_continue } + -re "^<-+ More -+>\[^\n\r]*" { + send_user -- "$expect_out(buffer)" + send " " + exp_continue } + } + } + log_user 1 + + if { [string compare "extreme" "$platform"] } { + send -h "exit\r" + } else { + send -h "quit\r" + } + expect { + -re "^\[^\n\r *]*$reprompt" { + # the Cisco CE and Jnx ERX + # return to non-enabled mode + # on exit in enabled mode. + send -h "exit\r" + exp_continue; + } + "The system has unsaved changes" { # Force10 SFTOS + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + "Would you like to save them now" { # Force10 + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + -re "(Profile|Configuration) changes have occurred.*" { + # Cisco CSS + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + "Do you wish to save your configuration changes" { + if {$do_saveconfig} { + catch {send "y\r"} + } else { + catch {send "n\r"} + } + exp_continue + } + -re "\[\n\r]+" { exp_continue } + timeout { catch {close}; catch {wait}; + return 0 + } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +set exitval 0 +set prompt_match "" +foreach router [lrange $argv $i end] { + set router [string tolower $router] + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # device timeout + set timeout [find timeout $router] + if { [llength $timeout] == 0 } { + set timeout $timeoutdflt + } + + # Default prompt. + set prompt [join [find prompt $router] ""] + if { [llength $prompt] == 0 } { + set prompt "(>|#| \\(enable\\))" + } + + # look for autoenable option in .cloginrc & cmd-line + set ae [find autoenable $router] + if { "$ae" == "1" || $avautoenable } { + set autoenable 1 + } else { + set autoenable 0 + } + # look for enable options in .cloginrc & cmd-line + if { $avenable == 0 } { + set enable 0 + } else { + set ne [find noenable $router] + if { "$ne" == "1" || "$autoenable" == "1" } { + set enable 0 + } else { + set enable 1 + } + } + + # Figure out passwords + if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user -- "\nError: no password for $router in $password_file.\n" + continue + } + if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { + send_user -- "\nError: no enable password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out enable command + set enacmd [join [find enablecmd $router] ""] + if { "$enacmd" == "" } { set enacmd "enable" } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(\[Uu]sername|Login|login|user name|User):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { + set e_prompt "\[Pp]assword:" + } else { + set e_prompt [join [lindex $e_prompt 0] ""] + } + + # Figure out identity file to use + set identfile [join [lindex [find identity $router] 0] ""] + + # Figure out passphrase to use + if {[info exists avpassphrase]} { + set passphrase $avpassphrase + } else { + set passphrase [join [lindex [find passphrase $router] 0] ""] + } + if { ! [string length "$passphrase"]} { + set passphrase $passwd + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [join [lindex [find sshcmd $router] 0] ""] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} { + incr exitval + # if login failed or rsh was unsuccessful, move on to the next device + continue + } + # Figure out the prompt. + if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } { + set enable 0 + } + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + incr exitval + catch {close}; catch {wait}; + continue + } + } + } + # we are logged in, now figure out the full prompt + send "\r" + regsub -all {^(\^*)(.*)} $prompt {\2} reprompt + expect { + -re "\[\r\n]+" { exp_continue; } + -re "^(.+\[:.])1 ($reprompt)" { # stoopid extreme cmd-line numbers and + # prompt based on state of config changes, + # which may have an * at the beginning. + set junk $expect_out(1,string) + regsub -all "^\\\* " $expect_out(1,string) {} junk + regsub -all "\[\]\[\(\)]" $junk {\\&} junk; + set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)"; + set platform "extreme" + } + -re "^.+$reprompt" { set junk $expect_out(0,string); + regsub -all "\[\]\[\(\)+]" $junk {\\&} prompt; + } + } + if { $do_command || $do_script } { + if { [string compare "extreme" "$platform"] } { + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "terminal length 0". + if [regexp -- ".*> .*enable" "$prompt"] { + send "set length 0\r" + expect -re $prompt {} + send "set width 132\r" + expect -re $prompt {} + send "set logging session disable\r" + } else { + send "terminal length 0\r" + expect -re $prompt {} + send "terminal width 132\r" + } + expect -re $prompt {} + } else { + send "disable clipaging\r" + expect -re $prompt {} + } + } + if { $do_command } { + if {[run_commands $prompt $command]} { + incr exitval + continue + } + } elseif { $do_script } { + source $sfile + catch {close}; + } else { + label $router + log_user 1 + interact + } + + # End of for each router + catch {wait}; + sleep 0.3 +} +exit $exitval diff --git a/bin/zterancid b/bin/zterancid new file mode 100644 index 0000000..61a0405 --- /dev/null +++ b/bin/zterancid @@ -0,0 +1,324 @@ +#! /usr/bin/perl +## +## $Id: zyrancid,v 0.1 2015/03/03 14:38:27 root Exp $ +## +## @PACKAGE@ @VERSION@ +## Copyright (C) 2015 by Kentec Communications, Inc. +## Portions 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. +## +# +# zyrancid - adapted for ZyXel ethernet switches by Jesse Norell +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: zyrancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dfl'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$found_version = 0; +$found_env = 0; +$found_diag = 0; +$timeo = 90; # clogin timeout in seconds +$clogin_pgm= $ENV{'RANCID_CLOGIN'} || "ztelogin"; +$prompt = '.*>'; +delete $ENV{'TERM'}; + +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)) && %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 routing 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 routing 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 routing 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 routing (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 system-information" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + ProcessHistory("COMMENTS","keysort","A1","\n! # $cmd\n"); + + while () { + tr/\015//d; + s/\x1b\x37//g; # ANSI escape code: Save Cursor Position + if (/^$prompt/) { $found_version=1; last}; + next if(/^(\s*|\s*$cmd\s*)$/); + return(1) if (/\s+\% Command not found \".*\"/); + return(0) if ($found_version); # Only do this routine once + + # in case the pager prompt shows up + s/^----- more -----.*ESC//; + + # ignore "System up Time" value + s/^( System uptime\s+is\s).*$/$1[removed]/; + s/^( Onboard temperature\s+:\s).*$/$1[removed]/; + ProcessHistory("COMMENTS","keysort","A1","! $_"); + } + + return(0); +} + +sub ShowMisc { # keyval + my $keyval= $_[0] or "C1"; + print STDERR " In ShowMisc($keyval): $_" if ($debug); + ProcessHistory("COMMENTS","keysort",$keyval,"\n! # $cmd\n"); + + while () { + tr/\015//d; + s/\x1b\x37//g; # ANSI escape code: Save Cursor Position + if (/^$prompt/) { $found_version=1; last}; + next if(/^(\s*|\s*$cmd\s*)$/); + return(1) if (/\s+\% Command not found \".*\"/); + + # in case the pager prompt shows up + s/^----- more -----.*ESC//; + + ProcessHistory("COMMENTS","keysort",$keyval,"! $_"); + } + + return(0); +} + +sub ShowFan { ShowMisc("B1"); } +sub ShowAuth { ShowMisc("C1"); } +sub ShowLogins { ShowMisc("D1"); } +sub ShowSNMP { ShowMisc("E1"); } +sub ShowRadius { ShowMisc("F1"); } +sub ShowRemoteAcc { ShowMisc("G1"); } + +sub ShowConfig { + print STDERR " In ShowConfig: $_" if ($debug); + ProcessHistory("COMMENTS","","","\n! # $cmd\n"); + + while () { + tr/\015//d; + s/\x1b\x37//g; # ANSI escape code: Save Cursor Position + if (/^$prompt/) { $found_end=1; $clean_run=1; return 0}; + next if(/^(\s*|\s*$cmd\s*)$/); + return(1) if (/\s+\% Command not found \".*\"/); + + + # in case the pager prompt shows up + s/^----- more -----.*ESC//; + + ProcessHistory("","","","$_"); + } +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +@commandtable=( + {'show version' => "ShowVersion"}, + {'show fan' => "ShowFan"}, + {'show loginauth' => "ShowAuth"}, + {'show user' => "ShowLogins"}, + {'show snmp' => "ShowSNMP"}, + {'show radius' => "ShowRadius"}, + {'show remote-access' => "ShowRemoteAcc"}, + {'show running-config' => "ShowConfig"}, +); + +# Use array to preserve order of commands, and hash for mapping to subroutine +my (%commands, @commands); +foreach (@commandtable) { + push @commands, (keys(%{$_}))[0]; + $commands{$commands[$#commands]}= (values(%{$_}))[0]; +}; + +$clogin_cmds=join(";", @commands); +$cmds_regexp=join("|", @commands); + +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) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing $clogin_pgm -t $timeo -c\"$clogin_cmds\" $host\n" if ($debug); + print STDOUT "executing $clogin_pgm -t $timeo -c\"$clogin_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "$clogin_pgm -t $timeo -c \"$clogin_cmds\" $host $host.raw 2>&1" || die "$clogin_pgm failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "$clogin_pgm failed for $host: $!\n"; + } else { + open(INPUT,"$clogin_pgm -t $timeo -c \"$clogin_cmds\" $host ) { + tr/\015//d; + s/\x1b\x37//g; # ANSI escape code: Save Cursor Position + + # ZyXel logouts get you EPIPE, it's not an error (probably) + if (/^(($prompt)exit|Write failed: Broken pipe)$/) { + $clean_run=1; + last; + } + # clogin sends cisco commands the ZyXel complains of - just ignore these + next if (/\s+\%Invalid command \".*\"/); + + while (/($prompt)\s*($cmds_regexp)/) { + $cmd = $2; + if (!defined($actual_prompt)) { + $actual_prompt = ($_ =~ /^([^>]+>)/)[0]; + $actual_prompt =~ s/([][+.*}{)(\\])/\\$1/g; + print STDERR ("PROMPT MATCH: $actual_prompt\n") if ($debug); + $prompt = $actual_prompt; + } + 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 $clogin_pgm: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + 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))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} From 9eb395195366098e97bcc96e79dfedccff319c7f Mon Sep 17 00:00:00 2001 From: manyax Date: Wed, 13 Jan 2016 14:33:08 +0100 Subject: [PATCH 25/38] rancid files for hp1910 and zte zrx10 --- bin/{hp1910login => hp1910login.in} | 47 +++------------------------ bin/{hp1910rancid => hp1910rancid.in} | 6 ++-- bin/{ztelogin => ztelogin.in} | 18 ++++++++-- bin/{zterancid => zterancid.in} | 12 +++---- 4 files changed, 30 insertions(+), 53 deletions(-) rename bin/{hp1910login => hp1910login.in} (93%) rename bin/{hp1910rancid => hp1910rancid.in} (99%) rename bin/{ztelogin => ztelogin.in} (97%) rename bin/{zterancid => zterancid.in} (96%) diff --git a/bin/hp1910login b/bin/hp1910login.in similarity index 93% rename from bin/hp1910login rename to bin/hp1910login.in index 25d52cf..f973ff0 100644 --- a/bin/hp1910login +++ b/bin/hp1910login.in @@ -1,48 +1,12 @@ -#! /usr/bin/expect -- +#! @EXPECT_PATH@ -- ## -## $Id: clogin.in 3057 2015-03-13 20:32:14Z heas $ -## -## rancid 3.2 -## Copyright (c) 1997-2015 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. ## All rights reserved. ## -## This code is derived from software contributed to and maintained by -## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, -## Pete Whiting, Austin Schutz, and Andrew Fort. -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## 1. Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## 3. All advertising materials mentioning features or use of this software -## must display the following acknowledgement: -## This product includes software developed by Terrapin Communications, -## Inc. and its contributors for RANCID. -## 4. Neither the name of Terrapin Communications, Inc. nor the names of its -## contributors may be used to endorse or promote products derived from -## this software without specific prior written permission. -## 5. It is requested that non-binding fixes and modifications be contributed -## back to Terrapin Communications, Inc. -## -## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS -## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS -## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -## POSSIBILITY OF SUCH DAMAGE. +# hp1910login - adapted for HP1910 ethernet switches by Alexandru Musat # -# The expect login scripts were based on Erik Sherk's gwtn, by permission. -# -# clogin - Cisco login +# Modified from clogin for use with HP1910 1/9/2016 # # Most options are intuitive for logging into a Cisco router. # The default is to enable (thus -noenable). Some folks have @@ -51,7 +15,6 @@ # the process of enabling and the prompt will be the "#" prompt. # The default username password is the same as the vty password. # - # Usage line set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ diff --git a/bin/hp1910rancid b/bin/hp1910rancid.in similarity index 99% rename from bin/hp1910rancid rename to bin/hp1910rancid.in index 1167782..69954f1 100644 --- a/bin/hp1910rancid +++ b/bin/hp1910rancid.in @@ -1,8 +1,8 @@ -#! /usr/bin/perl +#! @PERLV_PATH@ ## ## -## rancid 3.2 -## Copyright (c) 1997-2015 by Terrapin Communications, Inc. +## @PACKAGE@ @VERSION@ +## Copyright (c) 1997-2008 by Terrapin Communications, Inc. ## All rights reserved. ## # HP1910rancid - adapted for HP 1910 ethernet switches by Alexandru Musat diff --git a/bin/ztelogin b/bin/ztelogin.in similarity index 97% rename from bin/ztelogin rename to bin/ztelogin.in index c7f9156..cb03875 100644 --- a/bin/ztelogin +++ b/bin/ztelogin.in @@ -1,6 +1,20 @@ -#! /usr/bin/expect -- +#! @EXPECT_PATH@ -- +## +## @PACKAGE@ @VERSION@ +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. +## All rights reserved. +## +# ztelogin - ZTE ethernet switches by Alexandru Musat +# +# Modified from clogin for use with ZTE 1/9/2016 +# +# Most options are intuitive for logging into a Cisco router. +# The default is to enable (thus -noenable). Some folks have +# setup tacacs to have a user login at priv-lvl = 15 (enabled) +# so the -autoenable flag was added for this case (don't go through +# the process of enabling and the prompt will be the "#" prompt. +# The default username password is the same as the vty password. # - # Usage line set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ diff --git a/bin/zterancid b/bin/zterancid.in similarity index 96% rename from bin/zterancid rename to bin/zterancid.in index 61a0405..9e2a816 100644 --- a/bin/zterancid +++ b/bin/zterancid.in @@ -1,10 +1,9 @@ -#! /usr/bin/perl +#! @PERLV_PATH@ ## -## $Id: zyrancid,v 0.1 2015/03/03 14:38:27 root Exp $ +## $Id: ## ## @PACKAGE@ @VERSION@ -## Copyright (C) 2015 by Kentec Communications, Inc. -## Portions Copyright (C) 1997-2004 by Terrapin Communications, Inc. +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. ## All rights reserved. ## ## This software may be freely copied, modified and redistributed @@ -20,12 +19,13 @@ ## Except where noted otherwise, rancid was written by and is maintained by ## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz. ## +# zterancid - ZTE ethernet switches by Alexandru Musat # -# zyrancid - adapted for ZyXel ethernet switches by Jesse Norell +# Modified from zyrancid for use with ZTE 1/9/2016 # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: zyrancid [-d] [-l] [-f filename | $host] +# usage: zterancid [-d] [-l] [-f filename | $host] # use Getopt::Std; getopts('dfl'); From 01b9753679dc7aceb1093e1d8e335bd26723a924 Mon Sep 17 00:00:00 2001 From: manyax Date: Thu, 18 Feb 2016 11:45:16 +0100 Subject: [PATCH 26/38] Added promt to match tac_plus to zterancid and fix enable for shelllogin --- bin/shelllogin.in | 6 +++--- bin/zterancid.in | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/shelllogin.in b/bin/shelllogin.in index e32f325..0121709 100755 --- a/bin/shelllogin.in +++ b/bin/shelllogin.in @@ -615,14 +615,14 @@ proc do_enable { enauser enapasswd } { # Set bash answer in english send "export LANG=C\r" expect { - "#" { set prompt "#" } + "$" { set prompt "$" } -re "error" { send_user "\nError: check your appliance\n" return 1 } } send "su -\r" expect { - -re "$u_prompt" { send -- "$enauser\r"; exp_continue} + -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} "#" { set prompt "#" } -re "(denied|Sorry|Incorrect)" { @@ -868,7 +868,7 @@ foreach router [lrange $argv $i end] { } else { set autoenable 0 set enable $avenable - set prompt ":~> " + set prompt "(:~$ | \$)" } } diff --git a/bin/zterancid.in b/bin/zterancid.in index 9e2a816..b720820 100644 --- a/bin/zterancid.in +++ b/bin/zterancid.in @@ -40,7 +40,8 @@ $found_env = 0; $found_diag = 0; $timeo = 90; # clogin timeout in seconds $clogin_pgm= $ENV{'RANCID_CLOGIN'} || "ztelogin"; -$prompt = '.*>'; +###If tac_plus is enable the prompt will be # +$prompt = "[#>]"; delete $ENV{'TERM'}; my(%filter_pwds); # password filtering mode @@ -278,7 +279,8 @@ TOP: while() { while (/($prompt)\s*($cmds_regexp)/) { $cmd = $2; if (!defined($actual_prompt)) { - $actual_prompt = ($_ =~ /^([^>]+>)/)[0]; + #To match the prompt for TAC_pluS) + $actual_prompt = ($_ =~ /^([^#>]+[#|>])/)[0]; $actual_prompt =~ s/([][+.*}{)(\\])/\\$1/g; print STDERR ("PROMPT MATCH: $actual_prompt\n") if ($debug); $prompt = $actual_prompt; From 23d0a2667290934dc36101ca52b5d366ebe6c6d6 Mon Sep 17 00:00:00 2001 From: manyax Date: Thu, 18 Feb 2016 13:18:16 +0100 Subject: [PATCH 27/38] changed shelllogin to run with sudo --- bin/shelllogin.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/shelllogin.in b/bin/shelllogin.in index 0121709..d4ba700 100755 --- a/bin/shelllogin.in +++ b/bin/shelllogin.in @@ -615,7 +615,7 @@ proc do_enable { enauser enapasswd } { # Set bash answer in english send "export LANG=C\r" expect { - "$" { set prompt "$" } + "#" { set prompt "#" } -re "error" { send_user "\nError: check your appliance\n" return 1 } @@ -623,6 +623,7 @@ proc do_enable { enauser enapasswd } { send "su -\r" expect { + -re "$u_prompt" { send -- "$enauser\r"; exp_continue} -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} "#" { set prompt "#" } -re "(denied|Sorry|Incorrect)" { @@ -868,7 +869,7 @@ foreach router [lrange $argv $i end] { } else { set autoenable 0 set enable $avenable - set prompt "(:~$ | \$)" + set prompt ":~> " } } From cf8b237e1227f2fe9f7b9956cfc82cd16bc3726d Mon Sep 17 00:00:00 2001 From: manyax Date: Thu, 18 Feb 2016 13:21:02 +0100 Subject: [PATCH 28/38] changed shelllogin/shellrancid to run with sudo > sudologin/sudorancid --- bin/sudologin.in | 1023 +++++++++++++++++++++++++++++++++++++++++++++ bin/sudorancid.in | 327 +++++++++++++++ 2 files changed, 1350 insertions(+) create mode 100644 bin/sudologin.in create mode 100644 bin/sudorancid.in diff --git a/bin/sudologin.in b/bin/sudologin.in new file mode 100644 index 0000000..875b302 --- /dev/null +++ b/bin/sudologin.in @@ -0,0 +1,1023 @@ +#! @EXPECT_PATH@ -- +## +## shelllogin (git) 2014/01/31 +## based on llogin 1.0.2 2009/07/07 +## based on clogin.in,v 1.136 2009/04/22 18:59:04 +## +## @PACKAGE@ @VERSION@ +## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc. +## All rights reserved. +## Derived from works by Diego Ercolani - SSIS S.p.A. - San Marino +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# The expect login scripts were based on Erik Sherk's gwtn, by permission. +# +# shelllogin - Shell Login +# +# Most options are intuitive for logging into a Cisco router. +# The default is to enable (thus -noenable). Some folks have +# setup tacacs to have a user login at priv-lvl = 15 (enabled) +# so the -autoenable flag was added for this case (don't go through +# the process of enabling and the prompt will be the "#" prompt. +# The default username password is the same as the vty password. +# +#changed script to run with sudo Alexandru Musat +# +# Usage line +set usage "Usage: $argv0 \[-dSV\] \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set avenable 1 +# The default is that you login non-enabled (tacacs can have you login already +# enabled) +set avautoenable 0 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 +set do_enapasswd 1 +# Save config, if prompted +set do_saveconfig 0 +# +set send_human {.4 .4 .7 .3 5} + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ]} { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} + +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeout 45 + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Expect debug mode + -d* { + exp_internal 1 + # Username + } -u* { + if {! [regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -p* { + if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # VTY Password + } -v* { + if {! [regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [ lindex $argv $i ] + } + set do_passwd 0 + # Version string + } -V* { + send_user "rancid 2.3.2\n" + exit 0 + # Enable Username + } -w* { + if {! [regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [ lindex $argv $i ] + } + # Environment variable to pass to -s scripts + } -E* { + if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # Enable Password + } -e* { + if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [ lindex $argv $i ] + } + set do_enapasswd 0 + # Command to run. + } -c* { + if {! [regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* { + if {! [regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # save config on exit + } -S* { + set do_saveconfig 1 + # 'ssh -c' cypher type + } -y* { + if {! [regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* { + if {! [regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + # Timeout + } -t* { + if {! [regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeout [ lindex $argv $i ] + } + # Command file + } -x* { + if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # Do we enable? + } -noenable { + set avenable 0 + # Does tacacs automatically enable us? + } -autoenable { + set avautoenable 1 + set avenable 0 + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [ regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie + +# Add procedure has been modified to add elements of existant list +# if list exists and first list element is the same +proc add {var args} { + global int_$var ; + if { [info exists int_$var] } { + #search for the key element (the first after the name) + # that is the "glob" element + set variable [set int_$var] + set added 0 + for {set i 0} {$i< [llength $variable]} {incr i} { + if { [string compare [lindex $args 0] [lindex [lindex $variable $i] 0]] == 0 } { + #first element of this subelement is equal so we have to add to this subelement + set args [lreplace $args 0 0] ;#delete 1st element of args as it is the glob + #puts "($args)-> [lindex $variable $i]" + set a [lindex $variable $i] + # if args is an array then add single element a time + foreach j $args { + lappend a $j + } + set variable [lreplace $variable $i $i $a] + #puts "risultato: $a==[lindex $variable $i]" + set added 1 + break ;#break loop as we added things to current sublist + } + } + if { $added == 1 } { + # we have a new list that have the new items + # so we must redefine the int_$var with the correct list + set int_$var $variable + } else { + # we didn't find any glob that matches the one we have, so + # new list element containing all the subelements + lappend int_$var $args + } + } else { + lappend int_$var $args + } +} + +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + send_debug "searching in $list occurrancies of $var in router $router\n" + foreach line $list { + send_debug "$line\n" + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } else { send_debug "Warning: int_$var list not found\n" } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +# returns: 0 on success, 1 on failure, -1 if rsh was used successfully +proc login { router user userpswd passwd enapasswd cmethod cyphertype } { + global command spawn_id in_proc do_command do_script platform + global prompt u_prompt p_prompt e_prompt sshcmd + set in_proc 1 + set uprompt_seen 0 + send_debug "In login\n" + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + incr progs -1 + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port + if {"$port" == ""} { + set retval [ catch {spawn telnet $router} reason ] + } else { + set retval [ catch {spawn telnet $router $port} reason ] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + return 1 + } + } elseif [string match "ssh*" $prog] { + regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port + if {"$port" == ""} { + set retval [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] + } else { + set retval [ catch {spawn $sshcmd -c $cyphertype -x -l $user -p $port $router} reason ] + } + if { $retval } { + send_user "\nError: $sshcmd failed: $reason\n" + return 1 + } + } elseif ![string compare $prog "rsh"] { + if { ! $do_command } { + if { [llength $cmethod] == 1 } { + send_user "\nError: rsh is an invalid method for -x and " + send_user "interactive logins\n" + } + if { $progs == 0 } { + return 1 + } + continue; + } + + set commands [split $command \;] + set num_commands [llength $commands] + set rshfail 0 + for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { + log_user 0 + set retval [ catch {spawn rsh $user@$router [lindex $commands $i] } reason ] + if { $retval } { + send_user "\nError: rsh failed: $reason\n" + log_user 1; return 1 + } + send_user "$router# [lindex $commands $i]\n" + + # rcmd does not get a pager and no prompts, so we just have to + # look for failures & lines. + expect { + "Connection refused" { catch {close}; catch {wait}; + send_user "\nError: Connection\ + Refused ($prog): $router\n" + set rshfail 1 + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + send_user "\nError: Connection\ + closed ($prog): $router\n" + set rshfail 1 + } + "Host is unreachable" { catch {close}; catch {wait}; + send_user "\nError: Host Unreachable:\ + $router\n" + set rshfail 1 + } + "No address associated with" { + catch {close}; catch {wait}; + send_user "\nError: Unknown host\ + $router\n" + set rshfail 1 + } + -re "\b+" { exp_continue } + -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + timeout { catch {close}; catch {wait}; + send_user "\nError: TIMEOUT reached\n" + set rshfail 1 + } + eof { catch {close}; catch {wait}; } + } + log_user 1 + } + if { $rshfail } { + if { !$progs } { + return 1 + } else { + continue + } + } + # fake the end of the session for rancid. + send_user "${prompt}exit\n" + send_user "$router# exit\n" + # return rsh "success" + return -1 + } else { + send_user "\nError: unknown connection method: $prog\n" + return 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection Refused ($prog): $router\n" + return 1 + } + } + -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection closed ($prog): $router\n" + return 1 + } + } + eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } + -nocase "unknown host\r" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + "Host is unreachable" { + send_user "\nError: Host Unreachable: $router\n"; + catch {close}; catch {wait}; + return 1 + } + "No address associated with name" { + send_user "\nError: Unknown host $router\n"; + catch {close}; catch {wait}; + return 1 + } + -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue + } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "Offending key for .* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + catch {close}; catch {wait}; + return 1 + } + -re "(denied|Sorry)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Login failed" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + -re "% (Bad passwords|Authentication failed)" { + send_user "\nError: Check your passwd for $router\n" + catch {close}; catch {wait}; return 1 + } + "Press any key to continue" { + # send_user "Pressing the ANY key\n" + send "\r" + exp_continue + } + -re "Enter Selection: " { + # Catalyst 1900s have some lame menu. Enter + # K to reach a command-line. + send "K\r" + exp_continue + } + -re "Last login:" { + exp_continue + } + -re "@\[^\r\n]+ $p_prompt" { + # ssh pwd prompt + sleep 1 + send -- "$userpswd\r" + exp_continue + } + -re "$u_prompt" { + send -- "$user\r" + set uprompt_seen 1 + exp_continue + } + -re "$p_prompt" { + sleep 1 + if {$uprompt_seen == 1} { + send -- "$userpswd\r" + } else { + send -- "$passwd\r" + } + exp_continue + } + -re "$prompt" { break; } + "Login invalid" { + send_user "\nError: Invalid login: $router\n"; + catch {close}; catch {wait}; return 1 + } + } + } + # remove usage of history for classic commands from rancid + # set default language (english) + send -- "export HISTIGNORE=\"&:cat *:exit*:export *\";export LANG=C\r" + expect { + -re "$prompt" { } + -re "\b+" { send_user "Error: $expect_out(buffer)" + } + } + set in_proc 0 + return 0 +} + +# Enable +proc do_enable { enauser enapasswd } { + global do_saveconfig in_proc + global prompt u_prompt e_prompt + set in_proc 1 + # Set bash answer in english + send "export LANG=C\r" + expect { + "$" { set prompt "$" } + -re "error" { send_user "\nError: check your appliance\n" + return 1 + } + } + + send "sudo -i\r" + expect { + -re "$e_prompt" { send -- "$enapasswd\r"; exp_continue} + "#" { set prompt "#" } + -re "(denied|Sorry|Incorrect)" { + # % Access denied - from local auth and poss. others + send_user "\nError: Check your Enable passwd\n"; + return 1 + } + "% Error in authentication" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + -re "(Authentication failure|incorrect password)" { + send_user "\nError: Check your Enable passwd\n" + return 1 + } + } + # We set the prompt variable (above) so script files don't need + # to know what it is. + set in_proc 0 + return 0 +} + + +proc BackupFiles { host files prompt } { + send_debug "In BackupFiles host:$host files:$files prompt:$prompt\n" + # faking start TAG + send_user "\n$prompt\BackupFiles\n" + + foreach item $files { + send_user "#rancid llogin : $item\n###########" + send -- "\r" + expect { + -re "$prompt" { send -- "cat $item\r" + exp_continue + } + -re "^cat $item\r" { } + -re "^cat: " { send_user -- "\nError: $expect_out(buffer)\n" + exit 1 + } + } + expect { + -re "^bash: .*" { + send_user -- "\nError: $expect_out(buffer)\n" + exit 1 + } + # word delimiter + -re "\b+" { send_user -- "$expect_out(buffer)" + exp_continue + } + -re "^\[^\r\n *]*$prompt" { + #send_user -- "$expect_out(buffer)" + } + -re "^\[^\r\n]*$prompt." { + #send_user -- "$expect_out(buffer)" + #exp_continue + } + -re "\[\r\n]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + } + } + # Faking End TAG + send_user "${prompt}\n" + send_user "${prompt}exit\n" + send -- "\r" + return 0 +} + + +# Run commands given on the command line. +proc run_commands { host prompt command } { + global in_proc platform + # Every environment variable have to be declared! Variable Scope: + # If I call a procedure that uses a global variable I have also to declare global + # here! (int_backupfile is used when I call [find backupfile $host] + global password_file int_backupfile + + set in_proc 1 + + set reprompt $prompt + + # this is the only way i see to get rid of more prompts in o/p..grrrrr + log_user 0 + + set commands [split $command \;] + + set num_commands [llength $commands] + # the pager can not be turned off on the PIX, so we have to look + # for the "More" prompt. the extreme is equally obnoxious, with a + # global switch in the config. + for {set i 0} {$i < $num_commands} { incr i} { + # If command is a "MetaCommand", call the handler procedure + # if it is not a "MetaCommand", passes the command "as is" to + # the console + # send_user "[subst [lindex $commands $i]]\n" + switch -glob -nocase [subst -nocommands [lindex $commands $i]] { + backupfiles { + set files [find backupfile $host] + if { [info exists files] && [llength $files] > 0 } { + BackupFiles $host $files $reprompt + } else { + send_user "\n\nPlease give some entries in $password_file: like this:\n" + send_user "add backupfile $host /etc/passwd /etc/resolv.conf\n\n" + } + } + * { + send -- "\r" + expect { + -re "^.*$reprompt" { send -- "[subst -nocommands [lindex $commands $i]]\r" } + } + expect { + -re "^bash: .*" { send_user -- "\nError: $expect_out(buffer)" + exit 1 + } + # word delimiter + -re "\b+" { send_user -- "$expect_out(buffer)" + exp_continue } + -re "^\[^\r\n *]*$reprompt" { send_user -- "$expect_out(buffer)" + } + -re "^\[^\r\n]*$reprompt." { send_user -- "$expect_out(buffer)" + exp_continue + } + -re "\[\r\n]+" { send_user -- "$expect_out(buffer)" + exp_continue + } + } + } ;#end default + } ;#end switch + send_debug "\nEnd Switch\n" + } + log_user 1 + + send -- "exit\r" + expect { + -re "\b+" { exp_continue } + -re "Connection to .* closed" { return 0} + -re "^\[^\n\r *]*$reprompt" { + # the Cisco CE and Jnx ERX + # return to non-enabled mode + # on exit in enabled mode. + send -h "exit\r" + exp_continue; + } + -re "\[\n\r]+" { exp_continue } + timeout { catch {close}; catch {wait}; + return 0 + } + eof { return 0 } + } + set in_proc 0 +} + + +proc send_debug { text } { + if { [ exp_internal -info ] == 1 } { + send_user "\033\[32mDebug:\033\[m$text" + } +} + +proc un_ansi {data} { + # -------------------------------------------------------------------------- + # remove ansi escape sequences + # http://wiki.tcl.tk/9673 + # -------------------------------------------------------------------------- + set txt {} + while {[string length ${data}]} { + set match { } + switch -regexp -- ${data} { + {^\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]} { + regexp -- {^\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]} ${data} match + append txt "\n" + } + {^(.+?)\x1b} { + regexp -- {^(.+?)\x1b} ${data} UNUSED match + # handle special escape sequences + regsub -all -- {\\([\\\[\]])} ${match} {\1} raw_match + append txt ${raw_match} + } + {^\x1b} { + # do nothing + } + default { + set match ${data} + append txt ${match} + } + } + set data [string range ${data} [string length ${match}] end] + } + + # remove white spaces not needed anymore + regsub -all -- "\t+" ${txt} { } txt + regsub -all -- " +" ${txt} { } txt + regsub -all -nocase -- "\n+" [string trim ${txt}] "\n" txt + return ${txt} +} + +proc escape_string {data} { + #Convert all non-ASCII and Tcl-significant characters into \u escape sequences + # by using regsub and subst in combination + # http://www.tcl.tk/man/tcl8.5/TclCmd/regsub.htm + # This RE is just a character class for everything "bad" + set RE {[][{};#\\\$\s\u0080-\uffff]} + # We will substitute with a fragment of Tcl script in brackets + set substitution {[format \\\\u%04x [scan "\\&" %c]]} + # Now we apply the substitution to get a subst-string that + # will perform the computational parts of the conversion. + set data [subst [regsub -all $RE $data $substitution]] + return ${data} +} + + + + + + + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +set exitval 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + # attempt at platform switching. + set platform "" + send_user -- "$router\n" + + # Figure out the prompt. + # autoenable is off by default. If we have it defined, it was done + # on the command line. If it is not specifically set on the command + # line, check the password file. + if $avautoenable { + set autoenable 1 + set enable 0 + set prompt "(:~# | ~\]#)" + } else { + set ae [find autoenable $router] + if { "$ae" == "1" } { + set autoenable 1 + set enable 0 + set prompt "(:~# | ~\]#)" + } else { + set autoenable 0 + set enable $avenable + set prompt "(:~$ | \$)" + } + } + + # look for noenable option in .cloginrc + if { [find noenable $router] != "" } { + set enable 0 + } + + # Figure out passwords + if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user -- "\nError: no password for $router in $password_file.\n" + continue + } + if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { + send_user -- "\nError: no enable password for $router in $password_file.\n" + continue + } + set passwd [join [lindex $pswd 0] ""] + set enapasswd [join [lindex $pswd 1] ""] + } else { + set passwd $userpasswd + set enapasswd $enapasswd + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [join [find user $router] ""] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [join [find userpassword $router] ""] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [join [find enauser $router] ""] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { + set u_prompt "(Username|Login|login|user name|User):" + } else { + set u_prompt [join [lindex $u_prompt 0] ""] + } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { + set p_prompt "(\[Pp]assword|passwd):" + } else { + set p_prompt [join [lindex $p_prompt 0] ""] + } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { + set e_prompt "\password for $ruser:" + } else { + set e_prompt [join [lindex $e_prompt 0] ""] + } + + # Figure out cypher type + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { + incr exitval + # if login failed or rsh was unsuccessful, move on to the next device + continue + } + send_debug "End of Login\n" + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + incr exitval + catch {close}; catch {wait}; + continue + } + } + send_debug "End Enable\n" + } + # we are logged in, now figure out the full prompt + send_debug "Figure out FULL prompt\n" + send "\r" + expect { + -re "\[\r\n]+" { exp_continue; } + -re "^.+$prompt.*" { + # get all the prompt (all the line) + set prompt $expect_out(buffer) + # escape sequence (some character are interpreted + # as regexp so we have to escape them) + set prompt [escape_string $prompt] + send_debug "Prompt modified: $prompt\n" + } + } + + if { $do_command } { + if {[run_commands $router $prompt $command]} { + incr exitval + continue + } + } elseif { $do_script } { + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "terminal length 0". + if [ regexp -- ".*> .*enable" "$prompt" ] { + send "set length 0\r" + expect -re $prompt {} + send "set logging session disable\r" + } else { + send "terminal length 0\r" + } + expect -re $prompt {} + source $sfile + catch {close}; + } else { + label $router + log_user 1 + interact + } + + # End of for each router + catch {wait}; + sleep 0.3 +} +exit $exitval diff --git a/bin/sudorancid.in b/bin/sudorancid.in new file mode 100644 index 0000000..5935b47 --- /dev/null +++ b/bin/sudorancid.in @@ -0,0 +1,327 @@ +#! @PERLV_PATH@ +## +## shelllrancid.in +## based on lrancid v 1.0 2009/07/07 +## which was in turn based on: +## $Id: rancid.in,v 1.255 2009/04/20 19:56:27 heas Exp $ +## +## @PACKAGE@ @VERSION@ +## Copyright (c) 1997-2009 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: shellrancid [-dV] [-l] [-f filename | hostname] +# +# Backup files by specifying them in your cloginrc +# +# add method linux.machine.domain ssh rlogin +# add user linux.machine.domain root +# add password linux.machine.domain thepassword thepassword +# add autoenable linux.machine.domain 1 +# add backupfile linux.machine.domain /etc/issue +# add backupfile linux.machine.domain /etc/network/interfaces +# add backupfile linux.machine.domain /etc/iptables/rules.v4 +# +#changed script to run with sudo Alexandru Musat +# +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]; +$ios = "IOS"; +$clean_run = 0; +$found_version = 0; +$found_env = 0; +$found_diag = 0; +$timeo = 90; # sudologin timeout in seconds + +my(@commandtable, %commands, @commands);# command lists +my($aclsort) = ("ipsort"); # ACL sorting mode +my($config_register); # configuration register value +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)) && %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; } + +### ### SORT Procedures ### +# 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); +} + +sub regex_escape { + my $regex = $1; + $regex =~ s/\\/\\\\/g; + $regex =~ s/\@/\\@/g; + return $regex; +} + + + +### ### Commands Parser ### +# dummy function +sub DoNothing {print STDOUT;} + +sub BackupFiles { + print STDERR " In BackupFiles: $_" if ($debug); + while () { + print STDERR "BackupFiles: $_" if $debug; + if (/^$prompt/) { $found_version = 1; last}; + ProcessHistory("COMMENTS","","","$_") && next; + } + return 0; +} + +# Main +@commandtable = ( + # Router (pseudo-)command => MetaCommand + {'BackupFiles' => 'BackupFiles'}, +); +# 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) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing sudologin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing sudologin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "sudologin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "sudologin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "sudologin failed for $host: $!\n"; + } else { + open(INPUT,"sudologin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/$prompt\s?exit$/) { + $clean_run = 1; + last; + } + if (/^Error:/) { + print STDOUT ("$host sudologin error: $_"); + print STDERR ("$host sudologin error: $_") if ($debug); + $clean_run = 0; + last; + } + while (/(.*)($cmds_regexp)\s*$/) { + # find fullprompt + $cmd = $2; + if (!defined($prompt)) { + $prompt = regex_escape($1); + 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 $host: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run ) { + if (scalar(%commands)) { + printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run ) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} From 6f134dd2ae4bb8d2c3026d81af35e4950f3777ab Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 30 Nov 2016 17:35:01 +0000 Subject: [PATCH 29/38] added routers.missed to generated .gitignore file --- bin/rancid-cvs.in | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/rancid-cvs.in b/bin/rancid-cvs.in index 97bcbcc..d36c2bf 100644 --- a/bin/rancid-cvs.in +++ b/bin/rancid-cvs.in @@ -173,6 +173,7 @@ do echo "$GROUP/routers.deleted" >> .gitignore echo "$GROUP/routers.single" >> .gitignore echo "$GROUP/routers.up.missed" >> .gitignore + echo "$GROUP/routers.missed" >> .gitignore echo "$GROUP/routers.failed" >> .gitignore ( flock -x 200 From bf17c5557d53d16869fe5cbbe6f65b4a87a4fd38 Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Wed, 17 Jan 2018 15:41:13 -0700 Subject: [PATCH 30/38] copy rancid-cisco-sb files --- bin/csblogin | 584 ++++++++++++++++++++++++++++++++++++++++++++++++++ bin/csbrancid | 466 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1050 insertions(+) create mode 100644 bin/csblogin create mode 100644 bin/csbrancid diff --git a/bin/csblogin b/bin/csblogin new file mode 100644 index 0000000..c3074c4 --- /dev/null +++ b/bin/csblogin @@ -0,0 +1,584 @@ +#!/usr/bin/expect -- +## +## $Id: csblogin,v 1.3 2010-01-28 13:12:00 bjorn Exp $ +## +## rancid 2.3.2a8 +## Copyright (c) 1997-2007 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# The expect login scripts were based on Erik Sherk's gwtn, by permission. +# +# csblogin - Cisco/Linksys "Small Business" switch login +# +# Most options are intuitive for logging into a Cisco router. +# The default username password is the same as the vty password. +# + +# Usage line +set usage "Usage: $argv0 \[-dV\] \[-c command\] \[-Evar=x\] \ +\[-f cloginrc-file\] \[-p user-password\] \[-r passphrase\] \[-s script-file\] \ +\[-u username\] \[-t timeout\] \[-x command-file\] \[-y ssh_cypher_type\] \ +router \[router...\]\n" + +# env(CLOGIN) may contain the following chars: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set avenable 1 +# The default is to look in the password file to find the passwords. This +# tracks if we receive them on the command line. +set do_passwd 1 + +# Find the user in the ENV, or use the unix userid. +if {[ info exists env(CISCO_USER) ]} { + set default_user $env(CISCO_USER) +} elseif {[ info exists env(USER) ]} { + set default_user $env(USER) +} elseif {[ info exists env(LOGNAME) ]} { + set default_user $env(LOGNAME) +} else { + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - + # unlike whoami or id -nu. + if [ catch {exec id} reason ] { + send_error "\nError: could not exec id: $reason\n" + exit 1 + } + regexp {\(([^)]*)} "$reason" junk default_user +} +if {[ info exists env(CLOGINRC) ]} { + set password_file $env(CLOGINRC) +} + +# Sometimes routers take awhile to answer (the default is 10 sec) +set timeout 120 + +# Process the command line +for {set i 0} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + + switch -glob -- $arg { + # Command to run. + -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect debug mode + } -d* { + exp_internal 1 + # Environment variable to pass to -s scripts + } -E* + { + if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { + set E$varname $varvalue + } else { + send_user "\nError: invalid format for -E in $arg\n" + exit 1 + } + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + # user Password + } -p* - + -P* { + if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # Version string + } -V* { + send_user "rancid 2.3.2a8\n" + exit 0 + # passphrase + } -r* - + -R* { + if {! [ regexp .\[rR\](.+) $arg ignore passphrase]} { + incr i + set avpassphrase [ lindex $argv $i ] + } + # Expect script to run. + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "\nError: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # Timeout + } -t* - + -T* { + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeout [ lindex $argv $i ] + } + # Username + } -u* - + -U* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { + incr i + set username [ lindex $argv $i ] + } + # command file + } -x* - + -X* { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + if [ catch {set cmd_fd [open $cmd_file r]} reason ] { + send_user "\nError: $reason\n" + exit 1 + } + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # 'ssh -c' cypher type + } -y* - + -Y* { + if {! [ regexp .\[yY\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + } -* { + send_user "\nError: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "\nError: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global int_$var ; lappend int_$var $args} +proc include {args} { + global env + regsub -all "(^{|}$)" $args {} args + if { [ regexp "^/" $args ignore ] == 0 } { + set args $env(HOME)/$args + } + source_password_file $args +} + +proc find {var router} { + upvar int_$var list + if { [info exists list] } { + foreach line $list { + if { [string match [lindex $line 0] $router ] } { + return [lrange $line 1 end] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# it is sourced, the user better know what to put in there, as it +# could install more than just password info... I will assume however, +# that a "bad guy" could just as easy put such code in the clogin +# script, so I will leave .cloginrc as just an extention of that script +proc source_password_file { password_file } { + global env + if { ! [file exists $password_file] } { + send_user "\nError: password file ($password_file) does not exist\n" + exit 1 + } + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "\nError: $password_file must not be world readable/writable\n" + exit 1 + } + if [ catch {source $password_file} reason ] { + send_user "\nError: $reason\n" + exit 1 + } +} + +# Log into the router. +# returns: 0 on success, 1 on failure +proc login { router user passwd cmethod cyphertype identfile} { + global spawn_id in_proc do_command do_script passphrase prompt + global sshcmd + set in_proc 1 + + # try each of the connection methods in $cmethod until one is successful + set progs [llength $cmethod] + foreach prog [lrange $cmethod 0 end] { + incr progs -1 + if [string match "telnet*" $prog] { + regexp {telnet(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + set retval [ catch {spawn telnet $router} reason ] + } else { + set retval [ catch {spawn telnet $router $port} reason ] + } + if { $retval } { + send_user "\nError: telnet failed: $reason\n" + return 1 + } + } elseif [string match "ssh*" $prog] { + # ssh to the router & try to login with or without an identfile. + # We use two calls to spawn since spawn does not seem to parse + # spaces correctly. + regexp {ssh(:([^[:space:]]+))*} $prog command suffix port + if {"$port" == ""} { + if {$identfile != ""} { + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user -i $identfile $router} reason ] { + send_user "\nError: failed to $sshcmd: $reason\n" + return 1 + } + } else { + if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: failed to $sshcmd: $reason\n" + return 1 + } + } + } else { + if {$identfile != ""} { + if [ catch {spawn $sshcmd -p $port -c $cyphertype -x -l $user -i $identfile $router} reason ] { + send_user "\nError: failed to $sshcmd: $reason\n" + return 1 + } + } else { + if [ catch {spawn $sshcmd -p $port -c $cyphertype -x -l $user $router} reason ] { + send_user "\nError: failed to $sshcmd: $reason\n" + return 1 + } + } + } + } elseif ![string compare $prog "rsh"] { + send_error "\nError: unsupported method: rsh\n" + if { $progs == 0 } { + return 1 + } + continue + } else { + send_user "\nError: unknown connection method: $prog\n" + return 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + catch {close}; catch {wait}; + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + expect { + -re "(Connection refused|Secure connection \[^\n\r]+ refused|Connection closed by)" { + catch {close}; catch {wait}; + if !$progs { + send_user "\nError: Connection Refused ($prog)\n"; return 1 + } + } + eof { send_user "\nError: Couldn't login\n"; wait; return 1 + } -nocase "unknown host\r\n" { + catch {close}; catch {wait}; + send_user "\nError: Unknown host\n"; wait; return 1 + } "Host is unreachable" { + catch {close}; catch {wait}; + send_user "\nError: Host Unreachable!\n"; wait; return 1 + } "No address associated with name" { + catch {close}; catch {wait}; + send_user "\nError: Unknown host\n"; wait; return 1 + } + "Bad user name or password" { + send_user "\nError: Check your password for $router\n" + catch {close}; catch {wait}; return 1 + } + -re "Enter passphrase.*: " { + # sleep briefly to allow time for stty -echo + sleep 1 + send "$passphrase\r" + exp_continue } + -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" { + send "yes\r" + send_user "\nHost $router added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" + return 1 } + -re "Offending key for .* \(yes\/no\)\?" { + send "no\r" + send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" + return 1 } + "Login Screen" { + send "$user\t$passwd\r" + exp_continue + } + "Switch Main Menu" { + # send Ctrl+Z + sleep 1; send "send \032" + exp_continue + } + ">" { + send "lcli\r" + exp_continue + } + -re "User Name:$" { + send "$user\r" + exp_continue + } + -re "Password:$" { + send "$passwd\r" + exp_continue + } + -re "assword: $" { + send "$passwd\r" + exp_continue + } + + -re "$prompt" { break; } + denied { send_user "\nError: Check your password for $router\n" + catch {close}; catch {wait}; return 1 + } + } + } + + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global in_proc + set in_proc 1 + + send "terminal datadump\r" + expect -re $prompt {} + + # Is this a multi-command? + if [ string match "*\;*" "$command" ] { + set commands [split $command \;] + set num_commands [llength $commands] + + for {set i 0} {$i < $num_commands} { incr i} { + send "[lindex $commands $i]\r" + expect { + -re "^\[^\n\r *]*$prompt *$" {} + -re "^\[^\n\r]*$prompt." { exp_continue } + -re "\[\r\n]+" { exp_continue } + } + } + } else { + send "$command\r" + expect { + -re "^\[^\n\r *]*$prompt *$" {} + -re "^\[^\n\r]*$prompt." { exp_continue } + -re "\[\r\n]+" { exp_continue } + } + } + send "exit\r\n" + expect { + "\n" { exp_continue } + timeout { catch {close}; catch {wait}; + return 0 + } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +source_password_file $password_file +set in_proc 0 +set exitval 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + send_user "$router\n" + + set prompt "#" + + # Figure out username + if {[info exists username]} { + # command line username + set loginname $username + } else { + set loginname [join [find user $router] ""] + if { "$loginname" == "" } { set loginname $default_user } + } + + # Figure out loginname's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line passwd + set passwd $userpasswd + } else { + set passwd [join [lindex [find userpassword $router] 0] ""] + if { "$passwd" == "" } { + set passwd [join [lindex [find password $router] 0] ""] + if { "$passwd" == "" } { + send_user "\nError: no password for $router in $password_file.\n" + continue + } + } + } + + # Figure out identity file to use + set identfile [join [lindex [find identity $router] 0] ""] + + # Figure out passphrase to use + if {[info exists avpassphrase]} { + set passphrase $avpassphrase + } else { + set passphrase [join [lindex [find passphrase $router] 0] ""] + } + if { ! [string length "$passphrase"]} { + set passphrase $passwd + } + + # Figure out ssh cypher type + if {[info exists cypher]} { + # command line ssh cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Figure out connection method + set cmethod [find method $router] + if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } + + # Figure out the SSH executable name + set sshcmd [find sshcmd $router] + if { "$sshcmd" == "" } { set sshcmd {ssh} } + + # Login to the router + if {[login $router $loginname $passwd $cmethod $cyphertype $identfile]} { + incr exitval + continue + } + + if { $do_command } { + if {[run_commands $prompt $command]} { + incr exitval + continue + } + } elseif { $do_script } { + send "terminal datadump\r" + expect -re $prompt {} + source $sfile + catch {close}; + } else { + label $router + log_user 1 + interact + } + + # End of for each router + catch {wait}; + sleep 0.3 +} +exit $exitval diff --git a/bin/csbrancid b/bin/csbrancid new file mode 100644 index 0000000..95cedf4 --- /dev/null +++ b/bin/csbrancid @@ -0,0 +1,466 @@ +#!/usr/bin/perl +## +## $Id: csbrancid,v 1.4 2009-06-06 14:04:25 bjorn Exp $ +## +## rancid 2.3.2a8 +## Copyright (c) 1997-2007 by Terrapin Communications, Inc. +## All rights reserved. +## +## This code is derived from software contributed to and maintained by +## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan, +## Pete Whiting, Austin Schutz, and Andrew Fort. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. All advertising materials mentioning features or use of this software +## must display the following acknowledgement: +## This product includes software developed by Terrapin Communications, +## Inc. and its contributors for RANCID. +## 4. Neither the name of Terrapin Communications, Inc. nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## 5. It is requested that non-binding fixes and modifications be contributed +## back to Terrapin Communications, Inc. +## +## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS +## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS +## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. +# +# This version of rancid tries to deal with zebra s/w. +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-dV] [-l] [-f filename | hostname] +# +use Getopt::Std; +getopts('dflV'); +if ($opt_V) { + print "rancid 2.3.2a8\n"; + exit(0); +} +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # clogin timeout in seconds + +my(@commandtable, %commands, @commands);# command lists +my($aclsort) = ("ipsort"); # ACL sorting mode +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)) + && %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 system" +sub ShowSystem { + print STDERR " In ShowSystem: $_" if ($debug); + + $_ = ; + + if (/command authorization failed/i) { + return(-1); + } elsif (/^$prompt/) { + return(0); + } elsif (/^\s*$/) { + ShowSystemSections($_); + } else { + ShowSystemLines($_); + } + + return(0); +} + +sub ShowSystemSections { + $_ = $_[0]; + my $skip_section = 0; + while () { + # delete rare characters + tr/\015//d; + + # finish cases + last if(/^$prompt/); + + # new section comes, reset skip + if(/^(\s*|\s*$cmd\s*)$/) { + $skip_section = 0; + $_ = ; + next; + } + + # begin of a section to avoid + $skip_section=1 if(/Unit\s+Up\s+(T|t)ime/); + $skip_section=1 if(/Unit\s+(Fans|FAN)/); + $skip_section=1 if(/Unit\s+Temperature/); + + # we are on a section to avoid? + if($skip_section) { + $_ = ; + next; + } + ProcessHistory("COMMENTS","keysort","B0", "!$_"); + $_ = ; + } +} + +sub ShowSystemLines { + $_ = $_[0]; + my $skip = 0; + while () { + # delete rare characters + tr/\015//d; + + # finish cases + last if(/^$prompt/); + last if(/Unit\s*Temperature/); + + # remove lines but continue + $skip=1 if(/^(\s*|\s*$cmd\s*)$/); + $skip=1 if(/Up Time/); + + # if not skiped, save the log + if($skip){ + # reset skip for next line + $skip = 0; + } else { + ProcessHistory("COMMENTS","keysort","B0", "!$_"); + } + $_ = ; + } +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + return(-1) if (/command authorization failed/i); + + ProcessHistory("COMMENTS","keysort","C0", "!$_") && next; + + } + return(0); +} + +# This routine processes a "show startup-config" +sub ShowStartupConfig { + print STDERR " In ShowStartupConfig: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + return(-1) if (/command authorization failed/i); + + if (/^(enable password( \d)?) / && $filter_pwds >= 1) { + ProcessHistory("ENABLE","","","!$1 \n"); + next; + } + if (/^username (\S+)(\s.*)? password encrypted ((\d) \S+|\S+)(.*)/) { + if ($filter_pwds == 2) { + ProcessHistory("USER","keysort","$1","!username $1$2 password encrypted $5\n"); + } elsif ($filter_pwds == 1 && $4 ne "5"){ + ProcessHistory("USER","keysort","$1","!username $1$2 password encrypted $5\n"); + } else { + ProcessHistory("USER","keysort","$1","$_"); + } + next; + } + + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + + # order access-lists + /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && + ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next; + + # order logging statements + /^logging (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("LOGGING","ipsort","$1","$_") && next; + + # order/prune snmp-server host statements + # we only prune lines of the form + # snmp-server host a.b.c.d + if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { + if ($filter_commstr) { + my($ip) = $1; + my($line) = "snmp-server host $ip"; + my(@tokens) = split(' ', $'); #' + my($token); + while ($token = shift(@tokens)) { + if ($token eq 'version') { + $line .= " " . join(' ', ($token, shift(@tokens))); + } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { + $line .= " " . $token; + } else { + $line = "!$line " . join(' ', ("", join(' ',@tokens))); + last; + } + } + ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); + } else { + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); + } + next; + } + if (/^(snmp-server community) (\S+)/) { + if (defined($ENV{'NOCOMMSTR'})) { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 $'") && next; + } else { + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + } + } + + # prune tacacs/radius server keys + if (/(.* key )\S+(.*)/ && $filter_pwds >= 1) { + ProcessHistory("","","","!$1$2\n"); next; + } + + # catch anything that wasnt matched above. + ProcessHistory("","","","$_"); + + } + # there's no end marker, so we'll just have to assume that it was complete + $found_end = 1; + return(1); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +@commandtable = ( + {'show system' => 'ShowSystem'}, + {'show version' => 'ShowVersion'}, + {'show startup-config' => 'ShowStartupConfig'} +); +# 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) { + print STDERR "opening file $host\n" if ($debug); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing csblogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing csblogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "csblogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "csblogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "csblogin failed for $host: $!\n"; + } else { + open(INPUT,"csblogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/^Error:/) { + print STDOUT ("$host csblogin error: $_"); + print STDERR ("$host csblogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) { + $prompt = ($_ =~ /^([^#]+#)/)[0]; + $prompt =~ s/([][}{)(\\])/\\$1/g; + } + 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})) { + 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))); + printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "$host: End of run not found\n"; + print STDERR "$host: End of run not found (clean_run=$clean_run, found_end=$found_end)\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} From 18d1c398b0de54a63da706f1780b36a6316eb8f9 Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Thu, 18 Jan 2018 12:24:53 -0700 Subject: [PATCH 31/38] rename csb files for makefile integration --- bin/{csblogin => csblogin.in} | 0 bin/{csbrancid => csbrancid.in} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename bin/{csblogin => csblogin.in} (100%) rename bin/{csbrancid => csbrancid.in} (100%) diff --git a/bin/csblogin b/bin/csblogin.in similarity index 100% rename from bin/csblogin rename to bin/csblogin.in diff --git a/bin/csbrancid b/bin/csbrancid.in similarity index 100% rename from bin/csbrancid rename to bin/csbrancid.in From 049ef5ed81420f4a9c47f5f68f229ca3d244cdbd Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Thu, 25 Jan 2018 12:31:44 -0700 Subject: [PATCH 32/38] Added support for Cisco Small Business switches (cisco-sb). Upstream scripts: https://github.com/chrpinedo/rancid-cisco-sb --- .gitignore | 2 ++ README | 2 ++ bin/Makefile.am | 9 +++++---- bin/Makefile.in | 9 +++++++-- bin/csblogin.in | 4 ++-- bin/csbrancid.in | 8 ++++---- bin/rancid-fe.in | 1 + configure.ac | 1 + debian/changelog | 4 ++++ man/Makefile.am | 4 ++-- man/Makefile.in | 4 ++-- man/clogin.1 | 2 ++ man/csblogin.1 | 1 + man/csbrancid.1 | 1 + man/rancid.1 | 3 +++ 15 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 man/csblogin.1 create mode 100644 man/csbrancid.1 diff --git a/.gitignore b/.gitignore index 903b05b..7e189a3 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ bin/cat5rancid bin/clogin bin/control_rancid bin/cssrancid +bin/csblogin +bin/csbrancid bin/dlogin bin/drancid bin/elogin diff --git a/README b/README index 5f341e5..a999edb 100644 --- a/README +++ b/README @@ -53,6 +53,7 @@ bin/ brancid.in Version of rancid.in for baynet/nortel routers. cat5rancid.in Version of rancid.in for Cisco Catalyst switches. cssrancid.in Version of rancid.in for Cisco CSS switches. + csbrancid.in Version of rancid.in for Cisco Small Business switches. erancid.in Version of rancid.in for ADC EZ-T3 muxes. f10rancid.in Version of rancid.in for Force10 routers. f5rancid.in Version of rancid.in for F5 BigIPs. @@ -82,6 +83,7 @@ bin/ alogin.in Version of clogin.in for Alteon switches. blogin.in Version of clogin.in for baynet/Nortel routers. bntlogin.in Version of clogin.in for Blade Network Technologies (BNT)/HP BladeSystem switches. + csblogin.in Version of clogin.in for Cisco Small Business switches. elogin.in Version of clogin.in for ADC EZ-T3 muxes. flogin.in Version of clogin.in for Foundry switches. If foundry cleaned-up their bloody UI, clogin should do the job. diff --git a/bin/Makefile.am b/bin/Makefile.am index 4601a64..a81c17d 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -50,11 +50,12 @@ AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = hpuifilter bin_SCRIPTS = agmrancid alogin arancid arrancid avologin avorancid blogin \ - brancid bntlogin bntrancid brocaderancid cat5rancid clogin control_rancid cssrancid \ - elogin erancid f5rancid f10rancid flogin fnlogin fnrancid francid \ + brancid bntlogin bntrancid brocaderancid cat5rancid clogin control_rancid \ + csblogin csbrancid cssrancid elogin erancid \ + f5rancid f10rancid flogin fnlogin fnrancid francid \ hlogin hrancid htlogin htrancid jerancid jlogin jrancid mrancid \ - mrvlogin mrvrancid mtlogin mtrancid nlogin nrancid nslogin nsrancid \ - nxrancid rancid_par pflogin pfrancid prancid rancid rivlogin rivrancid rrancid srancid \ + mrvlogin mrvrancid mtlogin mtrancid nlogin nrancid nslogin nsrancid nxrancid \ + rancid_par pflogin pfrancid prancid rancid rivlogin rivrancid rrancid srancid \ telcorancid tlogin tntlogin tntrancid trancid ubnt-es-rancid urancid ucsrancid \ xrancid xrrancid zrancid zyrancid dlogin drancid shelllogin shellrancid \ vlogin vrancid h3clogin h3crancid diff --git a/bin/Makefile.in b/bin/Makefile.in index 2b8fe4d..1bc66ca 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -93,6 +93,7 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/bntlogin.in $(srcdir)/bntrancid.in \ $(srcdir)/brocaderancid.in $(srcdir)/cat5rancid.in \ $(srcdir)/clogin.in $(srcdir)/rancid.in $(srcdir)/cssrancid.in \ + $(srcdir)/csblogin.in $(srcdir)/csbrancid.in \ $(srcdir)/dlogin.in $(srcdir)/drancid.in $(srcdir)/elogin.in \ $(srcdir)/erancid.in $(srcdir)/f5rancid.in \ $(srcdir)/f10rancid.in $(srcdir)/flogin.in \ @@ -127,7 +128,7 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = agmrancid alogin arancid arrancid avologin \ avorancid blogin brancid bntlogin bntrancid brocaderancid cat5rancid clogin \ - rancid cssrancid dlogin drancid elogin erancid f5rancid \ + rancid csblogin csbrancid cssrancid dlogin drancid elogin erancid f5rancid \ f10rancid flogin francid fnlogin fnrancid hlogin hrancid \ htlogin htrancid jlogin jrancid jerancid mrancid mrvlogin \ mrvrancid mtrancid mtlogin nlogin nrancid nslogin nsrancid \ @@ -352,7 +353,7 @@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign bin_SCRIPTS = agmrancid alogin arancid arrancid avologin avorancid \ blogin brancid bntlogin bntrancid brocaderancid cat5rancid clogin control_rancid \ - cssrancid elogin erancid f5rancid f10rancid flogin fnlogin \ + csblogin csbrancid cssrancid elogin erancid f5rancid f10rancid flogin fnlogin \ fnrancid francid hlogin hrancid htlogin htrancid jerancid \ jlogin jrancid mrancid mrvlogin mrvrancid mtlogin mtrancid \ nlogin nrancid nslogin nsrancid nxrancid rancid_par pflogin \ @@ -462,6 +463,10 @@ clogin: $(top_builddir)/config.status $(srcdir)/clogin.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ rancid: $(top_builddir)/config.status $(srcdir)/rancid.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +csblogin: $(top_builddir)/config.status $(srcdir)/csblogin.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +csbrancid: $(top_builddir)/config.status $(srcdir)/csbrancid.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ cssrancid: $(top_builddir)/config.status $(srcdir)/cssrancid.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ dlogin: $(top_builddir)/config.status $(srcdir)/dlogin.in diff --git a/bin/csblogin.in b/bin/csblogin.in index c3074c4..78cbddc 100644 --- a/bin/csblogin.in +++ b/bin/csblogin.in @@ -1,8 +1,8 @@ -#!/usr/bin/expect -- +#! @EXPECT_PATH@ -- ## ## $Id: csblogin,v 1.3 2010-01-28 13:12:00 bjorn Exp $ ## -## rancid 2.3.2a8 +## @PACKAGE@ @VERSION@ ## Copyright (c) 1997-2007 by Terrapin Communications, Inc. ## All rights reserved. ## diff --git a/bin/csbrancid.in b/bin/csbrancid.in index 95cedf4..66b0946 100644 --- a/bin/csbrancid.in +++ b/bin/csbrancid.in @@ -1,8 +1,8 @@ -#!/usr/bin/perl +#! @PERLV_PATH@ ## ## $Id: csbrancid,v 1.4 2009-06-06 14:04:25 bjorn Exp $ ## -## rancid 2.3.2a8 +## @PACKAGE@ @VERSION@ ## Copyright (c) 1997-2007 by Terrapin Communications, Inc. ## All rights reserved. ## @@ -44,12 +44,12 @@ # # RANCID - Really Awesome New Cisco confIg Differ # -# usage: rancid [-dV] [-l] [-f filename | hostname] +# usage: csbrancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; getopts('dflV'); if ($opt_V) { - print "rancid 2.3.2a8\n"; + print "@PACKAGE@ @VERSION@\n"; exit(0); } $log = $opt_l; diff --git a/bin/rancid-fe.in b/bin/rancid-fe.in index dcdc864..10a90ea 100644 --- a/bin/rancid-fe.in +++ b/bin/rancid-fe.in @@ -61,6 +61,7 @@ $vendor =~ tr/[A-Z]/[a-z]/; 'cat5' => 'cat5rancid', 'cisco' => 'rancid', 'cisco-nx' => 'nxrancid', + 'cisco-sb' => 'csbrancid', 'cisco-xr' => 'xrrancid', 'ciscoucs' => 'ucsrancid', 'css' => 'cssrancid', diff --git a/configure.ac b/configure.ac index 41f8277..1eb282e 100644 --- a/configure.ac +++ b/configure.ac @@ -477,6 +477,7 @@ AC_CONFIG_FILES(bin/blogin bin/brancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/bntlogin bin/bntrancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/brocaderancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/cat5rancid bin/clogin bin/rancid, [chmod a+x $ac_file]) +AC_CONFIG_FILES(bin/csblogin bin/csbrancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/cssrancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/dlogin bin/drancid, [chmod a+x $ac_file]) AC_CONFIG_FILES(bin/elogin bin/erancid, [chmod a+x $ac_file]) diff --git a/debian/changelog b/debian/changelog index 3623f96..7b70562 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,10 @@ rancid-git (2.3.9-5) unstable; urgency=low * Unofficial package * Added Huawei config + [ Jesse Norell ] + * Added support for Cisco Small Business switches (cisco-sb) + + -- Egor Miadzvedzeu Thu, 21 Jul 2016 15:38:26 -0400 rancid-git (2.3.9-4) unstable; urgency=low diff --git a/man/Makefile.am b/man/Makefile.am index 664f7e0..046fbb8 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -52,8 +52,8 @@ AUTOMAKE_OPTIONS=foreign no-dependencies man_gen_MANS = lg.conf.5 rancid.conf.5 lg_intro.1 man_nogen_MANS = agmrancid.1 alogin.1 arancid.1 arrancid.1 avologin.1 \ avorancid.1 blogin.1 bntlogin.1 bntrancid.1 brancid.1 cat5rancid.1 clogin.1 \ - cloginrc.5 control_rancid.1 cssrancid.1 elogin.1 erancid.1 \ - f5rancid.1 f10rancid.1 flogin.1 fnlogin.1 fnrancid.1 francid.1 \ + cloginrc.5 control_rancid.1 csblogin.1 csbrancid.1 cssrancid.1 elogin.1 \ + erancid.1 f5rancid.1 f10rancid.1 flogin.1 fnlogin.1 fnrancid.1 francid.1 \ hlogin.1 hrancid.1 htlogin.1 htrancid.1 jerancid.1 jlogin.1 \ jrancid.1 mrancid.1 mrvlogin.1 mrvrancid.1 mtlogin.1 \ mtrancid.1 nlogin.1 nrancid.1 nslogin.1 nsrancid.1 nxrancid.1 \ diff --git a/man/Makefile.in b/man/Makefile.in index e7d171a..ce2cf9d 100644 --- a/man/Makefile.in +++ b/man/Makefile.in @@ -268,8 +268,8 @@ AUTOMAKE_OPTIONS = foreign no-dependencies man_gen_MANS = lg.conf.5 rancid.conf.5 lg_intro.1 man_nogen_MANS = agmrancid.1 alogin.1 arancid.1 arrancid.1 avologin.1 \ avorancid.1 blogin.1 bntlogin.1 bntrancid.2 brancid.1 cat5rancid.1 clogin.1 \ - cloginrc.5 control_rancid.1 cssrancid.1 elogin.1 erancid.1 \ - f5rancid.1 f10rancid.1 flogin.1 fnlogin.1 fnrancid.1 francid.1 \ + cloginrc.5 control_rancid.1 csblogin.1 csbrancid.1 cssrancid.1 elogin.1 \ + erancid.1 f5rancid.1 f10rancid.1 flogin.1 fnlogin.1 fnrancid.1 francid.1 \ hlogin.1 hrancid.1 htlogin.1 htrancid.1 jerancid.1 jlogin.1 \ jrancid.1 mrancid.1 mrvlogin.1 mrvrancid.1 mtlogin.1 \ mtrancid.1 nlogin.1 nrancid.1 nslogin.1 nsrancid.1 nxrancid.1 \ diff --git a/man/clogin.1 b/man/clogin.1 index 77f52f7..af84496 100644 --- a/man/clogin.1 +++ b/man/clogin.1 @@ -58,6 +58,7 @@ Alteon, Avocent (Cyclades), Bay Networks (nortel), Blade Network Technologies (BNT), +Cisco Small Business, ADC-kentrox EZ-T3 mux, Foundry, HP Procurve switches and Cisco AGMs, @@ -76,6 +77,7 @@ named .B avologin, .B blogin, .B bntlogin, +.B csblogin, .B elogin, .B flogin, .B fnlogin, diff --git a/man/csblogin.1 b/man/csblogin.1 new file mode 100644 index 0000000..4c83247 --- /dev/null +++ b/man/csblogin.1 @@ -0,0 +1 @@ +.so man1/clogin.1 diff --git a/man/csbrancid.1 b/man/csbrancid.1 new file mode 100644 index 0000000..b4633ee --- /dev/null +++ b/man/csbrancid.1 @@ -0,0 +1 @@ +.so man1/rancid.1 diff --git a/man/rancid.1 b/man/rancid.1 index 95dc864..bd218c6 100644 --- a/man/rancid.1 +++ b/man/rancid.1 @@ -44,6 +44,9 @@ Bay Networks (nortel) .B cat5rancid Cisco catalyst switches .TP +.B csbrancid +Cisco Small Business switches +.TP .B cssrancid Cisco content services switches .TP From ff0c478ddb66f4b9e96c1d738d1355e9ee229a7c Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Fri, 26 Jan 2018 10:34:47 -0700 Subject: [PATCH 33/38] change old 'lcli' to 'enable' to support newer SG series switches --- bin/csblogin.in | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/bin/csblogin.in b/bin/csblogin.in index 78cbddc..0054f54 100644 --- a/bin/csblogin.in +++ b/bin/csblogin.in @@ -284,10 +284,11 @@ proc source_password_file { password_file } { # Log into the router. # returns: 0 on success, 1 on failure -proc login { router user passwd cmethod cyphertype identfile} { +proc login { router user passwd enapasswd cmethod cyphertype identfile} { global spawn_id in_proc do_command do_script passphrase prompt global sshcmd set in_proc 1 + set enabled 0 # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] @@ -421,20 +422,22 @@ proc login { router user passwd cmethod cyphertype identfile} { sleep 1; send "send \032" exp_continue } - ">" { - send "lcli\r" + ">" { + send "enable\r" + set enabled 1 exp_continue } -re "User Name:$" { send "$user\r" exp_continue } - -re "Password:$" { - send "$passwd\r" - exp_continue - } - -re "assword: $" { - send "$passwd\r" + -re "Password: ?$" { + sleep 1 + if {$enabled == 1} { + send -- "$enapasswd\r" + } else { + send -- "$passwd\r" + } exp_continue } @@ -525,6 +528,17 @@ foreach router [lrange $argv $i end] { } } + # Look for enable password + if { ! [info exists enapasswd] } { + set pswd [find password $router] + if { [llength $pswd] > 1 } { + set enapasswd [join [lindex $pswd 1] ""] + } + } + if { ! [string length "$enapasswd"]} { + set enapasswd $passwd + } + # Figure out identity file to use set identfile [join [lindex [find identity $router] 0] ""] @@ -556,7 +570,7 @@ foreach router [lrange $argv $i end] { if { "$sshcmd" == "" } { set sshcmd {ssh} } # Login to the router - if {[login $router $loginname $passwd $cmethod $cyphertype $identfile]} { + if {[login $router $loginname $passwd $enapasswd $cmethod $cyphertype $identfile]} { incr exitval continue } From bd2eb107a4ef5df92ccc9d3a47f530d0936aeb44 Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Fri, 26 Jan 2018 11:01:49 -0700 Subject: [PATCH 34/38] remove hard-coded version number --- bin/csblogin.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/csblogin.in b/bin/csblogin.in index 0054f54..360e9f9 100644 --- a/bin/csblogin.in +++ b/bin/csblogin.in @@ -134,7 +134,7 @@ for {set i 0} {$i < $argc} {incr i} { set do_passwd 0 # Version string } -V* { - send_user "rancid 2.3.2a8\n" + send_user "@PACKAGE@ @VERSION@\n" exit 0 # passphrase } -r* - From c9748f793570d66bdaa9005acfcac49d4d22166c Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Thu, 29 Mar 2018 14:46:43 -0600 Subject: [PATCH 35/38] vlogin works with rsa keys (passwordless) login --- bin/vlogin.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/vlogin.in b/bin/vlogin.in index 2351d0f..a79de07 100644 --- a/bin/vlogin.in +++ b/bin/vlogin.in @@ -429,7 +429,7 @@ foreach router [lrange $argv $i end] { set timeout $timeoutdflt } - set prompt ":" + set prompt "\[:>]" # Figure out username if {[info exists username]} { From 5bd8c8ed56e938c8f0c0712d34df8dcccf3f901a Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Thu, 29 Mar 2018 16:10:54 -0600 Subject: [PATCH 36/38] vrancid updates for current VyOS --- bin/vrancid.in | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/bin/vrancid.in b/bin/vrancid.in index 42e0ddc..dea3ba3 100644 --- a/bin/vrancid.in +++ b/bin/vrancid.in @@ -151,26 +151,37 @@ sub ShowConfiguration { } next if (/^system (shutdown message from|going down )/i); next if (/^\{(master|backup)(:\d+)?\}/); + next if (/^Uptime:\s+/); $lines++; /^database header mismatch: / && return(-1); /^version .*;\d+$/ && return(-1); + if (/^Must be an admin user to run this command\.$/i) { + print STDERR " In ShowConfiguration: $_" if ($debug); + } + s/ # SECRET-DATA$//; s/ ## SECRET-DATA$//; # filter snmp community, when in snmp { stanza } - /^snmp/ && $snmp++; + /^(\s*)snmp/ && $snmp++; /^}/ && ($snmp = 0); if ($snmp && /^(\s*)(community|trap-group) [^ ;]+(\s?[;{])$/) { if ($filter_commstr) { $_ = "$1$2 \"\"$3\n"; } } + # community name can contain spaces if quoted + if (/^(set service snmp community )(\"[^\"]+\"|\'[^\']+\'|[^ ]+)/) { + if ($filter_commstr) { + $_ = "$1\"\"$'"; + } + } if (/(\s*authentication-key )[^ ;]+/ && $filter_pwds >= 1) { ProcessHistory("","","","#$1$'"); next; } - if (/(\s*md5 \d+ key )[^ ;]+/ && $filter_pwds >= 1) { + if (/(\s*md5( \d+ |-)key )[^ ;]+/ && $filter_pwds >= 1) { ProcessHistory("","","","#$1$'"); next; } @@ -187,16 +198,28 @@ sub ShowConfiguration { ProcessHistory("","","","#$1$'"); next; } - if (/(\s+encrypted-password )[^ ;]+/ && $filter_pwds >= 2) { - ProcessHistory("","","","#$1$'"); + if (/^(.+encrypted-password )(\"[^\"]+\"|\'[^\']+\'|[^ ]+)/ && $filter_pwds >= 2) { + ProcessHistory("","","","! $1\"\"$'\n"); + next; + } + if (/^(.+plaintext-password )(\"[^\"]+\"|\'[^\']+\'|[^ ]+)/ && $filter_pwds >= 1) { + ProcessHistory("","","","! $1\"\"$'\n"); next; } if (/(\s+ssh-(rsa|dsa) )\"/ && $filter_pwds >= 2) { - ProcessHistory("","","","#$1;\n"); + ProcessHistory("","","","! $1\n"); next; } if (/^(\s+(pre-shared-|)key (ascii-text|hexadecimal) )[^ ;]+/ && $filter_pwds >= 1) { - ProcessHistory("","","","#$1$'"); + ProcessHistory("","","","! $1$'"); + next; + } + if (/^(.* public-keys .+ key ).+/ && $filter_pwds >= 1) { + ProcessHistory("","","","! $1\n"); + next; + } + if (/^(set protocols bgp .+ neighbor (\S*) password )/ && $filter_pwds >= 1) { + ProcessHistory("","","","! $1 \n"); next; } ProcessHistory("","","","$_"); @@ -220,7 +243,7 @@ sub DoNothing {print STDOUT;} # Main @commandtable = ( - {'show version | grep -v Uptime' => 'ShowConfiguration'}, + {'show version' => 'ShowConfiguration'}, {'show configuration' => 'ShowConfiguration'}, {'show configuration commands' => 'ShowConfiguration'}, ); From 445344798496888de3d4e98b983f3ac6bccff3f5 Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Thu, 26 Apr 2018 10:10:11 -0600 Subject: [PATCH 37/38] handle "password exceeded max lifetime" prompt in csblogin --- bin/csblogin.in | 5 +++++ bin/csbrancid.in | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/bin/csblogin.in b/bin/csblogin.in index 360e9f9..4b60347 100644 --- a/bin/csblogin.in +++ b/bin/csblogin.in @@ -413,6 +413,11 @@ proc login { router user passwd enapasswd cmethod cyphertype identfile} { send "no\r" send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" return 1 } + -re "Your password has exceeded the maximum lifetime\..*\nDo you want to change it now \\\(Y\/N\\\).*\?" { + send "N" + send_user "\nPassword on host $router has exceeded the maximum lifetime and should be changed.\n" + exp_continue + } "Login Screen" { send "$user\t$passwd\r" exp_continue diff --git a/bin/csbrancid.in b/bin/csbrancid.in index 66b0946..35c654d 100644 --- a/bin/csbrancid.in +++ b/bin/csbrancid.in @@ -186,6 +186,9 @@ sub ShowSystem { sub ShowSystemSections { $_ = $_[0]; + + print STDERR " In ShowSystemSections: $_" if ($debug); + my $skip_section = 0; while () { # delete rare characters @@ -218,6 +221,11 @@ sub ShowSystemSections { sub ShowSystemLines { $_ = $_[0]; + + tr/\015//d; + + print STDERR " In ShowSystemLines: $_" if ($debug); + my $skip = 0; while () { # delete rare characters @@ -345,8 +353,8 @@ sub DoNothing {print STDOUT;} # Main @commandtable = ( - {'show system' => 'ShowSystem'}, - {'show version' => 'ShowVersion'}, + {'show system' => 'ShowSystem'}, + {'show version' => 'ShowVersion'}, {'show startup-config' => 'ShowStartupConfig'} ); # Use an array to preserve the order of the commands and a hash for mapping @@ -407,9 +415,9 @@ if ($ENV{"FILTER_PWDS"} =~ /no/i) { } ProcessHistory("","","","!RANCID-CONTENT-TYPE: cisco-sb\n!\n"); -ProcessHistory("COMMENTS","keysort","B0","!\n"); # show version -ProcessHistory("COMMENTS","keysort","C0","!\n"); # show package -ProcessHistory("COMMENTS","keysort","D0","!\n"); # show hardware +ProcessHistory("COMMENTS","keysort","B0","!\n"); # show system +ProcessHistory("COMMENTS","keysort","C0","!\n"); # show version +ProcessHistory("COMMENTS","keysort","D0","!\n"); # show startup-config ProcessHistory("COMMENTS","keysort","Z0","!\n"); $clean_run=1; TOP: while() { From 7d3e302b29ef536353af44da7d5d574ee2a55aa7 Mon Sep 17 00:00:00 2001 From: Jesse Norell Date: Wed, 16 May 2018 10:52:47 -0600 Subject: [PATCH 38/38] update .gitignore --- .gitignore | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7e189a3..9cd7427 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,10 @@ debian/rancid-util/ debian/rancid.postrm.debhelper debian/rancid/ debian/rancid-git/ +debian/.debhelper/ +debian/autoreconf.after +debian/autoreconf.before +debian/debhelper-build-stamp Makefile aclocal.m4 autom4te.cache/ @@ -22,6 +26,8 @@ bin/arrancid bin/avologin bin/avorancid bin/blogin +bin/bntlogin +bin/bntrancid bin/brancid bin/brocaderancid bin/cat5rancid @@ -39,6 +45,8 @@ bin/f5rancid bin/flogin bin/fnrancid bin/francid +bin/h3clogin +bin/h3crancid bin/hlogin bin/hpuifilter bin/hpuifilter.o @@ -83,6 +91,8 @@ bin/trancid bin/ubnt-es-rancid bin/ucsrancid bin/urancid +bin/vlogin +bin/vrancid bin/xrancid bin/xrrancid bin/zrancid @@ -104,5 +114,5 @@ share/rancid-cvspurge share/rtrfilter bin/fnlogin include/version.h - +include/config.h.in~