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