Gheek.net

February 15, 2008

F5 commandline cheatsheet

Filed under: bigip, cheatsheets, f5 — Tags: , — lancevermilion @ 2:52 pm

Some of the stuff is relevant to existing VIPs and you would have to change the name to meet your needs.

# F5 – commandline hints

tmctl global_stats.memory_used

tmstat

# F5 – Full power cycle

To accomplish this, either power-cycle the system

or use the /usr/bin/full_box_reboot command

# F5 – 3DNS

x – 3dprint sum # to get information on principle and other 3dns settings

# Boot CDROM on separate intel server to provide Network Install for F5 device

x – option 2 (setup server to provide network installation)

x – use defaults

– be sure to have bigip/3dns on connected to same vlan

x – enable net_reboot (b global net_reboot enable) – May not be supported)

note: on 3dns must reboot and with 10 secs, push “network” pin on front

panel

x – reboot and connect to network boot server

x – login (root/default)

x – run setup

# F5 – BigIP

# Recover install to new server

x – power on

x – hook up console cable

x – login as root (password is default)

x – set date/time

x – set the passwords for root and admin

nx – run hostname and set new hostname

x – run config and setup mgmt NIC to arbitrary address

x – setup direct connection to mgt NIC and laptop (normal eth cable)

x – copy ucs file from backup on loghost1

x – copy hotfix Hotfix-BIG-IP-9.1.1-CR58090.im

x – if ucs file is zipped (has extension “.gz”) on loghost1, unzip it

x – run b config install

nx – run keyswap.sccp (to pass new keys with sccp)

nx root: default

nx admin: (?) need admin password to get into GUI

x – login and run get_dossier -b # reg_key found in /config/RegKey.license

x – go to F5 (http://license.f5.com) site and paste dossier to get new license

x – paste new license information into /config/bigip.license

x – reboot

x – connect with laptop (need to setup new IP on laptop to reflect the

production ip for mgmt device – ifconfig eth0 on bigip to get IP/network).

x – run loaddb -local /config/BigDB.dat.cs

x – im Hotfix-BIG-IP-9.1.1-CR58090.im

x – b db Pva.Acceleration none

x – reboot

x – connect to gui (using admin because radius is unavailable) and see that all is good.

OR

x – manually get old config items

b vlan list | perl -ne ‘chomp $_ unless (/}/); print;’ | while read line; do echo b $line;

b self list | perl -ne ‘chomp $_ unless (/}/); print;’ | while read line; do echo b $line;

b mgmt route list | perl -ne ‘chomp $_ unless (/}/); print;’ | while read line; do echo b $line;

b interface list | perl -ne ‘chomp $_ unless (/}/); print;’ | while read line; do echo b $line;

b route list

b inter

# Get a command version for every command.

b list | perl -ne ‘chomp; s/^}/ }\n/g; print;’

Notes:

x – console is disabled on reboot unless you have a serial cable connected

– you can override this by vi /etc/ttys and change the tty00 line to:

tty00 “/usr/libexec/getty pccons” vt100 on secure

# To verify Certs

/usr/bin/openssl x509 -enddate -noout -in /config/ssl/ssl.crt/.crt

# To get output of a tcpdump on ssl port, use the following

ssldump -i vl_140 -Aedn -N -k /config/ssl/ssl.key/webconnect.abc.com.key -p host x.x.x.x and host x.x.x.x

# To get information on wideip pool members status

3dpipe wideip cvpn.abc.com pool cvpn-pool virtual show

# Email support call to support@f5.com

# tech@f5.com, devcentral@f5.com

# Problems (tcpdumps, remember to quickly)

# tcpdump -ni -c -s 1600 -X -w /var/tmp/.dmp

tcpdump -ni external -c 500 -s 1600 -X -w /var/tmp/external.dmp

tcpdump -ni internal -c 500 -s 1600 -X -w /var/tmp/internal.dmp

tcpdump -ni int-server -c 500 -s 1600 -X -w /var/tmp/int-server.dmp

top -n5 -b >/var/tmp/top.dmp

qkview

# Logfiles

/var/log/bigip.log

/var/log/messages.log

/var/log/bigd.log

# Full box reboot

/usr/bin/full_box_reboot

# Cheat commandline items

bigtop -once

b virtual

b node

b pool

qkview (to gather stats)

b ha table show # show high avail settings

# RamCache

# ram cache setting notes:

