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