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, ""); |
