xref: /openbsd-src/usr.sbin/ntpd/client.c (revision 8745f5cf9c71e9801d335b988c13bd14a57ce14d)
1*8745f5cfSotto /*	$OpenBSD: client.c,v 1.118 2023/12/20 15:36:36 otto Exp $ */
29096d664Shenning 
39096d664Shenning /*
49096d664Shenning  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
59096d664Shenning  * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
69096d664Shenning  *
79096d664Shenning  * Permission to use, copy, modify, and distribute this software for any
89096d664Shenning  * purpose with or without fee is hereby granted, provided that the above
99096d664Shenning  * copyright notice and this permission notice appear in all copies.
109096d664Shenning  *
119096d664Shenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
129096d664Shenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
139096d664Shenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
149096d664Shenning  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15774da4d1Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16774da4d1Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17774da4d1Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
189096d664Shenning  */
199096d664Shenning 
2061f07045Sderaadt #include <sys/types.h>
219096d664Shenning #include <errno.h>
22a94d3d28Snaddy #include <md5.h>
239ca3f2f2Sstevesk #include <stdio.h>
249096d664Shenning #include <stdlib.h>
259096d664Shenning #include <string.h>
269096d664Shenning #include <time.h>
279096d664Shenning #include <unistd.h>
289096d664Shenning 
299096d664Shenning #include "ntpd.h"
309096d664Shenning 
315ba7fd73Shenning int	client_update(struct ntp_peer *);
32841516aaSotto int	auto_cmp(const void *, const void *);
33eb7f225fSotto void	handle_auto(u_int8_t, double);
3446c6bb47Sotto void	set_deadline(struct ntp_peer *, time_t);
3546c6bb47Sotto 
3646c6bb47Sotto void
set_next(struct ntp_peer * p,time_t t)3746c6bb47Sotto set_next(struct ntp_peer *p, time_t t)
3846c6bb47Sotto {
392fae8c34Shenning 	p->next = getmonotime() + t;
4046c6bb47Sotto 	p->deadline = 0;
4164c82965Sphessler 	p->poll = t;
4246c6bb47Sotto }
4346c6bb47Sotto 
4446c6bb47Sotto void
set_deadline(struct ntp_peer * p,time_t t)4546c6bb47Sotto set_deadline(struct ntp_peer *p, time_t t)
4646c6bb47Sotto {
472fae8c34Shenning 	p->deadline = getmonotime() + t;
4846c6bb47Sotto 	p->next = 0;
4946c6bb47Sotto }
505ba7fd73Shenning 
519096d664Shenning int
client_peer_init(struct ntp_peer * p)529096d664Shenning client_peer_init(struct ntp_peer *p)
539096d664Shenning {
5420db0646Sotto 	p->query.fd = -1;
5520db0646Sotto 	p->query.msg.status = MODE_CLIENT | (NTP_VERSION << 3);
5620db0646Sotto 	p->query.xmttime = 0;
575c35bc7eShenning 	p->state = STATE_NONE;
585c35bc7eShenning 	p->shift = 0;
595c35bc7eShenning 	p->trustlevel = TRUSTLEVEL_PATHETIC;
60ec251dc1Sdtucker 	p->lasterror = 0;
61bc207761Smpf 	p->senderrors = 0;
625c35bc7eShenning 
635c35bc7eShenning 	return (client_addr_init(p));
645c35bc7eShenning }
655c35bc7eShenning 
665c35bc7eShenning int
client_addr_init(struct ntp_peer * p)675c35bc7eShenning client_addr_init(struct ntp_peer *p)
685c35bc7eShenning {
699096d664Shenning 	struct sockaddr_in	*sa_in;
709096d664Shenning 	struct sockaddr_in6	*sa_in6;
713801c0acShenning 	struct ntp_addr		*h;
729096d664Shenning 
733801c0acShenning 	for (h = p->addr; h != NULL; h = h->next) {
743801c0acShenning 		switch (h->ss.ss_family) {
759096d664Shenning 		case AF_INET:
763801c0acShenning 			sa_in = (struct sockaddr_in *)&h->ss;
779096d664Shenning 			if (ntohs(sa_in->sin_port) == 0)
789096d664Shenning 				sa_in->sin_port = htons(123);
796be00f15Shenning 			p->state = STATE_DNS_DONE;
809096d664Shenning 			break;
819096d664Shenning 		case AF_INET6:
823801c0acShenning 			sa_in6 = (struct sockaddr_in6 *)&h->ss;
839096d664Shenning 			if (ntohs(sa_in6->sin6_port) == 0)
849096d664Shenning 				sa_in6->sin6_port = htons(123);
856be00f15Shenning 			p->state = STATE_DNS_DONE;
869096d664Shenning 			break;
879096d664Shenning 		default:
88ede00a73Sstevesk 			fatalx("king bula sez: wrong AF in client_addr_init");
8925018bd4Sbcook 			/* NOTREACHED */
909096d664Shenning 		}
913801c0acShenning 	}
929096d664Shenning 
9320db0646Sotto 	p->query.fd = -1;
9446c6bb47Sotto 	set_next(p, 0);
959096d664Shenning 
969096d664Shenning 	return (0);
979096d664Shenning }
989096d664Shenning 
999096d664Shenning int
client_nextaddr(struct ntp_peer * p)1003801c0acShenning client_nextaddr(struct ntp_peer *p)
1013801c0acShenning {
10220db0646Sotto 	if (p->query.fd != -1) {
10320db0646Sotto 		close(p->query.fd);
10420db0646Sotto 		p->query.fd = -1;
1050e43a845Shenning 	}
1063801c0acShenning 
10768467764Sotto 	if (p->state == STATE_DNS_INPROGRESS)
10868467764Sotto 		return (-1);
10968467764Sotto 
110547afbf8Shenning 	if (p->addr_head.a == NULL) {
111b775b3eeSreyk 		priv_dns(IMSG_HOST_DNS, p->addr_head.name, p->id);
1126be00f15Shenning 		p->state = STATE_DNS_INPROGRESS;
113547afbf8Shenning 		return (-1);
114547afbf8Shenning 	}
115547afbf8Shenning 
1163801c0acShenning 	p->shift = 0;
1173801c0acShenning 	p->trustlevel = TRUSTLEVEL_PATHETIC;
1183801c0acShenning 
1196a6b450eSotto 	if (p->addr == NULL)
1206a6b450eSotto 		p->addr = p->addr_head.a;
1216a6b450eSotto 	else if ((p->addr = p->addr->next) == NULL)
1226a6b450eSotto 		return (1);
1236a6b450eSotto 
1243801c0acShenning 	return (0);
1253801c0acShenning }
1263801c0acShenning 
1273801c0acShenning int
client_query(struct ntp_peer * p)1289096d664Shenning client_query(struct ntp_peer *p)
1299096d664Shenning {
1306477e83aShenning 	int	val;
13162d6660dSdtucker 
132547afbf8Shenning 	if (p->addr == NULL && client_nextaddr(p) == -1) {
13309f868acSotto 		if (conf->settime)
13409f868acSotto 			set_next(p, INTERVAL_AUIO_DNSFAIL);
13509f868acSotto 		else
136e3770ba3Sbcook 			set_next(p, MAXIMUM(SETTIME_TIMEOUT,
13780596abcSotto 			    scale_interval(INTERVAL_QUERY_AGGRESSIVE)));
1388f3fb318Shenning 		return (0);
139547afbf8Shenning 	}
140547afbf8Shenning 
1413ee58c44Sotto 	if (conf->status.synced && p->addr->notauth) {
1423ee58c44Sotto 		peer_addr_head_clear(p);
1433ee58c44Sotto 		client_nextaddr(p);
1443ee58c44Sotto 		return (0);
1453ee58c44Sotto 	}
1463ee58c44Sotto 
1476be00f15Shenning 	if (p->state < STATE_DNS_DONE || p->addr == NULL)
1486be00f15Shenning 		return (-1);
1496be00f15Shenning 
15020db0646Sotto 	if (p->query.fd == -1) {
151359b7b95Sdtucker 		struct sockaddr *sa = (struct sockaddr *)&p->addr->ss;
1523e0a6a28Sbenno 		struct sockaddr *qa4 = (struct sockaddr *)&p->query_addr4;
1533e0a6a28Sbenno 		struct sockaddr *qa6 = (struct sockaddr *)&p->query_addr6;
154359b7b95Sdtucker 
15520db0646Sotto 		if ((p->query.fd = socket(p->addr->ss.ss_family, SOCK_DGRAM,
1567923f1d6Shenning 		    0)) == -1)
1577923f1d6Shenning 			fatal("client_query socket");
15802d74365Sphessler 
1593e0a6a28Sbenno 		if (p->addr->ss.ss_family == qa4->sa_family) {
16020db0646Sotto 			if (bind(p->query.fd, qa4, SA_LEN(qa4)) == -1)
1613e0a6a28Sbenno 				fatal("couldn't bind to IPv4 query address: %s",
1623e0a6a28Sbenno 				    log_sockaddr(qa4));
1633e0a6a28Sbenno 		} else if (p->addr->ss.ss_family == qa6->sa_family) {
16420db0646Sotto 			if (bind(p->query.fd, qa6, SA_LEN(qa6)) == -1)
1653e0a6a28Sbenno 				fatal("couldn't bind to IPv6 query address: %s",
1663e0a6a28Sbenno 				    log_sockaddr(qa6));
1673e0a6a28Sbenno 		}
1683e0a6a28Sbenno 
16920db0646Sotto 		if (connect(p->query.fd, sa, SA_LEN(sa)) == -1) {
1707923f1d6Shenning 			if (errno == ECONNREFUSED || errno == ENETUNREACH ||
171477b2fe3Shenning 			    errno == EHOSTUNREACH || errno == EADDRNOTAVAIL) {
1726a6b450eSotto 				/* cycle through addresses, but do increase
1736a6b450eSotto 				   senderrors */
1747923f1d6Shenning 				client_nextaddr(p);
1756a6b450eSotto 				if (p->addr == NULL)
1766a6b450eSotto 					p->addr = p->addr_head.a;
177e3770ba3Sbcook 				set_next(p, MAXIMUM(SETTIME_TIMEOUT,
17880596abcSotto 				    scale_interval(INTERVAL_QUERY_AGGRESSIVE)));
1796a6b450eSotto 				p->senderrors++;
1807923f1d6Shenning 				return (-1);
1817923f1d6Shenning 			} else
1827923f1d6Shenning 				fatal("client_query connect");
1837923f1d6Shenning 		}
1846477e83aShenning 		val = IPTOS_LOWDELAY;
18520db0646Sotto 		if (p->addr->ss.ss_family == AF_INET && setsockopt(p->query.fd,
1866477e83aShenning 		    IPPROTO_IP, IP_TOS, &val, sizeof(val)) == -1)
18762d6660dSdtucker 			log_warn("setsockopt IPTOS_LOWDELAY");
1886477e83aShenning 		val = 1;
18920db0646Sotto 		if (setsockopt(p->query.fd, SOL_SOCKET, SO_TIMESTAMP,
1906477e83aShenning 		    &val, sizeof(val)) == -1)
1916477e83aShenning 			fatal("setsockopt SO_TIMESTAMP");
1927923f1d6Shenning 	}
1937923f1d6Shenning 
1949096d664Shenning 	/*
1959096d664Shenning 	 * Send out a random 64-bit number as our transmit time.  The NTP
1969096d664Shenning 	 * server will copy said number into the originate field on the
1979096d664Shenning 	 * response that it sends us.  This is totally legal per the SNTP spec.
1989096d664Shenning 	 *
1999096d664Shenning 	 * The impact of this is two fold: we no longer send out the current
2009096d664Shenning 	 * system time for the world to see (which may aid an attacker), and
2019096d664Shenning 	 * it gives us a (not very secure) way of knowing that we're not
2029096d664Shenning 	 * getting spoofed by an attacker that can't capture our traffic
2039096d664Shenning 	 * but can spoof packets from the NTP server we're communicating with.
2049096d664Shenning 	 *
2059096d664Shenning 	 * Save the real transmit timestamp locally.
2069096d664Shenning 	 */
2079096d664Shenning 
20820db0646Sotto 	p->query.msg.xmttime.int_partl = arc4random();
20920db0646Sotto 	p->query.msg.xmttime.fractionl = arc4random();
21020db0646Sotto 	p->query.xmttime = gettime();
2119096d664Shenning 
21220db0646Sotto 	if (ntp_sendmsg(p->query.fd, NULL, &p->query.msg) == -1) {
213bc207761Smpf 		p->senderrors++;
21446c6bb47Sotto 		set_next(p, INTERVAL_QUERY_PATHETIC);
215f88f423aShenning 		p->trustlevel = TRUSTLEVEL_PATHETIC;
216e11a55dfShenning 		return (-1);
217e11a55dfShenning 	}
218e11a55dfShenning 
219bc207761Smpf 	p->senderrors = 0;
2209096d664Shenning 	p->state = STATE_QUERY_SENT;
22146c6bb47Sotto 	set_deadline(p, QUERYTIME_MAX);
2229096d664Shenning 
2239096d664Shenning 	return (0);
2249096d664Shenning }
2259096d664Shenning 
2269096d664Shenning int
auto_cmp(const void * a,const void * b)227841516aaSotto auto_cmp(const void *a, const void *b)
228841516aaSotto {
229841516aaSotto 	double at = *(const double *)a;
230841516aaSotto 	double bt = *(const double *)b;
231841516aaSotto 	return at < bt ? -1 : (at > bt ? 1 : 0);
232841516aaSotto }
233841516aaSotto 
234841516aaSotto void
handle_auto(uint8_t trusted,double offset)235eb7f225fSotto handle_auto(uint8_t trusted, double offset)
236841516aaSotto {
237841516aaSotto 	static int count;
238841516aaSotto 	static double v[AUTO_REPLIES];
239841516aaSotto 
240841516aaSotto 	/*
241841516aaSotto 	 * It happens the (constraint) resolves initially fail, don't give up
24206c2f543Sderaadt 	 * but see if we get validated replies later.
243841516aaSotto 	 */
244eb7f225fSotto 	if (!trusted && conf->constraint_median == 0)
245841516aaSotto 		return;
246841516aaSotto 
247841516aaSotto 	if (offset < AUTO_THRESHOLD) {
248841516aaSotto 		/* don't bother */
24971ba36b6Sotto 		priv_settime(0, "offset is negative or close enough");
250841516aaSotto 		return;
251841516aaSotto 	}
252841516aaSotto 	/* collect some more */
253841516aaSotto 	v[count++] = offset;
254841516aaSotto 	if (count < AUTO_REPLIES)
255841516aaSotto 		return;
256841516aaSotto 
257841516aaSotto 	/* we have enough */
258841516aaSotto 	qsort(v, count, sizeof(double), auto_cmp);
259841516aaSotto 	if (AUTO_REPLIES % 2 == 0)
260841516aaSotto 		offset = (v[AUTO_REPLIES / 2 - 1] + v[AUTO_REPLIES / 2]) / 2;
261841516aaSotto 	else
262841516aaSotto 		offset = v[AUTO_REPLIES / 2];
26371ba36b6Sotto 	priv_settime(offset, "");
264841516aaSotto }
265841516aaSotto 
266418ac0aeSotto 
267418ac0aeSotto /*
268418ac0aeSotto  * -1: Not processed, not an NTP message (e.g. icmp induced  ECONNREFUSED)
269418ac0aeSotto  *  0: Not prrocessed due to validation issues
270418ac0aeSotto  *  1: NTP message validated and processed
271418ac0aeSotto  */
272841516aaSotto int
client_dispatch(struct ntp_peer * p,u_int8_t settime,u_int8_t automatic)273841516aaSotto client_dispatch(struct ntp_peer *p, u_int8_t settime, u_int8_t automatic)
2749096d664Shenning {
2759096d664Shenning 	struct ntp_msg		 msg;
2766477e83aShenning 	struct msghdr		 somsg;
2776477e83aShenning 	struct iovec		 iov[1];
2786477e83aShenning 	struct timeval		 tv;
2796477e83aShenning 	char			 buf[NTP_MSGSIZE];
2806477e83aShenning 	union {
2816477e83aShenning 		struct cmsghdr	hdr;
2826477e83aShenning 		char		buf[CMSG_SPACE(sizeof(tv))];
2836477e83aShenning 	} cmsgbuf;
2846477e83aShenning 	struct cmsghdr		*cmsg;
2856477e83aShenning 	ssize_t			 size;
286418ac0aeSotto 	double			 T1, T2, T3, T4, offset, delay;
2875ba7fd73Shenning 	time_t			 interval;
2889096d664Shenning 
289842d7e97Sbcook 	memset(&somsg, 0, sizeof(somsg));
2906477e83aShenning 	iov[0].iov_base = buf;
2916477e83aShenning 	iov[0].iov_len = sizeof(buf);
2926477e83aShenning 	somsg.msg_iov = iov;
2936477e83aShenning 	somsg.msg_iovlen = 1;
2946477e83aShenning 	somsg.msg_control = cmsgbuf.buf;
2956477e83aShenning 	somsg.msg_controllen = sizeof(cmsgbuf.buf);
2966477e83aShenning 
29720db0646Sotto 	if ((size = recvmsg(p->query.fd, &somsg, 0)) == -1) {
29801c645f0Shenning 		if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
299ab51698fSdtucker 		    errno == ENETUNREACH || errno == ENETDOWN ||
300aa5b6c73Shenning 		    errno == ECONNREFUSED || errno == EADDRNOTAVAIL ||
301ee20ccfcShenning 		    errno == ENOPROTOOPT || errno == ENOENT) {
3026477e83aShenning 			client_log_error(p, "recvmsg", errno);
3037b668c67Sdtucker 			set_next(p, error_interval());
304418ac0aeSotto 			return (-1);
30501c645f0Shenning 		} else
3069096d664Shenning 			fatal("recvfrom");
30701c645f0Shenning 	}
3089096d664Shenning 
3096477e83aShenning 	if (somsg.msg_flags & MSG_TRUNC) {
3106477e83aShenning 		client_log_error(p, "recvmsg packet", EMSGSIZE);
3116477e83aShenning 		set_next(p, error_interval());
3126477e83aShenning 		return (0);
3136477e83aShenning 	}
3146477e83aShenning 
3156477e83aShenning 	if (somsg.msg_flags & MSG_CTRUNC) {
3166477e83aShenning 		client_log_error(p, "recvmsg control data", E2BIG);
3176477e83aShenning 		set_next(p, error_interval());
3186477e83aShenning 		return (0);
3196477e83aShenning 	}
3206477e83aShenning 
3216477e83aShenning 	for (cmsg = CMSG_FIRSTHDR(&somsg); cmsg != NULL;
3226477e83aShenning 	    cmsg = CMSG_NXTHDR(&somsg, cmsg)) {
3236477e83aShenning 		if (cmsg->cmsg_level == SOL_SOCKET &&
3246477e83aShenning 		    cmsg->cmsg_type == SCM_TIMESTAMP) {
3256477e83aShenning 			memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
326acf512e2Sbluhm 			T4 = gettime_from_timeval(&tv);
3276477e83aShenning 			break;
3286477e83aShenning 		}
3296477e83aShenning 	}
330acf512e2Sbluhm 	if (cmsg == NULL)
331acf512e2Sbluhm 		fatal("SCM_TIMESTAMP");
3326477e83aShenning 
333a6c97c40Sdtucker 	ntp_getmsg((struct sockaddr *)&p->addr->ss, buf, size, &msg);
3349096d664Shenning 
33520db0646Sotto 	if (msg.orgtime.int_partl != p->query.msg.xmttime.int_partl ||
33620db0646Sotto 	    msg.orgtime.fractionl != p->query.msg.xmttime.fractionl)
3379096d664Shenning 		return (0);
3389096d664Shenning 
339417a6d09Sdtucker 	if ((msg.status & LI_ALARM) == LI_ALARM || msg.stratum == 0 ||
3406bf14e63Sdtucker 	    msg.stratum > NTP_MAXSTRATUM) {
3419ca3f2f2Sstevesk 		char s[16];
3429ca3f2f2Sstevesk 
3439ca3f2f2Sstevesk 		if ((msg.status & LI_ALARM) == LI_ALARM) {
3449ca3f2f2Sstevesk 			strlcpy(s, "alarm", sizeof(s));
3459ca3f2f2Sstevesk 		} else if (msg.stratum == 0) {
3469ca3f2f2Sstevesk 			/* Kiss-o'-Death (KoD) packet */
3479ca3f2f2Sstevesk 			strlcpy(s, "KoD", sizeof(s));
3489ca3f2f2Sstevesk 		} else if (msg.stratum > NTP_MAXSTRATUM) {
3499ca3f2f2Sstevesk 			snprintf(s, sizeof(s), "stratum %d", msg.stratum);
3509ca3f2f2Sstevesk 		}
3517b668c67Sdtucker 		interval = error_interval();
3526bf14e63Sdtucker 		set_next(p, interval);
353b631dad7Smiod 		log_info("reply from %s: not synced (%s), next query %llds",
354*8745f5cfSotto 		    log_ntp_addr(p->addr), s, (long long)interval);
355417a6d09Sdtucker 		return (0);
3566bf14e63Sdtucker 	}
357417a6d09Sdtucker 
358692d048dSalexander 	/*
35905cdc201Salexander 	 * From RFC 2030 (with a correction to the delay math):
360692d048dSalexander 	 *
361692d048dSalexander 	 *     Timestamp Name          ID   When Generated
362692d048dSalexander 	 *     ------------------------------------------------------------
363692d048dSalexander 	 *     Originate Timestamp     T1   time request sent by client
364692d048dSalexander 	 *     Receive Timestamp       T2   time request received by server
365692d048dSalexander 	 *     Transmit Timestamp      T3   time reply sent by server
366692d048dSalexander 	 *     Destination Timestamp   T4   time reply received by client
367692d048dSalexander 	 *
368692d048dSalexander 	 *  The roundtrip delay d and local clock offset t are defined as
369692d048dSalexander 	 *
37005cdc201Salexander 	 *    d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2.
371692d048dSalexander 	 */
3729096d664Shenning 
37320db0646Sotto 	T1 = p->query.xmttime;
374692d048dSalexander 	T2 = lfp_to_d(msg.rectime);
375692d048dSalexander 	T3 = lfp_to_d(msg.xmttime);
376692d048dSalexander 
377bc58a738Sreyk 	/* Detect liars */
378eb7f225fSotto 	if (!p->trusted && conf->constraint_median != 0 &&
379bc58a738Sreyk 	    (constraint_check(T2) != 0 || constraint_check(T3) != 0)) {
380bc58a738Sreyk 		log_info("reply from %s: constraint check failed",
381*8745f5cfSotto 		    log_ntp_addr(p->addr));
382bc58a738Sreyk 		set_next(p, error_interval());
383bc58a738Sreyk 		return (0);
384bc58a738Sreyk 	}
385bc58a738Sreyk 
386acf512e2Sbluhm 	p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2 - getoffset();
38705cdc201Salexander 	p->reply[p->shift].delay = (T4 - T1) - (T3 - T2);
38864c82965Sphessler 	p->reply[p->shift].status.stratum = msg.stratum;
389b47582bfShenning 	if (p->reply[p->shift].delay < 0) {
390b47582bfShenning 		interval = error_interval();
391b47582bfShenning 		set_next(p, interval);
392ec29bbbaSckuethe 		log_info("reply from %s: negative delay %fs, "
393b631dad7Smiod 		    "next query %llds",
394*8745f5cfSotto 		    log_ntp_addr(p->addr),
395b631dad7Smiod 		    p->reply[p->shift].delay, (long long)interval);
396b47582bfShenning 		return (0);
397b47582bfShenning 	}
39858bea775Shenning 	p->reply[p->shift].error = (T2 - T1) - (T3 - T4);
3992fae8c34Shenning 	p->reply[p->shift].rcvd = getmonotime();
40058bea775Shenning 	p->reply[p->shift].good = 1;
4019096d664Shenning 
402a24621cfSdtucker 	p->reply[p->shift].status.leap = (msg.status & LIMASK);
403f2b597e2Salexander 	p->reply[p->shift].status.precision = msg.precision;
404bd8c7023Shenning 	p->reply[p->shift].status.rootdelay = sfp_to_d(msg.rootdelay);
405f2b597e2Salexander 	p->reply[p->shift].status.rootdispersion = sfp_to_d(msg.dispersion);
406895bba71Sstevesk 	p->reply[p->shift].status.refid = msg.refid;
407f2b597e2Salexander 	p->reply[p->shift].status.reftime = lfp_to_d(msg.reftime);
408f2b597e2Salexander 	p->reply[p->shift].status.poll = msg.ppoll;
409f2b597e2Salexander 
410a94d3d28Snaddy 	if (p->addr->ss.ss_family == AF_INET) {
411d0e4180eShenning 		p->reply[p->shift].status.send_refid =
412d0e4180eShenning 		    ((struct sockaddr_in *)&p->addr->ss)->sin_addr.s_addr;
413a94d3d28Snaddy 	} else if (p->addr->ss.ss_family == AF_INET6) {
414a94d3d28Snaddy 		MD5_CTX		context;
415a94d3d28Snaddy 		u_int8_t	digest[MD5_DIGEST_LENGTH];
416a94d3d28Snaddy 
417a94d3d28Snaddy 		MD5Init(&context);
418a94d3d28Snaddy 		MD5Update(&context, ((struct sockaddr_in6 *)&p->addr->ss)->
419a94d3d28Snaddy 		    sin6_addr.s6_addr, sizeof(struct in6_addr));
420a94d3d28Snaddy 		MD5Final(digest, &context);
421a94d3d28Snaddy 		memcpy((char *)&p->reply[p->shift].status.send_refid, digest,
422a94d3d28Snaddy 		    sizeof(u_int32_t));
423a94d3d28Snaddy 	} else
424d0e4180eShenning 		p->reply[p->shift].status.send_refid = msg.xmttime.fractionl;
425d0e4180eShenning 
42684e7b05bShenning 	p->state = STATE_REPLY_RECEIVED;
427692d048dSalexander 
42884e7b05bShenning 	/* every received reply which we do not discard increases trust */
42953a46c30Smickey 	if (p->trustlevel < TRUSTLEVEL_MAX) {
43084e7b05bShenning 		if (p->trustlevel < TRUSTLEVEL_BADPEER &&
43184e7b05bShenning 		    p->trustlevel + 1 >= TRUSTLEVEL_BADPEER)
43284e7b05bShenning 			log_info("peer %s now valid",
433*8745f5cfSotto 			    log_ntp_addr(p->addr));
43484e7b05bShenning 		p->trustlevel++;
435ba7c1387Shenning 	}
4369096d664Shenning 
437418ac0aeSotto 	offset = p->reply[p->shift].offset;
438418ac0aeSotto 	delay = p->reply[p->shift].delay;
439bde6c767Shenning 
4401b688c42Shenning 	client_update(p);
441841516aaSotto 	if (settime) {
442841516aaSotto 		if (automatic)
443eb7f225fSotto 			handle_auto(p->trusted, p->reply[p->shift].offset);
444841516aaSotto 		else
44571ba36b6Sotto 			priv_settime(p->reply[p->shift].offset, "");
446841516aaSotto 	}
4471b688c42Shenning 
448418ac0aeSotto 	if (p->trustlevel < TRUSTLEVEL_PATHETIC)
449418ac0aeSotto 		interval = scale_interval(INTERVAL_QUERY_PATHETIC);
450418ac0aeSotto 	else if (p->trustlevel < TRUSTLEVEL_AGGRESSIVE)
451418ac0aeSotto 		interval = (conf->settime && conf->automatic) ?
452418ac0aeSotto 		    INTERVAL_QUERY_ULTRA_VIOLENCE :
453418ac0aeSotto 		    scale_interval(INTERVAL_QUERY_AGGRESSIVE);
454418ac0aeSotto 	else
455418ac0aeSotto 		interval = scale_interval(INTERVAL_QUERY_NORMAL);
456418ac0aeSotto 
457418ac0aeSotto 	log_debug("reply from %s: offset %f delay %f, "
458*8745f5cfSotto 	    "next query %llds", log_ntp_addr(p->addr),
459*8745f5cfSotto 	    offset, delay, (long long)interval);
460418ac0aeSotto 
461418ac0aeSotto 	set_next(p, interval);
462418ac0aeSotto 
46359cad050Shenning 	if (++p->shift >= OFFSET_ARRAY_SIZE)
46484e7b05bShenning 		p->shift = 0;
4655ba7fd73Shenning 
466418ac0aeSotto 	return (1);
4675ba7fd73Shenning }
4685ba7fd73Shenning 
4695ba7fd73Shenning int
client_update(struct ntp_peer * p)4705ba7fd73Shenning client_update(struct ntp_peer *p)
4715ba7fd73Shenning {
4724c6157faSbluhm 	int	shift, best = -1, good = 0;
4735ba7fd73Shenning 
4745ba7fd73Shenning 	/*
4755ba7fd73Shenning 	 * clock filter
4765ba7fd73Shenning 	 * find the offset which arrived with the lowest delay
4775ba7fd73Shenning 	 * use that as the peer update
4785ba7fd73Shenning 	 * invalidate it and all older ones
4795ba7fd73Shenning 	 */
4805ba7fd73Shenning 
4814c6157faSbluhm 	for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++)
4824c6157faSbluhm 		if (p->reply[shift].good) {
4835ba7fd73Shenning 			good++;
4844c6157faSbluhm 			if (best == -1 ||
4854c6157faSbluhm 			    p->reply[shift].delay < p->reply[best].delay)
4864c6157faSbluhm 				best = shift;
4875ba7fd73Shenning 		}
4885ba7fd73Shenning 
4894c6157faSbluhm 	if (best == -1 || good < 8)
4905ba7fd73Shenning 		return (-1);
4915ba7fd73Shenning 
4924c6157faSbluhm 	p->update = p->reply[best];
493582f7186Sotto 	if (priv_adjtime() == 0) {
4944c6157faSbluhm 		for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++)
4954c6157faSbluhm 			if (p->reply[shift].rcvd <= p->reply[best].rcvd)
4964c6157faSbluhm 				p->reply[shift].good = 0;
497582f7186Sotto 	}
4989096d664Shenning 	return (0);
4999096d664Shenning }
500ec251dc1Sdtucker 
501ec251dc1Sdtucker void
client_log_error(struct ntp_peer * peer,const char * operation,int error)502ec251dc1Sdtucker client_log_error(struct ntp_peer *peer, const char *operation, int error)
503ec251dc1Sdtucker {
504ec251dc1Sdtucker 	const char *address;
505ec251dc1Sdtucker 
506*8745f5cfSotto 	address = log_ntp_addr(peer->addr);
507ec251dc1Sdtucker 	if (peer->lasterror == error) {
508a9a12196Sdtucker 		log_debug("%s %s: %s", operation, address, strerror(error));
509ec251dc1Sdtucker 		return;
510ec251dc1Sdtucker 	}
511ec251dc1Sdtucker 	peer->lasterror = error;
512ec251dc1Sdtucker 	log_warn("%s %s", operation, address);
513ec251dc1Sdtucker }
514