Gheek.net

November 13, 2008

Cisco IPS support for rancid

Filed under: Cisco, perl, rancid — Tags: , , , — lancevermilion @ 1:43 pm

In order to get rancid to collect the config from an IPS module you will need to make sure you have the correct login creds in the rancid users “.cloginrc”, add the type of ips to “rancid-fe” and you also need to create the “ipsrancid” script.

Sample addition for your “.cloginrc”. Make sure this is above anything else so no other wildcards in the “.cloginrc” get caught.

add autoenable ips-primary 1
add user ips-primary rancid
add password ips-primary <>
add method ips-primary ssh

Changes required for “rancid-fe”.

'ips' => 'ipsrancid',

Create the “ipsrancid” script as “<rancid_home>/bin/ipsrancid”. Make sure you “chmod 755 <rancid_home>/bin/ipsrancid” and “chown <rancid_user>:<rancid_user_group> <rancid_home>/bin/ipsrancid”.

#!/usr/bin/perl
##
## 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.
##
#
# hacked version of Hank's rancid - this one tries to deal with Hitachi's.
#
# Modified again by Lance Vermilion (11/13/08)
# Modified from htrancid by Jeremy M. Guthrie
# Created on 5/4/2007
#
# This is meant to try handle Cisco's IPS V5.X line and on
#
# RANCID - Really Awesome New Cisco confIg Differ
#
# usage: ipsrancid [-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;
$timeo = 90; # clogin timeout in seconds

my(@commandtable, %commands, @commands);# command lists
my(%filter_pwds); # password filtering mode

# This routine is used to print out the router configuration
sub ProcessHistory {

($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);
}

# This routine parses "show config"
sub ShowConfig {
print STDERR " In ShowConfig: $_" if ($debug);

$firstexit=0;

while () {
tr/15//d;
tr/20//d;

#strip out the stupid spinning running-config progress thingy
s/Generating current config: \.*[\|\/\-\\]//gi;
$skipprocess=0;

#sometimes an 'exit' appears at the top of the config, we don't want them
if ( (/^exit/) && ( ! $firstexit ) ) {
$firstexit=1;
$skipprocess=1;
}

#remove spaces left over from lame spinning progress thingy
if ( /^\s+! ------------------------------/ ) {
s/^\s+!/!/g
}

if (/^(read-only-community) / && $filter_pwds >= 1) {
ProcessHistory("","","","!$1 \n"); next;
}
if (/^(read-write-community) / && $filter_pwds >= 1) {
ProcessHistory("","","","!$1 \n"); next;
}
if (/^(trap-community-name) / && $filter_pwds >= 1) {
ProcessHistory("","","","!$1 \n"); next;
}
if (/^(ntp-keys \d+ md5-key) / && $filter_pwds >= 1) {
ProcessHistory("","","","!$1 \n"); next;
}
if (/^(password) / && $filter_pwds >= 1) {
ProcessHistory("","","","!$1 \n"); next;
}

last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
if ( ! /^$prompt/) {
if ( ! $skipprocess ) {
print STDOUT " ShowConfig Data: $_" if ($debug);
ProcessHistory("","","","$_");
}
}
}
$clean_run=1;
print STDERR " Exiting ShowConfig: $_" if ($debug);
return(0);
}

# This routine parses single command's that return no required info
sub ShowVersion {
print STDERR " In ShowVersion: $_" if ($debug);
ProcessHistory("","","","!\n!IPS Show Version Start\n");

while () {
tr/15//d;

$skipprocess=0;

if ( /^Sensor up-time/ ) { $skipprocess=1; }
if ( ( /using.*bytes of available/i ) ) { $skipprocess=1; }

last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
if ( ! /^$prompt/) {
if ( ! $skipprocess ) {
print STDOUT " ShowVersion Data: $_" if ($debug);
ProcessHistory("","","","! $_");
}
}
}
ProcessHistory("","","","!\n!IPS Show Version End\n");
print STDERR " Exiting ShowVersion: $_" if ($debug);
return(0)
}

