From eafee9c3f91879afa82749fa1d8cd2b0b53a5d5c Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 28 Apr 2025 22:01:01 +0200 Subject: WIP: check_icmp refactor --- plugins-root/check_icmp.d/check_icmp_helpers.c | 142 +++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 plugins-root/check_icmp.d/check_icmp_helpers.c (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c new file mode 100644 index 00000000..8f6d7362 --- /dev/null +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -0,0 +1,142 @@ +#include "./config.h" +#include "states.h" +#include +#include +#include "./check_icmp_helpers.h" +#include "../../plugins/netutils.h" + +check_icmp_config check_icmp_config_init() { + check_icmp_config tmp = { + .source_ip = NULL, + + .order_mode = false, + .mos_mode = false, + .rta_mode = false, + .pl_mode = false, + .jitter_mode = false, + .score_mode = false, + + .min_hosts_alive = -1, + .icmp_data_size = DEFAULT_PING_DATA_SIZE, + .icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN, + .pkt_interval = DEFAULT_PKT_INTERVAL, + .target_interval = 0, + .crit = {.pl = DEFAULT_CRIT_PL, + .rta = DEFAULT_CRIT_RTA, + .jitter = 50.0, + .mos = 3.0, + .score = 70.0}, + .warn = {.pl = DEFAULT_WARN_PL, + .rta = DEFAULT_WARN_RTA, + .jitter = 40.0, + .mos = 3.5, + .score = 80.0}, + .pid = {}, + .mode = MODE_RTA, + .timeout = DEFAULT_TIMEOUT, + .ttl = DEFAULT_TTL, + + .packets = DEFAULT_NUMBER_OF_PACKETS, + .number_of_targets = 0, + .hosts = NULL, + }; + return tmp; +} + +ping_target ping_target_init() { + ping_target tmp = { + .rtmin = INFINITY, + + .jitter_min = INFINITY, + + .rta_status = STATE_OK, + .jitter_status = STATE_OK, + .mos_status = STATE_OK, + .score_status = STATE_OK, + .pl_status = STATE_OK, + .order_status = STATE_OK, + }; + + return tmp; +} + +check_icmp_state check_icmp_state_init() { + check_icmp_state tmp = {.icmp_sent = 0, .icmp_lost = 0, .icmp_recv = 0, .targets_down = 0}; + + return tmp; +} + +rta_host_create_wrapper rta_host_create(char *name, struct sockaddr_storage *address) { + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + if (address_family == AF_INET) { + sin = (struct sockaddr_in *)address; + } else { + sin6 = (struct sockaddr_in6 *)address; + } + + rta_host_create_wrapper result = { + .errorcode = OK, + }; + + /* disregard obviously stupid addresses + * (I didn't find an ipv6 equivalent to INADDR_NONE) */ + if (((address_family == AF_INET && + (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) || + (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { + result.errorcode = ERROR; + return result; + } + + // TODO: Maybe add the following back in as a sanity check for the config + // /* no point in adding two identical IP's, so don't. ;) */ + // struct sockaddr_in *host_sin; + // struct sockaddr_in6 *host_sin6; + // struct rta_host *host = host_list; + + // while (host) { + // host_sin = (struct sockaddr_in *)&host->saddr_in; + // host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; + + // if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) || + // (address_family == AF_INET6 && + // host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) { + // if (debug) { + // printf("Identical IP already exists. Not adding %s\n", name); + // } + // return -1; + // } + // host = host->next; + // } + + /* add the fresh ip */ + ping_target host = ping_target_init(); + + /* set the values. use calling name for output */ + host.name = strdup(name); + + /* fill out the sockaddr_storage struct */ + if (address_family == AF_INET) { + struct sockaddr_in *host_sin = (struct sockaddr_in *)&host.saddr_in; + host_sin->sin_family = AF_INET; + host_sin->sin_addr.s_addr = sin->sin_addr.s_addr; + } else { + struct sockaddr_in6 *host_sin6 = (struct sockaddr_in6 *)&host.saddr_in; + host_sin6->sin6_family = AF_INET6; + memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, + sizeof host_sin6->sin6_addr.s6_addr); + } + + result.host = host; + + return result; +} + +check_icmp_target_container check_icmp_target_container_init() { + check_icmp_target_container tmp = { + .name = NULL, + .number_of_targets = 0, + .target_list = NULL, + }; + return tmp; +} -- cgit v1.2.3-74-g34f1 From 5a6adcb7db497fba7b89471a6d58dba80330ff4a Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 4 May 2025 01:42:52 +0200 Subject: WIP - check_icmp refactor 2 --- plugins-root/check_icmp.c | 724 +++++++++++++------------ plugins-root/check_icmp.d/check_icmp_helpers.c | 48 +- plugins-root/check_icmp.d/check_icmp_helpers.h | 7 +- plugins-root/check_icmp.d/config.h | 102 ++++ 4 files changed, 540 insertions(+), 341 deletions(-) create mode 100644 plugins-root/check_icmp.d/config.h (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 87dac21d..99414014 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -66,6 +66,9 @@ const char *email = "devel@monitoring-plugins.org"; #include #include #include +#include +#include +#include #include "../lib/states.h" #include "./check_icmp.d/config.h" @@ -131,76 +134,79 @@ void print_usage(void); /* Time related */ static unsigned int get_timevar(const char * /*str*/); -static time_t get_timevaldiff(struct timeval * /*early*/, struct timeval * /*later*/, - struct timeval *prog_start); +static time_t get_timevaldiff(struct timeval earlier, struct timeval later); +static time_t get_timevaldiff_to_now(struct timeval earlier); static in_addr_t get_ip_address(const char * /*ifname*/); -static void set_source_ip(char * /*arg*/, const int icmp_sock); +static void set_source_ip(char * /*arg*/, int icmp_sock); /* Receiving data */ -static int wait_for_reply(int /*sock*/, unsigned int /*t*/, bool order_mode, bool mos_mode, - bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode, - int min_hosts_alive, unsigned short icmp_pkt_size, - unsigned int *pkt_interval, unsigned int *target_interval, threshold warn, - threshold crit, pid_t pid, int mode, - unsigned long long max_completion_time, struct timeval *prog_start, - struct rta_host **table, const unsigned short packets, - const int icmp_sock, const unsigned short number_of_targets, - check_icmp_state *program_state); - -static int recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, - struct sockaddr * /*saddr*/, unsigned int * /*timo*/, - struct timeval * /*tv*/, struct timeval *prog_start); +static int wait_for_reply(int socket, time_t time_interval, unsigned short icmp_pkt_size, + unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid, + ping_target **table, unsigned short packets, + unsigned short number_of_targets, check_icmp_state *program_state); + +static ssize_t recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, + struct sockaddr * /*saddr*/, time_t *timeout, struct timeval * /*tv*/); static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/, unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid, - struct rta_host **table, unsigned short packets, - const unsigned short number_of_targets, - check_icmp_state *program_state); + ping_target **table, unsigned short packets, + unsigned short number_of_targets, check_icmp_state *program_state); /* Sending data */ -static int send_icmp_ping(int /*sock*/, struct rta_host * /*host*/, unsigned short icmp_pkt_size, +static int send_icmp_ping(int /*sock*/, ping_target * /*host*/, unsigned short icmp_pkt_size, pid_t pid, check_icmp_state *program_state); /* Threshold related */ -static int get_threshold(char *str, threshold *th); +static int get_threshold(char *str, threshold *threshold); static bool get_threshold2(char *str, size_t length, threshold * /*warn*/, threshold * /*crit*/, threshold_mode mode); -static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode); +static bool parse_threshold2_helper(char *threshold_string, size_t length, threshold *thr, + threshold_mode mode); /* main test function */ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode, int min_hosts_alive, unsigned short icmp_pkt_size, unsigned int *pkt_interval, unsigned int *target_interval, threshold warn, threshold crit, pid_t pid, - int mode, unsigned int max_completion_time, const struct timeval *prog_start, - struct rta_host **table, const unsigned short packets, const int icmp_sock, - const unsigned short number_of_targets, check_icmp_state *program_state); + int mode, unsigned int max_completion_time, struct timeval prog_start, + ping_target **table, unsigned short packets, int icmp_sock, + unsigned short number_of_targets, check_icmp_state *program_state, + ping_target *target_list); /* Target aquisition */ -static int add_target(char * /*arg*/, int mode); -static int add_target_ip(char * /*arg*/, struct sockaddr_storage * /*in*/); +typedef struct { + int error_code; + ping_target *targets; + unsigned int number_of_targets; +} add_target_wrapper; +static add_target_wrapper add_target(char * /*arg*/, int mode); + +typedef struct { + int error_code; + ping_target *target; +} add_target_ip_wrapper; +static add_target_ip_wrapper add_target_ip(char * /*arg*/, struct sockaddr_storage * /*in*/); -static void parse_address(struct sockaddr_storage * /*addr*/, char * /*address*/, int /*size*/); +static void parse_address(struct sockaddr_storage * /*addr*/, char * /*address*/, socklen_t size); static unsigned short icmp_checksum(uint16_t * /*p*/, size_t /*n*/); /* End of run function */ static void finish(int /*sig*/, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode, int min_hosts_alive, threshold warn, - threshold crit, const int icmp_sock, const unsigned short number_of_targets, - check_icmp_state *program_state); + threshold crit, int icmp_sock, unsigned short number_of_targets, + check_icmp_state *program_state, ping_target *target_list); /* Error exit */ static void crash(const char * /*fmt*/, ...); /** global variables **/ -static struct rta_host *cursor = NULL; -static struct rta_host *host_list = NULL; - static int debug = 0; -/** the working code **/ +extern unsigned int timeout; +/** the working code **/ static inline unsigned short targets_alive(unsigned short targets, unsigned short targets_down) { return targets - targets_down; } @@ -259,7 +265,8 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { } } - /* Parse protocol arguments first */ + // Parse protocol arguments first + // and count hosts here char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64"; for (int i = 1; i < argc; i++) { long int arg; @@ -281,10 +288,31 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { usage(_("IPv6 support not available\n")); #endif break; + case 'H': { + result.config.number_of_hosts++; + } } } } + char **tmp = &argv[optind]; + while (*tmp) { + result.config.number_of_hosts++; + tmp++; + } + + // Sanity check: if hostmode is selected,only a single host is allowed + if (result.config.mode == MODE_HOSTCHECK && result.config.number_of_hosts > 1) { + usage("check_host only allows a single host"); + } + + // Allocate hosts + result.config.hosts = + calloc(result.config.number_of_hosts, sizeof(check_icmp_target_container)); + if (result.config.hosts == NULL) { + crash("failed to allocate memory"); + } + /* Reset argument scanning */ optind = 1; @@ -301,8 +329,8 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { long size = strtol(optarg, NULL, 0); if ((unsigned long)size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && size < MAX_PING_DATA) { - result.config.icmp_data_size = size; - result.config.icmp_pkt_size = size + ICMP_MINLEN; + result.config.icmp_data_size = (unsigned short)size; + result.config.icmp_pkt_size = (unsigned short)(size + ICMP_MINLEN); } else { usage_va("ICMP data length must be between: %lu and %lu", sizeof(struct icmp) + sizeof(struct icmp_ping_data), @@ -323,24 +351,26 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { break; case 'n': case 'p': - result.config.packets = strtoul(optarg, NULL, 0); + result.config.packets = (unsigned short)strtoul(optarg, NULL, 0); if (result.config.packets > 20) { errno = 0; crash("packets is > 20 (%d)", result.config.packets); } break; case 't': - result.config.timeout = strtoul(optarg, NULL, 0); + timeout = (unsigned int)strtoul(optarg, NULL, 0); // TODO die here and complain about wrong input - // instead of: - if (!result.config.timeout) { - result.config.timeout = 10; - } break; case 'H': { - int add_result = add_target(optarg, result.config.mode); - if (add_result == 0) { - result.config.number_of_targets++; + add_target_wrapper add_result = add_target(optarg, result.config.mode); + if (add_result.error_code == OK) { + if (result.config.targets != NULL) { + result.config.number_of_targets += + ping_target_list_append(result.config.targets, add_result.targets); + } else { + result.config.targets = add_result.targets; + result.config.number_of_targets += add_result.number_of_targets; + } } } break; case 'l': @@ -569,7 +599,7 @@ static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icm static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, unsigned int *pkt_interval, unsigned int *target_interval, - const pid_t pid, struct rta_host **table, unsigned short packets, + const pid_t pid, ping_target **table, unsigned short packets, const unsigned short number_of_targets, check_icmp_state *program_state) { struct icmp p; @@ -611,7 +641,7 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad } /* it is indeed a response for us */ - struct rta_host *host = table[ntohs(sent_icmp.icmp_seq) / packets]; + ping_target *host = table[ntohs(sent_icmp.icmp_seq) / packets]; if (debug) { char address[INET6_ADDRSTRLEN]; parse_address(addr, address, sizeof(address)); @@ -629,8 +659,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad /* source quench means we're sending too fast, so increase the * interval and mark this packet lost */ if (p.icmp_type == ICMP_SOURCEQUENCH) { - *pkt_interval *= PACKET_BACKOFF_FACTOR; - *target_interval *= TARGET_BACKOFF_FACTOR; + *pkt_interval = (unsigned int)(*pkt_interval * PACKET_BACKOFF_FACTOR); + *target_interval = (unsigned int)(*target_interval * TARGET_BACKOFF_FACTOR); } else { program_state->targets_down++; host->flags |= FLAG_LOST_CAUSE; @@ -642,7 +672,7 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad return 0; } -void parse_address(struct sockaddr_storage *addr, char *address, int size) { +void parse_address(struct sockaddr_storage *addr, char *address, socklen_t size) { switch (address_family) { case AF_INET: inet_ntop(address_family, &((struct sockaddr_in *)addr)->sin_addr, address, size); @@ -722,32 +752,24 @@ int main(int argc, char **argv) { } } -#ifdef HAVE_SIGACTION struct sigaction sig_action; - sig_action.sa_sigaction = NULL; - sig_action.sa_handler = finish; + sig_action.sa_handler = NULL; + sig_action.sa_sigaction = check_icmp_timeout_handler; sigfillset(&sig_action.sa_mask); - sig_action.sa_flags = SA_NODEFER | SA_RESTART; + sig_action.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO; sigaction(SIGINT, &sig_action, NULL); sigaction(SIGHUP, &sig_action, NULL); sigaction(SIGTERM, &sig_action, NULL); sigaction(SIGALRM, &sig_action, NULL); -#else /* HAVE_SIGACTION */ - // signal(SIGINT, finish); - // signal(SIGHUP, finish); - // signal(SIGTERM, finish); - // signal(SIGALRM, finish); -#endif /* HAVE_SIGACTION */ if (debug) { - printf("Setting alarm timeout to %u seconds\n", config.timeout); + printf("Setting alarm timeout to %u seconds\n", timeout); } - alarm(config.timeout); + alarm(timeout); /* make sure we don't wait any longer than necessary */ - struct timezone time_zone_dummy; struct timeval prog_start; - gettimeofday(&prog_start, &time_zone_dummy); + gettimeofday(&prog_start, NULL); unsigned int max_completion_time = ((config.number_of_targets * config.packets * config.pkt_interval) + @@ -765,8 +787,8 @@ int main(int argc, char **argv) { } if (debug) { - if (max_completion_time > (unsigned int)config.timeout * 1000000) { - printf("max_completion_time: %u timeout: %u\n", max_completion_time, config.timeout); + if (max_completion_time > (timeout * 1000000)) { + printf("max_completion_time: %u timeout: %u\n", max_completion_time, timeout); printf("Timeout must be at least %u\n", (max_completion_time / 1000000) + 1); } } @@ -776,7 +798,7 @@ int main(int argc, char **argv) { config.warn.rta, config.warn.pl); printf("pkt_interval: %u target_interval: %u\n", config.pkt_interval, config.target_interval); - printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_pkt_size, config.timeout); + printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_pkt_size, timeout); } if (config.min_hosts_alive < -1) { @@ -784,18 +806,18 @@ int main(int argc, char **argv) { crash("minimum alive hosts is negative (%i)", config.min_hosts_alive); } - struct rta_host *host = host_list; - struct rta_host **table = malloc(sizeof(struct rta_host *) * config.number_of_targets); + ping_target *host = config.targets; + ping_target **table = malloc(sizeof(ping_target *) * config.number_of_targets); if (!table) { crash("main(): malloc failed for host table"); } - unsigned short i = 0; + unsigned short target_index = 0; while (host) { - host->id = i * config.packets; - table[i] = host; + host->id = target_index * config.packets; + table[target_index] = host; host = host->next; - i++; + target_index++; } unsigned int pkt_interval = config.pkt_interval; @@ -806,13 +828,13 @@ int main(int argc, char **argv) { run_checks(config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode, config.jitter_mode, config.score_mode, config.min_hosts_alive, config.icmp_data_size, &pkt_interval, &target_interval, config.warn, config.crit, config.pid, config.mode, - max_completion_time, &prog_start, table, config.packets, icmp_sock, - config.number_of_targets, &program_state); + max_completion_time, prog_start, table, config.packets, icmp_sock, + config.number_of_targets, &program_state, config.targets); errno = 0; finish(0, config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode, config.jitter_mode, config.score_mode, config.min_hosts_alive, config.warn, config.crit, - icmp_sock, config.number_of_targets, &program_state); + icmp_sock, config.number_of_targets, &program_state, config.targets); return (0); } @@ -822,9 +844,10 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo unsigned short icmp_pkt_size, unsigned int *pkt_interval, unsigned int *target_interval, threshold warn, threshold crit, const pid_t pid, const int mode, const unsigned int max_completion_time, - const struct timeval *prog_start, struct rta_host **table, + const struct timeval prog_start, ping_target **table, const unsigned short packets, const int icmp_sock, - const unsigned short number_of_targets, check_icmp_state *program_state) { + const unsigned short number_of_targets, check_icmp_state *program_state, + ping_target *target_list) { /* this loop might actually violate the pkt_interval or target_interval * settings, but only if there aren't any packets on the wire which * indicates that the target can handle an increased packet rate */ @@ -833,7 +856,8 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo /* don't send useless packets */ if (!targets_alive(number_of_targets, program_state->targets_down)) { finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode, - min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state); + min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state, + target_list); } if (table[target_index]->flags & FLAG_LOST_CAUSE) { if (debug) { @@ -845,25 +869,32 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo /* we're still in the game, so send next packet */ (void)send_icmp_ping(icmp_sock, table[target_index], icmp_pkt_size, pid, program_state); - wait_for_reply(icmp_sock, *target_interval, order_mode, mos_mode, rta_mode, pl_mode, - jitter_mode, score_mode, min_hosts_alive, icmp_pkt_size, pkt_interval, - target_interval, warn, crit, pid, mode, max_completion_time, prog_start, - table, packets, icmp_sock, number_of_targets, program_state); + /* wrap up if all targets are declared dead */ + if (targets_alive(number_of_targets, program_state->targets_down) || + get_timevaldiff(prog_start, prog_start) < max_completion_time || + !(mode == MODE_HOSTCHECK && program_state->targets_down)) { + wait_for_reply(icmp_sock, *target_interval, icmp_pkt_size, pkt_interval, + target_interval, pid, table, packets, number_of_targets, + program_state); + } + } + if (targets_alive(number_of_targets, program_state->targets_down) || + get_timevaldiff_to_now(prog_start) < max_completion_time || + !(mode == MODE_HOSTCHECK && program_state->targets_down)) { + wait_for_reply(icmp_sock, *pkt_interval * number_of_targets, icmp_pkt_size, + pkt_interval, target_interval, pid, table, packets, number_of_targets, + program_state); } - wait_for_reply(icmp_sock, *pkt_interval * number_of_targets, order_mode, mos_mode, rta_mode, - pl_mode, jitter_mode, score_mode, min_hosts_alive, icmp_pkt_size, - pkt_interval, target_interval, warn, crit, pid, mode, max_completion_time, - prog_start, table, packets, icmp_sock, number_of_targets, program_state); } if (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv, program_state->icmp_lost) && targets_alive(number_of_targets, program_state->targets_down)) { - unsigned int time_passed = get_timevaldiff(NULL, NULL, prog_start); - unsigned int final_wait = max_completion_time - time_passed; + time_t time_passed = get_timevaldiff_to_now(prog_start); + time_t final_wait = max_completion_time - time_passed; if (debug) { - printf("time_passed: %u final_wait: %u max_completion_time: %u\n", time_passed, + printf("time_passed: %ld final_wait: %ld max_completion_time: %u\n", time_passed, final_wait, max_completion_time); } if (time_passed > max_completion_time) { @@ -871,19 +902,22 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo printf("Time passed. Finishing up\n"); } finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode, - min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state); + min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state, + target_list); } /* catch the packets that might come in within the timeframe, but * haven't yet */ if (debug) { - printf("Waiting for %u micro-seconds (%0.3f msecs)\n", final_wait, + printf("Waiting for %ld micro-seconds (%0.3f msecs)\n", final_wait, (float)final_wait / 1000); } - wait_for_reply(icmp_sock, final_wait, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, - score_mode, min_hosts_alive, icmp_pkt_size, pkt_interval, target_interval, - warn, crit, pid, mode, max_completion_time, prog_start, table, packets, - icmp_sock, number_of_targets, program_state); + if (targets_alive(number_of_targets, program_state->targets_down) || + get_timevaldiff_to_now(prog_start) < max_completion_time || + !(mode == MODE_HOSTCHECK && program_state->targets_down)) { + wait_for_reply(icmp_sock, final_wait, icmp_pkt_size, pkt_interval, target_interval, pid, + table, packets, number_of_targets, program_state); + } } } @@ -897,15 +931,10 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo * both: * icmp echo reply : the rest */ -static int wait_for_reply(int sock, const unsigned int time_interval, bool order_mode, - bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode, - bool score_mode, int min_hosts_alive, unsigned short icmp_pkt_size, - unsigned int *pkt_interval, unsigned int *target_interval, threshold warn, - threshold crit, const pid_t pid, const int mode, - const unsigned long long max_completion_time, struct timeval *prog_start, - struct rta_host **table, const unsigned short packets, - const int icmp_sock, const unsigned short number_of_targets, - check_icmp_state *program_state) { +static int wait_for_reply(int sock, const time_t time_interval, unsigned short icmp_pkt_size, + unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid, + ping_target **table, const unsigned short packets, + const unsigned short number_of_targets, check_icmp_state *program_state) { union icmp_packet packet; if (!(packet.buf = malloc(icmp_pkt_size))) { crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); @@ -921,56 +950,50 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order return 0; } + // Get current time stamp struct timeval wait_start; - struct timezone time_zone_dummy; - gettimeofday(&wait_start, &time_zone_dummy); + gettimeofday(&wait_start, NULL); struct sockaddr_storage resp_addr; - unsigned int per_pkt_wait = + time_t per_pkt_wait = time_interval / icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv, program_state->icmp_lost); static unsigned char buf[65536]; - union ip_hdr *ip; - struct timeval now; + union ip_hdr *ip_header; + struct timeval packet_received_timestamp; while (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv, program_state->icmp_lost) && - get_timevaldiff(&wait_start, NULL, prog_start) < time_interval) { - unsigned int loop_time_interval = per_pkt_wait; - - /* wrap up if all targets are declared dead */ - if (!targets_alive(number_of_targets, program_state->targets_down) || - get_timevaldiff(prog_start, NULL, prog_start) >= max_completion_time || - (mode == MODE_HOSTCHECK && program_state->targets_down)) { - finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode, - min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state); - } + get_timevaldiff_to_now(wait_start) < time_interval) { + time_t loop_time_interval = per_pkt_wait; /* reap responses until we hit a timeout */ - int n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, - &loop_time_interval, &now, prog_start); + ssize_t n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, + &loop_time_interval, &packet_received_timestamp); if (!n) { if (debug > 1) { - printf("recvfrom_wto() timed out during a %u usecs wait\n", per_pkt_wait); + printf("recvfrom_wto() timed out during a %ld usecs wait\n", per_pkt_wait); } continue; /* timeout for this one, so keep trying */ } + if (n < 0) { if (debug) { printf("recvfrom_wto() returned errors\n"); } free(packet.buf); - return n; + return (int)n; } // FIXME: with ipv6 we don't have an ip header here if (address_family != AF_INET6) { - ip = (union ip_hdr *)buf; + ip_header = (union ip_hdr *)buf; if (debug > 1) { char address[INET6_ADDRSTRLEN]; parse_address(&resp_addr, address, sizeof(address)); printf("received %u bytes from %s\n", - address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen) : ntohs(ip->ip.ip_len), + address_family == AF_INET6 ? ntohs(ip_header->ip6.ip6_plen) + : ntohs(ip_header->ip.ip_len), address); } } @@ -982,7 +1005,7 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order * off the bottom 4 bits */ /* hlen = (ip->ip_vhl & 0x0f) << 2; */ /* #else */ - int hlen = (address_family == AF_INET6) ? 0 : ip->ip.ip_hl << 2; + int hlen = (address_family == AF_INET6) ? 0 : ip_header->ip.ip_hl << 2; /* #endif */ if (n < (hlen + ICMP_MINLEN)) { @@ -1020,7 +1043,7 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order } /* this is indeed a valid response */ - struct rta_host *host; + ping_target *target; struct icmp_ping_data data; if (address_family == PF_INET) { memcpy(&data, packet.icp->icmp_data, sizeof(data)); @@ -1029,7 +1052,7 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum); } - host = table[ntohs(packet.icp->icmp_seq) / packets]; + target = table[ntohs(packet.icp->icmp_seq) / packets]; } else { memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data)); if (debug > 2) { @@ -1037,55 +1060,55 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order ntohs(packet.icp6->icmp6_id), ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum); } - host = table[ntohs(packet.icp6->icmp6_seq) / packets]; + target = table[ntohs(packet.icp6->icmp6_seq) / packets]; } - unsigned int tdiff = get_timevaldiff(&data.stime, &now, prog_start); + time_t tdiff = get_timevaldiff(data.stime, packet_received_timestamp); - if (host->last_tdiff > 0) { + if (target->last_tdiff > 0) { /* Calculate jitter */ double jitter_tmp; - if (host->last_tdiff > tdiff) { - jitter_tmp = host->last_tdiff - tdiff; + if (target->last_tdiff > tdiff) { + jitter_tmp = (double)(target->last_tdiff - tdiff); } else { - jitter_tmp = tdiff - host->last_tdiff; + jitter_tmp = (double)(tdiff - target->last_tdiff); } - if (host->jitter == 0) { - host->jitter = jitter_tmp; - host->jitter_max = jitter_tmp; - host->jitter_min = jitter_tmp; + if (target->jitter == 0) { + target->jitter = jitter_tmp; + target->jitter_max = jitter_tmp; + target->jitter_min = jitter_tmp; } else { - host->jitter += jitter_tmp; + target->jitter += jitter_tmp; - if (jitter_tmp < host->jitter_min) { - host->jitter_min = jitter_tmp; + if (jitter_tmp < target->jitter_min) { + target->jitter_min = jitter_tmp; } - if (jitter_tmp > host->jitter_max) { - host->jitter_max = jitter_tmp; + if (jitter_tmp > target->jitter_max) { + target->jitter_max = jitter_tmp; } } /* Check if packets in order */ - if (host->last_icmp_seq >= packet.icp->icmp_seq) { - host->order_status = STATE_CRITICAL; + if (target->last_icmp_seq >= packet.icp->icmp_seq) { + target->order_status = STATE_CRITICAL; } } - host->last_tdiff = tdiff; + target->last_tdiff = tdiff; - host->last_icmp_seq = packet.icp->icmp_seq; + target->last_icmp_seq = packet.icp->icmp_seq; - host->time_waited += tdiff; - host->icmp_recv++; + target->time_waited += tdiff; + target->icmp_recv++; program_state->icmp_recv++; - if (tdiff > (unsigned int)host->rtmax) { - host->rtmax = tdiff; + if (tdiff > (unsigned int)target->rtmax) { + target->rtmax = (double)tdiff; } - if ((host->rtmin == INFINITY) || (tdiff < (unsigned int)host->rtmin)) { - host->rtmin = tdiff; + if ((target->rtmin == INFINITY) || (tdiff < (unsigned int)target->rtmin)) { + target->rtmin = (double)tdiff; } if (debug) { @@ -1095,26 +1118,16 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order switch (address_family) { case AF_INET: { printf("%0.3f ms rtt from %s, incoming ttl: %u, max: %0.3f, min: %0.3f\n", - (float)tdiff / 1000, address, ip->ip.ip_ttl, (float)host->rtmax / 1000, - (float)host->rtmin / 1000); + (float)tdiff / 1000, address, ip_header->ip.ip_ttl, + (float)target->rtmax / 1000, (float)target->rtmin / 1000); break; }; case AF_INET6: { printf("%0.3f ms rtt from %s, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, - address, (float)host->rtmax / 1000, (float)host->rtmin / 1000); + address, (float)target->rtmax / 1000, (float)target->rtmin / 1000); }; } } - - /* if we're in hostcheck mode, exit with limited printouts */ - if (mode == MODE_HOSTCHECK) { - printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" - "pkt=%u;;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", - host->name, program_state->icmp_recv, (float)tdiff / 1000, - program_state->icmp_recv, packets, (float)tdiff / 1000, (float)warn.rta / 1000, - (float)crit.rta / 1000); - exit(STATE_OK); - } } free(packet.buf); @@ -1122,7 +1135,7 @@ static int wait_for_reply(int sock, const unsigned int time_interval, bool order } /* the ping functions */ -static int send_icmp_ping(const int sock, struct rta_host *host, const unsigned short icmp_pkt_size, +static int send_icmp_ping(const int sock, ping_target *host, const unsigned short icmp_pkt_size, const pid_t pid, check_icmp_state *program_state) { if (sock == -1) { errno = 0; @@ -1140,18 +1153,17 @@ static int send_icmp_ping(const int sock, struct rta_host *host, const unsigned } memset(buf, 0, icmp_pkt_size); - struct timeval tv; - struct timezone tz; - if ((gettimeofday(&tv, &tz)) == -1) { + struct timeval current_time; + if ((gettimeofday(¤t_time, NULL)) == -1) { free(buf); return -1; } struct icmp_ping_data data; data.ping_id = 10; /* host->icmp.icmp_sent; */ - memcpy(&data.stime, &tv, sizeof(tv)); + memcpy(&data.stime, ¤t_time, sizeof(current_time)); - size_t addrlen; + socklen_t addrlen; if (address_family == AF_INET) { struct icmp *icp = (struct icmp *)buf; @@ -1162,7 +1174,7 @@ static int send_icmp_ping(const int sock, struct rta_host *host, const unsigned icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; - icp->icmp_id = htons(pid); + icp->icmp_id = htons((uint16_t)pid); icp->icmp_seq = htons(host->id++); icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size); @@ -1180,7 +1192,7 @@ static int send_icmp_ping(const int sock, struct rta_host *host, const unsigned icp6->icmp6_type = ICMP6_ECHO_REQUEST; icp6->icmp6_code = 0; icp6->icmp6_cksum = 0; - icp6->icmp6_id = htons(pid); + icp6->icmp6_id = htons((uint16_t)pid); icp6->icmp6_seq = htons(host->id++); // let checksum be calculated automatically @@ -1231,8 +1243,9 @@ static int send_icmp_ping(const int sock, struct rta_host *host, const unsigned return 0; } -static int recvfrom_wto(const int sock, void *buf, const unsigned int len, struct sockaddr *saddr, - unsigned int *timeout, struct timeval *tv, struct timeval *prog_start) { +static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, + struct sockaddr *saddr, time_t *timeout, + struct timeval *received_timestamp) { #ifdef HAVE_MSGHDR_MSG_CONTROL char ans_data[4096]; #endif // HAVE_MSGHDR_MSG_CONTROL @@ -1247,31 +1260,33 @@ static int recvfrom_wto(const int sock, void *buf, const unsigned int len, struc return 0; } - struct timeval to; - to.tv_sec = *timeout / 1000000; - to.tv_usec = (*timeout - (to.tv_sec * 1000000)); + struct timeval real_timeout; + real_timeout.tv_sec = *timeout / 1000000; + real_timeout.tv_usec = (*timeout - (real_timeout.tv_sec * 1000000)); - fd_set rd; - fd_set wr; - FD_ZERO(&rd); - FD_ZERO(&wr); - FD_SET(sock, &rd); - errno = 0; + // Dummy fds for select + fd_set dummy_write_fds; + FD_ZERO(&dummy_write_fds); + + // Read fds for select with the socket + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(sock, &read_fds); struct timeval then; - struct timezone time_zone_dummy; - gettimeofday(&then, &time_zone_dummy); + gettimeofday(&then, NULL); - int n = select(sock + 1, &rd, &wr, NULL, &to); - if (n < 0) { + errno = 0; + int select_return = select(sock + 1, &read_fds, &dummy_write_fds, NULL, &real_timeout); + if (select_return < 0) { crash("select() in recvfrom_wto"); } struct timeval now; - gettimeofday(&now, &time_zone_dummy); - *timeout = get_timevaldiff(&then, &now, prog_start); + gettimeofday(&now, NULL); + *timeout = get_timevaldiff(then, now); - if (!n) { + if (!select_return) { return 0; /* timeout */ } @@ -1299,16 +1314,16 @@ static int recvfrom_wto(const int sock, void *buf, const unsigned int len, struc for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) { if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) { - memcpy(tv, CMSG_DATA(chdr), sizeof(*tv)); + memcpy(received_timestamp, CMSG_DATA(chdr), sizeof(*received_timestamp)); break; } } if (!chdr) { - gettimeofday(tv, &time_zone_dummy); + gettimeofday(received_timestamp, NULL); } #else - gettimeofday(tv, &time_zone_dummy); + gettimeofday(tv, NULL); #endif // SO_TIMESTAMP return (ret); @@ -1317,7 +1332,7 @@ static int recvfrom_wto(const int sock, void *buf, const unsigned int len, struc static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode, int min_hosts_alive, threshold warn, threshold crit, const int icmp_sock, const unsigned short number_of_targets, - check_icmp_state *program_state) { + check_icmp_state *program_state, ping_target *target_list) { // Deactivate alarm alarm(0); @@ -1338,7 +1353,7 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool /* iterate thrice to calculate values, give output, and print perfparse */ mp_state_enum status = STATE_OK; - struct rta_host *host = host_list; + ping_target *host = target_list; unsigned int target_counter = 0; const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; @@ -1361,7 +1376,8 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool program_state->targets_down++; } } else { - packet_loss = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent; + packet_loss = + (unsigned char)((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent; rta = (double)host->time_waited / host->icmp_recv; } @@ -1507,7 +1523,7 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool } printf("%s - ", status_string[status]); - host = host_list; + host = target_list; while (host) { if (debug) { puts(""); @@ -1611,8 +1627,9 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) { printf("|"); } + target_counter = 0; - host = host_list; + host = target_list; while (host) { if (debug) { puts(""); @@ -1696,32 +1713,27 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool exit(status); } -static time_t get_timevaldiff(struct timeval *earlier, struct timeval *later, - struct timeval *prog_start) { - struct timeval now; - - if (!later) { - struct timezone time_zone_dummy; - gettimeofday(&now, &time_zone_dummy); - later = &now; - } - if (!earlier) { - earlier = prog_start; - } - +static time_t get_timevaldiff(const struct timeval earlier, const struct timeval later) { /* if early > later we return 0 so as to indicate a timeout */ - if (earlier->tv_sec > later->tv_sec || - (earlier->tv_sec == later->tv_sec && earlier->tv_usec > later->tv_usec)) { + if (earlier.tv_sec > later.tv_sec || + (earlier.tv_sec == later.tv_sec && earlier.tv_usec > later.tv_usec)) { return 0; } - time_t ret = (later->tv_sec - earlier->tv_sec) * 1000000; - ret += later->tv_usec - earlier->tv_usec; + time_t ret = (later.tv_sec - earlier.tv_sec) * 1000000; + ret += later.tv_usec - earlier.tv_usec; return ret; } -static int add_target_ip(char *arg, struct sockaddr_storage *address) { +static time_t get_timevaldiff_to_now(struct timeval earlier) { + struct timeval now; + gettimeofday(&now, NULL); + + return get_timevaldiff(earlier, now); +} + +static add_target_ip_wrapper add_target_ip(char *arg, struct sockaddr_storage *address) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; if (address_family == AF_INET) { @@ -1730,110 +1742,127 @@ static int add_target_ip(char *arg, struct sockaddr_storage *address) { sin6 = (struct sockaddr_in6 *)address; } + add_target_ip_wrapper result = { + .error_code = OK, + .target = NULL, + }; + /* disregard obviously stupid addresses * (I didn't find an ipv6 equivalent to INADDR_NONE) */ if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) || (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { - return -1; + result.error_code = ERROR; + return result; } + // TODO: allow duplicate targets for now, might be on purpose /* no point in adding two identical IP's, so don't. ;) */ - struct sockaddr_in *host_sin; - struct sockaddr_in6 *host_sin6; - struct rta_host *host = host_list; - while (host) { - host_sin = (struct sockaddr_in *)&host->saddr_in; - host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; - - if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) || - (address_family == AF_INET6 && - host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) { - if (debug) { - printf("Identical IP already exists. Not adding %s\n", arg); - } - return -1; - } - host = host->next; - } + // struct sockaddr_in *host_sin; + // struct sockaddr_in6 *host_sin6; + // ping_target *host = host_list; + // while (host) { + // host_sin = (struct sockaddr_in *)&host->saddr_in; + // host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; + + // if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) || + // (address_family == AF_INET6 && + // host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) { + // if (debug) { + // printf("Identical IP already exists. Not adding %s\n", arg); + // } + // return -1; + // } + // host = host->next; + // } /* add the fresh ip */ - host = (struct rta_host *)malloc(sizeof(struct rta_host)); - if (!host) { + ping_target *target = (ping_target *)malloc(sizeof(ping_target)); + if (!target) { char straddr[INET6_ADDRSTRLEN]; parse_address((struct sockaddr_storage *)&address, straddr, sizeof(straddr)); - crash("add_target_ip(%s, %s): malloc(%lu) failed", arg, straddr, sizeof(struct rta_host)); + crash("add_target_ip(%s, %s): malloc(%lu) failed", arg, straddr, sizeof(ping_target)); } - *host = ping_target_init(); + *target = ping_target_init(); /* set the values. use calling name for output */ - host->name = strdup(arg); + target->name = strdup(arg); /* fill out the sockaddr_storage struct */ + struct sockaddr_in *host_sin; + struct sockaddr_in6 *host_sin6; if (address_family == AF_INET) { - host_sin = (struct sockaddr_in *)&host->saddr_in; + host_sin = (struct sockaddr_in *)&target->saddr_in; host_sin->sin_family = AF_INET; host_sin->sin_addr.s_addr = sin->sin_addr.s_addr; } else { - host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; + host_sin6 = (struct sockaddr_in6 *)&target->saddr_in; host_sin6->sin6_family = AF_INET6; memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr); } - if (!host_list) { - host_list = cursor = host; - } else { - cursor->next = host; - } - - cursor = host; + result.target = target; - return 0; + return result; } /* wrapper for add_target_ip */ -static int add_target(char *arg, const int mode) { - struct sockaddr_storage ip; +static add_target_wrapper add_target(char *arg, const int mode) { + struct sockaddr_storage address_storage; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; - int result = -1; + int error_code = -1; switch (address_family) { case -1: /* -4 and -6 are not specified on cmdline */ address_family = AF_INET; - sin = (struct sockaddr_in *)&ip; - result = inet_pton(address_family, arg, &sin->sin_addr); + sin = (struct sockaddr_in *)&address_storage; + error_code = inet_pton(address_family, arg, &sin->sin_addr); #ifdef USE_IPV6 - if (result != 1) { + if (error_code != 1) { address_family = AF_INET6; - sin6 = (struct sockaddr_in6 *)&ip; - result = inet_pton(address_family, arg, &sin6->sin6_addr); + sin6 = (struct sockaddr_in6 *)&address_storage; + error_code = inet_pton(address_family, arg, &sin6->sin6_addr); } #endif /* If we don't find any valid addresses, we still don't know the address_family */ - if (result != 1) { + if (error_code != 1) { address_family = -1; } break; case AF_INET: - sin = (struct sockaddr_in *)&ip; - result = inet_pton(address_family, arg, &sin->sin_addr); + sin = (struct sockaddr_in *)&address_storage; + error_code = inet_pton(address_family, arg, &sin->sin_addr); break; case AF_INET6: - sin6 = (struct sockaddr_in6 *)&ip; - result = inet_pton(address_family, arg, &sin6->sin6_addr); + sin6 = (struct sockaddr_in6 *)&address_storage; + error_code = inet_pton(address_family, arg, &sin6->sin6_addr); break; default: crash("Address family not supported"); } + add_target_wrapper result = { + .error_code = OK, + .targets = NULL, + }; + /* don't resolve if we don't have to */ - if (result == 1) { + if (error_code == 1) { /* don't add all ip's if we were given a specific one */ - return add_target_ip(arg, &ip); + add_target_ip_wrapper targeted = add_target_ip(arg, &address_storage); + + if (targeted.error_code != OK) { + result.error_code = ERROR; + return result; + } + + result.targets = targeted.target; + result.number_of_targets = 1; + return result; } struct addrinfo hints; @@ -1851,14 +1880,28 @@ static int add_target(char *arg, const int mode) { if ((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) { errno = 0; crash("Failed to resolve %s: %s", arg, gai_strerror(error)); - return -1; + result.error_code = ERROR; + return result; } address_family = res->ai_family; /* possibly add all the IP's as targets */ - for (struct addrinfo *p = res; p != NULL; p = p->ai_next) { - memcpy(&ip, p->ai_addr, p->ai_addrlen); - add_target_ip(arg, &ip); + for (struct addrinfo *address = res; address != NULL; address = address->ai_next) { + struct sockaddr_storage temporary_ip_address; + memcpy(&temporary_ip_address, address->ai_addr, address->ai_addrlen); + add_target_ip_wrapper tmp = add_target_ip(arg, &temporary_ip_address); + + if (tmp.error_code != OK) { + // No proper error handling + // What to do? + } else { + if (result.targets == NULL) { + result.targets = tmp.target; + result.number_of_targets = 1; + } else { + result.number_of_targets += ping_target_list_append(result.targets, tmp.target); + } + } /* this is silly, but it works */ if (mode == MODE_HOSTCHECK || mode == MODE_ALL) { @@ -1867,11 +1910,13 @@ static int add_target(char *arg, const int mode) { } continue; } + + // Abort after first hit if not in of the modes above break; } freeaddrinfo(res); - return 0; + return result; } static void set_source_ip(char *arg, const int icmp_sock) { @@ -1890,8 +1935,8 @@ static void set_source_ip(char *arg, const int icmp_sock) { /* TODO: Move this to netutils.c and also change check_dhcp to use that. */ static in_addr_t get_ip_address(const char *ifname) { // TODO: Rewrite this so the function return an error and we exit somewhere else - struct sockaddr_in ip; - ip.sin_addr.s_addr = 0; // Fake initialization to make compiler happy + struct sockaddr_in ip_address; + ip_address.sin_addr.s_addr = 0; // Fake initialization to make compiler happy #if defined(SIOCGIFADDR) struct ifreq ifr; @@ -1909,7 +1954,7 @@ static in_addr_t get_ip_address(const char *ifname) { errno = 0; crash("Cannot get interface IP address on this platform."); #endif - return ip.sin_addr.s_addr; + return ip_address.sin_addr.s_addr; } /* @@ -1930,87 +1975,90 @@ static unsigned int get_timevar(const char *str) { /* unit might be given as ms|m (millisec), * us|u (microsec) or just plain s, for seconds */ - char p = '\0'; - char u = str[len - 1]; + char tmp = '\0'; + char unit = str[len - 1]; if (len >= 2 && !isdigit((int)str[len - 2])) { - p = str[len - 2]; + tmp = str[len - 2]; } - if (p && u == 's') { - u = p; - } else if (!p) { - p = u; + + if (tmp && unit == 's') { + unit = tmp; + } else if (!tmp) { + tmp = unit; } + if (debug > 2) { - printf("evaluating %s, u: %c, p: %c\n", str, u, p); + printf("evaluating %s, u: %c, p: %c\n", str, unit, tmp); } unsigned int factor = 1000; /* default to milliseconds */ - if (u == 'u') { + if (unit == 'u') { factor = 1; /* microseconds */ - } else if (u == 'm') { + } else if (unit == 'm') { factor = 1000; /* milliseconds */ - } else if (u == 's') { + } else if (unit == 's') { factor = 1000000; /* seconds */ } + if (debug > 2) { printf("factor is %u\n", factor); } char *ptr; - unsigned int i; - i = strtoul(str, &ptr, 0); + unsigned long pre_radix; + pre_radix = strtoul(str, &ptr, 0); if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) { - return i * factor; + return (unsigned int)(pre_radix * factor); } /* time specified in usecs can't have decimal points, so ignore them */ if (factor == 1) { - return i; + return (unsigned int)pre_radix; } /* integer and decimal, respectively */ - unsigned int d = strtoul(ptr + 1, NULL, 0); + unsigned int post_radix = (unsigned int)strtoul(ptr + 1, NULL, 0); /* d is decimal, so get rid of excess digits */ - while (d >= factor) { - d /= 10; + while (post_radix >= factor) { + post_radix /= 10; } /* the last parenthesis avoids floating point exceptions. */ - return ((i * factor) + (d * (factor / 10))); + return (unsigned int)((pre_radix * factor) + (post_radix * (factor / 10))); } /* not too good at checking errors, but it'll do (main() should barfe on -1) */ -static int get_threshold(char *str, threshold *th) { - if (!str || !strlen(str) || !th) { +static int get_threshold(char *str, threshold *threshold) { + if (!str || !strlen(str) || !threshold) { return -1; } /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */ - char i = 0; - char *p = &str[strlen(str) - 1]; - while (p != &str[1]) { - if (*p == '%') { - *p = '\0'; - } else if (*p == ',' && i) { - *p = '\0'; /* reset it so get_timevar(str) works nicely later */ - th->pl = (unsigned char)strtoul(p + 1, NULL, 0); + bool is_at_last_char = false; + char *tmp = &str[strlen(str) - 1]; + while (tmp != &str[1]) { + if (*tmp == '%') { + *tmp = '\0'; + } else if (*tmp == ',' && is_at_last_char) { + *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */ + threshold->pl = (unsigned char)strtoul(tmp + 1, NULL, 0); break; } - i = 1; - p--; + is_at_last_char = true; + tmp--; } - th->rta = get_timevar(str); + threshold->rta = get_timevar(str); - if (!th->rta) { + if (!threshold->rta) { return -1; } - if (th->rta > MAXTTL * 1000000) { - th->rta = MAXTTL * 1000000; + if (threshold->rta > MAXTTL * 1000000) { + threshold->rta = MAXTTL * 1000000; } - if (th->pl > 100) { - th->pl = 100; + if (threshold->pl > 100) { + threshold->pl = 100; } return 0; @@ -2034,58 +2082,58 @@ static bool get_threshold2(char *str, size_t length, threshold *warn, threshold } // p points to the last char in str - char *p = &str[length - 1]; + char *work_pointer = &str[length - 1]; // first_iteration is bof-stop on stupid libc's bool first_iteration = true; - while (p != &str[0]) { - if ((*p == 'm') || (*p == '%')) { - *p = '\0'; - } else if (*p == ',' && !first_iteration) { - *p = '\0'; /* reset it so get_timevar(str) works nicely later */ + while (work_pointer != &str[0]) { + if ((*work_pointer == 'm') || (*work_pointer == '%')) { + *work_pointer = '\0'; + } else if (*work_pointer == ',' && !first_iteration) { + *work_pointer = '\0'; /* reset it so get_timevar(str) works nicely later */ - char *start_of_value = p + 1; + char *start_of_value = work_pointer + 1; if (!parse_threshold2_helper(start_of_value, strlen(start_of_value), crit, mode)) { return false; } } first_iteration = false; - p--; + work_pointer--; } - return parse_threshold2_helper(p, strlen(p), warn, mode); + return parse_threshold2_helper(work_pointer, strlen(work_pointer), warn, mode); } -static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode) { +static bool parse_threshold2_helper(char *threshold_string, size_t length, threshold *thr, + threshold_mode mode) { char *resultChecker = {0}; switch (mode) { case const_rta_mode: - thr->rta = strtod(s, &resultChecker) * 1000; + thr->rta = (unsigned int)(strtod(threshold_string, &resultChecker) * 1000); break; case const_packet_loss_mode: - thr->pl = (unsigned char)strtoul(s, &resultChecker, 0); + thr->pl = (unsigned char)strtoul(threshold_string, &resultChecker, 0); break; case const_jitter_mode: - thr->jitter = strtod(s, &resultChecker); - + thr->jitter = strtod(threshold_string, &resultChecker); break; case const_mos_mode: - thr->mos = strtod(s, &resultChecker); + thr->mos = strtod(threshold_string, &resultChecker); break; case const_score_mode: - thr->score = strtod(s, &resultChecker); + thr->score = strtod(threshold_string, &resultChecker); break; } - if (resultChecker == s) { + if (resultChecker == threshold_string) { // Failed to parse return false; } - if (resultChecker != (s + length)) { + if (resultChecker != (threshold_string + length)) { // Trailing symbols return false; } @@ -2093,24 +2141,24 @@ static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, thre return true; } -unsigned short icmp_checksum(uint16_t *p, size_t n) { +unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) { long sum = 0; /* sizeof(uint16_t) == 2 */ - while (n >= 2) { - sum += *(p++); - n -= 2; + while (packet_size >= 2) { + sum += *(packet++); + packet_size -= 2; } /* mop up the occasional odd byte */ - if (n == 1) { - sum += *((uint8_t *)p - 1); + if (packet_size == 1) { + sum += *((uint8_t *)packet - 1); } sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ unsigned short cksum; - cksum = ~sum; /* ones-complement, trunc to 16 bits */ + cksum = (unsigned short)~sum; /* ones-complement, trunc to 16 bits */ return cksum; } diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index 8f6d7362..2efe6e59 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -5,6 +5,9 @@ #include "./check_icmp_helpers.h" #include "../../plugins/netutils.h" +// timeout as a global variable to make it available to the timeout handler +unsigned int timeout = DEFAULT_TIMEOUT; + check_icmp_config check_icmp_config_init() { check_icmp_config tmp = { .source_ip = NULL, @@ -33,11 +36,14 @@ check_icmp_config check_icmp_config_init() { .score = 80.0}, .pid = {}, .mode = MODE_RTA, - .timeout = DEFAULT_TIMEOUT, .ttl = DEFAULT_TTL, .packets = DEFAULT_NUMBER_OF_PACKETS, + .number_of_targets = 0, + .targets = NULL, + + .number_of_hosts = 0, .hosts = NULL, }; return tmp; @@ -140,3 +146,43 @@ check_icmp_target_container check_icmp_target_container_init() { }; return tmp; } + +unsigned int ping_target_list_append(ping_target *list, ping_target *elem) { + if (elem == NULL || list == NULL) { + return 0; + } + + while (list->next != NULL) { + list = list->next; + } + + list->next = elem; + + unsigned int result = 1; + + while (elem->next != NULL) { + result++; + elem = elem->next; + } + + return result; +} + +void check_icmp_timeout_handler(int signal, siginfo_t * info, void *ucontext) { + // Ignore unused arguments + (void) info; + (void) ucontext; + mp_subcheck timeout_sc = mp_subcheck_init(); + timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state); + + if (signal == SIGALRM) { + xasprintf(&timeout_sc.output, _("timeout after %d seconds\n"), timeout); + } else { + xasprintf(&timeout_sc.output, _("timeout after %d seconds\n"), timeout); + } + + mp_check overall = mp_check_init(); + mp_add_subcheck_to_check(&overall, timeout_sc); + + mp_exit(overall); +} diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h index 49f720ec..7e8a4d9f 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.h +++ b/plugins-root/check_icmp.d/check_icmp_helpers.h @@ -15,7 +15,7 @@ typedef struct rta_host { char *msg; /* icmp error message, if any */ struct sockaddr_storage saddr_in; /* the address of this host */ struct sockaddr_storage error_addr; /* stores address of error replies */ - unsigned long long time_waited; /* total time waited, in usecs */ + time_t time_waited; /* total time waited, in usecs */ unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */ unsigned char icmp_type, icmp_code; /* type and code from errors */ unsigned short flags; /* control/status flags */ @@ -32,7 +32,7 @@ typedef struct rta_host { double mos; /* Mean opinion score */ double score; /* score */ - unsigned int last_tdiff; + time_t last_tdiff; unsigned int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */ unsigned char pl; /* measured packet loss */ @@ -71,3 +71,6 @@ typedef struct { } rta_host_create_wrapper; rta_host_create_wrapper rta_host_create(char *name, struct sockaddr_storage *address); +unsigned int ping_target_list_append(ping_target *list, ping_target *elem); + +void check_icmp_timeout_handler(int, siginfo_t *, void *); diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h new file mode 100644 index 00000000..deae9bec --- /dev/null +++ b/plugins-root/check_icmp.d/config.h @@ -0,0 +1,102 @@ +#pragma once + +#include "../../config.h" +#include "../../lib/states.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "./check_icmp_helpers.h" + +/* threshold structure. all values are maximum allowed, exclusive */ +typedef struct threshold { + unsigned char pl; /* max allowed packet loss in percent */ + unsigned int rta; /* roundtrip time average, microseconds */ + double jitter; /* jitter time average, microseconds */ + double mos; /* MOS */ + double score; /* Score */ +} threshold; + +typedef struct { + char *source_ip; + + bool order_mode; + bool mos_mode; + bool rta_mode; + bool pl_mode; + bool jitter_mode; + bool score_mode; + + int min_hosts_alive; + unsigned short icmp_data_size; + unsigned short icmp_pkt_size; + unsigned int pkt_interval; + unsigned int target_interval; + threshold crit; + threshold warn; + pid_t pid; + + int mode; + unsigned long ttl; + + unsigned short packets; + + unsigned short number_of_targets; + ping_target *targets; + + unsigned short number_of_hosts; + check_icmp_target_container *hosts; +} check_icmp_config; + +check_icmp_config check_icmp_config_init(); + +/* the data structure */ +typedef struct icmp_ping_data { + struct timeval stime; /* timestamp (saved in protocol struct as well) */ + unsigned short ping_id; +} icmp_ping_data; + +#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */ +#define IP_HDR_SIZE 20 +#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN) +#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data) +#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44) + +/* 80 msec packet interval by default */ +#define DEFAULT_PKT_INTERVAL 80000 +#define DEFAULT_TARGET_INTERVAL 0 + +#define DEFAULT_WARN_RTA 200000 +#define DEFAULT_CRIT_RTA 500000 +#define DEFAULT_WARN_PL 40 +#define DEFAULT_CRIT_PL 80 + +#define DEFAULT_TIMEOUT 10 +#define DEFAULT_TTL 64 + +/* the different modes of this program are as follows: + * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping) + * MODE_HOSTCHECK: Return immediately upon any sign of life + * In addition, sends packets to ALL addresses assigned + * to this host (as returned by gethostbyname() or + * gethostbyaddr() and expects one host only to be checked at + * a time. Therefore, any packet response what so ever will + * count as a sign of life, even when received outside + * crit.rta limit. Do not misspell any additional IP's. + * MODE_ALL: Requires packets from ALL requested IP to return OK (default). + * MODE_ICMP: implement something similar to check_icmp (MODE_RTA without + * tcp and udp args does this) + */ +#define MODE_RTA 0 +#define MODE_HOSTCHECK 1 +#define MODE_ALL 2 +#define MODE_ICMP 3 + +#define DEFAULT_NUMBER_OF_PACKETS 5 + +#define PACKET_BACKOFF_FACTOR 1.5 +#define TARGET_BACKOFF_FACTOR 1.5 -- cgit v1.2.3-74-g34f1 From 5fd8191a50df6be712c9143ca6d73de7878f57d1 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 5 May 2025 22:52:56 +0200 Subject: WIP - check_icmp refactor 3 --- plugins-root/check_icmp.c | 150 ++++++++++++------------- plugins-root/check_icmp.d/check_icmp_helpers.c | 25 +++-- plugins-root/check_icmp.d/config.h | 58 +++++----- 3 files changed, 118 insertions(+), 115 deletions(-) (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 99414014..9d163678 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -142,37 +142,38 @@ static void set_source_ip(char * /*arg*/, int icmp_sock); /* Receiving data */ static int wait_for_reply(int socket, time_t time_interval, unsigned short icmp_pkt_size, - unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid, - ping_target **table, unsigned short packets, + unsigned int *pkt_interval, unsigned int *target_interval, + uint16_t sender_id, ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); static ssize_t recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, struct sockaddr * /*saddr*/, time_t *timeout, struct timeval * /*tv*/); static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/, - unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid, + unsigned int *pkt_interval, unsigned int *target_interval, uint16_t sender_id, ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); /* Sending data */ static int send_icmp_ping(int /*sock*/, ping_target * /*host*/, unsigned short icmp_pkt_size, - pid_t pid, check_icmp_state *program_state); + uint16_t sender_id, check_icmp_state *program_state); /* Threshold related */ -static int get_threshold(char *str, threshold *threshold); -static bool get_threshold2(char *str, size_t length, threshold * /*warn*/, threshold * /*crit*/, - threshold_mode mode); -static bool parse_threshold2_helper(char *threshold_string, size_t length, threshold *thr, - threshold_mode mode); +static int get_threshold(char *str, check_icmp_threshold *threshold); +static bool get_threshold2(char *str, size_t length, check_icmp_threshold * /*warn*/, + check_icmp_threshold * /*crit*/, threshold_mode mode); +static bool parse_threshold2_helper(char *threshold_string, size_t length, + check_icmp_threshold *thr, threshold_mode mode); /* main test function */ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode, int min_hosts_alive, unsigned short icmp_pkt_size, unsigned int *pkt_interval, - unsigned int *target_interval, threshold warn, threshold crit, pid_t pid, - int mode, unsigned int max_completion_time, struct timeval prog_start, - ping_target **table, unsigned short packets, int icmp_sock, - unsigned short number_of_targets, check_icmp_state *program_state, - ping_target *target_list); + unsigned int *target_interval, check_icmp_threshold warn, + check_icmp_threshold crit, uint16_t sender_id, + check_icmp_execution_mode mode, unsigned int max_completion_time, + struct timeval prog_start, ping_target **table, unsigned short packets, + int icmp_sock, unsigned short number_of_targets, + check_icmp_state *program_state, ping_target *target_list); /* Target aquisition */ typedef struct { @@ -190,13 +191,14 @@ static add_target_ip_wrapper add_target_ip(char * /*arg*/, struct sockaddr_stora static void parse_address(struct sockaddr_storage * /*addr*/, char * /*address*/, socklen_t size); -static unsigned short icmp_checksum(uint16_t * /*p*/, size_t /*n*/); +static unsigned short icmp_checksum(uint16_t *packet, size_t packet_size); /* End of run function */ static void finish(int /*sig*/, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, - bool jitter_mode, bool score_mode, int min_hosts_alive, threshold warn, - threshold crit, int icmp_sock, unsigned short number_of_targets, - check_icmp_state *program_state, ping_target *target_list); + bool jitter_mode, bool score_mode, int min_hosts_alive, + check_icmp_threshold warn, check_icmp_threshold crit, int icmp_sock, + unsigned short number_of_targets, check_icmp_state *program_state, + ping_target *target_list); /* Error exit */ static void crash(const char * /*fmt*/, ...); @@ -239,21 +241,21 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { /* use the pid to mark packets as ours */ /* Some systems have 32-bit pid_t so mask off only 16 bits */ - result.config.pid = getpid() & 0xffff; + result.config.sender_id = getpid() & 0xffff; if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) { result.config.mode = MODE_ICMP; } else if (!strcmp(progname, "check_host")) { result.config.mode = MODE_HOSTCHECK; result.config.pkt_interval = 1000000; - result.config.packets = 5; + result.config.number_of_packets = 5; result.config.crit.rta = result.config.warn.rta = 1000000; result.config.crit.pl = result.config.warn.pl = 100; } else if (!strcmp(progname, "check_rta_multi")) { result.config.mode = MODE_ALL; result.config.target_interval = 0; result.config.pkt_interval = 50000; - result.config.packets = 5; + result.config.number_of_packets = 5; } /* support "--help" and "--version" */ if (argc == 2) { @@ -279,14 +281,10 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { address_family = AF_INET; break; case '6': -#ifdef USE_IPV6 if (address_family != -1) { crash("Multiple protocol versions not supported"); } address_family = AF_INET6; -#else - usage(_("IPv6 support not available\n")); -#endif break; case 'H': { result.config.number_of_hosts++; @@ -351,10 +349,10 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { break; case 'n': case 'p': - result.config.packets = (unsigned short)strtoul(optarg, NULL, 0); - if (result.config.packets > 20) { + result.config.number_of_packets = (unsigned short)strtoul(optarg, NULL, 0); + if (result.config.number_of_packets > 20) { errno = 0; - crash("packets is > 20 (%d)", result.config.packets); + crash("packets is > 20 (%d)", result.config.number_of_packets); } break; case 't': @@ -599,18 +597,18 @@ static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icm static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, unsigned int *pkt_interval, unsigned int *target_interval, - const pid_t pid, ping_target **table, unsigned short packets, + const uint16_t sender_id, ping_target **table, unsigned short packets, const unsigned short number_of_targets, check_icmp_state *program_state) { - struct icmp p; - memcpy(&p, packet, sizeof(p)); - if (p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) { + struct icmp icmp_packet; + memcpy(&icmp_packet, packet, sizeof(icmp_packet)); + if (icmp_packet.icmp_type == ICMP_ECHO && ntohs(icmp_packet.icmp_id) == sender_id) { /* echo request from us to us (pinging localhost) */ return 0; } if (debug) { - printf("handle_random_icmp(%p, %p)\n", (void *)&p, (void *)addr); + printf("handle_random_icmp(%p, %p)\n", (void *)&icmp_packet, (void *)addr); } /* only handle a few types, since others can't possibly be replies to @@ -623,8 +621,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad * TIMXCEED actually sends a proper icmp response we will have passed * too many hops to have a hope of reaching it later, in which case it * indicates overconfidence in the network, poor routing or both. */ - if (p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED && - p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) { + if (icmp_packet.icmp_type != ICMP_UNREACH && icmp_packet.icmp_type != ICMP_TIMXCEED && + icmp_packet.icmp_type != ICMP_SOURCEQUENCH && icmp_packet.icmp_type != ICMP_PARAMPROB) { return 0; } @@ -632,7 +630,7 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad * to RFC 792). If it isn't, just ignore it */ struct icmp sent_icmp; memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp)); - if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid || + if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != sender_id || ntohs(sent_icmp.icmp_seq) >= number_of_targets * packets) { if (debug) { printf("Packet is no response to a packet we sent\n"); @@ -646,7 +644,7 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad char address[INET6_ADDRSTRLEN]; parse_address(addr, address, sizeof(address)); printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", - get_icmp_error_msg(p.icmp_type, p.icmp_code), address, host->name); + get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address, host->name); } program_state->icmp_lost++; @@ -658,15 +656,15 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad /* source quench means we're sending too fast, so increase the * interval and mark this packet lost */ - if (p.icmp_type == ICMP_SOURCEQUENCH) { + if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) { *pkt_interval = (unsigned int)(*pkt_interval * PACKET_BACKOFF_FACTOR); *target_interval = (unsigned int)(*target_interval * TARGET_BACKOFF_FACTOR); } else { program_state->targets_down++; host->flags |= FLAG_LOST_CAUSE; } - host->icmp_type = p.icmp_type; - host->icmp_code = p.icmp_code; + host->icmp_type = icmp_packet.icmp_type; + host->icmp_code = icmp_packet.icmp_code; host->error_addr = *addr; return 0; @@ -772,18 +770,18 @@ int main(int argc, char **argv) { gettimeofday(&prog_start, NULL); unsigned int max_completion_time = - ((config.number_of_targets * config.packets * config.pkt_interval) + + ((config.number_of_targets * config.number_of_packets * config.pkt_interval) + (config.number_of_targets * config.target_interval)) + - (config.number_of_targets * config.packets * config.crit.rta) + config.crit.rta; + (config.number_of_targets * config.number_of_packets * config.crit.rta) + config.crit.rta; if (debug) { printf("packets: %u, targets: %u\n" "target_interval: %0.3f, pkt_interval %0.3f\n" "crit.rta: %0.3f\n" "max_completion_time: %0.3f\n", - config.packets, config.number_of_targets, (float)config.target_interval / 1000, - (float)config.pkt_interval / 1000, (float)config.crit.rta / 1000, - (float)max_completion_time / 1000); + config.number_of_packets, config.number_of_targets, + (float)config.target_interval / 1000, (float)config.pkt_interval / 1000, + (float)config.crit.rta / 1000, (float)max_completion_time / 1000); } if (debug) { @@ -814,7 +812,7 @@ int main(int argc, char **argv) { unsigned short target_index = 0; while (host) { - host->id = target_index * config.packets; + host->id = target_index * config.number_of_packets; table[target_index] = host; host = host->next; target_index++; @@ -827,9 +825,9 @@ int main(int argc, char **argv) { run_checks(config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode, config.jitter_mode, config.score_mode, config.min_hosts_alive, config.icmp_data_size, - &pkt_interval, &target_interval, config.warn, config.crit, config.pid, config.mode, - max_completion_time, prog_start, table, config.packets, icmp_sock, - config.number_of_targets, &program_state, config.targets); + &pkt_interval, &target_interval, config.warn, config.crit, config.sender_id, + config.mode, max_completion_time, prog_start, table, config.number_of_packets, + icmp_sock, config.number_of_targets, &program_state, config.targets); errno = 0; finish(0, config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode, @@ -842,8 +840,9 @@ int main(int argc, char **argv) { static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode, int min_hosts_alive, unsigned short icmp_pkt_size, unsigned int *pkt_interval, - unsigned int *target_interval, threshold warn, threshold crit, - const pid_t pid, const int mode, const unsigned int max_completion_time, + unsigned int *target_interval, check_icmp_threshold warn, + check_icmp_threshold crit, const uint16_t sender_id, + const check_icmp_execution_mode mode, const unsigned int max_completion_time, const struct timeval prog_start, ping_target **table, const unsigned short packets, const int icmp_sock, const unsigned short number_of_targets, check_icmp_state *program_state, @@ -867,14 +866,15 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo } /* we're still in the game, so send next packet */ - (void)send_icmp_ping(icmp_sock, table[target_index], icmp_pkt_size, pid, program_state); + (void)send_icmp_ping(icmp_sock, table[target_index], icmp_pkt_size, sender_id, + program_state); /* wrap up if all targets are declared dead */ if (targets_alive(number_of_targets, program_state->targets_down) || get_timevaldiff(prog_start, prog_start) < max_completion_time || !(mode == MODE_HOSTCHECK && program_state->targets_down)) { wait_for_reply(icmp_sock, *target_interval, icmp_pkt_size, pkt_interval, - target_interval, pid, table, packets, number_of_targets, + target_interval, sender_id, table, packets, number_of_targets, program_state); } } @@ -882,8 +882,8 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo get_timevaldiff_to_now(prog_start) < max_completion_time || !(mode == MODE_HOSTCHECK && program_state->targets_down)) { wait_for_reply(icmp_sock, *pkt_interval * number_of_targets, icmp_pkt_size, - pkt_interval, target_interval, pid, table, packets, number_of_targets, - program_state); + pkt_interval, target_interval, sender_id, table, packets, + number_of_targets, program_state); } } @@ -915,8 +915,8 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo if (targets_alive(number_of_targets, program_state->targets_down) || get_timevaldiff_to_now(prog_start) < max_completion_time || !(mode == MODE_HOSTCHECK && program_state->targets_down)) { - wait_for_reply(icmp_sock, final_wait, icmp_pkt_size, pkt_interval, target_interval, pid, - table, packets, number_of_targets, program_state); + wait_for_reply(icmp_sock, final_wait, icmp_pkt_size, pkt_interval, target_interval, + sender_id, table, packets, number_of_targets, program_state); } } } @@ -932,8 +932,8 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo * icmp echo reply : the rest */ static int wait_for_reply(int sock, const time_t time_interval, unsigned short icmp_pkt_size, - unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid, - ping_target **table, const unsigned short packets, + unsigned int *pkt_interval, unsigned int *target_interval, + uint16_t sender_id, ping_target **table, const unsigned short packets, const unsigned short number_of_targets, check_icmp_state *program_state) { union icmp_packet packet; if (!(packet.buf = malloc(icmp_pkt_size))) { @@ -1027,16 +1027,16 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i : sizeof(struct icmp));*/ if ((address_family == PF_INET && - (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY || + (ntohs(packet.icp->icmp_id) != sender_id || packet.icp->icmp_type != ICMP_ECHOREPLY || ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) || (address_family == PF_INET6 && - (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || + (ntohs(packet.icp6->icmp6_id) != sender_id || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) { if (debug > 2) { printf("not a proper ICMP_ECHOREPLY\n"); } - handle_random_icmp(buf + hlen, &resp_addr, pkt_interval, target_interval, pid, table, + handle_random_icmp(buf + hlen, &resp_addr, pkt_interval, target_interval, sender_id, table, packets, number_of_targets, program_state); continue; @@ -1136,7 +1136,7 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i /* the ping functions */ static int send_icmp_ping(const int sock, ping_target *host, const unsigned short icmp_pkt_size, - const pid_t pid, check_icmp_state *program_state) { + const uint16_t sender_id, check_icmp_state *program_state) { if (sock == -1) { errno = 0; crash("Attempt to send on bogus socket"); @@ -1174,7 +1174,7 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; - icp->icmp_id = htons((uint16_t)pid); + icp->icmp_id = htons((uint16_t)sender_id); icp->icmp_seq = htons(host->id++); icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size); @@ -1192,7 +1192,7 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor icp6->icmp6_type = ICMP6_ECHO_REQUEST; icp6->icmp6_code = 0; icp6->icmp6_cksum = 0; - icp6->icmp6_id = htons((uint16_t)pid); + icp6->icmp6_id = htons((uint16_t)sender_id); icp6->icmp6_seq = htons(host->id++); // let checksum be calculated automatically @@ -1330,9 +1330,10 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, } static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, - bool jitter_mode, bool score_mode, int min_hosts_alive, threshold warn, - threshold crit, const int icmp_sock, const unsigned short number_of_targets, - check_icmp_state *program_state, ping_target *target_list) { + bool jitter_mode, bool score_mode, int min_hosts_alive, + check_icmp_threshold warn, check_icmp_threshold crit, const int icmp_sock, + const unsigned short number_of_targets, check_icmp_state *program_state, + ping_target *target_list) { // Deactivate alarm alarm(0); @@ -1821,13 +1822,12 @@ static add_target_wrapper add_target(char *arg, const int mode) { address_family = AF_INET; sin = (struct sockaddr_in *)&address_storage; error_code = inet_pton(address_family, arg, &sin->sin_addr); -#ifdef USE_IPV6 + if (error_code != 1) { address_family = AF_INET6; sin6 = (struct sockaddr_in6 *)&address_storage; error_code = inet_pton(address_family, arg, &sin6->sin6_addr); } -#endif /* If we don't find any valid addresses, we still don't know the address_family */ if (error_code != 1) { address_family = -1; @@ -2029,7 +2029,7 @@ static unsigned int get_timevar(const char *str) { } /* not too good at checking errors, but it'll do (main() should barfe on -1) */ -static int get_threshold(char *str, threshold *threshold) { +static int get_threshold(char *str, check_icmp_threshold *threshold) { if (!str || !strlen(str) || !threshold) { return -1; } @@ -2075,8 +2075,8 @@ static int get_threshold(char *str, threshold *threshold) { * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score * (exclusively) */ -static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit, - threshold_mode mode) { +static bool get_threshold2(char *str, size_t length, check_icmp_threshold *warn, + check_icmp_threshold *crit, threshold_mode mode) { if (!str || !length || !warn || !crit) { return false; } @@ -2106,8 +2106,8 @@ static bool get_threshold2(char *str, size_t length, threshold *warn, threshold return parse_threshold2_helper(work_pointer, strlen(work_pointer), warn, mode); } -static bool parse_threshold2_helper(char *threshold_string, size_t length, threshold *thr, - threshold_mode mode) { +static bool parse_threshold2_helper(char *threshold_string, size_t length, + check_icmp_threshold *thr, threshold_mode mode) { char *resultChecker = {0}; switch (mode) { diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index 2efe6e59..2a521b04 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -10,8 +10,6 @@ unsigned int timeout = DEFAULT_TIMEOUT; check_icmp_config check_icmp_config_init() { check_icmp_config tmp = { - .source_ip = NULL, - .order_mode = false, .mos_mode = false, .rta_mode = false, @@ -20,10 +18,6 @@ check_icmp_config check_icmp_config_init() { .score_mode = false, .min_hosts_alive = -1, - .icmp_data_size = DEFAULT_PING_DATA_SIZE, - .icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN, - .pkt_interval = DEFAULT_PKT_INTERVAL, - .target_interval = 0, .crit = {.pl = DEFAULT_CRIT_PL, .rta = DEFAULT_CRIT_RTA, .jitter = 50.0, @@ -34,11 +28,18 @@ check_icmp_config check_icmp_config_init() { .jitter = 40.0, .mos = 3.5, .score = 80.0}, - .pid = {}, - .mode = MODE_RTA, + .ttl = DEFAULT_TTL, + .icmp_data_size = DEFAULT_PING_DATA_SIZE, + .icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN, + .pkt_interval = DEFAULT_PKT_INTERVAL, + .target_interval = 0, + .number_of_packets = DEFAULT_NUMBER_OF_PACKETS, + .source_ip = NULL, + + .sender_id = {}, - .packets = DEFAULT_NUMBER_OF_PACKETS, + .mode = MODE_RTA, .number_of_targets = 0, .targets = NULL, @@ -168,10 +169,10 @@ unsigned int ping_target_list_append(ping_target *list, ping_target *elem) { return result; } -void check_icmp_timeout_handler(int signal, siginfo_t * info, void *ucontext) { +void check_icmp_timeout_handler(int signal, siginfo_t *info, void *ucontext) { // Ignore unused arguments - (void) info; - (void) ucontext; + (void)info; + (void)ucontext; mp_subcheck timeout_sc = mp_subcheck_init(); timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state); diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h index deae9bec..3599c0f0 100644 --- a/plugins-root/check_icmp.d/config.h +++ b/plugins-root/check_icmp.d/config.h @@ -10,20 +10,38 @@ #include #include #include +#include #include "./check_icmp_helpers.h" /* threshold structure. all values are maximum allowed, exclusive */ -typedef struct threshold { +typedef struct { unsigned char pl; /* max allowed packet loss in percent */ unsigned int rta; /* roundtrip time average, microseconds */ double jitter; /* jitter time average, microseconds */ double mos; /* MOS */ double score; /* Score */ -} threshold; +} check_icmp_threshold; -typedef struct { - char *source_ip; +/* the different modes of this program are as follows: + * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping) + * MODE_HOSTCHECK: Return immediately upon any sign of life + * In addition, sends packets to ALL addresses assigned + * to this host (as returned by gethostbyname() or + * gethostbyaddr() and expects one host only to be checked at + * a time. Therefore, any packet response what so ever will + * count as a sign of life, even when received outside + * crit.rta limit. Do not misspell any additional IP's. + * MODE_ALL: Requires packets from ALL requested IP to return OK (default). + * MODE_ICMP: Default Mode + */ +typedef enum { + MODE_RTA, + MODE_HOSTCHECK, + MODE_ALL, + MODE_ICMP, +} check_icmp_execution_mode; +typedef struct { bool order_mode; bool mos_mode; bool rta_mode; @@ -32,18 +50,20 @@ typedef struct { bool score_mode; int min_hosts_alive; + check_icmp_threshold crit; + check_icmp_threshold warn; + + unsigned long ttl; unsigned short icmp_data_size; unsigned short icmp_pkt_size; unsigned int pkt_interval; unsigned int target_interval; - threshold crit; - threshold warn; - pid_t pid; + unsigned short number_of_packets; + char *source_ip; - int mode; - unsigned long ttl; + uint16_t sender_id; // PID of the main process, which is used as an ID in packets - unsigned short packets; + check_icmp_execution_mode mode; unsigned short number_of_targets; ping_target *targets; @@ -78,24 +98,6 @@ typedef struct icmp_ping_data { #define DEFAULT_TIMEOUT 10 #define DEFAULT_TTL 64 -/* the different modes of this program are as follows: - * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping) - * MODE_HOSTCHECK: Return immediately upon any sign of life - * In addition, sends packets to ALL addresses assigned - * to this host (as returned by gethostbyname() or - * gethostbyaddr() and expects one host only to be checked at - * a time. Therefore, any packet response what so ever will - * count as a sign of life, even when received outside - * crit.rta limit. Do not misspell any additional IP's. - * MODE_ALL: Requires packets from ALL requested IP to return OK (default). - * MODE_ICMP: implement something similar to check_icmp (MODE_RTA without - * tcp and udp args does this) - */ -#define MODE_RTA 0 -#define MODE_HOSTCHECK 1 -#define MODE_ALL 2 -#define MODE_ICMP 3 - #define DEFAULT_NUMBER_OF_PACKETS 5 #define PACKET_BACKOFF_FACTOR 1.5 -- cgit v1.2.3-74-g34f1 From 6b86583e0d3db92cc5e87af97f4d204bc0e797f3 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Fri, 16 May 2025 09:07:35 +0200 Subject: WIP - check_icmp refactor 5 --- plugins-root/check_icmp.c | 27 +++++++++++++++----------- plugins-root/check_icmp.d/check_icmp_helpers.c | 4 ++-- plugins-root/check_icmp.d/check_icmp_helpers.h | 4 ++-- 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 94f20eec..8565f32d 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -133,12 +133,12 @@ void print_help(); void print_usage(void); /* Time related */ -static unsigned int get_timevar(const char * /*str*/); +static unsigned int get_timevar(const char *str); static time_t get_timevaldiff(struct timeval earlier, struct timeval later); static time_t get_timevaldiff_to_now(struct timeval earlier); -static in_addr_t get_ip_address(const char * /*ifname*/); -static void set_source_ip(char * /*arg*/, int icmp_sock); +static in_addr_t get_ip_address(const char *ifname); +static void set_source_ip(char *arg, int icmp_sock); /* Receiving data */ static int wait_for_reply(int socket, time_t time_interval, unsigned short icmp_pkt_size, @@ -146,9 +146,9 @@ static int wait_for_reply(int socket, time_t time_interval, unsigned short icmp_ uint16_t sender_id, ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); -static ssize_t recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, - struct sockaddr * /*saddr*/, time_t *timeout, struct timeval * /*tv*/); -static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/, +static ssize_t recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, + time_t *timeout, struct timeval *received_timestamp); +static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, unsigned int *pkt_interval, unsigned int *target_interval, uint16_t sender_id, ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); @@ -193,20 +193,25 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo check_icmp_state *program_state, ping_target *target_list); /* Target aquisition */ +typedef struct { + int error_code; + check_icmp_target_container host; +} add_host_wrapper; +static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode); typedef struct { int error_code; ping_target *targets; unsigned int number_of_targets; } add_target_wrapper; -static add_target_wrapper add_target(char * /*arg*/, int mode); +static add_target_wrapper add_target(char *arg, check_icmp_execution_mode mode); typedef struct { int error_code; ping_target *target; } add_target_ip_wrapper; -static add_target_ip_wrapper add_target_ip(char * /*arg*/, struct sockaddr_storage * /*in*/); +static add_target_ip_wrapper add_target_ip(char *arg, struct sockaddr_storage *address); -static void parse_address(struct sockaddr_storage * /*addr*/, char * /*address*/, socklen_t size); +static void parse_address(struct sockaddr_storage *addr, char *address, socklen_t size); static unsigned short icmp_checksum(uint16_t *packet, size_t packet_size); @@ -218,7 +223,7 @@ static void finish(int /*sig*/, bool order_mode, bool mos_mode, bool rta_mode, b ping_target *target_list); /* Error exit */ -static void crash(const char * /*fmt*/, ...); +static void crash(const char *fmt, ...); /** global variables **/ static int debug = 0; @@ -1852,7 +1857,7 @@ static add_target_ip_wrapper add_target_ip(char *arg, struct sockaddr_storage *a } /* wrapper for add_target_ip */ -static add_target_wrapper add_target(char *arg, const int mode) { +static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode mode) { struct sockaddr_storage address_storage; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index 2a521b04..58e13581 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -73,7 +73,7 @@ check_icmp_state check_icmp_state_init() { return tmp; } -rta_host_create_wrapper rta_host_create(char *name, struct sockaddr_storage *address) { +ping_target_create_wrapper ping_target_create(char *name, struct sockaddr_storage *address) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; if (address_family == AF_INET) { @@ -82,7 +82,7 @@ rta_host_create_wrapper rta_host_create(char *name, struct sockaddr_storage *add sin6 = (struct sockaddr_in6 *)address; } - rta_host_create_wrapper result = { + ping_target_create_wrapper result = { .errorcode = OK, }; diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h index 7e8a4d9f..3e798f72 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.h +++ b/plugins-root/check_icmp.d/check_icmp_helpers.h @@ -68,9 +68,9 @@ check_icmp_state check_icmp_state_init(); typedef struct { int errorcode; ping_target host; -} rta_host_create_wrapper; +} ping_target_create_wrapper; -rta_host_create_wrapper rta_host_create(char *name, struct sockaddr_storage *address); +ping_target_create_wrapper ping_target_create(char *name, struct sockaddr_storage *address); unsigned int ping_target_list_append(ping_target *list, ping_target *elem); void check_icmp_timeout_handler(int, siginfo_t *, void *); -- cgit v1.2.3-74-g34f1 From a01d522c4cac11eb31510758d42fe744eb21471d Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sat, 17 May 2025 11:26:54 +0200 Subject: WIP - check_icmp refactor 6 --- plugins-root/check_icmp.c | 704 ++++++++++++------------- plugins-root/check_icmp.d/check_icmp_helpers.c | 22 +- plugins-root/check_icmp.d/check_icmp_helpers.h | 13 +- plugins-root/check_icmp.d/config.h | 4 + 4 files changed, 360 insertions(+), 383 deletions(-) (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 8565f32d..34adf6fe 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -46,6 +46,8 @@ const char *email = "devel@monitoring-plugins.org"; #include "../plugins/common.h" #include "netutils.h" #include "utils.h" +#include "output.h" +#include "perfdata.h" #if HAVE_SYS_SOCKIO_H # include @@ -182,8 +184,7 @@ static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_s threshold_mode mode); /* main test function */ -static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, - bool jitter_mode, bool score_mode, int min_hosts_alive, +static void run_checks(check_icmp_mode_switches modes, int min_hosts_alive, unsigned short icmp_pkt_size, unsigned int *pkt_interval, unsigned int *target_interval, check_icmp_threshold warn, check_icmp_threshold crit, uint16_t sender_id, @@ -191,6 +192,8 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo struct timeval prog_start, ping_target **table, unsigned short packets, int icmp_sock, unsigned short number_of_targets, check_icmp_state *program_state, ping_target *target_list); +mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, + check_icmp_threshold warn, check_icmp_threshold crit); /* Target aquisition */ typedef struct { @@ -198,6 +201,7 @@ typedef struct { check_icmp_target_container host; } add_host_wrapper; static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode); + typedef struct { int error_code; ping_target *targets; @@ -216,11 +220,10 @@ static void parse_address(struct sockaddr_storage *addr, char *address, socklen_ static unsigned short icmp_checksum(uint16_t *packet, size_t packet_size); /* End of run function */ -static void finish(int /*sig*/, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, - bool jitter_mode, bool score_mode, int min_hosts_alive, +static void finish(int sign, check_icmp_mode_switches modes, int min_hosts_alive, check_icmp_threshold warn, check_icmp_threshold crit, int icmp_sock, unsigned short number_of_targets, check_icmp_state *program_state, - ping_target *target_list); + ping_target *target_list) __attribute__((noreturn)); /* Error exit */ static void crash(const char *fmt, ...); @@ -336,6 +339,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { /* Reset argument scanning */ optind = 1; + int host_counter = 0; /* parse the arguments */ for (int i = 1; i < argc; i++) { long int arg; @@ -391,15 +395,20 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { // TODO die here and complain about wrong input break; case 'H': { - add_target_wrapper add_result = add_target(optarg, result.config.mode); - if (add_result.error_code == OK) { + add_host_wrapper host_add_result = add_host(optarg, result.config.mode); + if (host_add_result.error_code == OK) { + result.config.hosts[host_counter] = host_add_result.host; + host_counter++; + if (result.config.targets != NULL) { - result.config.number_of_targets += - ping_target_list_append(result.config.targets, add_result.targets); + result.config.number_of_targets += ping_target_list_append( + result.config.targets, host_add_result.host.target_list); } else { - result.config.targets = add_result.targets; - result.config.number_of_targets += add_result.number_of_targets; + result.config.targets = host_add_result.host.target_list; + result.config.number_of_targets += host_add_result.host.number_of_targets; } + } else { + // TODO adding host failed, crash here } } break; case 'l': @@ -428,7 +437,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { result.config.warn = rta_th.warn; result.config.crit = rta_th.crit; - result.config.rta_mode = true; + result.config.modes.rta_mode = true; } break; case 'P': /* packet loss mode */ { get_threshold2_wrapper pl_th = @@ -440,7 +449,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { result.config.warn = pl_th.warn; result.config.crit = pl_th.crit; - result.config.pl_mode = true; + result.config.modes.pl_mode = true; } break; case 'J': /* jitter mode */ { get_threshold2_wrapper jitter_th = @@ -452,7 +461,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { result.config.warn = jitter_th.warn; result.config.crit = jitter_th.crit; - result.config.jitter_mode = true; + result.config.modes.jitter_mode = true; } break; case 'M': /* MOS mode */ { get_threshold2_wrapper mos_th = get_threshold2( @@ -463,7 +472,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { result.config.warn = mos_th.warn; result.config.crit = mos_th.crit; - result.config.mos_mode = true; + result.config.modes.mos_mode = true; } break; case 'S': /* score mode */ { get_threshold2_wrapper score_th = @@ -475,10 +484,10 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { result.config.warn = score_th.warn; result.config.crit = score_th.crit; - result.config.score_mode = true; + result.config.modes.score_mode = true; } break; case 'O': /* out of order mode */ - result.config.order_mode = true; + result.config.modes.order_mode = true; break; } } @@ -869,22 +878,19 @@ int main(int argc, char **argv) { check_icmp_state program_state = check_icmp_state_init(); - run_checks(config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode, - config.jitter_mode, config.score_mode, config.min_hosts_alive, config.icmp_data_size, + run_checks(config.modes, config.min_hosts_alive, config.icmp_data_size, &pkt_interval, &target_interval, config.warn, config.crit, config.sender_id, config.mode, max_completion_time, prog_start, table, config.number_of_packets, icmp_sock, config.number_of_targets, &program_state, config.targets); errno = 0; - finish(0, config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode, - config.jitter_mode, config.score_mode, config.min_hosts_alive, config.warn, config.crit, + finish(0, config.modes, config.min_hosts_alive, config.warn, config.crit, icmp_sock, config.number_of_targets, &program_state, config.targets); return (0); } -static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, - bool jitter_mode, bool score_mode, int min_hosts_alive, +static void run_checks(check_icmp_mode_switches modes, int min_hosts_alive, unsigned short icmp_pkt_size, unsigned int *pkt_interval, unsigned int *target_interval, check_icmp_threshold warn, check_icmp_threshold crit, const uint16_t sender_id, @@ -900,7 +906,7 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo for (unsigned int target_index = 0; target_index < number_of_targets; target_index++) { /* don't send useless packets */ if (!targets_alive(number_of_targets, program_state->targets_down)) { - finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode, + finish(0, modes, min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state, target_list); } @@ -947,7 +953,7 @@ static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mo if (debug) { printf("Time passed. Finishing up\n"); } - finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode, + finish(0, modes, min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state, target_list); } @@ -1139,7 +1145,7 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i /* Check if packets in order */ if (target->last_icmp_seq >= packet.icp->icmp_seq) { - target->order_status = STATE_CRITICAL; + target->found_out_of_order_packets = true; } } target->last_tdiff = tdiff; @@ -1376,8 +1382,7 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, return (ret); } -static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode, - bool jitter_mode, bool score_mode, int min_hosts_alive, +static void finish(int sig, check_icmp_mode_switches modes, int min_hosts_alive, check_icmp_threshold warn, check_icmp_threshold crit, const int icmp_sock, const unsigned short number_of_targets, check_icmp_state *program_state, ping_target *target_list) { @@ -1399,358 +1404,53 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool targets_alive(number_of_targets, program_state->targets_down)); } - /* iterate thrice to calculate values, give output, and print perfparse */ - mp_state_enum status = STATE_OK; - ping_target *host = target_list; + mp_check overall = mp_check_init(); - unsigned int target_counter = 0; - const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; + // loop over targets to evaluate each one + ping_target *host = target_list; int hosts_ok = 0; int hosts_warn = 0; while (host) { - mp_state_enum this_status = STATE_OK; - - unsigned char packet_loss; - double rta; - if (!host->icmp_recv) { - /* rta 0 is ofcourse not entirely correct, but will still show up - * conspicuously as missing entries in perfparse and cacti */ - packet_loss = 100; - rta = 0; - status = STATE_CRITICAL; - /* up the down counter if not already counted */ - if (!(host->flags & FLAG_LOST_CAUSE) && - targets_alive(number_of_targets, program_state->targets_down)) { - program_state->targets_down++; - } - } else { - packet_loss = - (unsigned char)((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent; - rta = (double)host->time_waited / host->icmp_recv; - } - - if (host->icmp_recv > 1) { - /* - * This algorithm is probably pretty much blindly copied from - * locations like this one: - * https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos It calculates a MOS - * value (range of 1 to 5, where 1 is bad and 5 really good). According to some quick - * research MOS originates from the Audio/Video transport network area. Whether it can - * and should be computed from ICMP data, I can not say. - * - * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value - * - * MOS stands likely for Mean Opinion Score ( - * https://en.wikipedia.org/wiki/Mean_Opinion_Score ) - * - * More links: - * - https://confluence.slac.stanford.edu/display/IEPM/MOS - */ - host->jitter = (host->jitter / (host->icmp_recv - 1) / 1000); - - /* - * Take the average round trip latency (in milliseconds), add - * round trip jitter, but double the impact to latency - * then add 10 for protocol latencies (in milliseconds). - */ - host->EffectiveLatency = (rta / 1000) + host->jitter * 2 + 10; - - double R; - if (host->EffectiveLatency < 160) { - R = 93.2 - (host->EffectiveLatency / 40); - } else { - R = 93.2 - ((host->EffectiveLatency - 120) / 10); - } - - // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a - // loss of 5% will be entered as 5). - R = R - (packet_loss * 2.5); - - if (R < 0) { - R = 0; - } - - host->score = R; - host->mos = 1 + ((0.035) * R) + ((.000007) * R * (R - 60) * (100 - R)); - } else { - host->jitter = 0; - host->jitter_min = 0; - host->jitter_max = 0; - host->mos = 0; - } - - host->pl = packet_loss; - host->rta = rta; - - /* if no new mode selected, use old schema */ - if (!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && !order_mode) { - rta_mode = true; - pl_mode = true; - } - - /* Check which mode is on and do the warn / Crit stuff */ - if (rta_mode) { - if (rta >= crit.rta) { - this_status = STATE_CRITICAL; - status = STATE_CRITICAL; - host->rta_status = STATE_CRITICAL; - } else if (status != STATE_CRITICAL && (rta >= warn.rta)) { - this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); - status = STATE_WARNING; - host->rta_status = STATE_WARNING; - } - } - - if (pl_mode) { - if (packet_loss >= crit.pl) { - this_status = STATE_CRITICAL; - status = STATE_CRITICAL; - host->pl_status = STATE_CRITICAL; - } else if (status != STATE_CRITICAL && (packet_loss >= warn.pl)) { - this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); - status = STATE_WARNING; - host->pl_status = STATE_WARNING; - } + if (host->flags & FLAG_LOST_CAUSE) { + program_state->targets_down++; } + // TODO call evaluate here + mp_subcheck sc_target = evaluate_target(*host, modes, warn, crit); - if (jitter_mode) { - if (host->jitter >= crit.jitter) { - this_status = STATE_CRITICAL; - status = STATE_CRITICAL; - host->jitter_status = STATE_CRITICAL; - } else if (status != STATE_CRITICAL && (host->jitter >= warn.jitter)) { - this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); - status = STATE_WARNING; - host->jitter_status = STATE_WARNING; - } - } + mp_add_subcheck_to_check(&overall, sc_target); - if (mos_mode) { - if (host->mos <= crit.mos) { - this_status = STATE_CRITICAL; - status = STATE_CRITICAL; - host->mos_status = STATE_CRITICAL; - } else if (status != STATE_CRITICAL && (host->mos <= warn.mos)) { - this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); - status = STATE_WARNING; - host->mos_status = STATE_WARNING; - } - } - - if (score_mode) { - if (host->score <= crit.score) { - this_status = STATE_CRITICAL; - status = STATE_CRITICAL; - host->score_status = STATE_CRITICAL; - } else if (status != STATE_CRITICAL && (host->score <= warn.score)) { - this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); - status = STATE_WARNING; - host->score_status = STATE_WARNING; - } - } - - if (this_status == STATE_WARNING) { - hosts_warn++; - } else if (this_status == STATE_OK) { + mp_state_enum target_state = mp_compute_subcheck_state(sc_target); + if (target_state == STATE_OK) { hosts_ok++; + } else if (target_state == STATE_WARNING) { + hosts_warn++; } host = host->next; } /* this is inevitable */ - if (!targets_alive(number_of_targets, program_state->targets_down)) { - status = STATE_CRITICAL; - } - if (min_hosts_alive > -1) { - if (hosts_ok >= min_hosts_alive) { - status = STATE_OK; - } else if ((hosts_ok + hosts_warn) >= min_hosts_alive) { - status = STATE_WARNING; - } - } - printf("%s - ", status_string[status]); - - host = target_list; - while (host) { - if (debug) { - puts(""); - } - - if (target_counter) { - if (target_counter < number_of_targets) { - printf(" :: "); - } else { - printf("\n"); - } - } - - target_counter++; - - if (!host->icmp_recv) { - status = STATE_CRITICAL; - host->rtmin = 0; - host->jitter_min = 0; - - if (host->flags & FLAG_LOST_CAUSE) { - char address[INET6_ADDRSTRLEN]; - parse_address(&host->error_addr, address, sizeof(address)); - printf("%s: %s @ %s. rta nan, lost %d%%", host->name, - get_icmp_error_msg(host->icmp_type, host->icmp_code), address, 100); - } else { /* not marked as lost cause, so we have no flags for it */ - printf("%s: rta nan, lost 100%%", host->name); - } - } else { /* !icmp_recv */ - printf("%s", host->name); - /* rta text output */ - if (rta_mode) { - if (status == STATE_OK) { - printf(" rta %0.3fms", host->rta / 1000); - } else if (status == STATE_WARNING && host->rta_status == status) { - printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, - (float)warn.rta / 1000); - } else if (status == STATE_CRITICAL && host->rta_status == status) { - printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, - (float)crit.rta / 1000); - } - } - - /* pl text output */ - if (pl_mode) { - if (status == STATE_OK) { - printf(" lost %u%%", host->pl); - } else if (status == STATE_WARNING && host->pl_status == status) { - printf(" lost %u%% > %u%%", host->pl, warn.pl); - } else if (status == STATE_CRITICAL && host->pl_status == status) { - printf(" lost %u%% > %u%%", host->pl, crit.pl); - } - } - - /* jitter text output */ - if (jitter_mode) { - if (status == STATE_OK) { - printf(" jitter %0.3fms", (float)host->jitter); - } else if (status == STATE_WARNING && host->jitter_status == status) { - printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, warn.jitter); - } else if (status == STATE_CRITICAL && host->jitter_status == status) { - printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, crit.jitter); - } - } - - /* mos text output */ - if (mos_mode) { - if (status == STATE_OK) { - printf(" MOS %0.1f", (float)host->mos); - } else if (status == STATE_WARNING && host->mos_status == status) { - printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)warn.mos); - } else if (status == STATE_CRITICAL && host->mos_status == status) { - printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)crit.mos); - } - } - - /* score text output */ - if (score_mode) { - if (status == STATE_OK) { - printf(" Score %u", (int)host->score); - } else if (status == STATE_WARNING && host->score_status == status) { - printf(" Score %u < %u", (int)host->score, (int)warn.score); - } else if (status == STATE_CRITICAL && host->score_status == status) { - printf(" Score %u < %u", (int)host->score, (int)crit.score); - } - } - - /* order statis text output */ - if (order_mode) { - if (status == STATE_OK) { - printf(" Packets in order"); - } else if (status == STATE_CRITICAL && host->order_status == status) { - printf(" Packets out of order"); - } - } - } - host = host->next; - } - - /* iterate once more for pretty perfparse output */ - if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) { - printf("|"); - } - - target_counter = 0; - host = target_list; - while (host) { - if (debug) { - puts(""); - } - - if (rta_mode) { - if (host->pl < 100) { - printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ", - (number_of_targets > 1) ? host->name : "", host->rta / 1000, - (float)warn.rta / 1000, (float)crit.rta / 1000, - (number_of_targets > 1) ? host->name : "", (float)host->rtmax / 1000, - (number_of_targets > 1) ? host->name : "", - (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0); - } else { - printf("%srta=U;;;; %srtmax=U;;;; %srtmin=U;;;; ", - (number_of_targets > 1) ? host->name : "", - (number_of_targets > 1) ? host->name : "", - (number_of_targets > 1) ? host->name : ""); - } - } - - if (pl_mode) { - printf("%spl=%u%%;%u;%u;0;100 ", (number_of_targets > 1) ? host->name : "", host->pl, - warn.pl, crit.pl); - } - - if (jitter_mode) { - if (host->pl < 100) { - printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; " - "%sjitter_min=%0.3fms;;;; ", - (number_of_targets > 1) ? host->name : "", (float)host->jitter, - (float)warn.jitter, (float)crit.jitter, - (number_of_targets > 1) ? host->name : "", (float)host->jitter_max / 1000, - (number_of_targets > 1) ? host->name : "", (float)host->jitter_min / 1000); - } else { - printf("%sjitter_avg=U;;;; %sjitter_max=U;;;; %sjitter_min=U;;;; ", - (number_of_targets > 1) ? host->name : "", - (number_of_targets > 1) ? host->name : "", - (number_of_targets > 1) ? host->name : ""); - } - } - - if (mos_mode) { - if (host->pl < 100) { - printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ", (number_of_targets > 1) ? host->name : "", - (float)host->mos, (float)warn.mos, (float)crit.mos); - } else { - printf("%smos=U;;;; ", (number_of_targets > 1) ? host->name : ""); - } - } - - if (score_mode) { - if (host->pl < 100) { - printf("%sscore=%u;%u;%u;0;100 ", (number_of_targets > 1) ? host->name : "", - (int)host->score, (int)warn.score, (int)crit.score); - } else { - printf("%sscore=U;;;; ", (number_of_targets > 1) ? host->name : ""); - } - } - - host = host->next; + if (targets_alive(number_of_targets, program_state->targets_down) == 0) { + mp_subcheck sc_no_target_alive = mp_subcheck_init(); + sc_no_target_alive = mp_set_subcheck_state(sc_no_target_alive, STATE_CRITICAL); + sc_no_target_alive.output = strdup("No target is alive!"); + mp_add_subcheck_to_check(&overall, sc_no_target_alive); } if (min_hosts_alive > -1) { + mp_subcheck sc_min_targets_alive = mp_subcheck_init(); + sc_min_targets_alive = mp_set_subcheck_default_state(sc_min_targets_alive, STATE_OK); + + // TODO problably broken now if (hosts_ok >= min_hosts_alive) { - status = STATE_OK; + // TODO this should overwrite the main state + sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_OK); } else if ((hosts_ok + hosts_warn) >= min_hosts_alive) { - status = STATE_WARNING; + sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_WARNING); } } /* finish with an empty line */ - puts(""); if (debug) { printf( "targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n", @@ -1758,7 +1458,7 @@ static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool hosts_ok, hosts_warn, min_hosts_alive); } - exit(status); + mp_exit(overall); } static time_t get_timevaldiff(const struct timeval earlier, const struct timeval later) { @@ -1825,7 +1525,7 @@ static add_target_ip_wrapper add_target_ip(char *arg, struct sockaddr_storage *a // } /* add the fresh ip */ - ping_target *target = (ping_target *)malloc(sizeof(ping_target)); + ping_target *target = (ping_target *)calloc(1, sizeof(ping_target)); if (!target) { char straddr[INET6_ADDRSTRLEN]; parse_address((struct sockaddr_storage *)&address, straddr, sizeof(straddr)); @@ -2339,3 +2039,289 @@ void print_usage(void) { printf("%s\n", _("Usage:")); printf(" %s [options] [-H] host1 host2 hostN\n", progname); } + +static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode) { + add_host_wrapper result = { + .error_code = OK, + .host = check_icmp_target_container_init(), + }; + + add_target_wrapper targets = add_target(arg, mode); + + if (targets.error_code != OK) { + result.error_code = targets.error_code; + return result; + } + + result.host = check_icmp_target_container_init(); + + result.host.name = strdup(arg); + result.host.target_list = targets.targets; + result.host.number_of_targets = targets.number_of_targets; + + return result; +} + +mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, + check_icmp_threshold warn, check_icmp_threshold crit) { + /* if no new mode selected, use old schema */ + if (!modes.rta_mode && !modes.pl_mode && !modes.jitter_mode && !modes.score_mode && !modes.mos_mode && !modes.order_mode) { + modes.rta_mode = true; + modes.pl_mode = true; + } + + mp_subcheck result = mp_subcheck_init(); + result = mp_set_subcheck_default_state(result, STATE_OK); + xasprintf(&result.output, "%s", target.name); + + double packet_loss; + double rta; + if (!target.icmp_recv) { + /* rta 0 is of course not entirely correct, but will still show up + * conspicuously as missing entries in perfparse and cacti */ + packet_loss = 100; + rta = 0; + result = mp_set_subcheck_state(result, STATE_CRITICAL); + /* up the down counter if not already counted */ + + if (target.flags & FLAG_LOST_CAUSE) { + char address[INET6_ADDRSTRLEN]; + parse_address(&target.error_addr, address, sizeof(address)); + xasprintf(&result.output, "%s: %s @ %s", result.output, + get_icmp_error_msg(target.icmp_type, target.icmp_code), address); + } else { /* not marked as lost cause, so we have no flags for it */ + xasprintf(&result.output, "%s", result.output); + } + } else { + packet_loss = + (unsigned char)((target.icmp_sent - target.icmp_recv) * 100) / target.icmp_sent; + rta = (double)target.time_waited / target.icmp_recv; + } + + double EffectiveLatency; + double mos; /* Mean opinion score */ + double score; /* score */ + + if (target.icmp_recv > 1) { + /* + * This algorithm is probably pretty much blindly copied from + * locations like this one: + * https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos It calculates a MOS + * value (range of 1 to 5, where 1 is bad and 5 really good). According to some quick + * research MOS originates from the Audio/Video transport network area. Whether it can + * and should be computed from ICMP data, I can not say. + * + * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value + * + * MOS stands likely for Mean Opinion Score ( + * https://en.wikipedia.org/wiki/Mean_Opinion_Score ) + * + * More links: + * - https://confluence.slac.stanford.edu/display/IEPM/MOS + */ + target.jitter = (target.jitter / (target.icmp_recv - 1) / 1000); + + /* + * Take the average round trip latency (in milliseconds), add + * round trip jitter, but double the impact to latency + * then add 10 for protocol latencies (in milliseconds). + */ + EffectiveLatency = (rta / 1000) + target.jitter * 2 + 10; + + double R; + if (EffectiveLatency < 160) { + R = 93.2 - (EffectiveLatency / 40); + } else { + R = 93.2 - ((EffectiveLatency - 120) / 10); + } + + // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a + // loss of 5% will be entered as 5). + R = R - (packet_loss * 2.5); + + if (R < 0) { + R = 0; + } + + score = R; + mos = 1 + ((0.035) * R) + ((.000007) * R * (R - 60) * (100 - R)); + } else { + target.jitter = 0; + target.jitter_min = 0; + target.jitter_max = 0; + mos = 0; + } + + /* Check which mode is on and do the warn / Crit stuff */ + if (modes.rta_mode) { + mp_subcheck sc_rta = mp_subcheck_init(); + sc_rta = mp_set_subcheck_default_state(sc_rta, STATE_OK); + xasprintf(&sc_rta.output, "rta %0.3fms", rta / 1000); + + if (rta >= crit.rta) { + sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL); + xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, crit.rta / 1000); + } else if (rta >= warn.rta) { + sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING); + xasprintf(&sc_rta.output, "%s > %0.3fms", sc_rta.output, warn.rta / 1000); + } + + if (packet_loss < 100) { + mp_perfdata pd_rta = perfdata_init(); + xasprintf(&pd_rta.label, "%srta", target.name); + pd_rta.uom = strdup("ms"); + pd_rta.value = mp_create_pd_value(rta / 1000); + pd_rta.min = mp_create_pd_value(0); + + pd_rta.warn = mp_range_set_end(pd_rta.warn, mp_create_pd_value(warn.rta)); + pd_rta.crit = mp_range_set_end(pd_rta.crit, mp_create_pd_value(crit.rta)); + mp_add_perfdata_to_subcheck(&sc_rta, pd_rta); + + mp_perfdata pd_rt_min = perfdata_init(); + xasprintf(&pd_rt_min.label, "%srtmin", target.name); + pd_rt_min.value = mp_create_pd_value(target.rtmin / 1000); + pd_rt_min.uom = strdup("ms"); + mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_min); + + mp_perfdata pd_rt_max = perfdata_init(); + xasprintf(&pd_rt_max.label, "%srtmax", target.name); + pd_rt_max.value = mp_create_pd_value(target.rtmax / 1000); + pd_rt_max.uom = strdup("ms"); + mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_max); + } + + mp_add_subcheck_to_subcheck(&result, sc_rta); + } + + if (modes.pl_mode) { + mp_subcheck sc_pl = mp_subcheck_init(); + sc_pl = mp_set_subcheck_default_state(sc_pl, STATE_OK); + xasprintf(&sc_pl.output, "packet loss %.1f%%", packet_loss); + + if (packet_loss >= crit.pl) { + sc_pl = mp_set_subcheck_state(sc_pl, STATE_CRITICAL); + xasprintf(&sc_pl.output, "%s > %u%%", sc_pl.output, crit.pl); + } else if (packet_loss >= warn.pl) { + sc_pl = mp_set_subcheck_state(sc_pl, STATE_WARNING); + xasprintf(&sc_pl.output, "%s > %u%%", sc_pl.output, crit.pl); + } + + mp_perfdata pd_pl = perfdata_init(); + xasprintf(&pd_pl.label, "%spl", target.name); + pd_pl.uom = strdup("%"); + + pd_pl.warn = mp_range_set_end(pd_pl.warn, mp_create_pd_value(warn.pl)); + pd_pl.crit = mp_range_set_end(pd_pl.crit, mp_create_pd_value(crit.pl)); + pd_pl.value = mp_create_pd_value(packet_loss); + + mp_add_perfdata_to_subcheck(&sc_pl, pd_pl); + + mp_add_subcheck_to_subcheck(&result, sc_pl); + } + + if (modes.jitter_mode) { + mp_subcheck sc_jitter = mp_subcheck_init(); + sc_jitter = mp_set_subcheck_default_state(sc_jitter, STATE_OK); + xasprintf(&sc_jitter.output, "jitter %0.3fms", target.jitter); + + if (target.jitter >= crit.jitter) { + sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_CRITICAL); + xasprintf(&sc_jitter.output, "%s > %0.3fms", sc_jitter.output, crit.jitter); + } else if (target.jitter >= warn.jitter) { + sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_WARNING); + xasprintf(&sc_jitter.output, "%s > %0.3fms", sc_jitter.output, warn.jitter); + } + + if (packet_loss < 100) { + mp_perfdata pd_jitter = perfdata_init(); + pd_jitter.uom = strdup("ms"); + xasprintf(&pd_jitter.label, "%sjitter_avg", target.name); + pd_jitter.value = mp_create_pd_value(target.jitter); + pd_jitter.warn = mp_range_set_end(pd_jitter.warn, mp_create_pd_value(warn.jitter)); + pd_jitter.crit = mp_range_set_end(pd_jitter.crit, mp_create_pd_value(crit.jitter)); + mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter); + + mp_perfdata pd_jitter_min = perfdata_init(); + pd_jitter_min.uom = strdup("ms"); + xasprintf(&pd_jitter_min.label, "%sjitter_min", target.name); + pd_jitter_min.value = mp_create_pd_value(target.jitter_min); + mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_min); + + mp_perfdata pd_jitter_max = perfdata_init(); + pd_jitter_max.uom = strdup("ms"); + xasprintf(&pd_jitter_max.label, "%sjitter_max", target.name); + pd_jitter_max.value = mp_create_pd_value(target.jitter_max); + mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_max); + } + mp_add_subcheck_to_subcheck(&result, sc_jitter); + } + + if (modes.mos_mode) { + mp_subcheck sc_mos = mp_subcheck_init(); + sc_mos = mp_set_subcheck_default_state(sc_mos, STATE_OK); + xasprintf(&sc_mos.output, "MOS %0.1f", mos); + + if (mos <= crit.mos) { + sc_mos = mp_set_subcheck_state(sc_mos, STATE_CRITICAL); + xasprintf(&sc_mos.output, "%s < %0.1f", sc_mos.output, crit.mos); + } else if (mos <= warn.mos) { + sc_mos = mp_set_subcheck_state(sc_mos, STATE_WARNING); + xasprintf(&sc_mos.output, "%s < %0.1f", sc_mos.output, warn.mos); + } + + if (packet_loss < 100) { + mp_perfdata pd_mos = perfdata_init(); + xasprintf(&pd_mos.label, "%smos", target.name); + pd_mos.value = mp_create_pd_value(mos); + pd_mos.warn = mp_range_set_end(pd_mos.warn, mp_create_pd_value(warn.mos)); + pd_mos.crit = mp_range_set_end(pd_mos.crit, mp_create_pd_value(crit.mos)); + pd_mos.min = mp_create_pd_value(0); + pd_mos.max = mp_create_pd_value(5); + mp_add_perfdata_to_subcheck(&sc_mos, pd_mos); + } + mp_add_subcheck_to_subcheck(&result, sc_mos); + } + + if (modes.score_mode) { + mp_subcheck sc_score = mp_subcheck_init(); + sc_score = mp_set_subcheck_default_state(sc_score, STATE_OK); + xasprintf(&sc_score.output, "Score %u", score); + + if (score <= crit.score) { + sc_score = mp_set_subcheck_state(sc_score, STATE_CRITICAL); + xasprintf(&sc_score.output, "%s < %u", sc_score.output, crit.score); + } else if (score <= warn.score) { + sc_score = mp_set_subcheck_state(sc_score, STATE_WARNING); + xasprintf(&sc_score.output, "%s < %u", sc_score.output, warn.score); + } + + if (packet_loss < 100) { + mp_perfdata pd_score = perfdata_init(); + xasprintf(&pd_score.label, "%sscore", target.name); + pd_score.value = mp_create_pd_value(score); + pd_score.warn = mp_range_set_end(pd_score.warn, mp_create_pd_value(warn.score)); + pd_score.crit = mp_range_set_end(pd_score.crit, mp_create_pd_value(crit.score)); + pd_score.min = mp_create_pd_value(0); + pd_score.max = mp_create_pd_value(100); + mp_add_perfdata_to_subcheck(&sc_score, pd_score); + } + + mp_add_subcheck_to_subcheck(&result, sc_score); + } + + if (modes.order_mode) { + mp_subcheck sc_order = mp_subcheck_init(); + sc_order = mp_set_subcheck_default_state(sc_order, STATE_OK); + + if (target.found_out_of_order_packets) { + mp_set_subcheck_state(sc_order, STATE_CRITICAL); + xasprintf(&sc_order.output, "Packets out of order"); + } else { + xasprintf(&sc_order.output, "Packets in order"); + } + + mp_add_subcheck_to_subcheck(&result, sc_order); + } + + return result; +} diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index 58e13581..a2b54c6a 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -10,12 +10,15 @@ unsigned int timeout = DEFAULT_TIMEOUT; check_icmp_config check_icmp_config_init() { check_icmp_config tmp = { - .order_mode = false, - .mos_mode = false, - .rta_mode = false, - .pl_mode = false, - .jitter_mode = false, - .score_mode = false, + .modes = + { + .order_mode = false, + .mos_mode = false, + .rta_mode = false, + .pl_mode = false, + .jitter_mode = false, + .score_mode = false, + }, .min_hosts_alive = -1, .crit = {.pl = DEFAULT_CRIT_PL, @@ -56,12 +59,7 @@ ping_target ping_target_init() { .jitter_min = INFINITY, - .rta_status = STATE_OK, - .jitter_status = STATE_OK, - .mos_status = STATE_OK, - .score_status = STATE_OK, - .pl_status = STATE_OK, - .order_status = STATE_OK, + .found_out_of_order_packets = false, }; return tmp; diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h index 3e798f72..68c39b4a 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.h +++ b/plugins-root/check_icmp.d/check_icmp_helpers.h @@ -20,7 +20,6 @@ typedef struct rta_host { unsigned char icmp_type, icmp_code; /* type and code from errors */ unsigned short flags; /* control/status flags */ - double rta; /* measured RTA */ double rtmax; /* max rtt */ double rtmin; /* min rtt */ @@ -28,20 +27,10 @@ typedef struct rta_host { double jitter_max; /* jitter rtt maximum */ double jitter_min; /* jitter rtt minimum */ - double EffectiveLatency; - double mos; /* Mean opinion score */ - double score; /* score */ - time_t last_tdiff; unsigned int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */ - unsigned char pl; /* measured packet loss */ - mp_state_enum rta_status; // check result for RTA checks - mp_state_enum jitter_status; // check result for Jitter checks - mp_state_enum mos_status; // check result for MOS checks - mp_state_enum score_status; // check result for score checks - mp_state_enum pl_status; // check result for packet loss checks - mp_state_enum order_status; // check result for packet order checks + bool found_out_of_order_packets; struct rta_host *next; } ping_target; diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h index 3599c0f0..aa33c991 100644 --- a/plugins-root/check_icmp.d/config.h +++ b/plugins-root/check_icmp.d/config.h @@ -48,6 +48,10 @@ typedef struct { bool pl_mode; bool jitter_mode; bool score_mode; +} check_icmp_mode_switches; + +typedef struct { + check_icmp_mode_switches modes; int min_hosts_alive; check_icmp_threshold crit; -- cgit v1.2.3-74-g34f1 From b5de682309589ddb230e04beaaa54d74f2fe70d5 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 18 May 2025 18:10:25 +0200 Subject: WIP - check_icmp refactor 8 --- plugins-root/check_icmp.c | 505 +++++++++++++++---------- plugins-root/check_icmp.d/check_icmp_helpers.c | 64 +--- plugins-root/check_icmp.d/check_icmp_helpers.h | 15 +- plugins-root/check_icmp.d/config.h | 3 + 4 files changed, 332 insertions(+), 255 deletions(-) (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 0614d6aa..d4e55b0d 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -71,6 +71,9 @@ const char *email = "devel@monitoring-plugins.org"; #include #include #include +#include +#include +#include #include "../lib/states.h" #include "./check_icmp.d/config.h" @@ -140,24 +143,31 @@ static time_t get_timevaldiff(struct timeval earlier, struct timeval later); static time_t get_timevaldiff_to_now(struct timeval earlier); static in_addr_t get_ip_address(const char *ifname); -static void set_source_ip(char *arg, int icmp_sock); +static void set_source_ip(char *arg, int icmp_sock, sa_family_t addr_family); /* Receiving data */ -static int wait_for_reply(int socket, time_t time_interval, unsigned short icmp_pkt_size, - unsigned int *pkt_interval, unsigned int *target_interval, - uint16_t sender_id, ping_target **table, unsigned short packets, - unsigned short number_of_targets, check_icmp_state *program_state); +static int wait_for_reply(check_icmp_socket_set sockset, time_t time_interval, + unsigned short icmp_pkt_size, unsigned int *pkt_interval, + unsigned int *target_interval, uint16_t sender_id, ping_target **table, + unsigned short packets, unsigned short number_of_targets, + check_icmp_state *program_state); -static ssize_t recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, - time_t *timeout, struct timeval *received_timestamp); +typedef struct { + sa_family_t recv_proto; + ssize_t received; +} recvfrom_wto_wrapper; +static recvfrom_wto_wrapper recvfrom_wto(check_icmp_socket_set sockset, void *buf, unsigned int len, + struct sockaddr *saddr, time_t *timeout, + struct timeval *received_timestamp); static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, unsigned int *pkt_interval, unsigned int *target_interval, uint16_t sender_id, ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); /* Sending data */ -static int send_icmp_ping(int socket, ping_target *host, unsigned short icmp_pkt_size, - uint16_t sender_id, check_icmp_state *program_state); +static int send_icmp_ping(check_icmp_socket_set socket, ping_target *host, + unsigned short icmp_pkt_size, uint16_t sender_id, + check_icmp_state *program_state); /* Threshold related */ typedef struct { @@ -188,7 +198,7 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, unsigned int *target_interval, uint16_t sender_id, check_icmp_execution_mode mode, unsigned int max_completion_time, struct timeval prog_start, ping_target **table, unsigned short packets, - int icmp_sock, unsigned short number_of_targets, + check_icmp_socket_set sockset, unsigned short number_of_targets, check_icmp_state *program_state); mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, check_icmp_threshold warn, check_icmp_threshold crit); @@ -206,15 +216,21 @@ evaluate_host_wrapper evaluate_host(check_icmp_target_container host, typedef struct { int error_code; check_icmp_target_container host; + bool has_v4; + bool has_v6; } add_host_wrapper; -static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode); +static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode, + sa_family_t enforced_proto); typedef struct { int error_code; ping_target *targets; unsigned int number_of_targets; + bool has_v4; + bool has_v6; } add_target_wrapper; -static add_target_wrapper add_target(char *arg, check_icmp_execution_mode mode); +static add_target_wrapper add_target(char *arg, check_icmp_execution_mode mode, + sa_family_t enforced_proto); typedef struct { int error_code; @@ -222,13 +238,13 @@ typedef struct { } add_target_ip_wrapper; static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address); -static void parse_address(struct sockaddr_storage *addr, char *address, socklen_t size); +static void parse_address(const struct sockaddr_storage *addr, char *dst, socklen_t size); static unsigned short icmp_checksum(uint16_t *packet, size_t packet_size); /* End of run function */ static void finish(int sign, check_icmp_mode_switches modes, int min_hosts_alive, - check_icmp_threshold warn, check_icmp_threshold crit, int icmp_sock, + check_icmp_threshold warn, check_icmp_threshold crit, unsigned short number_of_targets, check_icmp_state *program_state, check_icmp_target_container host_list[], unsigned short number_of_hosts, mp_check overall[static 1]); @@ -298,6 +314,8 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { } } + sa_family_t enforced_ai_family = AF_UNSPEC; + // Parse protocol arguments first // and count hosts here char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64"; @@ -306,16 +324,16 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { while ((arg = getopt(argc, argv, opts_str)) != EOF) { switch (arg) { case '4': - if (address_family != -1) { + if (enforced_ai_family != AF_UNSPEC) { crash("Multiple protocol versions not supported"); } - address_family = AF_INET; + enforced_ai_family = AF_INET; break; case '6': - if (address_family != -1) { + if (enforced_ai_family != AF_UNSPEC) { crash("Multiple protocol versions not supported"); } - address_family = AF_INET6; + enforced_ai_family = AF_INET6; break; case 'H': { result.config.number_of_hosts++; @@ -402,7 +420,8 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { // TODO die here and complain about wrong input break; case 'H': { - add_host_wrapper host_add_result = add_host(optarg, result.config.mode); + add_host_wrapper host_add_result = + add_host(optarg, result.config.mode, enforced_ai_family); if (host_add_result.error_code == OK) { result.config.hosts[host_counter] = host_add_result.host; host_counter++; @@ -414,6 +433,13 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { result.config.targets = host_add_result.host.target_list; result.config.number_of_targets += host_add_result.host.number_of_targets; } + + if (host_add_result.has_v4) { + result.config.need_v4 = true; + } + if (host_add_result.has_v6) { + result.config.need_v6 = true; + } } else { // TODO adding host failed, crash here } @@ -502,7 +528,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { argv = &argv[optind]; while (*argv) { - add_target(*argv, result.config.mode); + add_target(*argv, result.config.mode, enforced_ai_family); argv++; } @@ -704,9 +730,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad if (debug) { char address[INET6_ADDRSTRLEN]; parse_address(addr, address, sizeof(address)); - printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", - get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address, - host->name); + printf("Received \"%s\" from %s for ICMP ECHO sent.\n", + get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address); } program_state->icmp_lost++; @@ -732,14 +757,16 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad return 0; } -void parse_address(struct sockaddr_storage *addr, char *address, socklen_t size) { - switch (address_family) { +void parse_address(const struct sockaddr_storage *addr, char *dst, socklen_t size) { + switch (addr->ss_family) { case AF_INET: - inet_ntop(address_family, &((struct sockaddr_in *)addr)->sin_addr, address, size); + inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, dst, size); break; case AF_INET6: - inet_ntop(address_family, &((struct sockaddr_in6 *)addr)->sin6_addr, address, size); + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, dst, size); break; + default: + assert(false); } } @@ -748,9 +775,6 @@ int main(int argc, char **argv) { bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - address_family = -1; - int icmp_proto = IPPROTO_ICMP; - /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ environ = NULL; @@ -765,35 +789,68 @@ int main(int argc, char **argv) { const check_icmp_config config = tmp_config.config; + // int icmp_proto = IPPROTO_ICMP; // add_target might change address_family - switch (address_family) { - case AF_INET: - icmp_proto = IPPROTO_ICMP; - break; - case AF_INET6: - icmp_proto = IPPROTO_ICMPV6; - break; - default: - crash("Address family not supported"); - } + // switch (address_family) { + // case AF_INET: + // icmp_proto = IPPROTO_ICMP; + // break; + // case AF_INET6: + // icmp_proto = IPPROTO_ICMPV6; + // break; + // default: + // crash("Address family not supported"); + // } + + check_icmp_socket_set sockset = { + .socket4 = -1, + .socket6 = -1, + }; - int icmp_sock = socket(address_family, SOCK_RAW, icmp_proto); - if (icmp_sock == -1) { - crash("Failed to obtain ICMP socket"); - } + if (config.need_v4) { + sockset.socket4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (sockset.socket4 == -1) { + crash("Failed to obtain ICMP v4 socket"); + } - if (config.source_ip) { - set_source_ip(config.source_ip, icmp_sock); - } + if (config.source_ip) { + + struct in_addr tmp = {}; + int error_code = inet_pton(AF_INET, config.source_ip, &tmp); + if (error_code == 1) { + set_source_ip(config.source_ip, sockset.socket4, AF_INET); + } else { + // just try this mindlessly if it's not a v4 address + set_source_ip(config.source_ip, sockset.socket6, AF_INET6); + } + } #ifdef SO_TIMESTAMP - int on = 1; - if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) { - if (debug) { - printf("Warning: no SO_TIMESTAMP support\n"); + if (sockset.socket4 != -1) { + int on = 1; + if (setsockopt(sockset.socket4, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) { + if (debug) { + printf("Warning: no SO_TIMESTAMP support\n"); + } + } + } + if (sockset.socket6 != -1) { + int on = 1; + if (setsockopt(sockset.socket6, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) { + if (debug) { + printf("Warning: no SO_TIMESTAMP support\n"); + } + } } - } #endif // SO_TIMESTAMP + } + + if (config.need_v6) { + sockset.socket6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + if (sockset.socket6 == -1) { + crash("Failed to obtain ICMP v6 socket"); + } + } /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ if (setuid(getuid()) == -1) { @@ -801,8 +858,19 @@ int main(int argc, char **argv) { return 1; } - if (icmp_sock) { - int result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl)); + if (sockset.socket4) { + int result = setsockopt(sockset.socket4, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl)); + if (debug) { + if (result == -1) { + printf("setsockopt failed\n"); + } else { + printf("ttl set to %lu\n", config.ttl); + } + } + } + + if (sockset.socket6) { + int result = setsockopt(sockset.socket6, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl)); if (debug) { if (result == -1) { printf("setsockopt failed\n"); @@ -888,15 +956,22 @@ int main(int argc, char **argv) { run_checks(config.icmp_data_size, &pkt_interval, &target_interval, config.sender_id, config.mode, max_completion_time, prog_start, table, config.number_of_packets, - icmp_sock, config.number_of_targets, &program_state); + sockset, config.number_of_targets, &program_state); errno = 0; mp_check overall = mp_check_init(); - finish(0, config.modes, config.min_hosts_alive, config.warn, config.crit, icmp_sock, + finish(0, config.modes, config.min_hosts_alive, config.warn, config.crit, config.number_of_targets, &program_state, config.hosts, config.number_of_hosts, &overall); + if (sockset.socket4) { + close(sockset.socket4); + } + if (sockset.socket6) { + close(sockset.socket6); + } + mp_exit(overall); } @@ -904,7 +979,7 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, unsigned int *target_interval, const uint16_t sender_id, const check_icmp_execution_mode mode, const unsigned int max_completion_time, const struct timeval prog_start, ping_target **table, - const unsigned short packets, const int icmp_sock, + const unsigned short packets, const check_icmp_socket_set sockset, const unsigned short number_of_targets, check_icmp_state *program_state) { /* this loop might actually violate the pkt_interval or target_interval * settings, but only if there aren't any packets on the wire which @@ -917,20 +992,23 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, } if (table[target_index]->flags & FLAG_LOST_CAUSE) { if (debug) { - printf("%s is a lost cause. not sending any more\n", table[target_index]->name); + + char address[INET6_ADDRSTRLEN]; + parse_address(&table[target_index]->address, address, sizeof(address)); + printf("%s is a lost cause. not sending any more\n", address); } continue; } /* we're still in the game, so send next packet */ - (void)send_icmp_ping(icmp_sock, table[target_index], icmp_pkt_size, sender_id, + (void)send_icmp_ping(sockset, table[target_index], icmp_pkt_size, sender_id, program_state); /* wrap up if all targets are declared dead */ if (targets_alive(number_of_targets, program_state->targets_down) || get_timevaldiff(prog_start, prog_start) < max_completion_time || !(mode == MODE_HOSTCHECK && program_state->targets_down)) { - wait_for_reply(icmp_sock, *target_interval, icmp_pkt_size, pkt_interval, + wait_for_reply(sockset, *target_interval, icmp_pkt_size, pkt_interval, target_interval, sender_id, table, packets, number_of_targets, program_state); } @@ -938,9 +1016,9 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, if (targets_alive(number_of_targets, program_state->targets_down) || get_timevaldiff_to_now(prog_start) < max_completion_time || !(mode == MODE_HOSTCHECK && program_state->targets_down)) { - wait_for_reply(icmp_sock, *pkt_interval * number_of_targets, icmp_pkt_size, - pkt_interval, target_interval, sender_id, table, packets, - number_of_targets, program_state); + wait_for_reply(sockset, *pkt_interval * number_of_targets, icmp_pkt_size, pkt_interval, + target_interval, sender_id, table, packets, number_of_targets, + program_state); } } @@ -970,7 +1048,7 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, if (targets_alive(number_of_targets, program_state->targets_down) || get_timevaldiff_to_now(prog_start) < max_completion_time || !(mode == MODE_HOSTCHECK && program_state->targets_down)) { - wait_for_reply(icmp_sock, final_wait, icmp_pkt_size, pkt_interval, target_interval, + wait_for_reply(sockset, final_wait, icmp_pkt_size, pkt_interval, target_interval, sender_id, table, packets, number_of_targets, program_state); } } @@ -986,10 +1064,11 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, * both: * icmp echo reply : the rest */ -static int wait_for_reply(int sock, const time_t time_interval, unsigned short icmp_pkt_size, - unsigned int *pkt_interval, unsigned int *target_interval, - uint16_t sender_id, ping_target **table, const unsigned short packets, - const unsigned short number_of_targets, check_icmp_state *program_state) { +static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_interval, + unsigned short icmp_pkt_size, unsigned int *pkt_interval, + unsigned int *target_interval, uint16_t sender_id, ping_target **table, + const unsigned short packets, const unsigned short number_of_targets, + check_icmp_state *program_state) { union icmp_packet packet; if (!(packet.buf = malloc(icmp_pkt_size))) { crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); @@ -1022,25 +1101,25 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i time_t loop_time_interval = per_pkt_wait; /* reap responses until we hit a timeout */ - ssize_t n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, - &loop_time_interval, &packet_received_timestamp); - if (!n) { + recvfrom_wto_wrapper recv_foo = + recvfrom_wto(sockset, buf, sizeof(buf), (struct sockaddr *)&resp_addr, + &loop_time_interval, &packet_received_timestamp); + if (!recv_foo.received) { if (debug > 1) { printf("recvfrom_wto() timed out during a %ld usecs wait\n", per_pkt_wait); } continue; /* timeout for this one, so keep trying */ } - if (n < 0) { + if (recv_foo.received < 0) { if (debug) { printf("recvfrom_wto() returned errors\n"); } free(packet.buf); - return (int)n; + return (int)recv_foo.received; } - // FIXME: with ipv6 we don't have an ip header here - if (address_family != AF_INET6) { + if (recv_foo.recv_proto != AF_INET6) { ip_header = (union ip_hdr *)buf; if (debug > 1) { @@ -1053,38 +1132,21 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i } } - /* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ - /* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ - /* alpha headers are decidedly broken. Using an ansi compiler, - * they provide ip_vhl instead of ip_hl and ip_v, so we mask - * off the bottom 4 bits */ - /* hlen = (ip->ip_vhl & 0x0f) << 2; */ - /* #else */ - int hlen = (address_family == AF_INET6) ? 0 : ip_header->ip.ip_hl << 2; - /* #endif */ - - if (n < (hlen + ICMP_MINLEN)) { + int hlen = (recv_foo.recv_proto == AF_INET6) ? 0 : ip_header->ip.ip_hl << 2; + + if (recv_foo.received < (hlen + ICMP_MINLEN)) { char address[INET6_ADDRSTRLEN]; parse_address(&resp_addr, address, sizeof(address)); - crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", n, - hlen + icmp_pkt_size, address); + crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", + recv_foo.received, hlen + icmp_pkt_size, address); } - /* else if(debug) { */ - /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ - /* hlen, ntohs(ip->ip_len) - hlen, */ - /* sizeof(struct ip), icmp_pkt_size); */ - /* } */ - /* check the response */ - memcpy(packet.buf, buf + hlen, icmp_pkt_size); - /* address_family == AF_INET6 ? sizeof(struct icmp6_hdr) - : sizeof(struct icmp));*/ - if ((address_family == PF_INET && + if ((recv_foo.recv_proto == AF_INET && (ntohs(packet.icp->icmp_id) != sender_id || packet.icp->icmp_type != ICMP_ECHOREPLY || ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) || - (address_family == PF_INET6 && + (recv_foo.recv_proto == AF_INET6 && (ntohs(packet.icp6->icmp6_id) != sender_id || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) { @@ -1101,7 +1163,7 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i /* this is indeed a valid response */ ping_target *target; struct icmp_ping_data data; - if (address_family == PF_INET) { + if (address_family == AF_INET) { memcpy(&data, packet.icp->icmp_data, sizeof(data)); if (debug > 2) { printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data), @@ -1171,7 +1233,7 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i char address[INET6_ADDRSTRLEN]; parse_address(&resp_addr, address, sizeof(address)); - switch (address_family) { + switch (recv_foo.recv_proto) { case AF_INET: { printf("%0.3f ms rtt from %s, incoming ttl: %u, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, address, ip_header->ip.ip_ttl, @@ -1191,23 +1253,14 @@ static int wait_for_reply(int sock, const time_t time_interval, unsigned short i } /* the ping functions */ -static int send_icmp_ping(const int sock, ping_target *host, const unsigned short icmp_pkt_size, - const uint16_t sender_id, check_icmp_state *program_state) { - if (sock == -1) { - errno = 0; - crash("Attempt to send on bogus socket"); - return -1; - } - - void *buf = NULL; - +static int send_icmp_ping(const check_icmp_socket_set sockset, ping_target *host, + const unsigned short icmp_pkt_size, const uint16_t sender_id, + check_icmp_state *program_state) { + void *buf = calloc(1, icmp_pkt_size); if (!buf) { - if (!(buf = malloc(icmp_pkt_size))) { - crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); - return -1; /* might be reached if we're in debug mode */ - } + crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); + return -1; /* might be reached if we're in debug mode */ } - memset(buf, 0, icmp_pkt_size); struct timeval current_time; if ((gettimeofday(¤t_time, NULL)) == -1) { @@ -1221,7 +1274,7 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor socklen_t addrlen; - if (address_family == AF_INET) { + if (host->address.ss_family == AF_INET) { struct icmp *icp = (struct icmp *)buf; addrlen = sizeof(struct sockaddr_in); @@ -1235,11 +1288,14 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size); if (debug > 2) { + char address[INET6_ADDRSTRLEN]; + parse_address((&host->address), address, sizeof(address)); + printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum, - host->name); + address); } - } else { + } else if (host->address.ss_family == AF_INET6) { struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf; addrlen = sizeof(struct sockaddr_in6); @@ -1253,10 +1309,16 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor // let checksum be calculated automatically if (debug > 2) { - printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", + char address[INET6_ADDRSTRLEN]; + parse_address((&host->address), address, sizeof(address)); + + printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to target %s\n", sizeof(data), ntohs(icp6->icmp6_id), ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, - host->name); + address); } + } else { + // unknown address family + crash("unknown address family in ", __func__); } struct iovec iov; @@ -1266,7 +1328,7 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor struct msghdr hdr; memset(&hdr, 0, sizeof(hdr)); - hdr.msg_name = (struct sockaddr *)&host->saddr_in; + hdr.msg_name = (struct sockaddr *)&host->address; hdr.msg_namelen = addrlen; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; @@ -1274,19 +1336,29 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor errno = 0; long int len; -/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ + /* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ + if (host->address.ss_family == AF_INET) { #ifdef MSG_CONFIRM - len = sendmsg(sock, &hdr, MSG_CONFIRM); + len = sendmsg(sockset.socket4, &hdr, MSG_CONFIRM); #else - len = sendmsg(sock, &hdr, 0); + len = sendmsg(sockset.socket4, &hdr, 0); #endif + } else if (host->address.ss_family == AF_INET6) { +#ifdef MSG_CONFIRM + len = sendmsg(sockset.socket6, &hdr, MSG_CONFIRM); +#else + len = sendmsg(sockset.socket6, &hdr, 0); +#endif + } else { + assert(false); + } free(buf); if (len < 0 || (unsigned int)len != icmp_pkt_size) { if (debug) { char address[INET6_ADDRSTRLEN]; - parse_address((&host->saddr_in), address, sizeof(address)); + parse_address((&host->address), address, sizeof(address)); printf("Failed to send ping to %s: %s\n", address, strerror(errno)); } errno = 0; @@ -1299,9 +1371,9 @@ static int send_icmp_ping(const int sock, ping_target *host, const unsigned shor return 0; } -static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, - struct sockaddr *saddr, time_t *timeout, - struct timeval *received_timestamp) { +static recvfrom_wto_wrapper recvfrom_wto(const check_icmp_socket_set sockset, void *buf, + const unsigned int len, struct sockaddr *saddr, + time_t *timeout, struct timeval *received_timestamp) { #ifdef HAVE_MSGHDR_MSG_CONTROL char ans_data[4096]; #endif // HAVE_MSGHDR_MSG_CONTROL @@ -1309,11 +1381,16 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, struct cmsghdr *chdr; #endif + recvfrom_wto_wrapper result = { + .received = 0, + .recv_proto = AF_UNSPEC, + }; + if (!*timeout) { if (debug) { printf("*timeout is not\n"); } - return 0; + return result; } struct timeval real_timeout; @@ -1327,13 +1404,21 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, // Read fds for select with the socket fd_set read_fds; FD_ZERO(&read_fds); - FD_SET(sock, &read_fds); + + if (sockset.socket4 != -1) { + FD_SET(sockset.socket4, &read_fds); + } + if (sockset.socket6 != -1) { + FD_SET(sockset.socket6, &read_fds); + } + + int nfds = (sockset.socket4 > sockset.socket6 ? sockset.socket4 : sockset.socket6) + 1; struct timeval then; gettimeofday(&then, NULL); errno = 0; - int select_return = select(sock + 1, &read_fds, &dummy_write_fds, NULL, &real_timeout); + int select_return = select(nfds, &read_fds, &dummy_write_fds, NULL, &real_timeout); if (select_return < 0) { crash("select() in recvfrom_wto"); } @@ -1343,7 +1428,7 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, *timeout = get_timevaldiff(then, now); if (!select_return) { - return 0; /* timeout */ + return result; /* timeout */ } unsigned int slen = sizeof(struct sockaddr_storage); @@ -1364,7 +1449,18 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, #endif }; - ssize_t ret = recvmsg(sock, &hdr, 0); + ssize_t ret; + if (FD_ISSET(sockset.socket4, &read_fds)) { + ret = recvmsg(sockset.socket4, &hdr, 0); + result.recv_proto = AF_INET; + } else if (FD_ISSET(sockset.socket6, &read_fds)) { + ret = recvmsg(sockset.socket6, &hdr, 0); + result.recv_proto = AF_INET6; + } else { + assert(false); + } + + result.received = ret; #ifdef SO_TIMESTAMP for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) { @@ -1382,11 +1478,11 @@ static ssize_t recvfrom_wto(const int sock, void *buf, const unsigned int len, gettimeofday(tv, NULL); #endif // SO_TIMESTAMP - return (ret); + return (result); } static void finish(int sig, check_icmp_mode_switches modes, int min_hosts_alive, - check_icmp_threshold warn, check_icmp_threshold crit, const int icmp_sock, + check_icmp_threshold warn, check_icmp_threshold crit, const unsigned short number_of_targets, check_icmp_state *program_state, check_icmp_target_container host_list[], unsigned short number_of_hosts, mp_check overall[static 1]) { @@ -1397,10 +1493,6 @@ static void finish(int sig, check_icmp_mode_switches modes, int min_hosts_alive, printf("finish(%d) called\n", sig); } - if (icmp_sock != -1) { - close(icmp_sock); - } - if (debug) { printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", program_state->icmp_sent, program_state->icmp_recv, program_state->icmp_lost); @@ -1476,17 +1568,21 @@ static time_t get_timevaldiff_to_now(struct timeval earlier) { } static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address) { + assert((address.ss_family == AF_INET) || (address.ss_family == AF_INET6)); + if (debug) { char straddr[INET6_ADDRSTRLEN]; - parse_address((struct sockaddr_storage *)&address, straddr, sizeof(straddr)); + parse_address((&address), straddr, sizeof(straddr)); printf("add_target_ip called with: %s\n", straddr); } struct sockaddr_in *sin; struct sockaddr_in6 *sin6; - if (address_family == AF_INET) { + if (address.ss_family == AF_INET) { sin = (struct sockaddr_in *)&address; - } else { + } else if (address.ss_family == AF_INET6) { sin6 = (struct sockaddr_in6 *)&address; + } else { + assert(false); } add_target_ip_wrapper result = { @@ -1496,9 +1592,9 @@ static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address) { /* disregard obviously stupid addresses * (I didn't find an ipv6 equivalent to INADDR_NONE) */ - if (((address_family == AF_INET && + if (((address.ss_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) || - (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { + (address.ss_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { result.error_code = ERROR; return result; } @@ -1513,32 +1609,21 @@ static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address) { crash("add_target_ip(%s): malloc(%lu) failed", straddr, sizeof(ping_target)); } - *target = ping_target_init(); + ping_target_create_wrapper target_wrapper = ping_target_create(address); - /* set the values. use calling name for output */ - target->name = strdup(straddr); - - /* fill out the sockaddr_storage struct */ - struct sockaddr_in *host_sin; - struct sockaddr_in6 *host_sin6; - if (address_family == AF_INET) { - host_sin = (struct sockaddr_in *)&target->saddr_in; - host_sin->sin_family = AF_INET; - host_sin->sin_addr.s_addr = sin->sin_addr.s_addr; + if (target_wrapper.errorcode == OK) { + *target = target_wrapper.host; + result.target = target; } else { - host_sin6 = (struct sockaddr_in6 *)&target->saddr_in; - host_sin6->sin6_family = AF_INET6; - memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, - sizeof host_sin6->sin6_addr.s6_addr); + result.error_code = target_wrapper.errorcode; } - result.target = target; - return result; } /* wrapper for add_target_ip */ -static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode mode) { +static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode mode, + sa_family_t enforced_proto) { if (debug > 0) { printf("add_target called with argument %s\n", arg); } @@ -1548,30 +1633,31 @@ static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode struct sockaddr_in6 *sin6 = NULL; int error_code = -1; - switch (address_family) { - case -1: - /* -4 and -6 are not specified on cmdline */ - address_family = AF_INET; + switch (enforced_proto) { + case AF_UNSPEC: + /* + * no enforced protocoll family + * try to parse the address with each one + */ sin = (struct sockaddr_in *)&address_storage; - error_code = inet_pton(address_family, arg, &sin->sin_addr); + error_code = inet_pton(AF_INET, arg, &sin->sin_addr); + address_storage.ss_family = AF_INET; if (error_code != 1) { - address_family = AF_INET6; sin6 = (struct sockaddr_in6 *)&address_storage; - error_code = inet_pton(address_family, arg, &sin6->sin6_addr); - } - /* If we don't find any valid addresses, we still don't know the address_family */ - if (error_code != 1) { - address_family = -1; + error_code = inet_pton(AF_INET6, arg, &sin6->sin6_addr); + address_storage.ss_family = AF_INET6; } break; case AF_INET: sin = (struct sockaddr_in *)&address_storage; - error_code = inet_pton(address_family, arg, &sin->sin_addr); + error_code = inet_pton(AF_INET, arg, &sin->sin_addr); + address_storage.ss_family = AF_INET; break; case AF_INET6: sin6 = (struct sockaddr_in6 *)&address_storage; - error_code = inet_pton(address_family, arg, &sin6->sin6_addr); + error_code = inet_pton(AF_INET, arg, &sin6->sin6_addr); + address_storage.ss_family = AF_INET6; break; default: crash("Address family not supported"); @@ -1580,9 +1666,11 @@ static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode add_target_wrapper result = { .error_code = OK, .targets = NULL, + .has_v4 = false, + .has_v6 = false, }; - /* don't resolve if we don't have to */ + // if error_code == 1 the address was a valid address parsed above if (error_code == 1) { /* don't add all ip's if we were given a specific one */ add_target_ip_wrapper targeted = add_target_ip(address_storage); @@ -1592,19 +1680,21 @@ static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode return result; } + if (targeted.target->address.ss_family == AF_INET) { + result.has_v4 = true; + } else if (targeted.target->address.ss_family == AF_INET6) { + result.has_v6 = true; + } else { + assert(false); + } result.targets = targeted.target; result.number_of_targets = 1; return result; } - struct addrinfo hints; + struct addrinfo hints = {}; errno = 0; - memset(&hints, 0, sizeof(hints)); - if (address_family == -1) { - hints.ai_family = AF_UNSPEC; - } else { - hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6; - } + hints.ai_family = enforced_proto; hints.ai_socktype = SOCK_RAW; int error; @@ -1615,7 +1705,6 @@ static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode result.error_code = ERROR; return result; } - address_family = res->ai_family; /* possibly add all the IP's as targets */ for (struct addrinfo *address = res; address != NULL; address = address->ai_next) { @@ -1634,6 +1723,11 @@ static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode } else { result.number_of_targets += ping_target_list_append(result.targets, tmp.target); } + if (address->ai_family == AF_INET) { + result.has_v4 = true; + } else if (address->ai_family == AF_INET6) { + result.has_v6 = true; + } } /* this is silly, but it works */ @@ -1652,11 +1746,11 @@ static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode return result; } -static void set_source_ip(char *arg, const int icmp_sock) { +static void set_source_ip(char *arg, const int icmp_sock, sa_family_t addr_family) { struct sockaddr_in src; memset(&src, 0, sizeof(src)); - src.sin_family = address_family; + src.sin_family = addr_family; if ((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) { src.sin_addr.s_addr = get_ip_address(arg); } @@ -2026,7 +2120,8 @@ void print_usage(void) { printf(" %s [options] [-H] host1 host2 hostN\n", progname); } -static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode) { +static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode, + sa_family_t enforced_proto) { if (debug) { printf("add_host called with argument %s\n", arg); } @@ -2034,15 +2129,20 @@ static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode) { add_host_wrapper result = { .error_code = OK, .host = check_icmp_target_container_init(), + .has_v4 = false, + .has_v6 = false, }; - add_target_wrapper targets = add_target(arg, mode); + add_target_wrapper targets = add_target(arg, mode, enforced_proto); if (targets.error_code != OK) { result.error_code = targets.error_code; return result; } + result.has_v4 = targets.has_v4; + result.has_v6 = targets.has_v6; + result.host = check_icmp_target_container_init(); result.host.name = strdup(arg); @@ -2063,7 +2163,12 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, mp_subcheck result = mp_subcheck_init(); result = mp_set_subcheck_default_state(result, STATE_OK); - xasprintf(&result.output, "%s", target.name); + + char address[INET6_ADDRSTRLEN]; + memset(address, 0, INET6_ADDRSTRLEN); + parse_address(&target.address, address, sizeof(address)); + + xasprintf(&result.output, "%s", address); double packet_loss; double rta; @@ -2076,8 +2181,6 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, /* up the down counter if not already counted */ if (target.flags & FLAG_LOST_CAUSE) { - char address[INET6_ADDRSTRLEN]; - parse_address(&target.error_addr, address, sizeof(address)); xasprintf(&result.output, "%s: %s @ %s", result.output, get_icmp_error_msg(target.icmp_type, target.icmp_code), address); } else { /* not marked as lost cause, so we have no flags for it */ @@ -2159,7 +2262,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, if (packet_loss < 100) { mp_perfdata pd_rta = perfdata_init(); - xasprintf(&pd_rta.label, "%srta", target.name); + xasprintf(&pd_rta.label, "%srta", address); pd_rta.uom = strdup("ms"); pd_rta.value = mp_create_pd_value(rta / 1000); pd_rta.min = mp_create_pd_value(0); @@ -2169,13 +2272,13 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, mp_add_perfdata_to_subcheck(&sc_rta, pd_rta); mp_perfdata pd_rt_min = perfdata_init(); - xasprintf(&pd_rt_min.label, "%srtmin", target.name); + xasprintf(&pd_rt_min.label, "%srtmin", address); pd_rt_min.value = mp_create_pd_value(target.rtmin / 1000); pd_rt_min.uom = strdup("ms"); mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_min); mp_perfdata pd_rt_max = perfdata_init(); - xasprintf(&pd_rt_max.label, "%srtmax", target.name); + xasprintf(&pd_rt_max.label, "%srtmax", address); pd_rt_max.value = mp_create_pd_value(target.rtmax / 1000); pd_rt_max.uom = strdup("ms"); mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_max); @@ -2198,7 +2301,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, } mp_perfdata pd_pl = perfdata_init(); - xasprintf(&pd_pl.label, "%spl", target.name); + xasprintf(&pd_pl.label, "%spl", address); pd_pl.uom = strdup("%"); pd_pl.warn = mp_range_set_end(pd_pl.warn, mp_create_pd_value(warn.pl)); @@ -2226,7 +2329,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, if (packet_loss < 100) { mp_perfdata pd_jitter = perfdata_init(); pd_jitter.uom = strdup("ms"); - xasprintf(&pd_jitter.label, "%sjitter_avg", target.name); + xasprintf(&pd_jitter.label, "%sjitter_avg", address); pd_jitter.value = mp_create_pd_value(target.jitter); pd_jitter.warn = mp_range_set_end(pd_jitter.warn, mp_create_pd_value(warn.jitter)); pd_jitter.crit = mp_range_set_end(pd_jitter.crit, mp_create_pd_value(crit.jitter)); @@ -2234,13 +2337,13 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, mp_perfdata pd_jitter_min = perfdata_init(); pd_jitter_min.uom = strdup("ms"); - xasprintf(&pd_jitter_min.label, "%sjitter_min", target.name); + xasprintf(&pd_jitter_min.label, "%sjitter_min", address); pd_jitter_min.value = mp_create_pd_value(target.jitter_min); mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_min); mp_perfdata pd_jitter_max = perfdata_init(); pd_jitter_max.uom = strdup("ms"); - xasprintf(&pd_jitter_max.label, "%sjitter_max", target.name); + xasprintf(&pd_jitter_max.label, "%sjitter_max", address); pd_jitter_max.value = mp_create_pd_value(target.jitter_max); mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_max); } @@ -2262,7 +2365,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, if (packet_loss < 100) { mp_perfdata pd_mos = perfdata_init(); - xasprintf(&pd_mos.label, "%smos", target.name); + xasprintf(&pd_mos.label, "%smos", address); pd_mos.value = mp_create_pd_value(mos); pd_mos.warn = mp_range_set_end(pd_mos.warn, mp_create_pd_value(warn.mos)); pd_mos.crit = mp_range_set_end(pd_mos.crit, mp_create_pd_value(crit.mos)); @@ -2288,7 +2391,7 @@ mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, if (packet_loss < 100) { mp_perfdata pd_score = perfdata_init(); - xasprintf(&pd_score.label, "%sscore", target.name); + xasprintf(&pd_score.label, "%sscore", address); pd_score.value = mp_create_pd_value(score); pd_score.warn = mp_range_set_end(pd_score.warn, mp_create_pd_value(warn.score)); pd_score.crit = mp_range_set_end(pd_score.crit, mp_create_pd_value(crit.score)); diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index a2b54c6a..47604952 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -1,7 +1,7 @@ #include "./config.h" -#include "states.h" #include #include +#include #include "./check_icmp_helpers.h" #include "../../plugins/netutils.h" @@ -38,7 +38,10 @@ check_icmp_config check_icmp_config_init() { .pkt_interval = DEFAULT_PKT_INTERVAL, .target_interval = 0, .number_of_packets = DEFAULT_NUMBER_OF_PACKETS, + .source_ip = NULL, + .need_v4 = false, + .need_v6 = false, .sender_id = {}, @@ -71,68 +74,31 @@ check_icmp_state check_icmp_state_init() { return tmp; } -ping_target_create_wrapper ping_target_create(char *name, struct sockaddr_storage *address) { - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - if (address_family == AF_INET) { - sin = (struct sockaddr_in *)address; - } else { - sin6 = (struct sockaddr_in6 *)address; - } - +ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) { ping_target_create_wrapper result = { .errorcode = OK, }; + struct sockaddr_storage *tmp_addr = &address; + /* disregard obviously stupid addresses * (I didn't find an ipv6 equivalent to INADDR_NONE) */ - if (((address_family == AF_INET && - (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) || - (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { + if (((tmp_addr->ss_family == AF_INET && + (((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_NONE || + ((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) || + (tmp_addr->ss_family == AF_INET6 && + (((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) { result.errorcode = ERROR; return result; } - // TODO: Maybe add the following back in as a sanity check for the config - // /* no point in adding two identical IP's, so don't. ;) */ - // struct sockaddr_in *host_sin; - // struct sockaddr_in6 *host_sin6; - // struct rta_host *host = host_list; - - // while (host) { - // host_sin = (struct sockaddr_in *)&host->saddr_in; - // host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; - - // if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) || - // (address_family == AF_INET6 && - // host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) { - // if (debug) { - // printf("Identical IP already exists. Not adding %s\n", name); - // } - // return -1; - // } - // host = host->next; - // } - /* add the fresh ip */ - ping_target host = ping_target_init(); - - /* set the values. use calling name for output */ - host.name = strdup(name); + ping_target target = ping_target_init(); /* fill out the sockaddr_storage struct */ - if (address_family == AF_INET) { - struct sockaddr_in *host_sin = (struct sockaddr_in *)&host.saddr_in; - host_sin->sin_family = AF_INET; - host_sin->sin_addr.s_addr = sin->sin_addr.s_addr; - } else { - struct sockaddr_in6 *host_sin6 = (struct sockaddr_in6 *)&host.saddr_in; - host_sin6->sin6_family = AF_INET6; - memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, - sizeof host_sin6->sin6_addr.s6_addr); - } + target.address = address; - result.host = host; + result.host = target; return result; } diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h index 5f771635..713dd8ce 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.h +++ b/plugins-root/check_icmp.d/check_icmp_helpers.h @@ -10,10 +10,10 @@ #include typedef struct rta_host { - unsigned short id; /* id in **table, and icmp pkts */ - char *name; /* arg used for adding this host */ - char *msg; /* icmp error message, if any */ - struct sockaddr_storage saddr_in; /* the address of this host */ + unsigned short id; /* id in **table, and icmp pkts */ + char *msg; /* icmp error message, if any */ + + struct sockaddr_storage address; /* the address of this host */ struct sockaddr_storage error_addr; /* stores address of error replies */ time_t time_waited; /* total time waited, in usecs */ unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */ @@ -59,7 +59,12 @@ typedef struct { ping_target host; } ping_target_create_wrapper; -ping_target_create_wrapper ping_target_create(char *name, struct sockaddr_storage *address); +typedef struct { + int socket4; + int socket6; +} check_icmp_socket_set; + +ping_target_create_wrapper ping_target_create(struct sockaddr_storage address); unsigned int ping_target_list_append(ping_target *list, ping_target *elem); void check_icmp_timeout_handler(int, siginfo_t *, void *); diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h index aa33c991..8e9c96b2 100644 --- a/plugins-root/check_icmp.d/config.h +++ b/plugins-root/check_icmp.d/config.h @@ -63,7 +63,10 @@ typedef struct { unsigned int pkt_interval; unsigned int target_interval; unsigned short number_of_packets; + char *source_ip; + bool need_v4; + bool need_v6; uint16_t sender_id; // PID of the main process, which is used as an ID in packets -- cgit v1.2.3-74-g34f1 From d92bbaef8386e77c00ecdeab9fc722fa4b9106b0 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 18 May 2025 18:46:30 +0200 Subject: Some more fixes --- plugins-root/check_icmp.c | 53 +++++++++++++------------- plugins-root/check_icmp.d/check_icmp_helpers.c | 2 +- plugins-root/check_icmp.d/check_icmp_helpers.h | 4 +- plugins-root/check_icmp.d/config.h | 4 +- 4 files changed, 31 insertions(+), 32 deletions(-) (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index d4e55b0d..43eae276 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -147,8 +147,8 @@ static void set_source_ip(char *arg, int icmp_sock, sa_family_t addr_family); /* Receiving data */ static int wait_for_reply(check_icmp_socket_set sockset, time_t time_interval, - unsigned short icmp_pkt_size, unsigned int *pkt_interval, - unsigned int *target_interval, uint16_t sender_id, ping_target **table, + unsigned short icmp_pkt_size, time_t *pkt_interval, + time_t *target_interval, uint16_t sender_id, ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); @@ -160,12 +160,12 @@ static recvfrom_wto_wrapper recvfrom_wto(check_icmp_socket_set sockset, void *bu struct sockaddr *saddr, time_t *timeout, struct timeval *received_timestamp); static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, - unsigned int *pkt_interval, unsigned int *target_interval, - uint16_t sender_id, ping_target **table, unsigned short packets, + time_t *pkt_interval, time_t *target_interval, uint16_t sender_id, + ping_target **table, unsigned short packets, unsigned short number_of_targets, check_icmp_state *program_state); /* Sending data */ -static int send_icmp_ping(check_icmp_socket_set socket, ping_target *host, +static int send_icmp_ping(check_icmp_socket_set sockset, ping_target *host, unsigned short icmp_pkt_size, uint16_t sender_id, check_icmp_state *program_state); @@ -194,12 +194,11 @@ static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_s threshold_mode mode); /* main test function */ -static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, - unsigned int *target_interval, uint16_t sender_id, - check_icmp_execution_mode mode, unsigned int max_completion_time, - struct timeval prog_start, ping_target **table, unsigned short packets, - check_icmp_socket_set sockset, unsigned short number_of_targets, - check_icmp_state *program_state); +static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, + uint16_t sender_id, check_icmp_execution_mode mode, + unsigned int max_completion_time, struct timeval prog_start, + ping_target **table, unsigned short packets, check_icmp_socket_set sockset, + unsigned short number_of_targets, check_icmp_state *program_state); mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes, check_icmp_threshold warn, check_icmp_threshold crit); @@ -683,7 +682,7 @@ static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icm } static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr, - unsigned int *pkt_interval, unsigned int *target_interval, + time_t *pkt_interval, time_t *target_interval, const uint16_t sender_id, ping_target **table, unsigned short packets, const unsigned short number_of_targets, check_icmp_state *program_state) { @@ -899,7 +898,7 @@ int main(int argc, char **argv) { struct timeval prog_start; gettimeofday(&prog_start, NULL); - unsigned int max_completion_time = + time_t max_completion_time = ((config.number_of_targets * config.number_of_packets * config.pkt_interval) + (config.number_of_targets * config.target_interval)) + (config.number_of_targets * config.number_of_packets * config.crit.rta) + config.crit.rta; @@ -916,15 +915,15 @@ int main(int argc, char **argv) { if (debug) { if (max_completion_time > (timeout * 1000000)) { - printf("max_completion_time: %u timeout: %u\n", max_completion_time, timeout); - printf("Timeout must be at least %u\n", (max_completion_time / 1000000) + 1); + printf("max_completion_time: %ld timeout: %u\n", max_completion_time, timeout); + printf("Timeout must be at least %ld\n", (max_completion_time / 1000000) + 1); } } if (debug) { printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", config.crit.rta, config.crit.pl, config.warn.rta, config.warn.pl); - printf("pkt_interval: %u target_interval: %u\n", config.pkt_interval, + printf("pkt_interval: %ld target_interval: %ld\n", config.pkt_interval, config.target_interval); printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_pkt_size, timeout); } @@ -949,8 +948,8 @@ int main(int argc, char **argv) { target_index++; } - unsigned int pkt_interval = config.pkt_interval; - unsigned int target_interval = config.target_interval; + time_t pkt_interval = config.pkt_interval; + time_t target_interval = config.target_interval; check_icmp_state program_state = check_icmp_state_init(); @@ -975,12 +974,12 @@ int main(int argc, char **argv) { mp_exit(overall); } -static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, - unsigned int *target_interval, const uint16_t sender_id, - const check_icmp_execution_mode mode, const unsigned int max_completion_time, - const struct timeval prog_start, ping_target **table, - const unsigned short packets, const check_icmp_socket_set sockset, - const unsigned short number_of_targets, check_icmp_state *program_state) { +static void run_checks(unsigned short icmp_pkt_size, time_t *pkt_interval, time_t *target_interval, + const uint16_t sender_id, const check_icmp_execution_mode mode, + const unsigned int max_completion_time, const struct timeval prog_start, + ping_target **table, const unsigned short packets, + const check_icmp_socket_set sockset, const unsigned short number_of_targets, + check_icmp_state *program_state) { /* this loop might actually violate the pkt_interval or target_interval * settings, but only if there aren't any packets on the wire which * indicates that the target can handle an increased packet rate */ @@ -1065,8 +1064,8 @@ static void run_checks(unsigned short icmp_pkt_size, unsigned int *pkt_interval, * icmp echo reply : the rest */ static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_interval, - unsigned short icmp_pkt_size, unsigned int *pkt_interval, - unsigned int *target_interval, uint16_t sender_id, ping_target **table, + unsigned short icmp_pkt_size, time_t *pkt_interval, + time_t *target_interval, uint16_t sender_id, ping_target **table, const unsigned short packets, const unsigned short number_of_targets, check_icmp_state *program_state) { union icmp_packet packet; @@ -1568,7 +1567,7 @@ static time_t get_timevaldiff_to_now(struct timeval earlier) { } static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address) { - assert((address.ss_family == AF_INET) || (address.ss_family == AF_INET6)); + assert((address.ss_family == AF_INET) || (address.ss_family == AF_INET6)); if (debug) { char straddr[INET6_ADDRSTRLEN]; diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index 47604952..7a936cc9 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -43,7 +43,7 @@ check_icmp_config check_icmp_config_init() { .need_v4 = false, .need_v6 = false, - .sender_id = {}, + .sender_id = 0, .mode = MODE_RTA, diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h index 713dd8ce..1b9372ce 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.h +++ b/plugins-root/check_icmp.d/check_icmp_helpers.h @@ -9,7 +9,7 @@ #include #include -typedef struct rta_host { +typedef struct ping_target { unsigned short id; /* id in **table, and icmp pkts */ char *msg; /* icmp error message, if any */ @@ -32,7 +32,7 @@ typedef struct rta_host { bool found_out_of_order_packets; - struct rta_host *next; + struct ping_target *next; } ping_target; ping_target ping_target_init(); diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h index 8e9c96b2..97be7fc1 100644 --- a/plugins-root/check_icmp.d/config.h +++ b/plugins-root/check_icmp.d/config.h @@ -60,8 +60,8 @@ typedef struct { unsigned long ttl; unsigned short icmp_data_size; unsigned short icmp_pkt_size; - unsigned int pkt_interval; - unsigned int target_interval; + time_t pkt_interval; + time_t target_interval; unsigned short number_of_packets; char *source_ip; -- cgit v1.2.3-74-g34f1 From 2bea8e9522af1c454d1a6a618402f9f342730406 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:04:34 +0200 Subject: check_icmp: Remove signal handling and timeouts The timeout option was redundant in that the runtime of check_icmp was always limited by the input parameters and therefore timeout gets removed with this commit to avoid that confusion. The rest of the signal handlings was removed too, since the added complexity does not provide sufficient returns. If check_icmp gets a signal, it now dies like most other programs instead of trying to save some things and return a (arguably wrong) result. --- plugins-root/check_icmp.c | 18 +--------------- plugins-root/check_icmp.d/check_icmp_helpers.c | 19 ---------------- plugins-root/check_icmp.d/check_icmp_helpers.h | 2 -- plugins-root/t/check_icmp.t | 30 +++++++++++++------------- 4 files changed, 16 insertions(+), 53 deletions(-) (limited to 'plugins-root/check_icmp.d/check_icmp_helpers.c') diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 7360b435..55405b8a 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -431,8 +431,7 @@ check_icmp_config_wrapper process_arguments(int argc, char **argv) { } break; case 't': - timeout = (unsigned int)strtoul(optarg, NULL, 0); - // TODO die here and complain about wrong input + // WARNING Deprecated since execution time is determined by the other factors break; case 'H': { add_host_wrapper host_add_result = @@ -895,21 +894,6 @@ int main(int argc, char **argv) { } } - struct sigaction sig_action; - sig_action.sa_handler = NULL; - sig_action.sa_sigaction = check_icmp_timeout_handler; - sigfillset(&sig_action.sa_mask); - sig_action.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO; - - sigaction(SIGINT, &sig_action, NULL); - sigaction(SIGHUP, &sig_action, NULL); - sigaction(SIGTERM, &sig_action, NULL); - sigaction(SIGALRM, &sig_action, NULL); - if (debug) { - printf("Setting alarm timeout to %u seconds\n", timeout); - } - alarm(timeout); - /* make sure we don't wait any longer than necessary */ struct timeval prog_start; gettimeofday(&prog_start, NULL); diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c index 7a936cc9..ec786305 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.c +++ b/plugins-root/check_icmp.d/check_icmp_helpers.c @@ -132,22 +132,3 @@ unsigned int ping_target_list_append(ping_target *list, ping_target *elem) { return result; } - -void check_icmp_timeout_handler(int signal, siginfo_t *info, void *ucontext) { - // Ignore unused arguments - (void)info; - (void)ucontext; - mp_subcheck timeout_sc = mp_subcheck_init(); - timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state); - - if (signal == SIGALRM) { - xasprintf(&timeout_sc.output, _("timeout after %d seconds\n"), timeout); - } else { - xasprintf(&timeout_sc.output, _("timeout after %d seconds\n"), timeout); - } - - mp_check overall = mp_check_init(); - mp_add_subcheck_to_check(&overall, timeout_sc); - - mp_exit(overall); -} diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h index 1b9372ce..dc6ea40b 100644 --- a/plugins-root/check_icmp.d/check_icmp_helpers.h +++ b/plugins-root/check_icmp.d/check_icmp_helpers.h @@ -66,5 +66,3 @@ typedef struct { ping_target_create_wrapper ping_target_create(struct sockaddr_storage address); unsigned int ping_target_list_append(ping_target *list, ping_target *elem); - -void check_icmp_timeout_handler(int, siginfo_t *, void *); diff --git a/plugins-root/t/check_icmp.t b/plugins-root/t/check_icmp.t index 2c1d12e6..e68617cd 100644 --- a/plugins-root/t/check_icmp.t +++ b/plugins-root/t/check_icmp.t @@ -33,12 +33,12 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID", my $res; $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -w 10000ms,100% -c 10000ms,100%" + "$sudo ./check_icmp -H $host_responsive -w 100ms,100% -c 100ms,100%" ); is( $res->return_code, 0, "Syntax ok" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 10000ms,100%" + "$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 100ms,100%" ); is( $res->return_code, 1, "Syntax ok, with forced warning" ); @@ -48,32 +48,32 @@ $res = NPTest->testCmd( is( $res->return_code, 2, "Syntax ok, with forced critical" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -t 2" + "$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100%" ); is( $res->return_code, 2, "Timeout - host nonresponsive" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -w 10000ms,100% -c 10000ms,100%" + "$sudo ./check_icmp -w 100ms,100% -c 100ms,100%" ); is( $res->return_code, 3, "No hostname" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 0 -t 2" + "$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 0" ); is( $res->return_code, 0, "One host nonresponsive - zero required" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 1 -t 2" + "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 1" ); is( $res->return_code, 0, "One of two host nonresponsive - one required" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 2" + "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 2" ); is( $res->return_code, 2, "One of two host nonresponsive - two required" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 10000ms,100% -c 10000ms,100% -n 1 -m 2" + "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 100ms,100% -c 100ms,100% -n 1 -m 2" ); is( $res->return_code, 0, "IPv4 source_ip accepted" ); @@ -83,35 +83,35 @@ $res = NPTest->testCmd( is( $res->return_code, 0, "Try max packet size" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1 -t 2" + "$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1" ); is( $res->return_code, 0, "rta works" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1 -t 2" + "$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1" ); is( $res->return_code, 0, "pl works" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -J 80,90 -t 2" + "$sudo ./check_icmp -H $host_responsive -J 80,90" ); is( $res->return_code, 0, "jitter works" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -M 4,3 -t 2" + "$sudo ./check_icmp -H $host_responsive -M 4,3" ); is( $res->return_code, 0, "mos works" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -S 80,70 -t 2" + "$sudo ./check_icmp -H $host_responsive -S 80,70" ); is( $res->return_code, 0, "score works" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -O -t 2" + "$sudo ./check_icmp -H $host_responsive -O" ); is( $res->return_code, 0, "order works" ); $res = NPTest->testCmd( - "$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100 -t 2" + "$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100" ); is( $res->return_code, 0, "order works" ); -- cgit v1.2.3-74-g34f1