1#!/usr/local/bin/perl -w
2############################## check_snmp_nsbox #################
3# Version : 1.0
4# Date : Jan 16 2007
5# Author  : Patrick Proy ( patrick at proy.org)
6# Help : http://www.manubulon.com/nagios/
7# Licence : GPL - http://www.fsf.org/licenses/gpl.txt
8# Changelog :
9# Contributors :
10#################################################################
11#
12# Help : ./check_snmp_nsbox.pl -h
13#
14
15use strict;
16use Net::SNMP;
17use Getopt::Long;
18
19# Nagios specific
20
21use lib "/usr/local/libexec/nagios";
22use utils qw(%ERRORS $TIMEOUT);
23#my $TIMEOUT = 15;
24#my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
25
26# SNMP Datas
27my $ns_service_status=	"1.3.6.1.4.1.14020.2.2.1.3.0"; # service status 1= ok ??
28
29my $ns_service_table=	"1.3.6.1.4.1.14020.2.3"; # vhost & diode table
30my $ns_vhost_table=		"1.3.6.1.4.1.14020.2.3.1"; # vhost table
31my $ns_vhost_name=		"1.0"; # GUI Vhost Name
32my $ns_vhost_requests=	"2.0"; # Instant Vhost Requests per Second : NOT POPULATED IN V 2.0.8
33my $ns_vhost_Trequests=	"2.0"; # Total Vhost Requests : NOT POPULATED IN V 2.0.8
34my $ns_diode_table=		"1.3.6.1.4.1.14020.2.3.2"; # diode table
35my $ns_diode_name=		"1.0"; # GUI Diode Name
36my $ns_diode_status=	"2.0"; # Last diode Status (" " = OK?) (undocumented)
37
38my $ns_rsa_prct_usage=	".1.3.6.1.4.1.14020.1.1.1.3.0"; #  % usage of RSA operations. (undocumented)
39my $ns_rsa_oper_second=	".1.3.6.1.4.1.14020.1.1.3.4.0;"; # number of RSA operations/s (undocumented)
40
41# Globals
42
43my $Version='1.0';
44
45my $o_host = 	undef; 		# hostname
46my $o_community = undef; 	# community
47my $o_port = 	161; 		# port
48my $o_help=	undef; 		# wan't some help ?
49my $o_verb=	undef;		# verbose mode
50my $o_version=	undef;		# print version
51my $o_timeout=  undef; 		# Timeout (Default 5)
52my $o_perf=     undef;          # Output performance data
53my $o_version2= undef;          # use snmp v2c
54# specific
55my $o_vhost=	undef;	# vhost regexp
56my $o_diode=	undef;	# diode regexp
57my $o_nvhost=	undef;	# vhost number
58my $o_ndiode=	undef;	# diode number
59
60# SNMPv3 specific
61my $o_login=	undef;		# Login for snmpv3
62my $o_passwd=	undef;		# Pass for snmpv3
63my $v3protocols=undef;	# V3 protocol list.
64my $o_authproto='md5';		# Auth protocol
65my $o_privproto='des';		# Priv protocol
66my $o_privpass= undef;		# priv password
67
68# functions
69
70sub p_version { print "check_snmp_nsbox version : $Version\n"; }
71
72sub print_usage {
73    print "Usage: $0 [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>]) -d <diode> -s <vhost> -n <ndiode>,<nvhost> [-p <port>] [-f] [-t <timeout>] [-V]\n";
74}
75
76sub isnnum { # Return true if arg is not a number
77  my $num = shift;
78  if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
79  return 1;
80}
81
82sub set_status { # return worst status with this order : OK, unknwonw, warning, critical
83  my $new_status=shift;
84  my $cur_status=shift;
85  if (($cur_status == 0)|| ($new_status==$cur_status)){ return $new_status; }
86  if ($new_status==3) { return $cur_status; }
87  if ($new_status > $cur_status) {return $new_status;}
88  return $cur_status;
89}
90
91sub is_pattern_valid { # Test for things like "<I\s*[^>" or "+5-i"
92 my $pat = shift;
93 if (!defined($pat)) { $pat=" ";} # Just to get rid of compilation time warnings
94 return eval { "" =~ /$pat/; 1 } || 0;
95}
96
97sub help {
98   print "\nSNMP NetSecureOne Netbox monitor for Nagios version ",$Version,"\n";
99   print "(c)2004-2006 Patrick Proy\n\n";
100   print_usage();
101   print <<EOT;
102Check that diode and vhost selected by regexp are active.
103-v, --verbose
104   print extra debugging information
105-h, --help
106   print this help message
107-H, --hostname=HOST
108   name or IP address of host to check
109-C, --community=COMMUNITY NAME
110   community name for the host's SNMP agent (implies v1 protocol)
111-2, --v2c
112   Use snmp v2c
113-l, --login=LOGIN ; -x, --passwd=PASSWD
114   Login and auth password for snmpv3 authentication
115   If no priv password exists, implies AuthNoPriv
116-X, --privpass=PASSWD
117   Priv password for snmpv3 (AuthPriv protocol)
118-L, --protocols=<authproto>,<privproto>
119   <authproto> : Authentication protocol (md5|sha : default md5)
120   <privproto> : Priv protocole (des|aes : default des)
121-d, --diode=<diode>
122	Diode selection by regexp
123-s, --vhost=<vhost>
124	Vhost selection by regexp
125-n, --number=<ndiode>,<nvhost>
126	number of diode and vhost that must be up.
127-P, --port=PORT
128   SNMP port (Default 161)
129-f, --perfparse
130   Perfparse compatible output
131-t, --timeout=INTEGER
132   timeout for SNMP in seconds (Default: 5)
133-V, --version
134   prints version number
135EOT
136}
137
138# For verbose output
139sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }
140
141sub check_options {
142    Getopt::Long::Configure ("bundling");
143    GetOptions(
144	'v'		=> \$o_verb,		'verbose'		=> \$o_verb,
145	'h'     => \$o_help,    	'help'        	=> \$o_help,
146	'H:s'   => \$o_host,		'hostname:s'	=> \$o_host,
147	'p:i'   => \$o_port,   		'port:i'		=> \$o_port,
148	'C:s'   => \$o_community,	'community:s'	=> \$o_community,
149	'l:s'	=> \$o_login,		'login:s'		=> \$o_login,
150	'x:s'	=> \$o_passwd,		'passwd:s'		=> \$o_passwd,
151	'X:s'	=> \$o_privpass,	'privpass:s'	=> \$o_privpass,
152	'L:s'	=> \$v3protocols,	'protocols:s'	=> \$v3protocols,
153	't:i'   => \$o_timeout,     'timeout:i'		=> \$o_timeout,
154	'V'		=> \$o_version,		'version'		=> \$o_version,
155	'2'     => \$o_version2,	'v2c'			=> \$o_version2,
156	'f'     => \$o_perf,		'perfparse'		=> \$o_perf,
157	'd:s'	=> \$o_diode,		'diode:s'		=> \$o_diode,
158	's:s'	=> \$o_vhost,		'vhost:s'		=> \$o_vhost,
159	'n:s'	=> \$o_nvhost,		'number:s'		=> \$o_nvhost
160	);
161    # Basic checks
162	if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60)))
163	  { print "Timeout must be >1 and <60 !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
164	if (!defined($o_timeout)) {$o_timeout=5;}
165    if (defined ($o_help) ) { help(); exit $ERRORS{"UNKNOWN"}};
166    if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"}};
167    if ( ! defined($o_host) ) # check host and filter
168	{ print_usage(); exit $ERRORS{"UNKNOWN"}}
169    # check snmp information
170    if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) )
171	  { print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
172	if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) )
173	  { print "Can't mix snmp v1,2c,3 protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
174	if (defined ($v3protocols)) {
175	  if (!defined($o_login)) { print "Put snmp V3 login info with protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
176	  my @v3proto=split(/,/,$v3protocols);
177	  if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {$o_authproto=$v3proto[0];	}	# Auth protocol
178	  if (defined ($v3proto[1])) {$o_privproto=$v3proto[1];	}	# Priv  protocol
179	  if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
180	    print "Put snmp V3 priv login info with priv protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
181	}
182	if (!defined($o_vhost) || !(is_pattern_valid($o_vhost)))
183		{ print "Vhost selection must be set and be a valid regexp (-s)\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
184	if (!defined($o_diode) || !(is_pattern_valid($o_diode)))
185		{ print "Diode selection must be set and be a valid regexp (-d)\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
186	if (!defined($o_nvhost))
187		{ print "Diode and vhost number must be set (-n)\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
188	my @nsbox_number=split(/,/,$o_nvhost);
189	if ($#nsbox_number != 1)
190		{ print "2 numbers must be set with -n option\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
191	if (isnnum($nsbox_number[0]) || isnnum($nsbox_number[1]))
192		{ print "2 numbers must be set with -n option\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
193	$o_ndiode=$nsbox_number[0];
194	$o_nvhost=$nsbox_number[1];
195}
196
197########## MAIN #######
198
199check_options();
200
201# Check gobal timeout if snmp screws up
202if (defined($TIMEOUT)) {
203  verb("Alarm at $TIMEOUT + 5");
204  alarm($TIMEOUT+5);
205} else {
206  verb("no global timeout defined : $o_timeout + 10");
207  alarm ($o_timeout+10);
208}
209
210# Connect to host
211my ($session,$error);
212if ( defined($o_login) && defined($o_passwd)) {
213  # SNMPv3 login
214  verb("SNMPv3 login");
215    if (!defined ($o_privpass)) {
216  verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
217    ($session, $error) = Net::SNMP->session(
218      -hostname   	=> $o_host,
219      -version		=> '3',
220      -username		=> $o_login,
221      -authpassword	=> $o_passwd,
222      -authprotocol	=> $o_authproto,
223      -timeout          => $o_timeout
224    );
225  } else {
226    verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
227    ($session, $error) = Net::SNMP->session(
228      -hostname   	=> $o_host,
229      -version		=> '3',
230      -username		=> $o_login,
231      -authpassword	=> $o_passwd,
232      -authprotocol	=> $o_authproto,
233      -privpassword	=> $o_privpass,
234	  -privprotocol => $o_privproto,
235      -timeout          => $o_timeout
236    );
237  }
238} else {
239	if (defined ($o_version2)) {
240		# SNMPv2 Login
241		verb("SNMP v2c login");
242		  ($session, $error) = Net::SNMP->session(
243		 -hostname  => $o_host,
244		 -version   => 2,
245		 -community => $o_community,
246		 -port      => $o_port,
247		 -timeout   => $o_timeout
248		);
249  	} else {
250	  # SNMPV1 login
251	  verb("SNMP v1 login");
252	  ($session, $error) = Net::SNMP->session(
253		-hostname  => $o_host,
254		-community => $o_community,
255		-port      => $o_port,
256		-timeout   => $o_timeout
257	  );
258	}
259}
260if (!defined($session)) {
261   printf("ERROR opening session: %s.\n", $error);
262   exit $ERRORS{"UNKNOWN"};
263}
264
265
266########### check global status ##############
267my @oidlist=($ns_service_status);
268my $resultat = (Net::SNMP->VERSION < 4) ?
269          $session->get_request(@oidlist)
270        : $session->get_request(-varbindlist => \@oidlist);
271
272if (!defined($resultat) || ($$resultat{$ns_service_status} eq "noSuchObject")) {
273   printf("ERROR: Global status oid not found : %s.\n", $session->error);
274   $session->close;
275   exit $ERRORS{"UNKNOWN"};
276}
277
278if ($$resultat{$ns_service_status} != 1) {
279  print "Global service is in state ",$$resultat{$ns_service_status}," : CRITICAL\n";
280  exit $ERRORS{"CRITICAL"};
281}
282
283########### check vhost & diode status ##############
284$resultat=undef;
285$resultat = (Net::SNMP->VERSION < 4) ?
286		  $session->get_table($ns_service_table)
287		: $session->get_table(Baseoid => $ns_service_table);
288
289if (!defined($resultat)) {
290   printf("ERROR: vhost and diode status table : %s.\n", $session->error);
291   $session->close;
292   exit $ERRORS{"UNKNOWN"};
293}
294$session->close;
295
296my $output="";
297my $output_perf="";
298my ($index,$name)=undef;
299my ($nvhost,$ndiode)=(0,0);
300my (@found_vhost,@found_diode)=(undef,undef);
301
302foreach my $key ( keys %$resultat) {
303	verb("OID : $key, Desc : $$resultat{$key}");
304	if ( $key =~ /($ns_vhost_table)\.(\d+)\.($ns_vhost_name)/ ) { # Get index of vhost with name
305		$index=$2;$name=$$resultat{$key};
306		if ($name =~ /$o_vhost/) {
307			$found_vhost[$nvhost++]=$name;
308			verb ("found vhost $name");
309		}
310	}
311	if ( $key =~ /($ns_diode_table)\.(\d+)\.($ns_diode_name)/ ) { # Get index of diode with name
312		$index=$2;$name=$$resultat{$key};
313		if ($name =~ /$o_diode/) {
314			# TODO Check diode status : undocumented for now.
315			$found_diode[$ndiode++]=$name;
316			verb ("found diode $name");
317		}
318	}
319}
320
321if (($ndiode<$o_ndiode) || ($nvhost<$o_nvhost)) {
322	$output = "Diode";
323	if ($ndiode == 0 ) { $output.= ": none ";}
324	else {
325		$output.= "(".$ndiode."): :";
326		for (my $i=0;$i<$ndiode;$i++) {
327			$output.=$found_diode[$i]." ";
328		}
329	}
330	$output .= "Vhost";
331	if ($nvhost == 0 ) { $output.= ": none ";}
332	else {
333		$output.= "(".$nvhost."): :";
334		for (my $i=0;$i<$nvhost;$i++) {
335		$output.=$found_vhost[$i]." ";
336		}
337	}
338	$output .= " < " . $o_ndiode .",". $o_nvhost ." : CRITICAL";
339	print $output,"\n";
340	exit $ERRORS{"CRITICAL"};
341}
342
343$output = $ndiode . " diodes, " .$nvhost." vhosts :";
344if (($ndiode>$o_ndiode) || ($nvhost>$o_nvhost)) {
345	$output .= " > " . $o_ndiode .",". $o_nvhost ." : WARNING";
346} else {
347	$output .= " OK";
348}
349print $output,"\n";
350exit $ERRORS{"OK"};
351
352