summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml14
-rw-r--r--NEWS2
-rw-r--r--THANKS.in1
-rw-r--r--lib/utils_base.c19
-rw-r--r--lib/utils_base.h5
-rw-r--r--lib/utils_cmd.c42
-rw-r--r--lib/utils_cmd.h13
-rw-r--r--plugins-root/check_icmp.c465
-rw-r--r--plugins/check_dbi.c1
-rw-r--r--plugins/check_dns.c36
-rw-r--r--plugins/check_hpjd.c12
-rw-r--r--plugins/check_http.c2
-rw-r--r--plugins/check_pgsql.c1
-rw-r--r--plugins/check_smtp.c1
-rw-r--r--plugins/common.h14
-rw-r--r--plugins/popen.c29
-rw-r--r--plugins/runcmd.c13
-rw-r--r--plugins/t/NPTest.cache.travis2
-rw-r--r--plugins/tests/certs/server-cert.pem41
-rw-r--r--plugins/tests/certs/server-key.pem43
-rwxr-xr-xplugins/tests/check_http.t16
-rwxr-xr-xplugins/tests/check_snmp.t110
-rw-r--r--plugins/utils.c31
-rw-r--r--plugins/utils.h9
24 files changed, 572 insertions, 350 deletions
diff --git a/.travis.yml b/.travis.yml
index 712f2475..946345c4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
1sudo: required 1sudo: required
2dist: trusty 2dist: xenial
3language: c 3language: c
4 4
5env: 5env:
@@ -39,7 +39,6 @@ before_install:
39 - "sudo killall -9 ntpd ||:" 39 - "sudo killall -9 ntpd ||:"
40 # Trusty has no swap, lets create some 40 # Trusty has no swap, lets create some
41 - sudo fallocate -l 20M /swapfile; sudo chmod 600 /swapfile; sudo mkswap /swapfile; sudo swapon /swapfile 41 - sudo fallocate -l 20M /swapfile; sudo chmod 600 /swapfile; sudo mkswap /swapfile; sudo swapon /swapfile
42 - sudo add-apt-repository -y ppa:waja/trusty-backports
43 - sudo apt-get update -qq 42 - sudo apt-get update -qq
44 - sudo apt-get purge -qq gawk 43 - sudo apt-get purge -qq gawk
45 44
@@ -52,7 +51,7 @@ install:
52 - sudo apt-get install -qq --no-install-recommends autoconf automake 51 - sudo apt-get install -qq --no-install-recommends autoconf automake
53 - sudo apt-get install -qq --no-install-recommends faketime 52 - sudo apt-get install -qq --no-install-recommends faketime
54 - sudo apt-get install -qq --no-install-recommends libmonitoring-plugin-perl 53 - sudo apt-get install -qq --no-install-recommends libmonitoring-plugin-perl
55 - sudo apt-get install -qq --no-install-recommends squid3 54 - sudo apt-get install -qq --no-install-recommends squid
56 # Trusty related dependencies (not yet provided) 55 # Trusty related dependencies (not yet provided)
57 - test "$(dpkg -l | grep -E "mysql-(client|server)-[0-9].[0-9]" | grep -c ^ii)" -gt 0 || sudo apt-get install -qq --no-install-recommends mariadb-client mariadb-server 56 - test "$(dpkg -l | grep -E "mysql-(client|server)-[0-9].[0-9]" | grep -c ^ii)" -gt 0 || sudo apt-get install -qq --no-install-recommends mariadb-client mariadb-server
58 # enable ssl apache 57 # enable ssl apache
@@ -60,8 +59,9 @@ install:
60 - sudo a2ensite default-ssl 59 - sudo a2ensite default-ssl
61 - sudo make-ssl-cert generate-default-snakeoil --force-overwrite 60 - sudo make-ssl-cert generate-default-snakeoil --force-overwrite
62 - sudo service apache2 reload 61 - sudo service apache2 reload
63 - sudo cp tools/squid.conf /etc/squid3/squid.conf 62 - sudo cp tools/squid.conf /etc/squid/squid.conf
64 - sudo service squid3 reload 63 - sudo service squid reload
64 - sudo service mysql restart
65 65
66before_script: 66before_script:
67 # ensure we have a test database in place for tests 67 # ensure we have a test database in place for tests
@@ -73,8 +73,8 @@ before_script:
73 - make 73 - make
74 - export NPTEST_ACCEPTDEFAULT=1 74 - export NPTEST_ACCEPTDEFAULT=1
75 - export NPTEST_CACHE="$(pwd)/plugins/t/NPTest.cache.travis" 75 - export NPTEST_CACHE="$(pwd)/plugins/t/NPTest.cache.travis"
76 - ssh-keygen -t dsa -N "" -f ~/.ssh/id_dsa 76 - ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
77 - cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys 77 - cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
78 - ssh-keyscan localhost >> ~/.ssh/known_hosts 78 - ssh-keyscan localhost >> ~/.ssh/known_hosts
79 - touch ~/.ssh/config 79 - touch ~/.ssh/config
80 - sudo rm -f /usr/share/mibs/ietf/SNMPv2-PDU /usr/share/mibs/ietf/IPSEC-SPD-MIB /usr/share/mibs/ietf/IPATM-IPMC-MIB /usr/share/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB 80 - sudo rm -f /usr/share/mibs/ietf/SNMPv2-PDU /usr/share/mibs/ietf/IPSEC-SPD-MIB /usr/share/mibs/ietf/IPATM-IPMC-MIB /usr/share/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB
diff --git a/NEWS b/NEWS
index 2db2a2cb..0848705c 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ This file documents the major additions and syntax changes between releases.
5 check_dns: allow 'expected address' (-a) to be specified in CIDR notation 5 check_dns: allow 'expected address' (-a) to be specified in CIDR notation
6 (IPv4 only). 6 (IPv4 only).
7 check_dns: allow for IPv6 RDNS 7 check_dns: allow for IPv6 RDNS
8 check_dns: allow unsorted addresses
9 check_dns: allow forcing complete match of all addresses
8 check_apt: add --only-critical switch 10 check_apt: add --only-critical switch
9 check_apt: add -l/--list option to print packages 11 check_apt: add -l/--list option to print packages
10 12
diff --git a/THANKS.in b/THANKS.in
index ebc81556..9bb43828 100644
--- a/THANKS.in
+++ b/THANKS.in
@@ -356,3 +356,4 @@ Sven Geggus
356Thomas Kurschel 356Thomas Kurschel
357Yannick Charton 357Yannick Charton
358Nicolai Søborg 358Nicolai Søborg
359Rolf Eike Beer
diff --git a/lib/utils_base.c b/lib/utils_base.c
index 19a531f5..fd7058da 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -37,6 +37,9 @@
37 37
38monitoring_plugin *this_monitoring_plugin=NULL; 38monitoring_plugin *this_monitoring_plugin=NULL;
39 39
40unsigned int timeout_state = STATE_CRITICAL;
41unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
42
40int _np_state_read_file(FILE *); 43int _np_state_read_file(FILE *);
41 44
42void np_init( char *plugin_name, int argc, char **argv ) { 45void np_init( char *plugin_name, int argc, char **argv ) {
@@ -359,6 +362,22 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
359 return value; 362 return value;
360} 363}
361 364
365const char *
366state_text (int result)
367{
368 switch (result) {
369 case STATE_OK:
370 return "OK";
371 case STATE_WARNING:
372 return "WARNING";
373 case STATE_CRITICAL:
374 return "CRITICAL";
375 case STATE_DEPENDENT:
376 return "DEPENDENT";
377 default:
378 return "UNKNOWN";
379 }
380}
362 381
363/* 382/*
364 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 383 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 42ae0c09..d7e7dffa 100644
--- a/lib/utils_base.h
+++ b/lib/utils_base.h
@@ -61,6 +61,10 @@ void print_thresholds(const char *, thresholds *);
61int check_range(double, range *); 61int check_range(double, range *);
62int get_status(double, thresholds *); 62int get_status(double, thresholds *);
63 63
64/* Handle timeouts */
65extern unsigned int timeout_state;
66extern unsigned int timeout_interval;
67
64/* All possible characters in a threshold range */ 68/* All possible characters in a threshold range */
65#define NP_THRESHOLDS_CHARS "-0123456789.:@~" 69#define NP_THRESHOLDS_CHARS "-0123456789.:@~"
66 70
@@ -107,5 +111,6 @@ void np_state_write_string(time_t, char *);
107void np_init(char *, int argc, char **argv); 111void np_init(char *, int argc, char **argv);
108void np_set_args(int argc, char **argv); 112void np_set_args(int argc, char **argv);
109void np_cleanup(); 113void np_cleanup();
114const char *state_text (int);
110 115
111#endif /* _UTILS_BASE_ */ 116#endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 7eb9a3a0..795840d3 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -40,6 +40,7 @@
40 40
41/** includes **/ 41/** includes **/
42#include "common.h" 42#include "common.h"
43#include "utils.h"
43#include "utils_cmd.h" 44#include "utils_cmd.h"
44#include "utils_base.h" 45#include "utils_base.h"
45#include <fcntl.h> 46#include <fcntl.h>
@@ -65,31 +66,6 @@ extern char **environ;
65# define SIG_ERR ((Sigfunc *)-1) 66# define SIG_ERR ((Sigfunc *)-1)
66#endif 67#endif
67 68
68/* This variable must be global, since there's no way the caller
69 * can forcibly slay a dead or ungainly running program otherwise.
70 * Multithreading apps and plugins can initialize it (via CMD_INIT)
71 * in an async safe manner PRIOR to calling cmd_run() or cmd_run_array()
72 * for the first time.
73 *
74 * The check for initialized values is atomic and can
75 * occur in any number of threads simultaneously. */
76static pid_t *_cmd_pids = NULL;
77
78/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
79 * If that fails and the macro isn't defined, we fall back to an educated
80 * guess. There's no guarantee that our guess is adequate and the program
81 * will die with SIGSEGV if it isn't and the upper boundary is breached. */
82#define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */
83#define MAXFD_LIMIT 8192 /* upper limit of open files */
84#ifdef _SC_OPEN_MAX
85static long maxfd = 0;
86#elif defined(OPEN_MAX)
87# define maxfd OPEN_MAX
88#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
89# define maxfd DEFAULT_MAXFD
90#endif
91
92
93/** prototypes **/ 69/** prototypes **/
94static int _cmd_open (char *const *, int *, int *) 70static int _cmd_open (char *const *, int *, int *)
95 __attribute__ ((__nonnull__ (1, 2, 3))); 71 __attribute__ ((__nonnull__ (1, 2, 3)));
@@ -406,3 +382,19 @@ cmd_file_read ( char *filename, output *out, int flags)
406 382
407 return 0; 383 return 0;
408} 384}
385
386void
387timeout_alarm_handler (int signo)
388{
389 size_t i;
390 if (signo == SIGALRM) {
391 printf (_("%s - Plugin timed out after %d seconds\n"),
392 state_text(timeout_state), timeout_interval);
393
394 if(_cmd_pids) for(i = 0; i < maxfd; i++) {
395 if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL);
396 }
397
398 exit (timeout_state);
399 }
400}
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index ebaf15be..6f3aeb81 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -32,4 +32,17 @@ void cmd_init (void);
32#define CMD_NO_ARRAYS 0x01 /* don't populate arrays at all */ 32#define CMD_NO_ARRAYS 0x01 /* don't populate arrays at all */
33#define CMD_NO_ASSOC 0x02 /* output.line won't point to buf */ 33#define CMD_NO_ASSOC 0x02 /* output.line won't point to buf */
34 34
35/* This variable must be global, since there's no way the caller
36 * can forcibly slay a dead or ungainly running program otherwise.
37 * Multithreading apps and plugins can initialize it (via CMD_INIT)
38 * in an async safe manner PRIOR to calling cmd_run() or cmd_run_array()
39 * for the first time.
40 *
41 * The check for initialized values is atomic and can
42 * occur in any number of threads simultaneously. */
43static pid_t *_cmd_pids = NULL;
44
45RETSIGTYPE timeout_alarm_handler (int);
46
47
35#endif /* _UTILS_CMD_ */ 48#endif /* _UTILS_CMD_ */
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index 4098874c..e45fdf60 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -67,7 +67,9 @@ const char *email = "devel@monitoring-plugins.org";
67#include <netinet/in_systm.h> 67#include <netinet/in_systm.h>
68#include <netinet/in.h> 68#include <netinet/in.h>
69#include <netinet/ip.h> 69#include <netinet/ip.h>
70#include <netinet/ip6.h>
70#include <netinet/ip_icmp.h> 71#include <netinet/ip_icmp.h>
72#include <netinet/icmp6.h>
71#include <arpa/inet.h> 73#include <arpa/inet.h>
72#include <signal.h> 74#include <signal.h>
73#include <float.h> 75#include <float.h>
@@ -113,8 +115,8 @@ typedef struct rta_host {
113 unsigned short id; /* id in **table, and icmp pkts */ 115 unsigned short id; /* id in **table, and icmp pkts */
114 char *name; /* arg used for adding this host */ 116 char *name; /* arg used for adding this host */
115 char *msg; /* icmp error message, if any */ 117 char *msg; /* icmp error message, if any */
116 struct sockaddr_in saddr_in; /* the address of this host */ 118 struct sockaddr_storage saddr_in; /* the address of this host */
117 struct in_addr error_addr; /* stores address of error replies */ 119 struct sockaddr_storage error_addr; /* stores address of error replies */
118 unsigned long long time_waited; /* total time waited, in usecs */ 120 unsigned long long time_waited; /* total time waited, in usecs */
119 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */ 121 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
120 unsigned char icmp_type, icmp_code; /* type and code from errors */ 122 unsigned char icmp_type, icmp_code; /* type and code from errors */
@@ -140,6 +142,18 @@ typedef struct icmp_ping_data {
140 unsigned short ping_id; 142 unsigned short ping_id;
141} icmp_ping_data; 143} icmp_ping_data;
142 144
145typedef union ip_hdr {
146 struct ip ip;
147 struct ip6_hdr ip6;
148} ip_hdr;
149
150typedef union icmp_packet {
151 void *buf;
152 struct icmp *icp;
153 struct icmp6_hdr *icp6;
154 u_short *cksum_in;
155} icmp_packet;
156
143/* the different modes of this program are as follows: 157/* the different modes of this program are as follows:
144 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping) 158 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
145 * MODE_HOSTCHECK: Return immediately upon any sign of life 159 * MODE_HOSTCHECK: Return immediately upon any sign of life
@@ -190,8 +204,9 @@ static int get_threshold(char *str, threshold *th);
190static void run_checks(void); 204static void run_checks(void);
191static void set_source_ip(char *); 205static void set_source_ip(char *);
192static int add_target(char *); 206static int add_target(char *);
193static int add_target_ip(char *, struct in_addr *); 207static int add_target_ip(char *, struct sockaddr_storage *);
194static int handle_random_icmp(unsigned char *, struct sockaddr_in *); 208static int handle_random_icmp(unsigned char *, struct sockaddr_storage *);
209static void parse_address(struct sockaddr_storage *, char *, int);
195static unsigned short icmp_checksum(unsigned short *, int); 210static unsigned short icmp_checksum(unsigned short *, int);
196static void finish(int); 211static void finish(int);
197static void crash(const char *, ...); 212static void crash(const char *, ...);
@@ -300,7 +315,7 @@ get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code)
300} 315}
301 316
302static int 317static int
303handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr) 318handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr)
304{ 319{
305 struct icmp p, sent_icmp; 320 struct icmp p, sent_icmp;
306 struct rta_host *host = NULL; 321 struct rta_host *host = NULL;
@@ -342,9 +357,11 @@ handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr)
342 /* it is indeed a response for us */ 357 /* it is indeed a response for us */
343 host = table[ntohs(sent_icmp.icmp_seq)/packets]; 358 host = table[ntohs(sent_icmp.icmp_seq)/packets];
344 if(debug) { 359 if(debug) {
360 char address[INET6_ADDRSTRLEN];
361 parse_address(addr, address, sizeof(address));
345 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", 362 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n",
346 get_icmp_error_msg(p.icmp_type, p.icmp_code), 363 get_icmp_error_msg(p.icmp_type, p.icmp_code),
347 inet_ntoa(addr->sin_addr), host->name); 364 address, host->name);
348 } 365 }
349 366
350 icmp_lost++; 367 icmp_lost++;
@@ -364,11 +381,23 @@ handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr)
364 } 381 }
365 host->icmp_type = p.icmp_type; 382 host->icmp_type = p.icmp_type;
366 host->icmp_code = p.icmp_code; 383 host->icmp_code = p.icmp_code;
367 host->error_addr.s_addr = addr->sin_addr.s_addr; 384 host->error_addr = *addr;
368 385
369 return 0; 386 return 0;
370} 387}
371 388
389void parse_address(struct sockaddr_storage *addr, char *address, int size)
390{
391 switch (address_family) {
392 case AF_INET:
393 inet_ntop(address_family, &((struct sockaddr_in *)addr)->sin_addr, address, size);
394 break;
395 case AF_INET6:
396 inet_ntop(address_family, &((struct sockaddr_in6 *)addr)->sin6_addr, address, size);
397 break;
398 }
399}
400
372int 401int
373main(int argc, char **argv) 402main(int argc, char **argv)
374{ 403{
@@ -381,6 +410,7 @@ main(int argc, char **argv)
381#ifdef SO_TIMESTAMP 410#ifdef SO_TIMESTAMP
382 int on = 1; 411 int on = 1;
383#endif 412#endif
413 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:64";
384 414
385 setlocale (LC_ALL, ""); 415 setlocale (LC_ALL, "");
386 bindtextdomain (PACKAGE, LOCALEDIR); 416 bindtextdomain (PACKAGE, LOCALEDIR);
@@ -390,33 +420,8 @@ main(int argc, char **argv)
390 * that before pointer magic (esp. on network data) */ 420 * that before pointer magic (esp. on network data) */
391 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0; 421 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
392 422
393 if((icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1) 423 address_family = -1;
394 sockets |= HAVE_ICMP; 424 int icmp_proto = IPPROTO_ICMP;
395 else icmp_sockerrno = errno;
396
397 /* if((udp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) */
398 /* sockets |= HAVE_UDP; */
399 /* else udp_sockerrno = errno; */
400
401 /* if((tcp_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) */
402 /* sockets |= HAVE_TCP; */
403 /* else tcp_sockerrno = errno; */
404
405 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
406 setuid(getuid());
407
408#ifdef SO_TIMESTAMP
409 if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
410 if(debug) printf("Warning: no SO_TIMESTAMP support\n");
411#endif // SO_TIMESTAMP
412
413 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
414 environ = NULL;
415
416 /* use the pid to mark packets as ours */
417 /* Some systems have 32-bit pid_t so mask off only 16 bits */
418 pid = getpid() & 0xffff;
419 /* printf("pid = %u\n", pid); */
420 425
421 /* get calling name the old-fashioned way for portability instead 426 /* get calling name the old-fashioned way for portability instead
422 * of relying on the glibc-ism __progname */ 427 * of relying on the glibc-ism __progname */
@@ -456,20 +461,35 @@ main(int argc, char **argv)
456 packets = 5; 461 packets = 5;
457 } 462 }
458 463
459 /* Parse extra opts if any */ 464 /* Parse protocol arguments first */
460 argv=np_extra_opts(&argc, argv, progname); 465 for(i = 1; i < argc; i++) {
461 466 while((arg = getopt(argc, argv, opts_str)) != EOF) {
462 /* support "--help" and "--version" */ 467 unsigned short size;
463 if(argc == 2) { 468 switch(arg) {
464 if(!strcmp(argv[1], "--help")) 469 case '4':
465 strcpy(argv[1], "-h"); 470 if (address_family != -1)
466 if(!strcmp(argv[1], "--version")) 471 crash("Multiple protocol versions not supported");
467 strcpy(argv[1], "-V"); 472 address_family = AF_INET;
473 break;
474 case '6':
475#ifdef USE_IPV6
476 if (address_family != -1)
477 crash("Multiple protocol versions not supported");
478 address_family = AF_INET6;
479#else
480 usage (_("IPv6 support not available\n"));
481#endif
482 break;
483 }
484 }
468 } 485 }
469 486
487 /* Reset argument scanning */
488 optind = 1;
489
470 /* parse the arguments */ 490 /* parse the arguments */
471 for(i = 1; i < argc; i++) { 491 for(i = 1; i < argc; i++) {
472 while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:s:i:b:I:l:m:")) != EOF) { 492 while((arg = getopt(argc, argv, opts_str)) != EOF) {
473 unsigned short size; 493 unsigned short size;
474 switch(arg) { 494 switch(arg) {
475 case 'v': 495 case 'v':
@@ -530,10 +550,30 @@ main(int argc, char **argv)
530 case 'h': /* help */ 550 case 'h': /* help */
531 print_help (); 551 print_help ();
532 exit (STATE_UNKNOWN); 552 exit (STATE_UNKNOWN);
553 break;
533 } 554 }
534 } 555 }
535 } 556 }
536 557
558 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
559 environ = NULL;
560
561 /* use the pid to mark packets as ours */
562 /* Some systems have 32-bit pid_t so mask off only 16 bits */
563 pid = getpid() & 0xffff;
564 /* printf("pid = %u\n", pid); */
565
566 /* Parse extra opts if any */
567 argv=np_extra_opts(&argc, argv, progname);
568
569 /* support "--help" and "--version" */
570 if(argc == 2) {
571 if(!strcmp(argv[1], "--help"))
572 strcpy(argv[1], "-h");
573 if(!strcmp(argv[1], "--version"))
574 strcpy(argv[1], "-V");
575 }
576
537 argv = &argv[optind]; 577 argv = &argv[optind];
538 while(*argv) { 578 while(*argv) {
539 add_target(*argv); 579 add_target(*argv);
@@ -545,6 +585,30 @@ main(int argc, char **argv)
545 exit(3); 585 exit(3);
546 } 586 }
547 587
588 // add_target might change address_family
589 switch ( address_family ){
590 case AF_INET: icmp_proto = IPPROTO_ICMP;
591 break;
592 case AF_INET6: icmp_proto = IPPROTO_ICMPV6;
593 break;
594 default: crash("Address family not supported");
595 }
596 if((icmp_sock = socket(address_family, SOCK_RAW, icmp_proto)) != -1)
597 sockets |= HAVE_ICMP;
598 else icmp_sockerrno = errno;
599
600
601#ifdef SO_TIMESTAMP
602 if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
603 if(debug) printf("Warning: no SO_TIMESTAMP support\n");
604#endif // SO_TIMESTAMP
605
606 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
607 if (setuid(getuid()) == -1) {
608 printf("ERROR: Failed to drop privileges\n");
609 return 1;
610 }
611
548 if(!sockets) { 612 if(!sockets) {
549 if(icmp_sock == -1) { 613 if(icmp_sock == -1) {
550 errno = icmp_sockerrno; 614 errno = icmp_sockerrno;
@@ -633,7 +697,7 @@ main(int argc, char **argv)
633 } 697 }
634 698
635 host = list; 699 host = list;
636 table = malloc(sizeof(struct rta_host **) * targets); 700 table = (struct rta_host**)malloc(sizeof(struct rta_host **) * targets);
637 i = 0; 701 i = 0;
638 while(host) { 702 while(host) {
639 host->id = i*packets; 703 host->id = i*packets;
@@ -697,9 +761,15 @@ run_checks()
697 } 761 }
698} 762}
699 763
764
700/* response structure: 765/* response structure:
766 * IPv4:
701 * ip header : 20 bytes 767 * ip header : 20 bytes
702 * icmp header : 28 bytes 768 * icmp header : 28 bytes
769 * IPv6:
770 * ip header : 40 bytes
771 * icmp header : 28 bytes
772 * both:
703 * icmp echo reply : the rest 773 * icmp echo reply : the rest
704 */ 774 */
705static int 775static int
@@ -707,16 +777,27 @@ wait_for_reply(int sock, u_int t)
707{ 777{
708 int n, hlen; 778 int n, hlen;
709 static unsigned char buf[4096]; 779 static unsigned char buf[4096];
710 struct sockaddr_in resp_addr; 780 struct sockaddr_storage resp_addr;
711 struct ip *ip; 781 union ip_hdr *ip;
712 struct icmp icp; 782 union icmp_packet packet;
713 struct rta_host *host; 783 struct rta_host *host;
714 struct icmp_ping_data data; 784 struct icmp_ping_data data;
715 struct timeval wait_start, now; 785 struct timeval wait_start, now;
716 u_int tdiff, i, per_pkt_wait; 786 u_int tdiff, i, per_pkt_wait;
717 787
788 if (!(packet.buf = malloc(icmp_pkt_size))) {
789 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
790 icmp_pkt_size);
791 return -1; /* might be reached if we're in debug mode */
792 }
793
794 memset(packet.buf, 0, icmp_pkt_size);
795
718 /* if we can't listen or don't have anything to listen to, just return */ 796 /* if we can't listen or don't have anything to listen to, just return */
719 if(!t || !icmp_pkts_en_route) return 0; 797 if(!t || !icmp_pkts_en_route) {
798 free(packet.buf);
799 return 0;
800 }
720 801
721 gettimeofday(&wait_start, &tz); 802 gettimeofday(&wait_start, &tz);
722 803
@@ -735,7 +816,7 @@ wait_for_reply(int sock, u_int t)
735 816
736 /* reap responses until we hit a timeout */ 817 /* reap responses until we hit a timeout */
737 n = recvfrom_wto(sock, buf, sizeof(buf), 818 n = recvfrom_wto(sock, buf, sizeof(buf),
738 (struct sockaddr *)&resp_addr, &t, &now); 819 (struct sockaddr *)&resp_addr, &t, &now);
739 if(!n) { 820 if(!n) {
740 if(debug > 1) { 821 if(debug > 1) {
741 printf("recvfrom_wto() timed out during a %u usecs wait\n", 822 printf("recvfrom_wto() timed out during a %u usecs wait\n",
@@ -745,12 +826,23 @@ wait_for_reply(int sock, u_int t)
745 } 826 }
746 if(n < 0) { 827 if(n < 0) {
747 if(debug) printf("recvfrom_wto() returned errors\n"); 828 if(debug) printf("recvfrom_wto() returned errors\n");
829 free(packet.buf);
748 return n; 830 return n;
749 } 831 }
750 832
751 ip = (struct ip *)buf; 833 // FIXME: with ipv6 we don't have an ip header here
752 if(debug > 1) printf("received %u bytes from %s\n", 834 if (address_family != AF_INET6) {
753 ntohs(ip->ip_len), inet_ntoa(resp_addr.sin_addr)); 835 ip = (union ip_hdr *)buf;
836
837 if(debug > 1) {
838 char address[INET6_ADDRSTRLEN];
839 parse_address(&resp_addr, address, sizeof(address));
840 printf("received %u bytes from %s\n",
841 address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen)
842 : ntohs(ip->ip.ip_len),
843 address);
844 }
845 }
754 846
755/* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ 847/* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */
756/* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ 848/* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */
@@ -759,12 +851,14 @@ wait_for_reply(int sock, u_int t)
759 * off the bottom 4 bits */ 851 * off the bottom 4 bits */
760/* hlen = (ip->ip_vhl & 0x0f) << 2; */ 852/* hlen = (ip->ip_vhl & 0x0f) << 2; */
761/* #else */ 853/* #else */
762 hlen = ip->ip_hl << 2; 854 hlen = (address_family == AF_INET6) ? 0 : ip->ip.ip_hl << 2;
763/* #endif */ 855/* #endif */
764 856
765 if(n < (hlen + ICMP_MINLEN)) { 857 if(n < (hlen + ICMP_MINLEN)) {
858 char address[INET6_ADDRSTRLEN];
859 parse_address(&resp_addr, address, sizeof(address));
766 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", 860 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n",
767 n, hlen + icmp_pkt_size, inet_ntoa(resp_addr.sin_addr)); 861 n, hlen + icmp_pkt_size, address);
768 } 862 }
769 /* else if(debug) { */ 863 /* else if(debug) { */
770 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ 864 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */
@@ -773,23 +867,39 @@ wait_for_reply(int sock, u_int t)
773 /* } */ 867 /* } */
774 868
775 /* check the response */ 869 /* check the response */
776 memcpy(&icp, buf + hlen, sizeof(icp));
777 870
778 if(ntohs(icp.icmp_id) != pid || icp.icmp_type != ICMP_ECHOREPLY || 871 memcpy(packet.buf, buf + hlen, icmp_pkt_size);
779 ntohs(icp.icmp_seq) >= targets*packets) { 872/* address_family == AF_INET6 ? sizeof(struct icmp6_hdr)
873 : sizeof(struct icmp));*/
874
875 if( (address_family == PF_INET &&
876 (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY
877 || ntohs(packet.icp->icmp_seq) >= targets * packets))
878 || (address_family == PF_INET6 &&
879 (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY
880 || ntohs(packet.icp6->icmp6_seq) >= targets * packets))) {
780 if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); 881 if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n");
781 handle_random_icmp(buf + hlen, &resp_addr); 882 handle_random_icmp(buf + hlen, &resp_addr);
782 continue; 883 continue;
783 } 884 }
784 885
785 /* this is indeed a valid response */ 886 /* this is indeed a valid response */
786 memcpy(&data, icp.icmp_data, sizeof(data)); 887 if (address_family == PF_INET) {
787 if (debug > 2) 888 memcpy(&data, packet.icp->icmp_data, sizeof(data));
788 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", 889 if (debug > 2)
789 (unsigned long)sizeof(data), ntohs(icp.icmp_id), 890 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n",
790 ntohs(icp.icmp_seq), icp.icmp_cksum); 891 (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id),
892 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum);
893 host = table[ntohs(packet.icp->icmp_seq)/packets];
894 } else {
895 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data));
896 if (debug > 2)
897 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n",
898 (unsigned long)sizeof(data), ntohs(packet.icp6->icmp6_id),
899 ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum);
900 host = table[ntohs(packet.icp6->icmp6_seq)/packets];
901 }
791 902
792 host = table[ntohs(icp.icmp_seq)/packets];
793 tdiff = get_timevaldiff(&data.stime, &now); 903 tdiff = get_timevaldiff(&data.stime, &now);
794 904
795 host->time_waited += tdiff; 905 host->time_waited += tdiff;
@@ -801,22 +911,25 @@ wait_for_reply(int sock, u_int t)
801 host->rtmin = tdiff; 911 host->rtmin = tdiff;
802 912
803 if(debug) { 913 if(debug) {
914 char address[INET6_ADDRSTRLEN];
915 parse_address(&resp_addr, address, sizeof(address));
804 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", 916 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n",
805 (float)tdiff / 1000, inet_ntoa(resp_addr.sin_addr), 917 (float)tdiff / 1000, address,
806 ttl, ip->ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); 918 ttl, ip->ip.ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000);
807 } 919 }
808 920
809 /* if we're in hostcheck mode, exit with limited printouts */ 921 /* if we're in hostcheck mode, exit with limited printouts */
810 if(mode == MODE_HOSTCHECK) { 922 if(mode == MODE_HOSTCHECK) {
811 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" 923 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|"
812 "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", 924 "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n",
813 host->name, icmp_recv, (float)tdiff / 1000, 925 host->name, icmp_recv, (float)tdiff / 1000,
814 icmp_recv, packets, (float)tdiff / 1000, 926 icmp_recv, packets, (float)tdiff / 1000,
815 (float)warn.rta / 1000, (float)crit.rta / 1000); 927 (float)warn.rta / 1000, (float)crit.rta / 1000);
816 exit(STATE_OK); 928 exit(STATE_OK);
817 } 929 }
818 } 930 }
819 931
932 free(packet.buf);
820 return 0; 933 return 0;
821} 934}
822 935
@@ -824,62 +937,81 @@ wait_for_reply(int sock, u_int t)
824static int 937static int
825send_icmp_ping(int sock, struct rta_host *host) 938send_icmp_ping(int sock, struct rta_host *host)
826{ 939{
827 static union {
828 void *buf; /* re-use so we prevent leaks */
829 struct icmp *icp;
830 u_short *cksum_in;
831 } packet = { NULL };
832 long int len; 940 long int len;
833 struct icmp_ping_data data; 941 struct icmp_ping_data data;
834 struct msghdr hdr; 942 struct msghdr hdr;
835 struct iovec iov; 943 struct iovec iov;
836 struct timeval tv; 944 struct timeval tv;
837 struct sockaddr *addr; 945 void *buf = NULL;
838 946
839 if(sock == -1) { 947 if(sock == -1) {
840 errno = 0; 948 errno = 0;
841 crash("Attempt to send on bogus socket"); 949 crash("Attempt to send on bogus socket");
842 return -1; 950 return -1;
843 } 951 }
844 addr = (struct sockaddr *)&host->saddr_in;
845 952
846 if(!packet.buf) { 953 if(!buf) {
847 if (!(packet.buf = malloc(icmp_pkt_size))) { 954 if (!(buf = malloc(icmp_pkt_size))) {
848 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", 955 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
849 icmp_pkt_size); 956 icmp_pkt_size);
850 return -1; /* might be reached if we're in debug mode */ 957 return -1; /* might be reached if we're in debug mode */
851 } 958 }
852 } 959 }
853 memset(packet.buf, 0, icmp_pkt_size); 960 memset(buf, 0, icmp_pkt_size);
854 961
855 if((gettimeofday(&tv, &tz)) == -1) return -1; 962 if((gettimeofday(&tv, &tz)) == -1) {
963 free(buf);
964 return -1;
965 }
856 966
857 data.ping_id = 10; /* host->icmp.icmp_sent; */ 967 data.ping_id = 10; /* host->icmp.icmp_sent; */
858 memcpy(&data.stime, &tv, sizeof(tv)); 968 memcpy(&data.stime, &tv, sizeof(tv));
859 memcpy(&packet.icp->icmp_data, &data, sizeof(data)); 969
860 packet.icp->icmp_type = ICMP_ECHO; 970 if (address_family == AF_INET) {
861 packet.icp->icmp_code = 0; 971 struct icmp *icp = (struct icmp*)buf;
862 packet.icp->icmp_cksum = 0; 972
863 packet.icp->icmp_id = htons(pid); 973 memcpy(&icp->icmp_data, &data, sizeof(data));
864 packet.icp->icmp_seq = htons(host->id++); 974
865 packet.icp->icmp_cksum = icmp_checksum(packet.cksum_in, icmp_pkt_size); 975 icp->icmp_type = ICMP_ECHO;
866 976 icp->icmp_code = 0;
867 if (debug > 2) 977 icp->icmp_cksum = 0;
868 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", 978 icp->icmp_id = htons(pid);
869 (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), 979 icp->icmp_seq = htons(host->id++);
870 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, 980 icp->icmp_cksum = icmp_checksum((unsigned short*)buf, icmp_pkt_size);
871 host->name); 981
982 if (debug > 2)
983 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
984 (unsigned long)sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum, host->name);
985 }
986 else {
987 struct icmp6_hdr *icp6 = (struct icmp6_hdr*)buf;
988 memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data));
989 icp6->icmp6_type = ICMP6_ECHO_REQUEST;
990 icp6->icmp6_code = 0;
991 icp6->icmp6_cksum = 0;
992 icp6->icmp6_id = htons(pid);
993 icp6->icmp6_seq = htons(host->id++);
994 // let checksum be calculated automatically
995
996 if (debug > 2) {
997 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
998 (unsigned long)sizeof(data), ntohs(icp6->icmp6_id),
999 ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name);
1000 }
1001 }
872 1002
873 memset(&iov, 0, sizeof(iov)); 1003 memset(&iov, 0, sizeof(iov));
874 iov.iov_base = packet.buf; 1004 iov.iov_base = buf;
875 iov.iov_len = icmp_pkt_size; 1005 iov.iov_len = icmp_pkt_size;
876 1006
877 memset(&hdr, 0, sizeof(hdr)); 1007 memset(&hdr, 0, sizeof(hdr));
878 hdr.msg_name = addr; 1008 hdr.msg_name = (struct sockaddr *)&host->saddr_in;
879 hdr.msg_namelen = sizeof(struct sockaddr); 1009 hdr.msg_namelen = sizeof(struct sockaddr_storage);
880 hdr.msg_iov = &iov; 1010 hdr.msg_iov = &iov;
881 hdr.msg_iovlen = 1; 1011 hdr.msg_iovlen = 1;
882 1012
1013 errno = 0;
1014
883/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ 1015/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */
884#ifdef MSG_CONFIRM 1016#ifdef MSG_CONFIRM
885 len = sendmsg(sock, &hdr, MSG_CONFIRM); 1017 len = sendmsg(sock, &hdr, MSG_CONFIRM);
@@ -887,9 +1019,15 @@ send_icmp_ping(int sock, struct rta_host *host)
887 len = sendmsg(sock, &hdr, 0); 1019 len = sendmsg(sock, &hdr, 0);
888#endif 1020#endif
889 1021
1022 free(buf);
1023
890 if(len < 0 || (unsigned int)len != icmp_pkt_size) { 1024 if(len < 0 || (unsigned int)len != icmp_pkt_size) {
891 if(debug) printf("Failed to send ping to %s\n", 1025 if(debug) {
892 inet_ntoa(host->saddr_in.sin_addr)); 1026 char address[INET6_ADDRSTRLEN];
1027 parse_address((struct sockaddr_storage *)&host->saddr_in, address, sizeof(address));
1028 printf("Failed to send ping to %s: %s\n", address, strerror(errno));
1029 }
1030 errno = 0;
893 return -1; 1031 return -1;
894 } 1032 }
895 1033
@@ -934,7 +1072,7 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
934 1072
935 if(!n) return 0; /* timeout */ 1073 if(!n) return 0; /* timeout */
936 1074
937 slen = sizeof(struct sockaddr); 1075 slen = sizeof(struct sockaddr_storage);
938 1076
939 memset(&iov, 0, sizeof(iov)); 1077 memset(&iov, 0, sizeof(iov));
940 iov.iov_base = buf; 1078 iov.iov_base = buf;
@@ -958,6 +1096,7 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
958 break ; 1096 break ;
959 } 1097 }
960 } 1098 }
1099
961 if (!chdr) 1100 if (!chdr)
962#endif // SO_TIMESTAMP 1101#endif // SO_TIMESTAMP
963 gettimeofday(tv, &tz); 1102 gettimeofday(tv, &tz);
@@ -991,6 +1130,7 @@ finish(int sig)
991 1130
992 /* iterate thrice to calculate values, give output, and print perfparse */ 1131 /* iterate thrice to calculate values, give output, and print perfparse */
993 host = list; 1132 host = list;
1133
994 while(host) { 1134 while(host) {
995 if(!host->icmp_recv) { 1135 if(!host->icmp_recv) {
996 /* rta 0 is ofcourse not entirely correct, but will still show up 1136 /* rta 0 is ofcourse not entirely correct, but will still show up
@@ -1039,10 +1179,12 @@ finish(int sig)
1039 if(!host->icmp_recv) { 1179 if(!host->icmp_recv) {
1040 status = STATE_CRITICAL; 1180 status = STATE_CRITICAL;
1041 if(host->flags & FLAG_LOST_CAUSE) { 1181 if(host->flags & FLAG_LOST_CAUSE) {
1182 char address[INET6_ADDRSTRLEN];
1183 parse_address(&host->error_addr, address, sizeof(address));
1042 printf("%s: %s @ %s. rta nan, lost %d%%", 1184 printf("%s: %s @ %s. rta nan, lost %d%%",
1043 host->name, 1185 host->name,
1044 get_icmp_error_msg(host->icmp_type, host->icmp_code), 1186 get_icmp_error_msg(host->icmp_type, host->icmp_code),
1045 inet_ntoa(host->error_addr), 1187 address,
1046 100); 1188 100);
1047 } 1189 }
1048 else { /* not marked as lost cause, so we have no flags for it */ 1190 else { /* not marked as lost cause, so we have no flags for it */
@@ -1104,7 +1246,6 @@ get_timevaldiff(struct timeval *early, struct timeval *later)
1104 { 1246 {
1105 return 0; 1247 return 0;
1106 } 1248 }
1107
1108 ret = (later->tv_sec - early->tv_sec) * 1000000; 1249 ret = (later->tv_sec - early->tv_sec) * 1000000;
1109 ret += later->tv_usec - early->tv_usec; 1250 ret += later->tv_usec - early->tv_usec;
1110 1251
@@ -1112,18 +1253,35 @@ get_timevaldiff(struct timeval *early, struct timeval *later)
1112} 1253}
1113 1254
1114static int 1255static int
1115add_target_ip(char *arg, struct in_addr *in) 1256add_target_ip(char *arg, struct sockaddr_storage *in)
1116{ 1257{
1117 struct rta_host *host; 1258 struct rta_host *host;
1259 struct sockaddr_in *sin, *host_sin;
1260 struct sockaddr_in6 *sin6, *host_sin6;
1261
1262 if (address_family == AF_INET)
1263 sin = (struct sockaddr_in *)in;
1264 else
1265 sin6 = (struct sockaddr_in6 *)in;
1118 1266
1119 /* disregard obviously stupid addresses */ 1267
1120 if(in->s_addr == INADDR_NONE || in->s_addr == INADDR_ANY) 1268
1269 /* disregard obviously stupid addresses
1270 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
1271 if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE
1272 || sin->sin_addr.s_addr == INADDR_ANY)))
1273 || (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
1121 return -1; 1274 return -1;
1275 }
1122 1276
1123 /* no point in adding two identical IP's, so don't. ;) */ 1277 /* no point in adding two identical IP's, so don't. ;) */
1124 host = list; 1278 host = list;
1125 while(host) { 1279 while(host) {
1126 if(host->saddr_in.sin_addr.s_addr == in->s_addr) { 1280 host_sin = (struct sockaddr_in *)&host->saddr_in;
1281 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1282
1283 if( (address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr)
1284 || (address_family == AF_INET6 && host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) {
1127 if(debug) printf("Identical IP already exists. Not adding %s\n", arg); 1285 if(debug) printf("Identical IP already exists. Not adding %s\n", arg);
1128 return -1; 1286 return -1;
1129 } 1287 }
@@ -1131,19 +1289,29 @@ add_target_ip(char *arg, struct in_addr *in)
1131 } 1289 }
1132 1290
1133 /* add the fresh ip */ 1291 /* add the fresh ip */
1134 host = malloc(sizeof(struct rta_host)); 1292 host = (struct rta_host*)malloc(sizeof(struct rta_host));
1135 if(!host) { 1293 if(!host) {
1294 char straddr[INET6_ADDRSTRLEN];
1295 parse_address((struct sockaddr_storage*)&in, straddr, sizeof(straddr));
1136 crash("add_target_ip(%s, %s): malloc(%d) failed", 1296 crash("add_target_ip(%s, %s): malloc(%d) failed",
1137 arg, inet_ntoa(*in), sizeof(struct rta_host)); 1297 arg, straddr, sizeof(struct rta_host));
1138 } 1298 }
1139 memset(host, 0, sizeof(struct rta_host)); 1299 memset(host, 0, sizeof(struct rta_host));
1140 1300
1141 /* set the values. use calling name for output */ 1301 /* set the values. use calling name for output */
1142 host->name = strdup(arg); 1302 host->name = strdup(arg);
1143 1303
1144 /* fill out the sockaddr_in struct */ 1304 /* fill out the sockaddr_storage struct */
1145 host->saddr_in.sin_family = AF_INET; 1305 if(address_family == AF_INET) {
1146 host->saddr_in.sin_addr.s_addr = in->s_addr; 1306 host_sin = (struct sockaddr_in *)&host->saddr_in;
1307 host_sin->sin_family = AF_INET;
1308 host_sin->sin_addr.s_addr = sin->sin_addr.s_addr;
1309 }
1310 else {
1311 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1312 host_sin6->sin6_family = AF_INET6;
1313 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr);
1314 }
1147 1315
1148 host->rtmin = DBL_MAX; 1316 host->rtmin = DBL_MAX;
1149 1317
@@ -1160,31 +1328,67 @@ add_target_ip(char *arg, struct in_addr *in)
1160static int 1328static int
1161add_target(char *arg) 1329add_target(char *arg)
1162{ 1330{
1163 int i; 1331 int error, result;
1164 struct hostent *he; 1332 struct sockaddr_storage ip;
1165 struct in_addr *in, ip; 1333 struct addrinfo hints, *res, *p;
1334 struct sockaddr_in *sin;
1335 struct sockaddr_in6 *sin6;
1336
1337 switch (address_family) {
1338 case -1:
1339 /* -4 and -6 are not specified on cmdline */
1340 address_family = AF_INET;
1341 sin = (struct sockaddr_in *)&ip;
1342 result = inet_pton(address_family, arg, &sin->sin_addr);
1343#ifdef USE_IPV6
1344 if( result != 1 ){
1345 address_family = AF_INET6;
1346 sin6 = (struct sockaddr_in6 *)&ip;
1347 result = inet_pton(address_family, arg, &sin6->sin6_addr);
1348 }
1349#endif
1350 /* If we don't find any valid addresses, we still don't know the address_family */
1351 if ( result != 1) {
1352 address_family = -1;
1353 }
1354 break;
1355 case AF_INET:
1356 sin = (struct sockaddr_in *)&ip;
1357 result = inet_pton(address_family, arg, &sin->sin_addr);
1358 break;
1359 case AF_INET6:
1360 sin6 = (struct sockaddr_in6 *)&ip;
1361 result = inet_pton(address_family, arg, &sin6->sin6_addr);
1362 break;
1363 default: crash("Address family not supported");
1364 }
1166 1365
1167 /* don't resolve if we don't have to */ 1366 /* don't resolve if we don't have to */
1168 if((ip.s_addr = inet_addr(arg)) != INADDR_NONE) { 1367 if(result == 1) {
1169 /* don't add all ip's if we were given a specific one */ 1368 /* don't add all ip's if we were given a specific one */
1170 return add_target_ip(arg, &ip); 1369 return add_target_ip(arg, &ip);
1171 /* he = gethostbyaddr((char *)in, sizeof(struct in_addr), AF_INET); */
1172 /* if(!he) return add_target_ip(arg, in); */
1173 } 1370 }
1174 else { 1371 else {
1175 errno = 0; 1372 errno = 0;
1176 he = gethostbyname(arg); 1373 memset(&hints, 0, sizeof(hints));
1177 if(!he) { 1374 if (address_family == -1) {
1375 hints.ai_family = AF_UNSPEC;
1376 } else {
1377 hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6;
1378 }
1379 hints.ai_socktype = SOCK_RAW;
1380 if((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) {
1178 errno = 0; 1381 errno = 0;
1179 crash("Failed to resolve %s", arg); 1382 crash("Failed to resolve %s: %s", arg, gai_strerror(error));
1180 return -1; 1383 return -1;
1181 } 1384 }
1385 address_family = res->ai_family;
1182 } 1386 }
1183 1387
1184 /* possibly add all the IP's as targets */ 1388 /* possibly add all the IP's as targets */
1185 for(i = 0; he->h_addr_list[i]; i++) { 1389 for(p = res; p != NULL; p = p->ai_next) {
1186 in = (struct in_addr *)he->h_addr_list[i]; 1390 memcpy(&ip, p->ai_addr, p->ai_addrlen);
1187 add_target_ip(arg, in); 1391 add_target_ip(arg, &ip);
1188 1392
1189 /* this is silly, but it works */ 1393 /* this is silly, but it works */
1190 if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { 1394 if(mode == MODE_HOSTCHECK || mode == MODE_ALL) {
@@ -1193,6 +1397,7 @@ add_target(char *arg)
1193 } 1397 }
1194 break; 1398 break;
1195 } 1399 }
1400 freeaddrinfo(res);
1196 1401
1197 return 0; 1402 return 0;
1198} 1403}
@@ -1203,7 +1408,7 @@ set_source_ip(char *arg)
1203 struct sockaddr_in src; 1408 struct sockaddr_in src;
1204 1409
1205 memset(&src, 0, sizeof(src)); 1410 memset(&src, 0, sizeof(src));
1206 src.sin_family = AF_INET; 1411 src.sin_family = address_family;
1207 if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) 1412 if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE)
1208 src.sin_addr.s_addr = get_ip_address(arg); 1413 src.sin_addr.s_addr = get_ip_address(arg);
1209 if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) 1414 if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1)
@@ -1311,12 +1516,12 @@ get_threshold(char *str, threshold *th)
1311unsigned short 1516unsigned short
1312icmp_checksum(unsigned short *p, int n) 1517icmp_checksum(unsigned short *p, int n)
1313{ 1518{
1314 register unsigned short cksum; 1519 unsigned short cksum;
1315 register long sum = 0; 1520 long sum = 0;
1316 1521
1317 while(n > 1) { 1522 while(n > 2) {
1318 sum += *p++; 1523 sum += *p++;
1319 n -= 2; 1524 n -= sizeof(unsigned short);
1320 } 1525 }
1321 1526
1322 /* mop up the occasional odd byte */ 1527 /* mop up the occasional odd byte */
@@ -1347,6 +1552,8 @@ print_help(void)
1347 1552
1348 printf (" %s\n", "-H"); 1553 printf (" %s\n", "-H");
1349 printf (" %s\n", _("specify a target")); 1554 printf (" %s\n", _("specify a target"));
1555 printf (" %s\n", "[-4|-6]");
1556 printf (" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets"));
1350 printf (" %s\n", "-w"); 1557 printf (" %s\n", "-w");
1351 printf (" %s", _("warning threshold (currently ")); 1558 printf (" %s", _("warning threshold (currently "));
1352 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); 1559 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl);
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 826eb8d9..ced13d05 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -35,6 +35,7 @@ const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "utils_cmd.h"
38 39
39#include "netutils.h" 40#include "netutils.h"
40 41
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index f2061636..d4d0b885 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -56,6 +56,7 @@ char **expected_address = NULL;
56int expected_address_cnt = 0; 56int expected_address_cnt = 0;
57 57
58int expect_authority = FALSE; 58int expect_authority = FALSE;
59int all_match = FALSE;
59thresholds *time_thresholds = NULL; 60thresholds *time_thresholds = NULL;
60 61
61static int 62static int
@@ -168,8 +169,8 @@ main (int argc, char **argv)
168 temp_buffer++; 169 temp_buffer++;
169 170
170 /* Strip leading spaces */ 171 /* Strip leading spaces */
171 for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++) 172 while (*temp_buffer == ' ')
172 /* NOOP */; 173 temp_buffer++;
173 174
174 strip(temp_buffer); 175 strip(temp_buffer);
175 if (temp_buffer==NULL || strlen(temp_buffer)==0) { 176 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
@@ -228,16 +229,27 @@ main (int argc, char **argv)
228 if (result == STATE_OK && expected_address_cnt > 0) { 229 if (result == STATE_OK && expected_address_cnt > 0) {
229 result = STATE_CRITICAL; 230 result = STATE_CRITICAL;
230 temp_buffer = ""; 231 temp_buffer = "";
232 unsigned long expect_match = (1 << expected_address_cnt) - 1;
233 unsigned long addr_match = (1 << n_addresses) - 1;
231 234
232 for (i=0; i<expected_address_cnt; i++) { 235 for (i=0; i<expected_address_cnt; i++) {
236 int j;
233 /* check if we get a match on 'raw' ip or cidr */ 237 /* check if we get a match on 'raw' ip or cidr */
234 if ( strcmp(address, expected_address[i]) == 0 238 for (j=0; j<n_addresses; j++) {
235 || ip_match_cidr(address, expected_address[i]) ) 239 if ( strcmp(addresses[j], expected_address[i]) == 0
236 result = STATE_OK; 240 || ip_match_cidr(addresses[j], expected_address[i]) ) {
241 result = STATE_OK;
242 addr_match &= ~(1 << j);
243 expect_match &= ~(1 << i);
244 }
245 }
237 246
238 /* prepare an error string */ 247 /* prepare an error string */
239 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); 248 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
240 } 249 }
250 /* check if expected_address must cover all in addresses and none may be missing */
251 if (all_match && (expect_match != 0 || addr_match != 0))
252 result = STATE_CRITICAL;
241 if (result == STATE_CRITICAL) { 253 if (result == STATE_CRITICAL) {
242 /* Strip off last semicolon... */ 254 /* Strip off last semicolon... */
243 temp_buffer[strlen(temp_buffer)-2] = '\0'; 255 temp_buffer[strlen(temp_buffer)-2] = '\0';
@@ -401,6 +413,7 @@ process_arguments (int argc, char **argv)
401 {"reverse-server", required_argument, 0, 'r'}, 413 {"reverse-server", required_argument, 0, 'r'},
402 {"expected-address", required_argument, 0, 'a'}, 414 {"expected-address", required_argument, 0, 'a'},
403 {"expect-authority", no_argument, 0, 'A'}, 415 {"expect-authority", no_argument, 0, 'A'},
416 {"all", no_argument, 0, 'L'},
404 {"warning", required_argument, 0, 'w'}, 417 {"warning", required_argument, 0, 'w'},
405 {"critical", required_argument, 0, 'c'}, 418 {"critical", required_argument, 0, 'c'},
406 {0, 0, 0, 0} 419 {0, 0, 0, 0}
@@ -414,7 +427,7 @@ process_arguments (int argc, char **argv)
414 strcpy (argv[c], "-t"); 427 strcpy (argv[c], "-t");
415 428
416 while (1) { 429 while (1) {
417 c = getopt_long (argc, argv, "hVvAt:H:s:r:a:w:c:", long_opts, &opt_index); 430 c = getopt_long (argc, argv, "hVvALt:H:s:r:a:w:c:", long_opts, &opt_index);
418 431
419 if (c == -1 || c == EOF) 432 if (c == -1 || c == EOF)
420 break; 433 break;
@@ -462,6 +475,9 @@ process_arguments (int argc, char **argv)
462 case 'A': /* expect authority */ 475 case 'A': /* expect authority */
463 expect_authority = TRUE; 476 expect_authority = TRUE;
464 break; 477 break;
478 case 'L': /* all must match */
479 all_match = TRUE;
480 break;
465 case 'w': 481 case 'w':
466 warning = optarg; 482 warning = optarg;
467 break; 483 break;
@@ -530,14 +546,16 @@ print_help (void)
530 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n"); 546 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
531 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end")); 547 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
532 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any")); 548 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
533 printf (" %s\n", _("value match). If multiple addresses are returned at once, you have to match")); 549 printf (" %s\n", _("value matches)."));
534 printf (" %s\n", _("the whole string of addresses separated with commas (sorted alphabetically)."));
535 printf (" -A, --expect-authority\n"); 550 printf (" -A, --expect-authority\n");
536 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup")); 551 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
537 printf (" -w, --warning=seconds\n"); 552 printf (" -w, --warning=seconds\n");
538 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off")); 553 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
539 printf (" -c, --critical=seconds\n"); 554 printf (" -c, --critical=seconds\n");
540 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off")); 555 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
556 printf (" -L, --all\n");
557 printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
558 printf (" %s\n", _("returned. Default off"));
541 559
542 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 560 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
543 561
@@ -549,5 +567,5 @@ void
549print_usage (void) 567print_usage (void)
550{ 568{
551 printf ("%s\n", _("Usage:")); 569 printf ("%s\n", _("Usage:"));
552 printf ("%s -H host [-s server] [-a expected-address] [-A] [-t timeout] [-w warn] [-c crit]\n", progname); 570 printf ("%s -H host [-s server] [-a expected-address] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
553} 571}
diff --git a/plugins/check_hpjd.c b/plugins/check_hpjd.c
index f159f5a2..65465567 100644
--- a/plugins/check_hpjd.c
+++ b/plugins/check_hpjd.c
@@ -67,6 +67,7 @@ void print_usage (void);
67char *community = NULL; 67char *community = NULL;
68char *address = NULL; 68char *address = NULL;
69char *port = NULL; 69char *port = NULL;
70int check_paper_out = 1;
70 71
71int 72int
72main (int argc, char **argv) 73main (int argc, char **argv)
@@ -240,7 +241,8 @@ main (int argc, char **argv)
240 strcpy (errmsg, _("Paper Jam")); 241 strcpy (errmsg, _("Paper Jam"));
241 } 242 }
242 else if (paper_out) { 243 else if (paper_out) {
243 result = STATE_WARNING; 244 if (check_paper_out)
245 result = STATE_WARNING;
244 strcpy (errmsg, _("Out of Paper")); 246 strcpy (errmsg, _("Out of Paper"));
245 } 247 }
246 else if (line_status == OFFLINE) { 248 else if (line_status == OFFLINE) {
@@ -325,7 +327,7 @@ process_arguments (int argc, char **argv)
325 327
326 328
327 while (1) { 329 while (1) {
328 c = getopt_long (argc, argv, "+hVH:C:p:", longopts, &option); 330 c = getopt_long (argc, argv, "+hVH:C:p:D", longopts, &option);
329 331
330 if (c == -1 || c == EOF || c == 1) 332 if (c == -1 || c == EOF || c == 1)
331 break; 333 break;
@@ -347,6 +349,8 @@ process_arguments (int argc, char **argv)
347 usage2 (_("Port must be a positive short integer"), optarg); 349 usage2 (_("Port must be a positive short integer"), optarg);
348 else 350 else
349 port = atoi(optarg); 351 port = atoi(optarg);
352 case 'D': /* disable paper out check*/
353 check_paper_out = 0;
350 break; 354 break;
351 case 'V': /* version */ 355 case 'V': /* version */
352 print_revision (progname, NP_VERSION); 356 print_revision (progname, NP_VERSION);
@@ -420,6 +424,8 @@ print_help (void)
420 printf (" %s", _("Specify the port to check ")); 424 printf (" %s", _("Specify the port to check "));
421 printf (_("(default=%s)"), DEFAULT_PORT); 425 printf (_("(default=%s)"), DEFAULT_PORT);
422 printf ("\n"); 426 printf ("\n");
427 printf (" %s\n", "-D");
428 printf (" %s", _("Disable paper check "));
423 429
424 printf (UT_SUPPORT); 430 printf (UT_SUPPORT);
425} 431}
@@ -430,5 +436,5 @@ void
430print_usage (void) 436print_usage (void)
431{ 437{
432 printf ("%s\n", _("Usage:")); 438 printf ("%s\n", _("Usage:"));
433 printf ("%s -H host [-C community] [-p port]\n", progname); 439 printf ("%s -H host [-C community] [-p port] [-D]\n", progname);
434} 440}
diff --git a/plugins/check_http.c b/plugins/check_http.c
index 856e1e90..de59a068 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -1155,6 +1155,8 @@ check_http (void)
1155 xasprintf (&msg, 1155 xasprintf (&msg,
1156 _("Invalid HTTP response received from host on port %d: %s\n"), 1156 _("Invalid HTTP response received from host on port %d: %s\n"),
1157 server_port, status_line); 1157 server_port, status_line);
1158 if (show_body)
1159 xasprintf (&msg, _("%s\n%s"), msg, page);
1158 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg); 1160 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
1159 } 1161 }
1160 1162
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 5cd47093..11ce6916 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -34,6 +34,7 @@ const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
36#include "utils.h" 36#include "utils.h"
37#include "utils_cmd.h"
37 38
38#include "netutils.h" 39#include "netutils.h"
39#include <libpq-fe.h> 40#include <libpq-fe.h>
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index 0fcf4c68..d37c57c8 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -293,6 +293,7 @@ main (int argc, char **argv)
293 printf("%s", buffer); 293 printf("%s", buffer);
294 } 294 }
295 295
296 n = 0;
296 while (n < ncommands) { 297 while (n < ncommands) {
297 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 298 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n");
298 my_send(cmd_str, strlen(cmd_str)); 299 my_send(cmd_str, strlen(cmd_str));
diff --git a/plugins/common.h b/plugins/common.h
index 6bf4fca4..0f08e2f6 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -225,4 +225,18 @@ enum {
225# define __attribute__(x) /* do nothing */ 225# define __attribute__(x) /* do nothing */
226#endif 226#endif
227 227
228/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
229 * If that fails and the macro isn't defined, we fall back to an educated
230 * guess. There's no guarantee that our guess is adequate and the program
231 * will die with SIGSEGV if it isn't and the upper boundary is breached. */
232#define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */
233#define MAXFD_LIMIT 8192 /* upper limit of open files */
234#ifdef _SC_OPEN_MAX
235static long maxfd = 0;
236#elif defined(OPEN_MAX)
237# define maxfd OPEN_MAX
238#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
239# define maxfd DEFAULT_MAXFD
240#endif
241
228#endif /* _COMMON_H_ */ 242#endif /* _COMMON_H_ */
diff --git a/plugins/popen.c b/plugins/popen.c
index 592263fd..116d168d 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -78,7 +78,6 @@ RETSIGTYPE popen_timeout_alarm_handler (int);
78 78
79#define min(a,b) ((a) < (b) ? (a) : (b)) 79#define min(a,b) ((a) < (b) ? (a) : (b))
80#define max(a,b) ((a) > (b) ? (a) : (b)) 80#define max(a,b) ((a) > (b) ? (a) : (b))
81int open_max (void); /* {Prog openmax} */
82static void err_sys (const char *, ...) __attribute__((noreturn,format(printf, 1, 2))); 81static void err_sys (const char *, ...) __attribute__((noreturn,format(printf, 1, 2)));
83char *rtrim (char *, const char *); 82char *rtrim (char *, const char *);
84 83
@@ -86,7 +85,6 @@ char *pname = NULL; /* caller can set this from argv[0] */
86 85
87/*int *childerr = NULL;*//* ptr to array allocated at run-time */ 86/*int *childerr = NULL;*//* ptr to array allocated at run-time */
88/*extern pid_t *childpid = NULL; *//* ptr to array allocated at run-time */ 87/*extern pid_t *childpid = NULL; *//* ptr to array allocated at run-time */
89static int maxfd; /* from our open_max(), {Prog openmax} */
90 88
91#ifdef REDHAT_SPOPEN_ERROR 89#ifdef REDHAT_SPOPEN_ERROR
92static volatile int childtermd = 0; 90static volatile int childtermd = 0;
@@ -187,13 +185,11 @@ spopen (const char *cmdstring)
187 argv[i] = NULL; 185 argv[i] = NULL;
188 186
189 if (childpid == NULL) { /* first time through */ 187 if (childpid == NULL) { /* first time through */
190 maxfd = open_max (); /* allocate zeroed out array for child pids */
191 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL) 188 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL)
192 return (NULL); 189 return (NULL);
193 } 190 }
194 191
195 if (child_stderr_array == NULL) { /* first time through */ 192 if (child_stderr_array == NULL) { /* first time through */
196 maxfd = open_max (); /* allocate zeroed out array for child pids */
197 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL) 193 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL)
198 return (NULL); 194 return (NULL);
199 } 195 }
@@ -273,15 +269,6 @@ spclose (FILE * fp)
273 return (1); 269 return (1);
274} 270}
275 271
276#ifdef OPEN_MAX
277static int openmax = OPEN_MAX;
278#else
279static int openmax = 0;
280#endif
281
282#define OPEN_MAX_GUESS 256 /* if OPEN_MAX is indeterminate */
283 /* no guarantee this is adequate */
284
285#ifdef REDHAT_SPOPEN_ERROR 272#ifdef REDHAT_SPOPEN_ERROR
286RETSIGTYPE 273RETSIGTYPE
287popen_sigchld_handler (int signo) 274popen_sigchld_handler (int signo)
@@ -311,22 +298,6 @@ popen_timeout_alarm_handler (int signo)
311} 298}
312 299
313 300
314int
315open_max (void)
316{
317 if (openmax == 0) { /* first time through */
318 errno = 0;
319 if ((openmax = sysconf (_SC_OPEN_MAX)) < 0) {
320 if (errno == 0)
321 openmax = OPEN_MAX_GUESS; /* it's indeterminate */
322 else
323 err_sys (_("sysconf error for _SC_OPEN_MAX"));
324 }
325 }
326 return (openmax);
327}
328
329
330/* Fatal error related to a system call. 301/* Fatal error related to a system call.
331 * Print a message and die. */ 302 * Print a message and die. */
332 303
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index 1a7c904f..c3828678 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -67,19 +67,6 @@
67 * occur in any number of threads simultaneously. */ 67 * occur in any number of threads simultaneously. */
68static pid_t *np_pids = NULL; 68static pid_t *np_pids = NULL;
69 69
70/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
71 * If that fails and the macro isn't defined, we fall back to an educated
72 * guess. There's no guarantee that our guess is adequate and the program
73 * will die with SIGSEGV if it isn't and the upper boundary is breached. */
74#ifdef _SC_OPEN_MAX
75static long maxfd = 0;
76#elif defined(OPEN_MAX)
77# define maxfd OPEN_MAX
78#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
79# define maxfd 256
80#endif
81
82
83/** prototypes **/ 70/** prototypes **/
84static int np_runcmd_open(const char *, int *, int *) 71static int np_runcmd_open(const char *, int *, int *)
85 __attribute__((__nonnull__(1, 2, 3))); 72 __attribute__((__nonnull__(1, 2, 3)));
diff --git a/plugins/t/NPTest.cache.travis b/plugins/t/NPTest.cache.travis
index 6ee45053..9b9f8059 100644
--- a/plugins/t/NPTest.cache.travis
+++ b/plugins/t/NPTest.cache.travis
@@ -50,5 +50,5 @@
50 'NP_SNMP_USER' => '', 50 'NP_SNMP_USER' => '',
51 'NP_SSH_CONFIGFILE' => '~/.ssh/config', 51 'NP_SSH_CONFIGFILE' => '~/.ssh/config',
52 'NP_SSH_HOST' => 'localhost', 52 'NP_SSH_HOST' => 'localhost',
53 'NP_SSH_IDENTITY' => '~/.ssh/id_dsa' 53 'NP_SSH_IDENTITY' => '~/.ssh/id_rsa'
54} 54}
diff --git a/plugins/tests/certs/server-cert.pem b/plugins/tests/certs/server-cert.pem
index 549e4f7e..b84b91d2 100644
--- a/plugins/tests/certs/server-cert.pem
+++ b/plugins/tests/certs/server-cert.pem
@@ -1,21 +1,24 @@
1-----BEGIN CERTIFICATE----- 1-----BEGIN CERTIFICATE-----
2MIIDYzCCAsygAwIBAgIJAL8LkpNwzYdxMA0GCSqGSIb3DQEBBAUAMH8xCzAJBgNV 2MIIEBjCCAu6gAwIBAgIJANbQ5QQrKhUGMA0GCSqGSIb3DQEBCwUAMIGXMQswCQYD
3BAYTAlVLMRMwEQYDVQQIEwpEZXJieXNoaXJlMQ8wDQYDVQQHEwZCZWxwZXIxFzAV 3VQQGEwJERTEQMA4GA1UECAwHQmF2YXJpYTEPMA0GA1UEBwwGTXVuaWNoMRswGQYD
4BgNVBAoTDk5hZ2lvcyBQbHVnaW5zMREwDwYDVQQDEwhUb24gVm9vbjEeMBwGCSqG 4VQQKDBJNb25pdG9yaW5nIFBsdWdpbnMxGzAZBgNVBAMMEk1vbml0b3JpbmcgUGx1
5SIb3DQEJARYPdG9udm9vbkBtYWMuY29tMB4XDTA5MDMwNTIxNDEyOFoXDTE5MDMw 5Z2luczErMCkGCSqGSIb3DQEJARYcZGV2ZWxAbW9uaXRvcmluZy1wbHVnaW5zLm9y
6MzIxNDEyOFowfzELMAkGA1UEBhMCVUsxEzARBgNVBAgTCkRlcmJ5c2hpcmUxDzAN 6ZzAeFw0xOTAyMTkxNTMxNDRaFw0yOTAyMTYxNTMxNDRaMIGXMQswCQYDVQQGEwJE
7BgNVBAcTBkJlbHBlcjEXMBUGA1UEChMOTmFnaW9zIFBsdWdpbnMxETAPBgNVBAMT 7RTEQMA4GA1UECAwHQmF2YXJpYTEPMA0GA1UEBwwGTXVuaWNoMRswGQYDVQQKDBJN
8CFRvbiBWb29uMR4wHAYJKoZIhvcNAQkBFg90b252b29uQG1hYy5jb20wgZ8wDQYJ 8b25pdG9yaW5nIFBsdWdpbnMxGzAZBgNVBAMMEk1vbml0b3JpbmcgUGx1Z2luczEr
9KoZIhvcNAQEBBQADgY0AMIGJAoGBAKcWMBtNtfY8vZXk0SN6/EYTVN/LOvaOSegy 9MCkGCSqGSIb3DQEJARYcZGV2ZWxAbW9uaXRvcmluZy1wbHVnaW5zLm9yZzCCASIw
10oVdLoGwuwjagk+XmCzvCqHZRp8lnCLay7AO8AQI7TSN02ihCcSrgGA9OT+HciIJ1 10DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgV2yp8pQvJuN+aJGdAe6Hd0tja
11l5/kEYUAuA1PR6YKK/T713zUAlMzy2tsugx5+xSsSEwsXkmne52jJiG/wuE5CLT0 11uteCPcNIcM92WLOF69TLTSYon1XDon4tHTh4Z5d4lD8bfsGzFVBmDSgWidhAUf+v
129pF8HQqHAgMBAAGjgeYwgeMwHQYDVR0OBBYEFGioSPQ/rdE19+zaeY2YvHTXlUDI 12EqEXwbp293ej/Frc0pXCvmrz6kI1tWrLtQhL/VdbxFYxhV7JjKb+PY3SxGFpSLPe
13MIGzBgNVHSMEgaswgaiAFGioSPQ/rdE19+zaeY2YvHTXlUDIoYGEpIGBMH8xCzAJ 13PQ/5SwVndv7rZIwcjseL22K5Uy2TIrkgzzm2pRs/IvoxRybYr/+LGoHyrtJC6AO8
14BgNVBAYTAlVLMRMwEQYDVQQIEwpEZXJieXNoaXJlMQ8wDQYDVQQHEwZCZWxwZXIx 14ylp8A/etL0gwtUvRnrnZeTQ2pA1uZ5QN3anTL8JP/ZRZYNegIkaawqMtTKbhM6pi
15FzAVBgNVBAoTDk5hZ2lvcyBQbHVnaW5zMREwDwYDVQQDEwhUb24gVm9vbjEeMBwG 15u3/4a3Uppvt0y7vmGfQlYejxCpICnMrvHMpw8L58zv/98AbCGjDU3UwCt6MCAwEA
16CSqGSIb3DQEJARYPdG9udm9vbkBtYWMuY29tggkAvwuSk3DNh3EwDAYDVR0TBAUw 16AaNTMFEwHQYDVR0OBBYEFG/UH6nGYPlVcM75UXzXBF5GZyrcMB8GA1UdIwQYMBaA
17AwEB/zANBgkqhkiG9w0BAQQFAAOBgQCdqasaIO6JiV5ONFG6Tr1++85UfEdZKMUX 17FG/UH6nGYPlVcM75UXzXBF5GZyrcMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
18N2NHiNNUunolIZEYR+dW99ezKmHlDiQ/tMgoLVYpl2Ubho2pAkLGQR+W0ZASgWQ1 18AQELBQADggEBAGwitJPOnlIKLndNf+iCLMIs0dxsl8kAaejFcjoT0n4ja7Y6Zrqz
19NjfV27Rv0y6lYQMTA0lVAU93L1x9reo3FMedmL5+H+lIEpLCxEPtAJNISrJOneZB 19VSIidzz9vQWvy24xKJpAOdj/iLRHCUOG+Pf5fA6+/FiuqXr6gE2/lm0eC58BNONr
20W5jDadwkoQ== 20E5OzjQ/VoQ8RX4hDntgu6FYbaVa/vhwn16igt9qmdNGGZXf2/+DM3JADwyaA4EK8
21vm7KdofX9zkxXecHPNvf3jiVLPiDDt6tkGpHPEsyP/yc+RUdltUeZvHfliV0cCuC
22jJX+Fm9ysjSpHIFFr+jUMuMHibWoOD8iy3eYxfCDoWsH488pCbj8MNuAq6vd6DBk
23bOZxDz43vjWuYMkwXJTxJQh7Pne6kK0vE1g=
21-----END CERTIFICATE----- 24-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/server-key.pem b/plugins/tests/certs/server-key.pem
index eacaeaa3..11947555 100644
--- a/plugins/tests/certs/server-key.pem
+++ b/plugins/tests/certs/server-key.pem
@@ -1,15 +1,28 @@
1-----BEGIN RSA PRIVATE KEY----- 1-----BEGIN PRIVATE KEY-----
2MIICWwIBAAKBgQCnFjAbTbX2PL2V5NEjevxGE1Tfyzr2jknoMqFXS6BsLsI2oJPl 2MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCoFdsqfKULybjf
35gs7wqh2UafJZwi2suwDvAECO00jdNooQnEq4BgPTk/h3IiCdZef5BGFALgNT0em 3miRnQHuh3dLY2rrXgj3DSHDPdlizhevUy00mKJ9Vw6J+LR04eGeXeJQ/G37BsxVQ
4Civ0+9d81AJTM8trbLoMefsUrEhMLF5Jp3udoyYhv8LhOQi09PaRfB0KhwIDAQAB 4Zg0oFonYQFH/rxKhF8G6dvd3o/xa3NKVwr5q8+pCNbVqy7UIS/1XW8RWMYVeyYym
5AoGAfpxclcP8N3vteXErXURrd7pcXT0GECDgNjhvc9PV20RPXM+vYs1AA+fMeeQE 5/j2N0sRhaUiz3j0P+UsFZ3b+62SMHI7Hi9tiuVMtkyK5IM85tqUbPyL6MUcm2K//
6TaRqwO6x016aMRO4rz5ztYArecTBznkds1k59pkN/Ne/nsueU4tvGK8MNyS2o986 6ixqB8q7SQugDvMpafAP3rS9IMLVL0Z652Xk0NqQNbmeUDd2p0y/CT/2UWWDXoCJG
7Voohqkaq4Lcy1bcHJb9su1ELjegEr1R76Mz452Hsy+uTbAECQQDcg/tZWKVeh5CQ 7msKjLUym4TOqYrt/+Gt1Kab7dMu75hn0JWHo8QqSApzK7xzKcPC+fM7//fAGwhow
8dOEB3YWHwfn0NDgfPm/X2i2kAZ7n7URaUy/ffdlfsrr1mBtHCfedLoOxmmlNfEpM 81N1MArejAgMBAAECggEANuvdTwanTzC8jaNqHaq+OuemS2E9B8nwsGxtH/zFgvNR
9hXAAurSHAkEAwfk7fEb0iN0Sj9gTozO7c6Ky10KwePZyjVzqSQIiJq3NX8BEaIeb 9WZiMPtmrJnTkFWJcV+VPw/iMSAqN4nDHmBugVOb4Z4asxGTKK4T9shXJSnh0rqPU
1051TXxE5VxaLjjMLRkA0hWTYXClgERFZ6AQJAN7ChPqwzf08PRFwwIw911JY5cOHr 1000ZsvbmxY6z0+E5TesCJqQ+9GYTY1V357V7JchvaOxIRxWPqg9urHbru8OCtW/I5
11NoDHMCUql5vNLNdwBruxgGjBB/kUXEfgw60RusFvgt/zLh1wiii844JDawJAGQBF 11Fh5HPUZlgCvlMpjlhyjydIf/oXyVA3RNsXlwe8+2cKuGIrjEzm2j9o3VF0sctTX0
12sYP3urg7zzx7c3qUe5gJ0wLuefjR1PSX4ecbfb7DDMdcSdjIuG1QDiZGmd2f1KG7 12ItP8A9qDmDQN7GIWX0MW6gncojpS1omC2wcFsdjj/xfPyiDal1X4aq/2YqG8351c
13nwSCOtxk5dloW2KGAQJAQh/iBn0QhfKLFAP5eZBVk8E8XlZuw+S2DLy5SnBlIiYJ 13YlM/+6Va0u9WWE/i64gASTAVqpMV4Yg8y0gGycuA0QKBgQDbgI2QeLd3FvMcURiU
14GB5I2OClgtudXMv1labFrcST8O9eFrtsrhU1iUGUOw== 14l3w9qJgw/Jp3jaNC/9LkVGGz4f4lKKB67lPZvI4noMK8GqO/LcXgqP/RY1oJojoA
15-----END RSA PRIVATE KEY----- 15/6JKVvzYGASZ7VgMoG9bk1AneP1PGdibuTUEwimGlcObxnDFIC/yjwPFu3jIdqdS
16zZi1RZzyqAogN5y3SBEypSmn9wKBgQDECKsqqlcizmCl8v5aVk875AzGN+DOHZqx
17bkmztlnLO/2e2Fmk3G5Vvnui0FYisf8Eq19tUTQCF6lSfJlGQeFAT119wkFZhLu+
18FfLGqoEMH0ijJg/8PpdpFRK3I94YcISoTNN6yxMvE6xdDGfKCt5a+IX5bwQi9Zdc
19B242gEc6tQKBgA6tM8n7KFlAIZU9HuWgk2AUC8kKutFPmSD7tgAqXDYI4FNfugs+
20MEEYyHCB4UNujJBV4Ss6YZCAkh6eyD4U2aca1eElCfm40vBVMdzvpqZdAqLtWXxg
21D9l3mgszrFaYGCY2Fr6jLV9lP5g3xsxUjudf9jSLY9HvpfzjRrMaNATVAoGBALTl
22/vYfPMucwKlC5B7++J0e4/7iv6vUu9SyHocdZh1anb9AjPDKjXLIlZT4RhQ8R0XK
230wOw5JpttU2uN08TKkbLNk3/vYhbKVjPLjrQSseh8sjDLgsqw1QwIxYnniLVakVY
24p+rvjSNrNyqicQCMKQavwgocvSd5lJRTMwxOMezlAoGBAKWj71BX+0CK00/2S6lC
25TcNcuUPG0d8y1czZ4q6tUlG4htwq1FMOpaghATXjkdsOGTLS+H1aA0Kt7Ai9zDhc
26/bzOJEJ+jvBXV4Gcs7jl1r/HTKv0tT9ZSI5Vzkida0rfqxDGzcMVlLuCdH0cb8Iu
27N0wdmCAqlQwHR13+F1zrAD7V
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/check_http.t b/plugins/tests/check_http.t
index d6d31de1..006f1339 100755
--- a/plugins/tests/check_http.t
+++ b/plugins/tests/check_http.t
@@ -4,13 +4,13 @@
4# 4#
5# To create the https server certificate: 5# To create the https server certificate:
6# openssl req -new -x509 -keyout server-key.pem -out server-cert.pem -days 3650 -nodes 6# openssl req -new -x509 -keyout server-key.pem -out server-cert.pem -days 3650 -nodes
7# Country Name (2 letter code) [AU]:UK 7# Country Name (2 letter code) [AU]:DE
8# State or Province Name (full name) [Some-State]:Derbyshire 8# State or Province Name (full name) [Some-State]:Bavaria
9# Locality Name (eg, city) []:Belper 9# Locality Name (eg, city) []:Munich
10# Organization Name (eg, company) [Internet Widgits Pty Ltd]:Monitoring Plugins 10# Organization Name (eg, company) [Internet Widgits Pty Ltd]:Monitoring Plugins
11# Organizational Unit Name (eg, section) []: 11# Organizational Unit Name (eg, section) []:
12# Common Name (eg, YOUR name) []:Ton Voon 12# Common Name (e.g. server FQDN or YOUR name) []:Monitoring Plugins
13# Email Address []:tonvoon@mac.com 13# Email Address []:devel@monitoring-plugins.org
14 14
15use strict; 15use strict;
16use Test::More; 16use Test::More;
@@ -194,16 +194,16 @@ SKIP: {
194 194
195 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" ); 195 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
196 is( $result->return_code, 0, "$command -p $port_https -S -C 14" ); 196 is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
197 is( $result->output, 'OK - Certificate \'Ton Voon\' will expire on Sun Mar 3 21:41:28 2019 +0000.', "output ok" ); 197 is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on Fri Feb 16 15:31:44 2029 +0000.", "output ok" );
198 198
199 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" ); 199 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
200 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" ); 200 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
201 like( $result->output, '/WARNING - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(Sun Mar 3 21:41:28 2019 \+0000\)./', "output ok" ); 201 like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(Fri Feb 16 15:31:44 2029 \+0000\)./', "output ok" );
202 202
203 # Expired cert tests 203 # Expired cert tests
204 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" ); 204 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
205 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" ); 205 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
206 like( $result->output, '/CRITICAL - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(Sun Mar 3 21:41:28 2019 \+0000\)./', "output ok" ); 206 like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(Fri Feb 16 15:31:44 2029 \+0000\)./', "output ok" );
207 207
208 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" ); 208 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
209 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" ); 209 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t
index 73a68b20..85d6bf55 100755
--- a/plugins/tests/check_snmp.t
+++ b/plugins/tests/check_snmp.t
@@ -7,6 +7,7 @@ use strict;
7use Test::More; 7use Test::More;
8use NPTest; 8use NPTest;
9use FindBin qw($Bin); 9use FindBin qw($Bin);
10use POSIX qw/strftime/;
10 11
11my $tests = 67; 12my $tests = 67;
12# Check that all dependent modules are available 13# Check that all dependent modules are available
@@ -37,6 +38,7 @@ if ($@) {
37 38
38my $port_snmp = 16100 + int(rand(100)); 39my $port_snmp = 16100 + int(rand(100));
39 40
41my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
40 42
41# Start up server 43# Start up server
42my @pids; 44my @pids;
@@ -118,77 +120,81 @@ like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C
118"And now have fun with with this: \"C:\\\\\" 120"And now have fun with with this: \"C:\\\\\"
119because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); 121because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3");
120 122
121system("rm -f ".$ENV{'MP_STATE_PATH'}."/check_snmp/*"); 123system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*");
122$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
123is($res->return_code, 0, "Returns OK");
124is($res->output, "No previous data to calculate rate - assume okay");
125 124
126# Need to sleep, otherwise duration=0 125# run rate checks with faketime. rate checks depend on the exact amount of time spend between the
127sleep 1; 126# plugin runs which may fail on busy machines.
127# using faketime removes this race condition and also saves all the sleeps in between.
128SKIP: {
129 skip "No faketime binary found", 28 if !$faketime;
128 130
129$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 131 my $ts = time();
130is($res->return_code, 1, "WARNING - due to going above rate calculation" ); 132 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
131is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 "); 133 is($res->return_code, 0, "Returns OK");
134 is($res->output, "No previous data to calculate rate - assume okay");
132 135
133$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 136 # test rate 1 second later
134is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); 137 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
135is($res->output, "Time duration between plugin calls is invalid"); 138 is($res->return_code, 1, "WARNING - due to going above rate calculation" );
139 is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 ");
136 140
141 # test rate with same time
142 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
143 is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" );
144 is($res->output, "Time duration between plugin calls is invalid");
137 145
138$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
139is($res->return_code, 0, "OK for first call" );
140is($res->output, "No previous data to calculate rate - assume okay" );
141 146
142# Need to sleep, otherwise duration=0 147 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
143sleep 1; 148 is($res->return_code, 0, "OK for first call" );
149 is($res->output, "No previous data to calculate rate - assume okay" );
144 150
145$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 151 # test rate 1 second later
146is($res->return_code, 0, "OK as no thresholds" ); 152 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
147is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label"); 153 is($res->return_code, 0, "OK as no thresholds" );
154 is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label");
148 155
149sleep 2; 156 # test rate 3 seconds later
157 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
158 is($res->return_code, 0, "OK as no thresholds" );
159 is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval");
150 160
151$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
152is($res->return_code, 0, "OK as no thresholds" );
153is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval");
154 161
162 # label performance data check
163 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" );
164 is($res->return_code, 0, "OK as no thresholds" );
165 is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label");
155 166
156# label performance data check 167 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" );
157$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" ); 168 is($res->return_code, 0, "OK as no thresholds" );
158is($res->return_code, 0, "OK as no thresholds" ); 169 is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label");
159is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label");
160 170
161$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" ); 171 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" );
162is($res->return_code, 0, "OK as no thresholds" ); 172 is($res->return_code, 0, "OK as no thresholds" );
163is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label"); 173 is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label");
164 174
165$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" ); 175 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" );
166is($res->return_code, 0, "OK as no thresholds" ); 176 is($res->return_code, 0, "OK as no thresholds" );
167is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label"); 177 is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label");
168 178
169$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" ); 179 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" );
170is($res->return_code, 0, "OK as no thresholds" ); 180 is($res->return_code, 0, "OK as no thresholds" );
171is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label"); 181 is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label");
172 182
173$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" ); 183 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" );
174is($res->return_code, 0, "OK as no thresholds" ); 184 is($res->return_code, 0, "OK as no thresholds" );
175is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label"); 185 is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label");
176 186
177$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" );
178is($res->return_code, 0, "OK as no thresholds" );
179is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label");
180 187
188 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
189 is($res->return_code, 0, "OK for first call" );
190 is($res->output, "No previous data to calculate rate - assume okay" );
181 191
182$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); 192 # test 1 second later
183is($res->return_code, 0, "OK for first call" ); 193 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
184is($res->output, "No previous data to calculate rate - assume okay" ); 194 is($res->return_code, 0, "OK as no thresholds" );
185 195 is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier");
186# Need to sleep, otherwise duration=0 196};
187sleep 1;
188 197
189$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
190is($res->return_code, 0, "OK as no thresholds" );
191is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier");
192 198
193 199
194$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s '\"stringtests\"'" ); 200$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s '\"stringtests\"'" );
diff --git a/plugins/utils.c b/plugins/utils.c
index 231af92b..ee620133 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -36,9 +36,6 @@ extern const char *progname;
36#define STRLEN 64 36#define STRLEN 64
37#define TXTBLK 128 37#define TXTBLK 128
38 38
39unsigned int timeout_state = STATE_CRITICAL;
40unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
41
42time_t start_time, end_time; 39time_t start_time, end_time;
43 40
44/* ************************************************************************** 41/* **************************************************************************
@@ -148,33 +145,6 @@ print_revision (const char *command_name, const char *revision)
148 command_name, revision, PACKAGE, VERSION); 145 command_name, revision, PACKAGE, VERSION);
149} 146}
150 147
151const char *
152state_text (int result)
153{
154 switch (result) {
155 case STATE_OK:
156 return "OK";
157 case STATE_WARNING:
158 return "WARNING";
159 case STATE_CRITICAL:
160 return "CRITICAL";
161 case STATE_DEPENDENT:
162 return "DEPENDENT";
163 default:
164 return "UNKNOWN";
165 }
166}
167
168void
169timeout_alarm_handler (int signo)
170{
171 if (signo == SIGALRM) {
172 printf (_("%s - Plugin timed out after %d seconds\n"),
173 state_text(timeout_state), timeout_interval);
174 exit (timeout_state);
175 }
176}
177
178int 148int
179is_numeric (char *number) 149is_numeric (char *number)
180{ 150{
@@ -708,4 +678,3 @@ char *sperfdata_int (const char *label,
708 678
709 return data; 679 return data;
710} 680}
711
diff --git a/plugins/utils.h b/plugins/utils.h
index a436e1ca..6aa316fe 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -29,13 +29,6 @@ suite of plugins. */
29void support (void); 29void support (void);
30void print_revision (const char *, const char *); 30void print_revision (const char *, const char *);
31 31
32/* Handle timeouts */
33
34extern unsigned int timeout_state;
35extern unsigned int timeout_interval;
36
37RETSIGTYPE timeout_alarm_handler (int);
38
39extern time_t start_time, end_time; 32extern time_t start_time, end_time;
40 33
41/* Test input types */ 34/* Test input types */
@@ -89,8 +82,6 @@ void usage4(const char *) __attribute__((noreturn));
89void usage5(void) __attribute__((noreturn)); 82void usage5(void) __attribute__((noreturn));
90void usage_va(const char *fmt, ...) __attribute__((noreturn)); 83void usage_va(const char *fmt, ...) __attribute__((noreturn));
91 84
92const char *state_text (int);
93
94#define max(a,b) (((a)>(b))?(a):(b)) 85#define max(a,b) (((a)>(b))?(a):(b))
95#define min(a,b) (((a)<(b))?(a):(b)) 86#define min(a,b) (((a)<(b))?(a):(b))
96 87