1#!/usr/local/bin/perl -w 2############################## check_snmp_vrrp ############## 3my $Version='1.4'; 4# Date : Oct 17 2007 5# Author : Patrick Proy (patrick at proy.org) 6# Help : http://nagios.manubulon.com/ 7# Licence : GPL - http://www.fsf.org/licenses/gpl.txt 8# Contrib : C. Maser (Alteon + Netscreen), Harm-Jan Blok (Foundry) 9################################################################# 10# 11# Help : ./check_snmp_vrrp.pl -h 12# 13 14use strict; 15use Net::SNMP; 16use Getopt::Long; 17 18# Nagios specific 19 20my $TIMEOUT = 15; 21my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4); 22 23# SNMP Datas 24 25######### Nokia (standard ???) 26my $all_vrrp = "1.3.6.1.2.1.68"; 27my $nokia_base_vrrp = "1.3.6.1.2.1.68.1.3.1"; # oid for vrrp 28my $nokia_vrrp_oper = "1.3.6.1.2.1.68.1.3.1.3"; # vrrp operational status 29my $nokia_vrrp_admin ="1.3.6.1.2.1.68.1.3.1.4"; # vrrp admin status 30my $nokia_vrrp_prio = "1.3.6.1.2.1.68.1.3.1.5"; # vrrp vrid priority 31 32######### Nokia Ipso Clustering 33my $nokia_clust_table = "1.3.6.1.4.1.94.1.21.5.1.4.1"; # IpsoclusterEntry 34my $nokia_clust_index = "1.3.6.1.4.1.94.1.21.5.1.4.1.1.1"; #index 35my $nokia_clust_memberid = "1.3.6.1.4.1.94.1.21.5.1.4.1.2.1"; # member ID 36my $nokia_clust_percent = "1.3.6.1.4.1.94.1.21.5.1.4.1.3.1"; #percent assigned 37my $nokia_clust_rating = "1.3.6.1.4.1.94.1.21.5.1.4.1.4.1"; # node rating 38my $nokia_clust_addr = "1.3.6.1.4.1.94.1.21.5.1.4.1.5.1"; # ip address 39 40######### LinkProof 41my $lp_base_vrrp = "1.3.6.1.2.1.68.1.3.1"; # oid for vrrp 42my $lp_vrrp_oper = "1.3.6.1.2.1.68.1.3.1.4"; # vrrp operational status 43my $lp_vrrp_admin ="1.3.6.1.2.1.68.1.3.1.5"; # vrrp admin status 44my $lp_vrrp_prio = "1.3.6.1.2.1.68.1.3.1.6"; # vrrp vrid priority 45 46######### Alteon (AD4 Loadbalancers) 47my $alteon_base_vrrp = "1.3.6.1.4.1.1872.2.1.9.4"; 48my $alteon_vrrp_oper = "1.3.6.1.4.1.1872.2.1.9.4.1.1.2"; 49my $alteon_vrrp_admin = ""; 50my $alteon_vrrp_prio = "1.3.6.1.4.1.1872.2.1.9.4.1.1.3"; 51 52######### Netscreen (ScreenOS 5.1) 53### .0 is always the queried device itself 54### so in a cluster every device has its own numbering of members 55my $ns_base_vrrp = "1.3.6.1.4.1.3224.6.2"; 56my $ns_vrrp_oper = "1.3.6.1.4.1.3224.6.2.2.1.3"; 57my $ns_vrrp_admin = ""; 58my $ns_vrrp_prio = "1.3.6.1.4.1.3224.6.2.2.1.4"; 59 60######## Foundry 61my $foundry_base_vrrp = "1.3.6.1.4.1.1991.1.2.12.3.1.1"; # oid for vrrp 62my $foundry_vrrp_oper = "1.3.6.1.4.1.1991.1.2.12.3.1.1.10"; # vrrp operational status 63my $foundry_vrrp_admin ="1.3.6.1.4.1.1991.1.2.12.3.1.1.3"; # vrrp admin status 64my $foundry_vrrp_prio = "1.3.6.1.4.1.1991.1.2.12.3.1.1.6"; # vrrp vrid priority 65 66 67######### Make an array 68my %base_vrrp = ("nokia",$nokia_base_vrrp, 69 "lp",$lp_base_vrrp, 70 "alteon",$alteon_base_vrrp, 71 "nsc",$ns_base_vrrp, 72 "foundry",$foundry_base_vrrp 73 ); 74my %vrrp_oper = ("nokia",$nokia_vrrp_oper, 75 "lp",$lp_vrrp_oper, 76 "alteon",$alteon_vrrp_oper, 77 "nsc",$ns_vrrp_oper, 78 "foundry",$foundry_vrrp_oper 79 ); 80my %vrrp_admin =("nokia",$nokia_vrrp_admin, 81 "lp",$lp_vrrp_admin, 82 "alteon",$alteon_vrrp_admin, 83 "nsc",$ns_vrrp_admin, 84 "foundry",$foundry_vrrp_admin 85 ); 86my %vrrp_prio = ("nokia",$nokia_vrrp_prio, 87 "lp",$lp_vrrp_prio, 88 "alteon",$alteon_vrrp_prio, 89 "nsc",$ns_vrrp_prio, 90 "foundry",$foundry_vrrp_oper 91 ); 92 93my %state_master=("nokia",3,"alteon",2,"lp",3,"nsc",2,"foundry",1); 94my %state_backup=("nokia",2,"alteon",3,"lp",2,"nsc",3,"foundry",2); 95 96# Globals 97 98my $o_host = undef; # hostname 99my $o_community = undef; # community 100my $o_version2 = undef; #use snmp v2c 101my $o_port = 161; # port 102my $o_help= undef; # wan't some help ? 103my $o_verb= undef; # verbose mode 104my $o_version= undef; # print version 105my $o_state= undef; # Check master or backup state for ok 106my $o_clustnum= undef; # number of cluster members 107my $o_clustprct= undef; # Max % assigned to one cluster. 108my $o_type= 'nokia'; # Check type : nokia|alteon|lp|nsc|foundry 109my $o_long= undef; # Make output long 110my $o_timeout= 5; # Default 5s Timeout 111 112# SNMPv3 specific 113my $o_login= undef; # Login for snmpv3 114my $o_passwd= undef; # Pass for snmpv3 115my $v3protocols=undef; # V3 protocol list. 116my $o_authproto='md5'; # Auth protocol 117my $o_privproto='des'; # Priv protocol 118my $o_privpass= undef; # priv password 119 120# functions 121 122sub p_version { print "check_snmp_vrrp version : $Version\n"; } 123 124sub print_usage { 125 print "Usage: $0 [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>]) -s <master|backup|num,%> [-T <nokia|alteon|lp|nsc|ipsocluster|foundry>] [-p <port>] [-t <timeout>] [-V]\n"; 126} 127 128sub isnnum { # Return true if arg is not a number 129 my $num = shift; 130 if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;} 131 return 1; 132} 133 134sub help { 135 print "\nSNMP VRRP Monitor for Nagios version ",$Version,"\n"; 136 print "GPL licence, (c)2004-2007 Patrick Proy\n\n"; 137 print_usage(); 138 print <<EOT; 139-v, --verbose 140 print extra debugging information 141-h, --help 142 print this help message 143-H, --hostname=HOST 144 name or IP address of host to check 145-C, --community=COMMUNITY NAME 146 community name for the host's SNMP agent (implies v1 protocol) 147-2, --v2c 148 Use snmp v2c 149-l, --login=LOGIN ; -x, --passwd=PASSWD 150 Login and auth password for snmpv3 authentication 151 If no priv password exists, implies AuthNoPriv 152-X, --privpass=PASSWD 153 Priv password for snmpv3 (AuthPriv protocol) 154-L, --protocols=<authproto>,<privproto> 155 <authproto> : Authentication protocol (md5|sha : default md5) 156 <privproto> : Priv protocole (des|aes : default des) 157-P, --port=PORT 158 SNMP port (Default 161) 159-T, --type=<nokia|alteon|lp|nsc|ipso> 160 Type of vrrp router to check 161 nokia (default) : Nokia vrrp. Should be working for most vrrp routers 162 alteon : for Alteon AD4 Loadbalancers 163 lp : Radware Linkproof 164 nsc : Nescreen (ScreenOS 5.x NSRP) 165 ipso : Nokia IPSO clustering 166 foundry : Foundry VRRP 167-s, --state=master|backup|num,% 168 Nokia ipso clustering : number of members, max % assigned to nodes. 169 Other : check vrrp interface to be master or backup 170-g, --long 171 Make output long even is all is OK 172-t, --timeout=INTEGER 173 timeout for SNMP in seconds (Default: 5) 174-V, --version 175 prints version number 176EOT 177} 178 179# For verbose output 180sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; } 181 182# Get the alarm signal (just in case snmp timout screws up) 183$SIG{'ALRM'} = sub { 184 print ("ERROR: Alarm signal (Nagios time-out)\n"); 185 exit $ERRORS{"UNKNOWN"}; 186}; 187 188sub check_options { 189 Getopt::Long::Configure ("bundling"); 190 GetOptions( 191 'v' => \$o_verb, 'verbose' => \$o_verb, 192 'h' => \$o_help, 'help' => \$o_help, 193 'H:s' => \$o_host, 'hostname:s' => \$o_host, 194 'p:i' => \$o_port, 'port:i' => \$o_port, 195 'C:s' => \$o_community, 'community:s' => \$o_community, 196 't:i' => \$o_timeout, 'timeout:i' => \$o_timeout, 197 'V' => \$o_version, 'version' => \$o_version, 198 'g' => \$o_long, 'long' => \$o_long, 199 'T:s' => \$o_type, 'type:s' => \$o_type, 200 '2' => \$o_version2, 'v2c' => \$o_version2, 201 'l:s' => \$o_login, 'login:s' => \$o_login, 202 'x:s' => \$o_passwd, 'passwd:s' => \$o_passwd, 203 'X:s' => \$o_privpass, 'privpass:s' => \$o_privpass, 204 'L:s' => \$v3protocols, 'protocols:s' => \$v3protocols, 205 's:s' => \$o_state, 'state:s' => \$o_state 206 ); 207 if (defined ($o_help) ) { help(); exit $ERRORS{"UNKNOWN"}}; 208 if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"}}; 209 if ( ! defined($o_host) ) # check host and filter 210 { print_usage(); exit $ERRORS{"UNKNOWN"}} 211 # check snmp information 212 if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) ) 213 { print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}} 214 if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) ) 215 { print "Can't mix snmp v1,2c,3 protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}} 216 if (defined ($v3protocols)) { 217 if (!defined($o_login)) { print "Put snmp V3 login info with protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}} 218 my @v3proto=split(/,/,$v3protocols); 219 if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {$o_authproto=$v3proto[0]; } # Auth protocol 220 if (defined ($v3proto[1])) {$o_privproto=$v3proto[1]; } # Priv protocol 221 if ((defined ($v3proto[1])) && (!defined($o_privpass))) { 222 print "Put snmp V3 priv login info with priv protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}} 223 } 224 # Check state 225 if ($o_type eq "ipso") { 226 my @state=split(/,/,$o_state); 227 if ($#state != 1) { 228 print "On ipso clustering : number of nodes, % assigned\n";print_usage(); exit $ERRORS{"UNKNOWN"}} 229 $state[1] =~ s/%//; 230 if (isnnum($state[0]) || isnnum($state[1])) { 231 print "On ipso clustering (numbers) : number of nodes, % assigned\n";print_usage(); exit $ERRORS{"UNKNOWN"}} 232 $o_clustnum= $state[0]; 233 $o_clustprct= $state[1]; 234 } else { 235 if ( !defined($o_state) || ($o_state ne "master") && ($o_state ne "backup") ) 236 { print "state must be master or backup\n"; print_usage(); exit $ERRORS{"UNKNOWN"}} 237 } 238 # Check type 239 if ( !defined($o_type) || (($o_type ne "nokia") && ($o_type ne "alteon") && ($o_type ne "lp") && ($o_type ne"nsc") && ($o_type ne"ipso") && ($o_type ne "foundry")) ) 240 { print "type must be alteon,nokia,lp,nsc or ipso\n"; print_usage(); exit $ERRORS{"UNKNOWN"}} 241 242} 243 244########## MAIN ####### 245 246check_options(); 247 248# Check gobal timeout if snmp screws up 249if (defined($TIMEOUT)) { 250 verb("Alarm at $TIMEOUT"); 251 alarm($TIMEOUT); 252} else { 253 verb("no timeout defined : $o_timeout + 10"); 254 alarm ($o_timeout+10); 255} 256 257# Connect to host 258my ($session,$error); 259if ( defined($o_login) && defined($o_passwd)) { 260 # SNMPv3 login 261 verb("SNMPv3 login"); 262 if (!defined ($o_privpass)) { 263 verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto"); 264 ($session, $error) = Net::SNMP->session( 265 -hostname => $o_host, 266 -version => '3', 267 -username => $o_login, 268 -authpassword => $o_passwd, 269 -authprotocol => $o_authproto, 270 -port => $o_port, 271 -timeout => $o_timeout 272 ); 273 } else { 274 verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto"); 275 ($session, $error) = Net::SNMP->session( 276 -hostname => $o_host, 277 -version => '3', 278 -username => $o_login, 279 -authpassword => $o_passwd, 280 -authprotocol => $o_authproto, 281 -privpassword => $o_privpass, 282 -privprotocol => $o_privproto, 283 -port => $o_port, 284 -timeout => $o_timeout 285 ); 286 } 287} else { 288 if (defined ($o_version2)) { 289 # SNMPv2 Login 290 verb("SNMP v2c login"); 291 ($session, $error) = Net::SNMP->session( 292 -hostname => $o_host, 293 -version => 2, 294 -community => $o_community, 295 -port => $o_port, 296 -timeout => $o_timeout 297 ); 298 } else { 299 # SNMPV1 login 300 verb("SNMP v1 login"); 301 ($session, $error) = Net::SNMP->session( 302 -hostname => $o_host, 303 -community => $o_community, 304 -port => $o_port, 305 -timeout => $o_timeout 306 ); 307 } 308} 309if (!defined($session)) { 310 printf("ERROR opening session: %s.\n", $error); 311 exit $ERRORS{"UNKNOWN"}; 312} 313 314############ Nokia ipso clustering 315 316my $key=undef; 317 318if ($o_type eq "ipso") { 319# Get cluster table 320my $resultat; 321if (Net::SNMP->VERSION < 4) { 322 $resultat = $session->get_table( $nokia_clust_table ); 323} else { 324 $resultat = $session->get_table( Baseoid => $nokia_clust_table ); 325} 326if (!defined($resultat)) { 327 printf("ERROR: Description table : %s.\n", $session->error); 328 $session->close; 329 exit $ERRORS{"UNKNOWN"}; 330} 331$session->close; 332 333my $nclusterindex=0; 334my $output=undef; 335my $overload=0; 336foreach $key ( keys %$resultat) { 337 if ( $key =~ /$nokia_clust_memberid/){ 338 # Get rid of the vrrp oper part 339 my $Cindex = $$resultat{$key}; 340 $key =~ s/$nokia_clust_memberid\.//; 341 verb("Found cluster, index $key"); 342 343 my $Pkey= $nokia_clust_percent . "." . $key; 344 my $percent= $$resultat{$Pkey}; 345 verb("$percent / $Cindex"); 346 if ($percent > $o_clustprct) {$overload=1}; 347 if ( defined($output) ) { 348 $output .= "; Cluster " . $Cindex . " : ".$percent."%"; 349 } else { 350 $output = "Cluster " . $Cindex . " : ".$percent."%"; 351 } 352 $nclusterindex++; 353 } 354} 355 356if ($nclusterindex==0) { 357 print "No Cluster membre found : CRITICAL\n"; 358 exit $ERRORS{"CRITICAL"}; 359} 360if ($nclusterindex != $o_clustnum) { 361 print $output," : Not ",$o_clustnum," members : CRITICAL\n"; 362 exit $ERRORS{"CRITICAL"}; 363} 364if ($overload==1) { 365 print $output," assigned % is > " , $o_clustprct , " : WARNING\n"; 366 exit $ERRORS{"WARNING"}; 367} 368 369print $output," : OK\n"; 370exit $ERRORS{"OK"}; 371 372 373} 374 375########### get vrrp table ############ 376 377# Get vrrp table 378my $resultat; 379if (Net::SNMP->VERSION < 4) { 380 $resultat = $session->get_table( $base_vrrp{$o_type} ); 381} else { 382 $resultat = $session->get_table( Baseoid => $base_vrrp{$o_type} ); 383} 384if (!defined($resultat)) { 385 printf("ERROR: Description table : %s.\n", $session->error); 386 $session->close; 387 exit $ERRORS{"UNKNOWN"}; 388} 389$session->close; 390 391my @vrid=undef; 392my $nvrid=0; 393my $oid0=undef; 394my @oid=undef; 395 396if ( $o_type eq 'nsc' ) { 397 $nvrid = 1; 398 $vrid[0] = '0'; 399} else { 400 foreach $key ( keys %$resultat) { 401 if ( $key =~ /$vrrp_oper{$o_type}/){ 402 # Get rid of the vrrp oper part 403 $key =~ s/$vrrp_oper{$o_type}\.//; 404 @oid=split (/\./,$key); 405 $vrid[$nvrid]=pop(@oid); 406 $oid0=pop(@oid); 407 while ( defined ($oid0)) { 408 $vrid[$nvrid] = $oid0 . "." . $vrid[$nvrid]; 409 $oid0=pop(@oid); 410 } 411 verb("Added vrid $vrid[$nvrid]"); 412 $nvrid++; 413 } 414 } 415} 416 417if ( $nvrid == 0 ) 418{ printf("No vrid found : CRITICAL\n");exit $ERRORS{"CRITICAL"};} 419 420my $ok=0; 421my $value; 422my $output=undef; 423my $vrid_out; 424for (my $i=0;$i<$nvrid;$i++) { 425 $output .= ", " if (defined($output)); 426 # Get last part of oid to output the vrid 427 $vrid_out = $vrid[$i]; 428 $vrid_out =~ s/.*\.//; 429 $output .= "$vrid_out("; 430 # Get the state 431 $key=$vrrp_oper{$o_type}.".".$vrid[$i]; 432 433 $value = ($$resultat{$key} == $state_master{$o_type}) ? "master" : 434 ($$resultat{$key} == $state_backup{$o_type}) ? "backup" : "initialise : ".$$resultat{$key}; 435 $output.=$value . "/"; 436 ($value eq $o_state) && $ok++; 437 # Get the administrative status 438 if (($o_type eq 'alteon' )|| ($o_type eq 'nsc') ) { 439 $ok++ 440 } else { 441 $key= $vrrp_admin{$o_type} . "." . $vrid[$i]; 442 $value = ($$resultat{$key} == 1) ? "up" : "down"; 443 $output.= $value . "/"; 444 if (($o_type eq 'foundry') && ($o_state eq 'backup') && ($value eq "down")) { 445 $ok++ 446 } else { 447 ($value eq "up") && $ok++; 448 } 449 } 450 # Get the priority 451 $key=$vrrp_prio{$o_type}.".".$vrid[$i]; 452 $value = $$resultat{$key}; 453 $output.=$value . ")"; 454} 455 456verb("verif : $ok"); 457 458if ( $ok == (2*$nvrid) ) { 459 if (defined($o_long)) { 460 printf("Vrid : %s : %s %s : OK\n",$output,$nvrid,$o_state) ; 461 } else { 462 printf("%s vrid %s :OK\n",$nvrid,$o_state) ; 463 } 464 exit $ERRORS{"OK"} 465} 466printf("Vrid : %s : not all %s : NOK\n",$output,$o_state); 467exit $ERRORS{"CRITICAL"}; 468