xref: /openbsd-src/usr.sbin/ntpd/ntp.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: ntp.c,v 1.181 2024/11/21 13:38:14 claudio Exp $ */
2914fd659Shenning 
3914fd659Shenning /*
4914fd659Shenning  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5914fd659Shenning  * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
6914fd659Shenning  *
7914fd659Shenning  * Permission to use, copy, modify, and distribute this software for any
8914fd659Shenning  * purpose with or without fee is hereby granted, provided that the above
9914fd659Shenning  * copyright notice and this permission notice appear in all copies.
10914fd659Shenning  *
11914fd659Shenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12914fd659Shenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13914fd659Shenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14914fd659Shenning  * 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.
18914fd659Shenning  */
19914fd659Shenning 
2061f07045Sderaadt #include <sys/types.h>
21a09080daShenning #include <sys/time.h>
225f5e166aSdtucker #include <sys/stat.h>
23914fd659Shenning #include <errno.h>
2410da828bShenning #include <fcntl.h>
2510da828bShenning #include <paths.h>
26914fd659Shenning #include <poll.h>
27914fd659Shenning #include <pwd.h>
281ea54919Shenning #include <signal.h>
29914fd659Shenning #include <stdlib.h>
30914fd659Shenning #include <string.h>
31579813e4Sreyk #include <syslog.h>
32c1ed3944Shenning #include <time.h>
33914fd659Shenning #include <unistd.h>
3413e678ecSderaadt #include <err.h>
35914fd659Shenning 
36914fd659Shenning #include "ntpd.h"
37914fd659Shenning 
38e7e6fe2dShenning #define	PFD_PIPE_MAIN	0
397cfabfdeSreyk #define	PFD_PIPE_DNS	1
407cfabfdeSreyk #define	PFD_SOCK_CTL	2
417cfabfdeSreyk #define	PFD_MAX		3
42914fd659Shenning 
43914fd659Shenning volatile sig_atomic_t	 ntp_quit = 0;
4438da1314Shenning struct imsgbuf		*ibuf_main;
456fe90a5aSotto static struct imsgbuf	*ibuf_dns;
46bf22f0ffShenning struct ntpd_conf	*conf;
4764c82965Sphessler struct ctl_conns	 ctl_conns;
4899c99903Shenning u_int			 peer_cnt;
49804c161bSotto u_int			 sensors_cnt;
50a257dd04Sreyk extern u_int		 constraint_cnt;
51914fd659Shenning 
52914fd659Shenning void	ntp_sighdlr(int);
53914fd659Shenning int	ntp_dispatch_imsg(void);
545f5af31aShenning int	ntp_dispatch_imsg_dns(void);
5599c99903Shenning void	peer_add(struct ntp_peer *);
5699c99903Shenning void	peer_remove(struct ntp_peer *);
576a6b450eSotto int	inpool(struct sockaddr_storage *,
586a6b450eSotto 	    struct sockaddr_storage[MAX_SERVERS_DNS], size_t);
59914fd659Shenning 
60914fd659Shenning void
61914fd659Shenning ntp_sighdlr(int sig)
62914fd659Shenning {
63914fd659Shenning 	switch (sig) {
64914fd659Shenning 	case SIGINT:
65914fd659Shenning 	case SIGTERM:
66914fd659Shenning 		ntp_quit = 1;
67914fd659Shenning 		break;
68914fd659Shenning 	}
69914fd659Shenning }
70914fd659Shenning 
714e840e7aSrzalamena void
724e840e7aSrzalamena ntp_main(struct ntpd_conf *nconf, struct passwd *pw, int argc, char **argv)
73914fd659Shenning {
7460524ed1Shenning 	int			 a, b, nfds, i, j, idx_peers, timeout;
757cfabfdeSreyk 	int			 nullfd, pipe_dns[2], idx_clients;
76f66b74beSbcook 	int			 ctls;
774e840e7aSrzalamena 	int			 fd_ctl;
7814c44c9eSotto 	int			 clear_cdns;
7974fd4626Shenning 	u_int			 pfd_elms = 0, idx2peer_elms = 0;
800f8bb54dShenning 	u_int			 listener_cnt, new_cnt, sent_cnt, trial_cnt;
81b775b3eeSreyk 	u_int			 ctl_cnt;
8274fd4626Shenning 	struct pollfd		*pfd = NULL;
83914fd659Shenning 	struct servent		*se;
84e7e6fe2dShenning 	struct listen_addr	*la;
859096d664Shenning 	struct ntp_peer		*p;
8674fd4626Shenning 	struct ntp_peer		**idx2peer = NULL;
87dd4ec8aeShenning 	struct ntp_sensor	*s, *next_s;
88bc58a738Sreyk 	struct constraint	*cstr;
89a09080daShenning 	struct timespec		 tp;
905f5e166aSdtucker 	struct stat		 stb;
9164c82965Sphessler 	struct ctl_conn		*cc;
92bc58a738Sreyk 	time_t			 nextaction, last_sensor_scan = 0, now;
9314c44c9eSotto 	time_t			 last_action = 0, interval, last_cdns_reset = 0;
9474fd4626Shenning 	void			*newp;
95914fd659Shenning 
964e840e7aSrzalamena 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC,
974e840e7aSrzalamena 	    pipe_dns) == -1)
984e840e7aSrzalamena 		fatal("socketpair");
994e840e7aSrzalamena 
1004e840e7aSrzalamena 	start_child(NTPDNS_PROC_NAME, pipe_dns[1], argc, argv);
101914fd659Shenning 
1028d2ac903Sotto 	log_init(nconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG, nconf->verbose,
1038d2ac903Sotto 	    LOG_DAEMON);
104c9addb91Sotto 	if (!nconf->debug && setsid() == -1)
1054f98a7eeSotto 		fatal("setsid");
106579813e4Sreyk 	log_procinit("ntp");
107579813e4Sreyk 
108914fd659Shenning 	if ((se = getservbyname("ntp", "udp")) == NULL)
109914fd659Shenning 		fatal("getservbyname");
110914fd659Shenning 
1114e840e7aSrzalamena 	/* Start control socket. */
1124e840e7aSrzalamena 	if ((fd_ctl = control_init(CTLSOCKET)) == -1)
1134e840e7aSrzalamena 		fatalx("control socket init failed");
1144e840e7aSrzalamena 	if (control_listen(fd_ctl) == -1)
1154e840e7aSrzalamena 		fatalx("control socket listen failed");
116b7041c07Sderaadt 	if ((nullfd = open("/dev/null", O_RDWR)) == -1)
11710da828bShenning 		fatal(NULL);
11810da828bShenning 
119e5b59994Sbcook 	if (stat(pw->pw_dir, &stb) == -1) {
120e5b59994Sbcook 		fatal("privsep dir %s could not be opened", pw->pw_dir);
121e5b59994Sbcook 	}
122e5b59994Sbcook 	if (stb.st_uid != 0 || (stb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
123e5b59994Sbcook 		fatalx("bad privsep dir %s permissions: %o",
124e5b59994Sbcook 		    pw->pw_dir, stb.st_mode);
125e5b59994Sbcook 	}
126914fd659Shenning 	if (chroot(pw->pw_dir) == -1)
127914fd659Shenning 		fatal("chroot");
128914fd659Shenning 	if (chdir("/") == -1)
129914fd659Shenning 		fatal("chdir(\"/\")");
130914fd659Shenning 
13110da828bShenning 	if (!nconf->debug) {
13210da828bShenning 		dup2(nullfd, STDIN_FILENO);
13310da828bShenning 		dup2(nullfd, STDOUT_FILENO);
13410da828bShenning 		dup2(nullfd, STDERR_FILENO);
13510da828bShenning 	}
13610da828bShenning 	close(nullfd);
13710da828bShenning 
138914fd659Shenning 	setproctitle("ntp engine");
139914fd659Shenning 
140bf22f0ffShenning 	conf = nconf;
14174fd4626Shenning 	setup_listeners(se, conf, &listener_cnt);
142914fd659Shenning 
143914fd659Shenning 	if (setgroups(1, &pw->pw_gid) ||
14452da46bbSdjm 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
14552da46bbSdjm 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
146914fd659Shenning 		fatal("can't drop privileges");
147914fd659Shenning 
148914fd659Shenning 	endservent();
149914fd659Shenning 
150a257dd04Sreyk 	/* The ntp process will want to open NTP client sockets -> "inet" */
151a257dd04Sreyk 	if (pledge("stdio inet", NULL) == -1)
15213e678ecSderaadt 		err(1, "pledge");
15313e678ecSderaadt 
154914fd659Shenning 	signal(SIGTERM, ntp_sighdlr);
155914fd659Shenning 	signal(SIGINT, ntp_sighdlr);
156914fd659Shenning 	signal(SIGPIPE, SIG_IGN);
157e69e88aaShenning 	signal(SIGHUP, SIG_IGN);
158a257dd04Sreyk 	signal(SIGCHLD, SIG_DFL);
159914fd659Shenning 
16038da1314Shenning 	if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
16138da1314Shenning 		fatal(NULL);
162*f1b790a5Sclaudio 	if (imsgbuf_init(ibuf_main, PARENT_SOCK_FILENO) == -1)
163*f1b790a5Sclaudio 		fatal(NULL);
1645f5af31aShenning 	if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL)
1655f5af31aShenning 		fatal(NULL);
166*f1b790a5Sclaudio 	if (imsgbuf_init(ibuf_dns, pipe_dns[0]) == -1)
167*f1b790a5Sclaudio 		fatal(NULL);
168914fd659Shenning 
169bc58a738Sreyk 	constraint_cnt = 0;
170bc58a738Sreyk 	conf->constraint_median = 0;
171bc58a738Sreyk 	conf->constraint_last = getmonotime();
172bc58a738Sreyk 	TAILQ_FOREACH(cstr, &conf->constraints, entry)
173bc58a738Sreyk 		constraint_cnt += constraint_init(cstr);
174bc58a738Sreyk 
1759096d664Shenning 	TAILQ_FOREACH(p, &conf->ntp_peers, entry)
1769096d664Shenning 		client_peer_init(p);
1779096d664Shenning 
178842d7e97Sbcook 	memset(&conf->status, 0, sizeof(conf->status));
179164ca3f4Sotto 
1803f7e45deSotto 	conf->freq.num = 0;
181164ca3f4Sotto 	conf->freq.samples = 0;
182164ca3f4Sotto 	conf->freq.x = 0.0;
183164ca3f4Sotto 	conf->freq.xx = 0.0;
184164ca3f4Sotto 	conf->freq.xy = 0.0;
185164ca3f4Sotto 	conf->freq.y = 0.0;
186164ca3f4Sotto 	conf->freq.overall_offset = 0.0;
187164ca3f4Sotto 
188a24621cfSdtucker 	conf->status.synced = 0;
189a09080daShenning 	clock_getres(CLOCK_REALTIME, &tp);
19085d60af5Sdtucker 	b = 1000000000 / tp.tv_nsec;	/* convert to Hz */
191bf8cff5bSderaadt 	for (a = 0; b > 1; a--, b >>= 1)
192bf8cff5bSderaadt 		;
193a09080daShenning 	conf->status.precision = a;
19480f94c68Sdtucker 	conf->scale = 1;
195a09080daShenning 
19664c82965Sphessler 	TAILQ_INIT(&ctl_conns);
19796f46bd6Sotto 	sensor_init();
198dd4ec8aeShenning 
199914fd659Shenning 	log_info("ntp engine ready");
200914fd659Shenning 
20164c82965Sphessler 	ctl_cnt = 0;
20274fd4626Shenning 	peer_cnt = 0;
20374fd4626Shenning 	TAILQ_FOREACH(p, &conf->ntp_peers, entry)
20474fd4626Shenning 		peer_cnt++;
20574fd4626Shenning 
206914fd659Shenning 	while (ntp_quit == 0) {
207f4fb118eShenning 		if (peer_cnt > idx2peer_elms) {
208538d6a69Sderaadt 			if ((newp = reallocarray(idx2peer, peer_cnt,
2097ed8e17fSbcook 			    sizeof(*idx2peer))) == NULL) {
21074fd4626Shenning 				/* panic for now */
21174fd4626Shenning 				log_warn("could not resize idx2peer from %u -> "
212f4fb118eShenning 				    "%u entries", idx2peer_elms, peer_cnt);
21374fd4626Shenning 				fatalx("exiting");
21474fd4626Shenning 			}
21574fd4626Shenning 			idx2peer = newp;
216f4fb118eShenning 			idx2peer_elms = peer_cnt;
21774fd4626Shenning 		}
21874fd4626Shenning 
219bc58a738Sreyk 		new_cnt = PFD_MAX +
220a257dd04Sreyk 		    peer_cnt + listener_cnt + ctl_cnt;
221f4fb118eShenning 		if (new_cnt > pfd_elms) {
222538d6a69Sderaadt 			if ((newp = reallocarray(pfd, new_cnt,
2237ed8e17fSbcook 			    sizeof(*pfd))) == NULL) {
22474fd4626Shenning 				/* panic for now */
22574fd4626Shenning 				log_warn("could not resize pfd from %u -> "
226f4fb118eShenning 				    "%u entries", pfd_elms, new_cnt);
22774fd4626Shenning 				fatalx("exiting");
22874fd4626Shenning 			}
22974fd4626Shenning 			pfd = newp;
230f4fb118eShenning 			pfd_elms = new_cnt;
23174fd4626Shenning 		}
23274fd4626Shenning 
233842d7e97Sbcook 		memset(pfd, 0, sizeof(*pfd) * pfd_elms);
234842d7e97Sbcook 		memset(idx2peer, 0, sizeof(*idx2peer) * idx2peer_elms);
2351908d877Sotto 		nextaction = getmonotime() + 900;
23638da1314Shenning 		pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd;
237914fd659Shenning 		pfd[PFD_PIPE_MAIN].events = POLLIN;
2385f5af31aShenning 		pfd[PFD_PIPE_DNS].fd = ibuf_dns->fd;
2395f5af31aShenning 		pfd[PFD_PIPE_DNS].events = POLLIN;
24064c82965Sphessler 		pfd[PFD_SOCK_CTL].fd = fd_ctl;
24164c82965Sphessler 		pfd[PFD_SOCK_CTL].events = POLLIN;
242914fd659Shenning 
24361836557Shenning 		i = PFD_MAX;
244e7e6fe2dShenning 		TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
245e7e6fe2dShenning 			pfd[i].fd = la->fd;
246e7e6fe2dShenning 			pfd[i].events = POLLIN;
247e7e6fe2dShenning 			i++;
248e7e6fe2dShenning 		}
249e7e6fe2dShenning 
2509096d664Shenning 		idx_peers = i;
2510f8bb54dShenning 		sent_cnt = trial_cnt = 0;
2529096d664Shenning 		TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
253eb7f225fSotto 			if (!p->trusted && constraint_cnt &&
254eb7f225fSotto 			    conf->constraint_median == 0)
255bc58a738Sreyk 				continue;
256bc58a738Sreyk 
2572fae8c34Shenning 			if (p->next > 0 && p->next <= getmonotime()) {
2586be00f15Shenning 				if (p->state > STATE_DNS_INPROGRESS)
2590f8bb54dShenning 					trial_cnt++;
2606d7ece66Shenning 				if (client_query(p) == 0)
2616d7ece66Shenning 					sent_cnt++;
2620f8bb54dShenning 			}
2632fae8c34Shenning 			if (p->deadline > 0 && p->deadline <= getmonotime()) {
264a7c009afSckuethe 				timeout = 300;
2651f5acb8eSdtucker 				log_debug("no reply from %s received in time, "
2668745f5cfSotto 				    "next query %ds", log_ntp_addr( p->addr),
2678745f5cfSotto 				    timeout);
26884e7b05bShenning 				if (p->trustlevel >= TRUSTLEVEL_BADPEER &&
2695ba7fd73Shenning 				    (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER)
27084e7b05bShenning 					log_info("peer %s now invalid",
2718745f5cfSotto 					    log_ntp_addr(p->addr));
2726a6b450eSotto 				if (client_nextaddr(p) == 1) {
2736a6b450eSotto 					peer_addr_head_clear(p);
2743801c0acShenning 					client_nextaddr(p);
2756a6b450eSotto 				}
2761f5acb8eSdtucker 				set_next(p, timeout);
27784e7b05bShenning 			}
278bc207761Smpf 			if (p->senderrors > MAX_SEND_ERRORS) {
279bc207761Smpf 				log_debug("failed to send query to %s, "
2808745f5cfSotto 				    "next query %ds", log_ntp_addr(p->addr),
281bc207761Smpf 				    INTERVAL_QUERY_PATHETIC);
282bc207761Smpf 				p->senderrors = 0;
2836a6b450eSotto 				if (client_nextaddr(p) == 1) {
2846a6b450eSotto 					peer_addr_head_clear(p);
285bc207761Smpf 					client_nextaddr(p);
2866a6b450eSotto 				}
287bc207761Smpf 				set_next(p, INTERVAL_QUERY_PATHETIC);
288bc207761Smpf 			}
289bc207761Smpf 			if (p->next > 0 && p->next < nextaction)
290bc207761Smpf 				nextaction = p->next;
291bc207761Smpf 			if (p->deadline > 0 && p->deadline < nextaction)
292bc207761Smpf 				nextaction = p->deadline;
29384e7b05bShenning 
2947f72000eShenning 			if (p->state == STATE_QUERY_SENT &&
29520db0646Sotto 			    p->query.fd != -1) {
29620db0646Sotto 				pfd[i].fd = p->query.fd;
2979096d664Shenning 				pfd[i].events = POLLIN;
2989096d664Shenning 				idx2peer[i - idx_peers] = p;
2999096d664Shenning 				i++;
3009096d664Shenning 			}
3019096d664Shenning 		}
30264c82965Sphessler 		idx_clients = i;
3039096d664Shenning 
304fe63d0d1Sotto 		if (!TAILQ_EMPTY(&conf->ntp_conf_sensors) &&
3051511e2d1Sotto 		    (conf->trusted_sensors || constraint_cnt == 0 ||
3061511e2d1Sotto 		    conf->constraint_median != 0)) {
307f21b5a67Shenning 			if (last_sensor_scan == 0 ||
308bc8916e4Smillert 			    last_sensor_scan + SENSOR_SCAN_INTERVAL <= getmonotime()) {
30908e6c7daSckuethe 				sensors_cnt = sensor_scan();
3102fae8c34Shenning 				last_sensor_scan = getmonotime();
3118ccfafd5Shenning 			}
312b5ec6406Sderaadt 			if (sensors_cnt == 0 &&
31308e6c7daSckuethe 			    nextaction > last_sensor_scan + SENSOR_SCAN_INTERVAL)
31408e6c7daSckuethe 				nextaction = last_sensor_scan + SENSOR_SCAN_INTERVAL;
315dd4ec8aeShenning 			sensors_cnt = 0;
316dd4ec8aeShenning 			TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
317c72e2a3dSckuethe 				if (conf->settime && s->offsets[0].offset)
31871ba36b6Sotto 					priv_settime(s->offsets[0].offset, NULL);
319dd4ec8aeShenning 				sensors_cnt++;
320dd4ec8aeShenning 				if (s->next > 0 && s->next < nextaction)
321dd4ec8aeShenning 					nextaction = s->next;
322dd4ec8aeShenning 			}
323b5ec6406Sderaadt 		}
324dd4ec8aeShenning 
325ba4e9e2aShenning 		if (conf->settime &&
326dd4ec8aeShenning 		    ((trial_cnt > 0 && sent_cnt == 0) ||
327dd4ec8aeShenning 		    (peer_cnt == 0 && sensors_cnt == 0)))
32871ba36b6Sotto 			priv_settime(0, "no valid peers configured");
3296d7ece66Shenning 
33014c44c9eSotto 		clear_cdns = 1;
331e6588cf8Sotto 		TAILQ_FOREACH(cstr, &conf->constraints, entry) {
33214c44c9eSotto 			constraint_query(cstr, conf->status.synced);
33314c44c9eSotto 			if (cstr->state <= STATE_QUERY_SENT)
33414c44c9eSotto 				clear_cdns = 0;
335e6588cf8Sotto 		}
336e6588cf8Sotto 
33731be28caSclaudio 		if (imsgbuf_queuelen(ibuf_main) > 0)
338138ae74fShenning 			pfd[PFD_PIPE_MAIN].events |= POLLOUT;
33931be28caSclaudio 		if (imsgbuf_queuelen(ibuf_dns) > 0)
3405f5af31aShenning 			pfd[PFD_PIPE_DNS].events |= POLLOUT;
341138ae74fShenning 
34264c82965Sphessler 		TAILQ_FOREACH(cc, &ctl_conns, entry) {
34364c82965Sphessler 			pfd[i].fd = cc->ibuf.fd;
34464c82965Sphessler 			pfd[i].events = POLLIN;
34531be28caSclaudio 			if (imsgbuf_queuelen(&cc->ibuf) > 0)
34664c82965Sphessler 				pfd[i].events |= POLLOUT;
34764c82965Sphessler 			i++;
34864c82965Sphessler 		}
349bc58a738Sreyk 		ctls = i;
35064c82965Sphessler 
351bc58a738Sreyk 		now = getmonotime();
35214c44c9eSotto 		if (conf->constraint_median == 0 && clear_cdns &&
35314c44c9eSotto 		    now - last_cdns_reset > CONSTRAINT_SCAN_INTERVAL) {
35414c44c9eSotto 			log_debug("Reset constraint info");
35514c44c9eSotto 			constraint_reset();
35614c44c9eSotto 			last_cdns_reset = now;
35714c44c9eSotto 			nextaction = now + CONSTRAINT_RETRY_INTERVAL;
35814c44c9eSotto 		}
359bc58a738Sreyk 		timeout = nextaction - now;
3609096d664Shenning 		if (timeout < 0)
3619096d664Shenning 			timeout = 0;
3629096d664Shenning 
363fe63d0d1Sotto 		if ((nfds = poll(pfd, i, timeout ? timeout * 1000 : 1)) == -1)
364914fd659Shenning 			if (errno != EINTR) {
365914fd659Shenning 				log_warn("poll error");
366914fd659Shenning 				ntp_quit = 1;
367914fd659Shenning 			}
368138ae74fShenning 
369914fd659Shenning 		if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT))
370dd7efffeSclaudio 			if (imsgbuf_write(ibuf_main) == -1) {
371914fd659Shenning 				log_warn("pipe write error (to parent)");
372914fd659Shenning 				ntp_quit = 1;
373914fd659Shenning 			}
374914fd659Shenning 
37502135bd8Sdtucker 		if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
376914fd659Shenning 			nfds--;
3779079b9e1Sphessler 			if (ntp_dispatch_imsg() == -1) {
378b4844efeSotto 				log_debug("pipe read error (from main)");
379914fd659Shenning 				ntp_quit = 1;
380914fd659Shenning 			}
3819079b9e1Sphessler 		}
382914fd659Shenning 
3835f5af31aShenning 		if (nfds > 0 && (pfd[PFD_PIPE_DNS].revents & POLLOUT))
384dd7efffeSclaudio 			if (imsgbuf_write(ibuf_dns) == -1) {
3855f5af31aShenning 				log_warn("pipe write error (to dns engine)");
3865f5af31aShenning 				ntp_quit = 1;
3875f5af31aShenning 			}
3885f5af31aShenning 
3895f5af31aShenning 		if (nfds > 0 && pfd[PFD_PIPE_DNS].revents & (POLLIN|POLLERR)) {
3905f5af31aShenning 			nfds--;
3919079b9e1Sphessler 			if (ntp_dispatch_imsg_dns() == -1) {
392b4844efeSotto 				log_warn("pipe read error (from dns engine)");
3935f5af31aShenning 				ntp_quit = 1;
3945f5af31aShenning 			}
3959079b9e1Sphessler 		}
3965f5af31aShenning 
39764c82965Sphessler 		if (nfds > 0 && pfd[PFD_SOCK_CTL].revents & (POLLIN|POLLERR)) {
39864c82965Sphessler 			nfds--;
39964c82965Sphessler 			ctl_cnt += control_accept(fd_ctl);
40064c82965Sphessler 		}
40164c82965Sphessler 
40201955529Sclaudio 		for (j = PFD_MAX; nfds > 0 && j < idx_peers; j++)
40302135bd8Sdtucker 			if (pfd[j].revents & (POLLIN|POLLERR)) {
404914fd659Shenning 				nfds--;
4059079b9e1Sphessler 				if (server_dispatch(pfd[j].fd, conf) == -1) {
4069079b9e1Sphessler 					log_warn("pipe write error (conf)");
40774a91231Shenning 					ntp_quit = 1;
40874a91231Shenning 				}
4099079b9e1Sphessler 			}
4109096d664Shenning 
41164c82965Sphessler 		for (; nfds > 0 && j < idx_clients; j++) {
41202135bd8Sdtucker 			if (pfd[j].revents & (POLLIN|POLLERR)) {
413418ac0aeSotto 				struct ntp_peer *pp = idx2peer[j - idx_peers];
414418ac0aeSotto 
4159096d664Shenning 				nfds--;
416418ac0aeSotto 				switch (client_dispatch(pp, conf->settime,
417418ac0aeSotto 				    conf->automatic)) {
418418ac0aeSotto 				case -1:
419418ac0aeSotto 					log_debug("no reply from %s "
4208745f5cfSotto 					    "received", log_ntp_addr(pp->addr));
421418ac0aeSotto 					if (pp->trustlevel >=
422418ac0aeSotto 					    TRUSTLEVEL_BADPEER &&
423418ac0aeSotto 					    (pp->trustlevel /= 2) <
424418ac0aeSotto 					    TRUSTLEVEL_BADPEER)
425418ac0aeSotto 						log_info("peer %s now invalid",
4268745f5cfSotto 						    log_ntp_addr(pp->addr));
427418ac0aeSotto 					break;
428418ac0aeSotto 				case 0: /* invalid replies are ignored */
429418ac0aeSotto 					break;
430418ac0aeSotto 				case 1:
431c72d6e80Sotto 					last_action = now;
432418ac0aeSotto 					break;
4339096d664Shenning 				}
43464c82965Sphessler 			}
4359079b9e1Sphessler 		}
43664c82965Sphessler 
437bc58a738Sreyk 		for (; nfds > 0 && j < ctls; j++) {
43864c82965Sphessler 			nfds -= control_dispatch_msg(&pfd[j], &ctl_cnt);
439bc58a738Sreyk 		}
440bc58a738Sreyk 
441dd4ec8aeShenning 		for (s = TAILQ_FIRST(&conf->ntp_sensors); s != NULL;
442dd4ec8aeShenning 		    s = next_s) {
443dd4ec8aeShenning 			next_s = TAILQ_NEXT(s, entry);
444c72d6e80Sotto 			if (s->next <= now) {
445c72d6e80Sotto 				last_action = now;
4467ff9247fShenning 				sensor_query(s);
447dd4ec8aeShenning 			}
448914fd659Shenning 		}
449914fd659Shenning 
450c72d6e80Sotto 		/*
451c72d6e80Sotto 		 * Compute maximum of scale_interval(INTERVAL_QUERY_NORMAL),
452c72d6e80Sotto 		 * if we did not process a time message for three times that
453c72d6e80Sotto 		 * interval, stop advertising we're synced.
454c72d6e80Sotto 		 */
455c72d6e80Sotto 		interval = INTERVAL_QUERY_NORMAL * conf->scale;
456c72d6e80Sotto 		interval += SCALE_INTERVAL(interval) - 1;
457c72d6e80Sotto 		if (conf->status.synced && last_action + 3 * interval < now) {
458418ac0aeSotto 			log_info("clock is now unsynced due to lack of replies");
459c72d6e80Sotto 			conf->status.synced = 0;
460c72d6e80Sotto 			conf->scale = 1;
461c72d6e80Sotto 			priv_dns(IMSG_UNSYNCED, NULL, 0);
462c72d6e80Sotto 		}
463c72d6e80Sotto 	}
464c72d6e80Sotto 
465dd7efffeSclaudio 	imsgbuf_write(ibuf_main);
4669cbf9e90Sclaudio 	imsgbuf_clear(ibuf_main);
46738da1314Shenning 	free(ibuf_main);
468dd7efffeSclaudio 	imsgbuf_write(ibuf_dns);
4699cbf9e90Sclaudio 	imsgbuf_clear(ibuf_dns);
4705f5af31aShenning 	free(ibuf_dns);
471914fd659Shenning 
472914fd659Shenning 	log_info("ntp engine exiting");
4734e840e7aSrzalamena 	exit(0);
474914fd659Shenning }
475914fd659Shenning 
476914fd659Shenning int
477914fd659Shenning ntp_dispatch_imsg(void)
478914fd659Shenning {
479914fd659Shenning 	struct imsg		 imsg;
480914fd659Shenning 	int			 n;
481914fd659Shenning 
482f6bd242eSclaudio 	if (imsgbuf_read(ibuf_main) != 1)
483914fd659Shenning 		return (-1);
484914fd659Shenning 
485914fd659Shenning 	for (;;) {
48638da1314Shenning 		if ((n = imsg_get(ibuf_main, &imsg)) == -1)
487914fd659Shenning 			return (-1);
488914fd659Shenning 
489914fd659Shenning 		if (n == 0)
490914fd659Shenning 			break;
491914fd659Shenning 
492914fd659Shenning 		switch (imsg.hdr.type) {
4937de07ab1Sdtucker 		case IMSG_ADJTIME:
4947de07ab1Sdtucker 			memcpy(&n, imsg.data, sizeof(n));
495a24621cfSdtucker 			if (n == 1 && !conf->status.synced) {
4967de07ab1Sdtucker 				log_info("clock is now synced");
497a24621cfSdtucker 				conf->status.synced = 1;
498c9addb91Sotto 				priv_dns(IMSG_SYNCED, NULL, 0);
499c7e8e3a2Sotto 				constraint_reset();
500a24621cfSdtucker 			} else if (n == 0 && conf->status.synced) {
5017de07ab1Sdtucker 				log_info("clock is now unsynced");
502a24621cfSdtucker 				conf->status.synced = 0;
503c9addb91Sotto 				priv_dns(IMSG_UNSYNCED, NULL, 0);
5047de07ab1Sdtucker 			}
5057de07ab1Sdtucker 			break;
506a257dd04Sreyk 		case IMSG_CONSTRAINT_RESULT:
507a257dd04Sreyk 			constraint_msg_result(imsg.hdr.peerid,
508a257dd04Sreyk 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
509a257dd04Sreyk 			break;
510a257dd04Sreyk 		case IMSG_CONSTRAINT_CLOSE:
511a257dd04Sreyk 			constraint_msg_close(imsg.hdr.peerid,
512a257dd04Sreyk 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
513a257dd04Sreyk 			break;
5145f5af31aShenning 		default:
5155f5af31aShenning 			break;
5165f5af31aShenning 		}
5175f5af31aShenning 		imsg_free(&imsg);
5185f5af31aShenning 	}
5195f5af31aShenning 	return (0);
5205f5af31aShenning }
5215f5af31aShenning 
5225f5af31aShenning int
5236a6b450eSotto inpool(struct sockaddr_storage *a,
5246a6b450eSotto     struct sockaddr_storage old[MAX_SERVERS_DNS], size_t n)
5256a6b450eSotto {
5266a6b450eSotto 	size_t i;
5276a6b450eSotto 
5286a6b450eSotto 	for (i = 0; i < n; i++) {
5296a6b450eSotto 		if (a->ss_family != old[i].ss_family)
5306a6b450eSotto 			continue;
5316a6b450eSotto 		if (a->ss_family == AF_INET) {
5326a6b450eSotto 			if (((struct sockaddr_in *)a)->sin_addr.s_addr ==
5336a6b450eSotto 			    ((struct sockaddr_in *)&old[i])->sin_addr.s_addr)
5346a6b450eSotto 				return 1;
5356a6b450eSotto 		} else if (memcmp(&((struct sockaddr_in6 *)a)->sin6_addr,
5366a6b450eSotto 		    &((struct sockaddr_in6 *)&old[i])->sin6_addr,
5372df6d81dSjsg 		    sizeof(struct in6_addr)) == 0) {
5386a6b450eSotto 			return 1;
5396a6b450eSotto 		}
5406a6b450eSotto 	}
5416a6b450eSotto 	return 0;
5426a6b450eSotto }
5436a6b450eSotto 
5446a6b450eSotto int
5455f5af31aShenning ntp_dispatch_imsg_dns(void)
5465f5af31aShenning {
5475f5af31aShenning 	struct imsg		 imsg;
5486a6b450eSotto 	struct sockaddr_storage	 existing[MAX_SERVERS_DNS];
5493ee58c44Sotto 	struct ntp_peer		*peer, *npeer, *tmp;
5505f5af31aShenning 	u_int16_t		 dlen;
5515f5af31aShenning 	u_char			*p;
5525f5af31aShenning 	struct ntp_addr		*h;
5536a6b450eSotto 	size_t			 addrcount, peercount;
5545f5af31aShenning 	int			 n;
5555f5af31aShenning 
556f6bd242eSclaudio 	if (imsgbuf_read(ibuf_dns) != 1)
5575f5af31aShenning 		return (-1);
5585f5af31aShenning 
5595f5af31aShenning 	for (;;) {
5605f5af31aShenning 		if ((n = imsg_get(ibuf_dns, &imsg)) == -1)
5615f5af31aShenning 			return (-1);
5625f5af31aShenning 
5635f5af31aShenning 		if (n == 0)
5645f5af31aShenning 			break;
5655f5af31aShenning 
5665f5af31aShenning 		switch (imsg.hdr.type) {
5675c35bc7eShenning 		case IMSG_HOST_DNS:
5685c35bc7eShenning 			TAILQ_FOREACH(peer, &conf->ntp_peers, entry)
5695c35bc7eShenning 				if (peer->id == imsg.hdr.peerid)
5705c35bc7eShenning 					break;
571676a2b5fShenning 			if (peer == NULL) {
572676a2b5fShenning 				log_warnx("IMSG_HOST_DNS with invalid peerID");
573676a2b5fShenning 				break;
574676a2b5fShenning 			}
5755c35bc7eShenning 			if (peer->addr != NULL) {
5765c35bc7eShenning 				log_warnx("IMSG_HOST_DNS but addr != NULL!");
5775c35bc7eShenning 				break;
5785c35bc7eShenning 			}
5796be00f15Shenning 
5803ee58c44Sotto 			if (peer->addr_head.pool) {
5816a6b450eSotto 				n = 0;
5826a6b450eSotto 				peercount = 0;
5836a6b450eSotto 
5843ee58c44Sotto 				TAILQ_FOREACH_SAFE(npeer, &conf->ntp_peers,
5853ee58c44Sotto 				    entry, tmp) {
586c7e8e3a2Sotto 					if (npeer->addr_head.pool !=
587c7e8e3a2Sotto 					    peer->addr_head.pool)
5886a6b450eSotto 						continue;
5896a6b450eSotto 					peercount++;
5903ee58c44Sotto 					if (npeer->id == peer->id)
5913ee58c44Sotto 						continue;
5926a6b450eSotto 					if (npeer->addr != NULL)
5936a6b450eSotto 						existing[n++] = npeer->addr->ss;
5943ee58c44Sotto 				}
5953ee58c44Sotto 			}
5963ee58c44Sotto 
5975c35bc7eShenning 			dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
5986be00f15Shenning 			if (dlen == 0) {	/* no data -> temp error */
599150da408Sderaadt 				log_debug("DNS lookup tempfail");
6006be00f15Shenning 				peer->state = STATE_DNS_TEMPFAIL;
6016a6b450eSotto 				if (conf->tmpfail++ == TRIES_AUTO_DNSFAIL)
60271ba36b6Sotto 					priv_settime(0, "of dns failures");
6036be00f15Shenning 				break;
6046be00f15Shenning 			}
6056be00f15Shenning 
6065c35bc7eShenning 			p = (u_char *)imsg.data;
6076a6b450eSotto 			addrcount = dlen / (sizeof(struct sockaddr_storage) +
6086a6b450eSotto 			    sizeof(int));
6096a6b450eSotto 
610b98b0a5cSotto 			while (dlen >= sizeof(struct sockaddr_storage) +
611b98b0a5cSotto 			    sizeof(int)) {
6125c35bc7eShenning 				if ((h = calloc(1, sizeof(struct ntp_addr))) ==
6135c35bc7eShenning 				    NULL)
6145c35bc7eShenning 					fatal(NULL);
6155c35bc7eShenning 				memcpy(&h->ss, p, sizeof(h->ss));
6165c35bc7eShenning 				p += sizeof(h->ss);
6175c35bc7eShenning 				dlen -= sizeof(h->ss);
618b98b0a5cSotto 				memcpy(&h->notauth, p, sizeof(int));
619b98b0a5cSotto 				p += sizeof(int);
620b98b0a5cSotto 				dlen -= sizeof(int);
6215c35bc7eShenning 				if (peer->addr_head.pool) {
6226a6b450eSotto 					if (peercount > addrcount) {
6236a6b450eSotto 						free(h);
6246a6b450eSotto 						continue;
6256a6b450eSotto 					}
6266a6b450eSotto 					if (inpool(&h->ss, existing,
6276a6b450eSotto 					    n)) {
6286a6b450eSotto 						free(h);
6296a6b450eSotto 						continue;
6306a6b450eSotto 					}
6316a6b450eSotto 					log_debug("Adding address %s to %s",
6328745f5cfSotto 					    log_ntp_addr(h), peer->addr_head.name);
6335c35bc7eShenning 					npeer = new_peer();
63404b6053fSotto 					npeer->weight = peer->weight;
6353e0a6a28Sbenno 					npeer->query_addr4 = peer->query_addr4;
6363e0a6a28Sbenno 					npeer->query_addr6 = peer->query_addr6;
6375c35bc7eShenning 					h->next = NULL;
6385c35bc7eShenning 					npeer->addr = h;
6395c35bc7eShenning 					npeer->addr_head.a = h;
640804c161bSotto 					npeer->addr_head.name =
641804c161bSotto 					    peer->addr_head.name;
642c7e8e3a2Sotto 					npeer->addr_head.pool =
643c7e8e3a2Sotto 					    peer->addr_head.pool;
6445c35bc7eShenning 					client_peer_init(npeer);
6456be00f15Shenning 					npeer->state = STATE_DNS_DONE;
64699c99903Shenning 					peer_add(npeer);
6476a6b450eSotto 					peercount++;
6485c35bc7eShenning 				} else {
6495c35bc7eShenning 					h->next = peer->addr;
6505c35bc7eShenning 					peer->addr = h;
6515c35bc7eShenning 					peer->addr_head.a = peer->addr;
6526be00f15Shenning 					peer->state = STATE_DNS_DONE;
6535c35bc7eShenning 				}
6545c35bc7eShenning 			}
6555c35bc7eShenning 			if (dlen != 0)
656fbc4296bShenning 				fatalx("IMSG_HOST_DNS: dlen != 0");
65799c99903Shenning 			if (peer->addr_head.pool)
65899c99903Shenning 				peer_remove(peer);
65999c99903Shenning 			else
6605c35bc7eShenning 				client_addr_init(peer);
6615c35bc7eShenning 			break;
662b775b3eeSreyk 		case IMSG_CONSTRAINT_DNS:
663a257dd04Sreyk 			constraint_msg_dns(imsg.hdr.peerid,
664b775b3eeSreyk 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
665b775b3eeSreyk 			break;
66671ba36b6Sotto 		case IMSG_PROBE_ROOT:
66771ba36b6Sotto 			dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
66871ba36b6Sotto 			if (dlen != sizeof(int))
66971ba36b6Sotto 				fatalx("IMSG_PROBE_ROOT");
67071ba36b6Sotto 			memcpy(&n, imsg.data, sizeof(int));
67171ba36b6Sotto 			if (n < 0)
67271ba36b6Sotto 				priv_settime(0, "dns probe failed");
67371ba36b6Sotto 			break;
674914fd659Shenning 		default:
675914fd659Shenning 			break;
676914fd659Shenning 		}
677914fd659Shenning 		imsg_free(&imsg);
678914fd659Shenning 	}
679914fd659Shenning 	return (0);
680914fd659Shenning }
681914fd659Shenning 
682138ae74fShenning void
68399c99903Shenning peer_add(struct ntp_peer *p)
68499c99903Shenning {
68599c99903Shenning 	TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
68699c99903Shenning 	peer_cnt++;
68799c99903Shenning }
68899c99903Shenning 
68999c99903Shenning void
69099c99903Shenning peer_remove(struct ntp_peer *p)
69199c99903Shenning {
69299c99903Shenning 	TAILQ_REMOVE(&conf->ntp_peers, p, entry);
69399c99903Shenning 	free(p);
69499c99903Shenning 	peer_cnt--;
69599c99903Shenning }
69699c99903Shenning 
6973ee58c44Sotto void
6983ee58c44Sotto peer_addr_head_clear(struct ntp_peer *p)
6993ee58c44Sotto {
700c7e8e3a2Sotto 	host_dns_free(p->addr_head.a);
7013ee58c44Sotto 	p->addr_head.a = NULL;
7023ee58c44Sotto 	p->addr = NULL;
7033ee58c44Sotto }
7043ee58c44Sotto 
705164ca3f4Sotto static void
706164ca3f4Sotto priv_adjfreq(double offset)
707164ca3f4Sotto {
708164ca3f4Sotto 	double curtime, freq;
709164ca3f4Sotto 
710fe88e4ccSckuethe 	if (!conf->status.synced){
711fe88e4ccSckuethe 		conf->freq.samples = 0;
712164ca3f4Sotto 		return;
713fe88e4ccSckuethe 	}
714164ca3f4Sotto 
715164ca3f4Sotto 	conf->freq.samples++;
716164ca3f4Sotto 
717164ca3f4Sotto 	if (conf->freq.samples <= 0)
718164ca3f4Sotto 		return;
719164ca3f4Sotto 
720164ca3f4Sotto 	conf->freq.overall_offset += offset;
721164ca3f4Sotto 	offset = conf->freq.overall_offset;
722164ca3f4Sotto 
723164ca3f4Sotto 	curtime = gettime_corrected();
724164ca3f4Sotto 	conf->freq.xy += offset * curtime;
725164ca3f4Sotto 	conf->freq.x += curtime;
726164ca3f4Sotto 	conf->freq.y += offset;
727164ca3f4Sotto 	conf->freq.xx += curtime * curtime;
728164ca3f4Sotto 
729164ca3f4Sotto 	if (conf->freq.samples % FREQUENCY_SAMPLES != 0)
730164ca3f4Sotto 		return;
731164ca3f4Sotto 
732164ca3f4Sotto 	freq =
733164ca3f4Sotto 	    (conf->freq.xy - conf->freq.x * conf->freq.y / conf->freq.samples)
734164ca3f4Sotto 	    /
735164ca3f4Sotto 	    (conf->freq.xx - conf->freq.x * conf->freq.x / conf->freq.samples);
736164ca3f4Sotto 
737164ca3f4Sotto 	if (freq > MAX_FREQUENCY_ADJUST)
738164ca3f4Sotto 		freq = MAX_FREQUENCY_ADJUST;
739164ca3f4Sotto 	else if (freq < -MAX_FREQUENCY_ADJUST)
740164ca3f4Sotto 		freq = -MAX_FREQUENCY_ADJUST;
741164ca3f4Sotto 
74296e77fb8Spyr 	imsg_compose(ibuf_main, IMSG_ADJFREQ, 0, 0, -1, &freq, sizeof(freq));
74361fdcd24Sckuethe 	conf->filters |= FILTER_ADJFREQ;
744164ca3f4Sotto 	conf->freq.xy = 0.0;
745164ca3f4Sotto 	conf->freq.x = 0.0;
746164ca3f4Sotto 	conf->freq.y = 0.0;
747164ca3f4Sotto 	conf->freq.xx = 0.0;
748164ca3f4Sotto 	conf->freq.samples = 0;
749164ca3f4Sotto 	conf->freq.overall_offset = 0.0;
7503f7e45deSotto 	conf->freq.num++;
751164ca3f4Sotto }
752164ca3f4Sotto 
753582f7186Sotto int
754d81463d2Shenning priv_adjtime(void)
755138ae74fShenning {
756138ae74fShenning 	struct ntp_peer		 *p;
757dd4ec8aeShenning 	struct ntp_sensor	 *s;
75849532891Shenning 	int			  offset_cnt = 0, i = 0, j;
75925ce145eShenning 	struct ntp_offset	**offsets;
760f5d4a9eeShenning 	double			  offset_median;
761138ae74fShenning 
762d1204a71Salexander 	TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
763d1204a71Salexander 		if (p->trustlevel < TRUSTLEVEL_BADPEER)
764d1204a71Salexander 			continue;
765bf22f0ffShenning 		if (!p->update.good)
766582f7186Sotto 			return (1);
76749532891Shenning 		offset_cnt += p->weight;
7685ba7fd73Shenning 	}
769138ae74fShenning 
770dd4ec8aeShenning 	TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
771dd4ec8aeShenning 		if (!s->update.good)
772dd4ec8aeShenning 			continue;
773caa29b08Shenning 		offset_cnt += s->weight;
774dd4ec8aeShenning 	}
775dd4ec8aeShenning 
776582f7186Sotto 	if (offset_cnt == 0)
777582f7186Sotto 		return (1);
778582f7186Sotto 
77925ce145eShenning 	if ((offsets = calloc(offset_cnt, sizeof(struct ntp_offset *))) == NULL)
780c58354a7Shenning 		fatal("calloc priv_adjtime");
781f5d4a9eeShenning 
782f5d4a9eeShenning 	TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
783f5d4a9eeShenning 		if (p->trustlevel < TRUSTLEVEL_BADPEER)
784f5d4a9eeShenning 			continue;
78549532891Shenning 		for (j = 0; j < p->weight; j++)
78625ce145eShenning 			offsets[i++] = &p->update;
787f5d4a9eeShenning 	}
788f5d4a9eeShenning 
789dd4ec8aeShenning 	TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
790dd4ec8aeShenning 		if (!s->update.good)
791dd4ec8aeShenning 			continue;
79249532891Shenning 		for (j = 0; j < s->weight; j++)
793dd4ec8aeShenning 			offsets[i++] = &s->update;
794dd4ec8aeShenning 	}
795dd4ec8aeShenning 
79625ce145eShenning 	qsort(offsets, offset_cnt, sizeof(struct ntp_offset *), offset_compare);
797f5d4a9eeShenning 
798a1cf5cc5Sotto 	i = offset_cnt / 2;
799b737adbaSphessler 	if (offset_cnt % 2 == 0)
800b737adbaSphessler 		if (offsets[i - 1]->delay < offsets[i]->delay)
801b737adbaSphessler 			i -= 1;
802a1cf5cc5Sotto 	offset_median = offsets[i]->offset;
803a1cf5cc5Sotto 	conf->status.rootdelay = offsets[i]->delay;
804a1cf5cc5Sotto 	conf->status.stratum = offsets[i]->status.stratum;
805a1cf5cc5Sotto 	conf->status.leap = offsets[i]->status.leap;
806f5d4a9eeShenning 
80796e77fb8Spyr 	imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0, -1,
808138ae74fShenning 	    &offset_median, sizeof(offset_median));
809d1204a71Salexander 
810164ca3f4Sotto 	priv_adjfreq(offset_median);
811164ca3f4Sotto 
812d1204a71Salexander 	conf->status.reftime = gettime();
813834f51deShenning 	conf->status.stratum++;	/* one more than selected peer */
814417b8dd7Shenning 	if (conf->status.stratum > NTP_MAXSTRATUM)
815417b8dd7Shenning 		conf->status.stratum = NTP_MAXSTRATUM;
8167b668c67Sdtucker 	update_scale(offset_median);
817fb68be98Shenning 
818a1cf5cc5Sotto 	conf->status.refid = offsets[i]->status.send_refid;
819bf22f0ffShenning 
82025ce145eShenning 	free(offsets);
821f5d4a9eeShenning 
8224e6294c2Sotto 	TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
8234e6294c2Sotto 		for (i = 0; i < OFFSET_ARRAY_SIZE; i++)
8244e6294c2Sotto 			p->reply[i].offset -= offset_median;
825bf22f0ffShenning 		p->update.good = 0;
8264e6294c2Sotto 	}
827f45699e7Sotto 	TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
828f45699e7Sotto 		for (i = 0; i < SENSOR_OFFSETS; i++)
829f45699e7Sotto 			s->offsets[i].offset -= offset_median;
830f45699e7Sotto 		s->update.offset -= offset_median;
831f45699e7Sotto 	}
832582f7186Sotto 
833582f7186Sotto 	return (0);
834359b1f1aShenning }
8355c35bc7eShenning 
836f5d4a9eeShenning int
837f5d4a9eeShenning offset_compare(const void *aa, const void *bb)
838f5d4a9eeShenning {
83925ce145eShenning 	const struct ntp_offset * const *a;
84025ce145eShenning 	const struct ntp_offset * const *b;
841f5d4a9eeShenning 
842f5d4a9eeShenning 	a = aa;
843f5d4a9eeShenning 	b = bb;
844f5d4a9eeShenning 
84525ce145eShenning 	if ((*a)->offset < (*b)->offset)
846f5d4a9eeShenning 		return (-1);
84725ce145eShenning 	else if ((*a)->offset > (*b)->offset)
848f5d4a9eeShenning 		return (1);
849f5d4a9eeShenning 	else
850f5d4a9eeShenning 		return (0);
851f5d4a9eeShenning }
852f5d4a9eeShenning 
8535c35bc7eShenning void
85471ba36b6Sotto priv_settime(double offset, char *msg)
85510da828bShenning {
85671ba36b6Sotto 	if (offset == 0)
85771ba36b6Sotto 		log_info("cancel settime because %s", msg);
85896e77fb8Spyr 	imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, -1,
85996e77fb8Spyr 	    &offset, sizeof(offset));
86010da828bShenning 	conf->settime = 0;
86110da828bShenning }
86210da828bShenning 
86310da828bShenning void
864b775b3eeSreyk priv_dns(int cmd, char *name, u_int32_t peerid)
8655c35bc7eShenning {
866c9addb91Sotto 	u_int16_t	dlen = 0;
8675c35bc7eShenning 
868c9addb91Sotto 	if (name != NULL)
8695c35bc7eShenning 		dlen = strlen(name) + 1;
870b775b3eeSreyk 	imsg_compose(ibuf_dns, cmd, peerid, 0, -1, name, dlen);
8715c35bc7eShenning }
8727b668c67Sdtucker 
8737b668c67Sdtucker void
8747b668c67Sdtucker update_scale(double offset)
8757b668c67Sdtucker {
8764e6294c2Sotto 	offset += getoffset();
8777b668c67Sdtucker 	if (offset < 0)
8787b668c67Sdtucker 		offset = -offset;
8797b668c67Sdtucker 
8803f7e45deSotto 	if (offset > QSCALE_OFF_MAX || !conf->status.synced ||
8813f7e45deSotto 	    conf->freq.num < 3)
88280f94c68Sdtucker 		conf->scale = 1;
8837b668c67Sdtucker 	else if (offset < QSCALE_OFF_MIN)
88480f94c68Sdtucker 		conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
8857b668c67Sdtucker 	else
88680f94c68Sdtucker 		conf->scale = QSCALE_OFF_MAX / offset;
8877b668c67Sdtucker }
8887b668c67Sdtucker 
8897b668c67Sdtucker time_t
8907b668c67Sdtucker scale_interval(time_t requested)
8917b668c67Sdtucker {
89280f94c68Sdtucker 	time_t interval, r;
89380f94c68Sdtucker 
89480f94c68Sdtucker 	interval = requested * conf->scale;
895c72d6e80Sotto 	r = arc4random_uniform(SCALE_INTERVAL(interval));
89680f94c68Sdtucker 	return (interval + r);
8977b668c67Sdtucker }
8987b668c67Sdtucker 
8997b668c67Sdtucker time_t
9007b668c67Sdtucker error_interval(void)
9017b668c67Sdtucker {
90280f94c68Sdtucker 	time_t interval, r;
90380f94c68Sdtucker 
90480f94c68Sdtucker 	interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
90566ad965fSdjm 	r = arc4random_uniform(interval / 10);
90680f94c68Sdtucker 	return (interval + r);
9077b668c67Sdtucker }
908