GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/slaacd/control.c Lines: 5 127 3.9 %
Date: 2017-11-07 Branches: 1 72 1.4 %

Line Branch Exec Source
1
/*	$OpenBSD: control.c,v 1.1 2017/06/03 10:00:29 florian Exp $	*/
2
3
/*
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
#include <sys/types.h>
19
#include <sys/queue.h>
20
#include <sys/stat.h>
21
#include <sys/socket.h>
22
#include <sys/uio.h>
23
#include <sys/un.h>
24
25
#include <net/if.h>
26
#include <netinet/in.h>
27
#include <netinet/if_ether.h>
28
29
#include <errno.h>
30
#include <event.h>
31
#include <imsg.h>
32
#include <md5.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#include "log.h"
38
#include "slaacd.h"
39
#include "control.h"
40
#include "frontend.h"
41
42
#define	CONTROL_BACKLOG	5
43
44
struct ctl_conn	*control_connbyfd(int);
45
struct ctl_conn	*control_connbypid(pid_t);
46
void		 control_close(int);
47
48
int
49
control_init(char *path)
50
{
51
	struct sockaddr_un	 sun;
52
	int			 fd;
53
	mode_t			 old_umask;
54
55
	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
56
	    0)) == -1) {
57
		log_warn("%s: socket", __func__);
58
		return (-1);
59
	}
60
61
	memset(&sun, 0, sizeof(sun));
62
	sun.sun_family = AF_UNIX;
63
	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
64
65
	if (unlink(path) == -1)
66
		if (errno != ENOENT) {
67
			log_warn("%s: unlink %s", __func__, path);
68
			close(fd);
69
			return (-1);
70
		}
71
72
	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
73
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
74
		log_warn("%s: bind: %s", __func__, path);
75
		close(fd);
76
		umask(old_umask);
77
		return (-1);
78
	}
79
	umask(old_umask);
80
81
	if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
82
		log_warn("%s: chmod", __func__);
83
		close(fd);
84
		(void)unlink(path);
85
		return (-1);
86
	}
87
88
	control_state.fd = fd;
89
90
	return (0);
91
}
92
93
int
94
control_listen(void)
95
{
96
97
	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
98
		log_warn("%s: listen", __func__);
99
		return (-1);
100
	}
101
102
	event_set(&control_state.ev, control_state.fd, EV_READ,
103
	    control_accept, NULL);
104
	event_add(&control_state.ev, NULL);
105
	evtimer_set(&control_state.evt, control_accept, NULL);
106
107
	return (0);
108
}
109
110
void
111
control_cleanup(char *path)
112
{
113
18
	if (path == NULL)
114
		return;
115
9
	event_del(&control_state.ev);
116
9
	event_del(&control_state.evt);
117
9
	unlink(path);
118
18
}
119
120
void
121
control_accept(int listenfd, short event, void *bula)
122
{
123
	int			 connfd;
124
	socklen_t		 len;
125
	struct sockaddr_un	 sun;
126
	struct ctl_conn		*c;
127
128
	event_add(&control_state.ev, NULL);
129
	if ((event & EV_TIMEOUT))
130
		return;
131
132
	len = sizeof(sun);
133
	if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len,
134
	    SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) {
135
		/*
136
		 * Pause accept if we are out of file descriptors, or
137
		 * libevent will haunt us here too.
138
		 */
139
		if (errno == ENFILE || errno == EMFILE) {
140
			struct timeval evtpause = { 1, 0 };
141
142
			event_del(&control_state.ev);
143
			evtimer_add(&control_state.evt, &evtpause);
144
		} else if (errno != EWOULDBLOCK && errno != EINTR &&
145
		    errno != ECONNABORTED)
146
			log_warn("%s: accept4", __func__);
147
		return;
148
	}
149
150
	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
151
		log_warn("%s: calloc", __func__);
152
		close(connfd);
153
		return;
154
	}
155
156
	imsg_init(&c->iev.ibuf, connfd);
157
	c->iev.handler = control_dispatch_imsg;
158
	c->iev.events = EV_READ;
159
	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
160
	    c->iev.handler, &c->iev);
161
	event_add(&c->iev.ev, NULL);
