diff options
| author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-05-06 00:01:42 +0200 |
|---|---|---|
| committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-05-06 00:01:42 +0200 |
| commit | 9ebde5eb09dbf4b869ffd6f501d007b9b264e1a9 (patch) | |
| tree | b6401848d5feabaa086602262c7fecf1f7c6cfbc | |
| parent | 5fd8191a50df6be712c9143ca6d73de7878f57d1 (diff) | |
| download | monitoring-plugins-9ebde5eb09dbf4b869ffd6f501d007b9b264e1a9.tar.gz | |
WIP - check_icmp refactor 4
| -rw-r--r-- | plugins-root/check_icmp.c | 220 |
1 files changed, 147 insertions, 73 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 9d163678..94f20eec 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c | |||
| @@ -149,20 +149,37 @@ static int wait_for_reply(int socket, time_t time_interval, unsigned short icmp_ | |||
| 149 | static ssize_t recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, | 149 | static ssize_t recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, |
| 150 | struct sockaddr * /*saddr*/, time_t *timeout, struct timeval * /*tv*/); | 150 | struct sockaddr * /*saddr*/, time_t *timeout, struct timeval * /*tv*/); |
| 151 | static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/, | 151 | static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/, |
| 152 | unsigned int *pkt_interval, unsigned int *target_interval, uint16_t sender_id, | 152 | unsigned int *pkt_interval, unsigned int *target_interval, |
| 153 | ping_target **table, unsigned short packets, | 153 | uint16_t sender_id, ping_target **table, unsigned short packets, |
| 154 | unsigned short number_of_targets, check_icmp_state *program_state); | 154 | unsigned short number_of_targets, check_icmp_state *program_state); |
| 155 | 155 | ||
| 156 | /* Sending data */ | 156 | /* Sending data */ |
| 157 | static int send_icmp_ping(int /*sock*/, ping_target * /*host*/, unsigned short icmp_pkt_size, | 157 | static int send_icmp_ping(int socket, ping_target *host, unsigned short icmp_pkt_size, |
| 158 | uint16_t sender_id, check_icmp_state *program_state); | 158 | uint16_t sender_id, check_icmp_state *program_state); |
| 159 | 159 | ||
| 160 | /* Threshold related */ | 160 | /* Threshold related */ |
| 161 | static int get_threshold(char *str, check_icmp_threshold *threshold); | 161 | typedef struct { |
| 162 | static bool get_threshold2(char *str, size_t length, check_icmp_threshold * /*warn*/, | 162 | int errorcode; |
| 163 | check_icmp_threshold * /*crit*/, threshold_mode mode); | 163 | check_icmp_threshold threshold; |
| 164 | static bool parse_threshold2_helper(char *threshold_string, size_t length, | 164 | } get_threshold_wrapper; |
| 165 | check_icmp_threshold *thr, threshold_mode mode); | 165 | static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold); |
| 166 | |||
| 167 | typedef struct { | ||
| 168 | int errorcode; | ||
| 169 | check_icmp_threshold warn; | ||
| 170 | check_icmp_threshold crit; | ||
| 171 | } get_threshold2_wrapper; | ||
| 172 | static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn, | ||
| 173 | check_icmp_threshold crit, threshold_mode mode); | ||
| 174 | |||
| 175 | typedef struct { | ||
| 176 | int errorcode; | ||
| 177 | check_icmp_threshold result; | ||
| 178 | } parse_threshold2_helper_wrapper; | ||
| 179 | static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_string, | ||
| 180 | size_t length, | ||
| 181 | check_icmp_threshold thr, | ||
| 182 | threshold_mode mode); | ||
| 166 | 183 | ||
| 167 | /* main test function */ | 184 | /* main test function */ |
| 168 | static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, | 185 | static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, |
| @@ -314,7 +331,6 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 314 | /* Reset argument scanning */ | 331 | /* Reset argument scanning */ |
| 315 | optind = 1; | 332 | optind = 1; |
| 316 | 333 | ||
| 317 | bool err; | ||
| 318 | /* parse the arguments */ | 334 | /* parse the arguments */ |
| 319 | for (int i = 1; i < argc; i++) { | 335 | for (int i = 1; i < argc; i++) { |
| 320 | long int arg; | 336 | long int arg; |
| @@ -341,12 +357,22 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 341 | case 'I': | 357 | case 'I': |
| 342 | result.config.target_interval = get_timevar(optarg); | 358 | result.config.target_interval = get_timevar(optarg); |
| 343 | break; | 359 | break; |
| 344 | case 'w': | 360 | case 'w': { |
| 345 | get_threshold(optarg, &result.config.warn); | 361 | get_threshold_wrapper warn = get_threshold(optarg, result.config.warn); |
| 346 | break; | 362 | if (warn.errorcode == OK) { |
| 347 | case 'c': | 363 | result.config.warn = warn.threshold; |
| 348 | get_threshold(optarg, &result.config.crit); | 364 | } else { |
| 349 | break; | 365 | crash("failed to parse warning threshold"); |
| 366 | } | ||
| 367 | } break; | ||
| 368 | case 'c': { | ||
| 369 | get_threshold_wrapper crit = get_threshold(optarg, result.config.crit); | ||
| 370 | if (crit.errorcode == OK) { | ||
| 371 | result.config.crit = crit.threshold; | ||
| 372 | } else { | ||
| 373 | crash("failed to parse critical threshold"); | ||
| 374 | } | ||
| 375 | } break; | ||
| 350 | case 'n': | 376 | case 'n': |
| 351 | case 'p': | 377 | case 'p': |
| 352 | result.config.number_of_packets = (unsigned short)strtoul(optarg, NULL, 0); | 378 | result.config.number_of_packets = (unsigned short)strtoul(optarg, NULL, 0); |
| @@ -387,51 +413,65 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 387 | print_help(); | 413 | print_help(); |
| 388 | exit(STATE_UNKNOWN); | 414 | exit(STATE_UNKNOWN); |
| 389 | break; | 415 | break; |
| 390 | case 'R': /* RTA mode */ | 416 | case 'R': /* RTA mode */ { |
| 391 | err = get_threshold2(optarg, strlen(optarg), &result.config.warn, | 417 | get_threshold2_wrapper rta_th = get_threshold2( |
| 392 | &result.config.crit, const_rta_mode); | 418 | optarg, strlen(optarg), result.config.warn, result.config.crit, const_rta_mode); |
| 393 | if (!err) { | 419 | |
| 420 | if (rta_th.errorcode != OK) { | ||
| 394 | crash("Failed to parse RTA threshold"); | 421 | crash("Failed to parse RTA threshold"); |
| 395 | } | 422 | } |
| 396 | 423 | ||
| 424 | result.config.warn = rta_th.warn; | ||
| 425 | result.config.crit = rta_th.crit; | ||
| 397 | result.config.rta_mode = true; | 426 | result.config.rta_mode = true; |
| 398 | break; | 427 | } break; |
| 399 | case 'P': /* packet loss mode */ | 428 | case 'P': /* packet loss mode */ { |
| 400 | err = get_threshold2(optarg, strlen(optarg), &result.config.warn, | 429 | get_threshold2_wrapper pl_th = |
| 401 | &result.config.crit, const_packet_loss_mode); | 430 | get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit, |
| 402 | if (!err) { | 431 | const_packet_loss_mode); |
| 432 | if (pl_th.errorcode != OK) { | ||
| 403 | crash("Failed to parse packet loss threshold"); | 433 | crash("Failed to parse packet loss threshold"); |
| 404 | } | 434 | } |
| 405 | 435 | ||
| 436 | result.config.warn = pl_th.warn; | ||
| 437 | result.config.crit = pl_th.crit; | ||
| 406 | result.config.pl_mode = true; | 438 | result.config.pl_mode = true; |
| 407 | break; | 439 | } break; |
| 408 | case 'J': /* jitter mode */ | 440 | case 'J': /* jitter mode */ { |
| 409 | err = get_threshold2(optarg, strlen(optarg), &result.config.warn, | 441 | get_threshold2_wrapper jitter_th = |
| 410 | &result.config.crit, const_jitter_mode); | 442 | get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit, |
| 411 | if (!err) { | 443 | const_jitter_mode); |
| 444 | if (jitter_th.errorcode != OK) { | ||
| 412 | crash("Failed to parse jitter threshold"); | 445 | crash("Failed to parse jitter threshold"); |
| 413 | } | 446 | } |
| 414 | 447 | ||
| 448 | result.config.warn = jitter_th.warn; | ||
| 449 | result.config.crit = jitter_th.crit; | ||
| 415 | result.config.jitter_mode = true; | 450 | result.config.jitter_mode = true; |
| 416 | break; | 451 | } break; |
| 417 | case 'M': /* MOS mode */ | 452 | case 'M': /* MOS mode */ { |
| 418 | err = get_threshold2(optarg, strlen(optarg), &result.config.warn, | 453 | get_threshold2_wrapper mos_th = get_threshold2( |
| 419 | &result.config.crit, const_mos_mode); | 454 | optarg, strlen(optarg), result.config.warn, result.config.crit, const_mos_mode); |
| 420 | if (!err) { | 455 | if (mos_th.errorcode != OK) { |
| 421 | crash("Failed to parse MOS threshold"); | 456 | crash("Failed to parse MOS threshold"); |
| 422 | } | 457 | } |
| 423 | 458 | ||
| 459 | result.config.warn = mos_th.warn; | ||
| 460 | result.config.crit = mos_th.crit; | ||
| 424 | result.config.mos_mode = true; | 461 | result.config.mos_mode = true; |
| 425 | break; | 462 | } break; |
| 426 | case 'S': /* score mode */ | 463 | case 'S': /* score mode */ { |
| 427 | err = get_threshold2(optarg, strlen(optarg), &result.config.warn, | 464 | get_threshold2_wrapper score_th = |
| 428 | &result.config.crit, const_score_mode); | 465 | get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit, |
| 429 | if (!err) { | 466 | const_score_mode); |
| 467 | if (score_th.errorcode != OK) { | ||
| 430 | crash("Failed to parse score threshold"); | 468 | crash("Failed to parse score threshold"); |
| 431 | } | 469 | } |
| 432 | 470 | ||
| 471 | result.config.warn = score_th.warn; | ||
| 472 | result.config.crit = score_th.crit; | ||
| 433 | result.config.score_mode = true; | 473 | result.config.score_mode = true; |
| 434 | break; | 474 | } break; |
| 435 | case 'O': /* out of order mode */ | 475 | case 'O': /* out of order mode */ |
| 436 | result.config.order_mode = true; | 476 | result.config.order_mode = true; |
| 437 | break; | 477 | break; |
| @@ -644,7 +684,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad | |||
| 644 | char address[INET6_ADDRSTRLEN]; | 684 | char address[INET6_ADDRSTRLEN]; |
| 645 | parse_address(addr, address, sizeof(address)); | 685 | parse_address(addr, address, sizeof(address)); |
| 646 | printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", | 686 | printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", |
| 647 | get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address, host->name); | 687 | get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address, |
| 688 | host->name); | ||
| 648 | } | 689 | } |
| 649 | 690 | ||
| 650 | program_state->icmp_lost++; | 691 | program_state->icmp_lost++; |
| @@ -1030,14 +1071,15 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i | |||
| 1030 | (ntohs(packet.icp->icmp_id) != sender_id || packet.icp->icmp_type != ICMP_ECHOREPLY || | 1071 | (ntohs(packet.icp->icmp_id) != sender_id || packet.icp->icmp_type != ICMP_ECHOREPLY || |
| 1031 | ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) || | 1072 | ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) || |
| 1032 | (address_family == PF_INET6 && | 1073 | (address_family == PF_INET6 && |
| 1033 | (ntohs(packet.icp6->icmp6_id) != sender_id || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || | 1074 | (ntohs(packet.icp6->icmp6_id) != sender_id || |
| 1075 | packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || | ||
| 1034 | ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) { | 1076 | ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) { |
| 1035 | if (debug > 2) { | 1077 | if (debug > 2) { |
| 1036 | printf("not a proper ICMP_ECHOREPLY\n"); | 1078 | printf("not a proper ICMP_ECHOREPLY\n"); |
| 1037 | } | 1079 | } |
| 1038 | 1080 | ||
| 1039 | handle_random_icmp(buf + hlen, &resp_addr, pkt_interval, target_interval, sender_id, table, | 1081 | handle_random_icmp(buf + hlen, &resp_addr, pkt_interval, target_interval, sender_id, |
| 1040 | packets, number_of_targets, program_state); | 1082 | table, packets, number_of_targets, program_state); |
| 1041 | 1083 | ||
| 1042 | continue; | 1084 | continue; |
| 1043 | } | 1085 | } |
| @@ -2029,9 +2071,15 @@ static unsigned int get_timevar(const char *str) { | |||
| 2029 | } | 2071 | } |
| 2030 | 2072 | ||
| 2031 | /* not too good at checking errors, but it'll do (main() should barfe on -1) */ | 2073 | /* not too good at checking errors, but it'll do (main() should barfe on -1) */ |
| 2032 | static int get_threshold(char *str, check_icmp_threshold *threshold) { | 2074 | static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold) { |
| 2033 | if (!str || !strlen(str) || !threshold) { | 2075 | get_threshold_wrapper result = { |
| 2034 | return -1; | 2076 | .errorcode = OK, |
| 2077 | .threshold = threshold, | ||
| 2078 | }; | ||
| 2079 | |||
| 2080 | if (!str || !strlen(str)) { | ||
| 2081 | result.errorcode = ERROR; | ||
| 2082 | return result; | ||
| 2035 | } | 2083 | } |
| 2036 | 2084 | ||
| 2037 | /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */ | 2085 | /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */ |
| @@ -2042,26 +2090,27 @@ static int get_threshold(char *str, check_icmp_threshold *threshold) { | |||
| 2042 | *tmp = '\0'; | 2090 | *tmp = '\0'; |
| 2043 | } else if (*tmp == ',' && is_at_last_char) { | 2091 | } else if (*tmp == ',' && is_at_last_char) { |
| 2044 | *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */ | 2092 | *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */ |
| 2045 | threshold->pl = (unsigned char)strtoul(tmp + 1, NULL, 0); | 2093 | result.threshold.pl = (unsigned char)strtoul(tmp + 1, NULL, 0); |
| 2046 | break; | 2094 | break; |
| 2047 | } | 2095 | } |
| 2048 | is_at_last_char = true; | 2096 | is_at_last_char = true; |
| 2049 | tmp--; | 2097 | tmp--; |
| 2050 | } | 2098 | } |
| 2051 | threshold->rta = get_timevar(str); | 2099 | result.threshold.rta = get_timevar(str); |
| 2052 | 2100 | ||
| 2053 | if (!threshold->rta) { | 2101 | if (!result.threshold.rta) { |
| 2054 | return -1; | 2102 | result.errorcode = ERROR; |
| 2103 | return result; | ||
| 2055 | } | 2104 | } |
| 2056 | 2105 | ||
| 2057 | if (threshold->rta > MAXTTL * 1000000) { | 2106 | if (result.threshold.rta > MAXTTL * 1000000) { |
| 2058 | threshold->rta = MAXTTL * 1000000; | 2107 | result.threshold.rta = MAXTTL * 1000000; |
| 2059 | } | 2108 | } |
| 2060 | if (threshold->pl > 100) { | 2109 | if (result.threshold.pl > 100) { |
| 2061 | threshold->pl = 100; | 2110 | result.threshold.pl = 100; |
| 2062 | } | 2111 | } |
| 2063 | 2112 | ||
| 2064 | return 0; | 2113 | return result; |
| 2065 | } | 2114 | } |
| 2066 | 2115 | ||
| 2067 | /* | 2116 | /* |
| @@ -2075,10 +2124,17 @@ static int get_threshold(char *str, check_icmp_threshold *threshold) { | |||
| 2075 | * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score | 2124 | * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score |
| 2076 | * (exclusively) | 2125 | * (exclusively) |
| 2077 | */ | 2126 | */ |
| 2078 | static bool get_threshold2(char *str, size_t length, check_icmp_threshold *warn, | 2127 | static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn, |
| 2079 | check_icmp_threshold *crit, threshold_mode mode) { | 2128 | check_icmp_threshold crit, threshold_mode mode) { |
| 2080 | if (!str || !length || !warn || !crit) { | 2129 | get_threshold2_wrapper result = { |
| 2081 | return false; | 2130 | .errorcode = OK, |
| 2131 | .warn = warn, | ||
| 2132 | .crit = crit, | ||
| 2133 | }; | ||
| 2134 | |||
| 2135 | if (!str || !length) { | ||
| 2136 | result.errorcode = ERROR; | ||
| 2137 | return result; | ||
| 2082 | } | 2138 | } |
| 2083 | 2139 | ||
| 2084 | // p points to the last char in str | 2140 | // p points to the last char in str |
| @@ -2095,50 +2151,68 @@ static bool get_threshold2(char *str, size_t length, check_icmp_threshold *warn, | |||
| 2095 | 2151 | ||
| 2096 | char *start_of_value = work_pointer + 1; | 2152 | char *start_of_value = work_pointer + 1; |
| 2097 | 2153 | ||
| 2098 | if (!parse_threshold2_helper(start_of_value, strlen(start_of_value), crit, mode)) { | 2154 | parse_threshold2_helper_wrapper tmp = |
| 2099 | return false; | 2155 | parse_threshold2_helper(start_of_value, strlen(start_of_value), result.crit, mode); |
| 2156 | if (tmp.errorcode != OK) { | ||
| 2157 | result.errorcode = ERROR; | ||
| 2158 | return result; | ||
| 2100 | } | 2159 | } |
| 2160 | result.crit = tmp.result; | ||
| 2101 | } | 2161 | } |
| 2102 | first_iteration = false; | 2162 | first_iteration = false; |
| 2103 | work_pointer--; | 2163 | work_pointer--; |
| 2104 | } | 2164 | } |
| 2105 | 2165 | ||
| 2106 | return parse_threshold2_helper(work_pointer, strlen(work_pointer), warn, mode); | 2166 | parse_threshold2_helper_wrapper tmp = |
| 2167 | parse_threshold2_helper(work_pointer, strlen(work_pointer), result.warn, mode); | ||
| 2168 | if (tmp.errorcode != OK) { | ||
| 2169 | result.errorcode = ERROR; | ||
| 2170 | } else { | ||
| 2171 | result.warn = tmp.result; | ||
| 2172 | } | ||
| 2173 | return result; | ||
| 2107 | } | 2174 | } |
| 2108 | 2175 | ||
| 2109 | static bool parse_threshold2_helper(char *threshold_string, size_t length, | 2176 | static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_string, |
| 2110 | check_icmp_threshold *thr, threshold_mode mode) { | 2177 | size_t length, |
| 2178 | check_icmp_threshold thr, | ||
| 2179 | threshold_mode mode) { | ||
| 2111 | char *resultChecker = {0}; | 2180 | char *resultChecker = {0}; |
| 2181 | parse_threshold2_helper_wrapper result = { | ||
| 2182 | .result = thr, | ||
| 2183 | .errorcode = OK, | ||
| 2184 | }; | ||
| 2112 | 2185 | ||
| 2113 | switch (mode) { | 2186 | switch (mode) { |
| 2114 | case const_rta_mode: | 2187 | case const_rta_mode: |
| 2115 | thr->rta = (unsigned int)(strtod(threshold_string, &resultChecker) * 1000); | 2188 | result.result.rta = (unsigned int)(strtod(threshold_string, &resultChecker) * 1000); |
| 2116 | break; | 2189 | break; |
| 2117 | case const_packet_loss_mode: | 2190 | case const_packet_loss_mode: |
| 2118 | thr->pl = (unsigned char)strtoul(threshold_string, &resultChecker, 0); | 2191 | result.result.pl = (unsigned char)strtoul(threshold_string, &resultChecker, 0); |
| 2119 | break; | 2192 | break; |
| 2120 | case const_jitter_mode: | 2193 | case const_jitter_mode: |
| 2121 | thr->jitter = strtod(threshold_string, &resultChecker); | 2194 | result.result.jitter = strtod(threshold_string, &resultChecker); |
| 2122 | break; | 2195 | break; |
| 2123 | case const_mos_mode: | 2196 | case const_mos_mode: |
| 2124 | thr->mos = strtod(threshold_string, &resultChecker); | 2197 | result.result.mos = strtod(threshold_string, &resultChecker); |
| 2125 | break; | 2198 | break; |
| 2126 | case const_score_mode: | 2199 | case const_score_mode: |
| 2127 | thr->score = strtod(threshold_string, &resultChecker); | 2200 | result.result.score = strtod(threshold_string, &resultChecker); |
| 2128 | break; | 2201 | break; |
| 2129 | } | 2202 | } |
| 2130 | 2203 | ||
| 2131 | if (resultChecker == threshold_string) { | 2204 | if (resultChecker == threshold_string) { |
| 2132 | // Failed to parse | 2205 | // Failed to parse |
| 2133 | return false; | 2206 | result.errorcode = ERROR; |
| 2207 | return result; | ||
| 2134 | } | 2208 | } |
| 2135 | 2209 | ||
| 2136 | if (resultChecker != (threshold_string + length)) { | 2210 | if (resultChecker != (threshold_string + length)) { |
| 2137 | // Trailing symbols | 2211 | // Trailing symbols |
| 2138 | return false; | 2212 | result.errorcode = ERROR; |
| 2139 | } | 2213 | } |
| 2140 | 2214 | ||
| 2141 | return true; | 2215 | return result; |
| 2142 | } | 2216 | } |
| 2143 | 2217 | ||
| 2144 | unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) { | 2218 | unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) { |
