diff options
| author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-06-17 15:19:30 +0200 |
|---|---|---|
| committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-06-17 15:19:30 +0200 |
| commit | f680cd7b88aef2ff4ef8c4d336ee14269bea65bc (patch) | |
| tree | 561d8b4da6624ce1e36be4d9a577b38685fefd9e | |
| parent | 0f8690c19b352549961c46c75c7307814e255db0 (diff) | |
| download | monitoring-plugins-f680cd7b88aef2ff4ef8c4d336ee14269bea65bc.tar.gz | |
Improve error detection for threshold parsers
| -rw-r--r-- | plugins-root/check_icmp.c | 98 | ||||
| -rw-r--r-- | plugins-root/check_icmp.d/config.h | 2 |
2 files changed, 65 insertions, 35 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index a57edef4..dad03ffa 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c | |||
| @@ -138,7 +138,11 @@ void print_help(); | |||
| 138 | void print_usage(void); | 138 | void print_usage(void); |
| 139 | 139 | ||
| 140 | /* Time related */ | 140 | /* Time related */ |
| 141 | static unsigned int get_timevar(const char *str); | 141 | typedef struct { |
| 142 | int error_code; | ||
| 143 | time_t time_range; | ||
| 144 | } get_timevar_wrapper; | ||
| 145 | static get_timevar_wrapper get_timevar(const char *str); | ||
| 142 | static time_t get_timevaldiff(struct timeval earlier, struct timeval later); | 146 | static time_t get_timevaldiff(struct timeval earlier, struct timeval later); |
| 143 | static time_t get_timevaldiff_to_now(struct timeval earlier); | 147 | static time_t get_timevaldiff_to_now(struct timeval earlier); |
| 144 | 148 | ||
| @@ -196,8 +200,8 @@ static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_s | |||
| 196 | /* main test function */ | 200 | /* main test function */ |
| 197 | static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, | 201 | static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, |
| 198 | uint16_t sender_id, check_icmp_execution_mode mode, | 202 | uint16_t sender_id, check_icmp_execution_mode mode, |
| 199 | unsigned int max_completion_time, struct timeval prog_start, | 203 | time_t max_completion_time, struct timeval prog_start, ping_target **table, |
| 200 | ping_target **table, unsigned short packets, check_icmp_socket_set sockset, | 204 | unsigned short packets, check_icmp_socket_set sockset, |
| 201 | unsigned short number_of_targets, check_icmp_state *program_state); | 205 | unsigned short number_of_targets, check_icmp_state *program_state); |
| 202 | mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, | 206 | mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, |
| 203 | check_icmp_threshold warn, check_icmp_threshold crit); | 207 | check_icmp_threshold warn, check_icmp_threshold crit); |
| @@ -249,7 +253,7 @@ static void finish(int sign, check_icmp_mode_switches modes, int min_hosts_alive | |||
| 249 | mp_check overall[static 1]); | 253 | mp_check overall[static 1]); |
| 250 | 254 | ||
| 251 | /* Error exit */ | 255 | /* Error exit */ |
| 252 | static void crash(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); | 256 | static void crash(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
| 253 | 257 | ||
| 254 | /** global variables **/ | 258 | /** global variables **/ |
| 255 | static int debug = 0; | 259 | static int debug = 0; |
| @@ -384,12 +388,24 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 384 | MAX_PING_DATA - 1); | 388 | MAX_PING_DATA - 1); |
| 385 | } | 389 | } |
| 386 | } break; | 390 | } break; |
| 387 | case 'i': | 391 | case 'i': { |
| 388 | result.config.pkt_interval = get_timevar(optarg); | 392 | get_timevar_wrapper parsed_time = get_timevar(optarg); |
| 389 | break; | 393 | |
| 390 | case 'I': | 394 | if (parsed_time.error_code == OK) { |
| 391 | result.config.target_interval = get_timevar(optarg); | 395 | result.config.pkt_interval = parsed_time.time_range; |
| 392 | break; | 396 | } else { |
| 397 | crash("failed to parse packet interval"); | ||
| 398 | } | ||
| 399 | } break; | ||
| 400 | case 'I': { | ||
| 401 | get_timevar_wrapper parsed_time = get_timevar(optarg); | ||
| 402 | |||
| 403 | if (parsed_time.error_code == OK) { | ||
| 404 | result.config.target_interval = parsed_time.time_range; | ||
| 405 | } else { | ||
| 406 | crash("failed to parse target interval"); | ||
| 407 | } | ||
| 408 | } break; | ||
| 393 | case 'w': { | 409 | case 'w': { |
| 394 | get_threshold_wrapper warn = get_threshold(optarg, result.config.warn); | 410 | get_threshold_wrapper warn = get_threshold(optarg, result.config.warn); |
| 395 | if (warn.errorcode == OK) { | 411 | if (warn.errorcode == OK) { |
| @@ -575,7 +591,7 @@ static void crash(const char *fmt, ...) { | |||
| 575 | puts(""); | 591 | puts(""); |
| 576 | 592 | ||
| 577 | exit(3); | 593 | exit(3); |
| 578 | } | 594 | } |
| 579 | 595 | ||
| 580 | static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code) { | 596 | static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code) { |
| 581 | const char *msg = "unreachable"; | 597 | const char *msg = "unreachable"; |
| @@ -743,8 +759,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad | |||
| 743 | /* source quench means we're sending too fast, so increase the | 759 | /* source quench means we're sending too fast, so increase the |
| 744 | * interval and mark this packet lost */ | 760 | * interval and mark this packet lost */ |
| 745 | if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) { | 761 | if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) { |
| 746 | *pkt_interval = (unsigned int)(*pkt_interval * PACKET_BACKOFF_FACTOR); | 762 | *pkt_interval = (unsigned int)((double)*pkt_interval * PACKET_BACKOFF_FACTOR); |
| 747 | *target_interval = (unsigned int)(*target_interval * TARGET_BACKOFF_FACTOR); | 763 | *target_interval = (unsigned int)((double)*target_interval * TARGET_BACKOFF_FACTOR); |
| 748 | } else { | 764 | } else { |
| 749 | program_state->targets_down++; | 765 | program_state->targets_down++; |
| 750 | host->flags |= FLAG_LOST_CAUSE; | 766 | host->flags |= FLAG_LOST_CAUSE; |
| @@ -899,7 +915,7 @@ int main(int argc, char **argv) { | |||
| 899 | gettimeofday(&prog_start, NULL); | 915 | gettimeofday(&prog_start, NULL); |
| 900 | 916 | ||
| 901 | time_t max_completion_time = | 917 | time_t max_completion_time = |
| 902 | ((config.pkt_interval *config.number_of_targets * config.number_of_packets) + | 918 | ((config.pkt_interval * config.number_of_targets * config.number_of_packets) + |
| 903 | (config.target_interval * config.number_of_targets)) + | 919 | (config.target_interval * config.number_of_targets)) + |
| 904 | (config.number_of_targets * config.number_of_packets * config.crit.rta) + config.crit.rta; | 920 | (config.number_of_targets * config.number_of_packets * config.crit.rta) + config.crit.rta; |
| 905 | 921 | ||
| @@ -921,7 +937,7 @@ int main(int argc, char **argv) { | |||
| 921 | } | 937 | } |
| 922 | 938 | ||
| 923 | if (debug) { | 939 | if (debug) { |
| 924 | printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", config.crit.rta, config.crit.pl, | 940 | printf("crit = {%ld, %u%%}, warn = {%ld, %u%%}\n", config.crit.rta, config.crit.pl, |
| 925 | config.warn.rta, config.warn.pl); | 941 | config.warn.rta, config.warn.pl); |
| 926 | printf("pkt_interval: %ld target_interval: %ld\n", config.pkt_interval, | 942 | printf("pkt_interval: %ld target_interval: %ld\n", config.pkt_interval, |
| 927 | config.target_interval); | 943 | config.target_interval); |
| @@ -976,7 +992,7 @@ int main(int argc, char **argv) { | |||
| 976 | 992 | ||
| 977 | static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, | 993 | static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, |
| 978 | const uint16_t sender_id, const check_icmp_execution_mode mode, | 994 | const uint16_t sender_id, const check_icmp_execution_mode mode, |
| 979 | const unsigned int max_completion_time, const struct timeval prog_start, | 995 | const time_t max_completion_time, const struct timeval prog_start, |
| 980 | ping_target **table, const unsigned short packets, | 996 | ping_target **table, const unsigned short packets, |
| 981 | const check_icmp_socket_set sockset, const unsigned short number_of_targets, | 997 | const check_icmp_socket_set sockset, const unsigned short number_of_targets, |
| 982 | check_icmp_state *program_state) { | 998 | check_icmp_state *program_state) { |
| @@ -1028,7 +1044,7 @@ static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_ | |||
| 1028 | time_t final_wait = max_completion_time - time_passed; | 1044 | time_t final_wait = max_completion_time - time_passed; |
| 1029 | 1045 | ||
| 1030 | if (debug) { | 1046 | if (debug) { |
| 1031 | printf("time_passed: %ld final_wait: %ld max_completion_time: %u\n", time_passed, | 1047 | printf("time_passed: %ld final_wait: %ld max_completion_time: %ld\n", time_passed, |
| 1032 | final_wait, max_completion_time); | 1048 | final_wait, max_completion_time); |
| 1033 | } | 1049 | } |
| 1034 | if (time_passed > max_completion_time) { | 1050 | if (time_passed > max_completion_time) { |
| @@ -1138,7 +1154,6 @@ static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_inter | |||
| 1138 | parse_address(&resp_addr, address, sizeof(address)); | 1154 | parse_address(&resp_addr, address, sizeof(address)); |
| 1139 | crash("received packet too short for ICMP (%ld bytes, expected %d) from %s\n", | 1155 | crash("received packet too short for ICMP (%ld bytes, expected %d) from %s\n", |
| 1140 | recv_foo.received, hlen + icmp_pkt_size, address); | 1156 | recv_foo.received, hlen + icmp_pkt_size, address); |
| 1141 | |||
| 1142 | } | 1157 | } |
| 1143 | /* check the response */ | 1158 | /* check the response */ |
| 1144 | memcpy(packet.buf, buf + hlen, icmp_pkt_size); | 1159 | memcpy(packet.buf, buf + hlen, icmp_pkt_size); |
| @@ -1272,7 +1287,7 @@ static int send_icmp_ping(const check_icmp_socket_set sockset, ping_target *host | |||
| 1272 | data.ping_id = 10; /* host->icmp.icmp_sent; */ | 1287 | data.ping_id = 10; /* host->icmp.icmp_sent; */ |
| 1273 | memcpy(&data.stime, ¤t_time, sizeof(current_time)); | 1288 | memcpy(&data.stime, ¤t_time, sizeof(current_time)); |
| 1274 | 1289 | ||
| 1275 | socklen_t addrlen; | 1290 | socklen_t addrlen = 0; |
| 1276 | 1291 | ||
| 1277 | if (host->address.ss_family == AF_INET) { | 1292 | if (host->address.ss_family == AF_INET) { |
| 1278 | struct icmp *icp = (struct icmp *)buf; | 1293 | struct icmp *icp = (struct icmp *)buf; |
| @@ -1789,14 +1804,21 @@ static in_addr_t get_ip_address(const char *ifname) { | |||
| 1789 | * s = seconds | 1804 | * s = seconds |
| 1790 | * return value is in microseconds | 1805 | * return value is in microseconds |
| 1791 | */ | 1806 | */ |
| 1792 | static unsigned int get_timevar(const char *str) { | 1807 | static get_timevar_wrapper get_timevar(const char *str) { |
| 1808 | get_timevar_wrapper result = { | ||
| 1809 | .error_code = OK, | ||
| 1810 | .time_range = 0, | ||
| 1811 | }; | ||
| 1812 | |||
| 1793 | if (!str) { | 1813 | if (!str) { |
| 1794 | return 0; | 1814 | result.error_code = ERROR; |
| 1815 | return result; | ||
| 1795 | } | 1816 | } |
| 1796 | 1817 | ||
| 1797 | size_t len = strlen(str); | 1818 | size_t len = strlen(str); |
| 1798 | if (!len) { | 1819 | if (!len) { |
| 1799 | return 0; | 1820 | result.error_code = ERROR; |
| 1821 | return result; | ||
| 1800 | } | 1822 | } |
| 1801 | 1823 | ||
| 1802 | /* unit might be given as ms|m (millisec), | 1824 | /* unit might be given as ms|m (millisec), |
| @@ -1834,12 +1856,14 @@ static unsigned int get_timevar(const char *str) { | |||
| 1834 | unsigned long pre_radix; | 1856 | unsigned long pre_radix; |
| 1835 | pre_radix = strtoul(str, &ptr, 0); | 1857 | pre_radix = strtoul(str, &ptr, 0); |
| 1836 | if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) { | 1858 | if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) { |
| 1837 | return (unsigned int)(pre_radix * factor); | 1859 | result.time_range = (unsigned int)(pre_radix * factor); |
| 1860 | return result; | ||
| 1838 | } | 1861 | } |
| 1839 | 1862 | ||
| 1840 | /* time specified in usecs can't have decimal points, so ignore them */ | 1863 | /* time specified in usecs can't have decimal points, so ignore them */ |
| 1841 | if (factor == 1) { | 1864 | if (factor == 1) { |
| 1842 | return (unsigned int)pre_radix; | 1865 | result.time_range = (unsigned int)pre_radix; |
| 1866 | return result; | ||
| 1843 | } | 1867 | } |
| 1844 | 1868 | ||
| 1845 | /* integer and decimal, respectively */ | 1869 | /* integer and decimal, respectively */ |
| @@ -1851,10 +1875,10 @@ static unsigned int get_timevar(const char *str) { | |||
| 1851 | } | 1875 | } |
| 1852 | 1876 | ||
| 1853 | /* the last parenthesis avoids floating point exceptions. */ | 1877 | /* the last parenthesis avoids floating point exceptions. */ |
| 1854 | return (unsigned int)((pre_radix * factor) + (post_radix * (factor / 10))); | 1878 | result.time_range = (unsigned int)((pre_radix * factor) + (post_radix * (factor / 10))); |
| 1879 | return result; | ||
| 1855 | } | 1880 | } |
| 1856 | 1881 | ||
| 1857 | /* not too good at checking errors, but it'll do (main() should barfe on -1) */ | ||
| 1858 | static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold) { | 1882 | static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold) { |
| 1859 | get_threshold_wrapper result = { | 1883 | get_threshold_wrapper result = { |
| 1860 | .errorcode = OK, | 1884 | .errorcode = OK, |
| @@ -1880,9 +1904,15 @@ static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold thres | |||
| 1880 | is_at_last_char = true; | 1904 | is_at_last_char = true; |
| 1881 | tmp--; | 1905 | tmp--; |
| 1882 | } | 1906 | } |
| 1883 | result.threshold.rta = get_timevar(str); | ||
| 1884 | 1907 | ||
| 1885 | if (!result.threshold.rta) { | 1908 | get_timevar_wrapper parsed_time = get_timevar(str); |
| 1909 | |||
| 1910 | if (parsed_time.error_code == OK) { | ||
| 1911 | result.threshold.rta = parsed_time.time_range; | ||
| 1912 | } else { | ||
| 1913 | if (debug > 1) { | ||
| 1914 | printf("%s: failed to parse rta threshold\n", __FUNCTION__); | ||
| 1915 | } | ||
| 1886 | result.errorcode = ERROR; | 1916 | result.errorcode = ERROR; |
| 1887 | return result; | 1917 | return result; |
| 1888 | } | 1918 | } |
| @@ -2170,7 +2200,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, | |||
| 2170 | xasprintf(&result.output, "%s", address); | 2200 | xasprintf(&result.output, "%s", address); |
| 2171 | 2201 | ||
| 2172 | double packet_loss; | 2202 | double packet_loss; |
| 2173 | double rta; | 2203 | time_t rta; |
| 2174 | if (!target.icmp_recv) { | 2204 | if (!target.icmp_recv) { |
| 2175 | /* rta 0 is of course not entirely correct, but will still show up | 2205 | /* rta 0 is of course not entirely correct, but will still show up |
| 2176 | * conspicuously as missing entries in perfparse and cacti */ | 2206 | * conspicuously as missing entries in perfparse and cacti */ |
| @@ -2188,7 +2218,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, | |||
| 2188 | } else { | 2218 | } else { |
| 2189 | packet_loss = | 2219 | packet_loss = |
| 2190 | (unsigned char)((target.icmp_sent - target.icmp_recv) * 100) / target.icmp_sent; | 2220 | (unsigned char)((target.icmp_sent - target.icmp_recv) * 100) / target.icmp_sent; |
| 2191 | rta = (double)target.time_waited / target.icmp_recv; | 2221 | rta = target.time_waited / target.icmp_recv; |
| 2192 | } | 2222 | } |
| 2193 | 2223 | ||
| 2194 | double EffectiveLatency; | 2224 | double EffectiveLatency; |
| @@ -2219,7 +2249,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, | |||
| 2219 | * round trip jitter, but double the impact to latency | 2249 | * round trip jitter, but double the impact to latency |
| 2220 | * then add 10 for protocol latencies (in milliseconds). | 2250 | * then add 10 for protocol latencies (in milliseconds). |
| 2221 | */ | 2251 | */ |
| 2222 | EffectiveLatency = (rta / 1000) + target.jitter * 2 + 10; | 2252 | EffectiveLatency = ((double)rta / 1000) + target.jitter * 2 + 10; |
| 2223 | 2253 | ||
| 2224 | double R; | 2254 | double R; |
| 2225 | if (EffectiveLatency < 160) { | 2255 | if (EffectiveLatency < 160) { |
| @@ -2249,14 +2279,14 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, | |||
| 2249 | if (modes.rta_mode) { | 2279 | if (modes.rta_mode) { |
| 2250 | mp_subcheck sc_rta = mp_subcheck_init(); | 2280 | mp_subcheck sc_rta = mp_subcheck_init(); |
| 2251 | sc_rta = mp_set_subcheck_default_state(sc_rta, STATE_OK); | 2281 | sc_rta = mp_set_subcheck_default_state(sc_rta, STATE_OK); |
| 2252 | xasprintf(&sc_rta.output, "rta %0.3fms", rta / 1000); | 2282 | xasprintf(&sc_rta.output, "rta %0.3fms", (double)rta / 1000); |
| 2253 | 2283 | ||
| 2254 | if (rta >= crit.rta) { | 2284 | if (rta >= crit.rta) { |
| 2255 | sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL); | 2285 | sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL); |
| 2256 | xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, (double) crit.rta / 1000); | 2286 | xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, (double)crit.rta / 1000); |
| 2257 | } else if (rta >= warn.rta) { | 2287 | } else if (rta >= warn.rta) { |
| 2258 | sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING); | 2288 | sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING); |
| 2259 | xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, (double) warn.rta / 1000); | 2289 | xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, (double)warn.rta / 1000); |
| 2260 | } | 2290 | } |
| 2261 | 2291 | ||
| 2262 | if (packet_loss < 100) { | 2292 | if (packet_loss < 100) { |
diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h index 97be7fc1..fc9dd5a6 100644 --- a/plugins-root/check_icmp.d/config.h +++ b/plugins-root/check_icmp.d/config.h | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | /* threshold structure. all values are maximum allowed, exclusive */ | 16 | /* threshold structure. all values are maximum allowed, exclusive */ |
| 17 | typedef struct { | 17 | typedef struct { |
| 18 | unsigned char pl; /* max allowed packet loss in percent */ | 18 | unsigned char pl; /* max allowed packet loss in percent */ |
| 19 | unsigned int rta; /* roundtrip time average, microseconds */ | 19 | time_t rta; /* roundtrip time average, microseconds */ |
| 20 | double jitter; /* jitter time average, microseconds */ | 20 | double jitter; /* jitter time average, microseconds */ |
| 21 | double mos; /* MOS */ | 21 | double mos; /* MOS */ |
| 22 | double score; /* Score */ | 22 | double score; /* Score */ |
