#!/usr/bin/perl

#FILE: check_snmp_string.pl
#SYNOPSIS: check that SNMP-'sysName' matches DNS A record for this host, alternately that it matches a specified string.
# GUILTY_PARTY: Eli Stair
# LICENSE: GPL, Copyright 2006 Eli Stair <eli.stair {at} gmail {dot} com>

use Getopt::Long;
use Pod::Usage;
use Time::HiRes qw{usleep ualarm gettimeofday tv_interval};
use Net::SNMP qw{GET_REQUEST};


GetOptions(
  "help"	=> \$help,
  "H|host=s"	=> \$host,
  "m|match=s"	=> \$match,
  "c|cstring=s"	=> \$cstring,
  "o|oid=s"	=> \$oid,
  "t|timeout=i"	=> \$timeout,
);

######################################################################################
### START code:

# set timeout and alarm for execution time allowed.
unless ($timeout) {$timeout=15};
alarm($timeout);
$SIG{ALRM} = sub {print "$0 timed out.\n"; exit 2;};

# set match parameter to host if it's not defined:
unless ($match) {$match=$host};

# define program flow:
&processargs;
&exit_eval(&query_oid(&snmp_oid));

######################################################################################
### START functions:

### FUNC: query_oid
sub snmp_oid {
# some OID shortcuts allowed:
if ($oid eq 'sysName') {$oid = '.1.3.6.1.2.1.1.5.0'};
return $oid;
}

### FUNC: query_oid
sub query_oid {
$oid = shift;
($session, $error) = Net::SNMP->session(
  -hostname  => "$host",
  -community => "$cstring",
  -port      => 161,
  -timeout   => 5
);

my $session_snmp = $session->get_request(
  Varbindlist => [$oid]
);

if (!defined($session_snmp)) {
  $session_error = $session->error;
  return $session_error;
} else {
  $host_string = $session_snmp->{$oid};
  return $host_string;
} #/if

} #/sub query_oid


######################################################################################
### FUNC: processargs
sub processargs {

if ($man or $help) { 
  pod2usage(-verbose => 2,-noperldoc => 1,-exitval => 3);
  pod2usage(1);
  exit 1;
}
unless (defined ($host && $cstring)) {
  pod2usage("$0: Not enough arguments.\n");
}

} #/func processargs

######################################################################################
### FUNCTION: exit_eval
sub exit_eval {

# Immediately exit on query failures:
if (defined ($session_error)) {
  print "SYSNAME CRITICAL! QUERYRETURNCODE=($session_error) HOST=($host) \n";
  exit 2
} else { #query returned, compare strings:
  if ("$host_string" eq "$match") { # OIDstring matches, we're good:
    print "SYSNAME OK! QUERYRETURN=(OIDstring=>\"$host_string\" == HOST=>\"$match\") \n";
    exit 0;
  } else { # OIDstring dosn't match:
    print "SYSNAME CRITICAL! QUERYRETURN=(OIDstring=>\"$host_string\" != HOST=>\"$match\") \n";
    exit 2;
  } #/if hostname matches
} #/if error

} #/func exit_eval


=head1 NAME

check_snmp_string.pl - Check that SNMP-'OIDstring' matches DNS A record for this host, alternately that it matches a specified string.

=head1 SYNOPSIS

check_snmp_string.pl -H [HOSTNAME] -c [SNMP RO community string] ... [OPTIONAL ARGS]

=head1 OPTIONS

REQUIRED:

 -H, --host         The FQDN host to query for. NO search path supported.
 -c, --cstring      SNMP read-only community string.
 -o, --oid	    SNMP OID to request.

OPTIONAL:

 -m, --match        Optional string to match the SNMP return value against (defaults to $host if not defined).
 -t, --timeout      The timeout threshhold in seconds until seppuku.
 --help             This shoddy help.

=head1 DESCRIPTION

Supports extensive checks for validity, and correspondingly verbose exit messages reporting failure mode details.

Critical failure conditions:

SNMP query fails (timeout, incorrect cstring)
Match (if specified) does not reflect record(s) returned by query.
Number of records (if specified) does not reflect the number returned by query.
Critical query runtime threshhold exceeds specified value.

Warning failure only occurs if query runtime exceeds specified warn value.                                                                                

=head1 AUTHOR

LICENSE: GPL, Copyright 2006 Eli Stair <eli.stair {at} gmail {dot} com>

