xref: /openbsd/usr.sbin/rdate/ntp.c (revision 8932bfb7)
1 /*	$OpenBSD: ntp.c,v 1.30 2010/08/16 11:09:26 krw 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           4		/* 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_MAX      14		/* The maximum valid stratum */
71 #define NTP_INSANITY     3600.0		/* Errors beyond this are hopeless */
72 
73 #define NTP_PACKET_MIN       48		/* Without authentication */
74 #define NTP_PACKET_MAX       68		/* With authentication (ignored) */
75 
76 #define NTP_DISP_FIELD        8		/* Offset of dispersion field */
77 #define NTP_REFERENCE        16		/* Offset of reference timestamp */
78 #define NTP_ORIGINATE        24		/* Offset of originate timestamp */
79 #define NTP_RECEIVE          32		/* Offset of receive timestamp */
80 #define NTP_TRANSMIT         40		/* Offset of transmit timestamp */
81 
82 #define STATUS_NOWARNING      0		/* No Leap Indicator */
83 #define STATUS_LEAPHIGH       1		/* Last Minute Has 61 Seconds */
84 #define STATUS_LEAPLOW        2		/* Last Minute Has 59 Seconds */
85 #define STATUS_ALARM          3		/* Server Clock Not Synchronized */
86 
87 #define MAX_QUERIES         25
88 #define MAX_DELAY           15
89 
90 #define MILLION_L    1000000l		/* For conversion to/from timeval */
91 #define MILLION_D       1.0e6		/* Must be equal to MILLION_L */
92 
93 struct ntp_data {
94 	u_char		status;
95 	u_char		version;
96 	u_char		mode;
97 	u_char		stratum;
98 	double		receive;
99 	double		transmit;
100 	double		current;
101 	u_int64_t	recvck;
102 
103 	/* Local State */
104 	double		originate;
105 	u_int64_t	xmitck;
106 };
107 
108 void	ntp_client(const char *, int, struct timeval *, struct timeval *, int);
109 int	sync_ntp(int, const struct sockaddr *, double *, double *);
110 int	write_packet(int, struct ntp_data *);
111 int	read_packet(int, struct ntp_data *, double *, double *);
112 void	unpack_ntp(struct ntp_data *, u_char *);
113 double	current_time(double);
114 void	create_timeval(double, struct timeval *, struct timeval *);
115 
116 #ifdef DEBUG
117 void	print_packet(const struct ntp_data *);
118 #endif
119 
120 int	corrleaps;
121 
122 void
123 ntp_client(const char *hostname, int family, struct timeval *new,
124     struct timeval *adjust, int leapflag)
125 {
126 	struct addrinfo hints, *res0, *res;
127 	double offset, error;
128 	int accept = 0, ret, s, ierror;
129 
130 	memset(&hints, 0, sizeof(hints));
131 	hints.ai_family = family;
132 	hints.ai_socktype = SOCK_DGRAM;
133 	ierror = getaddrinfo(hostname, "ntp", &hints, &res0);
134 	if (ierror) {
135 		errx(1, "%s: %s", hostname, gai_strerror(ierror));
136 		/*NOTREACHED*/
137 	}
138 
139 	corrleaps = leapflag;
140 	if (corrleaps)
141 		ntpleaps_init();
142 
143 	s = -1;
144 	for (res = res0; res; res = res->ai_next) {
145 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
146 		if (s < 0)
147 			continue;
148 
149 		ret = sync_ntp(s, res->ai_addr, &offset, &error);
150 		if (ret < 0) {
151 #ifdef DEBUG
152 			fprintf(stderr, "try the next address\n");
153 #endif
154 			close(s);
155 			s = -1;
156 			continue;
157 		}
158 
159 		accept++;
160 		break;
161 	}
162 	freeaddrinfo(res0);
163 
164 #ifdef DEBUG
165 	fprintf(stderr, "Correction: %.6f +/- %.6f\n", offset, error);
166 #endif
167 
168 	if (accept < 1)
169 		errx(1, "Unable to get a reasonable time estimate");
170 
171 	create_timeval(offset, new, adjust);
172 }
173 
174 int
175 sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
176 {
177 	int attempts = 0, accepts = 0, rejects = 0;
178 	int delay = MAX_DELAY, ret;
179 	double deadline;
180 	double a, b, x, y;
181 	double minerr = 0.1;		/* Maximum ignorable variation */
182 	struct ntp_data data;
183 
184 	deadline = current_time(JAN_1970) + delay;
185 	*offset = 0.0;
186 	*error = NTP_INSANITY;
187 
188 	if (connect(fd, peer, SA_LEN(peer)) < 0) {
189 		warn("Failed to connect to server");
190 		return (-1);
191 	}
192 
193 	while (accepts < MAX_QUERIES && attempts < 2 * MAX_QUERIES) {
194 		memset(&data, 0, sizeof(data));
195 
196 		if (current_time(JAN_1970) > deadline) {
197 			warnx("Not enough valid responses received in time");
198 			return (-1);
199 		}
200 
201 		if (write_packet(fd, &data) < 0)
202 			return (-1);
203 
204 		ret = read_packet(fd, &data, &x, &y);
205 
206 		if (ret < 0)
207 			return (-1);
208 		else if (ret > 0) {
209 #ifdef DEBUG
210 			print_packet(&data);
211 #endif
212 
213 			if (++rejects > MAX_QUERIES) {
214 				warnx("Too many bad or lost packets");
215 				return (-1);
216 			} else
217 				continue;
218 		} else
219 			++accepts;
220 
221 #ifdef DEBUG
222 		fprintf(stderr, "Offset: %.6f +/- %.6f\n", x, y);
223 #endif
224 
225 		if ((a = x - *offset) < 0.0)
226 			a = -a;
227 		if (accepts <= 1)
228 			a = 0.0;
229 		b = *error + y;
230 		if (y < *error) {
231 			*offset = x;
232 			*error = y;
233 		}
234 
235 #ifdef DEBUG
236 		fprintf(stderr, "Best: %.6f +/- %.6f\n", *offset, *error);
237 #endif
238 
239 		if (a > b) {
240 			warnx("Inconsistent times received from NTP server");
241 			return (-1);
242 		}
243 
244 		if ((data.status & STATUS_ALARM) == STATUS_ALARM) {
245 			warnx("Ignoring NTP server with alarm flag set");
246 			return (-1);
247 		}
248 
249 		if (*error <= minerr)
250 			break;
251 	}
252 
253 	return (accepts);
254 }
255 
256 /* Send out NTP packet. */
257 int
258 write_packet(int fd, struct ntp_data *data)
259 {
260 	u_char	packet[NTP_PACKET_MIN];
261 	ssize_t	length;
262 
263 	memset(packet, 0, sizeof(packet));
264 
265 	packet[0] = (NTP_VERSION << 3) | (NTP_MODE_CLIENT);
266 
267 	data->xmitck = (u_int64_t)arc4random() << 32 | arc4random();
268 
269 	/*
270 	 * Send out a random 64-bit number as our transmit time.  The NTP
271 	 * server will copy said number into the originate field on the
272 	 * response that it sends us.  This is totally legal per the SNTP spec.
273 	 *
274 	 * The impact of this is two fold: we no longer send out the current
275 	 * system time for the world to see (which may aid an attacker), and
276 	 * it gives us a (not very secure) way of knowing that we're not
277 	 * getting spoofed by an attacker that can't capture our traffic
278 	 * but can spoof packets from the NTP server we're communicating with.
279 	 *
280 	 * No endian concerns here.  Since we're running as a strict
281 	 * unicast client, we don't have to worry about anyone else finding
282 	 * the transmit field intelligible.
283 	 */
284 
285 	bcopy(&data->xmitck, (packet + NTP_TRANSMIT), sizeof(data->xmitck));
286 
287 	data->originate = current_time(JAN_1970);
288 
289 	length = write(fd, packet, sizeof(packet));
290 
291 	if (length != sizeof(packet)) {
292 		warn("Unable to send NTP packet to server");
293 		return (-1);
294 	}
295 
296 	return (0);
297 }
298 
299 /*
300  * Check the packet and work out the offset and optionally the error.
301  * Note that this contains more checking than xntp does. Return 0 for
302  * success, 1 for failure. Note that it must not change its arguments
303  * if it fails.
304  */
305 int
306 read_packet(int fd, struct ntp_data *data, double *off, double *error)
307 {
308 	u_char	receive[NTP_PACKET_MAX];
309 	struct	timeval tv;
310 	double	x, y;
311 	int	length, r;
312 	fd_set	*rfds;
313 
314 	rfds = calloc(howmany(fd + 1, NFDBITS), sizeof(fd_mask));
315 	if (rfds == NULL)
316 		err(1, "calloc");
317 
318 	FD_SET(fd, rfds);
319 
320 retry:
321 	tv.tv_sec = 0;
322 	tv.tv_usec = 1000000 * MAX_DELAY / MAX_QUERIES;
323 
324 	r = select(fd + 1, rfds, NULL, NULL, &tv);
325 
326 	if (r < 0) {
327 		if (errno == EINTR)
328 			goto retry;
329 		else
330 			warn("select");
331 
332 		free(rfds);
333 		return (r);
334 	}
335 
336 	if (r != 1 || !FD_ISSET(fd, rfds)) {
337 		free(rfds);
338 		return (1);
339 	}
340 
341 	free(rfds);
342 
343 	length = read(fd, receive, NTP_PACKET_MAX);
344 
345 	if (length < 0) {
346 		warn("Unable to receive NTP packet from server");
347 		return (-1);
348 	}
349 
350 	if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
351 		warnx("Invalid NTP packet size, packet rejected");
352 		return (1);
353 	}
354 
355 	unpack_ntp(data, receive);
356 
357 	if (data->recvck != data->xmitck) {
358 		warnx("Invalid cookie received, packet rejected");
359 		return (1);
360 	}
361 
362 	if (data->version < NTP_VERSION_MIN ||
363 	    data->version > NTP_VERSION_MAX) {
364 		warnx("Received NTP version %u, need %u or lower",
365 		    data->version, NTP_VERSION);
366 		return (1);
367 	}
368 
369 	if (data->mode != NTP_MODE_SERVER) {
370 		warnx("Invalid NTP server mode, packet rejected");
371 		return (1);
372 	}
373 
374 	if (data->stratum > NTP_STRATUM_MAX) {
375 		warnx("Invalid stratum received, packet rejected");
376 		return (1);
377 	}
378 
379 	if (data->transmit == 0.0) {
380 		warnx("Server clock invalid, packet rejected");
381 		return (1);
382 	}
383 
384 	x = data->receive - data->originate;
385 	y = data->transmit - data->current;
386 
387 	*off = (x + y) / 2;
388 	*error = x - y;
389 
390 	x = (data->current - data->originate) / 2;
391 
392 	if (x > *error)
393 		*error = x;
394 
395 	return (0);
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)
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 
416 	for (i = 0, d = 0.0; i < 8; ++i)
417 	    d = 256.0*d+packet[NTP_RECEIVE+i];
418 
419 	data->receive = d / NTP_SCALE;
420 
421 	for (i = 0, d = 0.0; i < 8; ++i)
422 	    d = 256.0*d+packet[NTP_TRANSMIT+i];
423 
424 	data->transmit = d / NTP_SCALE;
425 
426 	/* See write_packet for why this isn't an endian problem. */
427 	bcopy((packet + NTP_ORIGINATE), &data->recvck, sizeof(data->recvck));
428 }
429 
430 /*
431  * Get the current UTC time in seconds since the Epoch plus an offset
432  * (usually the time from the beginning of the century to the Epoch)
433  */
434 double
435 current_time(double offset)
436 {
437 	struct timeval current;
438 	u_int64_t t;
439 
440 	if (gettimeofday(&current, NULL))
441 		err(1, "Could not get local time of day");
442 
443 	/*
444 	 * At this point, current has the current TAI time.
445 	 * Now subtract leap seconds to set the posix tick.
446 	 */
447 
448 	t = SEC_TO_TAI64(current.tv_sec);
449 	if (corrleaps)
450 		ntpleaps_sub(&t);
451 
452 	return (offset + TAI64_TO_SEC(t) + 1.0e-6 * current.tv_usec);
453 }
454 
455 /*
456  * Change offset into current UTC time. This is portable, even if
457  * struct timeval uses an unsigned long for tv_sec.
458  */
459 void
460 create_timeval(double difference, struct timeval *new, struct timeval *adjust)
461 {
462 	struct timeval old;
463 	long n;
464 
465 	/* Start by converting to timeval format. Note that we have to
466 	 * cater for negative, unsigned values. */
467 	if ((n = (long) difference) > difference)
468 		--n;
469 	adjust->tv_sec = n;
470 	adjust->tv_usec = (long) (MILLION_D * (difference-n));
471 	errno = 0;
472 	if (gettimeofday(&old, NULL))
473 		err(1, "Could not get local time of day");
474 	new->tv_sec = old.tv_sec + adjust->tv_sec;
475 	new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
476 
477 	if (n < 0) {
478 		new->tv_usec += MILLION_L;
479 		--new->tv_sec;
480 	} else if (n >= MILLION_L) {
481 		new->tv_usec -= MILLION_L;
482 		++new->tv_sec;
483 	}
484 }
485 
486 #ifdef DEBUG
487 void
488 print_packet(const struct ntp_data *data)
489 {
490 	printf("status:      %u\n", data->status);
491 	printf("version:     %u\n", data->version);
492 	printf("mode:        %u\n", data->mode);
493 	printf("stratum:     %u\n", data->stratum);
494 	printf("originate:   %f\n", data->originate);
495 	printf("receive:     %f\n", data->receive);
496 	printf("transmit:    %f\n", data->transmit);
497 	printf("current:     %f\n", data->current);
498 	printf("xmitck:      0x%0llX\n", data->xmitck);
499 	printf("recvck:      0x%0llX\n", data->recvck);
500 };
501 #endif
502