GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ntpd/control.c Lines: 0 200 0.0 %
Date: 2017-11-07 Branches: 0 119 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: control.c,v 1.12 2017/01/09 14:04:31 krw 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 <math.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
#include <fcntl.h>
31
#include <err.h>
32
33
#include "ntpd.h"
34
35
#define	CONTROL_BACKLOG	5
36
37
#define square(x) ((x) * (x))
38
39
int
40
control_init(char *path)
41
{
42
	struct sockaddr_un	 sa;
43
	int			 fd;
44
	mode_t			 old_umask;
45
46
	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
47
		log_warn("control_init: socket");
48
		return (-1);
49
	}
50
51
	memset(&sa, 0, sizeof(sa));
52
	sa.sun_family = AF_UNIX;
53
	if (strlcpy(sa.sun_path, path, sizeof(sa.sun_path)) >=
54
	    sizeof(sa.sun_path))
55
		errx(1, "ctl socket name too long");
56
57
	if (unlink(path) == -1)
58
		if (errno != ENOENT) {
59
			log_warn("control_init: unlink %s", path);
60
			close(fd);
61
			return (-1);
62
		}
63
64
	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
65
	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
66
		log_warn("control_init: bind: %s", path);
67
		close(fd);
68
		umask(old_umask);
69
		return (-1);
70
	}
71
	umask(old_umask);
72
73
	if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
74
		log_warn("control_init: chmod");
75
		close(fd);
76
		(void)unlink(path);
77
		return (-1);
78
	}
79
80
	session_socket_nonblockmode(fd);
81
82
	return (fd);
83
}
84
85
int
86
control_listen(int fd)
87
{
88
	if (fd != -1 && listen(fd, CONTROL_BACKLOG) == -1) {
89
		log_warn("control_listen: listen");
90
		return (-1);
91
	}
92
93
	return (0);
94
}
95
96
void
97
control_shutdown(int fd)
98
{
99
	close(fd);
100
}
101
102
void
103
control_cleanup(const char *path)
104
{
105
	if (path)
106
		unlink(path);
107
}
108
109
int
110
control_accept(int listenfd)
111
{
112
	int			 connfd;
113
	socklen_t		 len;
114
	struct sockaddr_un	 sa;
115
	struct ctl_conn		*ctl_conn;
116
117
	len = sizeof(sa);
118
	if ((connfd = accept(listenfd,
119
	    (struct sockaddr *)&sa, &len)) == -1) {
120
		if (errno != EWOULDBLOCK && errno != EINTR)
121
			log_warn("control_accept: accept");
122
		return (0);
123
	}
124
125
	session_socket_nonblockmode(connfd);
126
127
	if ((ctl_conn = calloc(1, sizeof(struct ctl_conn))) == NULL) {
128
		log_warn("control_accept");
129
		close(connfd);
130
		return (0);
131
	}
132
133
	imsg_init(&ctl_conn->ibuf, connfd);
134
135
	TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entry);
136
137
	return (1);
138
}
139
140
struct ctl_conn *
141
control_connbyfd(int fd)
142
{
143
	struct ctl_conn	*c;
144
145
	TAILQ_FOREACH(c, &ctl_conns, entry) {
146
		if (c->ibuf.fd == fd)
147
			break;
148
	}
149
150
	return (c);
151
}
152
153
int
154
control_close(int fd)
155
{
156
	struct ctl_conn	*c;
157
158
	if ((c = control_connbyfd(fd)) == NULL) {
159
		log_warn("control_close: fd %d: not found", fd);
160
		return (0);
161
	}
162
163
	msgbuf_clear(&c->ibuf.w);
164
	TAILQ_REMOVE(&ctl_conns, c, entry);
165
166
	close(c->ibuf.fd);
167
	free(c);
168
169
	return (1);
170
}
171
172
int
173
control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
174
{
175
	struct imsg		 imsg;
176
	struct ctl_conn		*c;
177
	struct ntp_peer		*p;
178
	struct ntp_sensor	*s;
179
	struct ctl_show_status	 c_status;
180
	struct ctl_show_peer	 c_peer;
181
	struct ctl_show_sensor	 c_sensor;
182
	int			 cnt;
183
	ssize_t			 n;
184
185
	if ((c = control_connbyfd(pfd->fd)) == NULL) {
186
		log_warn("control_dispatch_msg: fd %d: not found", pfd->fd);
187
		return (0);
188
	}
189
190
	if (pfd->revents & POLLOUT)
191
		if (msgbuf_write(&c->ibuf.w) <= 0 && errno != EAGAIN) {
192
			*ctl_cnt -= control_close(pfd->fd);
193
			return (1);
194
		}
195
196
	if (!(pfd->revents & POLLIN))
197
		return (0);
198
199
	if (((n = imsg_read(&c->ibuf)) == -1 && errno != EAGAIN) || n == 0) {
200
		*ctl_cnt -= control_close(pfd->fd);
201
		return (1);
202
	}
203
204
	for (;;) {
205
		if ((n = imsg_get(&c->ibuf, &imsg)) == -1) {
206
			*ctl_cnt -= control_close(pfd->fd);
207
			return (1);
208
		}
209
		if (n == 0)
210
			break;
211
212
		switch (imsg.hdr.type) {
213
		case IMSG_CTL_SHOW_STATUS:
214
			build_show_status(&c_status);
215
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_STATUS, 0, 0, -1,
216
			    &c_status, sizeof (c_status));
217
			break;
218
		case IMSG_CTL_SHOW_PEERS:
219
			cnt = 0;
220
			TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
221
				build_show_peer(&c_peer, p);
222
				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS,
223
				    0, 0, -1, &c_peer, sizeof(c_peer));
224
				cnt++;
225
			}
