diff options
Diffstat (limited to 'plugins-root')
-rw-r--r-- | plugins-root/check_icmp.c | 83 | ||||
-rw-r--r-- | plugins-root/t/check_icmp.t | 13 |
2 files changed, 61 insertions, 35 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 01ae174a..f8f15351 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c | |||
@@ -50,19 +50,11 @@ const char *email = "devel@monitoring-plugins.org"; | |||
50 | #if HAVE_SYS_SOCKIO_H | 50 | #if HAVE_SYS_SOCKIO_H |
51 | #include <sys/sockio.h> | 51 | #include <sys/sockio.h> |
52 | #endif | 52 | #endif |
53 | #include <sys/ioctl.h> | 53 | |
54 | #include <sys/time.h> | 54 | #include <sys/time.h> |
55 | #include <sys/types.h> | ||
56 | #include <stdio.h> | ||
57 | #include <stdlib.h> | ||
58 | #include <stdarg.h> | ||
59 | #include <unistd.h> | ||
60 | #include <stddef.h> | ||
61 | #include <errno.h> | 55 | #include <errno.h> |
62 | #include <string.h> | 56 | #include <signal.h> |
63 | #include <ctype.h> | 57 | #include <ctype.h> |
64 | #include <netdb.h> | ||
65 | #include <sys/socket.h> | ||
66 | #include <net/if.h> | 58 | #include <net/if.h> |
67 | #include <netinet/in_systm.h> | 59 | #include <netinet/in_systm.h> |
68 | #include <netinet/in.h> | 60 | #include <netinet/in.h> |
@@ -71,8 +63,6 @@ const char *email = "devel@monitoring-plugins.org"; | |||
71 | #include <netinet/ip_icmp.h> | 63 | #include <netinet/ip_icmp.h> |
72 | #include <netinet/icmp6.h> | 64 | #include <netinet/icmp6.h> |
73 | #include <arpa/inet.h> | 65 | #include <arpa/inet.h> |
74 | #include <signal.h> | ||
75 | #include <float.h> | ||
76 | 66 | ||
77 | 67 | ||
78 | /** sometimes undefined system macros (quite a few, actually) **/ | 68 | /** sometimes undefined system macros (quite a few, actually) **/ |
@@ -207,7 +197,7 @@ static int add_target(char *); | |||
207 | static int add_target_ip(char *, struct sockaddr_storage *); | 197 | static int add_target_ip(char *, struct sockaddr_storage *); |
208 | static int handle_random_icmp(unsigned char *, struct sockaddr_storage *); | 198 | static int handle_random_icmp(unsigned char *, struct sockaddr_storage *); |
209 | static void parse_address(struct sockaddr_storage *, char *, int); | 199 | static void parse_address(struct sockaddr_storage *, char *, int); |
210 | static unsigned short icmp_checksum(unsigned short *, int); | 200 | static unsigned short icmp_checksum(uint16_t *, size_t); |
211 | static void finish(int); | 201 | static void finish(int); |
212 | static void crash(const char *, ...); | 202 | static void crash(const char *, ...); |
213 | 203 | ||
@@ -223,7 +213,7 @@ static int mode, protocols, sockets, debug = 0, timeout = 10; | |||
223 | static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; | 213 | static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; |
224 | static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; | 214 | static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; |
225 | 215 | ||
226 | static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0; | 216 | static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0, ttl = 0; |
227 | #define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) | 217 | #define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) |
228 | static unsigned short targets_down = 0, targets = 0, packets = 0; | 218 | static unsigned short targets_down = 0, targets = 0, packets = 0; |
229 | #define targets_alive (targets - targets_down) | 219 | #define targets_alive (targets - targets_down) |
@@ -233,7 +223,6 @@ static pid_t pid; | |||
233 | static struct timezone tz; | 223 | static struct timezone tz; |
234 | static struct timeval prog_start; | 224 | static struct timeval prog_start; |
235 | static unsigned long long max_completion_time = 0; | 225 | static unsigned long long max_completion_time = 0; |
236 | static unsigned char ttl = 0; /* outgoing ttl */ | ||
237 | static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ | 226 | static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ |
238 | static int min_hosts_alive = -1; | 227 | static int min_hosts_alive = -1; |
239 | float pkt_backoff_factor = 1.5; | 228 | float pkt_backoff_factor = 1.5; |
@@ -410,6 +399,7 @@ main(int argc, char **argv) | |||
410 | #ifdef SO_TIMESTAMP | 399 | #ifdef SO_TIMESTAMP |
411 | int on = 1; | 400 | int on = 1; |
412 | #endif | 401 | #endif |
402 | char *source_ip = NULL; | ||
413 | char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:64"; | 403 | char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:64"; |
414 | 404 | ||
415 | setlocale (LC_ALL, ""); | 405 | setlocale (LC_ALL, ""); |
@@ -464,7 +454,6 @@ main(int argc, char **argv) | |||
464 | /* Parse protocol arguments first */ | 454 | /* Parse protocol arguments first */ |
465 | for(i = 1; i < argc; i++) { | 455 | for(i = 1; i < argc; i++) { |
466 | while((arg = getopt(argc, argv, opts_str)) != EOF) { | 456 | while((arg = getopt(argc, argv, opts_str)) != EOF) { |
467 | unsigned short size; | ||
468 | switch(arg) { | 457 | switch(arg) { |
469 | case '4': | 458 | case '4': |
470 | if (address_family != -1) | 459 | if (address_family != -1) |
@@ -487,10 +476,10 @@ main(int argc, char **argv) | |||
487 | /* Reset argument scanning */ | 476 | /* Reset argument scanning */ |
488 | optind = 1; | 477 | optind = 1; |
489 | 478 | ||
479 | unsigned short size; | ||
490 | /* parse the arguments */ | 480 | /* parse the arguments */ |
491 | for(i = 1; i < argc; i++) { | 481 | for(i = 1; i < argc; i++) { |
492 | while((arg = getopt(argc, argv, opts_str)) != EOF) { | 482 | while((arg = getopt(argc, argv, opts_str)) != EOF) { |
493 | unsigned short size; | ||
494 | switch(arg) { | 483 | switch(arg) { |
495 | case 'v': | 484 | case 'v': |
496 | debug++; | 485 | debug++; |
@@ -530,7 +519,7 @@ main(int argc, char **argv) | |||
530 | add_target(optarg); | 519 | add_target(optarg); |
531 | break; | 520 | break; |
532 | case 'l': | 521 | case 'l': |
533 | ttl = (unsigned char)strtoul(optarg, NULL, 0); | 522 | ttl = (int)strtoul(optarg, NULL, 0); |
534 | break; | 523 | break; |
535 | case 'm': | 524 | case 'm': |
536 | min_hosts_alive = (int)strtoul(optarg, NULL, 0); | 525 | min_hosts_alive = (int)strtoul(optarg, NULL, 0); |
@@ -542,7 +531,7 @@ main(int argc, char **argv) | |||
542 | } | 531 | } |
543 | break; | 532 | break; |
544 | case 's': /* specify source IP address */ | 533 | case 's': /* specify source IP address */ |
545 | set_source_ip(optarg); | 534 | source_ip = optarg; |
546 | break; | 535 | break; |
547 | case 'V': /* version */ | 536 | case 'V': /* version */ |
548 | print_revision (progname, NP_VERSION); | 537 | print_revision (progname, NP_VERSION); |
@@ -597,6 +586,8 @@ main(int argc, char **argv) | |||
597 | sockets |= HAVE_ICMP; | 586 | sockets |= HAVE_ICMP; |
598 | else icmp_sockerrno = errno; | 587 | else icmp_sockerrno = errno; |
599 | 588 | ||
589 | if( source_ip ) | ||
590 | set_source_ip(source_ip); | ||
600 | 591 | ||
601 | #ifdef SO_TIMESTAMP | 592 | #ifdef SO_TIMESTAMP |
602 | if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) | 593 | if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) |
@@ -717,7 +708,7 @@ main(int argc, char **argv) | |||
717 | static void | 708 | static void |
718 | run_checks() | 709 | run_checks() |
719 | { | 710 | { |
720 | u_int i, t, result; | 711 | u_int i, t; |
721 | u_int final_wait, time_passed; | 712 | u_int final_wait, time_passed; |
722 | 713 | ||
723 | /* this loop might actually violate the pkt_interval or target_interval | 714 | /* this loop might actually violate the pkt_interval or target_interval |
@@ -735,9 +726,9 @@ run_checks() | |||
735 | 726 | ||
736 | /* we're still in the game, so send next packet */ | 727 | /* we're still in the game, so send next packet */ |
737 | (void)send_icmp_ping(icmp_sock, table[t]); | 728 | (void)send_icmp_ping(icmp_sock, table[t]); |
738 | result = wait_for_reply(icmp_sock, target_interval); | 729 | wait_for_reply(icmp_sock, target_interval); |
739 | } | 730 | } |
740 | result = wait_for_reply(icmp_sock, pkt_interval * targets); | 731 | wait_for_reply(icmp_sock, pkt_interval * targets); |
741 | } | 732 | } |
742 | 733 | ||
743 | if(icmp_pkts_en_route && targets_alive) { | 734 | if(icmp_pkts_en_route && targets_alive) { |
@@ -757,7 +748,7 @@ run_checks() | |||
757 | * haven't yet */ | 748 | * haven't yet */ |
758 | if(debug) printf("Waiting for %u micro-seconds (%0.3f msecs)\n", | 749 | if(debug) printf("Waiting for %u micro-seconds (%0.3f msecs)\n", |
759 | final_wait, (float)final_wait / 1000); | 750 | final_wait, (float)final_wait / 1000); |
760 | result = wait_for_reply(icmp_sock, final_wait); | 751 | wait_for_reply(icmp_sock, final_wait); |
761 | } | 752 | } |
762 | } | 753 | } |
763 | 754 | ||
@@ -776,7 +767,7 @@ static int | |||
776 | wait_for_reply(int sock, u_int t) | 767 | wait_for_reply(int sock, u_int t) |
777 | { | 768 | { |
778 | int n, hlen; | 769 | int n, hlen; |
779 | static unsigned char buf[4096]; | 770 | static unsigned char buf[65536]; |
780 | struct sockaddr_storage resp_addr; | 771 | struct sockaddr_storage resp_addr; |
781 | union ip_hdr *ip; | 772 | union ip_hdr *ip; |
782 | union icmp_packet packet; | 773 | union icmp_packet packet; |
@@ -913,9 +904,27 @@ wait_for_reply(int sock, u_int t) | |||
913 | if(debug) { | 904 | if(debug) { |
914 | char address[INET6_ADDRSTRLEN]; | 905 | char address[INET6_ADDRSTRLEN]; |
915 | parse_address(&resp_addr, address, sizeof(address)); | 906 | parse_address(&resp_addr, address, sizeof(address)); |
916 | printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", | 907 | |
917 | (float)tdiff / 1000, address, | 908 | switch(address_family) { |
918 | ttl, ip->ip.ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); | 909 | case AF_INET: { |
910 | printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", | ||
911 | (float)tdiff / 1000, | ||
912 | address, | ||
913 | ttl, | ||
914 | ip->ip.ip_ttl, | ||
915 | (float)host->rtmax / 1000, | ||
916 | (float)host->rtmin / 1000); | ||
917 | break; | ||
918 | }; | ||
919 | case AF_INET6: { | ||
920 | printf("%0.3f ms rtt from %s, outgoing ttl: %u, max: %0.3f, min: %0.3f\n", | ||
921 | (float)tdiff / 1000, | ||
922 | address, | ||
923 | ttl, | ||
924 | (float)host->rtmax / 1000, | ||
925 | (float)host->rtmin / 1000); | ||
926 | }; | ||
927 | } | ||
919 | } | 928 | } |
920 | 929 | ||
921 | /* if we're in hostcheck mode, exit with limited printouts */ | 930 | /* if we're in hostcheck mode, exit with limited printouts */ |
@@ -938,6 +947,7 @@ static int | |||
938 | send_icmp_ping(int sock, struct rta_host *host) | 947 | send_icmp_ping(int sock, struct rta_host *host) |
939 | { | 948 | { |
940 | long int len; | 949 | long int len; |
950 | size_t addrlen; | ||
941 | struct icmp_ping_data data; | 951 | struct icmp_ping_data data; |
942 | struct msghdr hdr; | 952 | struct msghdr hdr; |
943 | struct iovec iov; | 953 | struct iovec iov; |
@@ -969,6 +979,7 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
969 | 979 | ||
970 | if (address_family == AF_INET) { | 980 | if (address_family == AF_INET) { |
971 | struct icmp *icp = (struct icmp*)buf; | 981 | struct icmp *icp = (struct icmp*)buf; |
982 | addrlen = sizeof(struct sockaddr_in); | ||
972 | 983 | ||
973 | memcpy(&icp->icmp_data, &data, sizeof(data)); | 984 | memcpy(&icp->icmp_data, &data, sizeof(data)); |
974 | 985 | ||
@@ -977,7 +988,7 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
977 | icp->icmp_cksum = 0; | 988 | icp->icmp_cksum = 0; |
978 | icp->icmp_id = htons(pid); | 989 | icp->icmp_id = htons(pid); |
979 | icp->icmp_seq = htons(host->id++); | 990 | icp->icmp_seq = htons(host->id++); |
980 | icp->icmp_cksum = icmp_checksum((unsigned short*)buf, icmp_pkt_size); | 991 | icp->icmp_cksum = icmp_checksum((uint16_t*)buf, (size_t)icmp_pkt_size); |
981 | 992 | ||
982 | if (debug > 2) | 993 | if (debug > 2) |
983 | printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", | 994 | printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", |
@@ -985,7 +996,10 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
985 | } | 996 | } |
986 | else { | 997 | else { |
987 | struct icmp6_hdr *icp6 = (struct icmp6_hdr*)buf; | 998 | struct icmp6_hdr *icp6 = (struct icmp6_hdr*)buf; |
999 | addrlen = sizeof(struct sockaddr_in6); | ||
1000 | |||
988 | memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data)); | 1001 | memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data)); |
1002 | |||
989 | icp6->icmp6_type = ICMP6_ECHO_REQUEST; | 1003 | icp6->icmp6_type = ICMP6_ECHO_REQUEST; |
990 | icp6->icmp6_code = 0; | 1004 | icp6->icmp6_code = 0; |
991 | icp6->icmp6_cksum = 0; | 1005 | icp6->icmp6_cksum = 0; |
@@ -1006,7 +1020,7 @@ send_icmp_ping(int sock, struct rta_host *host) | |||
1006 | 1020 | ||
1007 | memset(&hdr, 0, sizeof(hdr)); | 1021 | memset(&hdr, 0, sizeof(hdr)); |
1008 | hdr.msg_name = (struct sockaddr *)&host->saddr_in; | 1022 | hdr.msg_name = (struct sockaddr *)&host->saddr_in; |
1009 | hdr.msg_namelen = sizeof(struct sockaddr_storage); | 1023 | hdr.msg_namelen = addrlen; |
1010 | hdr.msg_iov = &iov; | 1024 | hdr.msg_iov = &iov; |
1011 | hdr.msg_iovlen = 1; | 1025 | hdr.msg_iovlen = 1; |
1012 | 1026 | ||
@@ -1514,18 +1528,19 @@ get_threshold(char *str, threshold *th) | |||
1514 | } | 1528 | } |
1515 | 1529 | ||
1516 | unsigned short | 1530 | unsigned short |
1517 | icmp_checksum(unsigned short *p, int n) | 1531 | icmp_checksum(uint16_t *p, size_t n) |
1518 | { | 1532 | { |
1519 | unsigned short cksum; | 1533 | unsigned short cksum; |
1520 | long sum = 0; | 1534 | long sum = 0; |
1521 | 1535 | ||
1522 | while(n > 2) { | 1536 | /* sizeof(uint16_t) == 2 */ |
1523 | sum += *p++; | 1537 | while(n >= 2) { |
1524 | n -= sizeof(unsigned short); | 1538 | sum += *(p++); |
1539 | n -= 2; | ||
1525 | } | 1540 | } |
1526 | 1541 | ||
1527 | /* mop up the occasional odd byte */ | 1542 | /* mop up the occasional odd byte */ |
1528 | if(n == 1) sum += (unsigned char)*p; | 1543 | if(n == 1) sum += *((uint8_t *)p -1); |
1529 | 1544 | ||
1530 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ | 1545 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
1531 | sum += (sum >> 16); /* add carry */ | 1546 | sum += (sum >> 16); /* add carry */ |
diff --git a/plugins-root/t/check_icmp.t b/plugins-root/t/check_icmp.t index e043d4ed..f6aa6813 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 | ||
14 | if ($allow_sudo eq "yes" or $> == 0) { | 14 | if ($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( | |||
83 | is( $res->return_code, 2, "One of two host nonresponsive - two required" ); | 83 | is( $res->return_code, 2, "One of two host nonresponsive - two required" ); |
84 | like( $res->output, $failureOutput, "Output OK" ); | 84 | like( $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 | ); | ||
89 | is( $res->return_code, 0, "IPv4 source_ip accepted" ); | ||
90 | like( $res->output, $successOutput, "Output OK" ); | ||
91 | |||
92 | $res = NPTest->testCmd( | ||
93 | "$sudo ./check_icmp -H $host_responsive -b 65507" | ||
94 | ); | ||
95 | is( $res->return_code, 0, "Try max paket size" ); | ||
96 | like( $res->output, $successOutput, "Output OK - Didn't overflow" ); | ||