#!/usr/bin/perl
# ============================================================================
# ============================== INFO ========================================
# ============================================================================
# Version : 0.1
# Date : July 20 2015
# Author : Michiel Timmers ( michiel.timmers AT gmx.net)
# Licence : GPL - summary below
#
# ============================================================================
# ============================== SUMMARY =====================================
# ============================================================================
# Check for BGP status on Cisco Routers using SNMP. Check status, number of
# prefixes and time established.
#
# Check the http://exchange.nagios.org website for new versions.
# For comments, questions, problems and patches send me an
# e-mail (michiel.timmmers AT gmx.net).
#
# ============================================================================
# ============================== LICENCE =====================================
# ============================================================================
# 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 3 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, see
#
# ============================================================================
# ============================== HELP ========================================
# ============================================================================
# Help : ./check_snmp_cisco_bgp.pl --help
#
# ============================================================================
use warnings;
use strict;
use Net::SNMP;
use Getopt::Long;
#use lib "/usr/local/nagios/libexec";
#use utils qw(%ERRORS $TIMEOUT);
# ============================================================================
# ============================== NAGIOS VARIABLES ============================
# ============================================================================
my $TIMEOUT = 15; # This is the global script timeout, not the SNMP timeout
my %ERRORS = ('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
my @Nagios_state = ("UNKNOWN","OK","WARNING","CRITICAL"); # Nagios states coding
# ============================================================================
# ============================== OID VARIABLES ===============================
# ============================================================================
# System description
my $snmp_bgpPeerState = "1.3.6.1.2.1.15.3.1.2"; # bgpPeerState
my $snmp_bgpPeerFsmEstablishedTime = "1.3.6.1.2.1.15.3.1.16"; # This timer indicates how long (in seconds) this peer has been in the Established state or how long since this peer was last in the Established state.
my $snmp_bgpPeerRemoteAs = "1.3.6.1.2.1.15.3.1.9"; # bgpPeerRemoteAs
my $snmp_cbgpPeerAcceptedPrefixes = "1.3.6.1.4.1.9.9.187.1.2.4.1.1"; # cbgpPeerAcceptedPrefixes
# ============================================================================
# ============================== GLOBAL VARIABLES ============================
# ============================================================================
my $Version = '0.1'; # Version number of this script
my $o_host = undef; # Hostname
my $o_community = undef; # Community
my $o_port = 161; # Port
my $o_help = undef; # Want some help ?
my $o_verb = undef; # Verbose mode
my $o_version = undef; # Print version
my $o_timeout = undef; # Timeout (Default 5)
my $o_version1 = undef; # Use SNMPv1
my $o_version2 = undef; # Use SNMPv2c
my $o_domain = undef; # Use IPv6
my $o_login = undef; # Login for SNMPv3
my $o_passwd = undef; # Pass for SNMPv3
my $v3protocols = undef; # V3 protocol list.
my $o_authproto = 'sha'; # Auth protocol
my $o_privproto = 'aes'; # Priv protocol
my $o_privpass = undef; # priv password
my $o_ippeer = undef; # BGP IP peer
my $o_low = undef; # Lower threshold number of prefixes
my $o_up = undef; # Upper threshold number of prefixes
my $o_warning = undef; # warning threshold in hours
my $o_critical = undef; # critical threshold in hours
# ============================================================================
# ============================== SUBROUTINES (FUNCTIONS) =====================
# ============================================================================
# Subroutine: Print version
sub p_version {
print "check_snmp_cisco_bgp version : $Version\n";
}
# Subroutine: Print Usage
sub print_usage {
print "Usage: $0 [-v] -H [-6] -C [-2] -P | (-l login -x passwd [-X pass -L ,]) [-p ] [-t ] [-low -up ] [-V]\n";
}
# Subroutine: Check number
sub isnnum { # Return true if arg is not a number
my $num = shift;
if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
return 1;
}
# Subroutine: Set final status
sub set_status { # Return worst status with this order : OK, unknown, warning, critical
my $new_status = shift;
my $cur_status = shift;
if ($new_status == 1 && $cur_status != 2) {$cur_status = $new_status;}
if ($new_status == 2) {$cur_status = $new_status;}
if ($new_status == 3 && $cur_status == 0) {$cur_status = $new_status;}
return $cur_status;
}
# Subroutine: Check if SNMP table could be retrieved, otherwise give error
sub check_snmp_result {
my $snmp_table = shift;
my $snmp_error_mesg = shift;
# Check if table is defined and does not contain specified error message.
# Had to do string compare it will not work with a status code
if (!defined($snmp_table) && $snmp_error_mesg !~ /table is empty or does not exist/) {
printf("ERROR: ". $snmp_error_mesg . " : UNKNOWN\n");
exit $ERRORS{"UNKNOWN"};
}
}
# Subroutine: Print complete help
sub help {
print "\nSNMP BGP Cisco check for Nagios\nVersion: ",$Version,"\n\n";
print_usage();
print <,
: Authentication protocol (md5|sha : default sha)
: Priv protocole (des|aes : default aes)
-p, --port=PORT
SNMP port (Default 161)
-w, --warning=INTEGER
warning threshold in hours that state should be established
-c, --critical=INTEGER
critical threshold in hours that state should be established
--lower=INTEGER
Low threshold number of prefixes
--upper=INTEGER
Upper threshold number of prefixes
-t, --timeout=INTEGER
Timeout for SNMP in seconds (Default: 5)
-V, --version
Prints version number
Notes:
- Check the http://exchange.nagios.org website for new versions.
- For questions, problems and patches send me an e-mail (michiel.timmmers AT gmx.net).
EOT
}
# Subroutine: Verbose output
sub verb {
my $t=shift;
print $t,"\n" if defined($o_verb);
}
# Subroutine: Verbose output
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,
'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,
'6' => \$o_domain, 'use-ipv6' => \$o_domain,
'1' => \$o_version1, 'v1' => \$o_version1,
'2' => \$o_version2, 'v2c' => \$o_version2,
'P:s' => \$o_ippeer, 'ippeer:s' => \$o_ippeer,
'w:s' => \$o_warning, 'warning:s' => \$o_warning,
'c:s' => \$o_critical, 'critical:s' => \$o_critical,
'lower:s' => \$o_low,
'upper:s' => \$o_up
);
# Basic checks
if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60))) {
print "Timeout must be >1 and <60 !\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
if (!defined($o_timeout)) {
$o_timeout=5;
}
if (defined ($o_help) ) {
help();
exit $ERRORS{"UNKNOWN"};
}
if (defined($o_version)) {
p_version();
exit $ERRORS{"UNKNOWN"};
}
# check host and filter
if ( ! defined($o_host) ) {
print_usage();
exit $ERRORS{"UNKNOWN"};
}
# Check IPv6
if (defined ($o_domain)) {
$o_domain="udp/ipv6";
} else {
$o_domain="udp/ipv4";
}
# 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,v2c,v3 protocols!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
# Check SNMPv3 information
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];
}
if (defined ($v3proto[1])) {
$o_privproto=$v3proto[1];
}
if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
print "Put SNMP v3 priv login info with priv protocols!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
}
# Check IP peer information
if ( !defined($o_ippeer) ){
print "Put BGP peer info!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
}
# ============================================================================
# ============================== MAIN ========================================
# ============================================================================
check_options();
# Check gobal timeout if SNMP screws up
if (defined($TIMEOUT)) {
verb("Alarm at ".$TIMEOUT." + ".$o_timeout);
alarm($TIMEOUT+$o_timeout);
} else {
verb("no global timeout defined : ".$o_timeout." + 15");
alarm ($o_timeout+15);
}
# Report when the script gets "stuck" in a loop or takes to long
$SIG{'ALRM'} = sub {
print "UNKNOWN: Script timed out\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)) {
# SNMPv3 login (Without encryption)
verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-hostname => $o_host,
-version => 3,
-username => $o_login,
-authpassword => $o_passwd,
-authprotocol => $o_authproto,
-timeout => $o_timeout
);
} else {
# SNMPv3 login (With encryption)
verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-hostname => $o_host,
-version => 3,
-username => $o_login,
-authpassword => $o_passwd,
-authprotocol => $o_authproto,
-privpassword => $o_privpass,
-privprotocol => $o_privproto,
-timeout => $o_timeout
);
}
} else {
if ((defined ($o_version2)) || (!defined ($o_version1))) {
# SNMPv2 login
verb("SNMP v2c login");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-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(
-domain => $o_domain,
-hostname => $o_host,
-version => 1,
-community => $o_community,
-port => $o_port,
-timeout => $o_timeout
);
}
}
# Check if there are any problems with the session
if (!defined($session)) {
printf("ERROR opening session: %s.\n", $error);
exit $ERRORS{"UNKNOWN"};
}
my $exit_val=undef;
# ============================================================================
# ============================== CHECK SNMP BGP CISCO ========================
# ============================================================================
# Define variables
my $output = "";
my $final_status = 0;
my $result_t;
my $index;
my @temp_oid;
my $day = 0;
my $hour = 0;
my $minute = 0;
# Get SNMP table(s) and check the result
# BGP peer state
my $snmp_BgpState_Peer = $snmp_bgpPeerState.".".$o_ippeer;
@temp_oid=($snmp_BgpState_Peer);
$result_t = $session->get_request( Varbindlist => \@temp_oid);
my $peer_state = $$result_t{$snmp_BgpState_Peer};
# Established time
my $snmp_est_time = $snmp_bgpPeerFsmEstablishedTime.".".$o_ippeer;
@temp_oid=($snmp_est_time);
$result_t = $session->get_request( Varbindlist => \@temp_oid);
my $established_time = $$result_t{$snmp_est_time};
# bgpPeerRemoteAs
my $snmp_bgpRemoteAs_Peer = $snmp_bgpPeerRemoteAs.".".$o_ippeer;
@temp_oid=($snmp_bgpRemoteAs_Peer);
$result_t = $session->get_request( Varbindlist => \@temp_oid);
my $Remote_As = $$result_t{$snmp_bgpRemoteAs_Peer};
# cbgpPeerAcceptedPrefixes
my $snmp_Prefixes_Peer = $snmp_cbgpPeerAcceptedPrefixes.".".$o_ippeer.".1.1";
@temp_oid=($snmp_Prefixes_Peer);
$result_t = $session->get_request( Varbindlist => \@temp_oid);
my $Prefixes = $$result_t{$snmp_Prefixes_Peer};
# Clear the SNMP Transport Domain and any errors associated with the object.
$session->close;
if (defined($peer_state) && defined($established_time)){
$output = "BGP state: ";
if ($peer_state == 1){$final_status = 1; $output = $output."idle";} #1 : idle
if ($peer_state == 2){$final_status = 2; $output = $output."connect";} #2 : connect
if ($peer_state == 3){$final_status = 2; $output = $output."active";} #3 : active
if ($peer_state == 4){$final_status = 2; $output = $output."opensent";} #4 : opensent
if ($peer_state == 5){$final_status = 2; $output = $output."openconfirm";} #5 : openconfirm
if ($peer_state == 6){ #6 : openconfirm
if (defined($o_warning) && defined($o_critical)){
if ($established_time <= $o_warning*60*60){$final_status = &set_status(1,$final_status);}
if ($established_time <= $o_critical*60*60){$final_status = &set_status(2,$final_status);}
}
while ($established_time>= 86400){$day++;$established_time = $established_time - 86400;}
while ($established_time >= 3600){$hour++;$established_time = $established_time - 3600;}
while ($established_time >= 60){$minute++;$established_time = $established_time - 60;}
$output = $output."established - Established for: ".$day." days, ".$hour." hours, ".$minute." minutes, ".$established_time." seconds, Remote AS: ".$Remote_As.", ";
if (defined($o_low) && defined($o_up)){
if ($Prefixes < $o_low){$output = $output."Number of prefixes: ".$Prefixes." bellow lower threshold (".$o_low.")!";$final_status = &set_status(1,$final_status);}
if ($Prefixes > $o_up){$output = $output."Number of prefixes: ".$Prefixes." above upper threshold (".$o_up.")!";$final_status = &set_status(1,$final_status);}
if ($Prefixes >= $o_low && $Prefixes <= $o_up){$output = $output."Number of prefixes: ".$Prefixes;}
}else{
$output = $output."Number of prefixes: ".$Prefixes;
}
}
}else{
$final_status = 3;
$output = "Can't get SNMP uptime data";
}
if ($final_status == 3) {
print $output," : UNKNOWN\n";
exit $ERRORS{"UNKNOWN"};
}
if ($final_status == 2) {
print $output," : CRITICAL\n";
exit $ERRORS{"CRITICAL"};
}
if ($final_status == 1) {
print $output," : WARNING\n";
exit $ERRORS{"WARNING"};
}
print $output," : OK\n";
exit $ERRORS{"OK"};
# ============================================================================
# ============================== NO CHECK DEFINED ============================
# ============================================================================
print "Unknown check type : UNKNOWN\n";
exit $ERRORS{"UNKNOWN"};