#!/usr/bin/perl
#
# check_snmp_if
#
# checks an interfaces operstatus and returns
# critical if ifoperstatus is not up and ifadminstatus is up
#

## libraries
use strict;

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

## variable declairations
my $progname = "check_snmp_if";
my $version = "0.3.5";

my %ERRORS = (
			"OK" => "0",
			"WARNING" => "1",
			"CRITICAL" => "2",
			"UNKNOWN" => 3,
);

my $hostname;
my $hostip;
my $TIMEOUT = 30;

my %ifAdminStatus = (
	1 => "up",
	2 => "down",
	3 => "testing",
);
my %ifOperStatus = (
	1 => "up",
	2 => "down",
	3 => "testing",
	4 => "unknown",
	5 => "dormant",
	6 => "notPresent",
	7 => "lowerLayerDown",
);

# default return value is UNKNOWN
my $state = "UNKNOWN";
my $answer;
my $needhelp = "";

# snmp variables
my $snmpcommunity = "public";
my $snmpport = "161";
my %snmpoid = (
	ifAdminStatus => ".1.3.6.1.2.1.2.2.1.7",
	ifOperStatus => ".1.3.6.1.2.1.2.2.1.8",
	ifName => ".1.3.6.1.2.1.31.1.1.1.1",
	ifDescr => ".1.3.6.1.2.1.2.2.1.2",
	ifAlias => ".1.3.6.1.2.1.31.1.1.1.18",
	portName => ".1.3.6.1.4.1.9.5.1.4.1.1.4",
);
my $snmpifindex;
my $snmpifname;
my $snmpifdescr;
my $snmpifalias;
my $snmpcatalyst;
my %snmpifstatus = (
	ifAdminStatus => 2,
	ifOperStatus => 2,
);


# Just in case of problems, let's not hang NetSaint
$SIG{'ALRM'} = sub {
     print ("ERROR: No snmp response from $hostname (alarm)\n");
     exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);


## process command line options

if (scalar(@ARGV) == 0) {
	usage();
}

Getopt::Long::Configure("no_ignore_case");
my $getoptret = GetOptions(
						"H|hostname=s"		=> \$hostname,
						"i|ifindex=s"		=> \$snmpifindex,
						"n|ifname=s"		=> \$snmpifname,
						"d|ifdescr=s"		=> \$snmpifdescr,
						"a|ifalias=s"		=> \$snmpifalias,
						"catalyst=s"		=> \$snmpcatalyst,
						"C|community=s"		=> \$snmpcommunity,
						"p|port=i"			=> \$snmpport,
						"h|help"			=> \$needhelp
						);


if ($getoptret == 0 || $needhelp) {
	usage();
} # end if no options or wants help
if (!defined($hostname)) {
	print "Hostname not specified\n\n";
	usage();
} # end if no hostname
if (!defined($snmpifindex) && !defined($snmpifname) &&
	!defined($snmpifdescr) && !defined($snmpifalias) &&
	!defined($snmpcatalyst)) {
	print "Must specify key\n\n";
	usage();
} # end if no key
 

## get the ifindex if we need to
if (!defined($snmpifindex)) {
	if (defined($snmpifname)) {
		$snmpifindex = FindIfIndexByName($snmpifname);
	} elsif (defined($snmpifdescr)) {
		$snmpifindex = FindIfIndexByDescr($snmpifdescr);
	} elsif (defined($snmpifalias)) {
		$snmpifindex = FindIfIndexByAlias($snmpifalias);
	} elsif (defined($snmpcatalyst)) {
		$snmpifindex = FindIfIndexByName($snmpcatalyst);
	} # find the ifindex by specified method
} # end if no ifIndex, find it

if (!defined($snmpifindex)) {
	$answer = "no key found";
	print "$state: $answer\n";
	exit($ERRORS{$state});
} # end if no key, die

$snmpifstatus{ifAdminStatus} = GetAdminStatus($snmpifindex);
$snmpifstatus{ifOperStatus} = GetOperStatus($snmpifindex);


if ($ifAdminStatus{$snmpifstatus{ifAdminStatus}} eq "down") {
	$state = "OK";
} elsif ($ifAdminStatus{$snmpifstatus{ifAdminStatus}} eq "testing") {
	$state = "WARNING";
} elsif ($ifAdminStatus{$snmpifstatus{ifAdminStatus}} eq "up" &&
	$ifOperStatus{$snmpifstatus{ifOperStatus}} ne "up") {
	$state = "CRITICAL";
} elsif ($ifAdminStatus{$snmpifstatus{ifAdminStatus}} eq "up" &&
	$ifOperStatus{$snmpifstatus{ifOperStatus}} eq "up") {
	$state = "OK";
} # end if ok, warning, and critical

$answer  = "Admn:".$ifAdminStatus{$snmpifstatus{ifAdminStatus}}."; ";
$answer .= "Oper:".$ifOperStatus{$snmpifstatus{ifOperStatus}}."; ";
if (!defined($snmpcatalyst)) {
	$answer .= "(".GetIfAlias($snmpifindex).")";
} else {
	$answer .= "(".GetPortName($snmpcatalyst).")";
} # end if catalyst or not
print "$state: $answer\n";
exit($ERRORS{$state});



## subroutines

sub usage
{
	print <<END;
== $progname $version ==
usage:
  $progname (-H|--hostname) <hostname> [-C|--community] <snmpcommunity>
    [-p|--port] <port> [-i|--ifindex] <ifIndex> [-n|--ifname] <ifName> 
    [-d|--ifdescr] <ifDescr> [-a|--ifAlias] <ifAlias> [--catalyst] <ifName>
    [-h|--help]

END

	exit($ERRORS{$state});
} # end usage;


