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 /plugins-root/check_icmp.c | |
parent | 5fd8191a50df6be712c9143ca6d73de7878f57d1 (diff) | |
download | monitoring-plugins-9ebde5eb09dbf4b869ffd6f501d007b9b264e1a9.tar.gz |
WIP - check_icmp refactor 4
Diffstat (limited to 'plugins-root/check_icmp.c')
-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) { |