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