#!/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";
}