#!/usr/local/bin/perl # # acctsum - Summarize SNMP Accounting info from cisco routers # Author: Carl Rigney; cdr@bach.amd.com; 90/7/23 # # Modification History # 1.0 90/10/16 cdr initial release # Boilerplate: # Copyright 1990 Carl Rigney. You may redistribute freely in any form. # # If you make any interesting improvements to this script I'd enjoy hearing # about them. # Synopsis: # This script runs CMU snmpwalk to retrieve lipAccountEntry from cisco # routers to show packet & byte counts for each pair of machines that # have communicated through the router using IP since last reboot. # It produces a tab-separated table of # source destination #packets #bytes # # If a hosts table is present it will place an asterisk by addresses it # doesn't find in the hosts table. You can use YP instead with -y. $logfile="/usr/tmp/snmp$$"; $unknown="*"; # character to flag unknown hosts with $mibvar = ".iso.org.dod.internet.private.enterprises.cisco.local.lip.lipAccoun tingTable.lipAccountEntry"; $prefix = "Name: ".$mibvar."."; # what CMU SNMP Tools output ### Parse Command-line options $log=0; # flag to log snmp output to $logfile $name=1; # flag to use names of known hosts $nis=0; # flag to use Network Information Services (YP ) while ($ARGV[0] =~ m/^-(.)/) { $log++ if $1 eq "l"; # -l log to $logfile $name=0 if $1 eq "n"; # -n use IP addresses for known hosts too $nis++ if $1 eq "y"; # -y use NIS (YP) to find known IP addresse s shift @ARGV; } if ($nis) { $hostfile="ypcat hosts|"; # to use YP } else { $hostfile="/etc/hosts"; # to use hostsfile } ### Retrieve Valid Hostnames # we don't use a Domain nameserver so someone else will have to adapt # this to use in-addr.arpa lookups if they want to use those. # slurp in hosts file to find valid IP addresses # run this only on hosts with YP or up-to-date hosts files, as chosen above open(HOSTS,$hostfile) || die "$0: couldn't read $hostfile;$!\n"; while () { chop; s/#.*//; # strip comments if (m/^([0-9.]+)\s+(\S+)/) { $ip{$1}=$2; # keep track of IP address } } close(HOSTS) || warn "$0: error in $hostfile;$!\n"; ### Read data from stdin or via snmpwalk # if no arguments were given, read from standard input # else do an snmpwalk on the named router # # Note, it would be faster to walk on just actByts and actPkts # instead of the whole lipAccountEntry, but it makes the code more # complex - to be corrected in a future release if ($#ARGV == 1 ) { close(STDIN) || die "$0: unable to redirect standard input;$!\n"; $snmpwalk = "snmpwalk $ARGV[0] $ARGV[1] $mibvar"; open(STDIN,"$snmpwalk |") || die "$0: unable to spawn snmpwalk; $!\n"; shift(@ARGV); shift(@ARGV); } elsif ($#ARGV >= 0 ) { warn "@ARGV\n"; die "usage: $0 [router community]\n"; } if ($log) { open(TMP,">$logfile") || die "$0: unable to open logfile; $!\n"; } ### now read through data & print table, marking unknown addresses while (<>) { print TMP $_ if $log; next if (! s/^$prefix//o); chop; $name = $_; $_ = <>; # fetch value print TMP $_ if $log; chop; if (m/(\S+):\s+/) { $type = $1; $value = $'; } # we already know source & destination, so skip those # if we were paranoid we could make sure they matched next if $name =~ /^act(Src|Dst)\./; if ($name =~ m/(\D+)\.(\d+\.\d+\.\d+.\d+)\.(\d+\.\d+\.\d+.\d+)/) { $marker= ($ip{$2}?" ":$unknown); $src=$marker.(($name&&$ip{$2})?$ip{$2}:$2); $marker= ($ip{$3}?" ":$unknown); $dst=$marker.(($name&&$ip{$3})?$ip{$3}:$3); $packets{"$src\t$dst"} = $value if $1 eq "actPkts"; $bytes{"$src\t$dst"} = $value if $1 eq "actByts"; next; } # ignore anything else } ### print results - currently sorts alphabetically for $pair (sort(keys(%packets))) { ($src,$dst) = split(/\t/,$pair); printf "%-15s\t%-15s\t%10u\t%10u\n", $src,$dst,$packets{$pair},$bytes{ $pair}; $tpackets += $packets{$pair}; $tbytes += $bytes{$pair}; $tpair ++; } printf "%24s\t%10u\t%10u\n", "TOTAL for $tpair host-pairs",$tpackets,$tbytes; if ($log) { close(TMP) || die "$0: unable to close log file $logfile ;$!\n"; warn "$0: snmp log written to $logfile\n"; }