226
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS_END,
227
			    0, 0, -1, &cnt, sizeof(cnt));
228
			break;
229
		case IMSG_CTL_SHOW_SENSORS:
230
			cnt = 0;
231
			TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
232
				build_show_sensor(&c_sensor, s);
233
				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS,
234
				    0, 0, -1, &c_sensor, sizeof(c_sensor));
235
			cnt++;
236
			}
237
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS_END,
238
			    0, 0, -1, &cnt, sizeof(cnt));
239
			break;
240
		case IMSG_CTL_SHOW_ALL:
241
			build_show_status(&c_status);
242
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_STATUS, 0, 0, -1,
243
			    &c_status, sizeof (c_status));
244
245
			cnt = 0;
246
			TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
247
				build_show_peer(&c_peer, p);
248
				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS,
249
				    0, 0, -1, &c_peer, sizeof(c_peer));
250
				cnt++;
251
			}
252
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS_END,
253
			    0, 0, -1, &cnt, sizeof(cnt));
254
255
			cnt = 0;
256
			TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
257
				build_show_sensor(&c_sensor, s);
258
				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS,
259
				    0, 0, -1, &c_sensor, sizeof(c_sensor));
260
			cnt++;
261
			}
262
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS_END,
263
			    0, 0, -1, &cnt, sizeof(cnt));
264
265
			imsg_compose(&c->ibuf, IMSG_CTL_SHOW_ALL_END,
266
			    0, 0, -1, NULL, 0);
267
			break;
268
		default:
269
			break;
270
		}
271
		imsg_free(&imsg);
272
	}
273
	return (0);
274
}
275
276
void
277
session_socket_nonblockmode(int fd)
278
{
279
	int	flags;
280
281
	if ((flags = fcntl(fd, F_GETFL)) == -1)
282
		fatal("fcntl F_GETFL");
283
284
	flags |= O_NONBLOCK;
285
286
	if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
287
		fatal("fcntl F_SETFL");
288
}
289
290
void
291
build_show_status(struct ctl_show_status *cs)
292
{
293
	struct ntp_peer		*p;
294
	struct ntp_sensor	*s;
295
296
	cs->peercnt = cs->valid_peers = 0;
297
	cs->sensorcnt = cs->valid_sensors = 0;
298
299
	TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
300
		cs->peercnt++;
301
		if (p->trustlevel >= TRUSTLEVEL_BADPEER)
302
			cs->valid_peers++;
303
	}
304
	TAILQ_FOREACH(s, &conf->ntp_sensors, entry) {
305
		cs->sensorcnt++;
306
		if (s->update.good)
307
			cs->valid_sensors++;
308
	}
309
310
	cs->synced = conf->status.synced;
311
	cs->stratum = conf->status.stratum;
312
	cs->clock_offset = getoffset() * 1000.0;
313
	cs->constraint_median = conf->constraint_median;
314
	cs->constraint_last = conf->constraint_last;
315
	cs->constraint_errors = conf->constraint_errors;
316
}
317
318
void
319
build_show_peer(struct ctl_show_peer *cp, struct ntp_peer *p)
320
{
321
	const char	*a = "not resolved";
322
	const char	*pool = "", *addr_head_name = "";
323
	u_int8_t	 shift, best, validdelaycnt, jittercnt;
324
	time_t		 now;
325
326
	now = getmonotime();
327
328
	if (p->addr)
329
		a = log_sockaddr((struct sockaddr *)&p->addr->ss);
330
	if (p->addr_head.pool)
331
		pool = "from pool ";
332
333
	if (0 != strcmp(a, p->addr_head.name))
334
		addr_head_name = p->addr_head.name;
335
336
	snprintf(cp->peer_desc, sizeof(cp->peer_desc),
337
	    "%s %s%s", a, pool, addr_head_name);
338
339
	validdelaycnt = best = 0;
340
	cp->offset = cp->delay = 0.0;
341
	for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++) {
342
		if (p->reply[shift].delay > 0.0) {
343
			cp->offset += p->reply[shift].offset;
344
			cp->delay += p->reply[shift].delay;
345
346
			if (p->reply[shift].delay < p->reply[best].delay)
347
				best = shift;
348
349
			validdelaycnt++;
350
		}
351
	}
352
353
	if (validdelaycnt > 1) {
354
		cp->offset /= validdelaycnt;
355
		cp->delay /= validdelaycnt;
356
	}
357
358
	jittercnt = 0;
359
	cp->jitter = 0.0;
360
	for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++) {
361
		if (p->reply[shift].delay > 0.0 && shift != best) {
362
			cp->jitter += square(p->reply[shift].delay -
363
			    p->reply[best].delay);
364
			jittercnt++;
365
		}
366
	}
367
	if (jittercnt > 1)
368
		cp->jitter /= jittercnt;
369
	cp->jitter = sqrt(cp->jitter);
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
}