#!/usr/bin/perl -w
use strict;
use Net::SNMP qw(:snmp);
use RRDs;

use Getopt::Long;

use vars qw($opt_V $opt_h $opt_H $opt_C $opt_i $opt_s $opt_w $opt_c $verbose);
use vars qw($PROGNAME);
use lib "/usr/lib/nagios/plugins" ;
use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);

#Program name
$PROGNAME = "check_traffic";
my $dbpath = "/var/www/html/cacti/rra";

#See if dirs exist, if not, make them
if (!(-e $dbpath)) { mkdir $dbpath || die "Couldn't create $dbpath!\n";}



sub print_help ();
sub print_usage ();

#Path security
$ENV{'PATH'}='';
$ENV{'BASH_ENV'}=''; 
$ENV{'ENV'}='';

#Read in options
Getopt::Long::Configure('bundling');
GetOptions
	("V"   => \$opt_V, "version"    => \$opt_V,
	 "h"   => \$opt_h, "help"       => \$opt_h,
	 "w=s" => \$opt_w, "warning=s"  => \$opt_w,
	 "c=s" => \$opt_c, "critical=s"  => \$opt_c,
	 "H=s" => \$opt_H, "hostname=s" => \$opt_H,
	 "C=s" => \$opt_C, "community=s" => \$opt_C,
	 "i=s" => \$opt_i, "interface=s" => \$opt_i,
	 "s=s" => \$opt_s, "snmpver=s" => \$opt_s);

#Print version
if ($opt_V) {
	print_revision($PROGNAME,'$Revision: 1.2 $');
	exit $ERRORS{'OK'};
}

#Print Help
if ($opt_h) {print_help(); exit $ERRORS{'OK'};}

#Read in Getopts
($opt_H) || usage("Host name/address not specified\n");
my $host = $1 if ($opt_H =~ /([-.A-Za-z0-9]+)/);
($host) || usage("Invalid host: $opt_H\n");

($opt_C) || usage("RO Community string not specified\n");
my $community = $opt_C;

($opt_i) || usage("Interface not specified.\n");
my @interfaces = split(/,/,$opt_i);

($opt_s) || ($opt_s = 1);
my $snmpver = $1 if ($opt_s =~ /^(1|2)$/);
($snmpver) || usage("Invalid SNMP Version: $opt_s\n");

($opt_w) || ($opt_w = shift) || ($opt_w = 85);
my $warn = $1 if ($opt_w =~ /^([0-9]{1,2}\%?|100\%?)$/);
($warn) || usage("Invalid warning threshold: $opt_w\n");

($opt_c) || ($opt_c = shift) || ($opt_c = 95);
my $crit = $1 if ($opt_c =~ /^([0-9]{1,2}\%?|100\%?)$/);
($crit) || usage("Invalid critical threshold: $opt_c\n");

#Strip percent sign from warn and crit
$crit =~ s/%//g;
$warn =~ s/%//g;
unless ( $warn < $crit) {
	usage("Percentage: warning ($warn) should be less than critical ($crit) \n");
}

#Set default state and answer
my $state = "OK";
my $answer = undef;

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub { 
	print "No Answer from Client\n";
	exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);

# Usage and Help subroutines
sub print_usage () {
	print "Usage: $PROGNAME -H <host> -C <community> -w <warn> -c <crit>\n";
}

sub print_help () {
	print_revision($PROGNAME,'$Revision: 1.2 $');
	print "Copyright (c) 2003 Justin Ellison

Description of plugin goes here

";
	print_usage();
	print "
-H, --hostname=HOST
   Name or IP address of host to check
-c
   SNMP RO Community String

";
	support();
}


#Main body
my $ifInOctetsOID = "1.3.6.1.2.1.2.2.1.10.";
my $ifOutOctetsOID = "1.3.6.1.2.1.2.2.1.16.";
my $ifSpeedOID = "1.3.6.1.2.1.2.2.1.5.";
my $ifDescrOID = "1.3.6.1.2.1.2.2.1.2.";
my @OIDlist;
foreach my $iface (@interfaces) { 
   push(@OIDlist,$ifInOctetsOID.$iface);
   push(@OIDlist,$ifOutOctetsOID.$iface);
   push(@OIDlist,$ifSpeedOID.$iface);
   push(@OIDlist,$ifDescrOID.$iface);
}
my ($session,$error) = Net::SNMP->session(
			-hostname	=> $host,
			-version	=> $snmpver,
			-community	=> $community,
			);
if (!defined($session)) {
	$state = "UNKNOWN";
        $answer = "UNKNOWN: Couldn't initiate SNMP session!";
	exit $ERRORS{$state};
	}

my $result = $session->get_request(-varbindlist => \@OIDlist,);
if (!defined($result)) {
   $state = "UNKNOWN";
   $answer = "UNKNOWN: $session->error";
   exit $ERRORS{$state};
}
#Done with Network, end the alarm
alarm(0);

my %states;
foreach my $iface (@interfaces) {
   #Create the RRD if necessary, update it with current values
   my $description = $result->{$ifDescrOID.$iface};
   $description =~ s/[\/,\s,\s+]/-/g;
   my $dbfile = $dbpath."/".$host."_".$description.".rrd";
   if (!(-e $dbfile)) { #create new rrd
      # Setup rrd
      RRDs::create ("$dbfile", "DS:traffic_in:COUNTER:600:U:U","DS:traffic_out:COUNTER:600:U:U","RRA:AVERAGE:0.5:1:600","RRA:AVERAGE:0.5:6:700","RRA:AVERAGE:0.5:24:775","RRA:AVERAGE:0.5:288:797","RRA:MAX:0.5:1:600","RRA:MAX:0.5:6:700","RRA:MAX:0.5:24:775","RRA:MAX:0.5:288:797") || die "Couldn't create RRD->$dbfile\n";
      } 
   # Now update the rrd  
   my $update_time = time;
   RRDs::update ("$dbfile","$update_time:$result->{($ifInOctetsOID).($iface)}:$result->{($ifOutOctetsOID).($iface)}");

   #Figure traffic values for last polling time
   my ($start,$end) = (time-86400,time-300);
   my ($averages,$xsize,$ysize) = RRDs::graph ("$dbfile.png",  "--start=$start", "--end=$end", "DEF:bytesin=$dbfile:traffic_in:AVERAGE", "DEF:bytesout=$dbfile:traffic_out:AVERAGE", "CDEF:bitsin=bytesin,8,*", "CDEF:bitsout=bytesout,8,*", 'PRINT:bitsin:LAST:%8.2lf', 'PRINT:bitsout:LAST:%8.2lf');
   my ($in,$out) = @$averages;
   # Figure usage %
   my $percentage = undef;
   if ($in > $out) { $percentage = ($in/$result->{$ifSpeedOID.$iface})*100;}
      else { $percentage = ($out/$result->{$ifSpeedOID.$iface})*100; }
   $percentage = (int ($percentage *10))/10;
   #Find a way to track per-interface states
   if ($percentage > $warn) { 
      if ($percentage < $crit) {$states{$iface} = "WARNING"; } else {$states{$iface}="CRITICAL"}
   } else {$states{$iface}="OK"; }
   $answer .= "$states{$iface}:  $result->{$ifDescrOID.$iface}($result->{$ifSpeedOID.$iface} bps) => In: $in - Out: $out - $percentage%\n"; 
} #end foreach
# Set appropriate state
foreach my $val (values %states) {
   if (($state eq "OK") && ($val ne "OK")) { $state = $val; }
}
#End main, print result
print "$answer";
exit $ERRORS{$state};
