1 /* $NetBSD: ntp_util.c,v 1.3 2012/02/01 07:46:22 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 #ifndef VMS 362 const char temp_ext[] = ".TEMP"; 363 #else 364 const char temp_ext[] = "-TEMP"; 365 #endif 366 367 /* 368 * Expand environment strings under Windows NT, since the 369 * command interpreter doesn't do this, the program must. 370 */ 371 #ifdef SYS_WINNT 372 char newvalue[MAX_PATH], parameter[MAX_PATH]; 373 374 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 375 switch(item) { 376 case STATS_FREQ_FILE: 377 strcpy(parameter,"STATS_FREQ_FILE"); 378 break; 379 380 case STATS_LEAP_FILE: 381 strcpy(parameter,"STATS_LEAP_FILE"); 382 break; 383 384 case STATS_STATSDIR: 385 strcpy(parameter,"STATS_STATSDIR"); 386 break; 387 388 case STATS_PID_FILE: 389 strcpy(parameter,"STATS_PID_FILE"); 390 break; 391 392 default: 393 strcpy(parameter,"UNKNOWN"); 394 break; 395 } 396 value = invalue; 397 msyslog(LOG_ERR, 398 "ExpandEnvironmentStrings(%s) failed: %m\n", 399 parameter); 400 } else { 401 value = newvalue; 402 } 403 #else 404 value = invalue; 405 #endif /* SYS_WINNT */ 406 407 switch(item) { 408 409 /* 410 * Open and read frequency file. 411 */ 412 case STATS_FREQ_FILE: 413 if (!value || (len = strlen(value)) == 0) 414 break; 415 416 stats_drift_file = erealloc(stats_drift_file, len + 1); 417 stats_temp_file = erealloc(stats_temp_file, 418 len + sizeof(".TEMP")); 419 420 memcpy(stats_drift_file, value, (unsigned)(len+1)); 421 memcpy(stats_temp_file, value, (unsigned)len); 422 memcpy(stats_temp_file + len, temp_ext, 423 sizeof(temp_ext)); 424 425 /* 426 * Open drift file and read frequency. If the file is 427 * missing or contains errors, tell the loop to reset. 428 */ 429 if ((fp = fopen(stats_drift_file, "r")) == NULL) 430 break; 431 432 if (fscanf(fp, "%lf", &old_drift) != 1) { 433 msyslog(LOG_ERR, 434 "format error frequency file %s", 435 stats_drift_file); 436 fclose(fp); 437 break; 438 439 } 440 fclose(fp); 441 old_drift /= 1e6; 442 prev_drift_comp = old_drift; 443 break; 444 445 /* 446 * Specify statistics directory. 447 */ 448 case STATS_STATSDIR: 449 450 /* 451 * HMS: the following test is insufficient: 452 * - value may be missing the DIR_SEP 453 * - we still need the filename after it 454 */ 455 if (strlen(value) >= sizeof(statsdir)) { 456 msyslog(LOG_ERR, 457 "statsdir too long (>%d, sigh)", 458 (int)sizeof(statsdir) - 1); 459 } else { 460 l_fp now; 461 int add_dir_sep; 462 int value_l = strlen(value); 463 464 /* Add a DIR_SEP unless we already have one. */ 465 if (value_l == 0) 466 add_dir_sep = 0; 467 else 468 add_dir_sep = (DIR_SEP != 469 value[value_l - 1]); 470 471 if (add_dir_sep) 472 snprintf(statsdir, sizeof(statsdir), 473 "%s%c", value, DIR_SEP); 474 else 475 snprintf(statsdir, sizeof(statsdir), 476 "%s", value); 477 478 get_systime(&now); 479 if(peerstats.prefix == &statsdir[0] && 480 peerstats.fp != NULL) { 481 fclose(peerstats.fp); 482 peerstats.fp = NULL; 483 filegen_setup(&peerstats, now.l_ui); 484 } 485 if(loopstats.prefix == &statsdir[0] && 486 loopstats.fp != NULL) { 487 fclose(loopstats.fp); 488 loopstats.fp = NULL; 489 filegen_setup(&loopstats, now.l_ui); 490 } 491 if(clockstats.prefix == &statsdir[0] && 492 clockstats.fp != NULL) { 493 fclose(clockstats.fp); 494 clockstats.fp = NULL; 495 filegen_setup(&clockstats, now.l_ui); 496 } 497 if(rawstats.prefix == &statsdir[0] && 498 rawstats.fp != NULL) { 499 fclose(rawstats.fp); 500 rawstats.fp = NULL; 501 filegen_setup(&rawstats, now.l_ui); 502 } 503 if(sysstats.prefix == &statsdir[0] && 504 sysstats.fp != NULL) { 505 fclose(sysstats.fp); 506 sysstats.fp = NULL; 507 filegen_setup(&sysstats, now.l_ui); 508 } 509 if(protostats.prefix == &statsdir[0] && 510 protostats.fp != NULL) { 511 fclose(protostats.fp); 512 protostats.fp = NULL; 513 filegen_setup(&protostats, now.l_ui); 514 } 515 #ifdef OPENSSL 516 if(cryptostats.prefix == &statsdir[0] && 517 cryptostats.fp != NULL) { 518 fclose(cryptostats.fp); 519 cryptostats.fp = NULL; 520 filegen_setup(&cryptostats, now.l_ui); 521 } 522 #endif /* OPENSSL */ 523 #ifdef DEBUG_TIMING 524 if(timingstats.prefix == &statsdir[0] && 525 timingstats.fp != NULL) { 526 fclose(timingstats.fp); 527 timingstats.fp = NULL; 528 filegen_setup(&timingstats, now.l_ui); 529 } 530 #endif /* DEBUG_TIMING */ 531 } 532 break; 533 534 /* 535 * Open pid file. 536 */ 537 case STATS_PID_FILE: 538 if ((fp = fopen(value, "w")) == NULL) { 539 msyslog(LOG_ERR, "pid file %s: %m", 540 value); 541 break; 542 } 543 fprintf(fp, "%d", (int)getpid()); 544 fclose(fp);; 545 break; 546 547 /* 548 * Read leapseconds file. 549 */ 550 case STATS_LEAP_FILE: 551 if ((fp = fopen(value, "r")) == NULL) { 552 msyslog(LOG_ERR, "leapseconds file %s: %m", 553 value); 554 break; 555 } 556 557 if (leap_file(fp) < 0) { 558 msyslog(LOG_ERR, 559 "format error leapseconds file %s", 560 value); 561 } else { 562 strcpy(str1, fstostr(leap_sec)); 563 strcpy(str2, fstostr(leap_expire)); 564 snprintf(tbuf, sizeof(tbuf), 565 "%d leap %s expire %s", leap_tai, str1, 566 str2); 567 report_event(EVNT_TAI, NULL, tbuf); 568 } 569 fclose(fp); 570 break; 571 572 default: 573 /* oh well */ 574 break; 575 } 576 } 577 578 579 /* 580 * record_peer_stats - write peer statistics to file 581 * 582 * file format: 583 * day (MJD) 584 * time (s past UTC midnight) 585 * IP address 586 * status word (hex) 587 * offset 588 * delay 589 * dispersion 590 * jitter 591 */ 592 void 593 record_peer_stats( 594 sockaddr_u *addr, 595 int status, 596 double offset, /* offset */ 597 double delay, /* delay */ 598 double dispersion, /* dispersion */ 599 double jitter /* jitter */ 600 ) 601 { 602 l_fp now; 603 u_long day; 604 605 if (!stats_control) 606 return; 607 608 get_systime(&now); 609 filegen_setup(&peerstats, now.l_ui); 610 day = now.l_ui / 86400 + MJD_1900; 611 now.l_ui %= 86400; 612 if (peerstats.fp != NULL) { 613 fprintf(peerstats.fp, 614 "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 615 ulfptoa(&now, 3), stoa(addr), status, offset, 616 delay, dispersion, jitter); 617 fflush(peerstats.fp); 618 } 619 } 620 621 622 /* 623 * record_loop_stats - write loop filter statistics to file 624 * 625 * file format: 626 * day (MJD) 627 * time (s past midnight) 628 * offset 629 * frequency (PPM) 630 * jitter 631 * wnder (PPM) 632 * time constant (log2) 633 */ 634 void 635 record_loop_stats( 636 double offset, /* offset */ 637 double freq, /* frequency (PPM) */ 638 double jitter, /* jitter */ 639 double wander, /* wander (PPM) */ 640 int spoll 641 ) 642 { 643 l_fp now; 644 u_long day; 645 646 if (!stats_control) 647 return; 648 649 get_systime(&now); 650 filegen_setup(&loopstats, now.l_ui); 651 day = now.l_ui / 86400 + MJD_1900; 652 now.l_ui %= 86400; 653 if (loopstats.fp != NULL) { 654 fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 655 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 656 wander * 1e6, spoll); 657 fflush(loopstats.fp); 658 } 659 } 660 661 662 /* 663 * record_clock_stats - write clock statistics to file 664 * 665 * file format: 666 * day (MJD) 667 * time (s past midnight) 668 * IP address 669 * text message 670 */ 671 void 672 record_clock_stats( 673 sockaddr_u *addr, 674 const char *text /* timecode string */ 675 ) 676 { 677 l_fp now; 678 u_long day; 679 680 if (!stats_control) 681 return; 682 683 get_systime(&now); 684 filegen_setup(&clockstats, now.l_ui); 685 day = now.l_ui / 86400 + MJD_1900; 686 now.l_ui %= 86400; 687 if (clockstats.fp != NULL) { 688 fprintf(clockstats.fp, "%lu %s %s %s\n", day, 689 ulfptoa(&now, 3), stoa(addr), text); 690 fflush(clockstats.fp); 691 } 692 } 693 694 695 /* 696 * record_raw_stats - write raw timestamps to file 697 * 698 * file format 699 * day (MJD) 700 * time (s past midnight) 701 * peer ip address 702 * IP address 703 * t1 t2 t3 t4 timestamps 704 */ 705 void 706 record_raw_stats( 707 sockaddr_u *srcadr, 708 sockaddr_u *dstadr, 709 l_fp *t1, /* originate timestamp */ 710 l_fp *t2, /* receive timestamp */ 711 l_fp *t3, /* transmit timestamp */ 712 l_fp *t4 /* destination timestamp */ 713 ) 714 { 715 l_fp now; 716 u_long day; 717 718 if (!stats_control) 719 return; 720 721 get_systime(&now); 722 filegen_setup(&rawstats, now.l_ui); 723 day = now.l_ui / 86400 + MJD_1900; 724 now.l_ui %= 86400; 725 if (rawstats.fp != NULL) { 726 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", day, 727 ulfptoa(&now, 3), stoa(srcadr), dstadr ? 728 stoa(dstadr) : "-", ulfptoa(t1, 9), ulfptoa(t2, 9), 729 ulfptoa(t3, 9), ulfptoa(t4, 9)); 730 fflush(rawstats.fp); 731 } 732 } 733 734 735 /* 736 * record_sys_stats - write system statistics to file 737 * 738 * file format 739 * day (MJD) 740 * time (s past midnight) 741 * time since reset 742 * packets recieved 743 * packets for this host 744 * current version 745 * old version 746 * access denied 747 * bad length or format 748 * bad authentication 749 * declined 750 * rate exceeded 751 * KoD sent 752 */ 753 void 754 record_sys_stats(void) 755 { 756 l_fp now; 757 u_long day; 758 759 if (!stats_control) 760 return; 761 762 get_systime(&now); 763 filegen_setup(&sysstats, now.l_ui); 764 day = now.l_ui / 86400 + MJD_1900; 765 now.l_ui %= 86400; 766 if (sysstats.fp != NULL) { 767 fprintf(sysstats.fp, 768 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 769 day, ulfptoa(&now, 3), current_time - sys_stattime, 770 sys_received, sys_processed, sys_newversion, 771 sys_oldversion, sys_restricted, sys_badlength, 772 sys_badauth, sys_declined, sys_limitrejected, 773 sys_kodsent); 774 fflush(sysstats.fp); 775 proto_clr_stats(); 776 } 777 } 778 779 780 /* 781 * record_proto_stats - write system statistics to file 782 * 783 * file format 784 * day (MJD) 785 * time (s past midnight) 786 * text message 787 */ 788 void 789 record_proto_stats( 790 char *str /* text string */ 791 ) 792 { 793 l_fp now; 794 u_long day; 795 796 if (!stats_control) 797 return; 798 799 get_systime(&now); 800 filegen_setup(&protostats, now.l_ui); 801 day = now.l_ui / 86400 + MJD_1900; 802 now.l_ui %= 86400; 803 if (protostats.fp != NULL) { 804 fprintf(protostats.fp, "%lu %s %s\n", day, 805 ulfptoa(&now, 3), str); 806 fflush(protostats.fp); 807 } 808 } 809 810 811 #ifdef OPENSSL 812 /* 813 * record_crypto_stats - write crypto statistics to file 814 * 815 * file format: 816 * day (mjd) 817 * time (s past midnight) 818 * peer ip address 819 * text message 820 */ 821 void 822 record_crypto_stats( 823 sockaddr_u *addr, 824 const char *text /* text message */ 825 ) 826 { 827 l_fp now; 828 u_long day; 829 830 if (!stats_control) 831 return; 832 833 get_systime(&now); 834 filegen_setup(&cryptostats, now.l_ui); 835 day = now.l_ui / 86400 + MJD_1900; 836 now.l_ui %= 86400; 837 if (cryptostats.fp != NULL) { 838 if (addr == NULL) 839 fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 840 day, ulfptoa(&now, 3), text); 841 else 842 fprintf(cryptostats.fp, "%lu %s %s %s\n", 843 day, ulfptoa(&now, 3), stoa(addr), text); 844 fflush(cryptostats.fp); 845 } 846 } 847 #endif /* OPENSSL */ 848 849 850 #ifdef DEBUG_TIMING 851 /* 852 * record_timing_stats - write timing statistics to file 853 * 854 * file format: 855 * day (mjd) 856 * time (s past midnight) 857 * text message 858 */ 859 void 860 record_timing_stats( 861 const char *text /* text message */ 862 ) 863 { 864 static unsigned int flshcnt; 865 l_fp now; 866 u_long day; 867 868 if (!stats_control) 869 return; 870 871 get_systime(&now); 872 filegen_setup(&timingstats, now.l_ui); 873 day = now.l_ui / 86400 + MJD_1900; 874 now.l_ui %= 86400; 875 if (timingstats.fp != NULL) { 876 fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 877 3), text); 878 if (++flshcnt % 100 == 0) 879 fflush(timingstats.fp); 880 } 881 } 882 #endif 883 884 885 /* 886 * leap_file - read leapseconds file 887 * 888 * Read the ERTS leapsecond file in NIST text format and extract the 889 * NTP seconds of the latest leap and TAI offset after the leap. 890 */ 891 static int 892 leap_file( 893 FILE *fp /* file handle */ 894 ) 895 { 896 char buf[NTP_MAXSTRLEN]; /* file line buffer */ 897 u_long leap; /* NTP time at leap */ 898 u_long expire; /* NTP time when file expires */ 899 int offset; /* TAI offset at leap (s) */ 900 int i; 901 902 /* 903 * Read and parse the leapseconds file. Empty lines and comments 904 * are ignored. A line beginning with #@ contains the file 905 * expiration time in NTP seconds. Other lines begin with two 906 * integers followed by junk or comments. The first integer is 907 * the NTP seconds at the leap, the second is the TAI offset 908 * after the leap. 909 */ 910 offset = 0; 911 leap = 0; 912 expire = 0; 913 i = 10; 914 while (fgets(buf, NTP_MAXSTRLEN - 1, fp) != NULL) { 915 if (strlen(buf) < 1) 916 continue; 917 918 if (buf[0] == '#') { 919 if (strlen(buf) < 3) 920 continue; 921 922 /* 923 * Note the '@' flag was used only in the 2006 924 * table; previious to that the flag was '$'. 925 */ 926 if (buf[1] == '@' || buf[1] == '$') { 927 if (sscanf(&buf[2], "%lu", &expire) != 928 1) 929 return (-1); 930 931 continue; 932 } 933 } 934 if (sscanf(buf, "%lu %d", &leap, &offset) == 2) { 935 936 /* 937 * Valid offsets must increase by one for each 938 * leap. 939 */ 940 if (i++ != offset) 941 return (-1); 942 } 943 } 944 945 /* 946 * There must be at least one leap. 947 */ 948 if (i == 10) 949 return (-1); 950 951 leap_tai = offset; 952 leap_sec = leap; 953 leap_expire = expire; 954 return (0); 955 } 956 957 958 /* 959 * leap_month - returns seconds until the end of the month. 960 */ 961 u_long 962 leap_month( 963 u_long sec /* current NTP second */ 964 ) 965 { 966 u_long ltemp; 967 u_long *ptr; 968 u_long year[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 969 31}; 970 u_long lyear[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 971 31}; 972 973 /* 974 * Find current leap cycle. 975 */ 976 ltemp = sec; 977 while (ltemp >= L_CENT) 978 ltemp -= L_CENT; 979 while (ltemp >= L_4YEAR) 980 ltemp -= L_4YEAR; 981 982 /* 983 * We are within four years of the target. If in leap year, use 984 * leap year month table; otherwise, use year month table. 985 */ 986 if (ltemp < L_LYEAR) { 987 ptr = lyear; 988 } else { 989 ptr = year; 990 ltemp -= L_LYEAR; 991 while (ltemp >= L_YEAR) 992 ltemp -= L_YEAR; 993 } 994 995 /* 996 * We are within one year of the target. Find the month of the 997 * leap. 998 */ 999 while (ltemp >= *ptr * L_DAY) 1000 ltemp -= *ptr++ * L_DAY; 1001 1002 /* 1003 * The result is the number of seconds until the end of the 1004 * month when the leap is to occur. 1005 */ 1006 return (*ptr * L_DAY - ltemp - L_DAY); 1007 } 1008 1009 1010 /* 1011 * getauthkeys - read the authentication keys from the specified file 1012 */ 1013 void 1014 getauthkeys( 1015 const char *keyfile 1016 ) 1017 { 1018 int len; 1019 1020 len = strlen(keyfile); 1021 if (!len) 1022 return; 1023 1024 #ifndef SYS_WINNT 1025 key_file_name = erealloc(key_file_name, len + 1); 1026 memmove(key_file_name, keyfile, len + 1); 1027 #else 1028 key_file_name = erealloc(key_file_name, _MAX_PATH); 1029 if (len + 1 > _MAX_PATH) 1030 return; 1031 if (!ExpandEnvironmentStrings(keyfile, key_file_name, 1032 _MAX_PATH)) { 1033 msyslog(LOG_ERR, 1034 "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 1035 strncpy(key_file_name, keyfile, _MAX_PATH); 1036 } 1037 #endif /* SYS_WINNT */ 1038 1039 authreadkeys(key_file_name); 1040 } 1041 1042 1043 /* 1044 * rereadkeys - read the authentication key file over again. 1045 */ 1046 void 1047 rereadkeys(void) 1048 { 1049 if (NULL != key_file_name) 1050 authreadkeys(key_file_name); 1051 } 1052 1053 1054 /* 1055 * sock_hash - hash a sockaddr_u structure 1056 */ 1057 u_short 1058 sock_hash( 1059 sockaddr_u *addr 1060 ) 1061 { 1062 u_int hashVal; 1063 u_int j; 1064 size_t len; 1065 u_char *pch; 1066 hashVal = 0; 1067 len = 0; 1068 1069 /* 1070 * We can't just hash the whole thing because there are hidden 1071 * fields in sockaddr_in6 that might be filled in by recvfrom(), 1072 * so just use the family, port and address. 1073 */ 1074 pch = (u_char *)&AF(addr); 1075 hashVal = 37 * hashVal + *pch; 1076 if (sizeof(AF(addr)) > 1) { 1077 pch++; 1078 hashVal = 37 * hashVal + *pch; 1079 } 1080 switch(AF(addr)) { 1081 case AF_INET: 1082 pch = (u_char *)&SOCK_ADDR4(addr); 1083 len = sizeof(SOCK_ADDR4(addr)); 1084 break; 1085 1086 case AF_INET6: 1087 pch = (u_char *)&SOCK_ADDR6(addr); 1088 len = sizeof(SOCK_ADDR6(addr)); 1089 break; 1090 } 1091 1092 for (j = 0; j < len ; j++) 1093 hashVal = 37 * hashVal + pch[j]; 1094 1095 hashVal = hashVal & NTP_HASH_MASK; 1096 1097 return (u_short)hashVal; 1098 } 1099 1100 1101 #if notyet 1102 /* 1103 * ntp_exit - document explicitly that ntpd has exited 1104 */ 1105 void 1106 ntp_exit(int retval) 1107 { 1108 msyslog(LOG_ERR, "EXITING with return code %d", retval); 1109 exit(retval); 1110 } 1111 #endif 1112 1113 /* 1114 * fstostr - prettyprint NTP seconds 1115 */ 1116 char * fstostr( 1117 time_t ntp_stamp 1118 ) 1119 { 1120 static char str[20]; 1121 struct tm * tm; 1122 time_t unix_stamp; 1123 1124 unix_stamp = ntp_stamp - JAN_1970; 1125 tm = gmtime(&unix_stamp); 1126 if (NULL != tm) 1127 snprintf(str, sizeof(str), 1128 "%04d%02d%02d%02d%02d", 1129 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 1130 tm->tm_hour, tm->tm_min); 1131 else 1132 strcpy(str, "gmtime() error"); 1133 1134 return str; 1135 } 1136