xref: /openbsd-src/usr.sbin/rdate/ntp.c (revision 2d44acdfaab57249232ee6a7c663cee6d1074a00)
1*2d44acdfSotto /*	$OpenBSD: ntp.c,v 1.37 2023/11/12 18:53:22 otto Exp $	*/
24142bea0Sjakob 
34142bea0Sjakob /*
44142bea0Sjakob  * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
54142bea0Sjakob  * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved.
62f6e235dSjakob  * Copyright (c) 2002 by Thorsten "mirabile" Glaser.
74142bea0Sjakob  *
84142bea0Sjakob  * Redistribution and use in source and binary forms, with or without
94142bea0Sjakob  * modification, are permitted provided that the following conditions
104142bea0Sjakob  * are met:
114142bea0Sjakob  * 1. Redistributions of source code must retain the above copyright
124142bea0Sjakob  *    notice, this list of conditions and the following disclaimer.
134142bea0Sjakob  * 2. Redistributions in binary form must reproduce the above copyright
144142bea0Sjakob  *    notice, this list of conditions and the following disclaimer in the
154142bea0Sjakob  *    documentation and/or other materials provided with the distribution.
164142bea0Sjakob  * 3. Neither the name of the author nor the university may be used to
174142bea0Sjakob  *    endorse or promote products derived from this software without
184142bea0Sjakob  *    specific prior written permission.
194142bea0Sjakob  *
204142bea0Sjakob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
214142bea0Sjakob  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
224142bea0Sjakob  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
234142bea0Sjakob  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
244142bea0Sjakob  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
254142bea0Sjakob  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
264142bea0Sjakob  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
274142bea0Sjakob  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
284142bea0Sjakob  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
294142bea0Sjakob  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
304142bea0Sjakob  */
314142bea0Sjakob 
324142bea0Sjakob #include <sys/socket.h>
334142bea0Sjakob #include <sys/time.h>
344142bea0Sjakob #include <netinet/in.h>
354142bea0Sjakob #include <arpa/inet.h>
364142bea0Sjakob 
374142bea0Sjakob #include <ctype.h>
384142bea0Sjakob #include <err.h>
394142bea0Sjakob #include <errno.h>
404142bea0Sjakob #include <fcntl.h>
414142bea0Sjakob #include <float.h>
424142bea0Sjakob #include <limits.h>
434142bea0Sjakob #include <math.h>
444142bea0Sjakob #include <netdb.h>
45*2d44acdfSotto #include <stdint.h>
464142bea0Sjakob #include <stdio.h>
474142bea0Sjakob #include <stdlib.h>
484142bea0Sjakob #include <string.h>
494142bea0Sjakob #include <time.h>
504d79ab39Sderaadt #include <poll.h>
514142bea0Sjakob #include <unistd.h>
52b9ce4fd1Sjakob 
532f6e235dSjakob #include "ntpleaps.h"
544142bea0Sjakob 
55eea542eaSderaadt /*
56eea542eaSderaadt  * NTP definitions.  Note that these assume 8-bit bytes - sigh.  There
574142bea0Sjakob  * is little point in parameterising everything, as it is neither
584142bea0Sjakob  * feasible nor useful.  It would be very useful if more fields could
594142bea0Sjakob  * be defined as unspecified.  The NTP packet-handling routines
60eea542eaSderaadt  * contain a lot of extra assumptions.
61eea542eaSderaadt  */
624142bea0Sjakob 
634142bea0Sjakob #define JAN_1970   2208988800.0		/* 1970 - 1900 in seconds */
644142bea0Sjakob #define NTP_SCALE  4294967296.0		/* 2^32, of course! */
654142bea0Sjakob 
664142bea0Sjakob #define NTP_MODE_CLIENT       3		/* NTP client mode */
674142bea0Sjakob #define NTP_MODE_SERVER       4		/* NTP server mode */
684844c6b7Salexander #define NTP_VERSION           4		/* The current version */
694f8983dbSsthen #define NTP_VERSION_MIN       1		/* The minimum valid version */
704142bea0Sjakob #define NTP_VERSION_MAX       4		/* The maximum valid version */
714844c6b7Salexander #define NTP_STRATUM_MAX      14		/* The maximum valid stratum */
724142bea0Sjakob #define NTP_INSANITY     3600.0		/* Errors beyond this are hopeless */
734142bea0Sjakob 
744142bea0Sjakob #define NTP_PACKET_MIN       48		/* Without authentication */
754142bea0Sjakob #define NTP_PACKET_MAX       68		/* With authentication (ignored) */
764142bea0Sjakob 
774142bea0Sjakob #define NTP_DISP_FIELD        8		/* Offset of dispersion field */
784142bea0Sjakob #define NTP_REFERENCE        16		/* Offset of reference timestamp */
794142bea0Sjakob #define NTP_ORIGINATE        24		/* Offset of originate timestamp */
804142bea0Sjakob #define NTP_RECEIVE          32		/* Offset of receive timestamp */
814142bea0Sjakob #define NTP_TRANSMIT         40		/* Offset of transmit timestamp */
824142bea0Sjakob 
835d5f61deSjakob #define STATUS_NOWARNING      0		/* No Leap Indicator */
845d5f61deSjakob #define STATUS_LEAPHIGH       1		/* Last Minute Has 61 Seconds */
855d5f61deSjakob #define STATUS_LEAPLOW        2		/* Last Minute Has 59 Seconds */
865d5f61deSjakob #define STATUS_ALARM          3		/* Server Clock Not Synchronized */
875d5f61deSjakob 
884142bea0Sjakob #define MAX_QUERIES         25
894142bea0Sjakob #define MAX_DELAY           15
904142bea0Sjakob 
914142bea0Sjakob #define MILLION_L    1000000l		/* For conversion to/from timeval */
924142bea0Sjakob #define MILLION_D       1.0e6		/* Must be equal to MILLION_L */
934142bea0Sjakob 
94*2d44acdfSotto /*
95*2d44acdfSotto  * The era we're in if we have no reason to assume otherwise.
96*2d44acdfSotto  * If unpack_ntp() sees a small offset the era is is assumed to be
97*2d44acdfSotto  * NTP_ERA + 1.
98*2d44acdfSotto  * Once the actual year is well into era 1, (after 2036) define NTP_ERA to 1
99*2d44acdfSotto  * and adapt (disable) the increments in unpack_ntp().
100*2d44acdfSotto  * Once more than half of era 1 has elapsed (after 2104), re-inroduce the test
101*2d44acdfSotto  * to move to era 2 if offset is small, repeat for each half era.
102*2d44acdfSotto  */
103*2d44acdfSotto #define NTP_ERA         0
104*2d44acdfSotto 
105*2d44acdfSotto #define SECS_IN_ERA     (UINT32_MAX + 1ULL)
106*2d44acdfSotto 
107*2d44acdfSotto 
1084142bea0Sjakob struct ntp_data {
10904ef39a3Sderaadt 	u_char		status;
11004ef39a3Sderaadt 	u_char		version;
11104ef39a3Sderaadt 	u_char		mode;
11204ef39a3Sderaadt 	u_char		stratum;
1134142bea0Sjakob 	double		receive;
1144142bea0Sjakob 	double		transmit;
1154142bea0Sjakob 	double		current;
1161346900eSjakob 	u_int64_t	recvck;
1174844c6b7Salexander 
1184844c6b7Salexander 	/* Local State */
1194844c6b7Salexander 	double		originate;
1204844c6b7Salexander 	u_int64_t	xmitck;
1214142bea0Sjakob };
1224142bea0Sjakob 
12322d417c3Sjakob void	ntp_client(const char *, int, struct timeval *, struct timeval *, int);
1244142bea0Sjakob int	sync_ntp(int, const struct sockaddr *, double *, double *);
1254844c6b7Salexander int	write_packet(int, struct ntp_data *);
1264844c6b7Salexander int	read_packet(int, struct ntp_data *, double *, double *);
1274844c6b7Salexander void	unpack_ntp(struct ntp_data *, u_char *);
1284142bea0Sjakob double	current_time(double);
1294142bea0Sjakob void	create_timeval(double, struct timeval *, struct timeval *);
1304142bea0Sjakob 
1317ad2fb6cSderaadt #ifdef DEBUG
1324844c6b7Salexander void	print_packet(const struct ntp_data *);
1334844c6b7Salexander #endif
1344844c6b7Salexander 
135246969aeSjakob int	corrleaps;
1367c465852Sjakob 
1374142bea0Sjakob void
ntp_client(const char * hostname,int family,struct timeval * new,struct timeval * adjust,int leapflag)13822d417c3Sjakob ntp_client(const char *hostname, int family, struct timeval *new,
139246969aeSjakob     struct timeval *adjust, int leapflag)
1404142bea0Sjakob {
1412e2f3e6dSjakob 	struct addrinfo hints, *res0, *res;
1424142bea0Sjakob 	double offset, error;
1434844c6b7Salexander 	int accept = 0, ret, s, ierror;
1444142bea0Sjakob 
1452e2f3e6dSjakob 	memset(&hints, 0, sizeof(hints));
14622d417c3Sjakob 	hints.ai_family = family;
1472e2f3e6dSjakob 	hints.ai_socktype = SOCK_DGRAM;
14863894342Sitojun 	ierror = getaddrinfo(hostname, "ntp", &hints, &res0);
14963894342Sitojun 	if (ierror) {
15063894342Sitojun 		errx(1, "%s: %s", hostname, gai_strerror(ierror));
1512e2f3e6dSjakob 		/*NOTREACHED*/
1524142bea0Sjakob 	}
1534142bea0Sjakob 
1544a5cc25cSmestre 	if (pledge("stdio inet", NULL) == -1)
1554a5cc25cSmestre 		err(1, "pledge");
1564a5cc25cSmestre 
157246969aeSjakob 	corrleaps = leapflag;
15843a75b63Sjakob 	if (corrleaps)
15943a75b63Sjakob 		ntpleaps_init();
16043a75b63Sjakob 
1612e2f3e6dSjakob 	s = -1;
1622e2f3e6dSjakob 	for (res = res0; res; res = res->ai_next) {
1632e2f3e6dSjakob 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
164df69c215Sderaadt 		if (s == -1)
1652e2f3e6dSjakob 			continue;
1664142bea0Sjakob 
1674844c6b7Salexander 		ret = sync_ntp(s, res->ai_addr, &offset, &error);
1684844c6b7Salexander 		if (ret < 0) {
1692e2f3e6dSjakob #ifdef DEBUG
1702e2f3e6dSjakob 			fprintf(stderr, "try the next address\n");
1712e2f3e6dSjakob #endif
1724142bea0Sjakob 			close(s);
1732e2f3e6dSjakob 			s = -1;
1742e2f3e6dSjakob 			continue;
1752e2f3e6dSjakob 		}
1764844c6b7Salexander 
1774844c6b7Salexander 		accept++;
1782e2f3e6dSjakob 		break;
1792e2f3e6dSjakob 	}
1802e2f3e6dSjakob 	freeaddrinfo(res0);
1814142bea0Sjakob 
18220d5699bSjakob #ifdef DEBUG
1834142bea0Sjakob 	fprintf(stderr, "Correction: %.6f +/- %.6f\n", offset, error);
18420d5699bSjakob #endif
1854142bea0Sjakob 
186ab7b68a0Shenning 	if (accept < 1)
1874844c6b7Salexander 		errx(1, "Unable to get a reasonable time estimate");
1884844c6b7Salexander 
1894142bea0Sjakob 	create_timeval(offset, new, adjust);
1904142bea0Sjakob }
1914142bea0Sjakob 
1924142bea0Sjakob int
sync_ntp(int fd,const struct sockaddr * peer,double * offset,double * error)1934142bea0Sjakob sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
1944142bea0Sjakob {
19519b39fdbStb 	int accepts = 0, rejects = 0;
1964844c6b7Salexander 	int delay = MAX_DELAY, ret;
1974142bea0Sjakob 	double deadline;
1984142bea0Sjakob 	double a, b, x, y;
1994142bea0Sjakob 	double minerr = 0.1;		/* Maximum ignorable variation */
2004142bea0Sjakob 	struct ntp_data data;
2014142bea0Sjakob 
2024142bea0Sjakob 	deadline = current_time(JAN_1970) + delay;
2034142bea0Sjakob 	*offset = 0.0;
2044142bea0Sjakob 	*error = NTP_INSANITY;
2054142bea0Sjakob 
206df69c215Sderaadt 	if (connect(fd, peer, SA_LEN(peer)) == -1) {
2074844c6b7Salexander 		warn("Failed to connect to server");
208ab7b68a0Shenning 		return (-1);
2094844c6b7Salexander 	}
2104844c6b7Salexander 
21119b39fdbStb 	while (accepts < MAX_QUERIES) {
2124844c6b7Salexander 		memset(&data, 0, sizeof(data));
2134142bea0Sjakob 
2144844c6b7Salexander 		if (current_time(JAN_1970) > deadline) {
2154844c6b7Salexander 			warnx("Not enough valid responses received in time");
216ab7b68a0Shenning 			return (-1);
2174844c6b7Salexander 		}
2184142bea0Sjakob 
2194844c6b7Salexander 		if (write_packet(fd, &data) < 0)
220ab7b68a0Shenning 			return (-1);
2214844c6b7Salexander 
2224844c6b7Salexander 		ret = read_packet(fd, &data, &x, &y);
2234844c6b7Salexander 
2244844c6b7Salexander 		if (ret < 0)
225ab7b68a0Shenning 			return (-1);
2264844c6b7Salexander 		else if (ret > 0) {
2274844c6b7Salexander #ifdef DEBUG
2284844c6b7Salexander 			print_packet(&data);
2294844c6b7Salexander #endif
2304844c6b7Salexander 
2314844c6b7Salexander 			if (++rejects > MAX_QUERIES) {
2324844c6b7Salexander 				warnx("Too many bad or lost packets");
233ab7b68a0Shenning 				return (-1);
2344844c6b7Salexander 			} else
2354142bea0Sjakob 				continue;
2364142bea0Sjakob 		} else
2374142bea0Sjakob 			++accepts;
2384142bea0Sjakob 
23920d5699bSjakob #ifdef DEBUG
240ab7b68a0Shenning 		fprintf(stderr, "Offset: %.6f +/- %.6f\n", x, y);
24120d5699bSjakob #endif
2424142bea0Sjakob 
24304ef39a3Sderaadt 		if ((a = x - *offset) < 0.0)
24404ef39a3Sderaadt 			a = -a;
24504ef39a3Sderaadt 		if (accepts <= 1)
24604ef39a3Sderaadt 			a = 0.0;
2474142bea0Sjakob 		b = *error + y;
2484142bea0Sjakob 		if (y < *error) {
2494142bea0Sjakob 			*offset = x;
2504142bea0Sjakob 			*error = y;
2514142bea0Sjakob 		}
2524142bea0Sjakob 
25320d5699bSjakob #ifdef DEBUG
2544142bea0Sjakob 		fprintf(stderr, "Best: %.6f +/- %.6f\n", *offset, *error);
25520d5699bSjakob #endif
2564142bea0Sjakob 
2574844c6b7Salexander 		if (a > b) {
2584844c6b7Salexander 			warnx("Inconsistent times received from NTP server");
259ab7b68a0Shenning 			return (-1);
2604844c6b7Salexander 		}
2614142bea0Sjakob 
262231a5ec4Sckuethe 		if ((data.status & STATUS_ALARM) == STATUS_ALARM) {
263231a5ec4Sckuethe 			warnx("Ignoring NTP server with alarm flag set");
264231a5ec4Sckuethe 			return (-1);
265231a5ec4Sckuethe 		}
266231a5ec4Sckuethe 
26704ef39a3Sderaadt 		if (*error <= minerr)
26804ef39a3Sderaadt 			break;
2694142bea0Sjakob 	}
2704142bea0Sjakob 
271ab7b68a0Shenning 	return (accepts);
2724142bea0Sjakob }
2734142bea0Sjakob 
2744844c6b7Salexander /* Send out NTP packet. */
2754844c6b7Salexander int
write_packet(int fd,struct ntp_data * data)2764844c6b7Salexander write_packet(int fd, struct ntp_data *data)
2774142bea0Sjakob {
2784844c6b7Salexander 	u_char	packet[NTP_PACKET_MIN];
2794844c6b7Salexander 	ssize_t	length;
2801346900eSjakob 
2814844c6b7Salexander 	memset(packet, 0, sizeof(packet));
2824844c6b7Salexander 
2834844c6b7Salexander 	packet[0] = (NTP_VERSION << 3) | (NTP_MODE_CLIENT);
2844844c6b7Salexander 
2854d79ab39Sderaadt 	arc4random_buf(&data->xmitck, sizeof(data->xmitck));
2861346900eSjakob 
2871346900eSjakob 	/*
2881346900eSjakob 	 * Send out a random 64-bit number as our transmit time.  The NTP
2891346900eSjakob 	 * server will copy said number into the originate field on the
2901346900eSjakob 	 * response that it sends us.  This is totally legal per the SNTP spec.
2911346900eSjakob 	 *
2921346900eSjakob 	 * The impact of this is two fold: we no longer send out the current
2931346900eSjakob 	 * system time for the world to see (which may aid an attacker), and
2941346900eSjakob 	 * it gives us a (not very secure) way of knowing that we're not
2951346900eSjakob 	 * getting spoofed by an attacker that can't capture our traffic
2961346900eSjakob 	 * but can spoof packets from the NTP server we're communicating with.
2971346900eSjakob 	 *
2984844c6b7Salexander 	 * No endian concerns here.  Since we're running as a strict
2994844c6b7Salexander 	 * unicast client, we don't have to worry about anyone else finding
3004844c6b7Salexander 	 * the transmit field intelligible.
3011346900eSjakob 	 */
3021346900eSjakob 
303914fb6eeSkrw 	bcopy(&data->xmitck, (packet + NTP_TRANSMIT), sizeof(data->xmitck));
3044142bea0Sjakob 
3054844c6b7Salexander 	data->originate = current_time(JAN_1970);
3064142bea0Sjakob 
3074844c6b7Salexander 	length = write(fd, packet, sizeof(packet));
3084844c6b7Salexander 
3094844c6b7Salexander 	if (length != sizeof(packet)) {
3104844c6b7Salexander 		warn("Unable to send NTP packet to server");
311ab7b68a0Shenning 		return (-1);
3124142bea0Sjakob 	}
3134142bea0Sjakob 
314ab7b68a0Shenning 	return (0);
3154142bea0Sjakob }
3164142bea0Sjakob 
317eea542eaSderaadt /*
318eea542eaSderaadt  * Check the packet and work out the offset and optionally the error.
3194142bea0Sjakob  * Note that this contains more checking than xntp does. Return 0 for
3204142bea0Sjakob  * success, 1 for failure. Note that it must not change its arguments
321eea542eaSderaadt  * if it fails.
322eea542eaSderaadt  */
3234142bea0Sjakob int
read_packet(int fd,struct ntp_data * data,double * off,double * error)3244844c6b7Salexander read_packet(int fd, struct ntp_data *data, double *off, double *error)
3254142bea0Sjakob {
3264844c6b7Salexander 	u_char	receive[NTP_PACKET_MAX];
3274d79ab39Sderaadt 	struct	pollfd pfd[1];
3284844c6b7Salexander 	double	x, y;
3291ed5e288Sho 	int	length, r;
3304142bea0Sjakob 
3314d79ab39Sderaadt 	pfd[0].fd = fd;
3324d79ab39Sderaadt 	pfd[0].events = POLLIN;
3331ed5e288Sho 
3341ed5e288Sho retry:
3354d79ab39Sderaadt 	r = poll(pfd, 1, 1000 * MAX_DELAY / MAX_QUERIES);
336df69c215Sderaadt 	if (r == -1) {
3371ed5e288Sho 		if (errno == EINTR)
3381ed5e288Sho 			goto retry;
3394844c6b7Salexander 		warn("select");
340ab7b68a0Shenning 		return (r);
3414844c6b7Salexander 	}
3424844c6b7Salexander 
3434d79ab39Sderaadt 	if (r != 1)
344ab7b68a0Shenning 		return (1);
3454d79ab39Sderaadt 	if ((pfd[0].revents & POLLIN) == 0)
3464d79ab39Sderaadt 		return (1);
3474844c6b7Salexander 
3484844c6b7Salexander 	length = read(fd, receive, NTP_PACKET_MAX);
349df69c215Sderaadt 	if (length == -1) {
3504844c6b7Salexander 		warn("Unable to receive NTP packet from server");
351ab7b68a0Shenning 		return (-1);
3524844c6b7Salexander 	}
3534844c6b7Salexander 
3544142bea0Sjakob 	if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
35556dc85a1Salexander 		warnx("Invalid NTP packet size, packet rejected");
356ab7b68a0Shenning 		return (1);
3574142bea0Sjakob 	}
3584142bea0Sjakob 
3594844c6b7Salexander 	unpack_ntp(data, receive);
3604142bea0Sjakob 
3611346900eSjakob 	if (data->recvck != data->xmitck) {
36256dc85a1Salexander 		warnx("Invalid cookie received, packet rejected");
363ab7b68a0Shenning 		return (1);
3641346900eSjakob 	}
3651346900eSjakob 
366eb434a57Shenning 	if (data->version < NTP_VERSION_MIN ||
367eb434a57Shenning 	    data->version > NTP_VERSION_MAX) {
368eb22ee6cShenning 		warnx("Received NTP version %u, need %u or lower",
369eb22ee6cShenning 		    data->version, NTP_VERSION);
370ab7b68a0Shenning 		return (1);
3714142bea0Sjakob 	}
3724142bea0Sjakob 
3734142bea0Sjakob 	if (data->mode != NTP_MODE_SERVER) {
3744142bea0Sjakob 		warnx("Invalid NTP server mode, packet rejected");
375ab7b68a0Shenning 		return (1);
3764142bea0Sjakob 	}
3774142bea0Sjakob 
378454d8160Shenning 	if (data->stratum > NTP_STRATUM_MAX) {
3794844c6b7Salexander 		warnx("Invalid stratum received, packet rejected");
380ab7b68a0Shenning 		return (1);
3814844c6b7Salexander 	}
3824844c6b7Salexander 
3834844c6b7Salexander 	if (data->transmit == 0.0) {
3844844c6b7Salexander 		warnx("Server clock invalid, packet rejected");
385ab7b68a0Shenning 		return (1);
3864142bea0Sjakob 	}
3874142bea0Sjakob 
3884142bea0Sjakob 	x = data->receive - data->originate;
3894844c6b7Salexander 	y = data->transmit - data->current;
3904844c6b7Salexander 
3914844c6b7Salexander 	*off = (x + y) / 2;
3924142bea0Sjakob 	*error = x - y;
3934844c6b7Salexander 
3944844c6b7Salexander 	x = (data->current - data->originate) / 2;
3954844c6b7Salexander 
3964844c6b7Salexander 	if (x > *error)
3974844c6b7Salexander 		*error = x;
3984142bea0Sjakob 
399ab7b68a0Shenning 	return (0);
4004142bea0Sjakob }
4014142bea0Sjakob 
402eea542eaSderaadt /*
403eea542eaSderaadt  * Unpack the essential data from an NTP packet, bypassing struct
4044142bea0Sjakob  * layout and endian problems.  Note that it ignores fields irrelevant
405eea542eaSderaadt  * to SNTP.
406eea542eaSderaadt  */
4074142bea0Sjakob void
unpack_ntp(struct ntp_data * data,u_char * packet)4084844c6b7Salexander unpack_ntp(struct ntp_data *data, u_char *packet)
4094142bea0Sjakob {
410*2d44acdfSotto 	int i, era;
4114142bea0Sjakob 	double d;
4124142bea0Sjakob 
4134142bea0Sjakob 	data->current = current_time(JAN_1970);
4144142bea0Sjakob 
4154142bea0Sjakob 	data->status = (packet[0] >> 6);
4164142bea0Sjakob 	data->version = (packet[0] >> 3) & 0x07;
4174142bea0Sjakob 	data->mode = packet[0] & 0x07;
4184142bea0Sjakob 	data->stratum = packet[1];
4194142bea0Sjakob 
4204142bea0Sjakob 	for (i = 0, d = 0.0; i < 8; ++i)
4214142bea0Sjakob 		d = 256.0*d+packet[NTP_RECEIVE+i];
422ab7b68a0Shenning 
423*2d44acdfSotto 	era = NTP_ERA;
424*2d44acdfSotto 	if (packet[NTP_RECEIVE] <= 127)
425*2d44acdfSotto 		era++;
4264142bea0Sjakob 	data->receive = d / NTP_SCALE;
427*2d44acdfSotto 	data->receive += era * SECS_IN_ERA;
4284142bea0Sjakob 
4294142bea0Sjakob 	for (i = 0, d = 0.0; i < 8; ++i)
4304142bea0Sjakob 		d = 256.0*d+packet[NTP_TRANSMIT+i];
431ab7b68a0Shenning 
432*2d44acdfSotto 	era = NTP_ERA;
433*2d44acdfSotto 	if (packet[NTP_TRANSMIT] <= 127)
434*2d44acdfSotto 		era++;
4354142bea0Sjakob 	data->transmit = d / NTP_SCALE;
436*2d44acdfSotto 	data->transmit += era * SECS_IN_ERA;
4371346900eSjakob 
4384844c6b7Salexander 	/* See write_packet for why this isn't an endian problem. */
439914fb6eeSkrw 	bcopy((packet + NTP_ORIGINATE), &data->recvck, sizeof(data->recvck));
4404142bea0Sjakob }
4414142bea0Sjakob 
442eea542eaSderaadt /*
443eea542eaSderaadt  * Get the current UTC time in seconds since the Epoch plus an offset
4444142bea0Sjakob  * (usually the time from the beginning of the century to the Epoch)
445eea542eaSderaadt  */
4464142bea0Sjakob double
current_time(double offset)4474142bea0Sjakob current_time(double offset)
4484142bea0Sjakob {
4494142bea0Sjakob 	struct timeval current;
4502f6e235dSjakob 	u_int64_t t;
4514142bea0Sjakob 
4524142bea0Sjakob 	if (gettimeofday(&current, NULL))
4534142bea0Sjakob 		err(1, "Could not get local time of day");
4544142bea0Sjakob 
455c81dd12eSjakob 	/*
456c81dd12eSjakob 	 * At this point, current has the current TAI time.
4572f6e235dSjakob 	 * Now subtract leap seconds to set the posix tick.
4582f6e235dSjakob 	 */
4592f6e235dSjakob 
460c81dd12eSjakob 	t = SEC_TO_TAI64(current.tv_sec);
4617c465852Sjakob 	if (corrleaps)
4622f6e235dSjakob 		ntpleaps_sub(&t);
4632f6e235dSjakob 
464ab7b68a0Shenning 	return (offset + TAI64_TO_SEC(t) + 1.0e-6 * current.tv_usec);
4654142bea0Sjakob }
4664142bea0Sjakob 
467eea542eaSderaadt /*
468eea542eaSderaadt  * Change offset into current UTC time. This is portable, even if
469eea542eaSderaadt  * struct timeval uses an unsigned long for tv_sec.
470eea542eaSderaadt  */
4714142bea0Sjakob void
create_timeval(double difference,struct timeval * new,struct timeval * adjust)4724142bea0Sjakob create_timeval(double difference, struct timeval *new, struct timeval *adjust)
4734142bea0Sjakob {
4744142bea0Sjakob 	struct timeval old;
475*2d44acdfSotto 	long long n;
4764142bea0Sjakob 
4774142bea0Sjakob 	/* Start by converting to timeval format. Note that we have to
4784142bea0Sjakob 	 * cater for negative, unsigned values. */
479*2d44acdfSotto 	if ((n = (long long) difference) > difference)
4804142bea0Sjakob 		--n;
4814142bea0Sjakob 	adjust->tv_sec = n;
4824142bea0Sjakob 	adjust->tv_usec = (long) (MILLION_D * (difference-n));
4834142bea0Sjakob 	errno = 0;
4844142bea0Sjakob 	if (gettimeofday(&old, NULL))
4854142bea0Sjakob 		err(1, "Could not get local time of day");
4864142bea0Sjakob 	new->tv_sec = old.tv_sec + adjust->tv_sec;
4874142bea0Sjakob 	new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
4884142bea0Sjakob 
4894142bea0Sjakob 	if (n < 0) {
4904142bea0Sjakob 		new->tv_usec += MILLION_L;
4914142bea0Sjakob 		--new->tv_sec;
4924142bea0Sjakob 	} else if (n >= MILLION_L) {
4934142bea0Sjakob 		new->tv_usec -= MILLION_L;
4944142bea0Sjakob 		++new->tv_sec;
4954142bea0Sjakob 	}
4964142bea0Sjakob }
4974142bea0Sjakob 
4984142bea0Sjakob #ifdef DEBUG
4994142bea0Sjakob void
print_packet(const struct ntp_data * data)5004142bea0Sjakob print_packet(const struct ntp_data *data)
5014142bea0Sjakob {
5024142bea0Sjakob 	printf("status:      %u\n", data->status);
5034142bea0Sjakob 	printf("version:     %u\n", data->version);
5044142bea0Sjakob 	printf("mode:        %u\n", data->mode);
5054142bea0Sjakob 	printf("stratum:     %u\n", data->stratum);
5064844c6b7Salexander 	printf("originate:   %f\n", data->originate);
5074844c6b7Salexander 	printf("receive:     %f\n", data->receive);
5084844c6b7Salexander 	printf("transmit:    %f\n", data->transmit);
5094844c6b7Salexander 	printf("current:     %f\n", data->current);
5101346900eSjakob 	printf("xmitck:      0x%0llX\n", data->xmitck);
5111346900eSjakob 	printf("recvck:      0x%0llX\n", data->recvck);
5124142bea0Sjakob };
5134142bea0Sjakob #endif
514