summaryrefslogtreecommitdiffstats
path: root/plugins-root/check_icmp.c
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-05-06 00:01:42 +0200
committerLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-05-06 00:01:42 +0200
commit9ebde5eb09dbf4b869ffd6f501d007b9b264e1a9 (patch)
treeb6401848d5feabaa086602262c7fecf1f7c6cfbc /plugins-root/check_icmp.c
parent5fd8191a50df6be712c9143ca6d73de7878f57d1 (diff)
downloadmonitoring-plugins-9ebde5eb09dbf4b869ffd6f501d007b9b264e1a9.tar.gz
WIP - check_icmp refactor 4
Diffstat (limited to 'plugins-root/check_icmp.c')
-rw-r--r--plugins-root/check_icmp.c220
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_
149static ssize_t recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, 149static 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*/);
151static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/, 151static 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 */
157static int send_icmp_ping(int /*sock*/, ping_target * /*host*/, unsigned short icmp_pkt_size, 157static 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 */
161static int get_threshold(char *str, check_icmp_threshold *threshold); 161typedef struct {
162static 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;
164static bool parse_threshold2_helper(char *threshold_string, size_t length, 164} get_threshold_wrapper;
165 check_icmp_threshold *thr, threshold_mode mode); 165static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold);
166
167typedef struct {
168 int errorcode;
169 check_icmp_threshold warn;
170 check_icmp_threshold crit;
171} get_threshold2_wrapper;
172static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn,
173 check_icmp_threshold crit, threshold_mode mode);
174
175typedef struct {
176 int errorcode;
177 check_icmp_threshold result;
178} parse_threshold2_helper_wrapper;
179static 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 */
168static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, 185static 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) */
2032static int get_threshold(char *str, check_icmp_threshold *threshold) { 2074static 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 */
2078static bool get_threshold2(char *str, size_t length, check_icmp_threshold *warn, 2127static 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
2109static bool parse_threshold2_helper(char *threshold_string, size_t length, 2176static 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
2144unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) { 2218unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) {