summaryrefslogtreecommitdiffstats
path: root/plugins-root
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root')
-rw-r--r--plugins-root/Makefile.am5
-rw-r--r--plugins-root/check_dhcp.c19
-rw-r--r--plugins-root/check_icmp.c620
-rw-r--r--plugins-root/pst3.c2
-rw-r--r--plugins-root/t/check_dhcp.t9
-rw-r--r--plugins-root/t/check_icmp.t13
6 files changed, 464 insertions, 204 deletions
diff --git a/plugins-root/Makefile.am b/plugins-root/Makefile.am
index a1ebb6d..40aa020 100644
--- a/plugins-root/Makefile.am
+++ b/plugins-root/Makefile.am
@@ -26,7 +26,7 @@ EXTRA_PROGRAMS = pst3
26 26
27EXTRA_DIST = t pst3.c 27EXTRA_DIST = t pst3.c
28 28
29BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a 29BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
30NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS) 30NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS)
31NETLIBS = $(NETOBJS) $(SOCKETLIBS) 31NETLIBS = $(NETOBJS) $(SOCKETLIBS)
32 32
@@ -37,6 +37,9 @@ TESTS = @PLUGIN_TEST@
37test: 37test:
38 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl 38 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
39 39
40test-debug:
41 NPTEST_DEBUG=1 HARNESS_VERBOSE=1 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
42
40setuid_root_mode = ug=rx,u+s 43setuid_root_mode = ug=rx,u+s
41 44
42# /* Author Coreutils team - see ACKNOWLEDGEMENTS */ 45# /* Author Coreutils team - see ACKNOWLEDGEMENTS */
diff --git a/plugins-root/check_dhcp.c b/plugins-root/check_dhcp.c
index f4c2daf..2d22619 100644
--- a/plugins-root/check_dhcp.c
+++ b/plugins-root/check_dhcp.c
@@ -229,7 +229,7 @@ struct in_addr requested_address;
229 229
230int process_arguments(int, char **); 230int process_arguments(int, char **);
231int call_getopt(int, char **); 231int call_getopt(int, char **);
232int validate_arguments(int, int); 232int validate_arguments(int);
233void print_usage(void); 233void print_usage(void);
234void print_help(void); 234void print_help(void);
235 235
@@ -323,7 +323,8 @@ int get_hardware_address(int sock,char *interface_name){
323#elif defined(__bsd__) 323#elif defined(__bsd__)
324 /* King 2004 see ACKNOWLEDGEMENTS */ 324 /* King 2004 see ACKNOWLEDGEMENTS */
325 325
326 int mib[6], len; 326 size_t len;
327 int mib[6];
327 char *buf; 328 char *buf;
328 unsigned char *ptr; 329 unsigned char *ptr;
329 struct if_msghdr *ifm; 330 struct if_msghdr *ifm;
@@ -469,10 +470,6 @@ int send_dhcp_discover(int sock){
469 packet_xid=random(); 470 packet_xid=random();
470 discover_packet.xid=htonl(packet_xid); 471 discover_packet.xid=htonl(packet_xid);
471 472
472 /**** WHAT THE HECK IS UP WITH THIS?!? IF I DON'T MAKE THIS CALL, ONLY ONE SERVER RESPONSE IS PROCESSED!!!! ****/
473 /* downright bizzarre... */
474 ntohl(discover_packet.xid);
475
476 /*discover_packet.secs=htons(65535);*/ 473 /*discover_packet.secs=htons(65535);*/
477 discover_packet.secs=0xFF; 474 discover_packet.secs=0xFF;
478 475
@@ -1058,8 +1055,8 @@ int process_arguments(int argc, char **argv){
1058 return ERROR; 1055 return ERROR;
1059 1056
1060 arg_index = call_getopt(argc,argv); 1057 arg_index = call_getopt(argc,argv);
1061 return validate_arguments(argc,arg_index); 1058 return validate_arguments(argc);
1062 } 1059}
1063 1060
1064 1061
1065 1062
@@ -1157,13 +1154,13 @@ int call_getopt(int argc, char **argv){
1157 } 1154 }
1158 1155
1159 1156
1160int validate_arguments(int argc, int arg_index){ 1157int validate_arguments(int argc){
1161 1158
1162 if(argc-optind > 0) 1159 if(argc - optind > 0)
1163 usage(_("Got unexpected non-option argument")); 1160 usage(_("Got unexpected non-option argument"));
1164 1161
1165 return OK; 1162 return OK;
1166 } 1163}
1167 1164
1168 1165
1169#if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1166#if defined(__sun__) || defined(__solaris__) || defined(__hpux__)
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index a7fad36..72ad1d7 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -1,39 +1,39 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_icmp plugin 3* Monitoring check_icmp plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2005-2008 Monitoring Plugins Development Team 6* Copyright (c) 2005-2008 Monitoring Plugins Development Team
7* Original Author : Andreas Ericsson <ae@op5.se> 7* Original Author : Andreas Ericsson <ae@op5.se>
8* 8*
9* Description: 9* Description:
10* 10*
11* This file contains the check_icmp plugin 11* This file contains the check_icmp plugin
12* 12*
13* Relevant RFC's: 792 (ICMP), 791 (IP) 13* Relevant RFC's: 792 (ICMP), 791 (IP)
14* 14*
15* This program was modeled somewhat after the check_icmp program, 15* This program was modeled somewhat after the check_icmp program,
16* which was in turn a hack of fping (www.fping.org) but has been 16* which was in turn a hack of fping (www.fping.org) but has been
17* completely rewritten since to generate higher precision rta values, 17* completely rewritten since to generate higher precision rta values,
18* and support several different modes as well as setting ttl to control. 18* and support several different modes as well as setting ttl to control.
19* redundant routes. The only remainders of fping is currently a few 19* redundant routes. The only remainders of fping is currently a few
20* function names. 20* function names.
21* 21*
22* 22*
23* This program is free software: you can redistribute it and/or modify 23* This program is free software: you can redistribute it and/or modify
24* it under the terms of the GNU General Public License as published by 24* it under the terms of the GNU General Public License as published by
25* the Free Software Foundation, either version 3 of the License, or 25* the Free Software Foundation, either version 3 of the License, or
26* (at your option) any later version. 26* (at your option) any later version.
27* 27*
28* This program is distributed in the hope that it will be useful, 28* This program is distributed in the hope that it will be useful,
29* but WITHOUT ANY WARRANTY; without even the implied warranty of 29* but WITHOUT ANY WARRANTY; without even the implied warranty of
30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31* GNU General Public License for more details. 31* GNU General Public License for more details.
32* 32*
33* You should have received a copy of the GNU General Public License 33* You should have received a copy of the GNU General Public License
34* along with this program. If not, see <http://www.gnu.org/licenses/>. 34* along with this program. If not, see <http://www.gnu.org/licenses/>.
35* 35*
36* 36*
37*****************************************************************************/ 37*****************************************************************************/
38 38
39/* progname may change */ 39/* progname may change */
@@ -54,27 +54,20 @@ const char *email = "devel@monitoring-plugins.org";
54#if HAVE_SYS_SOCKIO_H 54#if HAVE_SYS_SOCKIO_H
55#include <sys/sockio.h> 55#include <sys/sockio.h>
56#endif 56#endif
57#include <sys/ioctl.h> 57
58#include <sys/time.h> 58#include <sys/time.h>
59#include <sys/types.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <stdarg.h>
63#include <unistd.h>
64#include <stddef.h>
65#include <errno.h> 59#include <errno.h>
66#include <string.h> 60#include <signal.h>
67#include <ctype.h> 61#include <ctype.h>
68#include <netdb.h> 62#include <float.h>
69#include <sys/socket.h>
70#include <net/if.h> 63#include <net/if.h>
71#include <netinet/in_systm.h> 64#include <netinet/in_systm.h>
72#include <netinet/in.h> 65#include <netinet/in.h>
73#include <netinet/ip.h> 66#include <netinet/ip.h>
67#include <netinet/ip6.h>
74#include <netinet/ip_icmp.h> 68#include <netinet/ip_icmp.h>
69#include <netinet/icmp6.h>
75#include <arpa/inet.h> 70#include <arpa/inet.h>
76#include <signal.h>
77#include <float.h>
78 71
79 72
80/** sometimes undefined system macros (quite a few, actually) **/ 73/** sometimes undefined system macros (quite a few, actually) **/
@@ -107,18 +100,14 @@ const char *email = "devel@monitoring-plugins.org";
107# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 100# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
108#endif 101#endif
109 102
110#ifndef DBL_MAX
111# define DBL_MAX 9.9999999999e999
112#endif
113
114typedef unsigned short range_t; /* type for get_range() -- unimplemented */ 103typedef unsigned short range_t; /* type for get_range() -- unimplemented */
115 104
116typedef struct rta_host { 105typedef struct rta_host {
117 unsigned short id; /* id in **table, and icmp pkts */ 106 unsigned short id; /* id in **table, and icmp pkts */
118 char *name; /* arg used for adding this host */ 107 char *name; /* arg used for adding this host */
119 char *msg; /* icmp error message, if any */ 108 char *msg; /* icmp error message, if any */
120 struct sockaddr_in saddr_in; /* the address of this host */ 109 struct sockaddr_storage saddr_in; /* the address of this host */
121 struct in_addr error_addr; /* stores address of error replies */ 110 struct sockaddr_storage error_addr; /* stores address of error replies */
122 unsigned long long time_waited; /* total time waited, in usecs */ 111 unsigned long long time_waited; /* total time waited, in usecs */
123 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */ 112 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
124 unsigned char icmp_type, icmp_code; /* type and code from errors */ 113 unsigned char icmp_type, icmp_code; /* type and code from errors */
@@ -161,6 +150,18 @@ typedef struct icmp_ping_data {
161 unsigned short ping_id; 150 unsigned short ping_id;
162} icmp_ping_data; 151} icmp_ping_data;
163 152
153typedef union ip_hdr {
154 struct ip ip;
155 struct ip6_hdr ip6;
156} ip_hdr;
157
158typedef union icmp_packet {
159 void *buf;
160 struct icmp *icp;
161 struct icmp6_hdr *icp6;
162 u_short *cksum_in;
163} icmp_packet;
164
164/* the different modes of this program are as follows: 165/* the different modes of this program are as follows:
165 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping) 166 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
166 * MODE_HOSTCHECK: Return immediately upon any sign of life 167 * MODE_HOSTCHECK: Return immediately upon any sign of life
@@ -212,9 +213,10 @@ static int get_threshold2(char *str, threshold *, threshold *, int type);
212static void run_checks(void); 213static void run_checks(void);
213static void set_source_ip(char *); 214static void set_source_ip(char *);
214static int add_target(char *); 215static int add_target(char *);
215static int add_target_ip(char *, struct in_addr *); 216static int add_target_ip(char *, struct sockaddr_storage *);
216static int handle_random_icmp(unsigned char *, struct sockaddr_in *); 217static int handle_random_icmp(unsigned char *, struct sockaddr_storage *);
217static unsigned short icmp_checksum(unsigned short *, int); 218static void parse_address(struct sockaddr_storage *, char *, int);
219static unsigned short icmp_checksum(uint16_t *, size_t);
218static void finish(int); 220static void finish(int);
219static void crash(const char *, ...); 221static void crash(const char *, ...);
220 222
@@ -230,7 +232,7 @@ static int mode, protocols, sockets, debug = 0, timeout = 10;
230static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; 232static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE;
231static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; 233static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN;
232 234
233static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0; 235static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0, ttl = 0;
234#define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) 236#define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost))
235static unsigned short targets_down = 0, targets = 0, packets = 0; 237static unsigned short targets_down = 0, targets = 0, packets = 0;
236#define targets_alive (targets - targets_down) 238#define targets_alive (targets - targets_down)
@@ -240,7 +242,6 @@ static pid_t pid;
240static struct timezone tz; 242static struct timezone tz;
241static struct timeval prog_start; 243static struct timeval prog_start;
242static unsigned long long max_completion_time = 0; 244static unsigned long long max_completion_time = 0;
243static unsigned char ttl = 0; /* outgoing ttl */
244static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ 245static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */
245static int min_hosts_alive = -1; 246static int min_hosts_alive = -1;
246float pkt_backoff_factor = 1.5; 247float pkt_backoff_factor = 1.5;
@@ -301,7 +302,7 @@ get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code)
301 break; 302 break;
302 303
303 case ICMP_TIMXCEED: 304 case ICMP_TIMXCEED:
304 /* really 'out of reach', or non-existant host behind a router serving 305 /* really 'out of reach', or non-existent host behind a router serving
305 * two different subnets */ 306 * two different subnets */
306 switch(icmp_code) { 307 switch(icmp_code) {
307 case ICMP_TIMXCEED_INTRANS: msg = "Time to live exceeded in transit"; break; 308 case ICMP_TIMXCEED_INTRANS: msg = "Time to live exceeded in transit"; break;
@@ -328,7 +329,7 @@ get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code)
328} 329}
329 330
330static int 331static int
331handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr) 332handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr)
332{ 333{
333 struct icmp p, sent_icmp; 334 struct icmp p, sent_icmp;
334 struct rta_host *host = NULL; 335 struct rta_host *host = NULL;
@@ -370,9 +371,11 @@ handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr)
370 /* it is indeed a response for us */ 371 /* it is indeed a response for us */
371 host = table[ntohs(sent_icmp.icmp_seq)/packets]; 372 host = table[ntohs(sent_icmp.icmp_seq)/packets];
372 if(debug) { 373 if(debug) {
374 char address[INET6_ADDRSTRLEN];
375 parse_address(addr, address, sizeof(address));
373 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", 376 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n",
374 get_icmp_error_msg(p.icmp_type, p.icmp_code), 377 get_icmp_error_msg(p.icmp_type, p.icmp_code),
375 inet_ntoa(addr->sin_addr), host->name); 378 address, host->name);
376 } 379 }
377 380
378 icmp_lost++; 381 icmp_lost++;
@@ -392,11 +395,23 @@ handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr)
392 } 395 }
393 host->icmp_type = p.icmp_type; 396 host->icmp_type = p.icmp_type;
394 host->icmp_code = p.icmp_code; 397 host->icmp_code = p.icmp_code;
395 host->error_addr.s_addr = addr->sin_addr.s_addr; 398 host->error_addr = *addr;
396 399
397 return 0; 400 return 0;
398} 401}
399 402
403void parse_address(struct sockaddr_storage *addr, char *address, int size)
404{
405 switch (address_family) {
406 case AF_INET:
407 inet_ntop(address_family, &((struct sockaddr_in *)addr)->sin_addr, address, size);
408 break;
409 case AF_INET6:
410 inet_ntop(address_family, &((struct sockaddr_in6 *)addr)->sin6_addr, address, size);
411 break;
412 }
413}
414
400int 415int
401main(int argc, char **argv) 416main(int argc, char **argv)
402{ 417{
@@ -412,7 +427,8 @@ main(int argc, char **argv)
412#ifdef SO_TIMESTAMP 427#ifdef SO_TIMESTAMP
413 int on = 1; 428 int on = 1;
414#endif 429#endif
415 430 char *source_ip = NULL;
431 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
416 setlocale (LC_ALL, ""); 432 setlocale (LC_ALL, "");
417 bindtextdomain (PACKAGE, LOCALEDIR); 433 bindtextdomain (PACKAGE, LOCALEDIR);
418 textdomain (PACKAGE); 434 textdomain (PACKAGE);
@@ -421,33 +437,8 @@ main(int argc, char **argv)
421 * that before pointer magic (esp. on network data) */ 437 * that before pointer magic (esp. on network data) */
422 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0; 438 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
423 439
424 if((icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1) 440 address_family = -1;
425 sockets |= HAVE_ICMP; 441 int icmp_proto = IPPROTO_ICMP;
426 else icmp_sockerrno = errno;
427
428 /* if((udp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) */
429 /* sockets |= HAVE_UDP; */
430 /* else udp_sockerrno = errno; */
431
432 /* if((tcp_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) */
433 /* sockets |= HAVE_TCP; */
434 /* else tcp_sockerrno = errno; */
435
436 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
437 setuid(getuid());
438
439#ifdef SO_TIMESTAMP
440 if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
441 if(debug) printf("Warning: no SO_TIMESTAMP support\n");
442#endif // SO_TIMESTAMP
443
444 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
445 environ = NULL;
446
447 /* use the pid to mark packets as ours */
448 /* Some systems have 32-bit pid_t so mask off only 16 bits */
449 pid = getpid() & 0xffff;
450 /* printf("pid = %u\n", pid); */
451 442
452 /* get calling name the old-fashioned way for portability instead 443 /* get calling name the old-fashioned way for portability instead
453 * of relying on the glibc-ism __progname */ 444 * of relying on the glibc-ism __progname */
@@ -473,7 +464,7 @@ main(int argc, char **argv)
473 warn.jitter = 40; 464 warn.jitter = 40;
474 warn.mos= 3.5; 465 warn.mos= 3.5;
475 warn.score=80; 466 warn.score=80;
476 467
477 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP; 468 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
478 pkt_interval = 80000; /* 80 msec packet interval by default */ 469 pkt_interval = 80000; /* 80 msec packet interval by default */
479 packets = 5; 470 packets = 5;
@@ -496,9 +487,6 @@ main(int argc, char **argv)
496 packets = 5; 487 packets = 5;
497 } 488 }
498 489
499 /* Parse extra opts if any */
500 argv=np_extra_opts(&argc, argv, progname);
501
502 /* support "--help" and "--version" */ 490 /* support "--help" and "--version" */
503 if(argc == 2) { 491 if(argc == 2) {
504 if(!strcmp(argv[1], "--help")) 492 if(!strcmp(argv[1], "--help"))
@@ -507,10 +495,36 @@ main(int argc, char **argv)
507 strcpy(argv[1], "-V"); 495 strcpy(argv[1], "-V");
508 } 496 }
509 497
498 /* Parse protocol arguments first */
499 for(i = 1; i < argc; i++) {
500 while((arg = getopt(argc, argv, opts_str)) != EOF) {
501 switch(arg) {
502 case '4':
503 if (address_family != -1)
504 crash("Multiple protocol versions not supported");
505 address_family = AF_INET;
506 break;
507 case '6':
508#ifdef USE_IPV6
509 if (address_family != -1)
510 crash("Multiple protocol versions not supported");
511 address_family = AF_INET6;
512#else
513 usage (_("IPv6 support not available\n"));
514#endif
515 break;
516 }
517 }
518 }
519
520 /* Reset argument scanning */
521 optind = 1;
522
523 unsigned long size;
510 /* parse the arguments */ 524 /* parse the arguments */
511 for(i = 1; i < argc; i++) { 525 for(i = 1; i < argc; i++) {
526 while((arg = getopt(argc, argv, opts_str)) != EOF) {
512 while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O")) != EOF) { 527 while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O")) != EOF) {
513 long size;
514 switch(arg) { 528 switch(arg) {
515 case 'v': 529 case 'v':
516 debug++; 530 debug++;
@@ -522,7 +536,7 @@ main(int argc, char **argv)
522 icmp_data_size = size; 536 icmp_data_size = size;
523 icmp_pkt_size = size + ICMP_MINLEN; 537 icmp_pkt_size = size + ICMP_MINLEN;
524 } else 538 } else
525 usage_va("ICMP data length must be between: %d and %d", 539 usage_va("ICMP data length must be between: %lu and %lu",
526 sizeof(struct icmp) + sizeof(struct icmp_ping_data), 540 sizeof(struct icmp) + sizeof(struct icmp_ping_data),
527 MAX_PING_DATA - 1); 541 MAX_PING_DATA - 1);
528 break; 542 break;
@@ -550,7 +564,7 @@ main(int argc, char **argv)
550 add_target(optarg); 564 add_target(optarg);
551 break; 565 break;
552 case 'l': 566 case 'l':
553 ttl = (unsigned char)strtoul(optarg, NULL, 0); 567 ttl = (int)strtoul(optarg, NULL, 0);
554 break; 568 break;
555 case 'm': 569 case 'm':
556 min_hosts_alive = (int)strtoul(optarg, NULL, 0); 570 min_hosts_alive = (int)strtoul(optarg, NULL, 0);
@@ -562,41 +576,53 @@ main(int argc, char **argv)
562 } 576 }
563 break; 577 break;
564 case 's': /* specify source IP address */ 578 case 's': /* specify source IP address */
565 set_source_ip(optarg); 579 source_ip = optarg;
566 break; 580 break;
567 case 'V': /* version */ 581 case 'V': /* version */
568 print_revision (progname, NP_VERSION); 582 print_revision (progname, NP_VERSION);
569 exit (STATE_OK); 583 exit (STATE_OK);
570 case 'h': /* help */ 584 case 'h': /* help */
571 print_help (); 585 print_help ();
572 exit (STATE_OK); 586 exit (STATE_UNKNOWN);
587 break;
573 case 'R': /* RTA mode */ 588 case 'R': /* RTA mode */
574 get_threshold2(optarg, &warn, &crit,1); 589 get_threshold2(optarg, &warn, &crit,1);
575 rta_mode=1; 590 rta_mode=1;
576 break; 591 break;
577 case 'P': /* packet loss mode */ 592 case 'P': /* packet loss mode */
578 get_threshold2(optarg, &warn, &crit,2); 593 get_threshold2(optarg, &warn, &crit,2);
579 pl_mode=1; 594 pl_mode=1;
580 break; 595 break;
581 case 'J': /* packet loss mode */ 596 case 'J': /* packet loss mode */
582 get_threshold2(optarg, &warn, &crit,3); 597 get_threshold2(optarg, &warn, &crit,3);
583 jitter_mode=1; 598 jitter_mode=1;
584 break; 599 break;
585 case 'M': /* MOS mode */ 600 case 'M': /* MOS mode */
586 get_threshold2(optarg, &warn, &crit,4); 601 get_threshold2(optarg, &warn, &crit,4);
587 mos_mode=1; 602 mos_mode=1;
588 break; 603 break;
589 case 'S': /* score mode */ 604 case 'S': /* score mode */
590 get_threshold2(optarg, &warn, &crit,5); 605 get_threshold2(optarg, &warn, &crit,5);
591 score_mode=1; 606 score_mode=1;
592 break; 607 break;
593 case 'O': /* out of order mode */ 608 case 'O': /* out of order mode */
594 order_mode=1; 609 order_mode=1;
595 break; 610 break;
596 } 611 }
597 } 612 }
598 } 613 }
599 614
615 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
616 environ = NULL;
617
618 /* use the pid to mark packets as ours */
619 /* Some systems have 32-bit pid_t so mask off only 16 bits */
620 pid = getpid() & 0xffff;
621 /* printf("pid = %u\n", pid); */
622
623 /* Parse extra opts if any */
624 argv=np_extra_opts(&argc, argv, progname);
625
600 argv = &argv[optind]; 626 argv = &argv[optind];
601 while(*argv) { 627 while(*argv) {
602 add_target(*argv); 628 add_target(*argv);
@@ -608,6 +634,32 @@ main(int argc, char **argv)
608 exit(3); 634 exit(3);
609 } 635 }
610 636
637 // add_target might change address_family
638 switch ( address_family ){
639 case AF_INET: icmp_proto = IPPROTO_ICMP;
640 break;
641 case AF_INET6: icmp_proto = IPPROTO_ICMPV6;
642 break;
643 default: crash("Address family not supported");
644 }
645 if((icmp_sock = socket(address_family, SOCK_RAW, icmp_proto)) != -1)
646 sockets |= HAVE_ICMP;
647 else icmp_sockerrno = errno;
648
649 if( source_ip )
650 set_source_ip(source_ip);
651
652#ifdef SO_TIMESTAMP
653 if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
654 if(debug) printf("Warning: no SO_TIMESTAMP support\n");
655#endif // SO_TIMESTAMP
656
657 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
658 if (setuid(getuid()) == -1) {
659 printf("ERROR: Failed to drop privileges\n");
660 return 1;
661 }
662
611 if(!sockets) { 663 if(!sockets) {
612 if(icmp_sock == -1) { 664 if(icmp_sock == -1) {
613 errno = icmp_sockerrno; 665 errno = icmp_sockerrno;
@@ -710,7 +762,11 @@ main(int argc, char **argv)
710 } 762 }
711 763
712 host = list; 764 host = list;
713 table = malloc(sizeof(struct rta_host *) * targets); 765//<<<<<<< HEAD FIXME
766 table = (struct rta_host**)malloc(sizeof(struct rta_host **) * targets);
767//=======
768// table = malloc(sizeof(struct rta_host *) * targets);
769//>>>>>>> jitter-orig
714 i = 0; 770 i = 0;
715 while(host) { 771 while(host) {
716 host->id = i*packets; 772 host->id = i*packets;
@@ -730,7 +786,7 @@ main(int argc, char **argv)
730static void 786static void
731run_checks() 787run_checks()
732{ 788{
733 u_int i, t, result; 789 u_int i, t;
734 u_int final_wait, time_passed; 790 u_int final_wait, time_passed;
735 791
736 /* this loop might actually violate the pkt_interval or target_interval 792 /* this loop might actually violate the pkt_interval or target_interval
@@ -748,9 +804,9 @@ run_checks()
748 804
749 /* we're still in the game, so send next packet */ 805 /* we're still in the game, so send next packet */
750 (void)send_icmp_ping(icmp_sock, table[t]); 806 (void)send_icmp_ping(icmp_sock, table[t]);
751 (void)wait_for_reply(icmp_sock, target_interval); 807 wait_for_reply(icmp_sock, target_interval);
752 } 808 }
753 (void)wait_for_reply(icmp_sock, pkt_interval * targets); 809 wait_for_reply(icmp_sock, pkt_interval * targets);
754 } 810 }
755 811
756 if(icmp_pkts_en_route && targets_alive) { 812 if(icmp_pkts_en_route && targets_alive) {
@@ -770,31 +826,48 @@ run_checks()
770 * haven't yet */ 826 * haven't yet */
771 if(debug) printf("Waiting for %u micro-seconds (%0.3f msecs)\n", 827 if(debug) printf("Waiting for %u micro-seconds (%0.3f msecs)\n",
772 final_wait, (float)final_wait / 1000); 828 final_wait, (float)final_wait / 1000);
773 (void)wait_for_reply(icmp_sock, final_wait); 829 wait_for_reply(icmp_sock, final_wait);
774 } 830 }
775} 831}
776 832
833
777/* response structure: 834/* response structure:
835 * IPv4:
778 * ip header : 20 bytes 836 * ip header : 20 bytes
779 * icmp header : 28 bytes 837 * icmp header : 28 bytes
838 * IPv6:
839 * ip header : 40 bytes
840 * icmp header : 28 bytes
841 * both:
780 * icmp echo reply : the rest 842 * icmp echo reply : the rest
781 */ 843 */
782static int 844static int
783wait_for_reply(int sock, u_int t) 845wait_for_reply(int sock, u_int t)
784{ 846{
785 int n, hlen; 847 int n, hlen;
786 static unsigned char buf[4096]; 848 static unsigned char buf[65536];
787 struct sockaddr_in resp_addr; 849 struct sockaddr_storage resp_addr;
788 struct ip *ip; 850 union ip_hdr *ip;
789 struct icmp icp; 851 union icmp_packet packet;
790 struct rta_host *host; 852 struct rta_host *host;
791 struct icmp_ping_data data; 853 struct icmp_ping_data data;
792 struct timeval wait_start, now; 854 struct timeval wait_start, now;
793 u_int tdiff, i, per_pkt_wait; 855 u_int tdiff, i, per_pkt_wait;
794 double jitter_tmp; 856 double jitter_tmp;
795 857
858 if (!(packet.buf = malloc(icmp_pkt_size))) {
859 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
860 icmp_pkt_size);
861 return -1; /* might be reached if we're in debug mode */
862 }
863
864 memset(packet.buf, 0, icmp_pkt_size);
865
796 /* if we can't listen or don't have anything to listen to, just return */ 866 /* if we can't listen or don't have anything to listen to, just return */
797 if(!t || !icmp_pkts_en_route) return 0; 867 if(!t || !icmp_pkts_en_route) {
868 free(packet.buf);
869 return 0;
870 }
798 871
799 gettimeofday(&wait_start, &tz); 872 gettimeofday(&wait_start, &tz);
800 873
@@ -813,7 +886,7 @@ wait_for_reply(int sock, u_int t)
813 886
814 /* reap responses until we hit a timeout */ 887 /* reap responses until we hit a timeout */
815 n = recvfrom_wto(sock, buf, sizeof(buf), 888 n = recvfrom_wto(sock, buf, sizeof(buf),
816 (struct sockaddr *)&resp_addr, &t, &now); 889 (struct sockaddr *)&resp_addr, &t, &now);
817 if(!n) { 890 if(!n) {
818 if(debug > 1) { 891 if(debug > 1) {
819 printf("recvfrom_wto() timed out during a %u usecs wait\n", 892 printf("recvfrom_wto() timed out during a %u usecs wait\n",
@@ -823,12 +896,23 @@ wait_for_reply(int sock, u_int t)
823 } 896 }
824 if(n < 0) { 897 if(n < 0) {
825 if(debug) printf("recvfrom_wto() returned errors\n"); 898 if(debug) printf("recvfrom_wto() returned errors\n");
899 free(packet.buf);
826 return n; 900 return n;
827 } 901 }
828 902
829 ip = (struct ip *)buf; 903 // FIXME: with ipv6 we don't have an ip header here
830 if(debug > 1) printf("received %u bytes from %s\n", 904 if (address_family != AF_INET6) {
831 ntohs(ip->ip_len), inet_ntoa(resp_addr.sin_addr)); 905 ip = (union ip_hdr *)buf;
906
907 if(debug > 1) {
908 char address[INET6_ADDRSTRLEN];
909 parse_address(&resp_addr, address, sizeof(address));
910 printf("received %u bytes from %s\n",
911 address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen)
912 : ntohs(ip->ip.ip_len),
913 address);
914 }
915 }
832 916
833/* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ 917/* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */
834/* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ 918/* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */
@@ -837,12 +921,14 @@ wait_for_reply(int sock, u_int t)
837 * off the bottom 4 bits */ 921 * off the bottom 4 bits */
838/* hlen = (ip->ip_vhl & 0x0f) << 2; */ 922/* hlen = (ip->ip_vhl & 0x0f) << 2; */
839/* #else */ 923/* #else */
840 hlen = ip->ip_hl << 2; 924 hlen = (address_family == AF_INET6) ? 0 : ip->ip.ip_hl << 2;
841/* #endif */ 925/* #endif */
842 926
843 if(n < (hlen + ICMP_MINLEN)) { 927 if(n < (hlen + ICMP_MINLEN)) {
928 char address[INET6_ADDRSTRLEN];
929 parse_address(&resp_addr, address, sizeof(address));
844 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", 930 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n",
845 n, hlen + icmp_pkt_size, inet_ntoa(resp_addr.sin_addr)); 931 n, hlen + icmp_pkt_size, address);
846 } 932 }
847 /* else if(debug) { */ 933 /* else if(debug) { */
848 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ 934 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */
@@ -851,23 +937,39 @@ wait_for_reply(int sock, u_int t)
851 /* } */ 937 /* } */
852 938
853 /* check the response */ 939 /* check the response */
854 memcpy(&icp, buf + hlen, sizeof(icp));
855 940
856 if(ntohs(icp.icmp_id) != pid || icp.icmp_type != ICMP_ECHOREPLY || 941 memcpy(packet.buf, buf + hlen, icmp_pkt_size);
857 ntohs(icp.icmp_seq) >= targets*packets) { 942/* address_family == AF_INET6 ? sizeof(struct icmp6_hdr)
943 : sizeof(struct icmp));*/
944
945 if( (address_family == PF_INET &&
946 (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY
947 || ntohs(packet.icp->icmp_seq) >= targets * packets))
948 || (address_family == PF_INET6 &&
949 (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY
950 || ntohs(packet.icp6->icmp6_seq) >= targets * packets))) {
858 if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); 951 if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n");
859 handle_random_icmp(buf + hlen, &resp_addr); 952 handle_random_icmp(buf + hlen, &resp_addr);
860 continue; 953 continue;
861 } 954 }
862 955
863 /* this is indeed a valid response */ 956 /* this is indeed a valid response */
864 memcpy(&data, icp.icmp_data, sizeof(data)); 957 if (address_family == PF_INET) {
865 if (debug > 2) 958 memcpy(&data, packet.icp->icmp_data, sizeof(data));
866 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", 959 if (debug > 2)
867 (unsigned long)sizeof(data), ntohs(icp.icmp_id), 960 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n",
868 ntohs(icp.icmp_seq), icp.icmp_cksum); 961 (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id),
962 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum);
963 host = table[ntohs(packet.icp->icmp_seq)/packets];
964 } else {
965 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data));
966 if (debug > 2)
967 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n",
968 (unsigned long)sizeof(data), ntohs(packet.icp6->icmp6_id),
969 ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum);
970 host = table[ntohs(packet.icp6->icmp6_seq)/packets];
971 }
869 972
870 host = table[ntohs(icp.icmp_seq)/packets];
871 tdiff = get_timevaldiff(&data.stime, &now); 973 tdiff = get_timevaldiff(&data.stime, &now);
872 974
873 if (host->last_tdiff>0) { 975 if (host->last_tdiff>0) {
@@ -910,22 +1012,43 @@ wait_for_reply(int sock, u_int t)
910 host->rtmin = tdiff; 1012 host->rtmin = tdiff;
911 1013
912 if(debug) { 1014 if(debug) {
913 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", 1015 char address[INET6_ADDRSTRLEN];
914 (float)tdiff / 1000, inet_ntoa(resp_addr.sin_addr), 1016 parse_address(&resp_addr, address, sizeof(address));
915 ttl, ip->ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); 1017
1018 switch(address_family) {
1019 case AF_INET: {
1020 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n",
1021 (float)tdiff / 1000,
1022 address,
1023 ttl,
1024 ip->ip.ip_ttl,
1025 (float)host->rtmax / 1000,
1026 (float)host->rtmin / 1000);
1027 break;
1028 };
1029 case AF_INET6: {
1030 printf("%0.3f ms rtt from %s, outgoing ttl: %u, max: %0.3f, min: %0.3f\n",
1031 (float)tdiff / 1000,
1032 address,
1033 ttl,
1034 (float)host->rtmax / 1000,
1035 (float)host->rtmin / 1000);
1036 };
1037 }
916 } 1038 }
917 1039
918 /* if we're in hostcheck mode, exit with limited printouts */ 1040 /* if we're in hostcheck mode, exit with limited printouts */
919 if(mode == MODE_HOSTCHECK) { 1041 if(mode == MODE_HOSTCHECK) {
920 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" 1042 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|"
921 "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", 1043 "pkt=%u;;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n",
922 host->name, icmp_recv, (float)tdiff / 1000, 1044 host->name, icmp_recv, (float)tdiff / 1000,
923 icmp_recv, packets, (float)tdiff / 1000, 1045 icmp_recv, packets, (float)tdiff / 1000,
924 (float)warn.rta / 1000, (float)crit.rta / 1000); 1046 (float)warn.rta / 1000, (float)crit.rta / 1000);
925 exit(STATE_OK); 1047 exit(STATE_OK);
926 } 1048 }
927 } 1049 }
928 1050
1051 free(packet.buf);
929 return 0; 1052 return 0;
930} 1053}
931 1054
@@ -933,62 +1056,86 @@ wait_for_reply(int sock, u_int t)
933static int 1056static int
934send_icmp_ping(int sock, struct rta_host *host) 1057send_icmp_ping(int sock, struct rta_host *host)
935{ 1058{
936 static union {
937 void *buf; /* re-use so we prevent leaks */
938 struct icmp *icp;
939 u_short *cksum_in;
940 } packet = { NULL };
941 long int len; 1059 long int len;
1060 size_t addrlen;
942 struct icmp_ping_data data; 1061 struct icmp_ping_data data;
943 struct msghdr hdr; 1062 struct msghdr hdr;
944 struct iovec iov; 1063 struct iovec iov;
945 struct timeval tv; 1064 struct timeval tv;
946 struct sockaddr *addr; 1065 void *buf = NULL;
947 1066
948 if(sock == -1) { 1067 if(sock == -1) {
949 errno = 0; 1068 errno = 0;
950 crash("Attempt to send on bogus socket"); 1069 crash("Attempt to send on bogus socket");
951 return -1; 1070 return -1;
952 } 1071 }
953 addr = (struct sockaddr *)&host->saddr_in;
954 1072
955 if(!packet.buf) { 1073 if(!buf) {
956 if (!(packet.buf = malloc(icmp_pkt_size))) { 1074 if (!(buf = malloc(icmp_pkt_size))) {
957 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", 1075 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
958 icmp_pkt_size); 1076 icmp_pkt_size);
959 return -1; /* might be reached if we're in debug mode */ 1077 return -1; /* might be reached if we're in debug mode */
960 } 1078 }
961 } 1079 }
962 memset(packet.buf, 0, icmp_pkt_size); 1080 memset(buf, 0, icmp_pkt_size);
963 1081
964 if((gettimeofday(&tv, &tz)) == -1) return -1; 1082 if((gettimeofday(&tv, &tz)) == -1) {
1083 free(buf);
1084 return -1;
1085 }
965 1086
966 data.ping_id = 10; /* host->icmp.icmp_sent; */ 1087 data.ping_id = 10; /* host->icmp.icmp_sent; */
967 memcpy(&data.stime, &tv, sizeof(tv)); 1088 memcpy(&data.stime, &tv, sizeof(tv));
968 memcpy(&packet.icp->icmp_data, &data, sizeof(data)); 1089
969 packet.icp->icmp_type = ICMP_ECHO; 1090 if (address_family == AF_INET) {
970 packet.icp->icmp_code = 0; 1091 struct icmp *icp = (struct icmp*)buf;
971 packet.icp->icmp_cksum = 0; 1092 addrlen = sizeof(struct sockaddr_in);
972 packet.icp->icmp_id = htons(pid); 1093
973 packet.icp->icmp_seq = htons(host->id++); 1094 memcpy(&icp->icmp_data, &data, sizeof(data));
974 packet.icp->icmp_cksum = icmp_checksum(packet.cksum_in, icmp_pkt_size); 1095
975 1096 icp->icmp_type = ICMP_ECHO;
976 if (debug > 2) 1097 icp->icmp_code = 0;
977 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", 1098 icp->icmp_cksum = 0;
978 (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), 1099 icp->icmp_id = htons(pid);
979 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, 1100 icp->icmp_seq = htons(host->id++);
980 host->name); 1101 icp->icmp_cksum = icmp_checksum((uint16_t*)buf, (size_t)icmp_pkt_size);
1102
1103 if (debug > 2)
1104 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
1105 (unsigned long)sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum, host->name);
1106 }
1107 else {
1108 struct icmp6_hdr *icp6 = (struct icmp6_hdr*)buf;
1109 addrlen = sizeof(struct sockaddr_in6);
1110
1111 memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data));
1112
1113 icp6->icmp6_type = ICMP6_ECHO_REQUEST;
1114 icp6->icmp6_code = 0;
1115 icp6->icmp6_cksum = 0;
1116 icp6->icmp6_id = htons(pid);
1117 icp6->icmp6_seq = htons(host->id++);
1118 // let checksum be calculated automatically
1119
1120 if (debug > 2) {
1121 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
1122 (unsigned long)sizeof(data), ntohs(icp6->icmp6_id),
1123 ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name);
1124 }
1125 }
981 1126
982 memset(&iov, 0, sizeof(iov)); 1127 memset(&iov, 0, sizeof(iov));
983 iov.iov_base = packet.buf; 1128 iov.iov_base = buf;
984 iov.iov_len = icmp_pkt_size; 1129 iov.iov_len = icmp_pkt_size;
985 1130
986 memset(&hdr, 0, sizeof(hdr)); 1131 memset(&hdr, 0, sizeof(hdr));
987 hdr.msg_name = addr; 1132 hdr.msg_name = (struct sockaddr *)&host->saddr_in;
988 hdr.msg_namelen = sizeof(struct sockaddr); 1133 hdr.msg_namelen = addrlen;
989 hdr.msg_iov = &iov; 1134 hdr.msg_iov = &iov;
990 hdr.msg_iovlen = 1; 1135 hdr.msg_iovlen = 1;
991 1136
1137 errno = 0;
1138
992/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ 1139/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */
993#ifdef MSG_CONFIRM 1140#ifdef MSG_CONFIRM
994 len = sendmsg(sock, &hdr, MSG_CONFIRM); 1141 len = sendmsg(sock, &hdr, MSG_CONFIRM);
@@ -996,9 +1143,15 @@ send_icmp_ping(int sock, struct rta_host *host)
996 len = sendmsg(sock, &hdr, 0); 1143 len = sendmsg(sock, &hdr, 0);
997#endif 1144#endif
998 1145
1146 free(buf);
1147
999 if(len < 0 || (unsigned int)len != icmp_pkt_size) { 1148 if(len < 0 || (unsigned int)len != icmp_pkt_size) {
1000 if(debug) printf("Failed to send ping to %s\n", 1149 if(debug) {
1001 inet_ntoa(host->saddr_in.sin_addr)); 1150 char address[INET6_ADDRSTRLEN];
1151 parse_address((struct sockaddr_storage *)&host->saddr_in, address, sizeof(address));
1152 printf("Failed to send ping to %s: %s\n", address, strerror(errno));
1153 }
1154 errno = 0;
1002 return -1; 1155 return -1;
1003 } 1156 }
1004 1157
@@ -1043,7 +1196,7 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
1043 1196
1044 if(!n) return 0; /* timeout */ 1197 if(!n) return 0; /* timeout */
1045 1198
1046 slen = sizeof(struct sockaddr); 1199 slen = sizeof(struct sockaddr_storage);
1047 1200
1048 memset(&iov, 0, sizeof(iov)); 1201 memset(&iov, 0, sizeof(iov));
1049 iov.iov_base = buf; 1202 iov.iov_base = buf;
@@ -1069,6 +1222,7 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
1069 break ; 1222 break ;
1070 } 1223 }
1071 } 1224 }
1225
1072 if (!chdr) 1226 if (!chdr)
1073#endif // SO_TIMESTAMP 1227#endif // SO_TIMESTAMP
1074 gettimeofday(tv, &tz); 1228 gettimeofday(tv, &tz);
@@ -1104,10 +1258,11 @@ finish(int sig)
1104 /* iterate thrice to calculate values, give output, and print perfparse */ 1258 /* iterate thrice to calculate values, give output, and print perfparse */
1105 status=STATE_OK; 1259 status=STATE_OK;
1106 host = list; 1260 host = list;
1261
1107 while(host) { 1262 while(host) {
1108 if(!host->icmp_recv) { 1263 if(!host->icmp_recv) {
1109 /* rta 0 is ofcourse not entirely correct, but will still show up 1264 /* rta 0 is ofcourse not entirely correct, but will still show up
1110 * conspicuosly as missing entries in perfparse and cacti */ 1265 * conspicuously as missing entries in perfparse and cacti */
1111 pl = 100; 1266 pl = 100;
1112 rta = 0; 1267 rta = 0;
1113 status = STATE_CRITICAL; 1268 status = STATE_CRITICAL;
@@ -1240,10 +1395,12 @@ finish(int sig)
1240 host->rtmin=0; 1395 host->rtmin=0;
1241 host->jitter_min=0; 1396 host->jitter_min=0;
1242 if(host->flags & FLAG_LOST_CAUSE) { 1397 if(host->flags & FLAG_LOST_CAUSE) {
1398 char address[INET6_ADDRSTRLEN];
1399 parse_address(&host->error_addr, address, sizeof(address));
1243 printf("%s: %s @ %s. rta nan, lost %d%%", 1400 printf("%s: %s @ %s. rta nan, lost %d%%",
1244 host->name, 1401 host->name,
1245 get_icmp_error_msg(host->icmp_type, host->icmp_code), 1402 get_icmp_error_msg(host->icmp_type, host->icmp_code),
1246 inet_ntoa(host->error_addr), 1403 address,
1247 100); 1404 100);
1248 } 1405 }
1249 else { /* not marked as lost cause, so we have no flags for it */ 1406 else { /* not marked as lost cause, so we have no flags for it */
@@ -1317,7 +1474,13 @@ finish(int sig)
1317 while(host) { 1474 while(host) {
1318 if(debug) puts(""); 1475 if(debug) puts("");
1319 if (rta_mode && host->pl<100) { 1476 if (rta_mode && host->pl<100) {
1320 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",(targets > 1) ? host->name : "", (float)host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, (targets > 1) ? host->name : "", (float)host->rtmax / 1000, (targets > 1) ? host->name : "", (float)host->rtmin / 1000); 1477 // FIXME printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",(targets > 1) ? host->name : "", (float)host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, (targets > 1) ? host->name : "", (float)host->rtmax / 1000, (targets > 1) ? host->name : "", (float)host->rtmin / 1000);
1478 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %spl=%u%%;%u;%u;; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",
1479 (targets > 1) ? host->name : "",
1480 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000,
1481 (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl,
1482 (targets > 1) ? host->name : "", (float)host->rtmax / 1000,
1483 (targets > 1) ? host->name : "", (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0);
1321 } 1484 }
1322 if (pl_mode) { 1485 if (pl_mode) {
1323 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl); 1486 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl);
@@ -1365,7 +1528,6 @@ get_timevaldiff(struct timeval *early, struct timeval *later)
1365 { 1528 {
1366 return 0; 1529 return 0;
1367 } 1530 }
1368
1369 ret = (later->tv_sec - early->tv_sec) * 1000000; 1531 ret = (later->tv_sec - early->tv_sec) * 1000000;
1370 ret += later->tv_usec - early->tv_usec; 1532 ret += later->tv_usec - early->tv_usec;
1371 1533
@@ -1373,18 +1535,35 @@ get_timevaldiff(struct timeval *early, struct timeval *later)
1373} 1535}
1374 1536
1375static int 1537static int
1376add_target_ip(char *arg, struct in_addr *in) 1538add_target_ip(char *arg, struct sockaddr_storage *in)
1377{ 1539{
1378 struct rta_host *host; 1540 struct rta_host *host;
1541 struct sockaddr_in *sin, *host_sin;
1542 struct sockaddr_in6 *sin6, *host_sin6;
1543
1544 if (address_family == AF_INET)
1545 sin = (struct sockaddr_in *)in;
1546 else
1547 sin6 = (struct sockaddr_in6 *)in;
1548
1549
1379 1550
1380 /* disregard obviously stupid addresses */ 1551 /* disregard obviously stupid addresses
1381 if(in->s_addr == INADDR_NONE || in->s_addr == INADDR_ANY) 1552 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
1553 if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE
1554 || sin->sin_addr.s_addr == INADDR_ANY)))
1555 || (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
1382 return -1; 1556 return -1;
1557 }
1383 1558
1384 /* no point in adding two identical IP's, so don't. ;) */ 1559 /* no point in adding two identical IP's, so don't. ;) */
1385 host = list; 1560 host = list;
1386 while(host) { 1561 while(host) {
1387 if(host->saddr_in.sin_addr.s_addr == in->s_addr) { 1562 host_sin = (struct sockaddr_in *)&host->saddr_in;
1563 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1564
1565 if( (address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr)
1566 || (address_family == AF_INET6 && host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) {
1388 if(debug) printf("Identical IP already exists. Not adding %s\n", arg); 1567 if(debug) printf("Identical IP already exists. Not adding %s\n", arg);
1389 return -1; 1568 return -1;
1390 } 1569 }
@@ -1392,24 +1571,39 @@ add_target_ip(char *arg, struct in_addr *in)
1392 } 1571 }
1393 1572
1394 /* add the fresh ip */ 1573 /* add the fresh ip */
1395 host = malloc(sizeof(struct rta_host)); 1574 host = (struct rta_host*)malloc(sizeof(struct rta_host));
1396 if(!host) { 1575 if(!host) {
1397 crash("add_target_ip(%s, %s): malloc(%d) failed", 1576 char straddr[INET6_ADDRSTRLEN];
1398 arg, inet_ntoa(*in), sizeof(struct rta_host)); 1577 parse_address((struct sockaddr_storage*)&in, straddr, sizeof(straddr));
1578 crash("add_target_ip(%s, %s): malloc(%lu) failed",
1579 arg, straddr, sizeof(struct rta_host));
1399 } 1580 }
1400 memset(host, 0, sizeof(struct rta_host)); 1581 memset(host, 0, sizeof(struct rta_host));
1401 1582
1402 /* set the values. use calling name for output */ 1583 /* set the values. use calling name for output */
1403 host->name = strdup(arg); 1584 host->name = strdup(arg);
1404 1585
1586
1587 /* fill out the sockaddr_storage struct */
1588 if(address_family == AF_INET) {
1589 host_sin = (struct sockaddr_in *)&host->saddr_in;
1590 host_sin->sin_family = AF_INET;
1591 host_sin->sin_addr.s_addr = sin->sin_addr.s_addr;
1592 }
1593 else {
1594 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1595 host_sin6->sin6_family = AF_INET6;
1596 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr);
1597 }
1598
1405 /* fill out the sockaddr_in struct */ 1599 /* fill out the sockaddr_in struct */
1406 host->saddr_in.sin_family = AF_INET; 1600 host->saddr_in.sin_family = AF_INET;
1407 host->saddr_in.sin_addr.s_addr = in->s_addr; 1601 host->saddr_in.sin_addr.s_addr = in->s_addr;
1408 host->rtmin = DBL_MAX; 1602 host->rtmin = INFINITY;
1409 host->rtmax = 0; 1603 host->rtmax = 0;
1410 host->jitter=0; 1604 host->jitter=0;
1411 host->jitter_max=0; 1605 host->jitter_max=0;
1412 host->jitter_min=DBL_MAX; 1606 host->jitter_min=INFINITY;
1413 host->last_tdiff=0; 1607 host->last_tdiff=0;
1414 host->order_status=STATE_OK; 1608 host->order_status=STATE_OK;
1415 host->last_icmp_seq=0; 1609 host->last_icmp_seq=0;
@@ -1420,6 +1614,7 @@ add_target_ip(char *arg, struct in_addr *in)
1420 host->score_status=0; 1614 host->score_status=0;
1421 host->pl_status=0; 1615 host->pl_status=0;
1422 1616
1617
1423 if(!list) list = cursor = host; 1618 if(!list) list = cursor = host;
1424 else cursor->next = host; 1619 else cursor->next = host;
1425 1620
@@ -1433,31 +1628,67 @@ add_target_ip(char *arg, struct in_addr *in)
1433static int 1628static int
1434add_target(char *arg) 1629add_target(char *arg)
1435{ 1630{
1436 int i; 1631 int error, result = -1;
1437 struct hostent *he; 1632 struct sockaddr_storage ip;
1438 struct in_addr *in, ip; 1633 struct addrinfo hints, *res, *p;
1634 struct sockaddr_in *sin;
1635 struct sockaddr_in6 *sin6;
1636
1637 switch (address_family) {
1638 case -1:
1639 /* -4 and -6 are not specified on cmdline */
1640 address_family = AF_INET;
1641 sin = (struct sockaddr_in *)&ip;
1642 result = inet_pton(address_family, arg, &sin->sin_addr);
1643#ifdef USE_IPV6
1644 if( result != 1 ){
1645 address_family = AF_INET6;
1646 sin6 = (struct sockaddr_in6 *)&ip;
1647 result = inet_pton(address_family, arg, &sin6->sin6_addr);
1648 }
1649#endif
1650 /* If we don't find any valid addresses, we still don't know the address_family */
1651 if ( result != 1) {
1652 address_family = -1;
1653 }
1654 break;
1655 case AF_INET:
1656 sin = (struct sockaddr_in *)&ip;
1657 result = inet_pton(address_family, arg, &sin->sin_addr);
1658 break;
1659 case AF_INET6:
1660 sin6 = (struct sockaddr_in6 *)&ip;
1661 result = inet_pton(address_family, arg, &sin6->sin6_addr);
1662 break;
1663 default: crash("Address family not supported");
1664 }
1439 1665
1440 /* don't resolve if we don't have to */ 1666 /* don't resolve if we don't have to */
1441 if((ip.s_addr = inet_addr(arg)) != INADDR_NONE) { 1667 if(result == 1) {
1442 /* don't add all ip's if we were given a specific one */ 1668 /* don't add all ip's if we were given a specific one */
1443 return add_target_ip(arg, &ip); 1669 return add_target_ip(arg, &ip);
1444 /* he = gethostbyaddr((char *)in, sizeof(struct in_addr), AF_INET); */
1445 /* if(!he) return add_target_ip(arg, in); */
1446 } 1670 }
1447 else { 1671 else {
1448 errno = 0; 1672 errno = 0;
1449 he = gethostbyname(arg); 1673 memset(&hints, 0, sizeof(hints));
1450 if(!he) { 1674 if (address_family == -1) {
1675 hints.ai_family = AF_UNSPEC;
1676 } else {
1677 hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6;
1678 }
1679 hints.ai_socktype = SOCK_RAW;
1680 if((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) {
1451 errno = 0; 1681 errno = 0;
1452 crash("Failed to resolve %s", arg); 1682 crash("Failed to resolve %s: %s", arg, gai_strerror(error));
1453 return -1; 1683 return -1;
1454 } 1684 }
1685 address_family = res->ai_family;
1455 } 1686 }
1456 1687
1457 /* possibly add all the IP's as targets */ 1688 /* possibly add all the IP's as targets */
1458 for(i = 0; he->h_addr_list[i]; i++) { 1689 for(p = res; p != NULL; p = p->ai_next) {
1459 in = (struct in_addr *)he->h_addr_list[i]; 1690 memcpy(&ip, p->ai_addr, p->ai_addrlen);
1460 add_target_ip(arg, in); 1691 add_target_ip(arg, &ip);
1461 1692
1462 /* this is silly, but it works */ 1693 /* this is silly, but it works */
1463 if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { 1694 if(mode == MODE_HOSTCHECK || mode == MODE_ALL) {
@@ -1466,6 +1697,7 @@ add_target(char *arg)
1466 } 1697 }
1467 break; 1698 break;
1468 } 1699 }
1700 freeaddrinfo(res);
1469 1701
1470 return 0; 1702 return 0;
1471} 1703}
@@ -1476,7 +1708,7 @@ set_source_ip(char *arg)
1476 struct sockaddr_in src; 1708 struct sockaddr_in src;
1477 1709
1478 memset(&src, 0, sizeof(src)); 1710 memset(&src, 0, sizeof(src));
1479 src.sin_family = AF_INET; 1711 src.sin_family = address_family;
1480 if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) 1712 if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE)
1481 src.sin_addr.s_addr = get_ip_address(arg); 1713 src.sin_addr.s_addr = get_ip_address(arg);
1482 if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) 1714 if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1)
@@ -1487,20 +1719,26 @@ set_source_ip(char *arg)
1487static in_addr_t 1719static in_addr_t
1488get_ip_address(const char *ifname) 1720get_ip_address(const char *ifname)
1489{ 1721{
1722 // TODO: Rewrite this so the function return an error and we exit somewhere else
1723 struct sockaddr_in ip;
1724 ip.sin_addr.s_addr = 0; // Fake initialization to make compiler happy
1490#if defined(SIOCGIFADDR) 1725#if defined(SIOCGIFADDR)
1491 struct ifreq ifr; 1726 struct ifreq ifr;
1492 struct sockaddr_in ip;
1493 1727
1494 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); 1728 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
1729
1495 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; 1730 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
1731
1496 if(ioctl(icmp_sock, SIOCGIFADDR, &ifr) == -1) 1732 if(ioctl(icmp_sock, SIOCGIFADDR, &ifr) == -1)
1497 crash("Cannot determine IP address of interface %s", ifname); 1733 crash("Cannot determine IP address of interface %s", ifname);
1734
1498 memcpy(&ip, &ifr.ifr_addr, sizeof(ip)); 1735 memcpy(&ip, &ifr.ifr_addr, sizeof(ip));
1499 return ip.sin_addr.s_addr;
1500#else 1736#else
1737 (void) ifname;
1501 errno = 0; 1738 errno = 0;
1502 crash("Cannot get interface IP address on this platform."); 1739 crash("Cannot get interface IP address on this platform.");
1503#endif 1740#endif
1741 return ip.sin_addr.s_addr;
1504} 1742}
1505 1743
1506/* 1744/*
@@ -1622,18 +1860,19 @@ get_threshold2(char *str, threshold *warn, threshold *crit, int type)
1622} 1860}
1623 1861
1624unsigned short 1862unsigned short
1625icmp_checksum(unsigned short *p, int n) 1863icmp_checksum(uint16_t *p, size_t n)
1626{ 1864{
1627 register unsigned short cksum; 1865 unsigned short cksum;
1628 register long sum = 0; 1866 long sum = 0;
1629 1867
1630 while(n > 1) { 1868 /* sizeof(uint16_t) == 2 */
1631 sum += *p++; 1869 while(n >= 2) {
1870 sum += *(p++);
1632 n -= 2; 1871 n -= 2;
1633 } 1872 }
1634 1873
1635 /* mop up the occasional odd byte */ 1874 /* mop up the occasional odd byte */
1636 if(n == 1) sum += (unsigned char)*p; 1875 if(n == 1) sum += *((uint8_t *)p -1);
1637 1876
1638 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 1877 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1639 sum += (sum >> 16); /* add carry */ 1878 sum += (sum >> 16); /* add carry */
@@ -1647,7 +1886,7 @@ print_help(void)
1647{ 1886{
1648 /*print_revision (progname);*/ /* FIXME: Why? */ 1887 /*print_revision (progname);*/ /* FIXME: Why? */
1649 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n"); 1888 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n");
1650 1889
1651 printf (COPYRIGHT, copyright, email); 1890 printf (COPYRIGHT, copyright, email);
1652 1891
1653 printf ("\n\n"); 1892 printf ("\n\n");
@@ -1656,7 +1895,12 @@ print_help(void)
1656 1895
1657 printf (UT_HELP_VRSN); 1896 printf (UT_HELP_VRSN);
1658 printf (UT_EXTRA_OPTS); 1897 printf (UT_EXTRA_OPTS);
1659 printf (" %s\n", "-w"); 1898
1899 printf (" %s\n", "-H");
1900 printf (" %s\n", _("specify a target"));
1901 printf (" %s\n", "[-4|-6]");
1902 printf (" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets"));
1903 printf (" %s\n", "-w");
1660 printf (" %s", _("warning threshold (currently ")); 1904 printf (" %s", _("warning threshold (currently "));
1661 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); 1905 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl);
1662 printf (" %s\n", "-c"); 1906 printf (" %s\n", "-c");
diff --git a/plugins-root/pst3.c b/plugins-root/pst3.c
index c3589f0..1f69f3a 100644
--- a/plugins-root/pst3.c
+++ b/plugins-root/pst3.c
@@ -257,6 +257,6 @@ void usage() {
257 printf("\tRSS - Real memory usage (kilobytes)\n"); 257 printf("\tRSS - Real memory usage (kilobytes)\n");
258 printf("\t%%CPU - CPU usage\n"); 258 printf("\t%%CPU - CPU usage\n");
259 printf("\tCOMMAND - Command being run\n"); 259 printf("\tCOMMAND - Command being run\n");
260 printf("\tARGS - Full command line with arguements\n"); 260 printf("\tARGS - Full command line with arguments\n");
261 return; 261 return;
262} 262}
diff --git a/plugins-root/t/check_dhcp.t b/plugins-root/t/check_dhcp.t
index 222f454..ce62773 100644
--- a/plugins-root/t/check_dhcp.t
+++ b/plugins-root/t/check_dhcp.t
@@ -19,7 +19,7 @@ if ($allow_sudo eq "yes" or $> == 0) {
19my $sudo = $> == 0 ? '' : 'sudo'; 19my $sudo = $> == 0 ? '' : 'sudo';
20 20
21my $successOutput = '/OK: Received \d+ DHCPOFFER\(s\), \d+ of 1 requested servers responded, max lease time = \d+ sec\./'; 21my $successOutput = '/OK: Received \d+ DHCPOFFER\(s\), \d+ of 1 requested servers responded, max lease time = \d+ sec\./';
22my $failureOutput = '/CRITICAL: No DHCPOFFERs were received/'; 22my $failureOutput = '/CRITICAL: (No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/';
23my $invalidOutput = '/Invalid hostname/'; 23my $invalidOutput = '/Invalid hostname/';
24 24
25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE", 25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE",
@@ -36,7 +36,12 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
36 36
37# try to determince interface 37# try to determince interface
38my $interface = ''; 38my $interface = '';
39if(`ifconfig -a 2>/dev/null` =~ m/^(e\w*\d+)/mx and $1 ne 'eth0') { 39
40# find interface used for default route
41if (-x '/usr/sbin/ip' and `/usr/sbin/ip route get 1.1.1.1 2>/dev/null` =~ m/\sdev\s(\S+)/) {
42 $interface = "-i $1";
43}
44elsif (`ifconfig -a 2>/dev/null` =~ m/^(e\w*\d+)/mx and $1 ne 'eth0') {
40 $interface = ' -i '.$1; 45 $interface = ' -i '.$1;
41} 46}
42 47
diff --git a/plugins-root/t/check_icmp.t b/plugins-root/t/check_icmp.t
index e043d4e..96addd3 100644
--- a/plugins-root/t/check_icmp.t
+++ b/plugins-root/t/check_icmp.t
@@ -12,7 +12,7 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
12 "no" ); 12 "no" );
13 13
14if ($allow_sudo eq "yes" or $> == 0) { 14if ($allow_sudo eq "yes" or $> == 0) {
15 plan tests => 16; 15 plan tests => 20;
16} else { 16} else {
17 plan skip_all => "Need sudo to test check_icmp"; 17 plan skip_all => "Need sudo to test check_icmp";
18} 18}
@@ -83,3 +83,14 @@ $res = NPTest->testCmd(
83is( $res->return_code, 2, "One of two host nonresponsive - two required" ); 83is( $res->return_code, 2, "One of two host nonresponsive - two required" );
84like( $res->output, $failureOutput, "Output OK" ); 84like( $res->output, $failureOutput, "Output OK" );
85 85
86$res = NPTest->testCmd(
87 "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 10000ms,100% -c 10000ms,100% -n 1 -m 2"
88 );
89is( $res->return_code, 0, "IPv4 source_ip accepted" );
90like( $res->output, $successOutput, "Output OK" );
91
92$res = NPTest->testCmd(
93 "$sudo ./check_icmp -H $host_responsive -b 65507"
94 );
95is( $res->return_code, 0, "Try max packet size" );
96like( $res->output, $successOutput, "Output OK - Didn't overflow" );