diff options
author | Lars Michelsen <lm@mathias-kettner.de> | 2015-10-13 10:26:01 +0200 |
---|---|---|
committer | Jacob Hansen <jhansen@op5.com> | 2018-12-07 09:51:21 +0000 |
commit | fd6dc666538dd95f11811817ceb21604676e142c (patch) | |
tree | c113cedbe5ee016650cb321e33d39b9c3cea65b9 /plugins-root | |
parent | c7c4be2ad1fa97d5b8db0cff5f7204c605992047 (diff) | |
download | monitoring-plugins-fd6dc666538dd95f11811817ceb21604676e142c.tar.gz |
check_icmp: Add IPv6 support
This commit adds IPv6 capabilities to check_icmp. It is now possible to
specify the address family using the arguments -4 (default) or -6.
To make the change possible we had to move the argument parsing previous
to creating the socket to be able to create it with the correct address
family.
This commit also fixes some gcc 4.9.2 compiler warnings. It has been
tested with several current linux distributions (debian, ubuntu, rh,
sles).
This commit fixes monitoring-plugins/monitoring-plugins#1291
Diffstat (limited to 'plugins-root')
-rw-r--r-- | plugins-root/check_icmp.c | 491 |
1 files changed, 330 insertions, 161 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 4098874c..6aeedf45 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 | ||
145 | typedef union ip_hdr { | ||
146 | struct ip ip; | ||
147 | struct ip6_hdr ip6; | ||
148 | } ip_hdr; | ||
149 | |||
150 | typedef 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); | |||
190 | static void run_checks(void); | 204 | static void run_checks(void); |
191 | static void set_source_ip(char *); | 205 | static void set_source_ip(char *); |
192 | static int add_target(char *); | 206 | static int add_target(char *); |
193 | static int add_target_ip(char *, struct in_addr *); | 207 | static int add_target_ip(char *, struct sockaddr_storage *); |
194 | static int handle_random_icmp(unsigned char *, struct sockaddr_in *); | 208 | static int handle_random_icmp(unsigned char *, struct sockaddr_storage *); |
209 | static void parse_address(struct sockaddr_storage *, char *, int); | ||
195 | static unsigned short icmp_checksum(unsigned short *, int); | 210 | static unsigned short icmp_checksum(unsigned short *, int); |
196 | static void finish(int); | 211 | static void finish(int); |
197 | static void crash(const char *, ...); | 212 | static void crash(const char *, ...); |
@@ -300,7 +315,7 @@ get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code) | |||
300 | } | 315 | } |
301 | 316 | ||
302 | static int | 317 | static int |
303 | handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr) | 318 | handle_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 | ||
389 | void 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 | |||
372 | int | 401 | int |
373 | main(int argc, char **argv) | 402 | main(int argc, char **argv) |
374 | { | 403 | { |
@@ -390,7 +419,90 @@ main(int argc, char **argv) | |||
390 | * that before pointer magic (esp. on network data) */ | 419 | * that before pointer magic (esp. on network data) */ |
391 | icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0; | 420 | icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0; |
392 | 421 | ||
393 | if((icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1) | 422 | address_family = AF_INET; |
423 | int icmp_proto = IPPROTO_ICMP; | ||
424 | |||
425 | /* parse the arguments */ | ||
426 | for(i = 1; i < argc; i++) { | ||
427 | while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:s:i:b:I:l:m:64")) != EOF) { | ||
428 | unsigned short size; | ||
429 | switch(arg) { | ||
430 | case 'v': | ||
431 | debug++; | ||
432 | break; | ||
433 | case 'b': | ||
434 | size = (unsigned short)strtol(optarg,NULL,0); | ||
435 | if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && | ||
436 | size < MAX_PING_DATA) { | ||
437 | icmp_data_size = size; | ||
438 | icmp_pkt_size = size + ICMP_MINLEN; | ||
439 | } else | ||
440 | usage_va("ICMP data length must be between: %d and %d", | ||
441 | sizeof(struct icmp) + sizeof(struct icmp_ping_data), | ||
442 | MAX_PING_DATA - 1); | ||
443 | break; | ||
444 | case 'i': | ||
445 | pkt_interval = get_timevar(optarg); | ||
446 | break; | ||
447 | case 'I': | ||
448 | target_interval = get_timevar(optarg); | ||
449 | break; | ||
450 | case 'w': | ||
451 | get_threshold(optarg, &warn); | ||
452 | break; | ||
453 | case 'c': | ||
454 | get_threshold(optarg, &crit); | ||
455 | break; | ||
456 | case 'n': | ||
457 | case 'p': | ||
458 | packets = strtoul(optarg, NULL, 0); | ||
459 | break; | ||
460 | case 't': | ||
461 | timeout = strtoul(optarg, NULL, 0); | ||
462 | if(!timeout) timeout = 10; | ||
463 | break; | ||
464 | case 'H': | ||
465 | add_target(optarg); | ||
466 | break; | ||
467 | case 'l': | ||
468 | ttl = (unsigned char)strtoul(optarg, NULL, 0); | ||
469 | break; | ||
470 | case 'm': | ||
471 | min_hosts_alive = (int)strtoul(optarg, NULL, 0); | ||
472 | break; | ||
473 | case 'd': /* implement later, for cluster checks */ | ||
474 | warn_down = (unsigned char)strtoul(optarg, &ptr, 0); | ||
475 | if(ptr) { | ||
476 | crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0); | ||
477 | } | ||
478 | break; | ||
479 | case 's': /* specify source IP address */ | ||
480 | set_source_ip(optarg); | ||
481 | break; | ||
482 | case 'V': /* version */ | ||
483 | print_revision (progname, NP_VERSION); | ||
484 | exit (STATE_UNKNOWN); | ||
485 | case 'h': /* help */ | ||
486 | print_help (); | ||
487 | exit (STATE_UNKNOWN); | ||
488 | break; | ||
489 | case '4': | ||
490 | address_family = AF_INET; | ||
491 | icmp_proto = IPPROTO_ICMP; | ||
492 | break; | ||
493 | case '6': | ||
494 | #ifdef USE_IPV6 | ||
495 | address_family = AF_INET6; | ||
496 | icmp_proto = IPPROTO_ICMPV6; | ||
497 | #else | ||
498 | usage (_("IPv6 support not available\n")); | ||
499 | #endif | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | } | ||
504 | |||
505 | if((icmp_sock = socket(address_family, SOCK_RAW, icmp_proto)) != -1) | ||
394 | sockets |= HAVE_ICMP; | 506 | sockets |= HAVE_ICMP; |
395 | else icmp_sockerrno = errno; | 507 | else icmp_sockerrno = errno; |
396 | 508 | ||
@@ -403,7 +515,10 @@ main(int argc, char **argv) | |||
403 | /* else tcp_sockerrno = errno; */ | 515 | /* else tcp_sockerrno = errno; */ |
404 | 516 | ||
405 | /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ | 517 | /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ |
406 | setuid(getuid()); | 518 | if (setuid(getuid()) == -1) { |
519 | printf("ERROR: Failed to drop privileges\n"); | ||
520 | return 1; | ||
521 | } | ||
407 | 522 | ||
408 | #ifdef SO_TIMESTAMP | 523 | #ifdef SO_TIMESTAMP |
409 | if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) | 524 | if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) |
@@ -467,73 +582,6 @@ main(int argc, char **argv) | |||
467 | strcpy(argv[1], "-V"); | 582 | strcpy(argv[1], "-V"); |
468 | } | 583 | } |
469 | 584 | ||
470 | /* parse the arguments */ | ||
471 | 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) { | ||
473 | unsigned short size; | ||
474 | switch(arg) { | ||
475 | case 'v': | ||
476 | debug++; | ||
477 | break; | ||
478 | case 'b': | ||
479 | size = (unsigned short)strtol(optarg,NULL,0); | ||
480 | if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && | ||
481 | size < MAX_PING_DATA) { | ||
482 | icmp_data_size = size; | ||
483 | icmp_pkt_size = size + ICMP_MINLEN; | ||
484 | } else | ||
485 | usage_va("ICMP data length must be between: %d and %d", | ||
486 | sizeof(struct icmp) + sizeof(struct icmp_ping_data), | ||
487 | MAX_PING_DATA - 1); | ||
488 | break; | ||
489 | case 'i': | ||
490 | pkt_interval = get_timevar(optarg); | ||
491 | break; | ||
492 | case 'I': | ||
493 | target_interval = get_timevar(optarg); | ||
494 | break; | ||
495 | case 'w': | ||
496 | get_threshold(optarg, &warn); | ||
497 | break; | ||
498 | case 'c': | ||
499 | get_threshold(optarg, &crit); | ||
500 | break; | ||
501 | case 'n': | ||
502 | case 'p': | ||
503 | packets = strtoul(optarg, NULL, 0); | ||
504 | break; | ||
505 | case 't': | ||
506 | timeout = strtoul(optarg, NULL, 0); | ||
507 | if(!timeout) timeout = 10; | ||
508 | break; | ||
509 | case 'H': | ||
510 | add_target(optarg); | ||
511 | break; | ||
512 | case 'l': | ||
513 | ttl = (unsigned char)strtoul(optarg, NULL, 0); | ||
514 | break; | ||
515 | case 'm': | ||
516 | min_hosts_alive = (int)strtoul(optarg, NULL, 0); | ||
517 | break; | ||
518 | case 'd': /* implement later, for cluster checks */ | ||
519 | warn_down = (unsigned char)strtoul(optarg, &ptr, 0); | ||
520 | if(ptr) { | ||
521 | crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0); | ||
522 | } | ||
523 | break; | ||
524 | case 's': /* specify source IP address */ | ||
525 | set_source_ip(optarg); | ||
526 | break; | ||
527 | case 'V': /* version */ | ||
528 | print_revision (progname, NP_VERSION); | ||
529 | exit (STATE_UNKNOWN); | ||
530 | case 'h': /* help */ | ||
531 | print_help (); | ||
532 | exit (STATE_UNKNOWN); | ||
533 | } | ||
534 | } | ||
535 | } | ||
536 | |||
537 | argv = &argv[optind]; | 585 | argv = &argv[optind]; |
538 | while(*argv) { | 586 | while(*argv) { |
539 | add_target(*argv); | 587 | add_target(*argv); |
@@ -633,7 +681,7 @@ main(int argc, char **argv) | |||
633 | } | 681 | } |
634 | 682 | ||
635 | host = list; | 683 | host = list; |
636 | table = malloc(sizeof(struct rta_host **) * targets); | 684 | table = (struct rta_host**)malloc(sizeof(struct rta_host **) * targets); |
637 | i = 0; | 685 | i = 0; |
638 | while(host) { | 686 | while(host) { |
639 | host->id = i*packets; | 687 | host->id = i*packets; |
@@ -697,9 +745,15 @@ run_checks() | |||
697 | } | 745 | } |
698 | } | 746 | } |
699 | 747 | ||
748 | |||
700 | /* response structure: | 749 | /* response structure: |
750 | * IPv4: | ||
701 | * ip header : 20 bytes | 751 | * ip header : 20 bytes |
702 | * icmp header : 28 bytes | 752 | * icmp header : 28 bytes |
753 | * IPv6: | ||
754 | * ip header : 40 bytes | ||
755 | * icmp header : 28 bytes | ||
756 | * both: | ||
703 | * icmp echo reply : the rest | 757 | * icmp echo reply : the rest |
704 | */ | 758 | */ |
705 | static int | 759 | static int |
@@ -707,16 +761,27 @@ wait_for_reply(int sock, u_int t) | |||
707 | { | 761 | { |
708 | int n, hlen; | 762 | int n, hlen; |
709 | static unsigned char buf[4096]; | 763 | static unsigned char buf[4096]; |
710 | struct sockaddr_in resp_addr; | 764 | struct sockaddr_storage resp_addr; |
711 | struct ip *ip; | 765 | union ip_hdr *ip; |
712 | struct icmp icp; | 766 | union icmp_packet packet; |
713 | struct rta_host *host; | 767 | struct rta_host *host; |
714 | struct icmp_ping_data data; | 768 | struct icmp_ping_data data; |
715 | struct timeval wait_start, now; | 769 | struct timeval wait_start, now; |
716 | u_int tdiff, i, per_pkt_wait; | 770 | u_int tdiff, i, per_pkt_wait; |
717 | 771 | ||
772 | if (!(packet.buf = malloc(icmp_pkt_size))) { | ||
773 | crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", | ||
774 | icmp_pkt_size); | ||
775 | return -1; /* might be reached if we're in debug mode */ | ||
776 | } | ||
777 | |||
778 | memset(packet.buf, 0, icmp_pkt_size); | ||
779 | |||
718 | /* if we can't listen or don't have anything to listen to, just return */ | 780 | /* if we can't listen or don't have anything to listen to, just return */ |
719 | if(!t || !icmp_pkts_en_route) return 0; | 781 | if(!t || !icmp_pkts_en_route) { |
782 | free(packet.buf); | ||
783 | return 0; | ||
784 | } | ||
720 | 785 | ||
721 | gettimeofday(&wait_start, &tz); | 786 | gettimeofday(&wait_start, &tz); |
722 | 787 | ||
@@ -735,7 +800,7 @@ wait_for_reply(int sock, u_int t) | |||
735 | 800 | ||
736 | /* reap responses until we hit a timeout */ | 801 | /* reap responses until we hit a timeout */ |
737 | n = recvfrom_wto(sock, buf, sizeof(buf), | 802 | n = recvfrom_wto(sock, buf, sizeof(buf), |
738 | (struct sockaddr *)&resp_addr, &t, &now); | 803 | (struct sockaddr *)&resp_addr, &t, &now); |
739 | if(!n) { | 804 | if(!n) { |
740 | if(debug > 1) { | 805 | if(debug > 1) { |
741 | printf("recvfrom_wto() timed out during a %u usecs wait\n", | 806 | printf("recvfrom_wto() timed out during a %u usecs wait\n", |
@@ -745,12 +810,23 @@ wait_for_reply(int sock, u_int t) | |||
745 | } | 810 | } |
746 | if(n < 0) { | 811 | if(n < 0) { |
747 | if(debug) printf("recvfrom_wto() returned errors\n"); | 812 | if(debug) printf("recvfrom_wto() returned errors\n"); |
813 | free(packet.buf); | ||
748 | return n; | 814 | return n; |
749 | } | 815 | } |
750 | 816 | ||
751 | ip = (struct ip *)buf; | 817 | // FIXME: with ipv6 we don't have an ip header here |
752 | if(debug > 1) printf("received %u bytes from %s\n", | 818 | if (address_family != AF_INET6) { |
753 | ntohs(ip->ip_len), inet_ntoa(resp_addr.sin_addr)); | 819 | ip = (union ip_hdr *)buf; |
820 | |||
821 | if(debug > 1) { | ||
822 | char address[INET6_ADDRSTRLEN]; | ||
823 | parse_address(&resp_addr, address, sizeof(address)); | ||
824 | printf("received %u bytes from %s\n", | ||
825 | address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen) | ||
826 | : ntohs(ip->ip.ip_len), | ||
827 | address); | ||
828 | } | ||
829 | } | ||
754 | 830 | ||
755 | /* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ | 831 | /* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ |
756 | /* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ | 832 | /* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ |
@@ -759,12 +835,14 @@ wait_for_reply(int sock, u_int t) | |||
759 | * off the bottom 4 bits */ | 835 | * off the bottom 4 bits */ |
760 | /* hlen = (ip->ip_vhl & 0x0f) << 2; */ | 836 | /* hlen = (ip->ip_vhl & 0x0f) << 2; */ |
761 | /* #else */ | 837 | /* #else */ |
762 | hlen = ip->ip_hl << 2; | 838 | hlen = (address_family == AF_INET6) ? 0 : ip->ip.ip_hl << 2; |
763 | /* #endif */ | 839 | /* #endif */ |
764 | 840 | ||
765 | if(n < (hlen + ICMP_MINLEN)) { | 841 | if(n < (hlen + ICMP_MINLEN)) { |
842 | char address[INET6_ADDRSTRLEN]; | ||
843 | parse_address(&resp_addr, address, sizeof(address)); | ||
766 | crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", | 844 | 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)); | 845 | n, hlen + icmp_pkt_size, address); |
768 | } | 846 | } |
769 | /* else if(debug) { */ | 847 | /* else if(debug) { */ |
770 | /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ | 848 | /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ |
@@ -773,23 +851,39 @@ wait_for_reply(int sock, u_int t) | |||
773 | /* } */ | 851 | /* } */ |
774 | 852 | ||
775 | /* check the response */ | 853 | /* check the response */ |
776 | memcpy(&icp, buf + hlen, sizeof(icp)); | ||
777 | 854 | ||
778 | if(ntohs(icp.icmp_id) != pid || icp.icmp_type != ICMP_ECHOREPLY || | 855 | memcpy(packet.buf, buf + hlen, icmp_pkt_size); |
779 | ntohs(icp.icmp_seq) >= targets*packets) { | 856 | /* address_family == AF_INET6 ? sizeof(struct icmp6_hdr) |
857 | : sizeof(struct icmp));*/ | ||
858 | |||
859 | if( (address_family == PF_INET && | ||
860 | (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY | ||
861 | || ntohs(packet.icp->icmp_seq) >= targets * packets)) | ||
862 | || (address_family == PF_INET6 && | ||
863 | (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY | ||
864 | || ntohs(packet.icp6->icmp6_seq) >= targets * packets))) { | ||
780 | if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); | 865 | if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); |
781 | handle_random_icmp(buf + hlen, &resp_addr); | 866 | handle_random_icmp(buf + hlen, &resp_addr); |
782 | continue; | 867 | continue; |
783 | } | 868 | } |
784 | 869 | ||
785 | /* this is indeed a valid response */ | 870 | /* this is indeed a valid response */ |
786 | memcpy(&data, icp.icmp_data, sizeof(data)); | 871 | if (address_family == PF_INET) { |
787 | if (debug > 2) | 872 | memcpy(&data, packet.icp->icmp_data, sizeof(data)); |
788 | printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", | 873 | if (debug > 2) |
789 | (unsigned long)sizeof(data), ntohs(icp.icmp_id), | 874 | printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", |
790 | ntohs(icp.icmp_seq), icp.icmp_cksum); | 875 | (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), |
876 | ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum); | ||
877 | host = table[ntohs(packet.icp->icmp_seq)/packets]; | ||
878 | } else { | ||
879 | memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data)); | ||
880 | if (debug > 2) | ||
881 | printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", | ||
882 | (unsigned long)sizeof(data), ntohs(packet.icp6->icmp6_id), | ||
883 | ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum); | ||
884 | host = table[ntohs(packet.icp6->icmp6_seq)/packets]; | ||
885 | } | ||
791 | 886 | ||
792 | host = table[ntohs(icp.icmp_seq)/packets]; | ||
793 | tdiff = get_timevaldiff(&data.stime, &now); | 887 | tdiff = get_timevaldiff(&data.stime, &now); |
794 | 888 | ||
795 | host->time_waited += tdiff; | 889 | host->time_waited += tdiff; |
@@ -801,22 +895,25 @@ wait_for_reply(int sock, u_int t) | |||
801 | host->rtmin = tdiff; | 895 | host->rtmin = tdiff; |
802 | 896 | ||
803 | if(debug) { | 897 | if(debug) { |
898 | char address[INET6_ADDRSTRLEN]; | ||
899 | 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", | 900 | 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), | 901 | (float)tdiff / 1000, address, |
806 | ttl, ip->ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); | 902 | ttl, ip->ip.ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); |
807 | } | 903 | } |
808 | 904 | ||
809 | /* if we're in hostcheck mode, exit with limited printouts */ | 905 | /* if we're in hostcheck mode, exit with limited printouts */ |
810 | if(mode == MODE_HOSTCHECK) { | 906 | if(mode == MODE_HOSTCHECK) { |
811 | printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" | 907 | printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" |
812 | "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", | 908 | "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", |
813 | host->name, icmp_recv, (float)tdiff / 1000, | 909 | host->name, icmp_recv, (float)tdiff / 1000, |
814 | icmp_recv, packets, (float)tdiff / 1000, | 910 | icmp_recv, packets, (float)tdiff / 1000, |
815 | (float)warn.rta / 1000, (float)crit.rta / 1000); | 911 | (float)warn.rta / 1000, (float)crit.rta / 1000); |
816 | exit(STATE_OK); | 912 | exit(STATE_OK); |
817 | } | 913 | } |
818 | } | 914 | } |
819 | 915 | ||
916 | free(packet.buf); | ||
820 | return 0; | 917 | return 0; |
821 | } | 918 | } |
822 | 919 | ||
@@ -824,62 +921,81 @@ wait_for_reply(int sock, u_int t) | |||
824 | static int | 921 | static int |
825 | send_icmp_ping(int sock, struct rta_host *host) | 922 | send_icmp_ping(int sock, struct rta_host *host) |
826 | { | 923 | { |
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; | 924 | long int len; |
833 | struct icmp_ping_data data; | 925 | struct icmp_ping_data data; |
834 | struct msghdr hdr; | 926 | struct msghdr hdr; |
835 | struct iovec iov; | 927 | struct iovec iov; |
836 | struct timeval tv; | 928 | struct timeval tv; |
837 | struct sockaddr *addr; | 929 | void *buf = NULL; |
838 | 930 | ||
839 | if(sock == -1) { | 931 | if(sock == -1) { |
840 | errno = 0; | 932 | errno = 0; |
841 | crash("Attempt to send on bogus socket"); | 933 | crash("Attempt to send on bogus socket"); |
842 | return -1; | 934 | return -1; |
843 | } | 935 | } |
844 | addr = (struct sockaddr *)&host->saddr_in; | ||
845 | 936 | ||
846 | if(!packet.buf) { | 937 | if(!buf) { |
847 | if (!(packet.buf = malloc(icmp_pkt_size))) { | 938 | if (!(buf = malloc(icmp_pkt_size))) { |
848 | crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", | 939 | crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", |
849 | icmp_pkt_size); | 940 | icmp_pkt_size); |
850 | return -1; /* might be reached if we're in debug mode */ | 941 | return -1; /* might be reached if we're in debug mode */ |
851 | } | 942 | } |
852 | } | 943 | } |
853 | memset(packet.buf, 0, icmp_pkt_size); | 944 | memset(buf, 0, icmp_pkt_size); |
854 | 945 | ||
855 | if((gettimeofday(&tv, &tz)) == -1) return -1; | 946 | if((gettimeofday(&tv, &tz)) == -1) { |
947 | free(buf); | ||
948 | return -1; | ||
949 | } | ||
856 | 950 | ||
857 | data.ping_id = 10; /* host->icmp.icmp_sent; */ | 951 | data.ping_id = 10; /* host->icmp.icmp_sent; */ |
858 | memcpy(&data.stime, &tv, sizeof(tv)); | 952 | memcpy(&data.stime, &tv, sizeof(tv)); |
859 | memcpy(&packet.icp->icmp_data, &data, sizeof(data)); | 953 | |
860 | packet.icp->icmp_type = ICMP_ECHO; | 954 | if (address_family == AF_INET) { |
861 | packet.icp->icmp_code = 0; | 955 | struct icmp *icp = (struct icmp*)buf; |
862 | packet.icp->icmp_cksum = 0; | 956 | |
863 | packet.icp->icmp_id = htons(pid); | 957 | memcpy(&icp->icmp_data, &data, sizeof(data)); |
864 | packet.icp->icmp_seq = htons(host->id++); | 958 | |
865 | packet.icp->icmp_cksum = icmp_checksum(packet.cksum_in, icmp_pkt_size); | 959 | icp->icmp_type = ICMP_ECHO; |
866 | 960 | icp->icmp_code = 0; | |
867 | if (debug > 2) | 961 | icp->icmp_cksum = 0; |
868 | printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", | 962 | icp->icmp_id = htons(pid); |
869 | (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), | 963 | icp->icmp_seq = htons(host->id++); |
870 | ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, | 964 | icp->icmp_cksum = icmp_checksum((unsigned short*)buf, icmp_pkt_size); |
871 | host->name); | 965 | |
966 | if (debug > 2) | ||
967 | printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", | ||
968 | (unsigned long)sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum, host->name); | ||
969 | } | ||
970 | else { | ||
971 | struct icmp6_hdr *icp6 = (struct icmp6_hdr*)buf; | ||
972 | memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data)); | ||
973 | icp6->icmp6_type = ICMP6_ECHO_REQUEST; | ||
974 | icp6->icmp6_code = 0; | ||
975 | icp6->icmp6_cksum = 0; | ||
976 | icp6->icmp6_id = htons(pid); | ||
977 | icp6->icmp6_seq = htons(host->id++); | ||
978 | // let checksum be calculated automatically | ||
979 | |||
980 | if (debug > 2) { | ||
981 | printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", | ||
982 | (unsigned long)sizeof(data), ntohs(icp6->icmp6_id), | ||
983 | ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name); | ||
984 | } | ||
985 | } | ||
872 | 986 | ||
873 | memset(&iov, 0, sizeof(iov)); | 987 | memset(&iov, 0, sizeof(iov)); |
874 | iov.iov_base = packet.buf; | 988 | iov.iov_base = buf; |
875 | iov.iov_len = icmp_pkt_size; | 989 | iov.iov_len = icmp_pkt_size; |
876 | 990 | ||
877 | memset(&hdr, 0, sizeof(hdr)); | 991 | memset(&hdr, 0, sizeof(hdr)); |
878 | hdr.msg_name = addr; | 992 | hdr.msg_name = (struct sockaddr *)&host->saddr_in; |
879 | hdr.msg_namelen = sizeof(struct sockaddr); | 993 | hdr.msg_namelen = sizeof(struct sockaddr_storage); |
880 | hdr.msg_iov = &iov; | 994 | hdr.msg_iov = &iov; |
881 | hdr.msg_iovlen = 1; | 995 | hdr.msg_iovlen = 1; |
882 | 996 | ||
997 | errno = 0; | ||
998 | |||
883 | /* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ | 999 | /* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ |
884 | #ifdef MSG_CONFIRM | 1000 | #ifdef MSG_CONFIRM |
885 | len = sendmsg(sock, &hdr, MSG_CONFIRM); | 1001 | len = sendmsg(sock, &hdr, MSG_CONFIRM); |
@@ -887,9 +1003,15 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
887 | len = sendmsg(sock, &hdr, 0); | 1003 | len = sendmsg(sock, &hdr, 0); |
888 | #endif | 1004 | #endif |
889 | 1005 | ||
1006 | free(buf); | ||
1007 | |||
890 | if(len < 0 || (unsigned int)len != icmp_pkt_size) { | 1008 | if(len < 0 || (unsigned int)len != icmp_pkt_size) { |
891 | if(debug) printf("Failed to send ping to %s\n", | 1009 | if(debug) { |
892 | inet_ntoa(host->saddr_in.sin_addr)); | 1010 | char address[INET6_ADDRSTRLEN]; |
1011 | parse_address((struct sockaddr_storage *)&host->saddr_in, address, sizeof(address)); | ||
1012 | printf("Failed to send ping to %s: %s\n", address, strerror(errno)); | ||
1013 | } | ||
1014 | errno = 0; | ||
893 | return -1; | 1015 | return -1; |
894 | } | 1016 | } |
895 | 1017 | ||
@@ -934,7 +1056,7 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, | |||
934 | 1056 | ||
935 | if(!n) return 0; /* timeout */ | 1057 | if(!n) return 0; /* timeout */ |
936 | 1058 | ||
937 | slen = sizeof(struct sockaddr); | 1059 | slen = sizeof(struct sockaddr_storage); |
938 | 1060 | ||
939 | memset(&iov, 0, sizeof(iov)); | 1061 | memset(&iov, 0, sizeof(iov)); |
940 | iov.iov_base = buf; | 1062 | iov.iov_base = buf; |
@@ -958,6 +1080,7 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, | |||
958 | break ; | 1080 | break ; |
959 | } | 1081 | } |
960 | } | 1082 | } |
1083 | |||
961 | if (!chdr) | 1084 | if (!chdr) |
962 | #endif // SO_TIMESTAMP | 1085 | #endif // SO_TIMESTAMP |
963 | gettimeofday(tv, &tz); | 1086 | gettimeofday(tv, &tz); |
@@ -991,6 +1114,7 @@ finish(int sig) | |||
991 | 1114 | ||
992 | /* iterate thrice to calculate values, give output, and print perfparse */ | 1115 | /* iterate thrice to calculate values, give output, and print perfparse */ |
993 | host = list; | 1116 | host = list; |
1117 | |||
994 | while(host) { | 1118 | while(host) { |
995 | if(!host->icmp_recv) { | 1119 | if(!host->icmp_recv) { |
996 | /* rta 0 is ofcourse not entirely correct, but will still show up | 1120 | /* rta 0 is ofcourse not entirely correct, but will still show up |
@@ -1039,10 +1163,12 @@ finish(int sig) | |||
1039 | if(!host->icmp_recv) { | 1163 | if(!host->icmp_recv) { |
1040 | status = STATE_CRITICAL; | 1164 | status = STATE_CRITICAL; |
1041 | if(host->flags & FLAG_LOST_CAUSE) { | 1165 | if(host->flags & FLAG_LOST_CAUSE) { |
1166 | char address[INET6_ADDRSTRLEN]; | ||
1167 | parse_address(&host->error_addr, address, sizeof(address)); | ||
1042 | printf("%s: %s @ %s. rta nan, lost %d%%", | 1168 | printf("%s: %s @ %s. rta nan, lost %d%%", |
1043 | host->name, | 1169 | host->name, |
1044 | get_icmp_error_msg(host->icmp_type, host->icmp_code), | 1170 | get_icmp_error_msg(host->icmp_type, host->icmp_code), |
1045 | inet_ntoa(host->error_addr), | 1171 | address, |
1046 | 100); | 1172 | 100); |
1047 | } | 1173 | } |
1048 | else { /* not marked as lost cause, so we have no flags for it */ | 1174 | else { /* not marked as lost cause, so we have no flags for it */ |
@@ -1104,7 +1230,6 @@ get_timevaldiff(struct timeval *early, struct timeval *later) | |||
1104 | { | 1230 | { |
1105 | return 0; | 1231 | return 0; |
1106 | } | 1232 | } |
1107 | |||
1108 | ret = (later->tv_sec - early->tv_sec) * 1000000; | 1233 | ret = (later->tv_sec - early->tv_sec) * 1000000; |
1109 | ret += later->tv_usec - early->tv_usec; | 1234 | ret += later->tv_usec - early->tv_usec; |
1110 | 1235 | ||
@@ -1112,18 +1237,35 @@ get_timevaldiff(struct timeval *early, struct timeval *later) | |||
1112 | } | 1237 | } |
1113 | 1238 | ||
1114 | static int | 1239 | static int |
1115 | add_target_ip(char *arg, struct in_addr *in) | 1240 | add_target_ip(char *arg, struct sockaddr_storage *in) |
1116 | { | 1241 | { |
1117 | struct rta_host *host; | 1242 | struct rta_host *host; |
1243 | struct sockaddr_in *sin, *host_sin; | ||
1244 | struct sockaddr_in6 *sin6, *host_sin6; | ||
1118 | 1245 | ||
1119 | /* disregard obviously stupid addresses */ | 1246 | if (address_family == AF_INET) |
1120 | if(in->s_addr == INADDR_NONE || in->s_addr == INADDR_ANY) | 1247 | sin = (struct sockaddr_in *)in; |
1248 | else | ||
1249 | sin6 = (struct sockaddr_in6 *)in; | ||
1250 | |||
1251 | |||
1252 | |||
1253 | /* disregard obviously stupid addresses | ||
1254 | * (I didn't find an ipv6 equivalent to INADDR_NONE) */ | ||
1255 | if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE | ||
1256 | || sin->sin_addr.s_addr == INADDR_ANY))) | ||
1257 | || (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { | ||
1121 | return -1; | 1258 | return -1; |
1259 | } | ||
1122 | 1260 | ||
1123 | /* no point in adding two identical IP's, so don't. ;) */ | 1261 | /* no point in adding two identical IP's, so don't. ;) */ |
1124 | host = list; | 1262 | host = list; |
1125 | while(host) { | 1263 | while(host) { |
1126 | if(host->saddr_in.sin_addr.s_addr == in->s_addr) { | 1264 | host_sin = (struct sockaddr_in *)&host->saddr_in; |
1265 | host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; | ||
1266 | |||
1267 | if( (address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) | ||
1268 | || (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); | 1269 | if(debug) printf("Identical IP already exists. Not adding %s\n", arg); |
1128 | return -1; | 1270 | return -1; |
1129 | } | 1271 | } |
@@ -1131,19 +1273,29 @@ add_target_ip(char *arg, struct in_addr *in) | |||
1131 | } | 1273 | } |
1132 | 1274 | ||
1133 | /* add the fresh ip */ | 1275 | /* add the fresh ip */ |
1134 | host = malloc(sizeof(struct rta_host)); | 1276 | host = (struct rta_host*)malloc(sizeof(struct rta_host)); |
1135 | if(!host) { | 1277 | if(!host) { |
1278 | char straddr[INET6_ADDRSTRLEN]; | ||
1279 | parse_address((struct sockaddr_storage*)&in, straddr, sizeof(straddr)); | ||
1136 | crash("add_target_ip(%s, %s): malloc(%d) failed", | 1280 | crash("add_target_ip(%s, %s): malloc(%d) failed", |
1137 | arg, inet_ntoa(*in), sizeof(struct rta_host)); | 1281 | arg, straddr, sizeof(struct rta_host)); |
1138 | } | 1282 | } |
1139 | memset(host, 0, sizeof(struct rta_host)); | 1283 | memset(host, 0, sizeof(struct rta_host)); |
1140 | 1284 | ||
1141 | /* set the values. use calling name for output */ | 1285 | /* set the values. use calling name for output */ |
1142 | host->name = strdup(arg); | 1286 | host->name = strdup(arg); |
1143 | 1287 | ||
1144 | /* fill out the sockaddr_in struct */ | 1288 | /* fill out the sockaddr_storage struct */ |
1145 | host->saddr_in.sin_family = AF_INET; | 1289 | if(address_family == AF_INET) { |
1146 | host->saddr_in.sin_addr.s_addr = in->s_addr; | 1290 | host_sin = (struct sockaddr_in *)&host->saddr_in; |
1291 | host_sin->sin_family = AF_INET; | ||
1292 | host_sin->sin_addr.s_addr = sin->sin_addr.s_addr; | ||
1293 | } | ||
1294 | else { | ||
1295 | host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; | ||
1296 | host_sin6->sin6_family = AF_INET6; | ||
1297 | memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr); | ||
1298 | } | ||
1147 | 1299 | ||
1148 | host->rtmin = DBL_MAX; | 1300 | host->rtmin = DBL_MAX; |
1149 | 1301 | ||
@@ -1160,31 +1312,45 @@ add_target_ip(char *arg, struct in_addr *in) | |||
1160 | static int | 1312 | static int |
1161 | add_target(char *arg) | 1313 | add_target(char *arg) |
1162 | { | 1314 | { |
1163 | int i; | 1315 | int error, result; |
1164 | struct hostent *he; | 1316 | struct sockaddr_storage ip; |
1165 | struct in_addr *in, ip; | 1317 | struct addrinfo hints, *res, *p; |
1318 | struct sockaddr_in *sin; | ||
1319 | struct sockaddr_in6 *sin6; | ||
1320 | |||
1321 | switch (address_family) { | ||
1322 | case AF_INET: | ||
1323 | sin = (struct sockaddr_in *)&ip; | ||
1324 | result = inet_pton(address_family, arg, &sin->sin_addr); | ||
1325 | break; | ||
1326 | case AF_INET6: | ||
1327 | sin6 = (struct sockaddr_in6 *)&ip; | ||
1328 | result = inet_pton(address_family, arg, &sin6->sin6_addr); | ||
1329 | break; | ||
1330 | default: crash("Address family not supported"); | ||
1331 | } | ||
1166 | 1332 | ||
1167 | /* don't resolve if we don't have to */ | 1333 | /* don't resolve if we don't have to */ |
1168 | if((ip.s_addr = inet_addr(arg)) != INADDR_NONE) { | 1334 | if(result == 1) { |
1169 | /* don't add all ip's if we were given a specific one */ | 1335 | /* don't add all ip's if we were given a specific one */ |
1170 | return add_target_ip(arg, &ip); | 1336 | 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 | } | 1337 | } |
1174 | else { | 1338 | else { |
1175 | errno = 0; | 1339 | errno = 0; |
1176 | he = gethostbyname(arg); | 1340 | memset(&hints, 0, sizeof(hints)); |
1177 | if(!he) { | 1341 | hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6; |
1342 | hints.ai_socktype = SOCK_RAW; | ||
1343 | if((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) { | ||
1178 | errno = 0; | 1344 | errno = 0; |
1179 | crash("Failed to resolve %s", arg); | 1345 | crash("Failed to resolve %s: %s", arg, gai_strerror(error)); |
1180 | return -1; | 1346 | return -1; |
1181 | } | 1347 | } |
1182 | } | 1348 | } |
1183 | 1349 | ||
1184 | /* possibly add all the IP's as targets */ | 1350 | /* possibly add all the IP's as targets */ |
1185 | for(i = 0; he->h_addr_list[i]; i++) { | 1351 | for(p = res; p != NULL; p = p->ai_next) { |
1186 | in = (struct in_addr *)he->h_addr_list[i]; | 1352 | memcpy(&ip, p->ai_addr, p->ai_addrlen); |
1187 | add_target_ip(arg, in); | 1353 | add_target_ip(arg, &ip); |
1188 | 1354 | ||
1189 | /* this is silly, but it works */ | 1355 | /* this is silly, but it works */ |
1190 | if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { | 1356 | if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { |
@@ -1193,6 +1359,7 @@ add_target(char *arg) | |||
1193 | } | 1359 | } |
1194 | break; | 1360 | break; |
1195 | } | 1361 | } |
1362 | freeaddrinfo(res); | ||
1196 | 1363 | ||
1197 | return 0; | 1364 | return 0; |
1198 | } | 1365 | } |
@@ -1203,7 +1370,7 @@ set_source_ip(char *arg) | |||
1203 | struct sockaddr_in src; | 1370 | struct sockaddr_in src; |
1204 | 1371 | ||
1205 | memset(&src, 0, sizeof(src)); | 1372 | memset(&src, 0, sizeof(src)); |
1206 | src.sin_family = AF_INET; | 1373 | src.sin_family = address_family; |
1207 | if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) | 1374 | if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) |
1208 | src.sin_addr.s_addr = get_ip_address(arg); | 1375 | src.sin_addr.s_addr = get_ip_address(arg); |
1209 | if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) | 1376 | if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) |
@@ -1311,12 +1478,12 @@ get_threshold(char *str, threshold *th) | |||
1311 | unsigned short | 1478 | unsigned short |
1312 | icmp_checksum(unsigned short *p, int n) | 1479 | icmp_checksum(unsigned short *p, int n) |
1313 | { | 1480 | { |
1314 | register unsigned short cksum; | 1481 | unsigned short cksum; |
1315 | register long sum = 0; | 1482 | long sum = 0; |
1316 | 1483 | ||
1317 | while(n > 1) { | 1484 | while(n > 2) { |
1318 | sum += *p++; | 1485 | sum += *p++; |
1319 | n -= 2; | 1486 | n -= sizeof(unsigned short); |
1320 | } | 1487 | } |
1321 | 1488 | ||
1322 | /* mop up the occasional odd byte */ | 1489 | /* mop up the occasional odd byte */ |
@@ -1347,6 +1514,8 @@ print_help(void) | |||
1347 | 1514 | ||
1348 | printf (" %s\n", "-H"); | 1515 | printf (" %s\n", "-H"); |
1349 | printf (" %s\n", _("specify a target")); | 1516 | printf (" %s\n", _("specify a target")); |
1517 | printf (" %s\n", "[-4|-6]"); | ||
1518 | printf (" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets")); | ||
1350 | printf (" %s\n", "-w"); | 1519 | printf (" %s\n", "-w"); |
1351 | printf (" %s", _("warning threshold (currently ")); | 1520 | printf (" %s", _("warning threshold (currently ")); |
1352 | printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); | 1521 | printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); |