sub FindIfIndexByName
{
	my $snmpvalue = shift(@_);
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;
	my $returnval;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$state = "UNKNOWN";
		$answer = $snmp_error;
		print "$state: $answer\n";
		exit $ERRORS{$state};
	}

	if (!defined($snmp_response = $snmp_session->get_table($snmpoid{ifName}))) {
		$answer = $snmp_session->error;
		$snmp_session->close;
		$state = "WARNING";
		print "$state: $answer,$snmpcommunity,$snmpoid{ifName}\n";
		exit $ERRORS{$state};
	}

	foreach my $snmpkey (keys( %{$snmp_response})) {
		if ($snmp_response->{$snmpkey} =~ /$snmpvalue/i) {
			$snmpkey =~ /\.(\d+)$/;
			$returnval = $1;
		} # end if the snmp return value has the value wanted, return the index
	}
	$snmp_session->close;

	return $returnval;

} # end FindIfIndexByName;


sub FindIfIndexByDescr
{
	my $snmpvalue = shift(@_);
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;
	my $returnval;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$state = "UNKNOWN";
		$answer = $snmp_error;
		print "$state: $answer\n";
		exit $ERRORS{$state};
	}

	if (!defined($snmp_response = $snmp_session->get_table($snmpoid{ifDescr}))) {
		$answer = $snmp_session->error;
		$snmp_session->close;
		$state = "WARNING";
		print "$state: $answer,$snmpcommunity,$snmpoid{ifDescr}\n";
		exit $ERRORS{$state};
	}

	foreach my $snmpkey (keys( %{$snmp_response})) {
		if ($snmp_response->{$snmpkey} =~ /$snmpvalue/i) {
			$snmpkey =~ /\.(\d+)$/;
			$returnval = $1;
		} # end if the snmp return value has the value wanted, return the index
	}
	$snmp_session->close;

	return $returnval;

} # end FindIfIndexByDescr;


sub FindIfIndexByAlias
{
	my $snmpvalue = shift(@_);
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;
	my $returnval;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$state = "UNKNOWN";
		$answer = $snmp_error;
		print "$state: $answer\n";
		exit $ERRORS{$state};
	}

	if (!defined($snmp_response = $snmp_session->get_table($snmpoid{ifAlias}))) {
		$answer = $snmp_session->error;
		$snmp_session->close;
		$state = "WARNING";
		print "$state: $answer,$snmpcommunity,$snmpoid{ifAlias}\n";
		exit $ERRORS{$state};
	}

	foreach my $snmpkey (keys( %{$snmp_response})) {
		if ($snmp_response->{$snmpkey} =~ /$snmpvalue/i) {
			$snmpkey =~ /\.(\d+)$/;
			$returnval = $1;
		} # end if the snmp return value has the value wanted, return the index
	}
	$snmp_session->close;

	return $returnval;

} # end FindIfIndexByAlias;


sub GetAdminStatus
{
	my $snmpvalue = shift(@_);
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$state = "UNKNOWN";
		$answer = $snmp_error;
		print "$state: $answer\n";
		exit $ERRORS{$state};
	}

	if (!defined($snmp_response = $snmp_session->get_request("$snmpoid{ifAdminStatus}.$snmpvalue"))) {
		$answer = $snmp_session->error;
		$snmp_session->close;
		$state = "WARNING";
		print "$state: $answer,$snmpcommunity,$snmpoid{ifAdminStatus}.$snmpvalue\n";
		exit $ERRORS{$state};
	}
	$snmp_session->close;

	return $snmp_response->{"$snmpoid{ifAdminStatus}.$snmpvalue"}

} # end GetAdminStatus;


sub GetOperStatus
{
	my $snmpvalue = shift(@_);
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$state = "UNKNOWN";
		$answer = $snmp_error;
		print "$state: $answer\n";
		exit $ERRORS{$state};
	}

	if (!defined($snmp_response = $snmp_session->get_request("$snmpoid{ifOperStatus}.$snmpvalue"))) {
		$answer = $snmp_session->error;
		$snmp_session->close;
		$state = "WARNING";
		print "$state: $answer,$snmpcommunity,$snmpoid{ifOperStatus}.$snmpvalue\n";
		exit $ERRORS{$state};
	}
	$snmp_session->close;

	return $snmp_response->{"$snmpoid{ifOperStatus}.$snmpvalue"}

} # end GetOperStatus;


sub GetIfAlias
{
	my $snmpvalue = shift(@_);
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$snmp_session->close;
		return;
	}

	if (!defined($snmp_response = $snmp_session->get_request("$snmpoid{ifAlias}.$snmpvalue"))) {
		$snmp_session->close;
		return;
	}
	$snmp_session->close;

	return $snmp_response->{"$snmpoid{ifAlias}.$snmpvalue"}

} # end GetIfAlias;


sub GetPortName
{
	my $snmpvalue = shift(@_);
	$snmpvalue =~ s/\//./g;
	my $snmp_session;
	my $snmp_error;
	my $snmp_response;

	## get the list of active users via snmp
	($snmp_session, $snmp_error) = Net::SNMP->session(
		-hostname  => $hostname,
		-community => $snmpcommunity,
		-port      => $snmpport
	);

	if (!defined($snmp_session)) {
		$snmp_session->close;
		return;
	}

	if (!defined($snmp_response = $snmp_session->get_request("$snmpoid{portName}.$snmpvalue"))) {
		$snmp_session->close;
		return;
	}
	$snmp_session->close;

	return $snmp_response->{"$snmpoid{portName}.$snmpvalue"}

} # end GetPortName;

