1
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <netinet/in.h>
9#include <netdb.h>
10#include <arpa/inet.h>
11#include <time.h>
12#include <unistd.h>
13#include <errno.h>
14#ifdef _PRECISION_SIOCGSTAMP
15#include <sys/ioctl.h>
16#endif
17
18#define ENABLE_DEBUG
19
20extern char *optarg;
21
22#ifdef linux
23#include <sys/utsname.h>
24#include <sys/time.h>
25typedef u_int32_t __u32;
26#include <sys/timex.h>
27#else
28#define main ntpclient
29extern struct hostent *gethostbyname(const char *name);
30extern int h_errno;
31#define herror(hostname) \
32	fprintf(stderr,"Error %d looking up hostname %s\n", h_errno,hostname)
33typedef uint32_t __u32;
34#endif
35
36#define JAN_1970        0x83aa7e80      /* 2208988800 1970 - 1900 in seconds */
37#define NTP_PORT (123)
38
39/* How to multiply by 4294.967296 quickly (and not quite exactly)
40 * without using floating point or greater than 32-bit integers.
41 * If you want to fix the last 12 microseconds of error, add in
42 * (2911*(x))>>28)
43 */
44#define NTPFRAC(x) ( 4294*(x) + ( (1981*(x))>>11 ) )
45
46/* The reverse of the above, needed if we want to set our microsecond
47 * clock (via settimeofday) based on the incoming time in NTP format.
48 * Basically exact.
49 */
50#define USEC(x) ( ( (x) >> 12 ) - 759 * ( ( ( (x) >> 10 ) + 32768 ) >> 16 ) )
51
52/* Converts NTP delay and dispersion, apparently in seconds scaled
53 * by 65536, to microseconds.  RFC1305 states this time is in seconds,
54 * doesn't mention the scaling.
55 * Should somehow be the same as 1000000 * x / 65536
56 */
57#define sec2u(x) ( (x) * 15.2587890625 )
58
59struct ntptime {
60	unsigned int coarse;
61	unsigned int fine;
62};
63
64void send_packet(int usd);
65void rfc1305print(char *data, struct ntptime *arrival);
66void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len);
67
68/* global variables (I know, bad form, but this is a short program) */
69char incoming[1500];
70struct timeval time_of_send;
71int live=0;
72int set_clock=0;   /* non-zero presumably needs root privs */
73
74static __u32 transmit_timestamp[2]; /* Foxconn added pling 10/31/2006 */
75
76#ifdef ENABLE_DEBUG
77int debug=0;
78#define DEBUG_OPTION "d"
79#else
80#define debug 0
81#define DEBUG_OPTION
82#endif
83
84#ifdef NOT_REMOVED
85int contemplate_data(unsigned int absolute, double skew, double errorbar, int freq);
86
87int get_current_freq()
88{
89	/* OS dependent routine to get the current value of clock frequency.
90	 */
91#ifdef linux
92	struct timex txc;
93	txc.modes=0;
94	if (__adjtimex(&txc) < 0) {
95		perror("adjtimex"); exit(1);
96	}
97	return txc.freq;
98#else
99	return 0;
100#endif
101}
102
103int set_freq(int new_freq)
104{
105	/* OS dependent routine to set a new value of clock frequency.
106	 */
107#ifdef linux
108	struct timex txc;
109	txc.modes = ADJ_FREQUENCY;
110	txc.freq = new_freq;
111	if (__adjtimex(&txc) < 0) {
112		perror("adjtimex"); exit(1);
113	}
114	return txc.freq;
115#else
116	return 0;
117#endif
118}
119#endif /* NOT_REMOVED */
120
121void send_packet(int usd)
122{
123	__u32 data[12];
124	struct timeval now;
125#define LI 0
126#define VN 3
127#define MODE 3
128#define STRATUM 0
129#define POLL 4
130#define PREC -6
131
132	if (debug) fprintf(stderr,"Sending ...\n");
133	if (sizeof(data) != 48) {
134		fprintf(stderr,"size error\n");
135		return;
136	}
137	bzero((char*)data,sizeof(data));
138	data[0] = htonl (
139		( LI << 30 ) | ( VN << 27 ) | ( MODE << 24 ) |
140		( STRATUM << 16) | ( POLL << 8 ) | ( PREC & 0xff ) );
141	data[1] = htonl(1<<16);  /* Root Delay (seconds) */
142	data[2] = htonl(1<<16);  /* Root Dispersion (seconds) */
143	gettimeofday(&now,NULL);
144	data[10] = htonl(now.tv_sec + JAN_1970); /* Transmit Timestamp coarse */
145	data[11] = htonl(NTPFRAC(now.tv_usec));  /* Transmit Timestamp fine   */
146
147    /* Foxconn added start pling 10/31/2006 */
148    /* Save the transmit timestamp */
149    transmit_timestamp[0] = ntohl(data[10]);
150    transmit_timestamp[1] = ntohl(data[11]);
151    /* Foxconn added end pling 10/31/2006 */
152
153	send(usd,data,48,0);
154	time_of_send=now;
155}
156
157
158void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len)
159{
160	struct timeval udp_arrival;
161	struct ntptime udp_arrival_ntp;
162
163#ifdef _PRECISION_SIOCGSTAMP
164	if ( ioctl(usd, SIOCGSTAMP, &udp_arrival) < 0 ) {
165		perror("ioctl-SIOCGSTAMP");
166		gettimeofday(&udp_arrival,NULL);
167	}
168#else
169	gettimeofday(&udp_arrival,NULL);
170#endif
171	udp_arrival_ntp.coarse = udp_arrival.tv_sec + JAN_1970;
172	udp_arrival_ntp.fine   = NTPFRAC(udp_arrival.tv_usec);
173
174	if (debug) {
175		struct sockaddr_in *sa_in=(struct sockaddr_in *)sa_source;
176		printf("packet of length %d received\n",data_len);
177		if (sa_source->sa_family==AF_INET) {
178			printf("Source: INET Port %d host %s\n",
179				ntohs(sa_in->sin_port),inet_ntoa(sa_in->sin_addr));
180		} else {
181			printf("Source: Address family %d\n",sa_source->sa_family);
182		}
183	}
184	rfc1305print(data,&udp_arrival_ntp);
185}
186
187double ntpdiff( struct ntptime *start, struct ntptime *stop)
188{
189	int a;
190	unsigned int b;
191	a = stop->coarse - start->coarse;
192	if (stop->fine >= start->fine) {
193		b = stop->fine - start->fine;
194	} else {
195		b = start->fine - stop->fine;
196		b = ~b;
197		a -= 1;
198	}
199
200	return a*1.e6 + b * (1.e6/4294967296.0);
201}
202
203void rfc1305print(char *data, struct ntptime *arrival)
204{
205/* straight out of RFC-1305 Appendix A */
206	int li, vn, mode, stratum, poll, prec;
207	int delay, disp, refid;
208	struct ntptime reftime, orgtime, rectime, xmttime;
209#ifdef NOT_REMOVED
210	double etime,stime,skew1,skew2;
211	int freq;
212#endif /* NOT_REMOVED */
213
214#define Data(i) ntohl(((unsigned int *)data)[i])
215	li      = Data(0) >> 30 & 0x03;
216	vn      = Data(0) >> 27 & 0x07;
217	mode    = Data(0) >> 24 & 0x07;
218	stratum = Data(0) >> 16 & 0xff;
219	poll    = Data(0) >>  8 & 0xff;
220	prec    = Data(0)       & 0xff;
221	if (prec & 0x80) prec|=0xffffff00;
222	delay   = Data(1);
223	disp    = Data(2);
224	refid   = Data(3);
225	reftime.coarse = Data(4);
226	reftime.fine   = Data(5);
227	orgtime.coarse = Data(6);
228	orgtime.fine   = Data(7);
229	rectime.coarse = Data(8);
230	rectime.fine   = Data(9);
231	xmttime.coarse = Data(10);
232	xmttime.fine   = Data(11);
233#undef Data
234
235    /* Foxconn added start pling 10/31/2006 */
236    /* Add validity checks for reply packet */
237    if (stratum == 0) {
238        if (debug)
239            printf("Got Kiss of death packet from NTP server.\n");
240        exit(2);
241    }
242
243    if (orgtime.coarse != transmit_timestamp[0] ||
244        orgtime.fine != transmit_timestamp[1]) {
245		if (debug)
246            printf("Incorrect original timestamp. Drop NTP reply.\n");
247        exit(1);
248    }
249
250    if (xmttime.coarse == 0 && xmttime.fine == 0) {
251        if (debug)
252            printf("Transmit timestamp is 0. Drop NTP reply.\n");
253        exit(1);
254    }
255
256    if (mode != 4) {
257        if (debug)
258            printf("Incorrect mode (%d). Drop NTP reply.\n", mode);
259        exit(1);
260    }
261    /* Foxconn added end pling 10/31/2006 */
262
263	if (set_clock) {   /* you'd better be root, or ntpclient will crash! */
264		struct timeval tv_set;
265		/* it would be even better to subtract half the slop */
266		tv_set.tv_sec  = xmttime.coarse - JAN_1970;
267		/* divide xmttime.fine by 4294.967296 */
268		tv_set.tv_usec = USEC(xmttime.fine);
269		if (settimeofday(&tv_set,NULL)<0) {
270			perror("settimeofday");
271			exit(1);
272		}
273		if (debug) {
274			printf("set time to %lu.%.6lu\n", tv_set.tv_sec, tv_set.tv_usec);
275		}
276	}
277
278#ifdef NOT_REMOVED
279	if (debug) {
280	printf("LI=%d  VN=%d  Mode=%d  Stratum=%d  Poll=%d  Precision=%d\n",
281		li, vn, mode, stratum, poll, prec);
282	printf("Delay=%.1f  Dispersion=%.1f  Refid=%u.%u.%u.%u\n",
283		sec2u(delay),sec2u(disp),
284		refid>>24&0xff, refid>>16&0xff, refid>>8&0xff, refid&0xff);
285	printf("Reference %u.%.10u\n", reftime.coarse, reftime.fine);
286	printf("Originate %u.%.10u\n", orgtime.coarse, orgtime.fine);
287	printf("Receive   %u.%.10u\n", rectime.coarse, rectime.fine);
288	printf("Transmit  %u.%.10u\n", xmttime.coarse, xmttime.fine);
289	printf("Our recv  %u.%.10u\n", arrival->coarse, arrival->fine);
290	}
291	etime=ntpdiff(&orgtime,arrival);
292	stime=ntpdiff(&rectime,&xmttime);
293	skew1=ntpdiff(&orgtime,&rectime);
294	skew2=ntpdiff(&xmttime,arrival);
295	freq=get_current_freq();
296	if (debug) {
297	printf("Total elapsed: %9.2f\n"
298	       "Server stall:  %9.2f\n"
299	       "Slop:          %9.2f\n",
300		etime, stime, etime-stime);
301	printf("Skew:          %9.2f\n"
302	       "Frequency:     %9d\n"
303	       " day   second     elapsed    stall     skew  dispersion  freq\n",
304		(skew1-skew2)/2, freq);
305	}
306	if (debug) {
307	printf("%d %5d.%.3d  %8.1f %8.1f  %8.1f %8.1f %9d\n",
308		arrival->coarse/86400+15020, arrival->coarse%86400,
309		arrival->fine/4294967, etime, stime,
310		(skew1-skew2)/2, sec2u(disp), freq);
311	fflush(stdout);
312	}
313	if (live) {
314		int new_freq;
315		new_freq = contemplate_data(arrival->coarse, (skew1-skew2)/2,
316			etime+sec2u(disp), freq);
317		if (!debug && new_freq != freq) set_freq(new_freq);
318	}
319#endif /* NOT_REMOVED */
320}
321
322void stuff_net_addr(struct in_addr *p, char *hostname)
323{
324	struct hostent *ntpserver;
325	ntpserver=gethostbyname(hostname);
326	if (ntpserver == NULL) {
327		herror(hostname);
328		exit(1);
329	}
330	if (ntpserver->h_length != 4) {
331		fprintf(stderr,"oops %d\n",ntpserver->h_length);
332		exit(1);
333	}
334	memcpy(&(p->s_addr),ntpserver->h_addr_list[0],4);
335}
336
337void setup_receive(int usd, unsigned int interface, short port)
338{
339	struct sockaddr_in sa_rcvr;
340	bzero((char *) &sa_rcvr, sizeof(sa_rcvr));
341	sa_rcvr.sin_family=AF_INET;
342	sa_rcvr.sin_addr.s_addr=htonl(interface);
343	sa_rcvr.sin_port=htons(port);
344	if(bind(usd,(struct sockaddr *) &sa_rcvr,sizeof(sa_rcvr)) == -1) {
345		fprintf(stderr,"could not bind to udp port %d\n",port);
346		perror("bind");
347		exit(1);
348	}
349	listen(usd,3);
350}
351
352void setup_transmit(int usd, char *host, short port)
353{
354	struct sockaddr_in sa_dest;
355	bzero((char *) &sa_dest, sizeof(sa_dest));
356	sa_dest.sin_family=AF_INET;
357	stuff_net_addr(&(sa_dest.sin_addr),host);
358	sa_dest.sin_port=htons(port);
359	if (connect(usd,(struct sockaddr *)&sa_dest,sizeof(sa_dest))==-1)
360		{perror("connect");exit(1);}
361}
362
363int primary_loop(int usd, int num_probes, int cycle_time)
364{
365	fd_set fds;
366	struct sockaddr sa_xmit;
367	int i, pack_len, sa_xmit_len, probes_sent;
368	struct timeval to;
369
370	if (debug) printf("Listening...\n");
371
372	probes_sent=0;
373	sa_xmit_len=sizeof(sa_xmit);
374	to.tv_sec=0;
375	to.tv_usec=0;
376	for (;;) {
377		FD_ZERO(&fds);
378		FD_SET(usd,&fds);
379		i=select(usd+1,&fds,NULL,NULL,&to);  /* Wait on read or error */
380		if ((i!=1)||(!FD_ISSET(usd,&fds))) {
381			if (i==EINTR) continue;
382			if (i<0) perror("select");
383			if ((to.tv_sec == 0) || (to.tv_sec == cycle_time)) {
384				if (probes_sent >= num_probes &&
385					num_probes != 0) break;
386				send_packet(usd);
387				++probes_sent;
388				to.tv_sec=cycle_time;
389				to.tv_usec=0;
390			}
391			continue;
392		}
393		pack_len=recvfrom(usd,incoming,sizeof(incoming),0,
394		                  &sa_xmit,&sa_xmit_len);
395		if (pack_len<0) {
396			perror("recvfrom");
397		} else if (pack_len>0 && pack_len<sizeof(incoming)){
398			udp_handle(usd,incoming,pack_len,&sa_xmit,sa_xmit_len);
399			return 0;
400		} else {
401			printf("Ooops.  pack_len=%d\n",pack_len);
402			fflush(stdout);
403		}
404		if (probes_sent >= num_probes && num_probes != 0) break;
405	}
406	return -1;
407}
408
409#ifdef NOT_REMOVED
410void do_replay(void)
411{
412	char line[100];
413	int n, day, freq, absolute;
414	float sec, etime, stime, disp;
415	double skew, errorbar;
416	int simulated_freq = 0;
417	unsigned int last_fake_time = 0;
418	double fake_delta_time = 0.0;
419
420	while (fgets(line,sizeof(line),stdin)) {
421		n=sscanf(line,"%d %f %f %f %lf %f %d",
422			&day, &sec, &etime, &stime, &skew, &disp, &freq);
423		if (n==7) {
424			fputs(line,stdout);
425			absolute=(day-15020)*86400+(int)sec;
426			errorbar=etime+disp;
427			if (debug) printf("contemplate %u %.1f %.1f %d\n",
428				absolute,skew,errorbar,freq);
429			if (last_fake_time==0) simulated_freq=freq;
430			fake_delta_time += (absolute-last_fake_time)*((double)(freq-simulated_freq))/65536;
431			if (debug) printf("fake %f %d \n", fake_delta_time, simulated_freq);
432			skew += fake_delta_time;
433			freq = simulated_freq;
434			last_fake_time=absolute;
435			simulated_freq = contemplate_data(absolute, skew, errorbar, freq);
436		} else {
437			fprintf(stderr,"Replay input error\n");
438			exit(2);
439		}
440	}
441}
442#endif /* NOT_REMOVED */
443
444void usage(char *argv0)
445{
446	fprintf(stderr,
447	"Usage: %s [-c count] [-d] -h hostname [-i interval] [-l]\n"
448	"\t[-p port] [-r] [-s] \n",
449	argv0);
450}
451
452/* Copy each token in wordlist delimited by space into word */
453#define foreach(word, wordlist, next) \
454	for (next = &wordlist[strspn(wordlist, " ")], \
455	     strncpy(word, next, sizeof(word)), \
456	     word[strcspn(word, " ")] = '\0', \
457	     word[sizeof(word) - 1] = '\0', \
458	     next = strchr(next, ' '); \
459	     strlen(word); \
460	     next = next ? &next[strspn(next, " ")] : "", \
461	     strncpy(word, next, sizeof(word)), \
462	     word[strcspn(word, " ")] = '\0', \
463	     word[sizeof(word) - 1] = '\0', \
464	     next = strchr(next, ' '))
465
466int main(int argc, char *argv[]) {
467	int usd;  /* socket */
468	int c;
469	/* These parameters are settable from the command line
470	   the initializations here provide default behavior */
471	short int udp_local_port=0;   /* default of 0 means kernel chooses */
472	int cycle_time=3;          /* request timeout in seconds */
473	int probe_count=0;            /* default of 0 means loop forever */
474	/* int debug=0; is a global above */
475	char *hostname=NULL;          /* must be set */
476	int replay=0;                 /* replay mode overrides everything */
477	char ntps[32], *next;
478
479	for (;;) {
480		c = getopt( argc, argv, "c:" DEBUG_OPTION "h:i:p:lrs");
481		if (c == EOF) break;
482		switch (c) {
483			case 'c':
484				probe_count = atoi(optarg);
485				break;
486#ifdef ENABLE_DEBUG
487			case 'd':
488				++debug;
489				break;
490#endif
491			case 'h':
492				hostname = optarg;
493				break;
494			case 'i':
495				cycle_time = atoi(optarg);
496				break;
497			case 'l':
498				live++;
499				break;
500			case 'p':
501				udp_local_port = atoi(optarg);
502				break;
503			case 'r':
504				replay++;
505				break;
506			case 's':
507				set_clock = 1;
508				probe_count = 1;
509				break;
510			default:
511				usage(argv[0]);
512				exit(1);
513		}
514	}
515
516#ifdef NOT_REMOVED
517	if (replay) {
518		do_replay();
519		exit(0);
520	}
521#endif /* NOT_REMOVED */
522
523	if (hostname == NULL) {
524		usage(argv[0]);
525		exit(1);
526	}
527	if (debug) {
528		printf("Configuration:\n"
529		"  -c probe_count %d\n"
530		"  -d (debug)     %d\n"
531		"  -h hostname    %s\n"
532		"  -i interval    %d\n"
533		"  -l live        %d\n"
534		"  -p local_port  %d\n"
535		"  -s set_clock   %d\n",
536		probe_count, debug, hostname, cycle_time,
537		live, udp_local_port, set_clock);
538	}
539
540	foreach(ntps, hostname, next) {
541
542		/* Startup sequence */
543		if ((usd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) {
544			perror ("socket");
545			exit(1);
546		}
547
548		setup_receive(usd, INADDR_ANY, udp_local_port);
549
550		setup_transmit(usd, ntps, NTP_PORT);
551
552		if (!primary_loop(usd, probe_count, cycle_time)) {
553			close(usd);
554			return 0; /* break; */ /* wklin modified */
555		}
556
557		close(usd);
558	}
559
560	return 1;
561}
562