# This routine parses single command's that return no required info
sub ShowUsersAll {
print STDERR " In ShowUsersAll: $_" if ($debug);
ProcessHistory("","","","!\n!IPS User Database Start\n");

while () {
tr/15//d;

$skipprocess=0;

s/^ CLI ID //g;
s/^ //g;
s/^\* +[0-9]+ +//g;

last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
if ( ! /^$prompt/) {
if ( ! $skipprocess ) {
print STDOUT " ShowUsersAll Data: $_" if ($debug);
ProcessHistory("","","","!$_");
}
}
}
ProcessHistory("","","","!\n!IPS User Database End\n!\n!\n");
print STDERR " Exiting ShowUsersAll: $_" if ($debug);
return(0)
}

# dummy function
sub DoNothing {print STDOUT;}

# Main
@commandtable = (
{'show version' => 'ShowVersion'},
{'show users all' => 'ShowUsersAll'},
{'show configuration' => 'ShowConfig'}
);
# 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);

open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
select(OUTPUT);
# make OUTPUT unbuffered if debugging
if ($debug) { $| = 1; }

# The IPS doesn't like the TERM of network so we must change it
if ( $ENV{TERM} eq 'network' ) {
$ENV{TERM} = 'vt100';
}
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 -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})) {
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 </dev/null |") || die "clogin failed for $host: $!\n";
}
}
# Change the TERM back to network
if ( $ENV{TERM} eq 'vt100' ) {
$ENV{TERM} = 'network';
}

# determine password filtering mode
if ($ENV{"FILTER_PWDS"} =~ /no/i) {
$filter_pwds = 0;
} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
$filter_pwds = 2;
} else {
$filter_pwds = 1;
}

