1 /* $OpenBSD: src/usr.sbin/ntpd/ntp.c,v 1.57 2005/04/18 14:12:50 henning Exp $ */
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/param.h>
37 #define PFD_PIPE_MAIN 0
40 volatile sig_atomic_t ntp_quit
= 0;
41 struct imsgbuf
*ibuf_main
;
42 struct ntpd_conf
*conf
;
45 void ntp_sighdlr(int);
46 int ntp_dispatch_imsg(void);
47 void peer_add(struct ntp_peer
*);
48 void peer_remove(struct ntp_peer
*);
49 int offset_compare(const void *, const void *);
63 ntp_main(int pipe_prnt
[2], struct ntpd_conf
*nconf
)
65 int a
, b
, nfds
, i
, j
, idx_peers
, timeout
, nullfd
;
66 u_int pfd_elms
= 0, idx2peer_elms
= 0;
67 u_int listener_cnt
, new_cnt
, sent_cnt
, trial_cnt
;
69 struct pollfd
*pfd
= NULL
;
72 struct listen_addr
*la
;
74 struct ntp_peer
**idx2peer
= NULL
;
80 switch (pid
= fork()) {
90 if ((se
= getservbyname("ntp", "udp")) == NULL
)
91 fatal("getservbyname");
93 if ((pw
= getpwnam(NTPD_USER
)) == NULL
)
96 if ((nullfd
= open(_PATH_DEVNULL
, O_RDWR
, 0)) == -1)
99 if (stat(pw
->pw_dir
, &stb
) == -1)
101 if (stb
.st_uid
!= 0 || (stb
.st_mode
& (S_IWGRP
|S_IWOTH
)) != 0)
102 fatal("bad privsep dir permissions");
103 if (chroot(pw
->pw_dir
) == -1)
105 if (chdir("/") == -1)
106 fatal("chdir(\"/\")");
109 dup2(nullfd
, STDIN_FILENO
);
110 dup2(nullfd
, STDOUT_FILENO
);
111 dup2(nullfd
, STDERR_FILENO
);
115 setproctitle("ntp engine");
118 setup_listeners(se
, conf
, &listener_cnt
);
120 if (setgroups(1, &pw
->pw_gid
) ||
121 setegid(pw
->pw_gid
) || setgid(pw
->pw_gid
) ||
122 seteuid(pw
->pw_uid
) || setuid(pw
->pw_uid
))
123 fatal("can't drop privileges");
128 signal(SIGTERM
, ntp_sighdlr
);
129 signal(SIGINT
, ntp_sighdlr
);
130 signal(SIGPIPE
, SIG_IGN
);
131 signal(SIGHUP
, SIG_IGN
);
134 if ((ibuf_main
= malloc(sizeof(struct imsgbuf
))) == NULL
)
136 imsg_init(ibuf_main
, pipe_prnt
[1]);
138 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
)
141 bzero(&conf
->status
, sizeof(conf
->status
));
142 conf
->status
.leap
= LI_ALARM
;
143 clock_getres(CLOCK_REALTIME
, &tp
);
144 b
= 1000000000 / tp
.tv_nsec
; /* convert to Hz */
145 for (a
= 0; b
> 1; a
--, b
>>= 1)
147 conf
->status
.precision
= a
;
150 log_info("ntp engine ready");
153 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
)
156 while (ntp_quit
== 0) {
157 if (peer_cnt
> idx2peer_elms
) {
158 if ((newp
= realloc(idx2peer
, sizeof(void *) *
159 peer_cnt
)) == NULL
) {
161 log_warn("could not resize idx2peer from %u -> "
162 "%u entries", idx2peer_elms
, peer_cnt
);
166 idx2peer_elms
= peer_cnt
;
169 new_cnt
= PFD_MAX
+ peer_cnt
+ listener_cnt
;
170 if (new_cnt
> pfd_elms
) {
171 if ((newp
= realloc(pfd
, sizeof(struct pollfd
) *
174 log_warn("could not resize pfd from %u -> "
175 "%u entries", pfd_elms
, new_cnt
);
182 bzero(pfd
, sizeof(struct pollfd
) * pfd_elms
);
183 bzero(idx2peer
, sizeof(void *) * idx2peer_elms
);
184 nextaction
= time(NULL
) + 3600;
185 pfd
[PFD_PIPE_MAIN
].fd
= ibuf_main
->fd
;
186 pfd
[PFD_PIPE_MAIN
].events
= POLLIN
;
189 TAILQ_FOREACH(la
, &conf
->listen_addrs
, entry
) {
191 pfd
[i
].events
= POLLIN
;
196 sent_cnt
= trial_cnt
= 0;
197 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
) {
198 if (p
->next
> 0 && p
->next
< nextaction
)
199 nextaction
= p
->next
;
200 if (p
->next
> 0 && p
->next
<= time(NULL
)) {
202 if (client_query(p
) == 0)
206 if (p
->deadline
> 0 && p
->deadline
< nextaction
)
207 nextaction
= p
->deadline
;
208 if (p
->deadline
> 0 && p
->deadline
<= time(NULL
)) {
209 timeout
= error_interval();
210 log_debug("no reply from %s received in time, "
211 "next query %ds", log_sockaddr(
212 (struct sockaddr
*)&p
->addr
->ss
), timeout
);
213 if (p
->trustlevel
>= TRUSTLEVEL_BADPEER
&&
214 (p
->trustlevel
/= 2) < TRUSTLEVEL_BADPEER
)
215 log_info("peer %s now invalid",
217 (struct sockaddr
*)&p
->addr
->ss
));
219 set_next(p
, timeout
);
222 if (p
->state
== STATE_QUERY_SENT
) {
223 pfd
[i
].fd
= p
->query
->fd
;
224 pfd
[i
].events
= POLLIN
;
225 idx2peer
[i
- idx_peers
] = p
;
230 if (trial_cnt
> 0 && sent_cnt
== 0 && conf
->settime
)
231 priv_settime(0); /* no good peers, don't wait */
233 if (ibuf_main
->w
.queued
> 0)
234 pfd
[PFD_PIPE_MAIN
].events
|= POLLOUT
;
236 timeout
= nextaction
- time(NULL
);
240 if ((nfds
= poll(pfd
, i
, timeout
* 1000)) == -1)
241 if (errno
!= EINTR
) {
242 log_warn("poll error");
246 if (nfds
> 0 && (pfd
[PFD_PIPE_MAIN
].revents
& POLLOUT
))
247 if (msgbuf_write(&ibuf_main
->w
) < 0) {
248 log_warn("pipe write error (to parent)");
252 if (nfds
> 0 && pfd
[PFD_PIPE_MAIN
].revents
& (POLLIN
|POLLERR
)) {
254 if (ntp_dispatch_imsg() == -1)
258 for (j
= 1; nfds
> 0 && j
< idx_peers
; j
++)
259 if (pfd
[j
].revents
& (POLLIN
|POLLERR
)) {
261 if (server_dispatch(pfd
[j
].fd
, conf
) == -1)
265 for (; nfds
> 0 && j
< i
; j
++)
266 if (pfd
[j
].revents
& (POLLIN
|POLLERR
)) {
268 if (client_dispatch(idx2peer
[j
- idx_peers
],
269 conf
->settime
) == -1)
274 msgbuf_write(&ibuf_main
->w
);
275 msgbuf_clear(&ibuf_main
->w
);
278 log_info("ntp engine exiting");
283 ntp_dispatch_imsg(void)
287 struct ntp_peer
*peer
, *npeer
;
292 if ((n
= imsg_read(ibuf_main
)) == -1)
295 if (n
== 0) { /* connection closed */
296 log_warnx("ntp_dispatch_imsg in ntp engine: pipe closed");
301 if ((n
= imsg_get(ibuf_main
, &imsg
)) == -1)
307 switch (imsg
.hdr
.type
) {
309 TAILQ_FOREACH(peer
, &conf
->ntp_peers
, entry
)
310 if (peer
->id
== imsg
.hdr
.peerid
)
313 log_warnx("IMSG_HOST_DNS with invalid peerID");
316 if (peer
->addr
!= NULL
) {
317 log_warnx("IMSG_HOST_DNS but addr != NULL!");
320 dlen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
321 p
= (u_char
*)imsg
.data
;
322 while (dlen
>= sizeof(struct sockaddr_storage
)) {
323 if ((h
= calloc(1, sizeof(struct ntp_addr
))) ==
326 memcpy(&h
->ss
, p
, sizeof(h
->ss
));
328 dlen
-= sizeof(h
->ss
);
329 if (peer
->addr_head
.pool
) {
333 npeer
->addr_head
.a
= h
;
334 client_peer_init(npeer
);
337 h
->next
= peer
->addr
;
339 peer
->addr_head
.a
= peer
->addr
;
343 fatalx("IMSG_HOST_DNS: dlen != 0");
344 if (peer
->addr_head
.pool
)
347 client_addr_init(peer
);
358 peer_add(struct ntp_peer
*p
)
360 TAILQ_INSERT_TAIL(&conf
->ntp_peers
, p
, entry
);
365 peer_remove(struct ntp_peer
*p
)
367 TAILQ_REMOVE(&conf
->ntp_peers
, p
, entry
);
376 int offset_cnt
= 0, i
= 0;
377 struct ntp_peer
**peers
;
378 double offset_median
;
380 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
) {
381 if (p
->trustlevel
< TRUSTLEVEL_BADPEER
)
388 if ((peers
= calloc(offset_cnt
, sizeof(struct ntp_peer
*))) == NULL
)
389 fatal("calloc ntp_adjtime");
391 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
) {
392 if (p
->trustlevel
< TRUSTLEVEL_BADPEER
)
397 qsort(peers
, offset_cnt
, sizeof(struct ntp_peer
*), offset_compare
);
399 if (offset_cnt
> 0) {
400 if (offset_cnt
> 1 && offset_cnt
% 2 == 0) {
402 (peers
[offset_cnt
/ 2 - 1]->update
.offset
+
403 peers
[offset_cnt
/ 2]->update
.offset
) / 2;
404 conf
->status
.rootdelay
=
405 (peers
[offset_cnt
/ 2 - 1]->update
.delay
+
406 peers
[offset_cnt
/ 2]->update
.delay
) / 2;
407 conf
->status
.stratum
= MAX(
408 peers
[offset_cnt
/ 2 - 1]->update
.status
.stratum
,
409 peers
[offset_cnt
/ 2]->update
.status
.stratum
);
411 offset_median
= peers
[offset_cnt
/ 2]->update
.offset
;
412 conf
->status
.rootdelay
=
413 peers
[offset_cnt
/ 2]->update
.delay
;
414 conf
->status
.stratum
=
415 peers
[offset_cnt
/ 2]->update
.status
.stratum
;
418 imsg_compose(ibuf_main
, IMSG_ADJTIME
, 0, 0,
419 &offset_median
, sizeof(offset_median
));
421 conf
->status
.reftime
= gettime();
422 conf
->status
.leap
= LI_NOWARNING
;
423 conf
->status
.stratum
++; /* one more than selected peer */
424 update_scale(offset_median
);
426 if (peers
[offset_cnt
/ 2]->addr
->ss
.ss_family
== AF_INET
)
427 conf
->status
.refid
= ((struct sockaddr_in
*)
428 &peers
[offset_cnt
/ 2]->addr
->ss
)->sin_addr
.s_addr
;
433 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
)
438 offset_compare(const void *aa
, const void *bb
)
440 const struct ntp_peer
* const *a
;
441 const struct ntp_peer
* const *b
;
446 if ((*a
)->update
.offset
< (*b
)->update
.offset
)
448 else if ((*a
)->update
.offset
> (*b
)->update
.offset
)
455 priv_settime(double offset
)
459 imsg_compose(ibuf_main
, IMSG_SETTIME
, 0, 0, &offset
, sizeof(offset
));
462 TAILQ_FOREACH(p
, &conf
->ntp_peers
, entry
) {
466 p
->deadline
-= offset
;
471 priv_host_dns(char *name
, u_int32_t peerid
)
475 dlen
= strlen(name
) + 1;
476 imsg_compose(ibuf_main
, IMSG_HOST_DNS
, peerid
, 0, name
, dlen
);
480 update_scale(double offset
)
485 if (offset
> QSCALE_OFF_MAX
)
487 else if (offset
< QSCALE_OFF_MIN
)
488 conf
->scale
= QSCALE_OFF_MAX
/ QSCALE_OFF_MIN
;
490 conf
->scale
= QSCALE_OFF_MAX
/ offset
;
494 scale_interval(time_t requested
)
498 interval
= requested
* conf
->scale
;
499 r
= arc4random() % MAX(5, interval
/ 10);
500 return (interval
+ r
);
508 interval
= INTERVAL_QUERY_PATHETIC
* QSCALE_OFF_MAX
/ QSCALE_OFF_MIN
;
509 r
= arc4random() % (interval
/ 10);
510 return (interval
+ r
);