Merge pull request #1563 from jacobbaungard/ipv6_check_icmp
[monitoring-plugins.git] / plugins-scripts / check_ifstatus.pl
blob32984e53caeae705dfddefc87670e3afcebdcc38
1 #!@PERL@ -w
3 # check_ifstatus.pl - monitoring plugin
4 #
6 # Copyright (C) 2000 Christoph Kron
7 # Modified 5/2002 to conform to updated Monitoring Plugins Guidelines (S. Ghosh)
8 # Added -x option (4/2003)
9 # Added -u option (4/2003)
10 # Added -M option (10/2003)
11 # Added SNMPv3 support (10/2003)
12 # Added -n option (07/2014)
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29 # Report bugs to: ck@zet.net, help@monitoring-plugins.org
31 # 11.01.2000 Version 1.0
34 use POSIX;
35 use strict;
36 use FindBin;
37 use lib "$FindBin::Bin";
38 use utils qw($TIMEOUT %ERRORS &print_revision &support);
40 use Net::SNMP;
41 use Getopt::Long;
42 Getopt::Long::Configure('bundling');
44 my $PROGNAME = "check_ifstatus";
46 sub print_help ();
47 sub usage ($);
48 sub print_usage ();
49 sub process_arguments ();
51 $ENV{'PATH'}='@TRUSTED_PATH@';
52 $ENV{'BASH_ENV'}='';
53 $ENV{'ENV'}='';
55 my $status;
56 my %ifOperStatus = ('1','up',
57 '2','down',
58 '3','testing',
59 '4','unknown',
60 '5','dormant',
61 '6','notPresent',
62 '7','lowerLayerDown'); # down due to the state of lower layer interface(s));
64 my $timeout ;
65 my $state = "UNKNOWN";
66 my $answer = "";
67 my $snmpkey=0;
68 my $snmpoid=0;
69 my $key=0;
70 my $community = "public";
71 my $maxmsgsize = 1472 ; # Net::SNMP default is 1472
72 my ($seclevel, $authproto, $secname, $authpass, $privpass, $privproto, $auth, $priv, $context);
73 my $port = 161;
74 my @snmpoids;
75 my $snmpIfAdminStatus = '1.3.6.1.2.1.2.2.1.7';
76 my $snmpIfDescr = '1.3.6.1.2.1.2.2.1.2';
77 my $snmpIfOperStatus = '1.3.6.1.2.1.2.2.1.8';
78 my $snmpIfName = '1.3.6.1.2.1.31.1.1.1.1';
79 my $snmpIfAlias = '1.3.6.1.2.1.31.1.1.1.18';
80 my $snmpLocIfDescr = '1.3.6.1.4.1.9.2.2.1.1.28';
81 my $snmpIfType = '1.3.6.1.2.1.2.2.1.3';
82 my $hostname;
83 my $session;
84 my $error;
85 my $response;
86 my %ifStatus;
87 my $ifup =0 ;
88 my $ifdown =0;
89 my $ifdormant = 0;
90 my $ifexclude = 0 ;
91 my $ifunused = 0;
92 my $ifmessage = "";
93 my $snmp_version = 1;
94 my $ifXTable;
95 my $opt_h ;
96 my $opt_V ;
97 my $opt_u;
98 my $opt_n;
99 my $opt_x ;
100 my %excluded ;
101 my %unused_names ;
102 my @unused_ports ;
103 my %session_opts;
109 # Just in case of problems, let's not hang the monitoring system
110 $SIG{'ALRM'} = sub {
111 print ("ERROR: No snmp response from $hostname (alarm timeout)\n");
112 exit $ERRORS{"UNKNOWN"};
116 #Option checking
117 $status = process_arguments();
119 if ($status != 0)
121 print_help() ;
122 exit $ERRORS{'UNKNOWN'};
126 alarm($timeout);
127 ($session, $error) = Net::SNMP->session(%session_opts);
129 if (!defined($session)) {
130 $state='UNKNOWN';
131 $answer=$error;
132 print ("$state: $answer\n");
133 exit $ERRORS{$state};
137 push(@snmpoids,$snmpIfOperStatus);
138 push(@snmpoids,$snmpIfAdminStatus);
139 push(@snmpoids,$snmpIfDescr);
140 push(@snmpoids,$snmpIfType);
141 push(@snmpoids,$snmpIfName) if ( defined $ifXTable);
142 push(@snmpoids,$snmpIfAlias) if ( defined $ifXTable);
147 foreach $snmpoid (@snmpoids) {
149 if (!defined($response = $session->get_table($snmpoid))) {
150 $answer=$session->error;
151 $session->close;
152 $state = 'CRITICAL';
153 if ( ( $snmpoid =~ $snmpIfName ) && defined $ifXTable ) {
154 print ("$state: Device does not support ifTable - try without -I option\n");
155 }else{
156 print ("$state: $answer for $snmpoid with snmp version $snmp_version\n");
158 exit $ERRORS{$state};
161 foreach $snmpkey (keys %{$response}) {
162 $snmpkey =~ /.*\.(\d+)$/;
163 $key = $1;
164 $ifStatus{$key}{$snmpoid} = $response->{$snmpkey};
169 $session->close;
171 alarm(0);
173 foreach $key (keys %ifStatus) {
175 # skip unused interfaces
176 my $ifName = $ifStatus{$key}{$snmpIfDescr};
178 if (!defined($ifStatus{$key}{'notInUse'}) && !grep(/^${ifName}/, @unused_ports )) {
179 # check only if interface is administratively up
180 if ($ifStatus{$key}{$snmpIfAdminStatus} == 1 ) {
181 #check only if interface is not excluded
182 if (!defined $unused_names{$ifStatus{$key}{$snmpIfDescr}} ) {
183 # check only if interface type is not listed in %excluded
184 if (!defined $excluded{$ifStatus{$key}{$snmpIfType}} ) {
185 if ($ifStatus{$key}{$snmpIfOperStatus} == 1 ) { $ifup++ ; }
186 if ($ifStatus{$key}{$snmpIfOperStatus} == 2 ) {
187 $ifdown++ ;
188 if (defined $ifXTable) {
189 $ifmessage .= sprintf("%s: down -> %s<BR>\n", $ifStatus{$key}{$snmpIfName}, $ifStatus{$key}{$snmpIfAlias});
190 }else{
191 $ifmessage .= sprintf("%s: down <BR>\n",$ifStatus{$key}{$snmpIfDescr});
194 if ($ifStatus{$key}{$snmpIfOperStatus} == 5 ) { $ifdormant++ ;}
195 } else {
196 $ifexclude++;
198 } else {
199 $ifunused++;
203 }else{
204 $ifunused++;
208 if ($ifdown > 0) {
209 $state = 'CRITICAL';
210 $answer = sprintf("host '%s', interfaces up: %d, down: %d, dormant: %d, excluded: %d, unused: %d<BR>",
211 $hostname,
212 $ifup,
213 $ifdown,
214 $ifdormant,
215 $ifexclude,
216 $ifunused);
217 $answer = $answer . $ifmessage . "\n";
219 else {
220 $state = 'OK';
221 $answer = sprintf("host '%s', interfaces up: %d, down: %d, dormant: %d, excluded: %d, unused: %d",
222 $hostname,
223 $ifup,
224 $ifdown,
225 $ifdormant,
226 $ifexclude,
227 $ifunused);
229 my $perfdata = sprintf("up=%d down=%d dormant=%d excluded=%d unused=%d",$ifup,$ifdown,$ifdormant,$ifexclude,$ifunused);
230 print ("$state: $answer |$perfdata\n");
231 exit $ERRORS{$state};
233 sub usage($) {
234 print "$_[0]\n";
235 print_usage();
236 exit $ERRORS{"UNKNOWN"};
239 sub print_usage() {
240 printf "\n";
241 printf "usage: \n";
242 printf "check_ifstatus -C <READCOMMUNITY> -p <PORT> -H <HOSTNAME>\n";
243 printf "Copyright (C) 2000 Christoph Kron\n";
244 printf "Updates 5/2002 Subhendu Ghosh\n";
245 support();
246 printf "\n\n";
249 sub print_help() {
250 print_revision($PROGNAME, '@NP_VERSION@');
251 print_usage();
252 printf "check_ifstatus plugin for monitoring operational \n";
253 printf "status of each network interface on the target host\n";
254 printf "\nUsage:\n";
255 printf " -H (--hostname) Hostname to query - (required)\n";
256 printf " -C (--community) SNMP read community (defaults to public,\n";
257 printf " used with SNMP v1 and v2c\n";
258 printf " -v (--snmp_version) 1 for SNMP v1 (default)\n";
259 printf " 2 for SNMP v2c\n";
260 printf " SNMP v2c will use get_bulk for less overhead\n";
261 printf " 3 for SNMPv3 (requires -U option)";
262 printf " -p (--port) SNMP port (default 161)\n";
263 printf " -I (--ifmib) Agent supports IFMIB ifXTable. For Cisco - this will provide\n";
264 printf " the descriptive name. Do not use if you don't know what this is. \n";
265 printf " -x (--exclude) A comma separated list of ifType values that should be excluded \n";
266 printf " from the report (default for an empty list is PPP(23).\n";
267 printf " -n (--unused_ports_by_name) A comma separated list of ifDescr values that should be excluded \n";
268 printf " from the report (default is an empty exclusion list).\n";
269 printf " -u (--unused_ports) A comma separated list of ifIndex values that should be excluded \n";
270 printf " from the report (default is an empty exclusion list).\n";
271 printf " See the IANAifType-MIB for a list of interface types.\n";
272 printf " -L (--seclevel) choice of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\"\n";
273 printf " -U (--secname) username for SNMPv3 context\n";
274 printf " -c (--context) SNMPv3 context name (default is empty string)\n";
275 printf " -A (--authpass) authentication password (cleartext ascii or localized key\n";
276 printf " in hex with 0x prefix generated by using \"snmpkey\" utility\n";
277 printf " auth password and authEngineID\n";
278 printf " -a (--authproto) Authentication protocol (MD5 or SHA1)\n";
279 printf " -X (--privpass) privacy password (cleartext ascii or localized key\n";
280 printf " in hex with 0x prefix generated by using \"snmpkey\" utility\n";
281 printf " privacy password and authEngineID\n";
282 printf " -P (--privproto) privacy protocol (DES or AES; default: DES)\n";
283 printf " -M (--maxmsgsize) Max message size - useful only for v1 or v2c\n";
284 printf " -t (--timeout) seconds before the plugin times out (default=$TIMEOUT)\n";
285 printf " -V (--version) Plugin version\n";
286 printf " -h (--help) usage help \n\n";
287 print_revision($PROGNAME, '@NP_VERSION@');
291 sub process_arguments() {
292 $status = GetOptions(
293 "V" => \$opt_V, "version" => \$opt_V,
294 "h" => \$opt_h, "help" => \$opt_h,
295 "v=s" => \$snmp_version, "snmp_version=s" => \$snmp_version,
296 "C=s" => \$community,"community=s" => \$community,
297 "L=s" => \$seclevel, "seclevel=s" => \$seclevel,
298 "a=s" => \$authproto, "authproto=s" => \$authproto,
299 "U=s" => \$secname, "secname=s" => \$secname,
300 "A=s" => \$authpass, "authpass=s" => \$authpass,
301 "X=s" => \$privpass, "privpass=s" => \$privpass,
302 "P=s" => \$privproto, "privproto=s" => \$privproto,
303 "c=s" => \$context, "context=s" => \$context,
304 "p=i" =>\$port, "port=i" => \$port,
305 "H=s" => \$hostname, "hostname=s" => \$hostname,
306 "I" => \$ifXTable, "ifmib" => \$ifXTable,
307 "x:s" => \$opt_x, "exclude:s" => \$opt_x,
308 "u=s" => \$opt_u, "unused_ports=s" => \$opt_u,
309 "n=s" => \$opt_n, "unused_ports_by_name=s" => \$opt_n,
310 "M=i" => \$maxmsgsize, "maxmsgsize=i" => \$maxmsgsize,
311 "t=i" => \$timeout, "timeout=i" => \$timeout,
314 if ($status == 0){
315 print_help();
316 exit $ERRORS{'UNKNOWN'};
319 if ($opt_V) {
320 print_revision($PROGNAME,'@NP_VERSION@');
321 exit $ERRORS{'UNKNOWN'};
324 if ($opt_h) {
325 print_help();
326 exit $ERRORS{'UNKNOWN'};
329 unless (defined $timeout) {
330 $timeout = $TIMEOUT;
333 # Net::SNMP wants an integer
334 $snmp_version = 2 if $snmp_version eq "2c";
336 if ($snmp_version !~ /^[123]$/){
337 $state='UNKNOWN';
338 print ("$state: No support for SNMP v$snmp_version yet\n");
339 exit $ERRORS{$state};
342 %session_opts = (
343 -hostname => $hostname,
344 -port => $port,
345 -version => $snmp_version,
346 -maxmsgsize => $maxmsgsize
349 $session_opts{'-community'} = $community if (defined $community && $snmp_version =~ /[12]/);
351 if ($snmp_version =~ /3/ ) {
352 # Must define a security level even though default is noAuthNoPriv
353 # v3 requires a security username
354 if (defined $seclevel && defined $secname) {
355 $session_opts{'-username'} = $secname;
357 # Must define a security level even though defualt is noAuthNoPriv
358 unless ( grep /^$seclevel$/, qw(noAuthNoPriv authNoPriv authPriv) ) {
359 usage("Must define a valid security level even though default is noAuthNoPriv");
362 # Authentication wanted
363 if ( $seclevel eq 'authNoPriv' || $seclevel eq 'authPriv' ) {
364 if (defined $authproto && $authproto ne 'MD5' && $authproto ne 'SHA1') {
365 usage("Auth protocol can be either MD5 or SHA1");
367 $session_opts{'-authprotocol'} = $authproto if(defined $authproto);
369 if ( !defined $authpass) {
370 usage("Auth password/key is not defined");
371 }else{
372 if ($authpass =~ /^0x/ ) {
373 $session_opts{'-authkey'} = $authpass ;
374 }else{
375 $session_opts{'-authpassword'} = $authpass ;
380 # Privacy (DES encryption) wanted
381 if ($seclevel eq 'authPriv' ) {
382 if (! defined $privpass) {
383 usage("Privacy passphrase/key is not defined");
384 }else{
385 if ($privpass =~ /^0x/){
386 $session_opts{'-privkey'} = $privpass;
387 }else{
388 $session_opts{'-privpassword'} = $privpass;
392 $session_opts{'-privprotocol'} = $privproto if(defined $privproto);
395 # Context name defined or default
396 unless ( defined $context) {
397 $context = "";
400 }else {
401 usage("Security level or name is not defined");
403 } # end snmpv3
405 # Excluded interfaces types (ifType) (backup interfaces, dial-on demand interfaces, PPP interfaces
406 if (defined $opt_x) {
407 my @x = split(/,/, $opt_x);
408 if ( @x) {
409 foreach $key (@x){
410 $excluded{$key} = 1;
412 }else{
413 $excluded{23} = 1; # default PPP(23) if empty list - note (AIX seems to think PPP is 22 according to a post)
417 # Excluded interface descriptors
418 if (defined $opt_n) {
419 my @unused = split(/,/,$opt_n);
420 if ( @unused ) {
421 foreach $key (@unused) {
422 $unused_names{$key} = 1;
427 # Excluded interface ports (ifIndex) - management reasons
428 if ($opt_u) {
429 @unused_ports = split(/,/,$opt_u);
430 foreach $key (@unused_ports) {
431 $ifStatus{$key}{'notInUse'}++ ;
435 if (! utils::is_hostname($hostname)){
436 usage("Hostname invalid or not given");
437 exit $ERRORS{"UNKNOWN"};
441 if ($snmp_version !~ /[123]/) {
442 $state='UNKNOWN';
443 print ("$state: No support for SNMP v$snmp_version yet\n");
444 exit $ERRORS{$state};
447 return $ERRORS{"OK"};