#!/usr/bin/env perl
use strict;
use warnings;

#===============================================================================
#        BGPmon.net :: SOAP API script for NAgios
#        will retrieve all alarms from BGPmon.net using SOAP
#        And return the result to Nagios
#
#        For questions or feedback please contact Andree Toonk
#        andree@bgpmon.net
#        http://www.bgpmon.net/
#===============================================================================


#===============================================================================
#                               Configuration        
#===============================================================================

my $lastScriptModification = '2009-09-27';

#===============================================================================
#                              Initialization
#===============================================================================

#-------------------------------------------------------------------------------
#    Libraries
#-------------------------------------------------------------------------------

eval { require SOAP::Lite}; 
if ($@) {
	print "ERROR Could not find SOAP::Lite, please install the SOAP::Lite perl library\n"; 
	exit 3;
}
# Use only for debugging
#use SOAP::Lite +trace => 'debug';

use Getopt::Std;


#-------------------------------------------------------------------------------
#    Global var declarations
#-------------------------------------------------------------------------------
my (
   # Working vars 
   $usage,              # String containing usage help
   $active,             # Show only active or incactive alarms
   $days,               # How many days of data do we want.
   $maxcode,            # Maximum alarm code.
   $email,              # User email address
   $password,           # User password
   $info_message,       # the text message to return to nagios
   $state               # 2=critical (hijack), 1=warning, 0=ok, 3=error
);

#-------------------------------------------------------------------------------
#    Global var initializations
#-------------------------------------------------------------------------------

$usage = <<"EOF";
BGPmon.net Soap API:: nagios plugin
usage:   $0 -l <email> -p <password> [-d <days>] [-n <active>] [-c <maxcode>] [-v]
example: $0 -l 'demo\@bgpmon.net' -p 'demo' -d 3 -n 1 -c 23

[-h]          : Print this message

[-l] <email>  : email address / BGPmon.net login name -l 'andree\@bgpmon.net'
              : Mandatory argument.

[-p] <passw>  : BGPmon.net password
              : Mandatory argument.

[-d] <days>   : Number of days of data, -d 3 means from now to 3 days ago (default)
              : Optional argument.

[-n] <active> : flag for active alarms only. 1(default) is active only, 0 also cleared alarms
              : Optional argument.

[-c] <maxcode>: Include alarms up to (inclusive) max code. 
              : default is 22 (all hijacks and more specifics).  Optional argument.

[-v] 	      : Verbose mode, will print all details as well using getAlertDetails()
              : Will also print ASnames using getASName()


Andree Toonk: andree\@bgpmon.net  
$lastScriptModification
 
EOF

#===============================================================================
#                              Input Phase
#===============================================================================

#-------------------------------------------------------------------------------
# Check the usage
#-------------------------------------------------------------------------------
my $opt_string = 'vhl:p:d:n:c:';
my %opt;
getopts( "$opt_string", \%opt ) or die $usage;
die $usage if (defined $opt{h});
die $usage if (!defined $opt{l});
die $usage if (!defined $opt{p});

#-------------------------------------------------------------------------------
# Set the args for the soap session 
#-------------------------------------------------------------------------------
$email = $opt{l};
$password = $opt{p};
$maxcode = 22;
if (defined($opt{c})) {
	$maxcode = $opt{c};
}
$days = 3;
if (defined($opt{d})) {
	$days = $opt{d};
}
$active = 1;
if ((defined($opt{n})) && ($opt{n} eq 0)) {
	$active = $opt{n};
}
my $verbose = -1;
if (defined($opt{v})) {
	$verbose = 1;
}

#-------------------------------------------------------
# Here we go....
#-------------------------------------------------------
$state = -3;

my @alerts = get_alerts($email,$password,$days,$active);
process_alerts(@alerts);


#----------------------------------------------------------------------------
# And that's it already...
# let's return the result and we're done
# bye bye.
#----------------------------------------------------------------------------
print "$info_message\n";
exit $state;


#----------------------------------------------------------------------------
# Functions below....
#----------------------------------------------------------------------------

