#!/usr/local/bin/perl
#
# acctsum - Summarize SNMP Accounting info from cisco routers
# Author: Carl Rigney;
[email protected]; 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 (<HOSTS>) {
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";
}