diff options
-rw-r--r-- | plugins/check_ntp_time.c | 109 |
1 files changed, 56 insertions, 53 deletions
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index 85024c54..703b69df 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c | |||
@@ -209,17 +209,19 @@ typedef struct { | |||
209 | 209 | ||
210 | /* calculate the offset of the local clock */ | 210 | /* calculate the offset of the local clock */ |
211 | static inline double calc_offset(const ntp_message *m, const struct timeval *t) { | 211 | static inline double calc_offset(const ntp_message *m, const struct timeval *t) { |
212 | double client_tx, peer_rx, peer_tx, client_rx; | 212 | double client_tx = NTP64asDOUBLE(m->origts); |
213 | client_tx = NTP64asDOUBLE(m->origts); | 213 | double peer_rx = NTP64asDOUBLE(m->rxts); |
214 | peer_rx = NTP64asDOUBLE(m->rxts); | 214 | double peer_tx = NTP64asDOUBLE(m->txts); |
215 | peer_tx = NTP64asDOUBLE(m->txts); | 215 | double client_rx = TVasDOUBLE((*t)); |
216 | client_rx = TVasDOUBLE((*t)); | ||
217 | return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx))); | 216 | return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx))); |
218 | } | 217 | } |
219 | 218 | ||
220 | /* print out a ntp packet in human readable/debuggable format */ | 219 | /* print out a ntp packet in human readable/debuggable format */ |
221 | void print_ntp_message(const ntp_message *p) { | 220 | void print_ntp_message(const ntp_message *p) { |
222 | struct timeval ref, orig, rx, tx; | 221 | struct timeval ref; |
222 | struct timeval orig; | ||
223 | struct timeval rx; | ||
224 | struct timeval tx; | ||
223 | 225 | ||
224 | NTP64toTV(p->refts, ref); | 226 | NTP64toTV(p->refts, ref); |
225 | NTP64toTV(p->origts, orig); | 227 | NTP64toTV(p->origts, orig); |
@@ -244,8 +246,6 @@ void print_ntp_message(const ntp_message *p) { | |||
244 | } | 246 | } |
245 | 247 | ||
246 | void setup_request(ntp_message *p) { | 248 | void setup_request(ntp_message *p) { |
247 | struct timeval t; | ||
248 | |||
249 | memset(p, 0, sizeof(ntp_message)); | 249 | memset(p, 0, sizeof(ntp_message)); |
250 | LI_SET(p->flags, LI_ALARM); | 250 | LI_SET(p->flags, LI_ALARM); |
251 | VN_SET(p->flags, 4); | 251 | VN_SET(p->flags, 4); |
@@ -255,6 +255,7 @@ void setup_request(ntp_message *p) { | |||
255 | L16(p->rtdelay) = htons(1); | 255 | L16(p->rtdelay) = htons(1); |
256 | L16(p->rtdisp) = htons(1); | 256 | L16(p->rtdisp) = htons(1); |
257 | 257 | ||
258 | struct timeval t; | ||
258 | gettimeofday(&t, NULL); | 259 | gettimeofday(&t, NULL); |
259 | TVtoNTP64(t, p->txts); | 260 | TVtoNTP64(t, p->txts); |
260 | } | 261 | } |
@@ -263,10 +264,10 @@ void setup_request(ntp_message *p) { | |||
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. */ |
265 | int best_offset_server(const ntp_server_results *slist, int nservers) { | 266 | int best_offset_server(const ntp_server_results *slist, int nservers) { |
266 | int cserver = 0, best_server = -1; | 267 | int best_server = -1; |
267 | 268 | ||
268 | /* for each server */ | 269 | /* for each server */ |
269 | for (cserver = 0; cserver < nservers; cserver++) { | 270 | for (int cserver = 0; cserver < nservers; cserver++) { |
270 | /* We don't want any servers that fails these tests */ | 271 | /* We don't want any servers that fails these tests */ |
271 | /* Sort out servers that didn't respond or responede with a 0 stratum; | 272 | /* Sort out servers that didn't respond or responede with a 0 stratum; |
272 | * stratum 0 is for reference clocks so no NTP server should ever report | 273 | * stratum 0 is for reference clocks so no NTP server should ever report |
@@ -311,10 +312,9 @@ int best_offset_server(const ntp_server_results *slist, int nservers) { | |||
311 | if (best_server >= 0) { | 312 | if (best_server >= 0) { |
312 | DBG(printf("best server selected: peer %d\n", best_server)); | 313 | DBG(printf("best server selected: peer %d\n", best_server)); |
313 | return best_server; | 314 | return best_server; |
314 | } else { | ||
315 | DBG(printf("no peers meeting synchronization criteria :(\n")); | ||
316 | return -1; | ||
317 | } | 315 | } |
316 | DBG(printf("no peers meeting synchronization criteria :(\n")); | ||
317 | return -1; | ||
318 | } | 318 | } |
319 | 319 | ||
320 | /* do everything we need to get the total average offset | 320 | /* do everything we need to get the total average offset |
@@ -323,50 +323,48 @@ int best_offset_server(const ntp_server_results *slist, int nservers) { | |||
323 | * - we also "manually" handle resolving host names and connecting, because | 323 | * - we also "manually" handle resolving host names and connecting, because |
324 | * we have to do it in a way that our lazy macros don't handle currently :( */ | 324 | * we have to do it in a way that our lazy macros don't handle currently :( */ |
325 | double offset_request(const char *host, int *status) { | 325 | double offset_request(const char *host, int *status) { |
326 | int i = 0, j = 0, ga_result = 0, num_hosts = 0, *socklist = NULL, respnum = 0; | ||
327 | int servers_completed = 0, one_read = 0, servers_readable = 0, best_index = -1; | ||
328 | time_t now_time = 0, start_ts = 0; | ||
329 | ntp_message *req = NULL; | ||
330 | double avg_offset = 0.; | ||
331 | struct timeval recv_time; | ||
332 | struct addrinfo *ai = NULL, *ai_tmp = NULL, hints; | ||
333 | struct pollfd *ufds = NULL; | ||
334 | ntp_server_results *servers = NULL; | ||
335 | |||
336 | /* setup hints to only return results from getaddrinfo that we'd like */ | 326 | /* setup hints to only return results from getaddrinfo that we'd like */ |
327 | struct addrinfo hints; | ||
337 | memset(&hints, 0, sizeof(struct addrinfo)); | 328 | memset(&hints, 0, sizeof(struct addrinfo)); |
338 | hints.ai_family = address_family; | 329 | hints.ai_family = address_family; |
339 | hints.ai_protocol = IPPROTO_UDP; | 330 | hints.ai_protocol = IPPROTO_UDP; |
340 | hints.ai_socktype = SOCK_DGRAM; | 331 | hints.ai_socktype = SOCK_DGRAM; |
341 | 332 | ||
342 | /* fill in ai with the list of hosts resolved by the host name */ | 333 | /* fill in ai with the list of hosts resolved by the host name */ |
343 | ga_result = getaddrinfo(host, port, &hints, &ai); | 334 | struct addrinfo *ai = NULL; |
335 | int ga_result = getaddrinfo(host, port, &hints, &ai); | ||
344 | if (ga_result != 0) { | 336 | if (ga_result != 0) { |
345 | die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); | 337 | die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); |
346 | } | 338 | } |
347 | 339 | ||
348 | /* count the number of returned hosts, and allocate stuff accordingly */ | 340 | /* count the number of returned hosts, and allocate stuff accordingly */ |
349 | for (ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { | 341 | int num_hosts = 0; |
342 | for (struct addrinfo *ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { | ||
350 | num_hosts++; | 343 | num_hosts++; |
351 | } | 344 | } |
352 | req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); | 345 | |
346 | ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); | ||
347 | |||
353 | if (req == NULL) | 348 | if (req == NULL) |
354 | die(STATE_UNKNOWN, "can not allocate ntp message array"); | 349 | die(STATE_UNKNOWN, "can not allocate ntp message array"); |
355 | socklist = (int *)malloc(sizeof(int) * num_hosts); | 350 | int *socklist = (int *)malloc(sizeof(int) * num_hosts); |
351 | |||
356 | if (socklist == NULL) | 352 | if (socklist == NULL) |
357 | die(STATE_UNKNOWN, "can not allocate socket array"); | 353 | die(STATE_UNKNOWN, "can not allocate socket array"); |
358 | ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts); | 354 | |
355 | struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts); | ||
359 | if (ufds == NULL) | 356 | if (ufds == NULL) |
360 | die(STATE_UNKNOWN, "can not allocate socket array"); | 357 | die(STATE_UNKNOWN, "can not allocate socket array"); |
361 | servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts); | 358 | |
359 | ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts); | ||
362 | if (servers == NULL) | 360 | if (servers == NULL) |
363 | die(STATE_UNKNOWN, "can not allocate server array"); | 361 | die(STATE_UNKNOWN, "can not allocate server array"); |
364 | memset(servers, 0, sizeof(ntp_server_results) * num_hosts); | 362 | memset(servers, 0, sizeof(ntp_server_results) * num_hosts); |
365 | DBG(printf("Found %d peers to check\n", num_hosts)); | 363 | DBG(printf("Found %d peers to check\n", num_hosts)); |
366 | 364 | ||
367 | /* setup each socket for writing, and the corresponding struct pollfd */ | 365 | /* setup each socket for writing, and the corresponding struct pollfd */ |
368 | ai_tmp = ai; | 366 | struct addrinfo *ai_tmp = ai; |
369 | for (i = 0; ai_tmp; i++) { | 367 | for (int i = 0; ai_tmp; i++) { |
370 | socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); | 368 | socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); |
371 | if (socklist[i] == -1) { | 369 | if (socklist[i] == -1) { |
372 | perror(NULL); | 370 | perror(NULL); |
@@ -388,7 +386,11 @@ double offset_request(const char *host, int *status) { | |||
388 | 386 | ||
389 | /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds | 387 | /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds |
390 | * have passed in order to ensure post-processing and jitter time. */ | 388 | * have passed in order to ensure post-processing and jitter time. */ |
389 | time_t start_ts = 0; | ||
390 | time_t now_time = 0; | ||
391 | now_time = start_ts = time(NULL); | 391 | now_time = start_ts = time(NULL); |
392 | int servers_completed = 0; | ||
393 | bool one_read = false; | ||
392 | while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) { | 394 | while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) { |
393 | /* loop through each server and find each one which hasn't | 395 | /* loop through each server and find each one which hasn't |
394 | * been touched in the past second or so and is still lacking | 396 | * been touched in the past second or so and is still lacking |
@@ -396,7 +398,7 @@ double offset_request(const char *host, int *status) { | |||
396 | * and update the "waiting" timestamp with the current time. */ | 398 | * and update the "waiting" timestamp with the current time. */ |
397 | now_time = time(NULL); | 399 | now_time = time(NULL); |
398 | 400 | ||
399 | for (i = 0; i < num_hosts; i++) { | 401 | for (int i = 0; i < num_hosts; i++) { |
400 | if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) { | 402 | if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) { |
401 | if (verbose && servers[i].waiting != 0) | 403 | if (verbose && servers[i].waiting != 0) |
402 | printf("re-"); | 404 | printf("re-"); |
@@ -410,23 +412,25 @@ double offset_request(const char *host, int *status) { | |||
410 | } | 412 | } |
411 | 413 | ||
412 | /* quickly poll for any sockets with pending data */ | 414 | /* quickly poll for any sockets with pending data */ |
413 | servers_readable = poll(ufds, num_hosts, 100); | 415 | int servers_readable = poll(ufds, num_hosts, 100); |
414 | if (servers_readable == -1) { | 416 | if (servers_readable == -1) { |
415 | perror("polling ntp sockets"); | 417 | perror("polling ntp sockets"); |
416 | die(STATE_UNKNOWN, "communication errors"); | 418 | die(STATE_UNKNOWN, "communication errors"); |
417 | } | 419 | } |
418 | 420 | ||
419 | /* read from any sockets with pending data */ | 421 | /* read from any sockets with pending data */ |
420 | for (i = 0; servers_readable && i < num_hosts; i++) { | 422 | for (int i = 0; servers_readable && i < num_hosts; i++) { |
421 | if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) { | 423 | if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) { |
422 | if (verbose) { | 424 | if (verbose) { |
423 | printf("response from peer %d: ", i); | 425 | printf("response from peer %d: ", i); |
424 | } | 426 | } |
425 | 427 | ||
426 | read(ufds[i].fd, &req[i], sizeof(ntp_message)); | 428 | read(ufds[i].fd, &req[i], sizeof(ntp_message)); |
429 | |||
430 | struct timeval recv_time; | ||
427 | gettimeofday(&recv_time, NULL); | 431 | gettimeofday(&recv_time, NULL); |
428 | DBG(print_ntp_message(&req[i])); | 432 | DBG(print_ntp_message(&req[i])); |
429 | respnum = servers[i].num_responses++; | 433 | int respnum = servers[i].num_responses++; |
430 | servers[i].offset[respnum] = calc_offset(&req[i], &recv_time) + time_offset; | 434 | servers[i].offset[respnum] = calc_offset(&req[i], &recv_time) + time_offset; |
431 | if (verbose) { | 435 | if (verbose) { |
432 | printf("offset %.10g\n", servers[i].offset[respnum]); | 436 | printf("offset %.10g\n", servers[i].offset[respnum]); |
@@ -437,7 +441,7 @@ double offset_request(const char *host, int *status) { | |||
437 | servers[i].waiting = 0; | 441 | servers[i].waiting = 0; |
438 | servers[i].flags = req[i].flags; | 442 | servers[i].flags = req[i].flags; |
439 | servers_readable--; | 443 | servers_readable--; |
440 | one_read = 1; | 444 | one_read = true; |
441 | if (servers[i].num_responses == AVG_NUM) | 445 | if (servers[i].num_responses == AVG_NUM) |
442 | servers_completed++; | 446 | servers_completed++; |
443 | } | 447 | } |
@@ -445,24 +449,25 @@ double offset_request(const char *host, int *status) { | |||
445 | /* lather, rinse, repeat. */ | 449 | /* lather, rinse, repeat. */ |
446 | } | 450 | } |
447 | 451 | ||
448 | if (one_read == 0) { | 452 | if (one_read == false) { |
449 | die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); | 453 | die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); |
450 | } | 454 | } |
451 | 455 | ||
452 | /* now, pick the best server from the list */ | 456 | /* now, pick the best server from the list */ |
453 | best_index = best_offset_server(servers, num_hosts); | 457 | double avg_offset = 0.; |
458 | int best_index = best_offset_server(servers, num_hosts); | ||
454 | if (best_index < 0) { | 459 | if (best_index < 0) { |
455 | *status = STATE_UNKNOWN; | 460 | *status = STATE_UNKNOWN; |
456 | } else { | 461 | } else { |
457 | /* finally, calculate the average offset */ | 462 | /* finally, calculate the average offset */ |
458 | for (i = 0; i < servers[best_index].num_responses; i++) { | 463 | for (int i = 0; i < servers[best_index].num_responses; i++) { |
459 | avg_offset += servers[best_index].offset[i]; | 464 | avg_offset += servers[best_index].offset[i]; |
460 | } | 465 | } |
461 | avg_offset /= servers[best_index].num_responses; | 466 | avg_offset /= servers[best_index].num_responses; |
462 | } | 467 | } |
463 | 468 | ||
464 | /* cleanup */ | 469 | /* cleanup */ |
465 | for (j = 0; j < num_hosts; j++) { | 470 | for (int j = 0; j < num_hosts; j++) { |
466 | close(socklist[j]); | 471 | close(socklist[j]); |
467 | } | 472 | } |
468 | free(socklist); | 473 | free(socklist); |
@@ -477,8 +482,6 @@ double offset_request(const char *host, int *status) { | |||
477 | } | 482 | } |
478 | 483 | ||
479 | int process_arguments(int argc, char **argv) { | 484 | int process_arguments(int argc, char **argv) { |
480 | int c; | ||
481 | int option = 0; | ||
482 | static struct option longopts[] = {{"version", no_argument, 0, 'V'}, | 485 | static struct option longopts[] = {{"version", no_argument, 0, 'V'}, |
483 | {"help", no_argument, 0, 'h'}, | 486 | {"help", no_argument, 0, 'h'}, |
484 | {"verbose", no_argument, 0, 'v'}, | 487 | {"verbose", no_argument, 0, 'v'}, |
@@ -496,12 +499,13 @@ int process_arguments(int argc, char **argv) { | |||
496 | if (argc < 2) | 499 | if (argc < 2) |
497 | usage("\n"); | 500 | usage("\n"); |
498 | 501 | ||
499 | while (1) { | 502 | while (true) { |
500 | c = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); | 503 | int option = 0; |
501 | if (c == -1 || c == EOF || c == 1) | 504 | int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); |
505 | if (option_char == -1 || option_char == EOF || option_char == 1) | ||
502 | break; | 506 | break; |
503 | 507 | ||
504 | switch (c) { | 508 | switch (option_char) { |
505 | case 'h': | 509 | case 'h': |
506 | print_help(); | 510 | print_help(); |
507 | exit(STATE_UNKNOWN); | 511 | exit(STATE_UNKNOWN); |
@@ -566,16 +570,10 @@ char *perfd_offset(double offset) { | |||
566 | } | 570 | } |
567 | 571 | ||
568 | int main(int argc, char *argv[]) { | 572 | int main(int argc, char *argv[]) { |
569 | int result, offset_result; | ||
570 | double offset = 0; | ||
571 | char *result_line, *perfdata_line; | ||
572 | |||
573 | setlocale(LC_ALL, ""); | 573 | setlocale(LC_ALL, ""); |
574 | bindtextdomain(PACKAGE, LOCALEDIR); | 574 | bindtextdomain(PACKAGE, LOCALEDIR); |
575 | textdomain(PACKAGE); | 575 | textdomain(PACKAGE); |
576 | 576 | ||
577 | result = offset_result = STATE_OK; | ||
578 | |||
579 | /* Parse extra opts if any */ | 577 | /* Parse extra opts if any */ |
580 | argv = np_extra_opts(&argc, argv, progname); | 578 | argv = np_extra_opts(&argc, argv, progname); |
581 | 579 | ||
@@ -590,13 +588,16 @@ int main(int argc, char *argv[]) { | |||
590 | /* set socket timeout */ | 588 | /* set socket timeout */ |
591 | alarm(socket_timeout); | 589 | alarm(socket_timeout); |
592 | 590 | ||
593 | offset = offset_request(server_address, &offset_result); | 591 | int offset_result = STATE_OK; |
592 | int result = STATE_OK; | ||
593 | double offset = offset_request(server_address, &offset_result); | ||
594 | if (offset_result == STATE_UNKNOWN) { | 594 | if (offset_result == STATE_UNKNOWN) { |
595 | result = ((!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); | 595 | result = ((!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); |
596 | } else { | 596 | } else { |
597 | result = get_status(fabs(offset), offset_thresholds); | 597 | result = get_status(fabs(offset), offset_thresholds); |
598 | } | 598 | } |
599 | 599 | ||
600 | char *result_line; | ||
600 | switch (result) { | 601 | switch (result) { |
601 | case STATE_CRITICAL: | 602 | case STATE_CRITICAL: |
602 | xasprintf(&result_line, _("NTP CRITICAL:")); | 603 | xasprintf(&result_line, _("NTP CRITICAL:")); |
@@ -611,6 +612,8 @@ int main(int argc, char *argv[]) { | |||
611 | xasprintf(&result_line, _("NTP UNKNOWN:")); | 612 | xasprintf(&result_line, _("NTP UNKNOWN:")); |
612 | break; | 613 | break; |
613 | } | 614 | } |
615 | |||
616 | char *perfdata_line; | ||
614 | if (offset_result == STATE_UNKNOWN) { | 617 | if (offset_result == STATE_UNKNOWN) { |
615 | xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); | 618 | xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); |
616 | xasprintf(&perfdata_line, ""); | 619 | xasprintf(&perfdata_line, ""); |