xref: /openbsd-src/usr.sbin/ntpd/control.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: control.c,v 1.2 2013/11/13 20:44:39 benno Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2012 Mike Miller <mmiller@mgm51.com>
6  *
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.
10  *
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 USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <err.h>
31 
32 #include "ntpd.h"
33 
34 #define	CONTROL_BACKLOG	5
35 
36 int
37 control_init(char *path)
38 {
39 	struct sockaddr_un	 sun;
40 	int			 fd;
41 	mode_t			 old_umask;
42 
43 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
44 		log_warn("control_init: socket");
45 		return (-1);
46 	}
47 
48 	bzero(&sun, sizeof(sun));
49 	sun.sun_family = AF_UNIX;
50 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
51 	    sizeof(sun.sun_path))
52 		errx(1, "ctl socket name too long");
53 
54 	if (unlink(path) == -1)
55 		if (errno != ENOENT) {
56 			log_warn("control_init: unlink %s", path);
57 			close(fd);
58 			return (-1);
59 		}
60 
61 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
62 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
63 		log_warn("control_init: bind: %s", path);
64 		close(fd);
65 		umask(old_umask);
66 		return (-1);
67 	}
68 	umask(old_umask);
69 
70 	if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
71 		log_warn("control_init: chmod");
72 		close(fd);
73 		(void)unlink(path);
74 		return (-1);
75 	}
76 
77 	session_socket_blockmode(fd, BM_NONBLOCK);
78 
79 	return (fd);
80 }
81 
82 int
83 control_listen(int fd)
84 {
85 	if (fd != -1 && listen(fd, CONTROL_BACKLOG) == -1) {
86 		log_warn("control_listen: listen");
87 		return (-1);
88 	}
89 
90 	return (0);
91 }
92 
93 void
94 control_shutdown(int fd)
95 {
96 	close(fd);
97 }
98 
99 void
100 control_cleanup(const char *path)
101 {
102 	if (path)
103 		unlink(path);
104 }
105 
106 int
107 control_accept(int listenfd)
108 {
109 	int			 connfd;
110 	socklen_t		 len;
111 	struct sockaddr_un	 sun;
112 	struct ctl_conn		*ctl_conn;
113 
114 	len = sizeof(sun);
115 	if ((connfd = accept(listenfd,
116 	    (struct sockaddr *)&sun, &len)) == -1) {
117 		if (errno != EWOULDBLOCK && errno != EINTR)
118 			log_warn("control_accept: accept");
119 		return (0);
120 	}
121 
122 	session_socket_blockmode(connfd, BM_NONBLOCK);
123 
124 	if ((ctl_conn = calloc(1, sizeof(struct ctl_conn))) == NULL) {
125 		log_warn("control_accept");
126 		close(connfd);
127 		return (0);
128 	}
129 
130 	imsg_init(&ctl_conn->ibuf, connfd);
131 
132 	TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entry);
133 
134 	return (1);
135 }
136 
137 struct ctl_conn *
138 control_connbyfd(int fd)
139 {
140 	struct ctl_conn	*c;
141 
142 	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.fd != fd;
143 	    c = TAILQ_NEXT(c, entry))
144 		;	/* nothing */
145 
146 	return (c);
147 }
148 
149 int
150 control_close(int fd)
151 {
152 	struct ctl_conn	*c;
153 
154 	if ((c = control_connbyfd(fd)) == NULL) {
155 		log_warn("control_close: fd %d: not found", fd);
156 		return (0);
157 	}
158 
159 	msgbuf_clear(&c->ibuf.w);
160 	TAILQ_REMOVE(&ctl_conns, c, entry);
161 
162 	close(c->ibuf.fd);
163 	free(c);
164 
165 	return (1);
166 }
167 
168 int
169 control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
170 {
171 	struct imsg		 imsg;
172 	struct ctl_conn		*c;
173 	struct ntp_peer 	*p;
174 	struct ntp_sensor 	*s;
175 	struct ctl_show_status	 c_status;
176 	struct ctl_show_peer	 c_peer;
177 	struct ctl_show_sensor	 c_sensor;
178 	int			 cnt;
179 	ssize_t			 n;
180 
181 	if ((c = control_connbyfd(pfd->fd)) == NULL) {
182 		log_warn("control_dispatch_msg: fd %d: not found", pfd->fd);
183 		return (0);
184 	}
185 
186 	if (pfd->revents & POLLOUT)
187 		if (msgbuf_write(&c->ibuf.w) <= 0 && errno != EAGAIN) {
188 			*ctl_cnt -= control_close(pfd->fd);
189 			return (1);
190 		}
191 
192 	if (!(pfd->revents & POLLIN))
193 		return (0);
194 
195 	if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) {
196 		*ctl_cnt -= control_close(pfd->fd);
197 		return (1);
198 	}
199 
200 	for (;;) {
201 		if ((n = imsg_get(&c->ibuf, &imsg)) == -1) {
202 			*ctl_cnt -= control_close(pfd->fd);
203 			return (1);
204 		}
205 		if (n == 0)
206 			break;
207 
208 		switch (imsg.hdr.type) {
209 		case IMSG_CTL_SHOW_STATUS:
210 			build_show_status(&c_status);
211 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_STATUS, 0, 0, -1,
212 			    &c_status, sizeof (c_status));
213 			break;
214 		case IMSG_CTL_SHOW_PEERS:
215 			cnt = 0;
216 			TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
217 				build_show_peer(&c_peer, p);
218 				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS,
219 				    0, 0, -1, &c_peer, sizeof(c_peer));
220 				cnt++;
221 			}
222 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS_END,
223 			    0, 0, -1, &cnt, sizeof(cnt));
224 			break;
225 		case IMSG_CTL_SHOW_SENSORS:
226 			cnt = 0;
227 			TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
228 				build_show_sensor(&c_sensor, s);
229 				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS,
230 				    0, 0, -1, &c_sensor, sizeof(c_sensor));
231 			cnt++;
232 			}
233 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS_END,
234 			    0, 0, -1, &cnt, sizeof(cnt));
235 			break;
236 		case IMSG_CTL_SHOW_ALL:
237 			build_show_status(&c_status);
238 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_STATUS, 0, 0, -1,
239 			    &c_status, sizeof (c_status));
240 
241 			cnt = 0;
242 			TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
243 				build_show_peer(&c_peer, p);
244 				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS,
245 				    0, 0, -1, &c_peer, sizeof(c_peer));
246 				cnt++;
247 			}
248 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS_END,
249 			    0, 0, -1, &cnt, sizeof(cnt));
250 
251 			cnt = 0;
252 			TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
253 				build_show_sensor(&c_sensor, s);
254 				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS,
255 				    0, 0, -1, &c_sensor, sizeof(c_sensor));
256 			cnt++;
257 			}
258 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS_END,
259 			    0, 0, -1, &cnt, sizeof(cnt));
260 
261 			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_ALL_END,
262 			    0, 0, -1, NULL, 0);
263 			break;
264 		default:
265 			break;
266 		}
267 		imsg_free(&imsg);
268 	}
269 	return (0);
270 }
271 
272 void
273 session_socket_blockmode(int fd, enum blockmodes bm)
274 {
275 	int	flags;
276 
277 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
278 		fatal("fcntl F_GETFL");
279 
280 	if (bm == BM_NONBLOCK)
281 		flags |= O_NONBLOCK;
282 	else
283 		flags &= ~O_NONBLOCK;
284 
285 	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
286 		fatal("fcntl F_SETFL");
287 }
288 
289 void
290 build_show_status(struct ctl_show_status *cs)
291 {
292 	struct ntp_peer 	*p;
293 	struct ntp_sensor 	*s;
294 
295 	cs->peercnt = cs->valid_peers = 0;
296 	cs->sensorcnt = cs->valid_sensors = 0;
297 
298 	TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
299 		cs->peercnt++;
300 		if (p->trustlevel >= TRUSTLEVEL_BADPEER)
301 			cs->valid_peers++;
302 	}
303 	TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
304 		cs->sensorcnt++;
305 		if (s->update.good)
306 			cs->valid_sensors++;
307 	}
308 
309 	cs->synced = conf->status.synced;
310 	cs->stratum = conf->status.stratum;
311 	cs->clock_offset = getoffset() * 1000.0;
312 }
313 
314 void
315 build_show_peer(struct ctl_show_peer *cp, struct ntp_peer *p)
316 {
317 	const char 	*a = "not resolved";
318 	const char 	*pool = "", *addr_head_name = "";
319 	u_int8_t 	 shift, best, validdelaycnt, jittercnt;
320 	time_t		 now;
321 
322 	now = getmonotime();
323 
324 	if (p->addr)
325 		a = log_sockaddr((struct sockaddr *)&p->addr->ss);
326 	if (p->addr_head.pool)
327 		pool = "from pool ";
328 
329 	if (0 != strcmp(a, p->addr_head.name))
330 		addr_head_name = p->addr_head.name;
331 
332 	snprintf(cp->peer_desc, sizeof(cp->peer_desc),
333 	    "%s %s%s %s", a, pool, addr_head_name,
334 	    print_rtable(p->rtable) );
335 
336 	validdelaycnt = best = 0;
337 	cp->offset = cp->delay = 0.0;
338 	for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++) {
339 		if (p->reply[shift].delay > 0.0) {
340 			cp->offset += p->reply[shift].offset;
341 			cp->delay += p->reply[shift].delay;
342 
343 			if (p->reply[shift].delay < p->reply[best].delay)
344 				best = shift;
345 
346 			validdelaycnt++;
347 		}
348 	}
349 
350 	if (validdelaycnt > 1) {
351 		cp->offset /= validdelaycnt;
352 		cp->delay /= validdelaycnt;
353 	}
354 
355 	/*
356 	 *  use simple average for jitter calculation, as the
357 	 *  RFC5905-recommended RMS average needs the math library
358 	 */
359 	jittercnt = 0;
360 	cp->jitter = 0.0;
361 	for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++) {
362 		if (p->reply[shift].delay > 0.0 && shift != best) {
363 			cp->jitter += p->reply[shift].delay -
364 			    p->reply[best].delay;
365 			jittercnt++;
366 		}
367 	}
368 	if (jittercnt > 1)
369 		cp->jitter /= jittercnt;
370 
371 	if (p->shift == 0)
372 		shift = OFFSET_ARRAY_SIZE - 1;
373 	else
374 		shift = p->shift - 1;
375 
376 	if (conf->status.synced == 1 &&
377 	    p->reply[shift].status.send_refid == conf->status.refid)
378 		cp->syncedto = 1;
379 	else
380 		cp->syncedto = 0;
381 
382 	/* milliseconds to reduce number of leading zeroes */
383 	cp->offset *= 1000.0;
384 	cp->delay *= 1000.0;
385 	cp->jitter *= 1000.0;
386 
387 	cp->weight = p->weight;
388 	cp->trustlevel = p->trustlevel;
389 	cp->stratum = p->reply[shift].status.stratum;
390 	cp->next = p->next - now < 0 ? 0 : p->next - now;
391 	cp->poll = p->poll;
392 }
393 
394 void
395 build_show_sensor(struct ctl_show_sensor *cs, struct ntp_sensor *s)
396 {
397 	time_t		 now;
398 	u_int8_t 	 shift;
399 	u_int32_t	 refid;
400 
401 	now = getmonotime();
402 
403 	memcpy(&refid, SENSOR_DEFAULT_REFID, sizeof(refid));
404 	refid = refid == s->refid ? 0 : s->refid;
405 
406 	snprintf(cs->sensor_desc, sizeof(cs->sensor_desc),
407 	    "%s  %.4s", s->device, (char *)&refid);
408 
409 	if (s->shift == 0)
410 		shift = SENSOR_OFFSETS - 1;
411 	else
412 		shift = s->shift - 1;
413 
414 	if (conf->status.synced == 1 &&
415 	    s->offsets[shift].status.send_refid == conf->status.refid)
416 		cs->syncedto = 1;
417 	else
418 		cs->syncedto = 0;
419 
420 	cs->weight = s->weight;
421 	cs->good = s->update.good;
422 	cs->stratum = s->offsets[shift].status.stratum;
423 	cs->next = s->next - now < 0 ? 0 : s->next - now;
424 	cs->poll = SENSOR_QUERY_INTERVAL;
425 	cs->offset = s->offsets[shift].offset * 1000.0;
426 	cs->correction = (double)s->correction / 1000.0;
427 }
428