summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-11-04 12:08:59 +0100
committerLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-11-04 12:08:59 +0100
commitb35853ee4e10c4485a9521d77c95aecae6573e64 (patch)
tree29402e5bbf420523682d3ef4357e609c93f8526f /plugins
parentbb9fcf5bfaf34aeffd651919b5a14b631b9fceb4 (diff)
downloadmonitoring-plugins-b35853ee4e10c4485a9521d77c95aecae6573e64.tar.gz
check_ntp_time: implement modern output
Diffstat (limited to 'plugins')
-rw-r--r--plugins/check_ntp_time.c160
-rw-r--r--plugins/check_ntp_time.d/config.h13
2 files changed, 93 insertions, 80 deletions
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 @@
34 * 34 *
35 *****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_ntp_time"; 37#include "output.h"
38const char *copyright = "2006-2024";
39const char *email = "devel@monitoring-plugins.org";
40
41#include "common.h" 38#include "common.h"
42#include "netutils.h" 39#include "netutils.h"
40#include "perfdata.h"
43#include "utils.h" 41#include "utils.h"
44#include "states.h" 42#include "states.h"
45#include "thresholds.h" 43#include "thresholds.h"
@@ -47,6 +45,10 @@ const char *email = "devel@monitoring-plugins.org";
47 45
48static int verbose = 0; 46static int verbose = 0;
49 47
48const char *progname = "check_ntp_time";
49const char *copyright = "2006-2024";
50const char *email = "devel@monitoring-plugins.org";
51
50typedef struct { 52typedef struct {
51 int errorcode; 53 int errorcode;
52 check_ntp_time_config config; 54 check_ntp_time_config config;
@@ -61,9 +63,6 @@ void print_usage(void);
61# define AVG_NUM 4 63# define AVG_NUM 4
62#endif 64#endif
63 65
64/* max size of control message data */
65#define MAX_CM_SIZE 468
66
67/* this structure holds everything in an ntp request/response as per rfc1305 */ 66/* this structure holds everything in an ntp request/response as per rfc1305 */
68typedef struct { 67typedef struct {
69 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 68 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
@@ -169,7 +168,9 @@ typedef struct {
169 : 0) 168 : 0)
170 169
171/* convert a struct timeval to a double */ 170/* convert a struct timeval to a double */
172#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec)) 171static double TVasDOUBLE(struct timeval time) {
172 return ((double)time.tv_sec + (0.000001 * (double)time.tv_usec));
173}
173 174
174/* convert an ntp 64-bit fp number to a struct timeval */ 175/* convert an ntp 64-bit fp number to a struct timeval */
175#define NTP64toTV(n, t) \ 176#define NTP64toTV(n, t) \
@@ -262,8 +263,8 @@ void setup_request(ntp_message *message) {
262/* select the "best" server from a list of servers, and return its index. 263/* select the "best" server from a list of servers, and return its index.
263 * this is done by filtering servers based on stratum, dispersion, and 264 * this is done by filtering servers based on stratum, dispersion, and
264 * finally round-trip delay. */ 265 * finally round-trip delay. */
265int best_offset_server(const ntp_server_results *slist, int nservers) { 266static int best_offset_server(const ntp_server_results *slist, int nservers) {
266 int best_server = -1; 267 int best_server_index = -1;
267 268
268 /* for each server */ 269 /* for each server */
269 for (int cserver = 0; cserver < nservers; cserver++) { 270 for (int cserver = 0; cserver < nservers; cserver++) {
@@ -286,33 +287,33 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
286 } 287 }
287 288
288 /* If we don't have a server yet, use the first one */ 289 /* If we don't have a server yet, use the first one */
289 if (best_server == -1) { 290 if (best_server_index == -1) {
290 best_server = cserver; 291 best_server_index = cserver;
291 DBG(printf("using peer %d as our first candidate\n", best_server)); 292 DBG(printf("using peer %d as our first candidate\n", best_server_index));
292 continue; 293 continue;
293 } 294 }
294 295
295 /* compare the server to the best one we've seen so far */ 296 /* compare the server to the best one we've seen so far */
296 /* does it have an equal or better stratum? */ 297 /* does it have an equal or better stratum? */
297 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 298 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server_index));
298 if (slist[cserver].stratum <= slist[best_server].stratum) { 299 if (slist[cserver].stratum <= slist[best_server_index].stratum) {
299 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 300 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server_index));
300 /* does it have an equal or better dispersion? */ 301 /* does it have an equal or better dispersion? */
301 if (slist[cserver].rtdisp <= slist[best_server].rtdisp) { 302 if (slist[cserver].rtdisp <= slist[best_server_index].rtdisp) {
302 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 303 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server_index));
303 /* does it have a better rtdelay? */ 304 /* does it have a better rtdelay? */
304 if (slist[cserver].rtdelay < slist[best_server].rtdelay) { 305 if (slist[cserver].rtdelay < slist[best_server_index].rtdelay) {
305 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 306 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server_index));
306 best_server = cserver; 307 best_server_index = cserver;
307 DBG(printf("peer %d is now our best candidate\n", best_server)); 308 DBG(printf("peer %d is now our best candidate\n", best_server_index));
308 } 309 }
309 } 310 }
310 } 311 }
311 } 312 }
312 313
313 if (best_server >= 0) { 314 if (best_server_index >= 0) {
314 DBG(printf("best server selected: peer %d\n", best_server)); 315 DBG(printf("best server selected: peer %d\n", best_server_index));
315 return best_server; 316 return best_server_index;
316 } 317 }
317 DBG(printf("no peers meeting synchronization criteria :(\n")); 318 DBG(printf("no peers meeting synchronization criteria :(\n"));
318 return -1; 319 return -1;
@@ -323,7 +324,11 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
323 * we don't waste time sitting around waiting for single packets. 324 * we don't waste time sitting around waiting for single packets.
324 * - we also "manually" handle resolving host names and connecting, because 325 * - we also "manually" handle resolving host names and connecting, because
325 * we have to do it in a way that our lazy macros don't handle currently :( */ 326 * we have to do it in a way that our lazy macros don't handle currently :( */
326double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) { 327typedef struct {
328 mp_state_enum offset_result;
329 double offset;
330} offset_request_wrapper;
331static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset) {
327 /* setup hints to only return results from getaddrinfo that we'd like */ 332 /* setup hints to only return results from getaddrinfo that we'd like */
328 struct addrinfo hints; 333 struct addrinfo hints;
329 memset(&hints, 0, sizeof(struct addrinfo)); 334 memset(&hints, 0, sizeof(struct addrinfo));
@@ -462,11 +467,16 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
462 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 467 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
463 } 468 }
464 469
470 offset_request_wrapper result = {
471 .offset = 0,
472 .offset_result = STATE_UNKNOWN,
473 };
474
465 /* now, pick the best server from the list */ 475 /* now, pick the best server from the list */
466 double avg_offset = 0.; 476 double avg_offset = 0.;
467 int best_index = best_offset_server(servers, num_hosts); 477 int best_index = best_offset_server(servers, num_hosts);
468 if (best_index < 0) { 478 if (best_index < 0) {
469 *status = STATE_UNKNOWN; 479 result.offset_result = STATE_UNKNOWN;
470 } else { 480 } else {
471 /* finally, calculate the average offset */ 481 /* finally, calculate the average offset */
472 for (int i = 0; i < servers[best_index].num_responses; i++) { 482 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,
488 if (verbose) { 498 if (verbose) {
489 printf("overall average offset: %.10g\n", avg_offset); 499 printf("overall average offset: %.10g\n", avg_offset);
490 } 500 }
491 return avg_offset; 501
502 result.offset = avg_offset;
503 return result;
492} 504}
493 505
494check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { 506static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
495 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 507 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
496 {"help", no_argument, 0, 'h'}, 508 {"help", no_argument, 0, 'h'},
497 {"verbose", no_argument, 0, 'v'}, 509 {"verbose", no_argument, 0, 'v'},
@@ -515,9 +527,6 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
515 .config = check_ntp_time_config_init(), 527 .config = check_ntp_time_config_init(),
516 }; 528 };
517 529
518 char *owarn = "60";
519 char *ocrit = "120";
520
521 while (true) { 530 while (true) {
522 int option = 0; 531 int option = 0;
523 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 532 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) {
540 case 'q': 549 case 'q':
541 result.config.quiet = true; 550 result.config.quiet = true;
542 break; 551 break;
543 case 'w': 552 case 'w': {
544 owarn = optarg; 553 mp_range_parsed tmp = mp_parse_range_string(optarg);
545 break; 554 if (tmp.error != MP_PARSING_SUCCES) {
546 case 'c': 555 die(STATE_UNKNOWN, "failed to parse warning threshold");
547 ocrit = optarg; 556 }
548 break; 557
558 result.config.offset_thresholds =
559 mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
560 } break;
561 case 'c': {
562 mp_range_parsed tmp = mp_parse_range_string(optarg);
563 if (tmp.error != MP_PARSING_SUCCES) {
564 die(STATE_UNKNOWN, "failed to parse crit threshold");
565 }
566
567 result.config.offset_thresholds =
568 mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
569 } break;
549 case 'H': 570 case 'H':
550 if (!is_host(optarg)) { 571 if (!is_host(optarg)) {
551 usage2(_("Invalid hostname/address"), optarg); 572 usage2(_("Invalid hostname/address"), optarg);
@@ -582,16 +603,9 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
582 usage4(_("Hostname was not supplied")); 603 usage4(_("Hostname was not supplied"));
583 } 604 }
584 605
585 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
586
587 return result; 606 return result;
588} 607}
589 608
590char *perfd_offset(double offset, thresholds *offset_thresholds) {
591 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
592 offset_thresholds->critical->end, false, 0, false, 0);
593}
594
595int main(int argc, char *argv[]) { 609int main(int argc, char *argv[]) {
596 setlocale(LC_ALL, ""); 610 setlocale(LC_ALL, "");
597 bindtextdomain(PACKAGE, LOCALEDIR); 611 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -614,46 +628,36 @@ int main(int argc, char *argv[]) {
614 /* set socket timeout */ 628 /* set socket timeout */
615 alarm(socket_timeout); 629 alarm(socket_timeout);
616 630
617 mp_state_enum offset_result = STATE_OK; 631 mp_check overall = mp_check_init();
618 mp_state_enum result = STATE_OK;
619 double offset =
620 offset_request(config.server_address, config.port, &offset_result, config.time_offset);
621 if (offset_result == STATE_UNKNOWN) {
622 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
623 } else {
624 result = get_status(fabs(offset), config.offset_thresholds);
625 }
626 632
627 char *result_line; 633 mp_subcheck sc_offset = mp_subcheck_init();
628 switch (result) { 634 offset_request_wrapper offset_result =
629 case STATE_CRITICAL: 635 offset_request(config.server_address, config.port, config.time_offset);
630 xasprintf(&result_line, _("NTP CRITICAL:"));
631 break;
632 case STATE_WARNING:
633 xasprintf(&result_line, _("NTP WARNING:"));
634 break;
635 case STATE_OK:
636 xasprintf(&result_line, _("NTP OK:"));
637 break;
638 default:
639 xasprintf(&result_line, _("NTP UNKNOWN:"));
640 break;
641 }
642 636
643 char *perfdata_line; 637 if (offset_result.offset_result == STATE_UNKNOWN) {
644 if (offset_result == STATE_UNKNOWN) { 638 sc_offset =
645 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 639 mp_set_subcheck_state(sc_offset, (!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
646 xasprintf(&perfdata_line, ""); 640 xasprintf(&sc_offset.output, "Offset unknown");
647 } else { 641 mp_add_subcheck_to_check(&overall, sc_offset);
648 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 642 mp_exit(overall);
649 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
650 } 643 }
651 printf("%s|%s\n", result_line, perfdata_line); 644
645 xasprintf(&sc_offset.output, "Offset: %.10g s", offset_result.offset);
646
647 mp_perfdata pd_offset = perfdata_init();
648 pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset));
649 pd_offset.label = "offset";
650 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
651
652 sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset));
653
654 mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
655 mp_add_subcheck_to_check(&overall, sc_offset);
652 656
653 if (config.server_address != NULL) { 657 if (config.server_address != NULL) {
654 free(config.server_address); 658 free(config.server_address);
655 } 659 }
656 exit(result); 660 mp_exit(overall);
657} 661}
658 662
659void print_help(void) { 663void print_help(void) {
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h
index 99dabbbd..a62e4ceb 100644
--- a/plugins/check_ntp_time.d/config.h
+++ b/plugins/check_ntp_time.d/config.h
@@ -11,7 +11,7 @@ typedef struct {
11 bool quiet; 11 bool quiet;
12 int time_offset; 12 int time_offset;
13 13
14 thresholds *offset_thresholds; 14 mp_thresholds offset_thresholds;
15} check_ntp_time_config; 15} check_ntp_time_config;
16 16
17check_ntp_time_config check_ntp_time_config_init() { 17check_ntp_time_config check_ntp_time_config_init() {
@@ -22,7 +22,16 @@ check_ntp_time_config check_ntp_time_config_init() {
22 .quiet = false, 22 .quiet = false,
23 .time_offset = 0, 23 .time_offset = 0,
24 24
25 .offset_thresholds = NULL, 25 .offset_thresholds = mp_thresholds_init(),
26 }; 26 };
27
28 mp_range warning = mp_range_init();
29 warning = mp_range_set_end(warning, mp_create_pd_value(60));
30 tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, warning);
31
32 mp_range critical = mp_range_init();
33 critical = mp_range_set_end(warning, mp_create_pd_value(120));
34 tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, critical);
35
27 return tmp; 36 return tmp;
28} 37}