#!/usr/bin/perl

use IO::Handle;
use Curses;
require 5.001;

$empty_line = "                                                                               " ;
#
# Nuno Leitao, 17/Aug/1998
# snmpstat, v0.1
#
# This Perl program parses the output of SNMP Sniff, and builds a number of
# statistics about your SNMP traffic.
# This is Alpha Software! Be warned.
#

# First, here's our signal handler for CTRL-C.
sub quit {
	my $sig = @_;
	print "Quitting, got signal: $sig\n";
	close(SNMPSNIFF);
	endwin();
	show_results();
	exit(0);
}

$SIG{INT} = \&quit;
$SIG{QUIT} = \&quit;

# First of all, define where things are.
# The following can be either the binary or snmpsniff.sh.
$snmpsniffbin = "/usr/local/bin/snmpsniff";

# The arguments to this script will be passed on to SNMP Sniff.
open(SNMPSNIFF, "$snmpsniffbin @ARGV|") || die "Couldn't open SNMP Sniff ($snmpsniffbin)\n";
STDOUT->autoflush(1);
$agents_c = 0; $managers_c = 0; $comm_c = 0; $err_packets = 0;

initscr();
noecho();
cbreak();
attrset(A_REVERSE);
addstr(1, 1, "SNMP Sniff running:                                                            ");
attrset(A_NORMAL);
addstr(2, 1, "Started on: ".`date`);
addstr(3, 1, `uname -a`);
attrset(A_REVERSE);
addstr(4, 1, $empty_line);
attrset(A_BOLD);
addstr(8, 1, "GET      GETNEXT      SET      GETBULK      RESPONSE      V1TRAP      V2TRAP");
attrset(A_REVERSE);
addstr(11, 1, $empty_line);
attrset(A_BOLD);
addstr(12, 1, "Packets with errors:");
addstr(14, 1, "tooBig  noSuchName  badValue  readOnly  genError  noAccess  wrongType  wrongLen");
addstr(16, 1, "wrongEncod  wrongValue  noCreation  inconsistentValue resUnavail  commitFail");
addstr(18, 1, "undoFail  authErr  notWritable  inconsistName  unknown");
attrset(A_REVERSE);
addstr(20, 1, $empty_line);
attrset(A_BOLD);
addstr(21, 1, "Agents:       Managers:        Communities:");
attrset(A_NORMAL);

refresh();

while(<SNMPSNIFF>) {
	# Now, let's parse each line, and build several hashes with info.
	/^(.+)(GET|GETNEXT|RESPONSE|SET|GETBULK|INFORM|V2TRAP|REPORT|V1TRAP|Unknown)(.+)$/;
	$header = $1;
	$type = $2;
	$value = $3;
	$header =~ /\((\d|:)+\)\s+((\w|-|\.)+)\((.+)\)->((\w|-|\.)+)(\s+(\(ReqID:\d+\)))?/;
	$from = $2; $comm = $4; $to = $5;
	$communities{$comm}++;
	$comm_c = keys(%communities);
	if($type =~ /GET|GETNEXT|SET|GETBULK/) {
		$managers{$from}++;
		$managers{$type."\@".$from}++;
		$managers_c = keys(%managers)/2;
	} elsif($type =~ /RESPONSE|V1TRAP|V2TRAP/) {
		$agents{$from}++;
		$agents{$type."\@".$from}++;
		$agents_c = keys(%agents)/2;
	}
	if($value =~ /\(Err:(\d+)\):/) {
		$err = $1;
		$err_packets++ if($err != 0);
		$err_packet{$err}++;
		SWITCH: {
			# Yeah, I know, I should place this in a hash...
			# This is ugly!
			if($err == 1) {
				addstr(15, 1, $err_packet{$err});
				last SWITCH;
			}
			if($err == 2) {
				addstr(15, 9, $err_packet{$err});
				last SWITCH;
			}
			if($err == 3) {
				addstr(15, 21, $err_packet{$err});
				last SWITCH;
			}
			if($err == 4) {
				addstr(15, 31, $err_packet{$err});
				last SWITCH;
			}
			if($err == 5) {
				addstr(15, 41, $err_packet{$err});
				last SWITCH;
			}
			if($err == 6) {
				addstr(15, 52, $err_packet{$err});
				last SWITCH;
			}
			if($err == 7) {
				addstr(15, 61, $err_packet{$err});
				last SWITCH;
			}
			if($err == 8) {
				addstr(15, 72, $err_packet{$err});
				last SWITCH;
			}
			if($err == 9) {
				addstr(17, 1, $err_packet{$err});
				last SWITCH;
			}
			if($err == 10) {
				addstr(17, 13, $err_packet{$err});
				last SWITCH;
			}
			if($err == 11) {
				addstr(17, 25, $err_packet{$err});
				last SWITCH;
			}
			if($err == 12) {
				addstr(17, 38, $err_packet{$err});
				last SWITCH;
			}
			if($err == 13) {
				addstr(17, 55, $err_packet{$err});
				last SWITCH;
			}
			if($err == 14) {
				addstr(17, 67, $err_packet{$err});
				last SWITCH;
			}
			if($err == 15) {
				addstr(19, 1, $err_packet{$err});
				last SWITCH;
			}
			if($err == 16) {
				addstr(19, 11, $err_packet{$err});
				last SWITCH;
			}
			if($err == 17) {
				addstr(19, 20, $err_packet{$err});
				last SWITCH;
			}
			if($err == 18) {
				addstr(19, 33, $err_packet{$err});
				last SWITCH;
			}
			if($err == 19) {
				addstr(19, 48, $err_packet{$err});
				last SWITCH;
			}
		}

	}
	$pdutype{$type}++;
	addstr(5, 1, $empty_line);
	attrset(A_BOLD);
	addstr(5, 1, "Last PDU: ");
	attrset(A_NORMAL);
	addstr(5, 11, "$from($comm)->$to $type");
	addstr(9, 1, $pdutype{'GET'});
	addstr(9, 10, $pdutype{'GETNEXT'});
	addstr(9, 23, $pdutype{'SET'});
	addstr(9, 32, $pdutype{'GETBULK'});
	addstr(9, 45, $pdutype{'RESPONSE'});
	addstr(9, 59, $pdutype{'V1TRAP'});
	addstr(9, 71, $pdutype{'V2TRAP'});
	addstr(12, 22, $err_packets);
	addstr(21, 9, $agents_c);
	addstr(21, 26, $managers_c);
	addstr(21, 46, $comm_c);
	refresh();
}
close(SNMPSNIFF);
show_results();
endwin();

sub show_results {
	print "\nResults for snmpsniff run:\n";
	print "------------------------------------------------------------\n";
	foreach $agent (keys(%agents)) {
		if($agent =~ /(GET|GETNEXT|RESPONSE|SET|GETBULK|INFORM|V2TRAP|REPORT|V1TRAP|Unknown)\@(.+)/) {
			print "Agent $2 issued $agents{$agent} $1 PDUs\n";
		} else {
			print "Agent: $agent $agents{$agent} PDUs\n";
		}
	}
	foreach $manager (keys(%managers)) {
		if($manager =~ /(GET|GETNEXT|RESPONSE|SET|GETBULK|INFORM|V2TRAP|REPORT|V1TRAP|Unknown)\@(.+)/) {
			print "Manager $2 issued $managers{$manager} $1 PDUs\n";
		} else {
			print "Manager: $manager $managers{$manager} PDUs\n";
		}
	}
}