sub get_alerts{
	my ($email, $password, $days, $active) = @_;
	#----------------------------------------------------------------------------

	## Ok let's make the soap call
	my @params = ( SOAP::Data->name("email" => $email),
			SOAP::Data->name("password" => $password),
			SOAP::Data->name("active" => $active),
		 	SOAP::Data->name("days" => $days),
		 	SOAP::Data->name("maxcode" => $maxcode)
			);

	my $result;
	eval { $result = SOAP::Lite                             
	-> uri('urn:http://bgpmon.net/soap/bgpmon')                
    -> proxy("http://bgpmon.net/soap/server.php")
	-> getAlerts(@params); 
	}  ;
	if ($@) {
		my $message = ($@);
		chomp($message);
		if ($message =~ /401 Unauthorized at/) {
			print "Something went wrong while doing SOAP call to BGPmon.net: 'Authentication failed, Incorrect email/password'\n"; 
		} else {
			print "Something went wrong while doing SOAP call to BGPmon.net: '$message'\n"; 
		}
		exit 3;
	}



	if ($result->fault) {
		$state = 3;
		print "Plugin Error: " . $result->faultcode, "--> ", $result->faultstring, "\n";
		exit 3;
	} else {
		# reference to array of structs is returned
		my @alerts = @{$result->result};
		# @alerts is the array of structs
		
		# verbose loop :
		# This is how you print all info from the returned result
		# here we print all AND get de alarm details using getAlertDetails()
		if ($verbose >0) {
			print "Verbose enabled, will  now print alert details as well using getAlertDetails()\n";
		
			# First loop trough all unique alerts
			foreach my $alert (@alerts) {
				print "\n";
				# This will loop through all the alert fields
				 foreach my $key (keys %{$alert}) {
					print $key, ": ", $alert->{$key} . "\n";
			 	}
				
				# This is an example of using getASName()
				# For retrieving the AS name of the origin_AS
				my $origin_result = SOAP::Lite                             
				-> uri('urn:http://bgpmon.net/soap/bgpmon')                
	    		-> proxy("http://bgpmon.net/soap/server.php")
				-> getASName(SOAP::Data->name("AS" => $alert->{'origin_AS'}));
				my $asname = $origin_result->result;
				print "OriginAS name $alert->{'origin_AS'} is  $asname\n";
		
				#This how you retrieve a single alert field, alert_id
				my $alert_id = $alert->{'alert_id'};
				print "Details for Alert id $alert_id :\n";

				# Now do a new soap call to retrieve the BGP messages for this
				# alert. This will be one or more BGP messages.
				my $detail_result = SOAP::Lite                             
				-> uri('urn:http://bgpmon.net/soap/bgpmon')                
	    		-> proxy("http://bgpmon.net/soap/server.php")
				-> getAlertDetails(SOAP::Data->name("email" => $email),
				SOAP::Data->name("password" => $password),
				SOAP::Data->name("alert_id" => $alert_id));
				if ($result->fault) {
					print "Plugin Error: " . $result->faultcode, "--> ", $result->faultstring, "\n";
					exit 3;
				}

				my @alert_details = @{$detail_result->result};

				# Loop through all BGP messages:
				foreach my $alert_detail (@alert_details) {
				# This loops though all alert_detail fields (peer_ip, peer_as,
				# etc...
					foreach my $key2 (keys %{$alert_detail}) {
						print $key2, ": ", $alert_detail->{$key2} . "|";
					}
					print "\n";
				}
			}        
		}

		return @alerts;
	}
}

sub process_alerts {
	my @alerts_array = @_;
	my %codes;
	$codes{hijack} = 0;
	$codes{morespec} =0;
	$codes{newupstream} =0;
	$codes{regex} =0;
	$codes{newprefix} =0;
	$codes{withdraw} =0;
	$codes{other} =0;
	foreach my $alert (@alerts_array) {
		my $code = $alert->{'alert_code'};
		if ($code < 20) {
			$codes{hijack}++;
			$state = 2;
		} elsif ($code < 23) {
			$codes{morespec}++;
		} elsif ($code < 32) {
			$codes{newupstream}++;
		} elsif ($code < 42) {
			$codes{regex}++;
		} elsif ($code < 65) {
			$codes{newprefix}++;
		} elsif ($code < 98) {
			$codes{withdraw}++;
		} else  {
			$codes{other}++;
		}
		
		# This is how you print all info in the answer
		#print all
		#foreach my $key (keys %{$alert}) {
		#	print $key, ": ", $alert->{$key} . "\n";
		#}        
	}
	#return string
	$info_message =  @alerts_array . " BGPmon Alerts => $codes{hijack} Hijacks, $codes{morespec} more specifics, $codes{newupstream} new upstreams, ".
		"$codes{regex} regex alerts, $codes{newprefix} new prefixes, $codes{withdraw} withdraw alerts, $codes{other} other";

	#### determine state
	if (@alerts_array eq 0) {
		$state = 0;
		$info_message =  "No BGPmon.net Alerts";
	} elsif ($codes{hijack} > 0) {
		$state = 2;
	} else {
		$state = 1;
	}
}