# Age Rate 0-10 = (#mins)(2^age_rate) = Effective Age Time (in minutes)

# = (3)(2^2) = 12 minutes (using age rate of 2 after 3

# minutes)

# to list ram cache

b profile http all ramcache dump

b profile http http-canadatest ramcache dump

b profile http http-canadatest ramcache uri asp dump

# to clear ram cache entry

b profile http all ramcache reset

b profile http http-canadatest ramcache reset

b profile http http-canadatest ramcache uri /ca/images/find.gif host canadacert.abc.com reset

**********

HTTP/HTTPS

**********

HTTP – pool

===========

b pool xx-80 { monitor all tcp member xx:http }

HTTP – virtual

==============

b virtual vs_199.41.238.xx-80 { destination 199.41.238.xx:http snat automap ip protocol tcp profile http oneconnect tcp pool xx-80 }

HTTP to HTTPS – virtual

virtual vs_xx-80 { destination xx:http snat automap ip protocol tcp profile http tcp pool pl_dummy-for-irule rule ir-redir_HTTP-to-HTTPS }

HTTPS – profile

=============

b profile clientssl pr-sslcli_xx.abc.com { defaults from clientssl key \”xx.abc.com.key\” cert \”xx.abc.com.crt\” }

HTTPS – virtual

===============

b virtual vs_x.x.x.x-443 { destination x.x.x.x:https snat automap ip protocol tcp profile http oneconnect pr-sslcli_xx.abc.com tcp pool pl_xx.abc.com-80 }

***

FTP

***

FTP – pool

==========

# for external

b pool pl_xx.abc.com-21 { monitor all tcp_half_open member x.x.x.x:ftp }

# for internal

b pool pl_xx.abc.com-21 { member x.x.x.x:ftp }

FTP – virtual

==========

# for external

b virtual vs_x.x.x.x-21 { destination x.x.x.x:ftp ip protocol tcp profile ftp tcp pool pl_xx.abc.com-21 rule ir-snat_abcNets }

# for internal

b virtual vs_x.x.x.x-21 { destination x.x.x.x:ftp snat automap ip protocol tcp profile ftp tcp pool pl_xx.abc.com-21 }

******

RADIUS

******

Monitor Radius (udp)

==============

b monitor udp_1645 { defaults from radius interval 30 timeout 91 debug \”no\” password \”abc123\” secret \”mybIgIp_forradius\” username \”bigip@local\” }

Pool Radius (udp)

===========

b pool pl_radius2-proxy.abc.com-1645 { monitor all udp_1645 member x.x.x.x:datametrics }

b pool pl_radius2-proxy.abc.com-1646 { monitor all udp member x.x.x.x:sa-msg-port }

Virtual Radius (udp)

==============

b virtual vs_x.x.x.x-1645 { destination x.x.x.x:datametrics ip protocol udp pool pl_radius2-proxy.abc.com-1645 }

b virtual vs_x.x.x.x-1646 { destination x.x.x.x:sa-msg-port ip protocol udp pool pl_radius2-proxy.abc.com-1646 }

Pool SMTP (tcp)

===========

b pool pl_abcsameday.abc.com-25 { monitor all tcp member x.x.x.x:25 member x.x.x.x:25 }

Virtual SMTP (tcp)

==============

b virtual vs_x.x.x.x-25 { destination x.x.x.x:25 ip protocol tcp profile tcp pool pl_abcsameday.abc.com-25 }

IRULES

======

Here is the iRule I was trying to implement.

when CLIENT_ACCEPTED {

if {[matchclass [IP::client_addr] equals $::dg_source]} {

forward

} else {

drop

}

}

Here is what I did to troubleshoot it. It basically echo’s the result

the logs. It was very helpful.

— Troubleshoot i-rule, place the log local0. statement below the to output

information to the log.

when CLIENT_ACCEPTED {

log local0. “checking for address [IP::client_addr] in dg_source list”

if {[matchclass [IP::client_addr] equals $::dg_source]} {

log local0. “address [IP::client_addr] is being allowed through”

forward

} else {

log local0. “address [IP::client_addr] not valid, dropping connection”

drop

}

}

# Sample i-rules

#
# Traffic sourced from port 8080 and 8081
# gets a new source address by way of
# Secure NAT (10.0.0.200)
#
rule i-SNAT {
when CLIENT_ACCEPTED {
if {[UDP::client_port] == 8080} {
snat 10.0.0.200
}
if {[UDP::client_port] == 8081} {
snat 10.0.0.200
}
}
}

