#!/usr/bin/perl -w
#
# check_iferrors.pl - Nagios(r) network traffic monitor plugin
# Copyright (C) 2004 Gerd Mueller / Netways GmbH
# $Id: check_iferrors.pl 622 2004-10-24 11:19:43Z gmueller $
#
# based on check_traffic from Adrian Wieczorek, <ads (at) irc.pila.pl>
#
# Send us bug reports, questions and comments about this plugin.
# Latest version of this software: http://www.nagiosexchange.org
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307

use strict;

use Net::SNMP;
use Getopt::Long;
&Getopt::Long::config('bundling');

use Data::Dumper;

my $host_address;
my $iface_number;
my $iface_descr;
my $opt_h;

my $session;
my $error;
my $port=161;
my $snmp_version = 1;

my @snmpoids;

# SNMP OIDs for Errors
my $snmpIfInErrors    = '1.3.6.1.2.1.2.2.1.14';
my $snmpIfOutErrors   = '1.3.6.1.2.1.2.2.1.20';
my $snmpIfDescr       = '1.3.6.1.2.1.2.2.1.2';
    
    
my $response;

# Path to  tmp files
my $ERRORS_FILE = "/tmp/ERRORS";

my %STATUS_CODE = (  'UNKNOWN'  => '-1','OK'=> '0','WARNING'  => '1','CRITICAL' => '2');
							    

#default values;
my ($in_errors,$out_errors) = 0;
my $warn_usage = 1;
my $crit_usage = 1;
my $COMMUNITY    = "public";

my $status = GetOptions(
	"h"              => \$opt_h,
	"help"           => \$opt_h,
	"C=s"            => \$COMMUNITY,
	"community=s"    => \$COMMUNITY,
	"w=s"            => \$warn_usage,
	"warning=s"      => \$warn_usage,
	"c=s"            => \$crit_usage,
	"critical=s"     => \$crit_usage,
	"p=i"            => \$port,
	"port=i"         => \$port,
	"i=s", 		     => \$iface_descr,
	"interface=s",   => \$iface_descr,
	"H=s"            => \$host_address,
	"hostname=s"     => \$host_address
);

if ( $status == 0 ) {
	print_help();
	exit $STATUS_CODE{'OK'};
}

if((!$host_address) or (!$iface_descr)) 
{ 
 print_usage();
}

if ( $snmp_version =~ /[12]/ ) {
	( $session, $error ) = Net::SNMP->session(-hostname  => $host_address,-community => $COMMUNITY,-port=> $port,-version  => $snmp_version);

	if ( !defined($session) ) {
		print("UNKNOWN: $error");
		exit $STATUS_CODE{'UNKNOWN'};
	}
}
elsif ( $snmp_version =~ /3/ ) {
	my $state = 'UNKNOWN';
	print("$state: No support for SNMP v3 yet\n");
	exit $STATUS_CODE{$state};
}
else {
	my $state = 'UNKNOWN';
	print("$state: No support for SNMP v$snmp_version yet\n");
	exit $STATUS_CODE{$state};
}

$iface_number=fetch_ifdescr($session,$iface_descr);

push( @snmpoids, $snmpIfInErrors.".".$iface_number);
push( @snmpoids, $snmpIfOutErrors.".".$iface_number);


if ( !defined( $response = $session->get_request(@snmpoids) ) ) {
	my $answer = $session->error;
	$session->close;

	print("WARNING: SNMP error: $answer\n");
	exit $STATUS_CODE{'WARNING'};
}

$in_errors  = $response->{$snmpIfInErrors.".".$iface_number};
$out_errors = $response->{$snmpIfOutErrors.".".$iface_number};

$session->close;

my $row;
my @last_values;
my $last_check_time=time-1;
my $last_in_errors=$in_errors;
my $last_out_errors=$out_errors;

if(open(FILE,"<".$ERRORS_FILE."_if".$iface_number."_".$host_address)) {
	while($row = <FILE>)
	{
 		@last_values = split(":",$row);
 		$last_check_time = $last_values[0];
 		$last_in_errors = $last_values[1];
 		$last_out_errors = $last_values[2];
	}
	close(FILE);
}

my $update_time = time;

open(FILE,">".$ERRORS_FILE."_if".$iface_number."_".$host_address) or die "Can't open $ERRORS_FILE for writing: $!";
print FILE "$update_time:$in_errors:$out_errors";
close(FILE);

my $db_file;

my $exit_status="OK";

# counters cleared? 
$last_in_errors=$in_errors if($last_in_errors>$in_errors);
$last_out_errors=$out_errors if($last_out_errors>$in_errors);

my $in_avg_errors = sprintf("%.2f",($in_errors-$last_in_errors)/(time-$last_check_time));
my $out_avg_errors = sprintf("%.2f",($out_errors-$last_out_errors)/(time-$last_check_time));

print "Total in Errors: $in_errors, Total out Errors: $out_errors<br>";
print "Average in Errors: $in_avg_errors, Average out Errors:  $out_avg_errors ";

if(($in_avg_errors > $crit_usage) or ($out_avg_errors > $crit_usage))
{
 $exit_status="CRITICAL";
}

if((($in_avg_errors > $warn_usage) or ($out_avg_errors > $warn_usage)) && $exit_status eq "OK")
{
 $exit_status="WARNING";
}

print "<br>$status amount of Errors! \n" if($exit_status ne "OK");

print "| inErrors=$in_avg_errors,$warn_usage,$crit_usage outErrors=$out_avg_errors,$warn_usage,$crit_usage\n";


exit($STATUS_CODE{$exit_status});


sub fetch_ifdescr {
    my $state;
 	my $response;

    my $snmpkey;
 	my $answer;
	my $key;

    my ($session,$ifdescr) = @_;
	
	if ( !defined( $response = $session->get_table($snmpIfDescr) ) ) {
		$answer = $session->error;
		$session->close;
		$state = 'CRITICAL';
		$session->close;
		exit $STATUS_CODE{$state};
	}

	foreach $key ( keys %{$response} ) {
		if ( $response->{$key} =~ /^$ifdescr$/ ) {
			$key =~ /.*\.(\d+)$/;
			$snmpkey = $1;

			# print "$ifdescr = $key / $snmpkey \n";  #debug
		}
	}
	unless ( defined $snmpkey ) {
		$session->close;
		$state = 'CRITICAL';
		printf "$state: Could not match $ifdescr \n";
		exit $STATUS_CODE{$state};
	}
	return $snmpkey;
}

sub print_usage
{
 print "Usage: check_iferrors.pl -H host -i if_descr -b if_max_speed [ -w warn ] [ -c crit ]\n\n";
 print "Options:\n";
 print " -H --host STRING or IPADDRESS\n";
 print "   Check interface on the indicated host.\n";
 print " -C --community STRING \n";
 print "   SNMP Community.\n";
 print " -i --interface STRING\n";
 print "   Interface Name.\n";
 print " -w --warning INTEGER\n";
 print "   number of necessary errors to result in warning status (default: 1%)\n";
 print " -c --critical INTEGER\n";
 print "   number of necessary errors to result in critical status (default: 1%)\n";
 
 exit($STATUS_CODE{"UNKNOWN"});
}

