PageRenderTime 45ms CodeModel.GetById 11ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/ntpd/ntp_util.c

https://bitbucket.org/freebsd/freebsd-head/
C | 801 lines | 774 code | 9 blank | 18 comment | 2 complexity | e3c99388bedd1787c8f517ed985fa470 MD5 | raw file
  1/*
  2 * ntp_util.c - stuff I didn't have any other place for
  3 */
  4
  5#ifdef HAVE_CONFIG_H
  6# include <config.h>
  7#endif
  8
  9#include "ntpd.h"
 10#include "ntp_io.h"
 11#include "ntp_unixtime.h"
 12#include "ntp_filegen.h"
 13#include "ntp_if.h"
 14#include "ntp_stdlib.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/*
 41 * This contains odds and ends.  Right now the only thing you'll find
 42 * in here is the hourly stats printer and some code to support
 43 * rereading the keys file, but I may eventually put other things in
 44 * here such as code to do something with the leap bits.
 45 */
 46/*
 47 * Name of the keys file
 48 */
 49static	char *key_file_name;
 50
 51/*
 52 * The name of the drift_comp file and the temporary.
 53 */
 54static	char *stats_drift_file;
 55static	char *stats_temp_file;
 56int stats_write_period = 3600;	/* # of seconds between writes. */
 57double stats_write_tolerance = 0;
 58static double prev_drift_comp = 99999.;
 59
 60/*
 61 * Statistics file stuff
 62 */
 63#ifndef NTP_VAR
 64# ifndef SYS_WINNT
 65#  define NTP_VAR "/var/NTP/"		/* NOTE the trailing '/' */
 66# else
 67#  define NTP_VAR "c:\\var\\ntp\\"		/* NOTE the trailing '\\' */
 68# endif /* SYS_WINNT */
 69#endif
 70
 71#ifndef MAXPATHLEN
 72# define MAXPATHLEN 256
 73#endif
 74
 75static	char statsdir[MAXPATHLEN] = NTP_VAR;
 76
 77static FILEGEN peerstats;
 78static FILEGEN loopstats;
 79static FILEGEN clockstats;
 80static FILEGEN rawstats;
 81static FILEGEN sysstats;
 82#ifdef DEBUG_TIMING
 83static FILEGEN timingstats;
 84#endif
 85#ifdef OPENSSL
 86static FILEGEN cryptostats;
 87#endif /* OPENSSL */
 88
 89/*
 90 * This controls whether stats are written to the fileset. Provided
 91 * so that ntpdc can turn off stats when the file system fills up. 
 92 */
 93int stats_control;
 94
 95/*
 96 * Initial frequency offset later passed to the loopfilter.
 97 */
 98double	old_drift;
 99
