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