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