1#!/usr/local/bin/perl -w
2############################## check_snmp_int ##############
3my $Version='1.24';
4# Date : Oct 10 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 : J. Jungmann, S. Probst, R. Leroy, M. Berger
9# TODO :
10# Maybe put base directory for performance as an option
11#################################################################
12#
13# Help : ./check_snmp_int.pl -h
14#
15use strict;
16use Net::SNMP;
17use Getopt::Long;
18
19############### BASE DIRECTORY FOR TEMP FILE ########
20my $o_base_dir="/var/tmp/tmp_Nagios_int.";
21my $file_history=200;   # number of data to keep in files.
22
23# Nagios specific
24
25my $TIMEOUT = 15;
26my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
27
28# SNMP Datas
29
30my $inter_table= '.1.3.6.1.2.1.2.2.1';
31my $index_table = '1.3.6.1.2.1.2.2.1.1';
32my $descr_table = '1.3.6.1.2.1.2.2.1.2';
33my $oper_table = '1.3.6.1.2.1.2.2.1.8.';
34my $admin_table = '1.3.6.1.2.1.2.2.1.7.';
35my $speed_table = '1.3.6.1.2.1.2.2.1.5.';
36my $speed_table_64 = '1.3.6.1.2.1.31.1.1.1.15.';
37my $in_octet_table = '1.3.6.1.2.1.2.2.1.10.';
38my $in_octet_table_64 = '1.3.6.1.2.1.31.1.1.1.6.';
39my $in_error_table = '1.3.6.1.2.1.2.2.1.14.';
40my $in_discard_table = '1.3.6.1.2.1.2.2.1.13.';
41my $out_octet_table = '1.3.6.1.2.1.2.2.1.16.';
42my $out_octet_table_64 = '1.3.6.1.2.1.31.1.1.1.10.';
43my $out_error_table = '1.3.6.1.2.1.2.2.1.20.';
44my $out_discard_table = '1.3.6.1.2.1.2.2.1.19.';
45
46my %status=(1=>'UP',2=>'DOWN',3=>'TESTING',4=>'UNKNOWN',5=>'DORMANT',6=>'NotPresent',7=>'lowerLayerDown');
47
48# Globals
49
50
51# Standard options
52my $o_host = 		undef; 	# hostname
53my $o_port = 		161; 	# port
54my $o_descr = 		undef; 	# description filter
55my $o_help=		undef; 	# wan't some help ?
56my $o_admin=		undef;	# admin status instead of oper
57my $o_inverse=  	undef;	# Critical when up
58my $o_dormant=        	undef;  # Dormant state is OK
59my $o_verb=		undef;	# verbose mode
60my $o_version=		undef;	# print version
61my $o_noreg=		undef;	# Do not use Regexp for name
62my $o_short=		undef;	# set maximum of n chars to be displayed
63my $o_label=		undef;	# add label before speed (in, out, etc...).
64# Performance data options
65my $o_perf=     	undef;  # Output performance data
66my $o_perfe=		undef;	# Output discard/error also in perf data
67my $o_perfs=		undef; # include speed in performance output (-S)
68my $o_perfp=		undef; # output performance data in % of max speed (-y)
69my $o_perfr=		undef; # output performance data in bits/s or Bytes/s (-Y)
70# Speed/error checks
71my $o_checkperf=	undef;	# checks in/out/err/disc values
72my $o_delta=		300;	# delta of time of perfcheck (default 5min)
73my $o_ext_checkperf=	undef;  # extended perf checks (+error+discard)
74my $o_warn_opt=		undef;  # warning options
75my $o_crit_opt=		undef;  # critical options
76my $o_kbits=		undef;	# Warn and critical in Kbits instead of KBytes
77my @o_warn=		undef;  # warning levels of perfcheck
78my @o_crit=		undef;  # critical levels of perfcheck
79my $o_highperf=		undef;	# Use 64 bits counters
80my $o_meg=		undef; # output in MBytes or Mbits (-M)
81my $o_gig=		undef; # output in GBytes or Gbits (-G)
82my $o_prct=		undef; # output in % of max speed  (-u)
83
84my $o_timeout=  undef; 		# Timeout (Default 5)
85# SNMP Message size parameter (Makina Corpus contrib)
86my $o_octetlength=undef;
87# Login options specific
88my $o_community = 	undef; 	# community
89my $o_version2	= undef;	#use snmp v2c
90my $o_login=	undef;		# Login for snmpv3
91my $o_passwd=	undef;		# Pass for snmpv3
92my $v3protocols=undef;	# V3 protocol list.
93my $o_authproto='md5';		# Auth protocol
94my $o_privproto='des';		# Priv protocol
95my $o_privpass= undef;		# priv password
96
97# Readable names for counters (M. Berger contrib)
98my @countername = ( "in=" , "out=" , "errors-in=" , "errors-out=" , "discard-in=" , "discard-out=" );
99my $checkperf_out_desc;
100
101# functions
102
103sub read_file {
104	# Input : File, items_number
105	# Returns : array of value : [line][item]
106  my ($traffic_file,$items_number)=@_;
107  my ($ligne,$n_rows)=(undef,0);
108  my (@last_values,@file_values,$i);
109  open(FILE,"<".$traffic_file) || return (1,0,0);
110
111  while($ligne = <FILE>)
112  {
113    chomp($ligne);
114    @file_values = split(":",$ligne);
115    #verb("@file_values");
116    if ($#file_values >= ($items_number-1)) {
117	# check if there is enough data, else ignore line
118      for ( $i=0 ; $i< $items_number ; $i++ ) {$last_values[$n_rows][$i]=$file_values[$i];}
119      $n_rows++;
120    }
121  }
122  close FILE;
123  if ($n_rows != 0) {
124    return (0,$n_rows,@last_values);
125  } else {
126    return (1,0,0);
127  }
128}
129
130sub write_file {
131  	# Input : file , rows, items, array of value : [line][item]
132        # Returns : 0 / OK, 1 / error
133  my ($file_out,$rows,$item,@file_values)=@_;
134  my $start_line= ($rows > $file_history) ? $rows -  $file_history : 0;
135  if ( open(FILE2,">".$file_out) ) {
136    for (my $i=$start_line;$i<$rows;$i++) {
137      for (my $j=0;$j<$item;$j++) {
138	print FILE2 $file_values[$i][$j];
139	if ($j != ($item -1)) { print FILE2 ":" };
140      }
141      print FILE2 "\n";
142    }
143    close FILE2;
144    return 0;
145  } else {
146    return 1;
147  }
148}
149
150sub p_version { print "check_snmp_int version : $Version\n"; }
151
152sub print_usage {
153    print "Usage: $0 [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>)  [-p <port>] -n <name in desc_oid> [-i -a -D] [-r] [-f[eSyY]] [-k[qBMGu] -g -w<warn levels> -c<crit levels> -d<delta>] [-o <octet_length>] [-t <timeout>] [-s] --label [-V]\n";
154}
155
156sub isnnum { # Return true if arg is not a number
157  my $num = shift;
158  if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
159  return 1;
160}
161
162sub help {
163   print "\nSNMP Network Interface Monitor for Nagios version ",$Version,"\n";
164   print "GPL licence, (c)2004-2007 Patrick Proy\n\n";
165   print_usage();
166   print <<EOT;
167-v, --verbose
168   print extra debugging information (including interface list on the system)
169-h, --help
170   print this help message
171-H, --hostname=HOST
172   name or IP address of host to check
173-C, --community=COMMUNITY NAME
174   community name for the host's SNMP agent (implies v1 protocol)
175-l, --login=LOGIN ; -x, --passwd=PASSWD, -2, --v2c
176   Login and auth password for snmpv3 authentication
177   If no priv password exists, implies AuthNoPriv
178   -2 : use snmp v2c
179-X, --privpass=PASSWD
180   Priv password for snmpv3 (AuthPriv protocol)
181-L, --protocols=<authproto>,<privproto>
182   <authproto> : Authentication protocol (md5|sha : default md5)
183   <privproto> : Priv protocole (des|aes : default des)
184-P, --port=PORT
185   SNMP port (Default 161)
186-n, --name=NAME
187   Name in description OID (eth0, ppp0 ...).
188   This is treated as a regexp : -n eth will match eth0,eth1,...
189   Test it before, because there are known bugs (ex : trailling /)
190-r, --noregexp
191   Do not use regexp to match NAME in description OID
192-i, --inverse
193   Make critical when up
194-a, --admin
195   Use administrative status instead of operational
196-D, --dormant
197   Dormant state is an OK state
198-o, --octetlength=INTEGER
199  max-size of the SNMP message, usefull in case of Too Long responses.
200  Be carefull with network filters. Range 484 - 65535, default are
201  usually 1472,1452,1460 or 1440.
202-f, --perfparse
203   Perfparse compatible output (no output when interface is down).
204-e, --error
205   Add error & discard to Perfparse output
206-S, --intspeed
207   Include speed in performance output in bits/s
208-y, --perfprct ; -Y, --perfspeed
209   -y : output performance data in % of max speed
210   -Y : output performance data in bits/s or Bytes/s (depending on -B)
211-k, --perfcheck ; -q, --extperfcheck
212   -k check the input/ouput bandwidth of the interface
213   -q also check the error and discard input/output
214--label
215   Add label before speed in output : in=, out=, errors-out=, etc...
216-g, --64bits
217   Use 64 bits counters instead of the standard counters when checking
218   bandwidth & performance data for interface >= 1Gbps.
219   You must use snmp v2c or v3 to get 64 bits counters.
220-d, --delta=seconds
221   make an average of <delta> seconds (default 300=5min)
222-B, --kbits
223   Make the warning and critical levels in K|M|G Bits/s instead of K|M|G Bytes/s
224-G, --giga ; -M, --mega ; -u, --prct
225   -G : Make the warning and critical levels in Gbps (with -B) or GBps
226   -M : Make the warning and critical levels in Mbps (with -B) or MBps
227   -u : Make the warning and critical levels in % of reported interface speed.
228-w, --warning=input,output[,error in,error out,discard in,discard out]
229   warning level for input / output bandwidth (0 for no warning)
230     unit depends on B,M,G,u options
231   warning for error & discard input / output in error/min (need -q)
232-c, --critical=input,output[,error in,error out,discard in,discard out]
233   critical level for input / output bandwidth (0 for no critical)
234     unit depends on B,M,G,u options
235   critical for error & discard input / output in error/min (need -q)
236-s, --short=int
237   Make the output shorter : only the first <n> chars of the interface(s)
238   If the number is negative, then get the <n> LAST caracters.
239-t, --timeout=INTEGER
240   timeout for SNMP in seconds (Default: 5)
241-V, --version
242   prints version number
243Note : when multiple interface are selected with regexp,
244       all be must be up (or down with -i) to get an OK result.
245EOT
246}
247
248# For verbose output
249sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }
250
251sub check_options {
252    Getopt::Long::Configure ("bundling");
253	GetOptions(
254   	'v'	=> \$o_verb,		'verbose'	=> \$o_verb,
255        'h'     => \$o_help,    	'help'        	=> \$o_help,
256        'H:s'   => \$o_host,		'hostname:s'	=> \$o_host,
257        'p:i'   => \$o_port,   		'port:i'	=> \$o_port,
258	'n:s'   => \$o_descr,           'name:s'        => \$o_descr,
259        'C:s'   => \$o_community,	'community:s'	=> \$o_community,
260		'2'	=> \$o_version2,	'v2c'		=> \$o_version2,
261	'l:s'	=> \$o_login,		'login:s'	=> \$o_login,
262	'x:s'	=> \$o_passwd,		'passwd:s'	=> \$o_passwd,
263	'X:s'	=> \$o_privpass,		'privpass:s'	=> \$o_privpass,
264	'L:s'	=> \$v3protocols,		'protocols:s'	=> \$v3protocols,
265        't:i'   => \$o_timeout,    	'timeout:i'	=> \$o_timeout,
266	'i'	=> \$o_inverse,		'inverse'	=> \$o_inverse,
267	'a'	=> \$o_admin,		'admin'		=> \$o_admin,
268	'r'	=> \$o_noreg,		'noregexp'	=> \$o_noreg,
269	'V'	=> \$o_version,		'version'	=> \$o_version,
270        'f'     => \$o_perf,            'perfparse'     => \$o_perf,
271        'e'     => \$o_perfe,           'error'     	=> \$o_perfe,
272        'k'     => \$o_checkperf,       'perfcheck'   	=> \$o_checkperf,
273        'q'     => \$o_ext_checkperf,   'extperfcheck'  => \$o_ext_checkperf,
274        'w:s'   => \$o_warn_opt,       	'warning:s'   	=> \$o_warn_opt,
275        'c:s'   => \$o_crit_opt,      	'critical:s'   	=> \$o_crit_opt,
276        'B'     => \$o_kbits,   'kbits'  => \$o_kbits,
277        's:i'   => \$o_short,      	'short:i'   	=> \$o_short,
278        'g'   	=> \$o_highperf,      	'64bits'   	=> \$o_highperf,
279        'S'   	=> \$o_perfs,      	'intspeed'   	=> \$o_perfs,
280        'y'   	=> \$o_perfp,      	'perfprct'   	=> \$o_perfp,
281        'Y'   	=> \$o_perfr,      	'perfspeed'   	=> \$o_perfr,
282        'M'   	=> \$o_meg,      	'mega'   	=> \$o_meg,
283        'G'   	=> \$o_gig,      	'giga'   	=> \$o_gig,
284        'u'   	=> \$o_prct,      	'prct'   	=> \$o_prct,
285		'o:i'   => \$o_octetlength,    	'octetlength:i' => \$o_octetlength,
286		'label'   => \$o_label,
287        'd:i'   => \$o_delta,           'delta:i'     	=> \$o_delta,
288	'D'   => \$o_dormant,           'dormant'             => \$o_dormant
289    );
290    if (defined ($o_help) ) { help(); exit $ERRORS{"UNKNOWN"}};
291    if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"}};
292    if ( ! defined($o_descr) ||  ! defined($o_host) ) # check host and filter
293	{ print_usage(); exit $ERRORS{"UNKNOWN"}}
294    # check snmp information
295    if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) )
296	{ print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
297	if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) )
298	{ print "Can't mix snmp v1,2c,3 protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
299	if (defined ($v3protocols)) {
300	  if (!defined($o_login)) { print "Put snmp V3 login info with protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
301	  my @v3proto=split(/,/,$v3protocols);
302	  if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {$o_authproto=$v3proto[0];	}	# Auth protocol
303	  if (defined ($v3proto[1])) {$o_privproto=$v3proto[1];	}	# Priv  protocol
304	  if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
305	    print "Put snmp V3 priv login info with priv protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
306	}
307	if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60)))
308	  { print "Timeout must be >1 and <60 !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
309	if (!defined($o_timeout)) {$o_timeout=5;}
310    # Check snmpv2c or v3 with 64 bit counters
311    if ( defined ($o_highperf) && (!defined($o_version2) && defined($o_community)))
312      { print "Can't get 64 bit counters with snmp version 1\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
313    if (defined ($o_highperf)) {
314      if (eval "require bigint") {
315        use bigint;
316      } else  { print "Need bigint module for 64 bit counters\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
317    }
318
319    # check if -e without -f
320    if ( defined($o_perfe) && !defined($o_perf))
321        { print "Cannot output error without -f option!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
322	if (defined ($o_perfr) && defined($o_perfp) )  {
323	    print "-Y and -y options are exclusives\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
324	if ((defined ($o_perfr) || defined($o_perfp) ) && !defined($o_checkperf))  {
325	    print "Cannot put -Y or -y options without perf check option (-k) \n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
326    if (defined ($o_short)) {
327      #TODO maybe some basic tests ? caracters return empty string
328    }
329    if (defined ($o_checkperf)) {
330      @o_warn=split(/,/,$o_warn_opt);
331      if (defined($o_ext_checkperf) && ($#o_warn != 5)) {
332        print "6 warning levels for extended checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}
333      }
334      if (!defined($o_ext_checkperf) &&($#o_warn !=1 )){
335	print "2 warning levels for bandwidth checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}
336      }
337      @o_crit=split(/,/,$o_crit_opt);
338      #verb(" $o_crit_opt :: $#o_crit : @o_crit");
339      if (defined($o_ext_checkperf) && ($#o_crit != 5)) {
340        print "6 critical levels for extended checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}
341      }
342      if (!defined($o_ext_checkperf) && ($#o_crit !=1 )) {
343	print "2 critical levels for bandwidth checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}
344      }
345      for (my $i=0;$i<=$#o_warn;$i++) {
346        if (($o_crit[$i]!=0)&&($o_warn[$i] > $o_crit[$i])) {
347          print "Warning must be < Critical level \n"; print_usage(); exit $ERRORS{"UNKNOWN"}
348        }
349      }
350	  if ((defined ($o_meg) && defined($o_gig) ) || (defined ($o_meg) && defined($o_prct) )|| (defined ($o_gig) && defined($o_prct) )) {
351	    print "-M -G and -u options are exclusives\n"; print_usage(); exit $ERRORS{"UNKNOWN"}
352	  }
353    }
354    #### octet length checks
355    if (defined ($o_octetlength) && (isnnum($o_octetlength) || $o_octetlength > 65535 || $o_octetlength < 484 )) {
356		print "octet lenght must be < 65535 and > 484\n";print_usage(); exit $ERRORS{"UNKNOWN"};
357    }
358}
359
360########## MAIN #######
361
362check_options();
363
364# Check gobal timeout if snmp screws up
365if (defined($TIMEOUT)) {
366  verb("Alarm at $TIMEOUT + 5");
367  alarm($TIMEOUT+5);
368} else {
369  verb("no timeout defined : $o_timeout + 10");
370  alarm ($o_timeout+10);
371}
372
373$SIG{'ALRM'} = sub {
374 print "No answer from host\n";
375 exit $ERRORS{"UNKNOWN"};
376};
377
378# Connect to host
379my ($session,$error);
380if ( defined($o_login) && defined($o_passwd)) {
381  # SNMPv3 login
382  if (!defined ($o_privpass)) {
383  verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
384    ($session, $error) = Net::SNMP->session(
385      -hostname   	=> $o_host,
386      -version		=> '3',
387      -port      	=> $o_port,
388      -username		=> $o_login,
389      -authpassword	=> $o_passwd,
390      -authprotocol	=> $o_authproto,
391      -timeout          => $o_timeout
392    );
393  } else {
394    verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
395    ($session, $error) = Net::SNMP->session(
396      -hostname   	=> $o_host,
397      -version		=> '3',
398      -username		=> $o_login,
399      -port      	=> $o_port,
400      -authpassword	=> $o_passwd,
401      -authprotocol	=> $o_authproto,
402      -privpassword	=> $o_privpass,
403	  -privprotocol => $o_privproto,
404      -timeout          => $o_timeout
405    );
406  }
407} else {
408  if (defined ($o_version2)) {
409    # SNMPv2c Login
410	verb("SNMP v2c login");
411	($session, $error) = Net::SNMP->session(
412       -hostname  => $o_host,
413	   -version   => 2,
414       -community => $o_community,
415       -port      => $o_port,
416       -timeout   => $o_timeout
417    );
418  } else {
419    # SNMPV1 login
420	verb("SNMP v1 login");
421    ($session, $error) = Net::SNMP->session(
422       -hostname  => $o_host,
423       -community => $o_community,
424       -port      => $o_port,
425       -timeout   => $o_timeout
426    );
427  }
428}
429if (!defined($session)) {
430   printf("ERROR opening session: %s.\n", $error);
431   exit $ERRORS{"UNKNOWN"};
432}
433
434if (defined($o_octetlength)) {
435	my $oct_resultat=undef;
436	my $oct_test= $session->max_msg_size();
437	verb(" actual max octets:: $oct_test");
438	$oct_resultat = $session->max_msg_size($o_octetlength);
439	if (!defined($oct_resultat)) {
440		 printf("ERROR: Session settings : %s.\n", $session->error);
441		 $session->close;
442		 exit $ERRORS{"UNKNOWN"};
443	}
444	$oct_test= $session->max_msg_size();
445	verb(" new max octets:: $oct_test");
446}
447
448# Get desctiption table
449my $resultat = $session->get_table(
450	Baseoid => $descr_table
451);
452
453if (!defined($resultat)) {
454   printf("ERROR: Description table : %s.\n", $session->error);
455   $session->close;
456   exit $ERRORS{"UNKNOWN"};
457}
458my @tindex = undef;
459my @oids = undef;
460my @descr = undef;
461my (@oid_perf,@oid_perf_outoct,@oid_perf_inoct,@oid_perf_inerr,@oid_perf_outerr,@oid_perf_indisc,@oid_perf_outdisc)=
462   (undef,undef,undef,undef,undef,undef,undef);
463my @oid_speed=undef;
464my @oid_speed_high=undef;
465my $num_int = 0;
466
467# Change to 64 bit counters if option is set :
468if (defined($o_highperf)) {
469  $out_octet_table=$out_octet_table_64;
470  $in_octet_table=$in_octet_table_64;
471}
472
473
474# Select interface by regexp of exact match
475# and put the oid to query in an array
476
477verb("Filter : $o_descr");
478foreach my $key ( keys %$resultat) {
479   verb("OID : $key, Desc : $$resultat{$key}");
480   # test by regexp or exact match
481   my $test = defined($o_noreg)
482		? $$resultat{$key} eq $o_descr
483		: $$resultat{$key} =~ /$o_descr/;
484  if ($test) {
485     # get the index number of the interface
486     my @oid_list = split (/\./,$key);
487     $tindex[$num_int] = pop (@oid_list);
488     # get the full description
489     $descr[$num_int]=$$resultat{$key};
490     # Get rid of special caracters (specially for Windows)
491     $descr[$num_int] =~ s/[[:cntrl:]]//g;
492     # put the admin or oper oid in an array
493     $oids[$num_int]= defined ($o_admin) ? $admin_table . $tindex[$num_int]
494			: $oper_table . $tindex[$num_int] ;
495     # Put the performance oid
496     if (defined($o_perf) || defined($o_checkperf)) {
497       $oid_perf_inoct[$num_int]= $in_octet_table . $tindex[$num_int];
498       $oid_perf_outoct[$num_int]= $out_octet_table . $tindex[$num_int];
499       $oid_speed[$num_int]=$speed_table . $tindex[$num_int];
500       $oid_speed_high[$num_int]=$speed_table_64 . $tindex[$num_int];
501       if (defined($o_ext_checkperf) || defined($o_perfe)) {
502	 $oid_perf_indisc[$num_int]= $in_discard_table . $tindex[$num_int];
503	 $oid_perf_outdisc[$num_int]= $out_discard_table . $tindex[$num_int];
504	 $oid_perf_inerr[$num_int]= $in_error_table . $tindex[$num_int];
505	 $oid_perf_outerr[$num_int]= $out_error_table . $tindex[$num_int];
506       }
507     }
508     verb("Name : $descr[$num_int], Index : $tindex[$num_int]");
509     $num_int++;
510  }
511}
512# No interface found -> error
513if ( $num_int == 0 ) { print "ERROR : Unknown interface $o_descr\n" ; exit $ERRORS{"UNKNOWN"};}
514
515my $result=undef;
516# Add performance oids if requested
517if (defined($o_perf)||defined($o_checkperf)) {
518  @oids=(@oids,@oid_perf_outoct,@oid_perf_inoct,@oid_speed);
519  if (defined($o_highperf)) {
520    @oids=(@oids,@oid_speed_high);
521  }
522  if (defined ($o_ext_checkperf) || defined($o_perfe)) {
523    @oids=(@oids,@oid_perf_inerr,@oid_perf_outerr,@oid_perf_indisc,@oid_perf_outdisc);
524  }
525}
526
527# Get the requested oid values
528$result = $session->get_request(
529   Varbindlist => \@oids
530);
531if (!defined($result)) { printf("ERROR: Status/statistics table : %s.\n", $session->error); $session->close;
532   exit $ERRORS{"UNKNOWN"};
533}
534
535$session->close;
536
537my $num_ok=0;
538my @checkperf_out=undef;
539my @checkperf_out_raw=undef;
540### Bandwidth test variables
541my $temp_file_name;
542my ($return,@file_values)=(undef,undef);
543my $n_rows=0;
544my $n_items_check=(defined($o_ext_checkperf))?7:3;
545my $timenow=time;
546my $trigger=$timenow - ($o_delta - ($o_delta/10));
547my $trigger_low=$timenow - 3*$o_delta;
548my ($old_value,$old_time)=undef;
549my $speed_unit=undef;
550my $speed_real=undef; # speed of interface using either standard or highperf mib.
551
552# define the OK value depending on -i option
553my $ok_val= defined ($o_inverse) ? 2 : 1;
554my $final_status = 0;
555my ($print_out,$perf_out)=(undef,undef);
556
557# make all checks and output for all interfaces
558for (my $i=0;$i < $num_int; $i++) {
559  $print_out.=", " if (defined($print_out));
560  $perf_out .= " " if (defined ($perf_out)) ;
561  my $usable_data=1;
562  # Get the status of the current interface
563  my $int_status= defined ($o_admin) ? $$result{$admin_table . $tindex[$i]}
564		:  $$result{ $oper_table . $tindex[$i] };
565
566  # Make the bandwith & error checks if necessary
567  if (defined ($o_checkperf) && $int_status==1) {
568    $temp_file_name=$descr[$i];
569    $temp_file_name =~ s/[ ;\/]/_/g;
570    $temp_file_name = $o_base_dir . $o_host ."." . $temp_file_name;
571    # First, read entire file
572    my @ret_array=read_file($temp_file_name,$n_items_check);
573    $return = shift(@ret_array);
574    $n_rows = shift(@ret_array);
575    if ($n_rows != 0) { @file_values = @ret_array };
576    verb ("File read returns : $return with $n_rows rows");
577    # Get the speed in normal or highperf speed counters
578    if ($$result{$oid_speed[$i]} == 4294967295) { # Too high for this counter (cf IF-MIB)
579       if (! defined($o_highperf) && (defined($o_prct) || defined ($o_perfs) || defined ($o_perfp))) {
580          print "Cannot get interface speed with standard MIB, use highperf mib (-g) : UNKNOWN\n";
581	  exit $ERRORS{"UNKNOWN"}
582 	}
583       if (defined ($$result{$oid_speed_high[$i]}) && $$result{$oid_speed_high[$i]} != 0) {
584	  $speed_real=$$result{$oid_speed_high[$i]} * 1000000;
585       } else {
586          print "Cannot get interface speed using highperf mib : UNKNOWN\n";
587          exit $ERRORS{"UNKNOWN"}
588	}
589    } else {
590      $speed_real=$$result{$oid_speed[$i]};
591    }
592    verb ("Interface speed : $speed_real");
593    #make the checks if the file is OK
594    if ($return ==0) {
595      my $j=$n_rows-1;
596      @checkperf_out=undef;
597	  @checkperf_out_raw=undef;
598      do {
599	if ($file_values[$j][0] < $trigger) {
600	  if ($file_values[$j][0] > $trigger_low) {
601		# Define the speed metric ( K | M | G ) (Bits|Bytes) or %
602		my $speed_metric=undef;
603		if (defined($o_prct)) { # in % of speed
604		  # Speed is in bits/s, calculated speed is in Bytes/s
605		  $speed_metric=$speed_real/800;
606		  $speed_unit="%";
607		} else {
608		  if (defined($o_kbits)) { # metric in bits
609		    if (defined($o_meg)) { # in Mbit/s = 1000000 bit/s
610			  $speed_metric=125000; #  (1000/8) * 1000
611			  $speed_unit="Mbps";
612		    } elsif (defined($o_gig)) { # in Gbit/s = 1000000000 bit/s
613			  $speed_metric=125000000; #  (1000/8) * 1000 * 1000
614			  $speed_unit="Gbps";
615			} else { # in Kbits
616			  $speed_metric=125; #  ( 1000/8 )
617			  $speed_unit="Kbps";
618			}
619		  } else { # metric in byte
620		    if (defined($o_meg)) { # in Mbits
621			  $speed_metric=1048576; # 1024^2
622			  $speed_unit="MBps";
623		    } elsif (defined($o_gig)) { # in Mbits
624			  $speed_metric=1073741824; # 1024^3
625			  $speed_unit="GBps";
626			} else {
627			  $speed_metric=1024; # 1024^3
628			  $speed_unit="KBps";
629			}
630		  }
631		}
632	    # check if the counter is back to 0 after 2^32 / 2^64.
633		# First set the modulus depending on highperf counters or not
634		my $overfl_mod = defined ($o_highperf) ? 18446744073709551616 : 4294967296;
635	    # Check counter (s)
636		my $overfl = ($$result{$oid_perf_inoct[$i]} >= $file_values[$j][1] ) ? 0 : $overfl_mod;
637	    $checkperf_out_raw[0] = ( ($overfl + $$result{$oid_perf_inoct[$i]} - $file_values[$j][1])/
638	      			      ($timenow - $file_values[$j][0] ));
639		$checkperf_out[0] = $checkperf_out_raw[0] / $speed_metric;
640
641	    $overfl = ($$result{$oid_perf_outoct[$i]} >= $file_values[$j][2] ) ? 0 : $overfl_mod;
642		$checkperf_out_raw[1] = ( ($overfl + $$result{$oid_perf_outoct[$i]} - $file_values[$j][2])/
643				      ($timenow - $file_values[$j][0] ));
644	    $checkperf_out[1] = $checkperf_out_raw[1] / $speed_metric;
645
646	    if (defined($o_ext_checkperf)) {
647	      $checkperf_out[2] = ( ($$result{$oid_perf_inerr[$i]} - $file_values[$j][3])/
648				($timenow - $file_values[$j][0] ))*60;
649	      $checkperf_out[3] = ( ($$result{$oid_perf_outerr[$i]} - $file_values[$j][4])/
650				($timenow - $file_values[$j][0] ))*60;
651	      $checkperf_out[4] = ( ($$result{$oid_perf_indisc[$i]} - $file_values[$j][5])/
652				($timenow - $file_values[$j][0] ))*60;
653	      $checkperf_out[5] = ( ($$result{$oid_perf_outdisc[$i]} - $file_values[$j][6])/
654				($timenow - $file_values[$j][0] ))*60;
655	    }
656	  }
657	}
658	$j--;
659      } while ( ($j>=0) && (!defined($checkperf_out[0])) );
660    }
661    # Put the new values in the array and write the file
662    $file_values[$n_rows][0]=$timenow;
663    $file_values[$n_rows][1]=$$result{$oid_perf_inoct[$i]};
664    $file_values[$n_rows][2]=$$result{$oid_perf_outoct[$i]};
665    if (defined($o_ext_checkperf)) { # Add other values (error & disc)
666      $file_values[$n_rows][3]=$$result{$oid_perf_inerr[$i]};
667      $file_values[$n_rows][4]=$$result{$oid_perf_outerr[$i]};
668      $file_values[$n_rows][5]=$$result{$oid_perf_indisc[$i]};
669      $file_values[$n_rows][6]=$$result{$oid_perf_outdisc[$i]};
670    }
671    $n_rows++;
672    $return=write_file($temp_file_name,$n_rows,$n_items_check,@file_values);
673    verb ("Write file returned : $return");
674    # Print the basic status
675    if (defined ($o_short)) {
676      my $short_desc=undef;
677      if ($o_short < 0) {$short_desc=substr($descr[$i],$o_short);}
678      else {$short_desc=substr($descr[$i],0,$o_short);}
679      $print_out.=sprintf("%s:%s",$short_desc, $status{$int_status} );
680    } else {
681      $print_out.=sprintf("%s:%s",$descr[$i], $status{$int_status} );
682    }
683    if ($return !=0) { # On error writing, return Unknown status
684      $final_status=3;
685      $print_out.= " !!Unable to write file ".$temp_file_name." !! ";
686    }
687    # print the other checks if it was calculated
688    if (defined($checkperf_out[0])) {
689      $print_out.= " (";
690      # check 2 or 6 values depending on ext_check_perf
691      my $num_checkperf=(defined($o_ext_checkperf))?6:2;
692      for (my $l=0;$l < $num_checkperf;$l++) {
693	    # Set labels if needed
694	    $checkperf_out_desc= (defined($o_label)) ? $countername[$l] : "";
695	    verb("Interface $i, check $l : $checkperf_out[$l]");
696        if ($l!=0) {$print_out.="/";}
697	    if (($o_crit[$l]!=0) && ($checkperf_out[$l]>$o_crit[$l])) {
698          $final_status=2;
699          $print_out.= sprintf("CRIT %s%.1f",$checkperf_out_desc,$checkperf_out[$l]);
700        } elsif (($o_warn[$l]!=0) && ($checkperf_out[$l]>$o_warn[$l])) {
701	      $final_status=($final_status==2)?2:1;
702          $print_out.= sprintf("WARN %s%.1f",$checkperf_out_desc,$checkperf_out[$l]);
703	    } else {
704          $print_out.= sprintf("%s%.1f",$checkperf_out_desc,$checkperf_out[$l]);
705	    }
706	    if ( $l==0 || $l == 1) { $print_out.= $speed_unit; }
707     }
708      $print_out .= ")";
709    } else { # Return unknown when no data
710      $print_out.= " No usable data on file (".$n_rows." rows) ";
711      $final_status=3;$usable_data=0;
712    }
713  } else {
714    if (defined ($o_short)) {
715      my $short_desc=undef;
716      if ($o_short < 0) {$short_desc=substr($descr[$i],$o_short);}
717      else {$short_desc=substr($descr[$i],0,$o_short);}
718      $print_out.=sprintf("%s:%s",$short_desc, $status{$int_status} );
719    } else {
720      $print_out.=sprintf("%s:%s",$descr[$i], $status{$int_status} );
721    }
722  }
723  # Get rid of special caracters for performance in description
724  $descr[$i] =~ s/'\/\(\)/_/g;
725  if (( $int_status == $ok_val)||(defined($o_dormant) && $int_status == 5)) {
726    $num_ok++;
727  }
728  if (( $int_status == 1 ) && defined ($o_perf)) {
729    if (defined ($o_perfp)) { # output in % of speed
730	  if ($usable_data==1) {
731	     my $warn_factor=1;
732	     if (!defined($o_prct)) { # warn&crit in K|M|G B|bps -> put warn_factor to make %
733		$warn_factor = (defined($o_meg)) ? 1000000 : (defined($o_gig)) ? 1000000000 : 1000;
734		if (!defined($o_kbits)) { $warn_factor*=8;}
735		$warn_factor/=$speed_real;
736		$warn_factor*=100; # now turn into displayed % : 0,1 = 10%
737	     }
738	    $perf_out .= "'" . $descr[$i] ."_in_prct'=";
739		$perf_out .= sprintf("%.0f",$checkperf_out_raw[0] * 800 / $speed_real) ."%;";
740		$perf_out .= ($o_warn[0]!=0) ? sprintf("%.0f",$o_warn[0]*$warn_factor) . ";" : ";";
741		$perf_out .= ($o_crit[0]!=0) ? sprintf("%.0f",$o_crit[0]*$warn_factor) . ";" : ";";
742		$perf_out .= "0;100 ";
743	    $perf_out .= "'" . $descr[$i] ."_out_prct'=";
744		$perf_out .= sprintf("%.0f",$checkperf_out_raw[1] * 800 / $speed_real) ."%;";
745		$perf_out .= ($o_warn[1]!=0) ? sprintf("%.0f",$o_warn[1]*$warn_factor) . ";" : ";";
746		$perf_out .= ($o_crit[1]!=0) ? sprintf("%.0f",$o_crit[1]*$warn_factor) . ";" : ";";
747		$perf_out .= "0;100 ";
748	  }
749	} elsif (defined ($o_perfr)) { # output in bites or Bytes /s
750	  if ($usable_data==1) {
751  	    if (defined($o_kbits)) { # bps
752		  # put warning and critical levels into bps or Bps
753		  my $warn_factor;
754		  if (defined($o_prct)) { # warn&crit in % -> put warn_factor to 1% of speed in bps
755			$warn_factor=$speed_real/100;
756		  } else { # just convert from K|M|G bps
757			$warn_factor = (defined($o_meg)) ? 1000000 : (defined($o_gig)) ? 1000000000 : 1000;
758		  }
759	      $perf_out .= "'" . $descr[$i] ."_in_bps'=";
760          $perf_out .= sprintf("%.0f",$checkperf_out_raw[0] * 8) .";";
761		  $perf_out .= ($o_warn[0]!=0) ? $o_warn[0]*$warn_factor . ";" : ";";
762		  $perf_out .= ($o_crit[0]!=0) ? $o_crit[0]*$warn_factor . ";" : ";";
763		  $perf_out .= "0;". $speed_real ." ";
764	      $perf_out .= "'" . $descr[$i] ."_out_bps'=";
765          $perf_out .= sprintf("%.0f",$checkperf_out_raw[1] * 8) .";";
766		  $perf_out .= ($o_warn[1]!=0) ? $o_warn[1]*$warn_factor . ";" : ";";
767		  $perf_out .= ($o_crit[1]!=0) ? $o_crit[1]*$warn_factor . ";" : ";";
768		  $perf_out .= "0;". $speed_real ." ";
769	    } else { # Bps
770                  my $warn_factor;
771                  if (defined($o_prct)) { # warn&crit in % -> put warn_factor to 1% of speed in Bps
772                        $warn_factor=$speed_real/800;
773                  } else { # just convert from K|M|G bps
774			$warn_factor = (defined($o_meg)) ? 1048576 : (defined($o_gig)) ? 1073741824 : 1024;
775		  }
776	      $perf_out .= "'" . $descr[$i] ."_in_Bps'=" . sprintf("%.0f",$checkperf_out_raw[0]) .";";
777		  $perf_out .= ($o_warn[0]!=0) ? $o_warn[0]*$warn_factor . ";" : ";";
778		  $perf_out .= ($o_crit[0]!=0) ? $o_crit[0]*$warn_factor . ";" : ";";
779		  $perf_out .= "0;". $speed_real / 8 ." ";
780	      $perf_out .= "'" . $descr[$i] ."_out_Bps'=" . sprintf("%.0f",$checkperf_out_raw[1]) .";" ;
781		  $perf_out .= ($o_warn[1]!=0) ? $o_warn[1]*$warn_factor . ";" : ";";
782		  $perf_out .= ($o_crit[1]!=0) ? $o_crit[1]*$warn_factor . ";" : ";";
783		  $perf_out .= "0;". $speed_real / 8 ." ";
784	    }
785	  }
786	} else { # output in octet counter
787      $perf_out .= "'" . $descr[$i] ."_in_octet'=". $$result{$oid_perf_inoct[$i]} ."c ";
788      $perf_out .= "'" . $descr[$i] ."_out_octet'=". $$result{$oid_perf_outoct[$i]} ."c ";
789	}
790    if (defined ($o_perfe)) {
791      $perf_out .= "'" . $descr[$i] ."_in_error'=". $$result{$oid_perf_inerr[$i]} ."c ";
792      $perf_out .= "'" . $descr[$i] ."_in_discard'=". $$result{$oid_perf_indisc[$i]} ."c ";
793      $perf_out .= "'" . $descr[$i] ."_out_error'=". $$result{$oid_perf_outerr[$i]} ."c ";
794      $perf_out .= "'" . $descr[$i] ."_out_discard'=". $$result{$oid_perf_outdisc[$i]} ."c ";
795    }
796	if (defined ($o_perfs)) {
797	  $perf_out .= "'" . $descr[$i] ."_speed_bps'=".$speed_real;
798	}
799  }
800}
801
802# Only a few ms left...
803alarm(0);
804
805# Check if all interface are OK
806if ($num_ok == $num_int) {
807  if ($final_status==0) {
808    print $print_out,":", $num_ok, " UP: OK";
809    if (defined ($o_perf)) { print " | ",$perf_out; }
810    print "\n";
811    exit $ERRORS{"OK"};
812  } elsif ($final_status==1) {
813    print $print_out,":(", $num_ok, " UP): WARNING";
814    if (defined ($o_perf)) { print " | ",$perf_out; }
815    print "\n";
816    exit $ERRORS{"WARNING"};
817  } elsif ($final_status==2) {
818    print $print_out,":(", $num_ok, " UP): CRITICAL";
819    if (defined ($o_perf)) { print " | ",$perf_out; }
820    print "\n";
821    exit $ERRORS{"CRITICAL"};
822  } else {
823    print $print_out,":(", $num_ok, " UP): UNKNOWN";
824    if (defined ($perf_out)) { print " | ",$perf_out; }
825    print "\n";
826    exit $ERRORS{"UNKNOWN"};
827  }
828}
829
830# else print the not OK interface number and exit (return is always critical if at least one int is down).
831
832print $print_out,": ", $num_int-$num_ok, " int NOK : CRITICAL";
833if (defined ($perf_out)) { print " | ",$perf_out; }
834print "\n";
835exit $ERRORS{"CRITICAL"};
836
837