#!/usr/local/bin/perl -w 

use strict;
use Net::SNMP;
use Getopt::Long;

my $Version='0.2';

use lib "/usr/local/nagios/libexec";
my $TIMEOUT=10;
my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);

my $o_host = 	undef; 		# hostname
my $o_community = undef; 	# community
my $o_version2	=undef;		# Version 2
my $o_port = 	161; 		# port
my $o_help=	undef; 		# wan't some help ?
my $o_verb=	undef;		# verbose mode
my $o_version=	undef;		# print version
my $o_timeout=  undef;            	# Default 5s Timeout
my $o_warn=	undef;		# Warning for connections
my $o_crit=	undef;		# Crit for connections
my $o_svn=	undef;		# Check for SVN status
my $o_fw=	undef;		# Check for FW status
my $o_ha=	undef;		# Check for HA status
my $o_mgmt=	undef;		# Check for management status
my $o_policy=	undef;		# Check for policy name
my $o_conn=	undef;		# Check for connexions
my $o_perf=	undef;		# Performance data output 

# SNMPv3 specific
my $o_login=	undef;		# Login for snmpv3
my $o_passwd=	undef;		# Pass for snmpv3
my $v3protocols=undef;	# V3 protocol list.
my $o_authproto='md5';		# Auth protocol
my $o_privproto='des';		# Priv protocol
my $o_privpass= undef;		# priv password

# functions

sub p_version { print "check_tunnel.pl version : $Version\n"; }

sub print_usage {
    print "Usage: $0 [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>]) [-p <port>] [-t <timeout>] [-V]\n";
}

sub isnnum { # Return true if arg is not a number
  my $num = shift;
  if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
  return 1;
}

sub help {
   print "\nSNMP Checkpoint FW-1 Tunnel Monitor for Nagios version ",$Version,"\n";
   print_usage();
   print <<EOT;
-v, --verbose
   print extra debugging information (including interface list on the system)
-h, --help
   print this help message
-H, --hostname=HOST
   name or IP address of host to check
-C, --community=COMMUNITY NAME
   community name for the host's SNMP agent (implies v1 protocol)
-2, --v2c
   Use snmp v2c
-l, --login=LOGIN ; -x, --passwd=PASSWD
   Login and auth password for snmpv3 authentication 
   If no priv password exists, implies AuthNoPriv 
-X, --privpass=PASSWD
   Priv password for snmpv3 (AuthPriv protocol)
-L, --protocols=<authproto>,<privproto>
   <authproto> : Authentication protocol (md5|sha : default md5)
   <privproto> : Priv protocole (des|aes : default des) 
-p, --port=PORT
   SNMP port (Default 161)
-t, --timeout=INTEGER
   timeout for SNMP (Default: Nagios default)   
-V, --version
   prints version number
EOT
}

# For verbose output
sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }

