1 /* $OpenBSD: ntp.c,v 1.92 2006/10/21 07:30:58 henning Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2014
5 * Thorsten Glaser <tg@mirbsd.org>
6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7 * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * The following disclaimer must also be retained:
14 *
15 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
16 * the utmost extent permitted by applicable law, neither express nor
17 * implied; without malicious intent or gross negligence. In no event
18 * may a licensor, author or contributor be held liable for indirect,
19 * direct, other damage, loss, or other issues arising in any way out
20 * of dealing in the work, even if advised of the possibility of such
21 * damage or existence of a defect, except proven that it results out
22 * of said person's immediate fault when using the work as intended.
23 */
24
25 #include <sys/param.h>
26 #include <sys/time.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <paths.h>
31 #include <poll.h>
32 #include <pwd.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38
39 #include "ntpd.h"
40 #include "ntp.h"
41
42 __RCSID("$MirOS: src/usr.sbin/ntpd/ntp.c,v 1.30 2014/03/13 05:48:24 tg Exp $");
43
44 extern void arc4random_ctl(unsigned int);
45
46 #define PFD_PIPE_MAIN 0
47 #define PFD_MAX 1
48
49 volatile sig_atomic_t ntp_quit = 0;
50 volatile sig_atomic_t ntp_arc4push = 0;
51 struct imsgbuf *ibuf_main;
52 struct ntpd_conf *conf;
53 u_int peer_cnt;
54
55 void ntp_sighdlr(int);
56 int ntp_dispatch_imsg(void);
57 void peer_add(struct ntp_peer *);
58 void peer_remove(struct ntp_peer *);
59 int offset_compare(const void *, const void *);
60
61 void
ntp_sighdlr(int sig)62 ntp_sighdlr(int sig)
63 {
64 switch (sig) {
65 case SIGINT:
66 case SIGTERM:
67 ntp_quit = 1;
68 break;
69 case SIGHUP:
70 case SIGUSR1:
71 ntp_arc4push = 1;
72 break;
73 }
74 }
75
76 pid_t
ntp_main(int pipe_prnt[2],struct ntpd_conf * nconf)77 ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf)
78 {
79 int a, b, nfds, i, j, idx_peers, timeout, nullfd;
80 u_int pfd_elms = 0, idx2peer_elms = 0;
81 u_int listener_cnt, new_cnt, sent_cnt, trial_cnt;
82 pid_t pid;
83 struct pollfd *pfd = NULL;
84 struct passwd *pw;
85 struct servent *se;
86 struct listen_addr *la;
87 struct ntp_peer *p;
88 struct ntp_peer **idx2peer = NULL;
89 struct timespec tp;
90 struct stat stb;
91 time_t nextaction;
92 void *newp;
93 time_t nextstir, nextshuf, now;
94
95 switch (pid = fork()) {
96 case -1:
97 fatal("cannot fork");
98 break;
99 case 0:
100 break;
101 default:
102 return (pid);
103 }
104
105 /* force re-stir directly after fork, before chroot */
106 (void)arc4random();
107 nextstir = (now = time(NULL)) + 5400;
108 nextshuf = now + 120;
109
110 if ((se = getservbyname("ntp", "udp")) == NULL)
111 fatal("getservbyname");
112
113 if ((pw = getpwnam(NTPD_USER)) == NULL)
114 fatal("getpwnam");
115
116 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
117 fatal(NULL);
118
119 if (stat(pw->pw_dir, &stb) == -1)
120 fatal("stat");
121 if (stb.st_uid != 0 || (stb.st_mode & (S_IWGRP|S_IWOTH)) != 0)
122 fatal("bad privsep dir permissions");
123 if (chroot(pw->pw_dir) == -1)
124 fatal("chroot");
125 if (chdir("/") == -1)
126 fatal("chdir(\"/\")");
127
128 if (!nconf->debug) {
129 dup2(nullfd, STDIN_FILENO);
130 dup2(nullfd, STDOUT_FILENO);
131 dup2(nullfd, STDERR_FILENO);
132 }
133 close(nullfd);
134
135 setproctitle("ntp engine");
136
137 conf = nconf;
138 setup_listeners(se, conf, &listener_cnt);
139
140 if (setgroups(1, &pw->pw_gid) ||
141 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
142 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
143 fatal("can't drop privileges");
144
145 endservent();
146
147 signal(SIGTERM, ntp_sighdlr);
148 signal(SIGINT, ntp_sighdlr);
149 signal(SIGPIPE, SIG_IGN);
150 signal(SIGUSR1, ntp_sighdlr);
151 signal(SIGHUP, ntp_sighdlr);
152
153 close(pipe_prnt[0]);
154 if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
155 fatal(NULL);
156 imsg_init(ibuf_main, pipe_prnt[1]);
157
158 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
159 client_peer_init(p);
160
161 bzero(&conf->status, sizeof(conf->status));
162 conf->status.synced = 0;
163 clock_getres(CLOCK_REALTIME, &tp);
164 b = 1000000000 / tp.tv_nsec; /* convert to Hz */
165 for (a = 0; b > 1; a--, b >>= 1)
166 ;
167 conf->status.precision = a;
168 conf->scale = 1;
169
170 log_info("ntp engine ready");
171
172 peer_cnt = 0;
173 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
174 peer_cnt++;
175
176 while (ntp_quit == 0) {
177 if (ntp_arc4push) {
178 nextstir = 0;
179 ntp_arc4push = 0;
180 }
181
182 if (nextstir < (now = time(NULL))) {
183 /* 1.5 hours after start, then every 2 hrs */
184 arc4random_ctl(2);
185 nextstir = now + 7200;
186 nextshuf = now + 600;
187 } else if (nextshuf < now) {
188 /* 2min after start, then every 5min except past stir */
189 arc4random_ctl(0);
190 nextshuf = now + 300;
191 }
192
193 if (peer_cnt > idx2peer_elms) {
194 if ((newp = realloc(idx2peer, sizeof(void *) *
195 peer_cnt)) == NULL) {
196 /* panic for now */
197 log_warn("could not resize idx2peer from %u -> "
198 "%u entries", idx2peer_elms, peer_cnt);
199 fatalx("exiting");
200 }
201 idx2peer = newp;
202 idx2peer_elms = peer_cnt;
203 }
204
205 new_cnt = PFD_MAX + peer_cnt + listener_cnt;
206 if (new_cnt > pfd_elms) {
207 if ((newp = realloc(pfd, sizeof(struct pollfd) *
208 new_cnt)) == NULL) {
209 /* panic for now */
210 log_warn("could not resize pfd from %u -> "
211 "%u entries", pfd_elms, new_cnt);
212 fatalx("exiting");
213 }
214 pfd = newp;
215 pfd_elms = new_cnt;
216 }
217
218 bzero(pfd, sizeof(struct pollfd) * pfd_elms);
219 bzero(idx2peer, sizeof(void *) * idx2peer_elms);
220 nextaction = now + 3600;
221 pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd;
222 pfd[PFD_PIPE_MAIN].events = POLLIN;
223
224 i = 1;
225 TAILQ_FOREACH(la, &conf->listen_addrs, entry) {
226 pfd[i].fd = la->fd;
227 pfd[i].events = POLLIN;
228 i++;
229 }
230
231 idx_peers = i;
232 sent_cnt = trial_cnt = 0;
233 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
234 if (p->next > 0 && p->next <= now) {
235 if (p->state > STATE_DNS_INPROGRESS)
236 trial_cnt++;
237 if (client_query(p) == 0)
238 sent_cnt++;
239 }
240 if (p->next > 0 && p->next < nextaction)
241 nextaction = p->next;
242
243 if (p->deadline > 0 && p->deadline < nextaction)
244 nextaction = p->deadline;
245 if (p->deadline > 0 && p->deadline <= now) {
246 timeout = error_interval();
247 log_debug("no reply from %s received in time, "
248 "next query %ds", log_sockaddr(
249 (struct sockaddr *)&p->addr->ss), timeout);
250 if (p->trustlevel >= TRUSTLEVEL_BADPEER &&
251 (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER)
252 chpeertrust(p, false);
253 client_nextaddr(p);
254 set_next(p, timeout);
255 }
256
257 if (p->state == STATE_QUERY_SENT &&
258 p->query->fd != -1) {
259 pfd[i].fd = p->query->fd;
260 pfd[i].events = POLLIN;
261 idx2peer[i - idx_peers] = p;
262 i++;
263 }
264 }
265
266 if (conf->settime &&
267 ((trial_cnt > 0 && sent_cnt == 0) || peer_cnt == 0))
268 priv_settime(0); /* no good peers, don't wait */
269
270 if (ibuf_main->w.queued > 0)
271 pfd[PFD_PIPE_MAIN].events |= POLLOUT;
272
273 timeout = nextaction - now;
274 if (timeout < 0)
275 timeout = 0;
276
277 if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
278 if (errno != EINTR) {
279 log_warn("poll error");
280 ntp_quit = 1;
281 }
282
283 if (nfds > 0 && (pfd[PFD_PIPE_MAIN].revents & POLLOUT))
284 if (msgbuf_write(&ibuf_main->w) < 0) {
285 log_warn("pipe write error (to parent)");
286 ntp_quit = 1;
287 }
288
289 if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & (POLLIN|POLLERR)) {
290 nfds--;
291 if (ntp_dispatch_imsg() == -1)
292 ntp_quit = 1;
293 }
294
295 for (j = 1; nfds > 0 && j < idx_peers; j++)
296 if (pfd[j].revents & (POLLIN|POLLERR)) {
297 nfds--;
298 if (server_dispatch(pfd[j].fd, conf) == -1)
299 ntp_quit = 1;
300 }
301
302 for (; nfds > 0 && j < i; j++)
303 if (pfd[j].revents & (POLLIN|POLLERR)) {
304 nfds--;
305 if (client_dispatch(idx2peer[j - idx_peers],
306 conf->settime, conf->trace) == -1)
307 ntp_quit = 1;
308 }
309 }
310
311 msgbuf_write(&ibuf_main->w);
312 msgbuf_clear(&ibuf_main->w);
313 free(ibuf_main);
314
315 log_info("ntp engine exiting");
316 _exit(0);
317 }
318
319 int
ntp_dispatch_imsg(void)320 ntp_dispatch_imsg(void)
321 {
322 struct imsg imsg;
323 int n;
324 struct ntp_peer *peer, *npeer;
325 u_int16_t dlen;
326 u_char *p;
327 struct ntp_addr *h;
328
329 if ((n = imsg_read(ibuf_main)) == -1)
330 return (-1);
331
332 if (n == 0) { /* connection closed */
333 log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed");
334 return (-1);
335 }
336
337 for (;;) {
338 if ((n = imsg_get(ibuf_main, &imsg)) == -1)
339 return (-1);
340
341 if (n == 0)
342 break;
343
344 switch (imsg.hdr.type) {
345 case IMSG_ADJTIME:
346 memcpy(&n, imsg.data, sizeof(n));
347 if (n == 1 && !conf->status.synced) {
348 log_info("clock is now synced");
349 conf->status.synced = 1;
350 } else if (n == 0 && conf->status.synced) {
351 log_info("clock is now unsynced");
352 conf->status.synced = 0;
353 }
354 break;
355 case IMSG_HOST_DNS:
356 TAILQ_FOREACH(peer, &conf->ntp_peers, entry)
357 if (peer->id == imsg.hdr.peerid)
358 break;
359 if (peer == NULL) {
360 log_warnx("IMSG_HOST_DNS with invalid peerID");
361 break;
362 }
363 if (peer->addr != NULL) {
364 log_warnx("IMSG_HOST_DNS but addr != NULL!");
365 break;
366 }
367
368 dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
369 if (dlen == 0) { /* no data -> temp error */
370 peer->state = STATE_DNS_TEMPFAIL;
371 break;
372 }
373
374 p = (u_char *)imsg.data;
375 while (dlen >= sizeof(struct sockaddr_storage)) {
376 if ((h = calloc(1, sizeof(struct ntp_addr))) ==
377 NULL)
378 fatal(NULL);
379 memcpy(&h->ss, p, sizeof(h->ss));
380 p += sizeof(h->ss);
381 dlen -= sizeof(h->ss);
382 if (peer->addr_head.pool) {
383 npeer = new_peer();
384 h->next = NULL;
385 npeer->addr = h;
386 npeer->addr_head.a = h;
387 client_peer_init(npeer);
388 npeer->state = STATE_DNS_DONE;
389 peer_add(npeer);
390 } else {
391 h->next = peer->addr;
392 peer->addr = h;
393 peer->addr_head.a = peer->addr;
394 peer->state = STATE_DNS_DONE;
395 }
396 }
397 if (dlen != 0)
398 fatalx("IMSG_HOST_DNS: dlen != 0");
399 if (peer->addr_head.pool)
400 peer_remove(peer);
401 else
402 client_addr_init(peer);
403 break;
404 case IMSG_RESET:
405 #if 0 /* XXX maybe use type 1 (n == 1) for SIGHUP? */
406 memcpy(&n, imsg.data, sizeof(n));
407 if (n) {
408 log_warn("invalid IMSG_RESET(%u) received", n);
409 break;
410 }
411 #endif
412 conf->scale = 1;
413 TAILQ_FOREACH(peer, &conf->ntp_peers, entry) {
414 bzero(peer->reply, sizeof (peer->reply));
415 peer->shift = 0;
416 if (peer->trustlevel > TRUSTLEVEL_RESET)
417 peer->trustlevel = TRUSTLEVEL_RESET;
418 set_next(peer, -1);
419 }
420 break;
421 default:
422 break;
423 }
424 imsg_free(&imsg);
425 }
426 return (0);
427 }
428
429 void
peer_add(struct ntp_peer * p)430 peer_add(struct ntp_peer *p)
431 {
432 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
433 peer_cnt++;
434 }
435
436 void
peer_remove(struct ntp_peer * p)437 peer_remove(struct ntp_peer *p)
438 {
439 TAILQ_REMOVE(&conf->ntp_peers, p, entry);
440 free(p);
441 peer_cnt--;
442 }
443
444 int
priv_adjtime(void)445 priv_adjtime(void)
446 {
447 struct ntp_peer *p;
448 int offset_cnt = 0, i = 0;
449 struct ntp_peer **peers;
450 double offset_median;
451 int weight_cnt, weight_half;
452
453 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
454 if (conf->trace > 5)
455 log_info("priv_adjtime, #%02d %s peer, trust %d %s,"
456 " st %2d dst %3dms ofs %6.1fms addr %s",
457 offset_cnt,
458 p->update.good ? "good" : "bad ",
459 p->trustlevel,
460 p->trustlevel < TRUSTLEVEL_BADPEER ? "bad" : "ok",
461 p->update.status.stratum,
462 (int)((p->update.delay + .0005) * 1000.),
463 p->update.offset * 1000.,
464 log_sockaddr((struct sockaddr *)&p->addr->ss));
465 else if (conf->trace > 3)
466 log_info("priv_adjtime, #%02d, peer"
467 " trustlevel %d %s, %sgood",
468 offset_cnt,
469 p->trustlevel,
470 p->trustlevel < TRUSTLEVEL_BADPEER ? "bad" : "ok",
471 p->update.good ? "" : "not ");
472
473 if (p->trustlevel < TRUSTLEVEL_BADPEER)
474 continue;
475 if (!p->update.good)
476 return (1);
477 offset_cnt++;
478 }
479
480 if (offset_cnt == 0) {
481 if (conf->trace > 2)
482 log_info("priv_adjtime, no peers");
483 return (1);
484 }
485
486 if ((peers = calloc(offset_cnt, sizeof(struct ntp_peer *))) == NULL)
487 fatal("calloc priv_adjtime");
488
489 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
490 if (p->trustlevel < TRUSTLEVEL_BADPEER)
491 continue;
492 peers[i++] = p;
493 }
494
495 qsort(peers, offset_cnt, sizeof(struct ntp_peer *), offset_compare);
496
497 if (conf->trace > 2)
498 log_info("priv_adjtime, %d peers", offset_cnt);
499
500 weight_cnt = 0;
501 weight_half = 0;
502 offset_median = peers[offset_cnt / 2]->update.offset;
503 for (i = 0; i < offset_cnt; ++i) {
504 int peer_weight = (i + 1) * (offset_cnt - i);
505 double peer_delta;
506
507 if (weight_half) {
508 /* even number of samples, II. median sample */
509 peer_weight += weight_half;
510 weight_half = 0;
511 } else if ((i + 1) * 2 == offset_cnt) {
512 /* even number of samples, I. median sample */
513 weight_half = weight_cnt;
514 peer_weight += weight_half;
515 } else if (i * 2 + 1 == offset_cnt) {
516 /* uneven number of samples, median sample */
517 peer_weight += 2 * weight_cnt;
518 }
519
520 /* ignore false-tickers (off by a second from median) */
521 peer_delta = offset_median - peers[i]->update.offset;
522 if (peer_delta > 1. || peer_delta < -1.)
523 peer_weight = 0;
524
525 /* this is safe here despite shallow copy */
526 peers[i]->update.good = peer_weight;
527 weight_cnt += peer_weight;
528 }
529 offset_median = 0.0;
530 for (i = 0; i < offset_cnt; ++i)
531 if (peers[i]->update.good)
532 offset_median += peers[i]->update.offset *
533 ((double)(peers[i]->update.good) / weight_cnt);
534
535 if (conf->trace > 4 || (conf->trace && conf->debug))
536 for (i = 0; i < offset_cnt; ++i)
537 log_info("peer %2d: trust %s (%d) st %2d dst %3dms"
538 " ofs %6.1fms weight %4d addr %s", i,
539 peers[i]->trustlevel < TRUSTLEVEL_BADPEER ?
540 "bad" : "good", peers[i]->trustlevel,
541 peers[i]->update.status.stratum,
542 (int)((peers[i]->update.delay + .0005) * 1000.),
543 peers[i]->update.offset * 1000.,
544 peers[i]->update.good,
545 log_sockaddr((struct sockaddr *)&peers[i]->addr->ss));
546
547 if (offset_cnt > 1 && offset_cnt % 2 == 0) {
548 conf->status.rootdelay =
549 (peers[offset_cnt / 2 - 1]->update.delay +
550 peers[offset_cnt / 2]->update.delay) / 2;
551 conf->status.stratum = MAX(
552 peers[offset_cnt / 2 - 1]->update.status.stratum,
553 peers[offset_cnt / 2]->update.status.stratum);
554 if (conf->trace)
555 log_info("adj%c stc %d dst %3d ofs %6.1f srv %s", '1',
556 peers[offset_cnt / 2 - 1]->update.status.stratum,
557 (int)((peers[offset_cnt / 2 - 1]->update.delay + .0005) * 1000.),
558 peers[offset_cnt / 2 - 1]->update.offset * 1000.,
559 log_sockaddr((struct sockaddr *)&peers[offset_cnt / 2 - 1]->addr->ss));
560 } else {
561 conf->status.rootdelay =
562 peers[offset_cnt / 2]->update.delay;
563 conf->status.stratum =
564 peers[offset_cnt / 2]->update.status.stratum;
565 }
566 if (conf->trace)
567 log_info("adj%c stc %d dst %3d ofs %6.1f srv %s",
568 (offset_cnt > 1 && offset_cnt % 2 == 0) ? '2' : 'x',
569 peers[offset_cnt / 2]->update.status.stratum,
570 (int)((peers[offset_cnt / 2]->update.delay + .0005) * 1000.),
571 peers[offset_cnt / 2]->update.offset * 1000.,
572 log_sockaddr((struct sockaddr *)&peers[offset_cnt / 2]->addr->ss));
573 conf->status.leap = peers[offset_cnt / 2]->update.status.leap;
574
575 imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0,
576 &offset_median, sizeof(offset_median));
577
578 conf->status.reftime = gettime();
579 /* one more than selected peer, but cap */
580 conf->status.stratum = MIN(conf->status.stratum, 254) + 1;
581 update_scale(offset_median);
582
583 conf->status.refid4 =
584 peers[offset_cnt / 2]->update.status.refid4;
585 if (peers[offset_cnt / 2]->addr->ss.ss_family == AF_INET)
586 conf->status.refid = ((struct sockaddr_in *)
587 &peers[offset_cnt / 2]->addr->ss)->sin_addr.s_addr;
588 else
589 conf->status.refid = conf->status.refid4;
590 if (peers[offset_cnt / 2]->update.status.stratum < 1)
591 conf->status.refid =
592 peers[offset_cnt / 2]->update.status.refid;
593
594 free(peers);
595
596 TAILQ_FOREACH(p, &conf->ntp_peers, entry)
597 p->update.good = 0;
598
599 return (0);
600 }
601
602 int
offset_compare(const void * aa,const void * bb)603 offset_compare(const void *aa, const void *bb)
604 {
605 const struct ntp_peer * const *a;
606 const struct ntp_peer * const *b;
607
608 a = aa;
609 b = bb;
610
611 if ((*a)->update.offset < (*b)->update.offset)
612 return (-1);
613 else if ((*a)->update.offset > (*b)->update.offset)
614 return (1);
615 else
616 return (0);
617 }
618
619 void
priv_settime(double offset)620 priv_settime(double offset)
621 {
622 struct ntp_peer *p;
623
624 imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset));
625 conf->settime = 0;
626
627 TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
628 if (p->next)
629 p->next -= offset;
630 if (p->deadline)
631 p->deadline -= offset;
632 }
633 }
634
635 void
priv_host_dns(char * name,u_int32_t peerid)636 priv_host_dns(char *name, u_int32_t peerid)
637 {
638 u_int16_t dlen;
639
640 dlen = strlen(name) + 1;
641 imsg_compose(ibuf_main, IMSG_HOST_DNS, peerid, 0, name, dlen);
642 }
643
644 void
update_scale(double offset)645 update_scale(double offset)
646 {
647 if (offset < 0)
648 offset = -offset;
649
650 if (offset > QSCALE_OFF_MAX)
651 conf->scale = 1;
652 else if (offset < QSCALE_OFF_MIN)
653 conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN;
654 else
655 conf->scale = QSCALE_OFF_MAX / offset;
656 }
657
658 time_t
scale_interval(time_t requested)659 scale_interval(time_t requested)
660 {
661 double interval = requested, r;
662
663 r = (interval *= conf->scale) / 10.;
664 if (r > 7.)
665 r = 7.;
666 return (interval + arc4random_uniform((int)(r + .5)) - (r / 2.));
667 }
668
669 time_t
error_interval(void)670 error_interval(void)
671 {
672 double interval = INTERVAL_QUERY_PATHETIC, r;
673
674 r = (interval *= QSCALE_OFF_MAX / QSCALE_OFF_MIN) / 10.;
675 return (interval + arc4random_uniform((int)(r + .5)) - (r / 2.));
676 }
677
678 void
chpeertrust(struct ntp_peer * p,bool nowvalid)679 chpeertrust(struct ntp_peer *p, bool nowvalid)
680 {
681 static u_int nvpeers;
682 const char *s = "";
683
684 if (nowvalid)
685 ++nvpeers;
686 else {
687 if (nvpeers)
688 --nvpeers;
689 else
690 log_warn("trying to decrease nvpeers below 0");
691 s = "in";
692 }
693
694 log_info("peer %s now %svalid, %u valid peers total",
695 log_sockaddr((struct sockaddr *)&p->addr->ss),
696 s, nvpeers);
697 }
698