100/*
101 * init_util - initialize the utilities
102 */
103void
104init_util(void)
105{
106	stats_drift_file = 0;
107	stats_temp_file = 0;
108	key_file_name = 0;
109
110	filegen_register(&statsdir[0], "peerstats", &peerstats);
111
112	filegen_register(&statsdir[0], "loopstats", &loopstats);
113
114	filegen_register(&statsdir[0], "clockstats", &clockstats);
115
116	filegen_register(&statsdir[0], "rawstats", &rawstats);
117
118	filegen_register(&statsdir[0], "sysstats", &sysstats);
119
120#ifdef OPENSSL
121	filegen_register(&statsdir[0], "cryptostats", &cryptostats);
122#endif /* OPENSSL */
123
124#ifdef DEBUG_TIMING
125	filegen_register(&statsdir[0], "timingstats", &timingstats);
126#endif
127}
128
129
130/*
131 * hourly_stats - print some interesting stats
132 */
133void
134write_stats(void)
135{
136	FILE *fp;
137
138#ifdef DOSYNCTODR
139	struct timeval tv;
140#if !defined(VMS)
141	int prio_set;
142#endif
143#ifdef HAVE_GETCLOCK
144        struct timespec ts;
145#endif
146	int o_prio;
147
148	/*
149	 * Sometimes having a Sun can be a drag.
150	 *
151	 * The kernel variable dosynctodr controls whether the system's
152	 * soft clock is kept in sync with the battery clock. If it
153	 * is zero, then the soft clock is not synced, and the battery
154	 * clock is simply left to rot. That means that when the system
155	 * reboots, the battery clock (which has probably gone wacky)
156	 * sets the soft clock. That means ntpd starts off with a very
157	 * confused idea of what time it is. It then takes a large
158	 * amount of time to figure out just how wacky the battery clock
159	 * has made things drift, etc, etc. The solution is to make the
160	 * battery clock sync up to system time. The way to do THAT is
161	 * to simply set the time of day to the current time of day, but
162	 * as quickly as possible. This may, or may not be a sensible
163	 * thing to do.
164	 *
165	 * CAVEAT: settimeofday() steps the sun clock by about 800 us,
166	 *         so setting DOSYNCTODR seems a bad idea in the
167	 *         case of us resolution
168	 */
169
170#if !defined(VMS)
171	/* (prr) getpriority returns -1 on error, but -1 is also a valid
172	 * return value (!), so instead we have to zero errno before the
173	 * call and check it for non-zero afterwards.
174	 */
175	errno = 0;
176	prio_set = 0;
177	o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
178
179	/*
180	 * (prr) if getpriority succeeded, call setpriority to raise
181	 * scheduling priority as high as possible.  If that succeeds
182	 * as well, set the prio_set flag so we remember to reset
183	 * priority to its previous value below.  Note that on Solaris
184	 * 2.6 (and beyond?), both getpriority and setpriority will fail
185	 * with ESRCH, because sched_setscheduler (called from main) put
186	 * us in the real-time scheduling class which setpriority
187	 * doesn't know about. Being in the real-time class is better
188	 * than anything setpriority can do, anyhow, so this error is
189	 * silently ignored.
190	 */
191	if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
192		prio_set = 1;	/* overdrive */
193#endif /* VMS */
194#ifdef HAVE_GETCLOCK
195        (void) getclock(TIMEOFDAY, &ts);
196        tv.tv_sec = ts.tv_sec;
197        tv.tv_usec = ts.tv_nsec / 1000;
198#else /*  not HAVE_GETCLOCK */
199	GETTIMEOFDAY(&tv,(struct timezone *)NULL);
200#endif /* not HAVE_GETCLOCK */
201	if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) {
202		msyslog(LOG_ERR, "can't sync battery time: %m");
203	}
204#if !defined(VMS)
205	if (prio_set)
206		setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
207#endif /* VMS */
208#endif /* DOSYNCTODR */
209
210	NLOG(NLOG_SYSSTATIST)
211		msyslog(LOG_INFO,
212		    "offset %.6f sec freq %.3f ppm error %.6f poll %d",
213		    last_offset, drift_comp * 1e6, sys_jitter,
214		    sys_poll);
215
216	
217	record_sys_stats();
218	if ((u_long)(fabs(prev_drift_comp - drift_comp) * 1e9) <=
219	    (u_long)(fabs(stats_write_tolerance * drift_comp) * 1e9)) {
220	     return;
221	}
222	prev_drift_comp = drift_comp;
223	if (stats_drift_file != 0) {
224		if ((fp = fopen(stats_temp_file, "w")) == NULL) {
225			msyslog(LOG_ERR, "can't open %s: %m",
226			    stats_temp_file);
227			return;
228		}
229		fprintf(fp, "%.3f\n", drift_comp * 1e6);
230		(void)fclose(fp);
231		/* atomic */
232#ifdef SYS_WINNT
233		(void) _unlink(stats_drift_file); /* rename semantics differ under NT */
234#endif /* SYS_WINNT */
235
236#ifndef NO_RENAME
237		(void) rename(stats_temp_file, stats_drift_file);
238#else
239		/* we have no rename NFS of ftp in use */
240		if ((fp = fopen(stats_drift_file, "w")) == NULL) {
241			msyslog(LOG_ERR, "can't open %s: %m",
242			    stats_drift_file);
243			return;
244		}
245
246#endif
247
248#if defined(VMS)
249		/* PURGE */
250		{
251			$DESCRIPTOR(oldvers,";-1");
252			struct dsc$descriptor driftdsc = {
253				strlen(stats_drift_file),0,0,stats_drift_file };
254
255			while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
256		}
257#endif
258	}
259}
260
261
262/*
263 * stats_config - configure the stats operation
264 */
265void
266stats_config(
267	int item,
268	const char *invalue	/* only one type so far */
269	)
270{
271	FILE *fp;
272	const char *value;
273	int len;
274
275	/*
276	 * Expand environment strings under Windows NT, since the
277	 * command interpreter doesn't do this, the program must.
278	 */
279#ifdef SYS_WINNT
280	char newvalue[MAX_PATH], parameter[MAX_PATH];
281
282	if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
283 		switch(item) {
284		    case STATS_FREQ_FILE:
285			strcpy(parameter,"STATS_FREQ_FILE");
286			break;
287		    case STATS_STATSDIR:
288			strcpy(parameter,"STATS_STATSDIR");
289			break;
290		    case STATS_PID_FILE:
291			strcpy(parameter,"STATS_PID_FILE");
292			break;
293		    default:
294			strcpy(parameter,"UNKNOWN");
295			break;
296		}
297		value = invalue;
298
299		msyslog(LOG_ERR,
300		    "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
301	} else {
302		value = newvalue;
303	}
304#else    
305	value = invalue;
306#endif /* SYS_WINNT */
307
308	switch(item) {
309	    case STATS_FREQ_FILE:
310		if (stats_drift_file != 0) {
311			(void) free(stats_drift_file);
312			(void) free(stats_temp_file);
313			stats_drift_file = 0;
314			stats_temp_file = 0;
315		}
316
317		if (value == 0 || (len = strlen(value)) == 0)
318		    break;
319
320		stats_drift_file = (char*)emalloc((u_int)(len + 1));
321#if !defined(VMS)
322		stats_temp_file = (char*)emalloc((u_int)(len +
323		    sizeof(".TEMP")));
324#else
325		stats_temp_file = (char*)emalloc((u_int)(len +
326		    sizeof("-TEMP")));
327#endif /* VMS */
328		memmove(stats_drift_file, value, (unsigned)(len+1));
329		memmove(stats_temp_file, value, (unsigned)len);
330#if !defined(VMS)
331		memmove(stats_temp_file + len, ".TEMP",
332		    sizeof(".TEMP"));
333#else
334		memmove(stats_temp_file + len, "-TEMP",
335		    sizeof("-TEMP"));
336#endif /* VMS */
337
338		/*
339		 * Open drift file and read frequency. If the file is
340		 * missing or contains errors, tell the loop to reset.
341		 */
342		if ((fp = fopen(stats_drift_file, "r")) == NULL) {
343			old_drift = 1e9;
344			break;
345		}
346		if (fscanf(fp, "%lf", &old_drift) != 1) {
347			msyslog(LOG_ERR, "Frequency format error in %s", 
348			    stats_drift_file);
349			old_drift = 1e9;
350			fclose(fp);
351			break;
352		}
353		fclose(fp);
354		prev_drift_comp = old_drift / 1e6;
355		msyslog(LOG_INFO,
356		    "frequency initialized %.3f PPM from %s",
357			old_drift, stats_drift_file);
358		break;
359	
360	    case STATS_STATSDIR:
361		if (strlen(value) >= sizeof(statsdir)) {
362			msyslog(LOG_ERR,
363			    "value for statsdir too long (>%d, sigh)",
364			    (int)sizeof(statsdir)-1);
365		} else {
366			l_fp now;
367
368			get_systime(&now);
369			strcpy(statsdir,value);
370			if(peerstats.prefix == &statsdir[0] &&
371			    peerstats.fp != NULL) {
372				fclose(peerstats.fp);
373				peerstats.fp = NULL;
374				filegen_setup(&peerstats, now.l_ui);
375			}
376			if(loopstats.prefix == &statsdir[0] &&
377			    loopstats.fp != NULL) {
378				fclose(loopstats.fp);
379				loopstats.fp = NULL;
380				filegen_setup(&loopstats, now.l_ui);
381			}
382			if(clockstats.prefix == &statsdir[0] &&
383			    clockstats.fp != NULL) {
384				fclose(clockstats.fp);
385				clockstats.fp = NULL;
386				filegen_setup(&clockstats, now.l_ui);
387			}
388			if(rawstats.prefix == &statsdir[0] &&
389			    rawstats.fp != NULL) {
390				fclose(rawstats.fp);
391				rawstats.fp = NULL;
392				filegen_setup(&rawstats, now.l_ui);
393			}
394			if(sysstats.prefix == &statsdir[0] &&
395			    sysstats.fp != NULL) {
396				fclose(sysstats.fp);
397				sysstats.fp = NULL;
398				filegen_setup(&sysstats, now.l_ui);
399			}
400#ifdef OPENSSL
401			if(cryptostats.prefix == &statsdir[0] &&
402			    cryptostats.fp != NULL) {
403				fclose(cryptostats.fp);
404				cryptostats.fp = NULL;
405				filegen_setup(&cryptostats, now.l_ui);
406			}
407#endif /* OPENSSL */
408		}
409		break;
410
411	    case STATS_PID_FILE:
412		if ((fp = fopen(value, "w")) == NULL) {
413			msyslog(LOG_ERR, "Can't open %s: %m", value);
414			break;
415		}
416		fprintf(fp, "%d", (int) getpid());
417		fclose(fp);;
418		break;
419
420	    default:
421		/* oh well */
422		break;
423	}
424}
425
426/*
427 * record_peer_stats - write peer statistics to file
428 *
429 * file format:
430 * day (mjd)
431 * time (s past UTC midnight)
432 * peer (ip address)
433 * peer status word (hex)
434 * peer offset (s)
435 * peer delay (s)
436 * peer error bound (s)
437 * peer error (s)
438*/
439void
440record_peer_stats(
441	struct sockaddr_storage *addr,
442	int	status,
443	double	offset,
444	double	delay,
445	double	dispersion,
446	double	skew
447	)
448{
449	l_fp	now;
450	u_long	day;
451
452	if (!stats_control)
453		return;
454
455	get_systime(&now);
456	filegen_setup(&peerstats, now.l_ui);
457	day = now.l_ui / 86400 + MJD_1900;
458	now.l_ui %= 86400;
459	if (peerstats.fp != NULL) {
460		fprintf(peerstats.fp,
461		    "%lu %s %s %x %.9f %.9f %.9f %.9f\n",
462		    day, ulfptoa(&now, 3), stoa(addr), status, offset,
463		    delay, dispersion, skew);
464		fflush(peerstats.fp);
465	}
466}
467
468/*
469 * record_loop_stats - write loop filter statistics to file
470 *
471 * file format:
472 * day (mjd)
473 * time (s past midnight)
474 * offset (s)
475 * frequency (approx ppm)
476 * time constant (log base 2)
477 */
478void
479record_loop_stats(
480	double	offset,
481	double	freq,
482	double	jitter,
483	double	stability,
484	int spoll
485	)
486{
487	l_fp	now;
488	u_long	day;
489
490	if (!stats_control)
491		return;
492
493	get_systime(&now);
494	filegen_setup(&loopstats, now.l_ui);
495	day = now.l_ui / 86400 + MJD_1900;
496	now.l_ui %= 86400;
497	if (loopstats.fp != NULL) {
498		fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
499		    day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
500		    stability * 1e6, spoll);
501		fflush(loopstats.fp);
502	}
503}
504
505/*
506 * record_clock_stats - write clock statistics to file
507 *
508 * file format:
509 * day (mjd)
510 * time (s past midnight)
511 * peer (ip address)
512 * text message
513 */
514void
515record_clock_stats(
516	struct sockaddr_storage *addr,
517	const char *text
518	)
519{
520	l_fp	now;
521	u_long	day;
522
523	if (!stats_control)
524		return;
525
526	get_systime(&now);
527	filegen_setup(&clockstats, now.l_ui);
528	day = now.l_ui / 86400 + MJD_1900;
529	now.l_ui %= 86400;
530	if (clockstats.fp != NULL) {
531		fprintf(clockstats.fp, "%lu %s %s %s\n",
532		    day, ulfptoa(&now, 3), stoa(addr), text);
533		fflush(clockstats.fp);
534	}
535}
536
537/*
538 * record_raw_stats - write raw timestamps to file
539 *
540 *
541 * file format
542 * time (s past midnight)
543 * peer ip address
544 * local ip address
545 * t1 t2 t3 t4 timestamps
546 */
547void
548record_raw_stats(
549        struct sockaddr_storage *srcadr,
550        struct sockaddr_storage *dstadr,
551	l_fp	*t1,
552	l_fp	*t2,
553	l_fp	*t3,
554	l_fp	*t4
555	)
556{
557	l_fp	now;
558	u_long	day;
559
560	if (!stats_control)
561		return;
562
563	get_systime(&now);
564	filegen_setup(&rawstats, now.l_ui);
565	day = now.l_ui / 86400 + MJD_1900;
566	now.l_ui %= 86400;
567	if (rawstats.fp != NULL) {
568                fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n",
569			day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-",
570			ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
571			ulfptoa(t4, 9));
572		fflush(rawstats.fp);
573	}
574}
575
576
577/*
578 * record_sys_stats - write system statistics to file
579 *
580 * file format
581 * time (s past midnight)
582 * time since startup (hr)
583 * packets recieved
584 * packets processed
585 * current version
586 * previous version
587 * bad version
588 * access denied
589 * bad length or format
590 * bad authentication
591 * rate exceeded
592 */
593void
594record_sys_stats(void)
595{
596	l_fp	now;
597	u_long	day;
598
599	if (!stats_control)
600		return;
601
602	get_systime(&now);
603	filegen_setup(&sysstats, now.l_ui);
604	day = now.l_ui / 86400 + MJD_1900;
605	now.l_ui %= 86400;
606	if (sysstats.fp != NULL) {
607                fprintf(sysstats.fp,
608		    "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
609		    day, ulfptoa(&now, 3), sys_stattime / 3600,
610		    sys_received, sys_processed, sys_newversionpkt,
611		    sys_oldversionpkt, sys_unknownversion,
612		    sys_restricted, sys_badlength, sys_badauth,
613		    sys_limitrejected);
614		fflush(sysstats.fp);
615		proto_clr_stats();
616	}
617}
618
619
620#ifdef OPENSSL
621/*
622 * record_crypto_stats - write crypto statistics to file
623 *
624 * file format:
625 * day (mjd)
626 * time (s past midnight)
627 * peer (ip address)
628 * text message
629 */
630void
631record_crypto_stats(
632	struct sockaddr_storage *addr,
633	const char *text
634	)
635{
636	l_fp	now;
637	u_long	day;
638
639	if (!stats_control)
640		return;
641
642	get_systime(&now);
643	filegen_setup(&cryptostats, now.l_ui);
644	day = now.l_ui / 86400 + MJD_1900;
645	now.l_ui %= 86400;
646	if (cryptostats.fp != NULL) {
647		if (addr == NULL)
648			fprintf(cryptostats.fp, "%lu %s %s\n",
649			    day, ulfptoa(&now, 3), text);
650		else
651			fprintf(cryptostats.fp, "%lu %s %s %s\n",
652			    day, ulfptoa(&now, 3), stoa(addr), text);
653		fflush(cryptostats.fp);
654	}
655}
656#endif /* OPENSSL */
657
658#ifdef DEBUG_TIMING
659/*
660 * record_crypto_stats - write crypto statistics to file
661 *
662 * file format:
663 * day (mjd)
664 * time (s past midnight)
665 * text message
666 */
667void
668record_timing_stats(
669	const char *text
670	)
671{
672	static unsigned int flshcnt;
673	l_fp	now;
674	u_long	day;
675
676	if (!stats_control)
677		return;
678
679	get_systime(&now);
680	filegen_setup(&timingstats, now.l_ui);
681	day = now.l_ui / 86400 + MJD_1900;
682	now.l_ui %= 86400;
683	if (timingstats.fp != NULL) {
684		fprintf(timingstats.fp, "%lu %s %s\n",
685			    day, lfptoa(&now, 3), text);
686		if (++flshcnt % 100 == 0)
687			fflush(timingstats.fp);
688	}
689}
690#endif
691/*
692 * getauthkeys - read the authentication keys from the specified file
693 */
694void
695getauthkeys(
696	const char *keyfile
697	)
698{
699	int len;
700
701	len = strlen(keyfile);
702	if (len == 0)
703		return;
704	
705	if (key_file_name != 0) {
706		if (len > (int)strlen(key_file_name)) {
707			(void) free(key_file_name);
708			key_file_name = 0;
709		}
710	}
711
712	if (key_file_name == 0) {
713#ifndef SYS_WINNT
714		key_file_name = (char*)emalloc((u_int) (len + 1));
715#else
716		key_file_name = (char*)emalloc((u_int)  (MAXPATHLEN));
717#endif
718	}
719#ifndef SYS_WINNT
720 	memmove(key_file_name, keyfile, (unsigned)(len+1));
721#else
722	if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN)) 
723	{
724		msyslog(LOG_ERR,
725		    "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
726	}
727#endif /* SYS_WINNT */
728
729	authreadkeys(key_file_name);
730}
731
732
733/*
734 * rereadkeys - read the authentication key file over again.
735 */
736void
737rereadkeys(void)
738{
739	if (key_file_name != 0)
740	    authreadkeys(key_file_name);
741}
742
743/*
744 * sock_hash - hash an sockaddr_storage structure
745 */
746int
747sock_hash(
748	struct sockaddr_storage *addr
749	)
750{
751	int hashVal;
752	int i;
753	int len;
754	char *ch;
755
756	hashVal = 0;
757	len = 0;
758	/*
759	 * We can't just hash the whole thing because there are hidden
760	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
761	 * so just use the family, port and address.
762	 */
763	ch = (char *)&addr->ss_family;
764	hashVal = 37 * hashVal + (int)*ch;
765	if (sizeof(addr->ss_family) > 1) {
766		ch++;
767		hashVal = 37 * hashVal + (int)*ch;
768	}
769	switch(addr->ss_family) {
770	case AF_INET:
771		ch = (char *)&((struct sockaddr_in *)addr)->sin_addr;
772		len = sizeof(struct in_addr);
773		break;
774	case AF_INET6:
775		ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr;
776		len = sizeof(struct in6_addr);
777		break;
778	}
779
780	for (i = 0; i < len ; i++)
781		hashVal = 37 * hashVal + (int)*(ch + i);
782
783	hashVal = hashVal % 128;  /* % MON_HASH_SIZE hardcoded */
784
785	if (hashVal < 0)
786		hashVal += 128;
787
788	return hashVal;
789}
790
791#if notyet
792/*
793 * ntp_exit - document explicitly that ntpd has exited
794 */
795void
796ntp_exit(int retval)
797{
798  msyslog(LOG_ERR, "EXITING with return code %d", retval);
799  exit(retval);
800}
801#endif