#
# Good when you need to do trouble shooting
# the arrows are not correct. that still needs
# some work. The arrows will all depend where
# this i-rule is places. Very handy when you need
# to know what i-rule traffic is hitting.
#
rule i-conns {
when CLIENT_ACCEPTED {
log local0. “Test1 – VN: [virtual name] CIP: [IP::client_addr]:[client_port]”
}
when SERVER_CONNECTED {
log local0. “Test1 – VN: [virtual name] CIP: [IP::server_addr]:[server_port] -> [client_addr]:[client_port]”
log local0. “Test2 – VN: [virtual name] CIP: [IP::client_addr]:[client_port] -> [server_addr]:[server_port]”
}
}

#
# Similar to the one above but a Secure NAT is made
# when the F5 receives syslog data from the network.
#
rule i-Syslog_515 {
when CLIENT_ACCEPTED {
if {[UDP::client_port] == 514} {
snat 10.0.1.95
}
when SERVER_CONNECTED {
log local0. “Test1 – VN: [virtual name] CIP: [IP::server_addr]:[server_port] -> [client_addr]:[client_port]”
log local0. “Test2 – VN: [virtual name] CIP: [IP::client_addr]:[client_port] -> [server_addr]:[server_port]”
}
}

# Scripts

#########

# to get virtual and pool information

#

b virtual pool | awk ‘/tas/ {print $3, $6}’ | while read virt pool; do echo ===========; b virtual $virt list; b pool $pool list ; done

f5rancid_pl.txt *copyright free*

Filed under: bigip, f5, perl — lancevermilion @ 1:59 pm

This version does not have any copyright stuff in it. This will be included in the next rancid release “rancid-2.3.2a9” with probably only a few minor changes.

In order for this to work you will need to include something like this in your .cloginrc

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

#!/usr/bin/perl
##
## $Id: f5rancid.in,v 1.8 2007/11/16 02:22:53 heas Exp $
##
## @PACKAGE@ @VERSION@
## 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 F5 BigIPs.
#
#  RANCID - Really Awesome New Cisco confIg Differ
#
# usage: rancid [-dV] [-l] [-f filename | hostname]
#
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;                            # 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))
        && 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 "bigpipe base list"
sub ShowBaseRun {
    my($line) = (0);
    print STDERR "    In ShowBaseRun: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("SHOWBASE","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        ProcessHistory("SHOWBASE","","","$_") && next;
    }
    return(0);
}

# This routine parses "bigpipe db show"
sub ShowDb {
    my($line) = (0);
    print STDERR "    In ShowDb: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("SHOWDB","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        /UCS.LoadTime/ && next;
        /Configsync.LocalConfigTime/ && next;
        /LTM.ConfigTime/ && next;

        if (/^(snmp\..*\.community\..* =) (.+)/i) {
            if ($filter_commstr) {
                ProcessHistory("SHOWDB","","","! $1 \n") && next;
            } else {
                ProcessHistory("SHOWDB","","","! $1 $2\n") && next;
            }
        }

        ProcessHistory("SHOWDB","","","! $_") && next;
    }
    return(0);
}

# This routine parses "cat /config/bigip.license"
sub ShowLicense {
    my($line) = (0);
    print STDERR "    In ShowLicense: $_" if ($debug);

    while () {
        tr/15//d;
        # v9 software license does not have CR at EOF
        s/^#-+($prompt.*)/$1/;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("LICENSE","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        ProcessHistory("LICENSE","","","! $_") && next;
    }
    return(0);
}

# This routine parses "ls --full-time --color=never /config/ssl/ssl.key"
sub ShowSslKey {
    my($line) = (0);
    print STDERR "    In ShowSslKey: $_" if ($debug);

    while () {
        tr/15//d;
        # v9 software license does not have CR at EOF
        s/^#-+($prompt.*)/$1/;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("SSLKEY","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        ProcessHistory("SSLKEY","","","! $_") && next;
    }
    return(0);
}

# This routine parses "ls --full-time --color=never /config/ssl/ssl.crt"
sub ShowSslCrt {
    my($line) = (0);
    print STDERR "    In ShowSslCrt: $_" if ($debug);

    while () {
        tr/15//d;
        # v9 software license does not have CR at EOF
        s/^#-+($prompt.*)/$1/;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("SSLCRT","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        ProcessHistory("SSLCRT","","","! $_") && next;
    }
    return(0);
}

