2
############################## check_snmp_win ##############
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
9
###############################################################
11
# help : ./check_snmp_win.pl -h
19
use lib "/usr/local/nagios/libexec";
20
use utils qw(%ERRORS $TIMEOUT);
22
#my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
24
# SNMP Datas for processes (MIB II)
25
my $process_table= '1.3.6.1.2.1.25.4.2.1';
26
my $index_table = '1.3.6.1.2.1.25.4.2.1.1';
27
my $run_name_table = '1.3.6.1.2.1.25.4.2.1.2';
28
my $run_path_table = '1.3.6.1.2.1.25.4.2.1.4';
29
my $proc_mem_table = '1.3.6.1.2.1.25.5.1.1.2'; # Kbytes
30
my $proc_cpu_table = '1.3.6.1.2.1.25.5.1.1.1'; # Centi sec of CPU
31
my $proc_run_state = '1.3.6.1.2.1.25.4.2.1.7';
35
my $win_serv_table = '1.3.6.1.4.1.77.1.2.3.1'; # Windows services table
36
my $win_serv_name = '1.3.6.1.4.1.77.1.2.3.1.1'; # Name of the service
37
# Install state : uninstalled(1), install-pending(2), uninstall-pending(3), installed(4)
38
my $win_serv_inst = '1.3.6.1.4.1.77.1.2.3.1.2';
39
# Operating state : active(1), continue-pending(2), pause-pending(3), paused(4)
40
my $win_serv_state = '1.3.6.1.4.1.77.1.2.3.1.3';
41
my %win_serv_state_label = ( 1 => 'active', 2=> 'continue-pending', 3=> 'pause-pending', 4=> 'paused');
42
# Can be uninstalled : cannot-be-uninstalled(1), can-be-uninstalled(2)
43
my $win_serv_uninst = '1.3.6.1.4.1.77.1.2.3.1.4';
48
my $Name='check_snmp_win';
50
my $o_host = undef; # hostname
51
my $o_community =undef; # community
52
my $o_port = 161; # port
53
my $o_version2 = undef; #use snmp v2c
54
my $o_descr = undef; # description filter
55
my @o_descrL = undef; # Service descriprion list.
56
my $o_showall = undef; # Show all services even if OK
57
my $o_type = "service"; # Check type (service, ...)
58
my $o_number = undef; # Number of service for warn and crit levels
59
my $o_help= undef; # wan't some help ?
60
my $o_verb= undef; # verbose mode
61
my $o_version= undef; # print version
62
my $o_noreg= undef; # Do not use Regexp for name
63
my $o_timeout= 5; # Default 5s Timeout
65
my $o_login= undef; # snmp v3 login
66
my $o_passwd= undef; # snmp v3 passwd
70
sub p_version { print "$Name version : $Version\n"; }
73
print "Usage: $Name [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd) [-p <port>] -n <name>[,<name2] [-T=service] [-r] [-s] [-N=<n>] [-t <timeout>] [-V]\n";
76
sub isnotnum { # Return true if arg is not a number
78
if ( $num =~ /^-?(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
82
sub is_pattern_valid { # Test for things like "<I\s*[^>" or "+5-i"
84
if (!defined($pat)) { $pat=" ";} # Just to get rid of compilation time warnings
85
return eval { "" =~ /$pat/; 1 } || 0;
88
# Get the alarm signal (just in case snmp timout screws up)
90
print ("ERROR: Alarm signal (Nagios time-out)\n");
91
exit $ERRORS{"UNKNOWN"};
95
print "\nSNMP Windows Monitor for Nagios version ",$Version,"\n";
96
print "GPL licence, (c)2004-2005 Patrick Proy\n\n";
100
print extra debugging information (and lists all services)
102
print this help message
104
name or IP address of host to check
105
-C, --community=COMMUNITY NAME
106
community name for the host's SNMP agent (implies SNMP v1 or v2c with option)
110
Login for snmpv3 authentication (implies v3 protocol with MD5)
112
Password for snmpv3 authentication
114
SNMP port (Default 161)
117
- service (default) checks service
118
-n, --name=NAME[,NAME2...]
119
Comma separated names of services (perl regular expressions can be used for every one).
120
By default, it is not case sensitive.
122
Compare matching services with <n> instead of the number of names provided.
124
Show all services in the output, instead of only the non-active ones.
126
Do not use regexp to match NAME in service description.
127
-t, --timeout=INTEGER
128
timeout for SNMP in seconds (Default: 5)
130
prints version number
132
The script will return
133
OK if ALL services are in active state,
134
WARNING if there is more than specified (ex 2 service specified, 3 active services matching),
135
CRITICAL if at least one of them is non active.
136
The -n option will allows regexp in perl format
137
-n "service" will match 'service WINS' 'sevice DNS' etc...
138
It is not case sensitive by default : WINS = wins
142
sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }
144
sub decode_utf8 { # just replaces UFT8 caracters by "."
146
if (substr($utfstr,0,2) ne "0x") { return $utfstr; }
147
my @stringL=split(//,$utfstr);
149
for (my $i=2;$i<$#stringL;$i+=2) {
150
if ( ($stringL[$i] . $stringL[$i+1]) eq "c3") {
151
$i+=2;$newstring .= ".";
153
$newstring .= chr(hex($stringL[$i] . $stringL[$i+1]));
160
Getopt::Long::Configure ("bundling");
162
'v' => \$o_verb, 'verbose' => \$o_verb,
163
'h' => \$o_help, 'help' => \$o_help,
164
'H:s' => \$o_host, 'hostname:s' => \$o_host,
165
'p:i' => \$o_port, 'port:i' => \$o_port,
166
'C:s' => \$o_community, 'community:s' => \$o_community,
167
'l:s' => \$o_login, 'login:s' => \$o_login,
168
'x:s' => \$o_passwd, 'passwd:s' => \$o_passwd,
169
't:i' => \$o_timeout, 'timeout:i' => \$o_timeout,
170
'n:s' => \$o_descr, 'name:s' => \$o_descr,
171
'r' => \$o_noreg, 'noregexp' => \$o_noreg,
172
'T:s' => \$o_type, 'type:s' => \$o_type,
173
'N:i' => \$o_number, 'number:i' => \$o_number,
174
'2' => \$o_version2, 'v2c' => \$o_version2,
175
's' => \$o_showall, 'showall' => \$o_showall,
176
'V' => \$o_version, 'version' => \$o_version
178
if (defined ($o_help)) { help(); exit $ERRORS{"UNKNOWN"}};
179
if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"}};
180
# check snmp information
181
if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) )
182
{ print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
183
# Check compulsory attributes
184
if ( $o_type ne "service" ) {
185
print "Invalid check type !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}
187
if ( ! defined($o_descr) || ! defined($o_host) ) { print_usage(); exit $ERRORS{"UNKNOWN"}};
188
@o_descrL=split(/,/,$o_descr);
189
foreach my $List (@o_descrL) {
190
if ( ! is_pattern_valid ($List) ) { print "Invalid pattern ! ";print_usage(); exit $ERRORS{"UNKNOWN"} }
192
if (defined ($o_number)) {
193
if (isnotnum($o_number) || ($o_number<0) )
194
{ print "Invalid number of services!\n";print_usage(); exit $ERRORS{"UNKNOWN"}}
199
########## MAIN #######
203
# Check gobal timeout if snmp screws up
204
if (defined($TIMEOUT)) {
205
verb("Alarm at $TIMEOUT");
208
verb("no timeout defined : $o_timeout + 10");
209
alarm ($o_timeout+10);
213
my ($session,$error);
214
if ( defined($o_login) && defined($o_passwd)) {
216
verb("SNMPv3 login");
217
($session, $error) = Net::SNMP->session(
218
-hostname => $o_host,
220
-username => $o_login,
221
-authpassword => $o_passwd,
222
-authprotocol => 'md5',
223
-privpassword => $o_passwd,
224
-timeout => $o_timeout
227
if (defined ($o_version2)) {
229
($session, $error) = Net::SNMP->session(
230
-hostname => $o_host,
232
-community => $o_community,
234
-timeout => $o_timeout
238
($session, $error) = Net::SNMP->session(
239
-hostname => $o_host,
240
-community => $o_community,
242
-timeout => $o_timeout
248
if (!defined($session)) {
249
printf("ERROR: %s.\n", $error);
250
exit $ERRORS{"UNKNOWN"};
253
$session->max_msg_size(5000);
254
verb($session->max_msg_size);
256
# Look for process in name or path name table
259
$resultat = (Net::SNMP->VERSION < 4) ?
260
$session->get_table($win_serv_name)
261
: $session->get_table(Baseoid => $win_serv_name);
263
if (!defined($resultat)) {
264
printf("ERROR: Process name table : %s.\n", $session->error);
266
exit $ERRORS{"UNKNOWN"};
274
# Select storage by regexp of exact match
275
# and put the oid to query in an array
277
verb("Filter : $o_descr");
279
foreach my $key ( keys %$resultat) {
280
my $descr_d=decode_utf8($$resultat{$key});
281
verb("Desc : $descr_d");
282
# test by regexp or exact match
284
foreach my $List (@o_descrL) {
286
$test = defined($o_noreg)
288
: $descr_d =~ /$List/i;
292
# get the full description
293
$descr[$num_int]=$descr_d;
294
# get the index number of the process
295
$key =~ s/$win_serv_name\.//;
296
$tindex[$num_int] = $key;
297
# put the oid of running state in an array.
298
$oids[$count_oid++]=$win_serv_state . "." . $tindex[$num_int];
299
verb("Name : $descr[$num_int], Index : $tindex[$num_int]");
304
if ( $num_int == 0) {
305
if (defined ($o_number) && ($o_number ==0)) {
306
print "No services ",(defined ($o_noreg)) ? "named \"" : "matching \"", $o_descr, "\" found : OK\n";
309
print "No services ",(defined ($o_noreg)) ? "named \"" : "matching \"", $o_descr, "\" found : CRITICAL\n";
310
exit $ERRORS{"CRITICAL"};
317
$result = (Net::SNMP->VERSION < 4) ?
318
$session->get_request(@oids)
319
: $session->get_request(Varbindlist => \@oids);
321
if (!defined($result)) { printf("ERROR: running table : %s.\n", $session->error); $session->close;
322
exit $ERRORS{"UNKNOWN"};
328
#Check if service are in active state
329
for (my $i=0; $i< $num_int; $i++) {
330
my $state=$$result{$win_serv_state . "." . $tindex[$i]};
331
verb ("Process $tindex[$i] in state $state");
335
$output .= ", " if defined($output);
336
$output .= $descr[$i] . " : " . $win_serv_state_label{$state};
340
my $force_critical=0;
342
# Show the services that are not present
343
# Or all of them with -s option
344
foreach my $List (@o_descrL) {
346
for (my $i=0; $i< $num_int; $i++) {
347
if ( $descr[$i] =~ /$List/i ) { $test++; }
350
$output .= ", " if defined($output);
351
$output .= "\"" . $List . "\" not active";
352
# Force a critical state (could otherwise lead to false OK)
354
} elsif ( defined ($o_showall) ) {
355
$output .= ", " if defined($output);
356
$output .= "\"" . $List . "\" active";
358
$output .= "(" .$test . " services)";
363
if (defined ($output) ) {
364
print $output, " : ";
366
print $num_int_ok, " services active (", (defined ($o_noreg)) ? "named \"" : "matching \"", $o_descr, "\") : ";
369
$o_number = $#o_descrL+1 if (!defined($o_number));
371
if (($num_int_ok < $o_number)||($force_critical == 1)) {
373
exit $ERRORS{"CRITICAL"};
374
} elsif ($num_int_ok > $o_number) {
376
exit $ERRORS{"WARNING"};