xref: /openbsd/usr.sbin/rdate/ntp.c (revision db3296cf)
1 /*	$OpenBSD: ntp.c,v 1.14 2003/05/14 18:06:21 itojun Exp $	*/
2 
3 /*
4  * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
5  * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved.
6  * Copyright (c) 2002 by Thorsten "mirabile" Glaser.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the author nor the university may be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/socket.h>
34 #include <sys/time.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 
38 #include <ctype.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <float.h>
43 #include <limits.h>
44 #include <math.h>
45 #include <netdb.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50 #include <unistd.h>
51 
52 #include "ntpleaps.h"
53 
54 /*
55  * NTP definitions.  Note that these assume 8-bit bytes - sigh.  There
56  * is little point in parameterising everything, as it is neither
57  * feasible nor useful.  It would be very useful if more fields could
58  * be defined as unspecified.  The NTP packet-handling routines
59  * contain a lot of extra assumptions.
60  */
61 
62 #define JAN_1970   2208988800.0		/* 1970 - 1900 in seconds */
63 #define NTP_SCALE  4294967296.0		/* 2^32, of course! */
64 
65 #define NTP_MODE_CLIENT       3		/* NTP client mode */
66 #define NTP_MODE_SERVER       4		/* NTP server mode */
67 #define NTP_VERSION           3		/* The current version */
68 #define NTP_VERSION_MIN       1		/* The minum valid version */
69 #define NTP_VERSION_MAX       4		/* The maximum valid version */
70 #define NTP_STRATUM_MIN       1		/* The minum valid stratum */
71 #define NTP_STRATUM_MAX      15		/* The maximum valid stratum */
72 #define NTP_INSANITY     3600.0		/* Errors beyond this are hopeless */
73 
74 #define NTP_PACKET_MIN       48		/* Without authentication */
75 #define NTP_PACKET_MAX       68		/* With authentication (ignored) */
76 
77 #define NTP_DISP_FIELD        8		/* Offset of dispersion field */
78 #define NTP_REFERENCE        16		/* Offset of reference timestamp */
79 #define NTP_ORIGINATE        24		/* Offset of originate timestamp */
80 #define NTP_RECEIVE          32		/* Offset of receive timestamp */
81 #define NTP_TRANSMIT         40		/* Offset of transmit timestamp */
82 
83 #define MAX_QUERIES         25
84 #define MAX_DELAY           15
85 
86 #define MILLION_L    1000000l		/* For conversion to/from timeval */
87 #define MILLION_D       1.0e6		/* Must be equal to MILLION_L */
88 
89 struct ntp_data {
90 	u_char	status;
91 	u_char	version;
92 	u_char	mode;
93 	u_char	stratum;
94 	u_char	polling;
95 	u_char	precision;
96 	double	dispersion;
97 	double	reference;
98 	double	originate;
99 	double	receive;
100 	double	transmit;
101 	double	current;
102 };
103 
104 void	ntp_client(const char *, struct timeval *, struct timeval *, int);
105 int	sync_ntp(int, const struct sockaddr *, double *, double *);
106 void	make_packet(struct ntp_data *);
107 int	write_packet(int, const struct sockaddr *, struct ntp_data *);
108 int	read_packet(int, struct ntp_data *, double *, double *, double *);
109 void	pack_ntp(u_char *, int, struct ntp_data *);
110 void	unpack_ntp(struct ntp_data *, u_char *, int);
111 double	current_time(double);
112 void	create_timeval(double, struct timeval *, struct timeval *);
113 
114 int	corrleaps;
115 
116 void
117 ntp_client(const char *hostname, struct timeval *new,
118     struct timeval *adjust, int leapflag)
119 {
120 	struct addrinfo hints, *res0, *res;
121 	double offset, error;
122 	int packets = 0, s, ierror;
123 
124 	memset(&hints, 0, sizeof(hints));
125 	hints.ai_family = PF_UNSPEC;
126 	hints.ai_socktype = SOCK_DGRAM;
127 	ierror = getaddrinfo(hostname, "ntp", &hints, &res0);
128 	if (ierror) {
129 		errx(1, "%s: %s", hostname, gai_strerror(ierror));
130 		/*NOTREACHED*/
131 	}
132 
133 	corrleaps = leapflag;
134 	if (corrleaps)
135 		ntpleaps_init();
136 
137 	s = -1;
138 	for (res = res0; res; res = res->ai_next) {
139 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
140 		if (s < 0)
141 			continue;
142 
143 		packets = sync_ntp(s, res->ai_addr, &offset, &error);
144 		if (packets == 0) {
145 #ifdef DEBUG
146 			fprintf(stderr, "try the next address\n");
147 #endif
148 			close(s);
149 			s = -1;
150 			continue;
151 		}
152 		if (error > NTP_INSANITY) {
153 			/* should we try the next address instead? */
154 			errx(1, "Unable to get a reasonable time estimate");
155 		}
156 		break;
157 	}
158 	freeaddrinfo(res0);
159 
160 #ifdef DEBUG
161 	fprintf(stderr,"Correction: %.6f +/- %.6f\n", offset,error);
162 #endif
163 
164 	create_timeval(offset, new, adjust);
165 }
166 
167 int
168 sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
169 {
170 	int attempts = 0, accepts = 0, rejects = 0;
171 	int delay = MAX_DELAY;
172 	double deadline;
173 	double a, b, x, y;
174 	double minerr = 0.1;		/* Maximum ignorable variation */
175 	double dispersion = 0.0;	/* The source dispersion in seconds */
176 	struct ntp_data data;
177 
178 	deadline = current_time(JAN_1970) + delay;
179         *offset = 0.0;
180         *error = NTP_INSANITY;
181 
182         while (accepts < MAX_QUERIES && attempts < 2 * MAX_QUERIES) {
183 		if (current_time(JAN_1970) > deadline)
184 			errx(1, "Not enough valid responses received in time");
185 
186 		make_packet(&data);
187 		write_packet(fd, peer, &data);
188 
189 		if (read_packet(fd, &data, &x, &y, &dispersion)) {
190 			if (++rejects > MAX_QUERIES)
191 				errx(1, "Too many bad or lost packets");
192 			else
193 			  continue;
194 		} else
195 			++accepts;
196 
197 #ifdef DEBUG
198 		fprintf(stderr,"Offset: %.6f +/- %.6f disp=%.6f\n",
199 		    x, y, dispersion);
200 #endif
201 
202 		if ((a = x - *offset) < 0.0)
203 			a = -a;
204 		if (accepts <= 1)
205 			a = 0.0;
206 		b = *error + y;
207 		if (y < *error) {
208 			*offset = x;
209 			*error = y;
210 		}
211 
212 #ifdef DEBUG
213 		fprintf(stderr,"Best: %.6f +/- %.6f\n", *offset, *error);
214 #endif
215 
216 		if (a > b)
217 			errx(1, "Inconsistent times received from NTP server");
218 
219 		if (*error <= minerr)
220 			break;
221         }
222 
223 	return accepts;
224 }
225 
226 /* Create an outgoing NTP packet */
227 void
228 make_packet(struct ntp_data *data)
229 {
230 	data->status = 0;
231 	data->version = NTP_VERSION;
232 	data->mode = NTP_MODE_CLIENT;
233 	data->stratum = 0;
234 	data->polling = 0;
235 	data->precision = 0;
236 	data->reference = data->dispersion = 0.0;
237 	data->receive = data->originate = 0.0;
238 	data->current = data->transmit = current_time(JAN_1970);
239 }
240 
241 int
242 write_packet(int fd, const struct sockaddr *peer, struct ntp_data *data)
243 {
244 	u_char	transmit[NTP_PACKET_MIN];
245 	int	length;
246 
247 	pack_ntp(transmit, NTP_PACKET_MIN, data);
248 	length = sendto(fd, transmit, NTP_PACKET_MIN, 0, peer, SA_LEN(peer));
249 	if (length <= 0) {
250 		warnx("Unable to send NTP packet to server");
251 		return 1;
252 	}
253 
254 	return 0;
255 }
256 
257 /*
258  * Check the packet and work out the offset and optionally the error.
259  * Note that this contains more checking than xntp does. Return 0 for
260  * success, 1 for failure. Note that it must not change its arguments
261  * if it fails.
262  */
263 int
264 read_packet(int fd, struct ntp_data *data, double *off, double *error,
265     double *dispersion)
266 {
267 	u_char	receive[NTP_PACKET_MAX+1];
268 	double	delay1, delay2, x, y;
269 	int	length, r;
270 	fd_set	*rfds;
271 	struct	timeval tv;
272 
273 	rfds = (fd_set *)calloc(howmany(fd + 1, NFDBITS), sizeof(fd_mask));
274 	if (!rfds) {
275 		warnx("calloc() failed");
276 		return 1;
277 	}
278 
279 	FD_SET(fd, rfds);
280 
281 retry:
282 	tv.tv_sec = 0;
283 	tv.tv_usec = 1000000 * MAX_DELAY / MAX_QUERIES;
284 
285 	r = select(fd + 1, rfds, NULL, NULL, &tv);
286 	if (r < 1 || !FD_ISSET(fd, rfds)) {
287 		if (r < 0) {
288 			if (errno == EINTR)
289 				goto retry;
290 			else
291 				warnx("select() failed");
292 		}
293 		free(rfds);
294 		return 1;
295 	}
296 	free(rfds);
297 
298 	length = recvfrom(fd, receive, NTP_PACKET_MAX + 1, 0, NULL, 0);
299 	if (length < 0) {
300 		warnx("Unable to receive NTP packet from server");
301 		return 1;
302 	}
303 
304 	if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
305 		warnx("Invalid NTP packet size, packet reject");
306 	        return 1;
307 	}
308 
309 	unpack_ntp(data, receive, length);
310 
311 	if (data->version < NTP_VERSION_MIN ||
312 	    data->version > NTP_VERSION_MAX) {
313 		warnx("Invalid NTP version, packet rejected");
314 		return 1;
315 	}
316 
317 	if (data->mode != NTP_MODE_SERVER) {
318 		warnx("Invalid NTP server mode, packet rejected");
319 		return 1;
320 	}
321 
322 	/*
323 	 * Note that the conventions are very poorly defined in the NTP
324 	 * protocol, so we have to guess.  Any full NTP server perpetrating
325 	 * completely unsynchronised packets is an abomination, anyway, so
326 	 * reject it.
327 	 */
328 	delay1 = data->transmit - data->receive;
329 	delay2 = data->current - data->originate;
330 
331 	if (data->reference == 0.0 ||
332 	    data->transmit == 0.0 ||
333 	    data->receive == 0.0 ||
334 	    (data->reference != 0.0 && data->receive < data->reference) ||
335 	    delay1 < 0.0 ||
336 	    delay1 > NTP_INSANITY ||
337 	    delay2 < 0.0 ||
338 	    delay2 > NTP_INSANITY ||
339 	    data->dispersion > NTP_INSANITY) {
340 		warnx("Incomprehensible NTP packet rejected");
341 		return 1;
342 	}
343 
344 	if (*dispersion < data->dispersion)
345 		*dispersion = data->dispersion;
346 
347         x = data->receive - data->originate;
348         y = (data->transmit == 0.0 ? 0.0 : data->transmit-data->current);
349         *off = 0.5*(x+y);
350         *error = x-y;
351         x = data->current - data->originate;
352         if (0.5*x > *error)
353 		*error = 0.5*x;
354 
355 	return 0;
356 }
357 
358 /*
359  * Pack the essential data into an NTP packet, bypassing struct layout
360  * and endian problems.  Note that it ignores fields irrelevant to
361  * SNTP.
362  */
363 void
364 pack_ntp(u_char	*packet, int length, struct ntp_data *data)
365 {
366 	int i, k;
367 	double d;
368 
369 	memset(packet,0, (size_t)length);
370 
371 	packet[0] = (data->status<<6)|(data->version<<3)|data->mode;
372 	packet[1] = data->stratum;
373 	packet[2] = data->polling;
374 	packet[3] = data->precision;
375 
376 	d = data->originate/NTP_SCALE;
377 	for (i = 0; i < 8; ++i) {
378 		if ((k = (int)(d *= 256.0)) >= 256) k = 255;
379 		packet[NTP_ORIGINATE+i] = k;
380 		d -= k;
381 	}
382 
383 	d = data->receive/NTP_SCALE;
384 	for (i = 0; i < 8; ++i) {
385 		if ((k = (int)(d *= 256.0)) >= 256) k = 255;
386 		packet[NTP_RECEIVE+i] = k;
387 		d -= k;
388 	}
389 
390 	d = data->transmit/NTP_SCALE;
391 	for (i = 0; i < 8; ++i) {
392 		if ((k = (int)(d *= 256.0)) >= 256) k = 255;
393 		packet[NTP_TRANSMIT+i] = k;
394 		d -= k;
395 	}
396 }
397 
398 /*
399  * Unpack the essential data from an NTP packet, bypassing struct
400  * layout and endian problems.  Note that it ignores fields irrelevant
401  * to SNTP.
402  */
403 void
404 unpack_ntp(struct ntp_data *data, u_char *packet, int length)
405 {
406 	int i;
407 	double d;
408 
409 	data->current = current_time(JAN_1970);
410 
411 	data->status = (packet[0] >> 6);
412 	data->version = (packet[0] >> 3)&0x07;
413 	data->mode = packet[0]&0x07;
414 	data->stratum = packet[1];
415 	data->polling = packet[2];
416 	data->precision = packet[3];
417 
418 	for (i = 0, d = 0.0; i < 4; ++i)
419 	    d = 256.0*d+packet[NTP_DISP_FIELD+i];
420 	data->dispersion = d/65536.0;
421 
422 	for (i = 0, d = 0.0; i < 8; ++i)
423 	    d = 256.0*d+packet[NTP_REFERENCE+i];
424 	data->reference = d/NTP_SCALE;
425 
426 	for (i = 0, d = 0.0; i < 8; ++i)
427 	    d = 256.0*d+packet[NTP_ORIGINATE+i];
428 	data->originate = d/NTP_SCALE;
429 
430 	for (i = 0, d = 0.0; i < 8; ++i)
431 	    d = 256.0*d+packet[NTP_RECEIVE+i];
432 	data->receive = d/NTP_SCALE;
433 
434 	for (i = 0, d = 0.0; i < 8; ++i)
435 	    d = 256.0*d+packet[NTP_TRANSMIT+i];
436 	data->transmit = d/NTP_SCALE;
437 }
438 
439 /*
440  * Get the current UTC time in seconds since the Epoch plus an offset
441  * (usually the time from the beginning of the century to the Epoch)
442  */
443 double
444 current_time(double offset)
445 {
446 	struct timeval current;
447 	u_int64_t t;
448 
449 	if (gettimeofday(&current, NULL))
450 		err(1, "Could not get local time of day");
451 
452 	/*
453 	 * At this point, current has the current TAI time.
454 	 * Now subtract leap seconds to set the posix tick.
455 	 */
456 
457 	t = SEC_TO_TAI64(current.tv_sec);
458 	if (corrleaps)
459 		ntpleaps_sub(&t);
460 
461 	return offset + TAI64_TO_SEC(t) + 1.0e-6 * current.tv_usec;
462 }
463 
464 /*
465  * Change offset into current UTC time. This is portable, even if
466  * struct timeval uses an unsigned long for tv_sec.
467  */
468 void
469 create_timeval(double difference, struct timeval *new, struct timeval *adjust)
470 {
471 	struct timeval old;
472 	long n;
473 
474 	/* Start by converting to timeval format. Note that we have to
475 	 * cater for negative, unsigned values. */
476 	if ((n = (long) difference) > difference)
477 		--n;
478 	adjust->tv_sec = n;
479 	adjust->tv_usec = (long) (MILLION_D * (difference-n));
480 	errno = 0;
481 	if (gettimeofday(&old, NULL))
482 		err(1, "Could not get local time of day");
483 	new->tv_sec = old.tv_sec + adjust->tv_sec;
484 	new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
485 
486 	if (n < 0) {
487 		new->tv_usec += MILLION_L;
488 		--new->tv_sec;
489 	} else if (n >= MILLION_L) {
490 		new->tv_usec -= MILLION_L;
491 		++new->tv_sec;
492 	}
493 }
494 
495 #ifdef DEBUG
496 void
497 print_packet(const struct ntp_data *data)
498 {
499 	printf("status:      %u\n", data->status);
500 	printf("version:     %u\n", data->version);
501 	printf("mode:        %u\n", data->mode);
502 	printf("stratum:     %u\n", data->stratum);
503 	printf("polling:     %u\n", data->polling);
504 	printf("precision:   %u\n", data->precision);
505 	printf("dispersion:  %e\n", data->dispersion);
506 	printf("reference:   %e\n", data->reference);
507 	printf("originate:   %e\n", data->originate);
508 	printf("receive:     %e\n", data->receive);
509 	printf("transmit:    %e\n", data->transmit);
510 	printf("current:     %e\n", data->current);
511 };
512 #endif
513