# This routine parses "bigpipe monitor list all"
sub ShowMonitor {
    my($line) = (0);
    print STDERR "    In ShowMonitor: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("MONITOR","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        if (/^(\s+community) (.+)/i) {
            if ($filter_commstr) {
                ProcessHistory("MONITOR","","","$1 \n") && next;
            } else {
                ProcessHistory("MONITOR","","","$1 $2\n") && next;
            }
        }
        if (/^(\s*)password / && $filter_pwds >= 1) {
            ProcessHistory("LINE-PASS","","","$1password \n");
            next;
        }

        ProcessHistory("MONITOR","",""," $_") && next;
    }
    return(0);
}

# This routine parses "bigpipe profile list"
sub ShowProfile {
    my($line) = (0);
    print STDERR "    In ShowProfile: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("PROFILE","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }

        ProcessHistory("PROFILE","",""," $_") && next;
    }
    return(0);
}

# This routine parses "bigpipe route static show"
sub ShowRouteStatic {
    my($line) = (0);
    print STDERR "    In ShowRouteStatic: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("ROUTE","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }

        ProcessHistory("ROUTE","",""," $_") && next;
    }
    return(0);
}


# This routine parses "bigpipe platform"
sub ShowPlatform {
    print STDERR "    In ShowPlatform: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(1) if /^\s*\^\s*$/;
        return(1) if /(Invalid input detected|Type help or )/;
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("COMMENTS","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        /fan speed/i && next;
        /chassis temperature/i && next;
        /degC/ && next;
        s/^\|//;
        /Type: / && ProcessHistory("COMMENTS","keysort","A0",
                                   "!Chassis type: $'");

        ProcessHistory("COMMENTS","keysort","B1","!$_") && next;
    }
    return(0);
}

# This routine parses "bigpipe version show"
sub ShowVersion {
    print STDERR "    In ShowVersion: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/^(\s*|\s*$cmd\s*)$/);
        return(-1) if (/command authorization failed/i);

        if (!$line++) {
            ProcessHistory("COMMENTS","","","!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");
        }
        /^kernel:/i && ($_ = ) &&
            ProcessHistory("COMMENTS","keysort","A3","!Image: Kernel: $_") &&
            next;
        if (/^package:/i) {
            my($line);

            while ($_ = ) {
                tr/15//d;
                last if (/:/);
                last if (/^$prompt/);
                chomp;
                $line .= " $_";
            }
            ProcessHistory("COMMENTS","keysort","A2",
                           "!Image: Package:$line\n");
        }

        if (/:/) {
            ProcessHistory("COMMENTS","keysort","C1","!$_");
        } else {
            ProcessHistory("COMMENTS","keysort","C1","!\t$_");
        }
    }
    return(0);
}

# This routine processes a "bigpipe list"
sub WriteTerm {
    my($lines) = 0;
    print STDERR "    In WriteTerm: $_" if ($debug);

            ProcessHistory("COMMENTS","","","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");

    while () {
        tr/15//d;
        next if (/^\s*$/);
        # end of config - hopefully.  f5 does not have a reliable end-of-config
        # tag.
        if (/^$prompt/) {
            $found_end++;
            last;
        }
        return(-1) if (/command authorization failed/i);
        # the pager can not be disabled per-session on the PIX
        s/^\s*//;
        /Non-Volatile memory is in use/  && return(-1); # NvRAM is locked
        # filter out any RCS/CVS tags to avoid confusing local CVS storage
        s/\$(Revision|Id):/ $1:/;
        $lines++;

        if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) {
            ProcessHistory("ENABLE","","","!$1$2 \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("LINE-PASS","","","!$1password \n");
            next;
        }
        if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
            ProcessHistory("","","","! neighbor $1 password \n");
            next;
        }
        # order logging statements
        /^logging (\d+\.\d+\.\d+\.\d+)/ &&
            ProcessHistory("LOGGING","ipsort","$1","$_") && next;
        # order/prune tacacs/radius server statements
        if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) {
            ProcessHistory("","","","!$1 key \n"); 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 line statements
        /^ip host line(\d+)/ &&
            ProcessHistory("IPHOST","numsort","$1","$_") && next;
        # order ip nat source static statements
        /^ip nat (\S+) source static (\S+)/ &&
            ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;

        # catch anything that wasnt matched above.
        ProcessHistory("","","","$_");
    }

    if ($lines  'ShowVersion'},
        {'bigpipe platform'             => 'ShowPlatform'},
        {'cat /config/bigip.license'    => 'ShowLicense'},
        {'bigpipe monitor list all'     => 'ShowMonitor'},
        {'bigpipe profile list'         => 'ShowProfile'},
        {'bigpipe base list'            => 'ShowBaseRun'},
        {'bigpipe db show'              => 'ShowDb'},
        {'bigpipe route static show'    => 'ShowRouteStatic'},
        {'ls --full-time --color=never /config/ssl/ssl.crt'     => 'ShowSslCrt'},
        {'ls --full-time --color=never /config/ssl/ssl.key'     => 'ShowSslKey'},
        {'bigpipe list'                 => 'WriteTerm'}
);
# Use an array to preserve the order of the commands and a hash for mapping
# commands to the subroutine and track commands that have been completed.
@commands = map(keys(%$_), @commandtable);
%commands = map(%$_, @commandtable);