ProcessHistory("","","","!RANCID-CONTENT-TYPE: ipsrancid\n!\n");
TOP: while() {
tr/15//d;

#strip out the stupid spinning running-config progress thingy
s/Generating current config: \.*[\|\/\-\\]//gi;

if (/^.*logout$/) {
$clean_run=1;
last;
}
if (/^Error:/) {
print STDOUT ("$host clogin error: $_");
print STDERR ("$host clogin error: $_") if ($debug);
$clean_run=0;
last;
}
while (/($cmds_regexp)/) {
$cmd = $1;
if (!defined($prompt)) {
$prompt = ($_ =~ /^([^#]+#)/)[0];
$prompt =~ s/([][}{)(\\])/\\$1/g;
print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
}
print STDERR ("IPS COMMAND:$_") if ($debug);
if (! defined($commands{$cmd})) {
print STDERR "$host: found unexpected command - \"$cmd\"\n";
$clean_run = 0;
last TOP;
}
$rval = };
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 ) {
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);
}

Advertisements

February 14, 2008

cssSSL-PROXY-usage_pl.txt

Filed under: Cisco, perl — Tags: , , , , — lancevermilion @ 2:54 pm
#!/usr/bin/perl -w
#Author: Lance Vermilion
#Purpose: Parse the css config and find how many ssl-servers
#         are not defined under a owner and thus can be used
#         for any owner that matches the requirements of that
#         cert.
##############################################################
$ipcount = 0;
$printip = 0;
$printnoip = 0;
$ssl = "";
$vip = "";
$ip = "";


#
# Check to see if the file exists
#
if ( ! -s "/apps/rancid/lanwan_configs/$ARGV[0].txt" )
{
  die "Can NOT open /apps/rancid/lanwan_configs/$ARGV[0].txt\n"
}


#
# Load in the css config
#
my @array = `cat /apps/rancid/lanwan_configs/$ARGV[0].txt`;

#
# Walk through the config to build the IP list from ssl-proxy-list
#
foreach (@array)
{
  if ($_ =~ /^\s+ssl-server \d+ vip address (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ )
  {
    push(@array1, $1);
  }
}

print "#" x 30 . "\n";
print " $ARGV[0]\n";
print "#" x 30 . "\n";
#
# Walk through the IP list we just built and use that to search with
#
foreach (@array1)
{
$ip = $_;
    $vipcount = 0;
    $sslcount = 0;
    $ipcount++;

  #
  # Walk through the config and pair up ssl-server and owner vips
  #
  foreach (@array)
  {
    #
    # Remove spaces at the end of each line
    #
    s/\s+$//g;

    #
    # Check for the ssl-server vip address
    #
    if ( $_ =~ /^\s+ssl-server \d+ vip address $ip$/ )
    {
      $sslcount++;
      chomp($ssl = $_);
      #print "\n$ssl ($sslcount)\n";
    }

    #
    # Check for the owner/content vip address
    #
    if ( $_ =~ /^\s+vip address $ip$/ )
    {
      $vipcount++;
      chomp($vip = $_);
      #print "$vip ($vipcount)\n";
    }
  }

  #
  # Make sure we have defined sslcount and vipcount
  # aka we have at least defined them as 0.
  #
  if ($sslcount && $vipcount)
  {
    #
    # Check if we have matched the ssl-server vip address
    # and the owner/content vip address
    #
    if ( $sslcount > 0 && $vipcount > 0 )
    {
      print "$ip has: ssl-server [$sslcount], vip [$vipcount]\n";
      $printip++ if ( $sslcount > 0 && $vipcount > 0 );
    }
  }
  else
  {
    print "$ip *WARN* has: ssl-server [$sslcount], vip [$vipcount]\n" if ($ipcount > 0);
    $printnoip++ if ( $ipcount > 0);
  }
}

print "#" x 30;
print "\nTotal SSL-SERVER VIPs: $ipcount\nSSL-SERVER with VIPs: $printip\nSSL-SERVER with No VIPs: $printnoip\n";
print "#" x 30;
print "\n";

cssintparse_pl.txt

Filed under: Cisco, perl — Tags: , , — lancevermilion @ 2:53 pm

A little script to parse Cisco CSS interfaces and make them look nice and easy to read.

#!/usr/bin/perl -w
#Author: Lance Vermilion scripts(a)gheek.net
#Similar Shell Command: egrep "^service| ip add|^keepalive| ip add|^ssl\-proxy\-list|[0-9] vip|^circuit| ip add|^group| vip add| content|^owner" /usr/local/rancid/var/networking/configs/hq-css-01.abc.com
#Purpose: To search for IP addresses in a CSS config.
#####################################################

open(FH, "/usr/local/rancid/var/networking/configs/$ARGV[0]");
while ()
{
  if ( /^(keepalive|service|owner|group|circuit|ssl-proxy-list)\s(.*)/ )
  {
    if ( $inttype && $int ) {
      print "$inttype,$int,NO_IP_FOUND\n" if ! $found_ip && $inttype =~ /(keepalive|service|circuit)/;
      if ( $content ) {
      print "$inttype,$int,$content,NO_VIP_FOUND\n" if ! $found_ovip && $inttype eq 'owner';
      }
      print "$inttype,$int,NO_CONTENT_FOUND,NO_VIP_FOUND\n" if ! $found_ovip && ! $found_content && $inttype eq 'owner';
      print "$inttype,$int,NO_VIP_FOUND\n" if ! $found_gvip && $inttype eq 'group';
      print "$inttype,$int,NO_VIP_FOUND\n" if ! $found_svip && $inttype eq 'ssl-proxy-list';
    }
    $found_ip = "";
    $found_content = "";
    $found_ovip = "";
    $found_gvip = "";
    $found_svip = "";
    $found_int = 1;
    $inttype = $1;
    $int = $2;
    $int =~ s/\s+$//g;
  } # END INT CHECK
  if ( /^\!BootFlash:\s+ip\saddress\s(.*)/ )
  {
    print "$ARGV[0],$1\n";
  }
  if ( $found_int )
  {
    chomp;

    if ( $inttype eq 'ssl-proxy-list' )
    {
      if ( /^\s+ssl-server\s(\d+)\svip address\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*/ )
      {
        print  "$inttype,$int,$1,$2\n";
        #$found_int = "0";
        $found_svip = 1;
      } # END VIP CHECK
    } # END GROUP CHECK

    if ( $inttype =~ /(service|keepalive|circuit)/ )
    {
      if ( /^\s+ip address\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+.*/ )
      {
        print "$inttype,$int,$1\n";
        $found_int = "0";
        $found_ip = "1";
        $int = '';
        $inttype = '';
        next;
      } # END IP CHECK
    } # END SERVICE/KEEPALIVE CHECK

    if ( $inttype eq 'owner' )
    {
      if ( /^\s\scontent\s(.*)/ )
      {
        $content = $1;
        $content =~ s/\s+$//g;
        $found_content = 1;
      } # END CONTENT FOUND

      if ( $found_content )
      {
        if ( /^\s\s\s\svip\saddress\s(.*)/ )
        {
          $found_ovip = 1;
          print  "$inttype,$int,$content,$1\n";
          $content = '';
          next;
        } # END VIP CHECK
      } # END CONTENT
    } # END OWNER CHECK

    if ( $inttype eq 'group' )
    {
      if ( /^\s+vip address\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*/ )
      {
        print  "$inttype,$int,$1\n";
        $found_int = "0";
        $found_gvip = 1;
        $int = '';
        $inttype = '';
        next;
      } # END VIP CHECK
    } # END GROUP CHECK

  } # END FOUND INT

} # END WHILE LOOP

cisco_passwd_decrypt_pl.txt

Filed under: Cisco, perl — Tags: , , , — lancevermilion @ 2:49 pm
#!/usr/bin/perl -w
# $Id: cisco.passwords.html 3722 2006-07-28 03:53:26Z fyodor $
#
# Credits for orginal code and description hobbit@avian.org,
# SPHiXe, .mudge et al. and for John Bashinski 
# for Cisco IOS password encryption facts.
#
# Use for any malice or illegal purposes strictly prohibited!
#
#
# Usage: perl cisco_passwd_decrypt.pl some_encrypted_password
#

@xlat = ( 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41,
          0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c,
          0x64, 0x4a, 0x4b, 0x44, 0x48, 0x53 , 0x55, 0x42 );

                $dp = "";
                ($s, $e) = ($ARGV[0] =~ /^(..)(.+)/o);
                for ($i = 0; $i < length($e); $i+=2) {
                    $dp .= sprintf "%c",hex(substr($e,$i,2))^$xlat[$s++];
                }
        print "+------------------------------------------------------+\n";
        print "| Decrypting an encrypted password from a Cisco device |\n";
        print "+------------------------------------------------------+\n";
        print "$dp\n";
        print "+------------------------------------------------------+\n";
# eof

cisco_passwd_decrypt_cfg_pl.txt

Filed under: Cisco, perl — Tags: , , , — lancevermilion @ 2:47 pm
#!/usr/bin/perl -w
# $Id: cisco.passwords.html 3722 2006-07-28 03:53:26Z fyodor $
#
# Credits for orginal code and description hobbit@avian.org,
# SPHiXe, .mudge et al. and for John Bashinski 
# for Cisco IOS password encryption facts.
#
# Use for any malice or illegal purposes strictly prohibited!
#
# Usage: cat some_cisco_config | perl cisco_passwd_decrypt_cfg.pl
#

@xlat = ( 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41,
          0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c,
          0x64, 0x4a, 0x4b, 0x44, 0x48, 0x53 , 0x55, 0x42 );

while () {
        if (/(password|md5|key)\s+7\s+([\da-f]+)/io) {
            if (!(length($2) & 1)) {
                $ep = $2; $dp = "";
                ($s, $e) = ($2 =~ /^(..)(.+)/o);
                for ($i = 0; $i < length($e); $i+=2) {
                    $dp .= sprintf "%c",hex(substr($e,$i,2))^$xlat[$s++];
                }
                s/7\s+$ep/$dp/;
            }
        }
        print;
}
# eof

cisco_passwd_decrypt_bulk_pl.txt

Filed under: Cisco, perl — Tags: , , , — lancevermilion @ 2:45 pm
#!/usr/bin/perl -w
# $Id: cisco.passwords.html 3722 2006-07-28 03:53:26Z fyodor $
#
# Credits for orginal code and description hobbit@avian.org,
# SPHiXe, .mudge et al. and for John Bashinski 
# for Cisco IOS password encryption facts.
#
# Use for any malice or illegal purposes strictly prohibited!
#
# Usage: cat some_file_with_only_encrypted_passwds | perl cisco_passwd_decrypt_bulk.pl
#


@xlat = ( 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41,
          0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c,
          0x64, 0x4a, 0x4b, 0x44, 0x48, 0x53 , 0x55, 0x42 );

        print "+------------------------------------------------------+\n";
        print "| Decrypting an encrypted password from a Cisco device |\n";
        print "+------------------------------------------------------+\n";
while () {
                $dp = "";
                ($s, $e) = ($_ =~ /^(..)(.+)/o);
                for ($i = 0; $i < length($e); $i+=2) {
                    $dp .= sprintf "%c",hex(substr($e,$i,2))^$xlat[$s++];
                }
        print "$dp\n";
}
        print "+------------------------------------------------------+\n";
# eof

January 28, 2008

Rancid 2.3.2a7 patched to include F5 BigIP support

Filed under: bigip, Cisco, expect, f5, perl, rancid — Tags: , , , , , , — lancevermilion @ 12:10 am

Here is a RANCID alpha version patched with a complete install that include F5 support.

To get the F5rancid script to work you will need to do something similar the following to your .cloginrc

add userprompt bigip* sshOnlyNoPrompt
add autoenable bigip* 1
add user bigip*

Rancid-2.3.2a7.1.tar.gz

wlclogin_exp

Filed under: Cisco, expect, rancid — Tags: , , , , — lancevermilion @ 12:00 am

This is the standard clogin for RANCID but with a few minor changes that will account for the Cisco Wireless controllers difference in prompting.

#! /usr/bin/expect --
##
## $Id: clogin.in,v 1.89 2005/08/14 20:18:19 heas Exp $
##
## 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.
##
#
# The login expect 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 \[-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
# attempt at platform switching.
set platform ""

# 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
}

# 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 {
        # Username
        -u* -
        -U* {
            if {! [  regexp .\[uU\](.+) $arg ignore user]} {
                incr i
                set username [ lindex $argv $i ]
            }
        # VTY Password
        } -p* -
        -P* {
            if {! [  regexp .\[pP\](.+) $arg ignore userpasswd]} {
                incr i
                set userpasswd [ lindex $argv $i ]
            }
            set do_passwd 0
        # VTY Password
        } -v* -
        -v* {
            if {! [  regexp .\[vV\](.+) $arg ignore passwd]} {
                incr i
                set passwd [ lindex $argv $i ]
            }
            set do_passwd 0
        # Enable Username
        } -w* -
        -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* -
        -C* {
            if {! [  regexp .\[cC\](.+) $arg ignore command]} {
                incr i
                set command [ lindex $argv $i ]
            }
            set do_command 1
        # 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
        # 'ssh -c' cypher type
        } -y* -
        -Y* {
            if {! [  regexp .\[eE\](.+) $arg ignore cypher]} {
                incr i
                set cypher [ lindex $argv $i ]
            }
        # alternate cloginrc file
        } -f* -
        -F* {
            if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
                incr i
                set password_file [ lindex $argv $i ]
            }
        # Timeout
        } -t* -
        -T* {
            if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {
                incr i
                set timeout [ 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
        # 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 "33]1;[lindex [split $host "."] 0]\a"
            send_user "33]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 } {
    global 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

    # 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] {
            regexp {ssh(:([^[:space:]]+))*} $prog command 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"] {
            global command

            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  (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 in_proc platform
    set in_proc 1

    # If the prompt is (enable), then we are on a switch and the
    # command is "set length 0"; otherwise its "term length 0".
    # skip if its an extreme (since the pager can not be disabled on a
    # per-vty basis).
    if { [ string compare "extreme" "$platform" ] } {
        if [ regexp -- ".*> .*enable" "$prompt" ] {
            send "set length 0\r"
            # This is ugly, but reduces code duplication, allowing the
            # subsequent expects to handle everything as normal.
            set command "set logging session disable;$command"
        } else {
            if [ regexp -- ".*-nc-.*" "$prompt" ] {
                send "\r"
            } else {
              # Modified for the Cisco 4xxx controller
              if [ regexp -- "\\(Cisco Controller\\) >" "$prompt" ] {
                send "\r"
              } else {
                send "term length 0\r"
              }
            }
        }
        # escape any parens in the prompt, such as "(enable)"
        regsub -all {[)(]} $prompt {\\&} reprompt
        # match cisco config mode prompts too, such as router(config-if)#,
        # but catalyst does not change in this fashion.
        regsub -all {^(.{1,14}).*([#>])$} $reprompt {\1([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?} reprompt
        expect {
            -re $reprompt       {}
            -re "\[\n\r]+"      { exp_continue }
        }
    } else {
        regsub -all "\[)(]" $prompt {\\&} reprompt
    }

    # this is the only way i see to get rid of more prompts in o/p..grrrrr
    log_user 0
    # Is this a multi-command?
    if [ string match "*\;*" "$command" ] {
        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} {
            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 "\[^\r\n]*Press  to cont\[^\r\n]*"   {
                                                  send " "
                                                  # bloody ^[[2K after " "
                                                  expect {
                                                        -re "^\[^\r\n]*\r" {}
                                                        }
                                                  exp_continue
                                                }
                -re "^ *--More--\[^\n\r]*"      {
                                                  send " "
                                                  exp_continue }
                -re "^\[^\n\r]*"    {
                                                  send_user -- "$expect_out(buffer)"
                                                  send " "
                                                  exp_continue }
            }
        }
    } else {
        # 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.
        send "[subst -nocommands $command]\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 "\[^\r\n]*Press  to cont\[^\r\n]*"   {
                                                  send " "
                                                  # bloody ^[[2K after " "
                                                  expect {
                                                        -re "^\[^\r\n]*\r" {}
                                                        }
                                                  exp_continue
                                                }
                -re "^ *--More--\[^\n\r]*"      {
                                                  send " "
                                                  exp_continue }
                -re "^\[^\n\r]*"    {
                                                  send_user -- "$expect_out(buffer)"
                                                  send " "
                                                  exp_continue }
        }
    }
    log_user 1

    # Modified for the Cisco 4xxx controller
    if [ regexp -- "\\(Cisco Controller\\) >" "$prompt" ] {
        send "logout\r\N"
    }

    if { [ string compare "extreme" "$platform" ] } {
        send "exit\r"
    } else {
        send "quit\r"
    }
    expect {
        -re "^\[^\n\r *]*$reprompt"             {
                                                  # the Cisco CE and Jnx ERX
                                                  # return to non-enabled mode
                                                  # on exit in enabled mode.
                                                  send "exit\r"
                                                  exp_continue;
                                                }
        "Do you wish to save your configuration changes" {
                                                  send "n\r"
                                                  exp_continue
                                                }
        -re "\[\n\r]+"                          { exp_continue }
        timeout                                 { 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
foreach router [lrange $argv $i end] {
    set router [string tolower $router]
    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 "(#|>| \\(enable\\))"
    } else {
        set ae [find autoenable $router]
        if { "$ae" == "1" } {
            set autoenable 1
            set enable 0
            set prompt "(#|>| \\(enable\\))"
        } 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]  \\\(enable\\\)"       {
                                  set junk $expect_out(0,string);
                                  regsub -all "\[\]\[]" $junk {\\&} prompt;
                                }
    }

    if { $do_command } {
        if {[run_commands $prompt $command]} {
            continue
        }
    } elseif { $do_script } {
        # If the prompt is (enable), then we are on a switch and the
        # command is "set length 0"; otherwise its "term length 0".
        if [ regexp -- ".*> .*enable" "$prompt" ] {
            send "set length 0\r"
            send "set logging session disable\r"
        } else {
            if [ regexp -- ".*>" "$prompt" ] {
                send "\r"
            } else {
              # Modified for the Cisco 4xxx controller
              if [ regexp -- "\\(Cisco Controller\\) >" "$prompt" ] {
                send "\r"
              } else {
                send "term length 0\r"
              }
            }
        }
        expect -re $prompt      {}
        source $sfile
        close
    } else {
        label $router
        log_user 1
        interact
    }

    # End of for each router
    wait
    sleep 0.3
}
exit 0

January 27, 2008

vlanrangeset_cgi

Filed under: cgi, Cisco, perl — Tags: , , , — lancevermilion @ 11:38 pm
#!/usr/bin/perl
#Author: Lance Vermilion
#Description: Create a list of vlans in a range format "1,3-300,302-999"
#                 to be set to on trunk ports.
################################################


use strict;
use warnings;
use CGI qw(:standard);

sub usage () {
print
  "Content-type: text/html\n\n" .
  "\n\n" .
  "Vlan Range Results\n" .
  "\n" .
  "\n" .
  "

ERROR

\n" . "

\n" . "\n"; print "\nYOU MUST FILL OUT EVERY FIELD\n"; print "\n" . "\n\n"; exit 0; } #### # Question for the user #### my $numbers = param('numbers'); if ( $numbers eq "" ) { &usage; } else { my @nums; #my @lines = split(/\s+/, $numbers) if ($numbers =~ /\s+/); my @lines = split(/\n/, $numbers); #my @lines = split(/,/, @lines) if @lines =~ /,/; foreach my $line (@lines) { if ( $line ne "" ) { chomp $line; split(/\s+/, $line); split(/\n/, $line); split(/,/, $line); push @nums, $line; } } #Sample data #my @num = sort {$a$b} qw( 1 20 21 22 23 24 40 60 100 101 102 140 141 145 ); my @num = sort {$a$b} @nums; my @new = (); my $span = 0; for( my $ii = 0; $ii <= $#num; $ii++ ) { if( defined $num[$ii - 1] && $num[$ii - 1] + 1 == $num[$ii] ) { if( $span == 1 ) { next; } else { $new[$#new] .= '-'; $span = 1; } } elsif( $span == 1 ) { $new[$#new] .= $num[$ii - 1]; push @new, $num[$ii]; $span = 0; } else { push @new, $num[$ii]; } } my @DISPLAY = join(',', @new)."\n"; print "Content-type: text/html\n\n" . "\n\n" . "LAN IP Range Results\n" . "\n" . "\n" . "

LAN IP Range Results

\n" . "

\n" . "\n"; print "@DISPLAY"; print "\n" . "\n\n"; exit 0; }

vlanrangeclear_cgi

Filed under: cgi, Cisco, perl — Tags: , , , — lancevermilion @ 11:29 pm
#!/usr/local/bin/perl -w
#Author: Lance Vermilion
#Description: Create a list of vlans in a range format "1,3-300,302-999"
#                 to be cleared on trunk ports.
################################################

use strict;
use warnings;
use CGI qw(:standard);

sub usage () {
print
  "Content-type: text/html\n\n" .
  "\n\n" .
  "Vlan Range Results\n" .
  "\n" .
  "\n" .
  "

ERROR

\n" . "

\n" . "\n"; print "\nYOU MUST FILL OUT EVERY FIELD\n"; print "\n" . "\n\n"; exit 0; } #### # Question for the user #### my $numbers = param('numbers'); if ( $numbers eq "" ) { &usage; } else { #my($beg, $end) = (shift(@ARGV) =~ /^(-?\d+)-(-?\d+)$/) # or die "Usage:\n$0 \n"; my($beg, $end) = (1, 1000); my @lines = split(/\s+/, $numbers); #my @lines = split(/,/, $numbers); my $def = { map { ($_,1) } @lines }; my @num = (); for my $ii ($beg..$end) { push @num, $ii unless defined $def->{$ii}; } my @new = (); my $span = 0; for( my $ii = 0; $ii <= $#num; $ii++ ) { if( defined $num[$ii - 1] && $num[$ii - 1] + 1 == $num[$ii] ) { if( $span == 1 ) { next; } else { $new[$#new] .= '-'; $span = 1; } } elsif( $span == 1 ) { $new[$#new] .= $num[$ii - 1]; push @new, $num[$ii]; $span = 0; } else { push @new, $num[$ii]; } } if( $span == 1 ) { $new[$#new] .= $num[$#num]; } #print join(',', @new)."\n"; my @DISPLAY = join(',', @new)."\n"; print "Content-type: text/html\n\n" . "\n\n" . "LAN IP Range Results\n" . "\n" . "\n" . "

LAN IP Range Results

\n" . "

\n" . "\n"; print "@DISPLAY"; print "\n" . "\n\n"; exit 0; } __END__

Blog at WordPress.com.