1 /* 2 * ntp_util.c - stuff I didn't have any other place for 3 */ 4 #ifdef HAVE_CONFIG_H 5 # include <config.h> 6 #endif 7 8 #include "ntpd.h" 9 #include "ntp_unixtime.h" 10 #include "ntp_filegen.h" 11 #include "ntp_if.h" 12 #include "ntp_stdlib.h" 13 #include "ntp_assert.h" 14 #include "ntp_calendar.h" 15 #include "ntp_leapsec.h" 16 #include "lib_strbuf.h" 17 18 #include <stdio.h> 19 #include <ctype.h> 20 #include <sys/types.h> 21 #ifdef HAVE_SYS_IOCTL_H 22 # include <sys/ioctl.h> 23 #endif 24 #ifdef HAVE_UNISTD_H 25 # include <unistd.h> 26 #endif 27 #include <sys/stat.h> 28 29 #ifdef HAVE_IEEEFP_H 30 # include <ieeefp.h> 31 #endif 32 #ifdef HAVE_MATH_H 33 # include <math.h> 34 #endif 35 36 #if defined(VMS) 37 # include <descrip.h> 38 #endif /* VMS */ 39 40 /* 41 * Defines used by the leapseconds stuff 42 */ 43 #define MAX_TAI 100 /* max TAI offset (s) */ 44 #define L_DAY 86400UL /* seconds per day */ 45 #define L_YEAR (L_DAY * 365) /* days per year */ 46 #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 47 #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 48 #define L_CENT (L_4YEAR * 25) /* days per century */ 49 50 /* 51 * This contains odds and ends, including the hourly stats, various 52 * configuration items, leapseconds stuff, etc. 53 */ 54 /* 55 * File names 56 */ 57 static char *key_file_name; /* keys file name */ 58 static char *leapfile_name; /* leapseconds file name */ 59 static struct stat leapfile_stat; /* leapseconds file stat() buffer */ 60 static int /*BOOL*/have_leapfile = FALSE; 61 static int /*BOOL*/chck_leaphash = TRUE; 62 char *stats_drift_file; /* frequency file name */ 63 static char *stats_temp_file; /* temp frequency file name */ 64 static double wander_resid; /* last frequency update */ 65 double wander_threshold = 1e-7; /* initial frequency threshold */ 66 static unsigned int cmdargs_seen = 0; /* stat options seen from command line */ 67 68 /* 69 * Statistics file stuff 70 */ 71 #ifndef NTP_VAR 72 # ifndef SYS_WINNT 73 # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 74 # else 75 # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 76 # endif /* SYS_WINNT */ 77 #endif 78 79 80 char statsdir[MAXFILENAME] = NTP_VAR; 81 static FILEGEN peerstats; 82 static FILEGEN loopstats; 83 static FILEGEN clockstats; 84 static FILEGEN rawstats; 85 static FILEGEN sysstats; 86 static FILEGEN protostats; 87 static FILEGEN cryptostats; 88 static FILEGEN timingstats; 89 90 /* 91 * This controls whether stats are written to the fileset. Provided 92 * so that ntpdc can turn off stats when the file system fills up. 93 */ 94 int stats_control; 95 96 /* 97 * Last frequency written to file. 98 */ 99 static double prev_drift_comp; /* last frequency update */ 100 101 /* 102 * Function prototypes 103 */ 104 static void record_sys_stats(void); 105 void ntpd_time_stepped(void); 106 static void check_leap_expiration(int, uint32_t, const time_t*); 107 108 /* 109 * Prototypes 110 */ 111 #ifdef DEBUG 112 void uninit_util(void); 113 #endif 114 115 /* 116 * uninit_util - free memory allocated by init_util 117 */ 118 #ifdef DEBUG 119 void 120 uninit_util(void) 121 { 122 #if defined(_MSC_VER) && defined (_DEBUG) 123 _CrtCheckMemory(); 124 #endif 125 if (stats_drift_file) { 126 free(stats_drift_file); 127 free(stats_temp_file); 128 stats_drift_file = NULL; 129 stats_temp_file = NULL; 130 } 131 if (key_file_name) { 132 free(key_file_name); 133 key_file_name = NULL; 134 } 135 filegen_unregister("peerstats"); 136 filegen_unregister("loopstats"); 137 filegen_unregister("clockstats"); 138 filegen_unregister("rawstats"); 139 filegen_unregister("sysstats"); 140 filegen_unregister("protostats"); 141 #ifdef AUTOKEY 142 filegen_unregister("cryptostats"); 143 #endif /* AUTOKEY */ 144 #ifdef DEBUG_TIMING 145 filegen_unregister("timingstats"); 146 #endif /* DEBUG_TIMING */ 147 148 #if defined(_MSC_VER) && defined (_DEBUG) 149 _CrtCheckMemory(); 150 #endif 151 } 152 #endif /* DEBUG */ 153 154 155 /* 156 * init_util - initialize the util module of ntpd 157 */ 158 void 159 init_util(void) 160 { 161 filegen_register(statsdir, "peerstats", &peerstats); 162 filegen_register(statsdir, "loopstats", &loopstats); 163 filegen_register(statsdir, "clockstats", &clockstats); 164 filegen_register(statsdir, "rawstats", &rawstats); 165 filegen_register(statsdir, "sysstats", &sysstats); 166 filegen_register(statsdir, "protostats", &protostats); 167 filegen_register(statsdir, "cryptostats", &cryptostats); 168 filegen_register(statsdir, "timingstats", &timingstats); 169 /* 170 * register with libntp ntp_set_tod() to call us back 171 * when time is stepped. 172 */ 173 step_callback = &ntpd_time_stepped; 174 #ifdef DEBUG 175 atexit(&uninit_util); 176 #endif /* DEBUG */ 177 } 178 179 180 /* 181 * hourly_stats - print some interesting stats 182 */ 183 void 184 write_stats(void) 185 { 186 FILE *fp; 187 #ifdef DOSYNCTODR 188 struct timeval tv; 189 #if !defined(VMS) 190 int prio_set; 191 #endif 192 #ifdef HAVE_GETCLOCK 193 struct timespec ts; 194 #endif 195 int o_prio; 196 197 /* 198 * Sometimes having a Sun can be a drag. 199 * 200 * The kernel variable dosynctodr controls whether the system's 201 * soft clock is kept in sync with the battery clock. If it 202 * is zero, then the soft clock is not synced, and the battery 203 * clock is simply left to rot. That means that when the system 204 * reboots, the battery clock (which has probably gone wacky) 205 * sets the soft clock. That means ntpd starts off with a very 206 * confused idea of what time it is. It then takes a large 207 * amount of time to figure out just how wacky the battery clock 208 * has made things drift, etc, etc. The solution is to make the 209 * battery clock sync up to system time. The way to do THAT is 210 * to simply set the time of day to the current time of day, but 211 * as quickly as possible. This may, or may not be a sensible 212 * thing to do. 213 * 214 * CAVEAT: settimeofday() steps the sun clock by about 800 us, 215 * so setting DOSYNCTODR seems a bad idea in the 216 * case of us resolution 217 */ 218 219 #if !defined(VMS) 220 /* 221 * (prr) getpriority returns -1 on error, but -1 is also a valid 222 * return value (!), so instead we have to zero errno before the 223 * call and check it for non-zero afterwards. 224 */ 225 errno = 0; 226 prio_set = 0; 227 o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 228 229 /* 230 * (prr) if getpriority succeeded, call setpriority to raise 231 * scheduling priority as high as possible. If that succeeds 232 * as well, set the prio_set flag so we remember to reset 233 * priority to its previous value below. Note that on Solaris 234 * 2.6 (and beyond?), both getpriority and setpriority will fail 235 * with ESRCH, because sched_setscheduler (called from main) put 236 * us in the real-time scheduling class which setpriority 237 * doesn't know about. Being in the real-time class is better 238 * than anything setpriority can do, anyhow, so this error is 239 * silently ignored. 240 */ 241 if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 242 prio_set = 1; /* overdrive */ 243 #endif /* VMS */ 244 #ifdef HAVE_GETCLOCK 245 (void) getclock(TIMEOFDAY, &ts); 246 tv.tv_sec = ts.tv_sec; 247 tv.tv_usec = ts.tv_nsec / 1000; 248 #else /* not HAVE_GETCLOCK */ 249 GETTIMEOFDAY(&tv,(struct timezone *)NULL); 250 #endif /* not HAVE_GETCLOCK */ 251 if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 252 msyslog(LOG_ERR, "can't sync battery time: %m"); 253 #if !defined(VMS) 254 if (prio_set) 255 setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 256 #endif /* VMS */ 257 #endif /* DOSYNCTODR */ 258 record_sys_stats(); 259 if (stats_drift_file != 0) { 260 261 /* 262 * When the frequency file is written, initialize the 263 * prev_drift_comp and wander_resid. Thereafter, 264 * reduce the wander_resid by half each hour. When 265 * the difference between the prev_drift_comp and 266 * drift_comp is less than the wander_resid, update 267 * the frequncy file. This minimizes the file writes to 268 * nonvolaile storage. 269 */ 270 #ifdef DEBUG 271 if (debug) 272 printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n", 273 (prev_drift_comp - drift_comp) * 1e6, wander_resid * 274 1e6, drift_comp * 1e6); 275 #endif 276 if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 277 wander_resid *= 0.5; 278 return; 279 } 280 prev_drift_comp = drift_comp; 281 wander_resid = wander_threshold; 282 if ((fp = fopen(stats_temp_file, "w")) == NULL) { 283 msyslog(LOG_ERR, "frequency file %s: %m", 284 stats_temp_file); 285 return; 286 } 287 fprintf(fp, "%.3f\n", drift_comp * 1e6); 288 (void)fclose(fp); 289 /* atomic */ 290 #ifdef SYS_WINNT 291 if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 292 msyslog(LOG_WARNING, 293 "Unable to remove prior drift file %s, %m", 294 stats_drift_file); 295 #endif /* SYS_WINNT */ 296 297 #ifndef NO_RENAME 298 if (rename(stats_temp_file, stats_drift_file)) 299 msyslog(LOG_WARNING, 300 "Unable to rename temp drift file %s to %s, %m", 301 stats_temp_file, stats_drift_file); 302 #else 303 /* we have no rename NFS of ftp in use */ 304 if ((fp = fopen(stats_drift_file, "w")) == 305 NULL) { 306 msyslog(LOG_ERR, 307 "frequency file %s: %m", 308 stats_drift_file); 309 return; 310 } 311 #endif 312 313 #if defined(VMS) 314 /* PURGE */ 315 { 316 $DESCRIPTOR(oldvers,";-1"); 317 struct dsc$descriptor driftdsc = { 318 strlen(stats_drift_file), 0, 0, 319 stats_drift_file }; 320 while(lib$delete_file(&oldvers, 321 &driftdsc) & 1); 322 } 323 #endif 324 } 325 } 326 327 328 /* 329 * stats_config - configure the stats operation 330 */ 331 static int 332 allow_config( 333 unsigned int option, 334 int/*BOOL*/ cmdopt) 335 { 336 /* If an option was given on the command line, make sure it 337 * persists and is not later changed by a corresponding option 338 * from the config file. Done by simply remembering an option was 339 * already seen from the command line. 340 * 341 * BTW, if we ever define stats options beyond 31, this needs a 342 * fix. Until then, simply assume the shift will not overflow. 343 */ 344 unsigned int mask = 1u << option; 345 int retv = cmdopt || !(cmdargs_seen & mask); 346 if (cmdopt) 347 cmdargs_seen |= mask; 348 return retv; 349 } 350 351 352 void 353 stats_config( 354 int item, 355 const char *invalue, /* only one type so far */ 356 int optflag 357 ) 358 { 359 FILE *fp; 360 const char *value; 361 size_t len; 362 double old_drift; 363 l_fp now; 364 time_t ttnow; 365 #ifndef VMS 366 static const char temp_ext[] = ".TEMP"; 367 #else 368 static const char temp_ext[] = "-TEMP"; 369 #endif 370 371 /* 372 * Expand environment strings under Windows NT, since the 373 * command interpreter doesn't do this, the program must. 374 */ 375 #ifdef SYS_WINNT 376 char newvalue[MAX_PATH], parameter[MAX_PATH]; 377 378 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 379 switch (item) { 380 case STATS_FREQ_FILE: 381 strlcpy(parameter, "STATS_FREQ_FILE", 382 sizeof(parameter)); 383 break; 384 385 case STATS_LEAP_FILE: 386 strlcpy(parameter, "STATS_LEAP_FILE", 387 sizeof(parameter)); 388 break; 389 390 case STATS_STATSDIR: 391 strlcpy(parameter, "STATS_STATSDIR", 392 sizeof(parameter)); 393 break; 394 395 case STATS_PID_FILE: 396 strlcpy(parameter, "STATS_PID_FILE", 397 sizeof(parameter)); 398 break; 399 400 default: 401 strlcpy(parameter, "UNKNOWN", 402 sizeof(parameter)); 403 break; 404 } 405 value = invalue; 406 msyslog(LOG_ERR, 407 "ExpandEnvironmentStrings(%s) failed: %m\n", 408 parameter); 409 } else { 410 value = newvalue; 411 } 412 #else 413 value = invalue; 414 #endif /* SYS_WINNT */ 415 416 switch (item) { 417 418 /* 419 * Open and read frequency file. 420 */ 421 case STATS_FREQ_FILE: 422 if (!allow_config(STATS_FREQ_FILE, optflag)) 423 break; 424 425 if (!value || (len = strlen(value)) == 0) 426 { 427 free(stats_drift_file); 428 free(stats_temp_file); 429 stats_drift_file = stats_temp_file = NULL; 430 } 431 else 432 { 433 stats_drift_file = erealloc(stats_drift_file, len + 1); 434 stats_temp_file = erealloc(stats_temp_file, 435 len + sizeof(".TEMP")); 436 memcpy(stats_drift_file, value, (size_t)(len+1)); 437 memcpy(stats_temp_file, value, (size_t)len); 438 memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext)); 439 } 440 441 /* 442 * Open drift file and read frequency. If the file is 443 * missing or contains errors, tell the loop to reset. 444 */ 445 if (NULL == stats_drift_file) { 446 loop_config(LOOP_NOFREQ, 0.0); 447 prev_drift_comp = 0.0; 448 } else if ((fp = fopen(stats_drift_file, "r")) == NULL) { 449 if (errno != ENOENT) 450 msyslog(LOG_WARNING, 451 "cannot read frequency file %s: %s", 452 stats_drift_file, strerror(errno)); 453 } else if (fscanf(fp, "%lf", &old_drift) != 1) { 454 msyslog(LOG_ERR, 455 "format error frequency file %s", 456 stats_drift_file); 457 fclose(fp); 458 } else { 459 loop_config(LOOP_FREQ, old_drift); 460 prev_drift_comp = drift_comp; 461 msyslog(LOG_INFO, 462 "initial drift restored to %f", 463 old_drift); 464 fclose(fp); 465 } 466 break; 467 468 /* 469 * Specify statistics directory. 470 */ 471 case STATS_STATSDIR: 472 if (!allow_config(STATS_STATSDIR, optflag)) 473 break; 474 475 /* - 1 since value may be missing the DIR_SEP. */ 476 if (strlen(value) >= sizeof(statsdir) - 1) { 477 msyslog(LOG_ERR, 478 "statsdir too long (>%d, sigh)", 479 (int)sizeof(statsdir) - 2); 480 } else { 481 int add_dir_sep; 482 size_t value_l; 483 484 /* Add a DIR_SEP unless we already have one. */ 485 value_l = strlen(value); 486 if (0 == value_l) 487 add_dir_sep = FALSE; 488 else 489 add_dir_sep = (DIR_SEP != 490 value[value_l - 1]); 491 492 if (add_dir_sep) 493 snprintf(statsdir, sizeof(statsdir), 494 "%s%c", value, DIR_SEP); 495 else 496 snprintf(statsdir, sizeof(statsdir), 497 "%s", value); 498 filegen_statsdir(); 499 } 500 break; 501 502 /* 503 * Open pid file. 504 */ 505 case STATS_PID_FILE: 506 if (!allow_config(STATS_PID_FILE, optflag)) 507 break; 508 509 if ((fp = fopen(value, "w")) == NULL) { 510 msyslog(LOG_ERR, "pid file %s: %m", 511 value); 512 break; 513 } 514 fprintf(fp, "%d", (int)getpid()); 515 fclose(fp); 516 break; 517 518 /* 519 * Read leapseconds file. 520 * 521 * Note: Currently a leap file without SHA1 signature is 522 * accepted, but if there is a signature line, the signature 523 * must be valid or the file is rejected. 524 */ 525 case STATS_LEAP_FILE: 526 if (!value || (len = strlen(value)) == 0) 527 break; 528 529 leapfile_name = erealloc(leapfile_name, len + 1); 530 memcpy(leapfile_name, value, len + 1); 531 chck_leaphash = optflag; 532 533 if (leapsec_load_file( 534 leapfile_name, &leapfile_stat, 535 TRUE, TRUE, chck_leaphash)) 536 { 537 leap_signature_t lsig; 538 539 get_systime(&now); 540 time(&ttnow); 541 leapsec_getsig(&lsig); 542 mprintf_event(EVNT_TAI, NULL, 543 "%d leap %s %s %s", 544 lsig.taiof, 545 fstostr(lsig.ttime), 546 leapsec_expired(now.l_ui, NULL) 547 ? "expired" 548 : "expires", 549 fstostr(lsig.etime)); 550 551 have_leapfile = TRUE; 552 553 /* force an immediate daily expiration check of 554 * the leap seconds table 555 */ 556 check_leap_expiration(TRUE, now.l_ui, &ttnow); 557 } 558 break; 559 560 default: 561 /* oh well */ 562 break; 563 } 564 } 565 566 567 /* 568 * record_peer_stats - write peer statistics to file 569 * 570 * file format: 571 * day (MJD) 572 * time (s past UTC midnight) 573 * IP address 574 * status word (hex) 575 * offset 576 * delay 577 * dispersion 578 * jitter 579 */ 580 void 581 record_peer_stats( 582 sockaddr_u *addr, 583 int status, 584 double offset, /* offset */ 585 double delay, /* delay */ 586 double dispersion, /* dispersion */ 587 double jitter /* jitter */ 588 ) 589 { 590 l_fp now; 591 u_long day; 592 593 if (!stats_control) 594 return; 595 596 get_systime(&now); 597 filegen_setup(&peerstats, now.l_ui); 598 day = now.l_ui / 86400 + MJD_1900; 599 now.l_ui %= 86400; 600 if (peerstats.fp != NULL) { 601 fprintf(peerstats.fp, 602 "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 603 ulfptoa(&now, 3), stoa(addr), status, offset, 604 delay, dispersion, jitter); 605 fflush(peerstats.fp); 606 } 607 } 608 609 610 /* 611 * record_loop_stats - write loop filter statistics to file 612 * 613 * file format: 614 * day (MJD) 615 * time (s past midnight) 616 * offset 617 * frequency (PPM) 618 * jitter 619 * wnder (PPM) 620 * time constant (log2) 621 */ 622 void 623 record_loop_stats( 624 double offset, /* offset */ 625 double freq, /* frequency (PPM) */ 626 double jitter, /* jitter */ 627 double wander, /* wander (PPM) */ 628 int spoll 629 ) 630 { 631 l_fp now; 632 u_long day; 633 634 if (!stats_control) 635 return; 636 637 get_systime(&now); 638 filegen_setup(&loopstats, now.l_ui); 639 day = now.l_ui / 86400 + MJD_1900; 640 now.l_ui %= 86400; 641 if (loopstats.fp != NULL) { 642 fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 643 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 644 wander * 1e6, spoll); 645 fflush(loopstats.fp); 646 } 647 } 648 649 650 /* 651 * record_clock_stats - write clock statistics to file 652 * 653 * file format: 654 * day (MJD) 655 * time (s past midnight) 656 * IP address 657 * text message 658 */ 659 void 660 record_clock_stats( 661 sockaddr_u *addr, 662 const char *text /* timecode string */ 663 ) 664 { 665 l_fp now; 666 u_long day; 667 668 if (!stats_control) 669 return; 670 671 get_systime(&now); 672 filegen_setup(&clockstats, now.l_ui); 673 day = now.l_ui / 86400 + MJD_1900; 674 now.l_ui %= 86400; 675 if (clockstats.fp != NULL) { 676 fprintf(clockstats.fp, "%lu %s %s %s\n", day, 677 ulfptoa(&now, 3), stoa(addr), text); 678 fflush(clockstats.fp); 679 } 680 } 681 682 683 /* 684 * mprintf_clock_stats - write clock statistics to file with 685 * msnprintf-style formatting. 686 */ 687 int 688 mprintf_clock_stats( 689 sockaddr_u *addr, 690 const char *fmt, 691 ... 692 ) 693 { 694 va_list ap; 695 int rc; 696 char msg[512]; 697 698 va_start(ap, fmt); 699 rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 700 va_end(ap); 701 if (stats_control) 702 record_clock_stats(addr, msg); 703 704 return rc; 705 } 706 707 /* 708 * record_raw_stats - write raw timestamps to file 709 * 710 * file format 711 * day (MJD) 712 * time (s past midnight) 713 * peer ip address 714 * IP address 715 * t1 t2 t3 t4 timestamps 716 * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 717 * length and hex dump of any EFs and any legacy MAC. 718 */ 719 void 720 record_raw_stats( 721 sockaddr_u *srcadr, 722 sockaddr_u *dstadr, 723 l_fp *t1, /* originate timestamp */ 724 l_fp *t2, /* receive timestamp */ 725 l_fp *t3, /* transmit timestamp */ 726 l_fp *t4, /* destination timestamp */ 727 int leap, 728 int version, 729 int mode, 730 int stratum, 731 int ppoll, 732 int precision, 733 double root_delay, /* seconds */ 734 double root_dispersion,/* seconds */ 735 u_int32 refid, 736 int len, 737 u_char *extra 738 ) 739 { 740 l_fp now; 741 u_long day; 742 743 if (!stats_control) 744 return; 745 746 /* 747 * Mode 6 and mode 7 packets do not have the format of normal 748 * NTP packets and will log garbage. So don't. [Bug 3774] 749 */ 750 if (MODE_CONTROL == mode || MODE_PRIVATE == mode) 751 return; 752 753 get_systime(&now); 754 filegen_setup(&rawstats, now.l_ui); 755 day = now.l_ui / 86400 + MJD_1900; 756 now.l_ui %= 86400; 757 if (rawstats.fp != NULL) { 758 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 759 day, ulfptoa(&now, 3), 760 srcadr ? stoa(srcadr) : "-", 761 dstadr ? stoa(dstadr) : "-", 762 ulfptoa(t1, 9), ulfptoa(t2, 9), 763 ulfptoa(t3, 9), ulfptoa(t4, 9), 764 leap, version, mode, stratum, ppoll, precision, 765 root_delay, root_dispersion, refid_str(refid, stratum)); 766 if (len > 0) { 767 int i; 768 769 fprintf(rawstats.fp, " %d: ", len); 770 for (i = 0; i < len; ++i) { 771 fprintf(rawstats.fp, "%02x", extra[i]); 772 } 773 } 774 fprintf(rawstats.fp, "\n"); 775 fflush(rawstats.fp); 776 } 777 } 778 779 780 /* 781 * record_sys_stats - write system statistics to file 782 * 783 * file format 784 * day (MJD) 785 * time (s past midnight) 786 * time since reset 787 * packets recieved 788 * packets for this host 789 * current version 790 * old version 791 * access denied 792 * bad length or format 793 * bad authentication 794 * declined 795 * rate exceeded 796 * KoD sent 797 */ 798 void 799 record_sys_stats(void) 800 { 801 l_fp now; 802 u_long day; 803 804 if (!stats_control) 805 return; 806 807 get_systime(&now); 808 filegen_setup(&sysstats, now.l_ui); 809 day = now.l_ui / 86400 + MJD_1900; 810 now.l_ui %= 86400; 811 if (sysstats.fp != NULL) { 812 fprintf(sysstats.fp, 813 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 814 day, ulfptoa(&now, 3), current_time - sys_stattime, 815 sys_received, sys_processed, sys_newversion, 816 sys_oldversion, sys_restricted, sys_badlength, 817 sys_badauth, sys_declined, sys_limitrejected, 818 sys_kodsent); 819 fflush(sysstats.fp); 820 proto_clr_stats(); 821 } 822 } 823 824 825 /* 826 * record_proto_stats - write system statistics to file 827 * 828 * file format 829 * day (MJD) 830 * time (s past midnight) 831 * text message 832 */ 833 void 834 record_proto_stats( 835 char *str /* text string */ 836 ) 837 { 838 l_fp now; 839 u_long day; 840 841 if (!stats_control) 842 return; 843 844 get_systime(&now); 845 filegen_setup(&protostats, now.l_ui); 846 day = now.l_ui / 86400 + MJD_1900; 847 now.l_ui %= 86400; 848 if (protostats.fp != NULL) { 849 fprintf(protostats.fp, "%lu %s %s\n", day, 850 ulfptoa(&now, 3), str); 851 fflush(protostats.fp); 852 } 853 } 854 855 856 #ifdef AUTOKEY 857 /* 858 * record_crypto_stats - write crypto statistics to file 859 * 860 * file format: 861 * day (mjd) 862 * time (s past midnight) 863 * peer ip address 864 * text message 865 */ 866 void 867 record_crypto_stats( 868 sockaddr_u *addr, 869 const char *text /* text message */ 870 ) 871 { 872 l_fp now; 873 u_long day; 874 875 if (!stats_control) 876 return; 877 878 get_systime(&now); 879 filegen_setup(&cryptostats, now.l_ui); 880 day = now.l_ui / 86400 + MJD_1900; 881 now.l_ui %= 86400; 882 if (cryptostats.fp != NULL) { 883 if (addr == NULL) 884 fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 885 day, ulfptoa(&now, 3), text); 886 else 887 fprintf(cryptostats.fp, "%lu %s %s %s\n", 888 day, ulfptoa(&now, 3), stoa(addr), text); 889 fflush(cryptostats.fp); 890 } 891 } 892 #endif /* AUTOKEY */ 893 894 895 #ifdef DEBUG_TIMING 896 /* 897 * record_timing_stats - write timing statistics to file 898 * 899 * file format: 900 * day (mjd) 901 * time (s past midnight) 902 * text message 903 */ 904 void 905 record_timing_stats( 906 const char *text /* text message */ 907 ) 908 { 909 static unsigned int flshcnt; 910 l_fp now; 911 u_long day; 912 913 if (!stats_control) 914 return; 915 916 get_systime(&now); 917 filegen_setup(&timingstats, now.l_ui); 918 day = now.l_ui / 86400 + MJD_1900; 919 now.l_ui %= 86400; 920 if (timingstats.fp != NULL) { 921 fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 922 3), text); 923 if (++flshcnt % 100 == 0) 924 fflush(timingstats.fp); 925 } 926 } 927 #endif 928 929 930 /* 931 * check_leap_file - See if the leapseconds file has been updated. 932 * 933 * Returns: n/a 934 * 935 * Note: This loads a new leapfile on the fly. Currently a leap file 936 * without SHA1 signature is accepted, but if there is a signature line, 937 * the signature must be valid or the file is rejected. 938 */ 939 void 940 check_leap_file( 941 int is_daily_check, 942 uint32_t ntptime , 943 const time_t *systime 944 ) 945 { 946 /* just do nothing if there is no leap file */ 947 if ( ! (leapfile_name && *leapfile_name)) 948 return; 949 950 /* try to load leapfile, force it if no leapfile loaded yet */ 951 if (leapsec_load_file( 952 leapfile_name, &leapfile_stat, 953 !have_leapfile, is_daily_check, chck_leaphash)) 954 have_leapfile = TRUE; 955 else if (!have_leapfile) 956 return; 957 958 check_leap_expiration(is_daily_check, ntptime, systime); 959 } 960 961 /* 962 * check expiration of a loaded leap table 963 */ 964 static void 965 check_leap_expiration( 966 int is_daily_check, 967 uint32_t ntptime , 968 const time_t *systime 969 ) 970 { 971 static const char * const logPrefix = "leapsecond file"; 972 int rc; 973 974 /* test the expiration of the leap data and log with proper 975 * level and frequency (once/hour or once/day, depending on the 976 * state. 977 */ 978 rc = leapsec_daystolive(ntptime, systime); 979 if (rc == 0) { 980 msyslog(LOG_WARNING, 981 "%s ('%s'): will expire in less than one day", 982 logPrefix, leapfile_name); 983 } else if (is_daily_check && rc < 28) { 984 if (rc < 0) 985 msyslog(LOG_ERR, 986 "%s ('%s'): expired %d day%s ago", 987 logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 988 else 989 msyslog(LOG_WARNING, 990 "%s ('%s'): will expire in less than %d days", 991 logPrefix, leapfile_name, 1+rc); 992 } 993 } 994 995 996 /* 997 * getauthkeys - read the authentication keys from the specified file 998 */ 999 void 1000 getauthkeys( 1001 const char *keyfile 1002 ) 1003 { 1004 size_t len; 1005 1006 len = strlen(keyfile); 1007 if (!len) 1008 return; 1009 1010 #ifndef SYS_WINNT 1011 key_file_name = erealloc(key_file_name, len + 1); 1012 memcpy(key_file_name, keyfile, len + 1); 1013 #else 1014 key_file_name = erealloc(key_file_name, _MAX_PATH); 1015 if (len + 1 > _MAX_PATH) 1016 return; 1017 if (!ExpandEnvironmentStrings(keyfile, key_file_name, 1018 _MAX_PATH)) { 1019 msyslog(LOG_ERR, 1020 "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 1021 strlcpy(key_file_name, keyfile, _MAX_PATH); 1022 } 1023 key_file_name = erealloc(key_file_name, 1024 1 + strlen(key_file_name)); 1025 #endif /* SYS_WINNT */ 1026 1027 authreadkeys(key_file_name); 1028 } 1029 1030 1031 /* 1032 * rereadkeys - read the authentication key file over again. 1033 */ 1034 void 1035 rereadkeys(void) 1036 { 1037 if (NULL != key_file_name) 1038 authreadkeys(key_file_name); 1039 } 1040 1041 1042 #if notyet 1043 /* 1044 * ntp_exit - document explicitly that ntpd has exited 1045 */ 1046 void 1047 ntp_exit(int retval) 1048 { 1049 msyslog(LOG_ERR, "EXITING with return code %d", retval); 1050 exit(retval); 1051 } 1052 #endif 1053 1054 /* 1055 * fstostr - prettyprint NTP seconds 1056 */ 1057 char * fstostr( 1058 time_t ntp_stamp 1059 ) 1060 { 1061 char * buf; 1062 struct calendar tm; 1063 1064 LIB_GETBUF(buf); 1065 if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 1066 snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 1067 (long)ntp_stamp); 1068 else 1069 snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 1070 tm.year, tm.month, tm.monthday, 1071 tm.hour, tm.minute); 1072 return buf; 1073 } 1074 1075 1076 /* 1077 * ntpd_time_stepped is called back by step_systime(), allowing ntpd 1078 * to do any one-time processing necessitated by the step. 1079 */ 1080 void 1081 ntpd_time_stepped(void) 1082 { 1083 u_int saved_mon_enabled; 1084 1085 /* 1086 * flush the monitor MRU list which contains l_fp timestamps 1087 * which should not be compared across the step. 1088 */ 1089 if (MON_OFF != mon_enabled) { 1090 saved_mon_enabled = mon_enabled; 1091 mon_stop(MON_OFF); 1092 mon_start(saved_mon_enabled); 1093 } 1094 1095 /* inform interpolating Windows code to allow time to go back */ 1096 #ifdef SYS_WINNT 1097 win_time_stepped(); 1098 #endif 1099 } 1100