$cisco_cmds=join(";",@commands);
$cmds_regexp=join("|",@commands);

if (length($host) == 0) {
    if ($file) {
        print(STDERR "Too few arguments: file name required\n");
        exit(1);
    } else {
        print(STDERR "Too few arguments: host name required\n");
        exit(1);
    }
}
open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
select(OUTPUT);
# make OUTPUT unbuffered if debugging
if ($debug) { $| = 1; }

if ($file) {
    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";
    }
}

# determine ACL sorting mode
if ($ENV{"ACLSORT"} =~ /no/i) {
    $aclsort = "";
}
# determine community string filtering mode
if (defined($ENV{"NOCOMMSTR"}) &&
    ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
    $filter_commstr = 1;
} else {
    $filter_commstr = 0;
}
# determine password filtering mode
if ($ENV{"FILTER_PWDS"} =~ /no/i) {
    $filter_pwds = 0;
} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
    $filter_pwds = 2;
} else {
    $filter_pwds = 1;
}

ProcessHistory("","","","!RANCID-CONTENT-TYPE: bigip\n!\n");
ProcessHistory("COMMENTS","keysort","A1","!\n");
ProcessHistory("COMMENTS","keysort","B0","!\n");
ProcessHistory("COMMENTS","keysort","C0","!\n");
TOP: while() {
    tr/15//d;
    if (/^Error:/) {
        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 = };
        delete($commands{$cmd});
        if ($rval == -1) {
            $clean_run = 0;
            last TOP;
        }
    }
    if (/\#\s?exit$/) {
        $clean_run=1;
        last;
    }
}
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\n" if ($debug);
        system("/usr/bin/tail -1 $host.new");
    }
    unlink "$host.new" if (! $debug);
}

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

January 27, 2008

nixlogin_exp

Filed under: bigip, expect, f5, linux, nix, rancid — Tags: , , , , , — lancevermilion @ 11:52 pm

In order to get this to work you will need to add something like this to your .cloginrc

add userprompt linuxsvr* sshOnlyNoPrompt
add autoenable linuxsvr* 1
add user linuxsvr*

#! /usr/bin/expect --
##
## $Id: clogin.in,v 1.79 2004/05/27 21:57:52 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  (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
    puts "past expect enable prompt"
}

