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" ); | ||
