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