sub check_options {
    Getopt::Long::Configure ("bundling");
    GetOptions(
   	'v'	=> \$o_verb,		'verbose'	=> \$o_verb,
        'h'     => \$o_help,    	'help'        	=> \$o_help,
        'H:s'   => \$o_host,		'hostname:s'	=> \$o_host,
        'p:i'   => \$o_port,   		'port:i'	=> \$o_port,
        'C:s'   => \$o_community,	'community:s'	=> \$o_community,
	'2'     => \$o_version2,        'v2c'           => \$o_version2,
	'l:s'	=> \$o_login,		'login:s'	=> \$o_login,
	'x:s'	=> \$o_passwd,		'passwd:s'	=> \$o_passwd,
	'X:s'	=> \$o_privpass,		'privpass:s'	=> \$o_privpass,
	'L:s'	=> \$v3protocols,		'protocols:s'	=> \$v3protocols,   
 	't:i'   => \$o_timeout,       	'timeout:i'     => \$o_timeout,
	'V'	=> \$o_version,		'version'	=> \$o_version,
    );
    if (defined ($o_help) ) { help(); exit $ERRORS{"UNKNOWN"}};
    if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"}};
    if ( ! defined($o_host) ) # check host and filter 
	{ print_usage(); exit $ERRORS{"UNKNOWN"}}
    # check snmp information
    if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) )
	  { print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
	if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) )
	  { print "Can't mix snmp v1,2c,3 protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
	if (defined ($v3protocols)) {
	  if (!defined($o_login)) { print "Put snmp V3 login info with protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
	  my @v3proto=split(/,/,$v3protocols);
	  if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {$o_authproto=$v3proto[0];	}	# Auth protocol
	  if (defined ($v3proto[1])) {$o_privproto=$v3proto[1];	}	# Priv  protocol
	  if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
	    print "Put snmp V3 priv login info with priv protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
	}
}

########## MAIN #######

check_options();

# Check gobal timeout if snmp screws up
if (defined($o_timeout)) {
  verb("Alarm at $o_timeout +2sec");
  alarm($o_timeout+2);
} else {
  verb("timeout not defined : $TIMEOUT +2sec");
  alarm ($TIMEOUT+2);
}

$SIG{'ALRM'} = sub {
 print "No answer from host\n";
 exit $ERRORS{"UNKNOWN"};
};

# Connect to host
my ($session,$error);
if ( defined($o_login) && defined($o_passwd)) {
  # SNMPv3 login
  verb("SNMPv3 login");
    if (!defined ($o_privpass)) {
  verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
    ($session, $error) = Net::SNMP->session(
      -hostname   	=> $o_host,
      -version		=> '3',
      -username		=> $o_login,
      -port      	=> $o_port,
      -authpassword	=> $o_passwd,
      -authprotocol	=> $o_authproto,
      -timeout          => $o_timeout 
    );  
  } else {
    verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
    ($session, $error) = Net::SNMP->session(
      -hostname   	=> $o_host,
      -version		=> '3',
      -username		=> $o_login,
      -port      	=> $o_port,
      -authpassword	=> $o_passwd,
      -authprotocol	=> $o_authproto,
      -privpassword	=> $o_privpass,
	  -privprotocol => $o_privproto,
      -timeout          => $o_timeout
    );
  }
} else {
	if (defined ($o_version2)) {
		# SNMPv2 Login
		verb("SNMP v2c login");
		  ($session, $error) = Net::SNMP->session(
		 -hostname  => $o_host,
		 -version   => 2,
		 -community => $o_community,
		 -port      => $o_port,
		 -timeout   => $o_timeout
		);
  	} else {
	  # SNMPV1 login
	  verb("SNMP v1 login");
	  ($session, $error) = Net::SNMP->session(
		-hostname  => $o_host,
		-community => $o_community,
		-port      => $o_port,
		-timeout   => $o_timeout || '5',
		-retries   => '2'
	  );
	verb("Login to $o_host, port $o_port with Comm $o_community");
	}
}
if (!defined($session)) {
   printf("ERROR opening session: %s.\n", $error);
   exit $ERRORS{"UNKNOWN"};
} else { verb ("SNMP Session opened successfully."); }

########### Global checks #################

my ($resultat,$key)=(undef,undef);
my $ES=0;
my $peerIP="1.1.1.1";
my $numTunnels=0; my $numTunnelsBad=0; my $numTunnelsGood=0;
my $tunnelName=""; my $tunnelStatus=""; my $tunnelCommunity=""; my $tunnelStatusLong="";
my $LINE1=""; my $LINE2=""; my $LINE3="";
my $ops="green"; my $term="normal";
my $previous="1.2.3.4";
my $OID="1.3.6.1.4.1.2620.500.9002.1.1";
my $OID1="1.3.6.1.2.1.1.5.0"; my $OID2="1.3.6.1.2.1.1.3.0"; my $OID3="1.3.6.1.4.1.2620.500.9002.1.1";
my @OID_all=($OID, $OID1);

while ( $ops =~ /green/ ) {
	$resultat = $session->get_next_request( Varbindlist => \@OID_all );
	if (!defined($resultat) ) { 
		if ( $numTunnels == 0 ) { verb ("No tunnels found!"); print "No tunnels configured"; exit 1 }
		verb("shit no SNMP $session->error"); print "Table $OID not found. Check CP SNMP agent!"; exit 2; }
	my @names = $session->var_bind_names;
	if ( $names[0] =~ /1.3.6.1.4.1.2620.500.9002.1.2/ ) { $ops="done"; }
	$peerIP=$$resultat{$names[0]};
	verb ("___________________________________________________________\nNext IP is $peerIP (source is OID $names[0]");
        if ( $peerIP =~ /^0$/ ) { $ops="done"; }
	if ($ops eq "green") {
        	# get tunnel status and details
                 verb ("obtaining tunnel details...");
        	$numTunnels++;
		if ( $numTunnels > 100 ) {  			# probably somthing is wrong!! e.g. SNMP loop?
		   $ops="red"; verb("ATTENTION: max number tunnels exceeded!"); $term="max_tunnel_reached"; }  
        	$OID1="1.3.6.1.4.1.2620.500.9002.1.2.${peerIP}.0";
        	$OID2="1.3.6.1.4.1.2620.500.9002.1.3.${peerIP}.0";
        	$OID3="1.3.6.1.4.1.2620.500.9002.1.4.${peerIP}.0";
		@OID_all=($OID1,$OID2,$OID3);
                verb ("checking OIDs:\n T_Name $OID1\n T_Stat $OID2\n T_Comm $OID3");
		$resultat = $session->get_request( Varbindlist => \@OID_all );
		if (!defined($resultat) ) { verb ("SNMP keine ahnung"); }
		#$error=$session->error;
		#verb ("SNMP error: $error");
		
        	$tunnelName=$$resultat{$OID1}; 		if (! defined($tunnelName) ) { $tunnelName="no name"; }
        	$tunnelStatus=$$resultat{$OID2};	if (! defined($tunnelStatus) ) { $tunnelStatus="-1"; }
        	$tunnelCommunity=$$resultat{$OID3}; 	if (! defined($tunnelCommunity) ) { $tunnelCommunity="no community"; }
		if ( length($tunnelCommunity) < 2) { $tunnelCommunity = "T:" . $tunnelName; }
		verb("Tunnel $tunnelName in status  $tunnelStatus, Comm: $tunnelCommunity|");
		if ( $tunnelStatus == 3) 	{ $tunnelStatusLong="active"; }
		if ( $tunnelStatus == 4) 	{ $tunnelStatusLong="destroy"; }
		if ( $tunnelStatus == 129) 	{ $tunnelStatusLong="idle"; }
		if ( $tunnelStatus == 130) 	{ $tunnelStatusLong="phase1"; }
		if ( $tunnelStatus == 131) 	{ $tunnelStatusLong="down"; }
		if ( $tunnelStatus == 132) 	{ $tunnelStatusLong="init"; }
		if (  ($tunnelStatus ne 3) && ($tunnelStatus ne 130) ) {
		   $LINE1=$LINE1." Tunnel ".$tunnelCommunity." (".$tunnelName.") is ".$tunnelStatusLong;
		   $numTunnelsBad++;
		   $ES=2; $term="tunnel_down";
                   verb ("Bad tunnel: $tunnelCommunity, $tunnelName, $tunnelStatusLong");
        	} else {
                   $LINE2=$LINE2." ". $tunnelCommunity .",";
                   $numTunnelsGood++;
                   verb ("Good Tunnnel: $tunnelCommunity, $tunnelName, $tunnelStatusLong"); 
        	}
 	 	verb ("Tunnel Count: good/bad $numTunnelsGood / $numTunnelsBad ");
		verb ("LINE1 (bad)  = $LINE1");
		verb ("LINE2 (good) = $LINE2");
        	# prepare for next run
        	$OID="1.3.6.1.4.1.2620.500.9002.1.1.$peerIP.0";
		@OID_all=($OID);
		if  ($previous eq $peerIP) { $ops="red"; verb("ATTENTION: SNMP loop detected!"); $term="SNMP_loop_detected"; }
        	$previous=$peerIP;
		# sleep 1;
    	}
}  # while
$session->close;
verb ("Closing SNMP session");

########## print results and exit
if ( $LINE1 eq "" ) { $LINE1=$LINE2;  }
# somethings was wrong: e.g. max number reached? or loop?  flag as warning
# if ( $ops ne "done" ) { $ES=1; }

if ($numTunnels == 0) { $ES=1; }

# truncate lengthy output
verb("Full output: $LINE1");
$OID=length($LINE1);
# if ($OID > 180) { $LINE1=substr($LINE1,1,177) . "..."; }

print "$LINE3$numTunnelsGood/$numTunnels tunnels active:$LINE1|Tunnels=$numTunnels; Termination=$term\n";
exit $ES;