# 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 "\r"
	    #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 {
	    #send "term length 0\r"
	    send "\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

    if { [ string compare "extreme" "$platform" ] } {
	send "\rexit\r"
    } else {
	send "\rquit\r"
    }
    expect {
	-re "^\[^\n\r *]*$reprompt"		{
						  # the Cisco CE and Jnx ERX
						  # return to non-enabled mode
						  # on exit in enabled mode.
						  send "\rexit\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 prompt.
    # 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
	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 "(\\$|\\>|\\:)"
	    #set prompt ">"
            puts "prompt: $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 "\r"
	    send "set logging session disable\r"
	} else {
	    #send "term length 0\r"
	    send "\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

f5login_exp

Filed under: bigip, expect, f5, rancid — Tags: , , , — lancevermilion @ 11:50 pm

***THIS IS NO LONGER NEEDED IF YOU USE THIS VERSION OF f5rancid***

To get this script to work with rancid you will need to add something like this to your .cloginrc

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

#! /usr/bin/expect --
##
## $Id: clogin.in,v 1.79 2004/05/27 21:57:52 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  (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 "\r"
            #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 {
            #send "term length 0\r"
            send "\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

    if { [ string compare "extreme" "$platform" ] } {
        send "\rexit\r"
    } else {
        send "\rquit\r"
    }
    expect {
        -re "^\[^\n\r *]*$reprompt"             {
                                                  # the Cisco CE and Jnx ERX
                                                  # return to non-enabled mode
                                                  # on exit in enabled mode.
                                                  send "\rexit\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 prompt.
    # 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
        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 "\r"
            send "set logging session disable\r"
        } else {
            #send "term length 0\r"
            send "\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 26, 2008

nixlogin_pl

Filed under: f5, linux, nix, perl, rancid — Tags: , , , , — lancevermilion @ 7:26 am
#! /usr/bin/perl
##
## $Id: nixrancid.in,v 1.4 2008/01/21 10:43:25 lvermilion Exp $
##
#
# TODO
# * Add to personal rancid distribution.
# * OS Detection (maybe use variable to support user defined OS)
# * Collection of more system critical files
# * Fix netstat to not include Use/Expire fields on BSD
#
# Changelog
#
# v1.4  lvermilion 1-21-08
# Added support so the original F5 script works on Linux/BSD/Unix
# Added support for the command "sudo su root"
# Added BSDConfFile, since these files are BSD specific
# and we don't want them ran unless we are on a BSD system
# Added a variety of linux/BSD commands
# Removed F5 commands at this point until OS detection is completed.
#
# v1.3 lvermilion
# Add banner formatting so it is more clear what command was ran
# Add support for more F5 commands (profile/monitor/regkey/license/etc).
#
# v1.2  mashcraft 9-18-07
# Fixed invalid TERM causing intermitent failures
# Works as non-root user
# Added Platform info and static routes
#
# v1.1  mashcraft 8-2-07
# Debugging problems with HF8.
#
#
## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
## All rights reserved.
##
## Copyright (C) 2007 by Omniture, Inc. Ver 1.1-1.2
## All rights reserved.
##
## Copyright (C) 2008 by Gheek.net Ver 1.3-1.4
## 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.
##
#
# Based on rancid, this script handles F5 BigIP/(Li|U)nix,BSD systems.
# Modifications by Mike Ashcraft and Lance Vermilion.
#
# This script has been tested with Big-IP Version 9.1.2, 9.2.x and 9.3.1
#
# This script uses nixlogin.  You will need to configure the
# host in .cloginrc as follows:
#
# add user hostname		username
# add userprompt hostname	sshOnlyNoPrompt # The default prompt regex matches the last login message and causes problems
# add method hostname		ssh
# add password hostname		password
# add autoenable hostname	1
#
#  RANCID - Really Awesome New Cisco confIg Differ
#
# usage: nixrancid [-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

my(@commandtable, %commands, @commands);# command lists
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 Platform  31-Jan-2007  Mike Ashcraft mashcraft@omniture.com
# This routine parses "cat filename"
sub Platform {
    print STDERR "    In Platform: $_" if ($debug);

    ProcessHistory("COMMENTS","","BO","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");

    while () {
        tr/15//d;
        last if (/^$prompt/);
        next if (/degC/);
        ProcessHistory("","","$cmd","$_");
    }
    $found_end = 1;
    return(0);
}

# sub BSDConfFile  21-Jan-2008  Lance Vermilion lvermilion@gheek.net
# This routine parses "cat filename"
sub BSDConfFile {
    print STDERR "    In BSDConfFile: $_" if ($debug);
        $uname=`uname`;

    ProcessHistory("COMMENTS","","BO","\n!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n") if ( $uname !~ /BSD/i );

    while () {
        last if ( $uname !~ /BSD/i );
        tr/15//d;
        last if (/^$prompt/);
        ProcessHistory("","","$cmd","$_") if ( $uname =~ /BSD/i );
    }
    $found_end = 1;
    return(0);
}

# sub ConfFile  31-Jan-2007  Mike Ashcraft mashcraft@omniture.com
# This routine parses "cat filename"
sub ConfFile {
    print STDERR "    In ConfFile: $_" if ($debug);

    ProcessHistory("COMMENTS","","BO","!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");

    while () {
        tr/15//d;
        last if (/^$prompt/);
        if ( $cmd =~ /netstat/ )
        {
          next if /.*UHLW.*/
        }
        next if ($cmd =~ /config sync show/ && !/^\s+Status/);
        ProcessHistory("","","$cmd","$_");
    }
    $found_end = 1;
    return(0);
}

# sub DirList  31-Jan-2007  Mike Ashcraft mashcraft@omniture.com
# This routine parses directory listings.
#
# Disable color and make sure the date format is consistent
# For example: ll --time-style=long-iso --color=never
#
sub DirList {
    print STDERR "    In ConfFile: $_" if ($debug);

    ProcessHistory("COMMENTS","","BO","!+----------------------------------------------+\n!|\n!| ####  Running $cmd\n!|\n!+----------------------------------------------+\n");

    while () {
        tr/15//d;
        last if (/^$prompt/);
        ProcessHistory("","","$cmd","$_");
    }
    $found_end = 1;
    return(0);
}

# sub NoOutput  18-Sep-2007  Mike Ashcraft mashcraft@omniture.com
# This routine handles commands where you do not want any output
#
#
sub NoOutput {
    print STDERR "    In ConfFile: $_" if ($debug);

    while () {
        tr/15//d;
        last if (/^$prompt/);
    }
    $found_end = 1;
    return(0);
}

# dummy function
sub DoNothing {print STDOUT;}

# Main
@commandtable = (
	{'TERM=xterm'			=> 'NoOutput'},
	{'export TERM'			=> 'NoOutput'},
	{'uname -a'			=> 'Platform'},
	{'netstat -rn'			=> 'ConfFile'},
	{'cat /etc/passwd'		=> 'ConfFile'},
	{'cat /etc/group'		=> 'ConfFile'},
	{'cat /etc/hosts'		=> 'ConfFile'},
	{'cat /etc/resolv.conf'		=> 'ConfFile'},
	{'cat /etc/my.cnf'		=> 'ConfFile'},
	{'cat /etc/drbd.conf'		=> 'ConfFile'},
	{'cat /etc/fstab'		=> 'ConfFile'},
	{'cat /etc/rc.conf'		=> 'ConfFile'},
	{'cat /etc/iscsi/iscsid.conf' 	=> 'ConfFile'},
	{'cat /etc/modprobe.conf'	=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-bond0'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-bond1'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-eth0'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-eth1'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-eth2'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-eth3'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-eth4'		=> 'ConfFile'},
	{'cat /etc/sysconfig/network-scripts/ifcfg-eth5'		=> 'ConfFile'},
	{'alternatives --config java' 	=> 'ConfFile'},
	{'/sbin/chkconfig --list' 	=> 'ConfFile'},
	{'/usr/bin/yum list installed' 	=> 'ConfFile'},
#        {'bigpipe platform'             => 'Platform'},
#        {'bigpipe version'              => 'ConfFile'},
#        {'bigpipe list'                 => 'ConfFile'},
#        {'bigpipe base list'            => 'ConfFile'},
#        {'bigpipe profile list'         => 'ConfFile'},
#        {'bigpipe monitor list'         => 'ConfFile'},
#        {'bigpipe config sync show'             => 'ConfFile'},
#        {'cat /config/RegKey.license'           => 'ConfFile'},
#        {'bigpipe route static show'            => 'ConfFile'},
#        {'ls --full-time --color=never /config/ssl/ssl.crt'     => 'DirList'},
#        {'ls --full-time --color=never /config/ssl/ssl.key'     => 'DirList'},

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

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 nixlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
    print STDOUT "executing nixlogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
    if (defined($ENV{NOPIPE})) {
	system "nixlogin -t $timeo -c \"$cisco_cmds\" $host  $host.raw 2>&1" || die "nixlogin failed for $host: $!\n";
	open(INPUT, "< $host.raw") || die "nixlogin failed for $host: $!\n";
    } else {
	open(INPUT,"nixlogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "nixlogin failed for $host: $!\n";
    }
}

# 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: nix\n!\n");
ProcessHistory("COMMENTS","keysort","B0","!\n");
ProcessHistory("COMMENTS","keysort","D0","!\n");
ProcessHistory("COMMENTS","keysort","F0","!\n");
ProcessHistory("COMMENTS","keysort","G0","!\n");
TOP: while() {
    tr/15//d;
    if (/\s?logout$/) {
	$clean_run=1;
	last;
    }
    if (/^Error:/) {
	print STDOUT ("$host nixlogin error: $_");
	print STDERR ("$host nixlogin 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 = };
	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\n" if ($debug);
	system("/usr/bin/tail -1 $host.new");
    }
    unlink "$host.new" if (! $debug);
}

Create a free website or blog at WordPress.com.