162
163
	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
164
}
165
166
struct ctl_conn *
167
control_connbyfd(int fd)
168
{
169
	struct ctl_conn	*c;
170
171
	TAILQ_FOREACH(c, &ctl_conns, entry) {
172
		if (c->iev.ibuf.fd == fd)
173
			break;
174
	}
175
176
	return (c);
177
}
178
179
struct ctl_conn *
180
control_connbypid(pid_t pid)
181
{
182
	struct ctl_conn	*c;
183
184
	TAILQ_FOREACH(c, &ctl_conns, entry) {
185
		if (c->iev.ibuf.pid == pid)
186
			break;
187
	}
188
189
	return (c);
190
}
191
192
void
193
control_close(int fd)
194
{
195
	struct ctl_conn	*c;
196
197
	if ((c = control_connbyfd(fd)) == NULL) {
198
		log_warnx("%s: fd %d: not found", __func__, fd);
199
		return;
200
	}
201
202
	msgbuf_clear(&c->iev.ibuf.w);
203
	TAILQ_REMOVE(&ctl_conns, c, entry);
204
205
	event_del(&c->iev.ev);
206
	close(c->iev.ibuf.fd);
207
208
	/* Some file descriptors are available again. */
209
	if (evtimer_pending(&control_state.evt, NULL)) {
210
		evtimer_del(&control_state.evt);
211
		event_add(&control_state.ev, NULL);
212
	}
213
214
	free(c);
215
}
216
217
void
218
control_dispatch_imsg(int fd, short event, void *bula)
219
{
220
	struct ctl_conn	*c;
221
	struct imsg	 imsg;
222
	ssize_t		 n;
223
	int		 verbose;
224
225
	if ((c = control_connbyfd(fd)) == NULL) {
226
		log_warnx("%s: fd %d: not found", __func__, fd);
227
		return;
228
	}
229
230
	if (event & EV_READ) {
231
		if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
232
		    n == 0) {
233
			control_close(fd);
234
			return;
235
		}
236
	}
237
	if (event & EV_WRITE) {
238
		if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
239
			control_close(fd);
240
			return;
241
		}
242
	}
243
244
	for (;;) {
245
		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
246
			control_close(fd);
247
			return;
248
		}
249
		if (n == 0)
250
			break;
251
252
		switch (imsg.hdr.type) {
253
		case IMSG_CTL_LOG_VERBOSE:
254
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
255
			    sizeof(verbose))
256
				break;
257
258
			/* Forward to all other processes. */
259
			frontend_imsg_compose_main(imsg.hdr.type, imsg.hdr.pid,
260
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
261
			frontend_imsg_compose_engine(imsg.hdr.type, 0,
262
			    imsg.hdr.pid, imsg.data,
263
			    imsg.hdr.len - IMSG_HEADER_SIZE);
264
265
			memcpy(&verbose, imsg.data, sizeof(verbose));
266
			log_setverbose(verbose);
267
			break;
268
		case IMSG_CTL_SHOW_INTERFACE_INFO:
269
			c->iev.ibuf.pid = imsg.hdr.pid;
270
			frontend_imsg_compose_engine(imsg.hdr.type, 0,
271
			    imsg.hdr.pid, imsg.data, imsg.hdr.len -
272
			    IMSG_HEADER_SIZE);
273
			break;
274
		case IMSG_CTL_SEND_SOLICITATION:
275
			c->iev.ibuf.pid = imsg.hdr.pid;
276
			frontend_imsg_compose_engine(imsg.hdr.type, 0,
277
			    imsg.hdr.pid, imsg.data, imsg.hdr.len -
278
			    IMSG_HEADER_SIZE);
279
			break;
280
		default:
281
			log_debug("%s: error handling imsg %d", __func__,
282
			    imsg.hdr.type);
283
			break;
284
		}
285
		imsg_free(&imsg);
286
	}
287
288
	imsg_event_add(&c->iev);
289
}
290
291
int
292
control_imsg_relay(struct imsg *imsg)
293
{
294
	struct ctl_conn	*c;
295
296
	if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
297
		return (0);
298
299
	return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
300
	    -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
301
}