From b35853ee4e10c4485a9521d77c95aecae6573e64 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:08:59 +0100 Subject: check_ntp_time: implement modern output --- plugins/check_ntp_time.c | 160 ++++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 78 deletions(-) (limited to 'plugins/check_ntp_time.c') diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index ad69b804..eee9c298 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c @@ -34,12 +34,10 @@ * *****************************************************************************/ -const char *progname = "check_ntp_time"; -const char *copyright = "2006-2024"; -const char *email = "devel@monitoring-plugins.org"; - +#include "output.h" #include "common.h" #include "netutils.h" +#include "perfdata.h" #include "utils.h" #include "states.h" #include "thresholds.h" @@ -47,6 +45,10 @@ const char *email = "devel@monitoring-plugins.org"; static int verbose = 0; +const char *progname = "check_ntp_time"; +const char *copyright = "2006-2024"; +const char *email = "devel@monitoring-plugins.org"; + typedef struct { int errorcode; check_ntp_time_config config; @@ -61,9 +63,6 @@ void print_usage(void); # define AVG_NUM 4 #endif -/* max size of control message data */ -#define MAX_CM_SIZE 468 - /* this structure holds everything in an ntp request/response as per rfc1305 */ typedef struct { uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ @@ -169,7 +168,9 @@ typedef struct { : 0) /* convert a struct timeval to a double */ -#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec)) +static double TVasDOUBLE(struct timeval time) { + return ((double)time.tv_sec + (0.000001 * (double)time.tv_usec)); +} /* convert an ntp 64-bit fp number to a struct timeval */ #define NTP64toTV(n, t) \ @@ -262,8 +263,8 @@ void setup_request(ntp_message *message) { /* select the "best" server from a list of servers, and return its index. * this is done by filtering servers based on stratum, dispersion, and * finally round-trip delay. */ -int best_offset_server(const ntp_server_results *slist, int nservers) { - int best_server = -1; +static int best_offset_server(const ntp_server_results *slist, int nservers) { + int best_server_index = -1; /* for each server */ for (int cserver = 0; cserver < nservers; cserver++) { @@ -286,33 +287,33 @@ int best_offset_server(const ntp_server_results *slist, int nservers) { } /* If we don't have a server yet, use the first one */ - if (best_server == -1) { - best_server = cserver; - DBG(printf("using peer %d as our first candidate\n", best_server)); + if (best_server_index == -1) { + best_server_index = cserver; + DBG(printf("using peer %d as our first candidate\n", best_server_index)); continue; } /* compare the server to the best one we've seen so far */ /* does it have an equal or better stratum? */ - DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); - if (slist[cserver].stratum <= slist[best_server].stratum) { - DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); + DBG(printf("comparing peer %d with peer %d\n", cserver, best_server_index)); + if (slist[cserver].stratum <= slist[best_server_index].stratum) { + DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server_index)); /* does it have an equal or better dispersion? */ - if (slist[cserver].rtdisp <= slist[best_server].rtdisp) { - DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); + if (slist[cserver].rtdisp <= slist[best_server_index].rtdisp) { + DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server_index)); /* does it have a better rtdelay? */ - if (slist[cserver].rtdelay < slist[best_server].rtdelay) { - DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); - best_server = cserver; - DBG(printf("peer %d is now our best candidate\n", best_server)); + if (slist[cserver].rtdelay < slist[best_server_index].rtdelay) { + DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server_index)); + best_server_index = cserver; + DBG(printf("peer %d is now our best candidate\n", best_server_index)); } } } } - if (best_server >= 0) { - DBG(printf("best server selected: peer %d\n", best_server)); - return best_server; + if (best_server_index >= 0) { + DBG(printf("best server selected: peer %d\n", best_server_index)); + return best_server_index; } DBG(printf("no peers meeting synchronization criteria :(\n")); return -1; @@ -323,7 +324,11 @@ int best_offset_server(const ntp_server_results *slist, int nservers) { * we don't waste time sitting around waiting for single packets. * - we also "manually" handle resolving host names and connecting, because * we have to do it in a way that our lazy macros don't handle currently :( */ -double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) { +typedef struct { + mp_state_enum offset_result; + double offset; +} offset_request_wrapper; +static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset) { /* setup hints to only return results from getaddrinfo that we'd like */ struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); @@ -462,11 +467,16 @@ double offset_request(const char *host, const char *port, mp_state_enum *status, die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); } + offset_request_wrapper result = { + .offset = 0, + .offset_result = STATE_UNKNOWN, + }; + /* now, pick the best server from the list */ double avg_offset = 0.; int best_index = best_offset_server(servers, num_hosts); if (best_index < 0) { - *status = STATE_UNKNOWN; + result.offset_result = STATE_UNKNOWN; } else { /* finally, calculate the average offset */ for (int i = 0; i < servers[best_index].num_responses; i++) { @@ -488,10 +498,12 @@ double offset_request(const char *host, const char *port, mp_state_enum *status, if (verbose) { printf("overall average offset: %.10g\n", avg_offset); } - return avg_offset; + + result.offset = avg_offset; + return result; } -check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { +static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { static struct option longopts[] = {{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, @@ -515,9 +527,6 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { .config = check_ntp_time_config_init(), }; - char *owarn = "60"; - char *ocrit = "120"; - while (true) { int option = 0; int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); @@ -540,12 +549,24 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { case 'q': result.config.quiet = true; break; - case 'w': - owarn = optarg; - break; - case 'c': - ocrit = optarg; - break; + case 'w': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse warning threshold"); + } + + result.config.offset_thresholds = + mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range); + } break; + case 'c': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse crit threshold"); + } + + result.config.offset_thresholds = + mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range); + } break; case 'H': if (!is_host(optarg)) { usage2(_("Invalid hostname/address"), optarg); @@ -582,16 +603,9 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { usage4(_("Hostname was not supplied")); } - set_thresholds(&result.config.offset_thresholds, owarn, ocrit); - return result; } -char *perfd_offset(double offset, thresholds *offset_thresholds) { - return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, - offset_thresholds->critical->end, false, 0, false, 0); -} - int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); @@ -614,46 +628,36 @@ int main(int argc, char *argv[]) { /* set socket timeout */ alarm(socket_timeout); - mp_state_enum offset_result = STATE_OK; - mp_state_enum result = STATE_OK; - double offset = - offset_request(config.server_address, config.port, &offset_result, config.time_offset); - if (offset_result == STATE_UNKNOWN) { - result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL); - } else { - result = get_status(fabs(offset), config.offset_thresholds); - } + mp_check overall = mp_check_init(); - char *result_line; - switch (result) { - case STATE_CRITICAL: - xasprintf(&result_line, _("NTP CRITICAL:")); - break; - case STATE_WARNING: - xasprintf(&result_line, _("NTP WARNING:")); - break; - case STATE_OK: - xasprintf(&result_line, _("NTP OK:")); - break; - default: - xasprintf(&result_line, _("NTP UNKNOWN:")); - break; - } + mp_subcheck sc_offset = mp_subcheck_init(); + offset_request_wrapper offset_result = + offset_request(config.server_address, config.port, config.time_offset); - char *perfdata_line; - if (offset_result == STATE_UNKNOWN) { - xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); - xasprintf(&perfdata_line, ""); - } else { - xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); - xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds)); + if (offset_result.offset_result == STATE_UNKNOWN) { + sc_offset = + mp_set_subcheck_state(sc_offset, (!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL); + xasprintf(&sc_offset.output, "Offset unknown"); + mp_add_subcheck_to_check(&overall, sc_offset); + mp_exit(overall); } - printf("%s|%s\n", result_line, perfdata_line); + + xasprintf(&sc_offset.output, "Offset: %.10g s", offset_result.offset); + + mp_perfdata pd_offset = perfdata_init(); + pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset)); + pd_offset.label = "offset"; + pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds); + + sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset)); + + mp_add_perfdata_to_subcheck(&sc_offset, pd_offset); + mp_add_subcheck_to_check(&overall, sc_offset); if (config.server_address != NULL) { free(config.server_address); } - exit(result); + mp_exit(overall); } void print_help(void) { -- cgit v1.2.3-74-g34f1 From 16daa06e439da1541cbcb4e0622131838b21ba0f Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:41:34 +0100 Subject: check_ntp_time: actually accept offset if known --- plugins/check_ntp_time.c | 1 + 1 file changed, 1 insertion(+) (limited to 'plugins/check_ntp_time.c') diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index eee9c298..d554089d 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c @@ -478,6 +478,7 @@ static offset_request_wrapper offset_request(const char *host, const char *port, if (best_index < 0) { result.offset_result = STATE_UNKNOWN; } else { + result.offset_result = STATE_OK; /* finally, calculate the average offset */ for (int i = 0; i < servers[best_index].num_responses; i++) { avg_offset += servers[best_index].offset[i]; -- cgit v1.2.3-74-g34f1 From cadcfaecbec56d2ecf44bb33bb394ca815240127 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:42:12 +0100 Subject: check_ntp_time: fix time-offset argument and description --- plugins/check_ntp_time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/check_ntp_time.c') diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index d554089d..8d97f2b9 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c @@ -511,7 +511,7 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'}, - {"time-offset", optional_argument, 0, 'o'}, + {"time-offset", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {"timeout", required_argument, 0, 't'}, @@ -682,7 +682,7 @@ void print_help(void) { printf(" %s\n", _("Offset to result in warning status (seconds)")); printf(" %s\n", "-c, --critical=THRESHOLD"); printf(" %s\n", _("Offset to result in critical status (seconds)")); - printf(" %s\n", "-o, --time_offset=INTEGER"); + printf(" %s\n", "-o, --time-offset=INTEGER"); printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); printf(UT_VERBOSE); -- cgit v1.2.3-74-g34f1 From 7b226257b7df01dd80af07c39e0f49fdcf84cee4 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:42:43 +0100 Subject: check_ntp_time: reduce number of significant bits a bit --- plugins/check_ntp_time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'plugins/check_ntp_time.c') diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index 8d97f2b9..7c3fc24d 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c @@ -643,11 +643,12 @@ int main(int argc, char *argv[]) { mp_exit(overall); } - xasprintf(&sc_offset.output, "Offset: %.10g s", offset_result.offset); + xasprintf(&sc_offset.output, "Offset: %.6fs", offset_result.offset); mp_perfdata pd_offset = perfdata_init(); pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset)); pd_offset.label = "offset"; + pd_offset.uom = "s"; pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds); sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset)); -- cgit v1.2.3-74-g34f1 From 71e0d5e0732225e95affbacd1a08f2a8513d2802 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 5 Nov 2025 12:19:20 +0100 Subject: check_ntp_time: add cli option for output format --- plugins/check_ntp_time.c | 22 ++++++++++++++++++++++ plugins/check_ntp_time.d/config.h | 6 ++++++ 2 files changed, 28 insertions(+) (limited to 'plugins/check_ntp_time.c') diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index 7c3fc24d..602b6010 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c @@ -505,6 +505,11 @@ static offset_request_wrapper offset_request(const char *host, const char *port, } static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { + + enum { + output_format_index = CHAR_MAX + 1, + }; + static struct option longopts[] = {{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, @@ -517,6 +522,7 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { {"timeout", required_argument, 0, 't'}, {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, + {"output-format", required_argument, 0, output_format_index}, {0, 0, 0, 0}}; if (argc < 2) { @@ -536,6 +542,17 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { } switch (option_char) { + case output_format_index: { + parsed_output_format parser = mp_parse_output_format(optarg); + if (!parser.parsing_success) { + printf("Invalid output format: %s\n", optarg); + exit(STATE_UNKNOWN); + } + + result.config.output_format_is_set = true; + result.config.output_format = parser.output_format; + break; + } case 'h': print_help(); exit(STATE_UNKNOWN); @@ -623,6 +640,10 @@ int main(int argc, char *argv[]) { const check_ntp_time_config config = tmp_config.config; + if (config.output_format_is_set) { + mp_set_format(config.output_format); + } + /* initialize alarm signal handling */ signal(SIGALRM, socket_timeout_alarm_handler); @@ -687,6 +708,7 @@ void print_help(void) { printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); printf(UT_VERBOSE); + printf(UT_OUTPUT_FORMAT); printf("\n"); printf("%s\n", _("This plugin checks the clock offset between the local host and a")); diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h index a62e4ceb..9bbd82aa 100644 --- a/plugins/check_ntp_time.d/config.h +++ b/plugins/check_ntp_time.d/config.h @@ -1,6 +1,7 @@ #pragma once #include "../../config.h" +#include "output.h" #include "thresholds.h" #include @@ -12,6 +13,9 @@ typedef struct { int time_offset; mp_thresholds offset_thresholds; + + bool output_format_is_set; + mp_output_format output_format; } check_ntp_time_config; check_ntp_time_config check_ntp_time_config_init() { @@ -23,6 +27,8 @@ check_ntp_time_config check_ntp_time_config_init() { .time_offset = 0, .offset_thresholds = mp_thresholds_init(), + + .output_format_is_set = false, }; mp_range warning = mp_range_init(); -- cgit v1.2.3-74-g34f1