GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/control.c Lines: 0 132 0.0 %
Date: 2017-11-13 Branches: 0 81 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: control.c,v 1.23 2017/01/08 23:04:42 krw 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
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
#include <sys/socket.h>
22
#include <sys/un.h>
23
#include <errno.h>
24
#include <fcntl.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <unistd.h>
28
29
#include "igmp.h"
30
#include "dvmrpd.h"
31
#include "dvmrp.h"
32
#include "dvmrpe.h"
33
#include "log.h"
34
#include "control.h"
35
36
#define	CONTROL_BACKLOG	5
37
38
struct ctl_conn	*control_connbyfd(int);
39
struct ctl_conn	*control_connbypid(pid_t);
40
void		 control_close(int);
41
42
int
43
control_init(void)
44
{
45
	struct sockaddr_un	 sun;
46
	int			 fd;
47
	mode_t			 old_umask;
48
49
	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
50
	    0)) == -1) {
51
		log_warn("control_init: socket");
52
		return (-1);
53
	}
54
55
	memset(&sun, 0, sizeof(sun));
56
	sun.sun_family = AF_UNIX;
57
	strlcpy(sun.sun_path, DVMRPD_SOCKET, sizeof(sun.sun_path));
58
59
	if (unlink(DVMRPD_SOCKET) == -1)
60
		if (errno != ENOENT) {
61
			log_warn("control_init: unlink %s", DVMRPD_SOCKET);
62
			close(fd);
63
			return (-1);
64
		}
65
66
	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
67
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
68
		log_warn("control_init: bind: %s", DVMRPD_SOCKET);
69
		close(fd);
70
		umask(old_umask);
71
		return (-1);
72
	}
73
	umask(old_umask);
74
75
	if (chmod(DVMRPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
76
		log_warn("control_init: chmod");
77
		close(fd);
78
		(void)unlink(DVMRPD_SOCKET);
79
		return (-1);
80
	}
81
82
	control_state.fd = fd;
83
84
	return (0);
85
}
86
87
int
88
control_listen(void)
89
{
90
91
	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
92
		log_warn("control_listen: listen");
93
		return (-1);
94
	}
95
96
	event_set(&control_state.ev, control_state.fd, EV_READ,
97
	    control_accept, NULL);
98
	event_add(&control_state.ev, NULL);
99
	evtimer_set(&control_state.evt, control_accept, NULL);
100
101
	return (0);
102
}
103
104
void
105
control_cleanup(void)
106
{
107
	event_del(&control_state.ev);
108
	event_del(&control_state.evt);
109
	unlink(DVMRPD_SOCKET);
110
}
111
112
/* ARGSUSED */
113
void
114
control_accept(int listenfd, short event, void *bula)
115
{
116
	int			 connfd;
117
	socklen_t		 len;
118
	struct sockaddr_un	 sun;
119
	struct ctl_conn		*c;
120
121
	event_add(&control_state.ev, NULL);
122
	if ((event & EV_TIMEOUT))
123
		return;
124
125
	len = sizeof(sun);
126
	if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len,
127
	    SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) {
128
		/*
129
		 * Pause accept if we are out of file descriptors, or
130
		 * libevent will haunt us here too.
131
		 */
132
		if (errno == ENFILE || errno == EMFILE) {
133
			struct timeval evtpause = { 1, 0 };
134
135
			event_del(&control_state.ev);
136
			evtimer_add(&control_state.evt, &evtpause);
137
		} else if (errno != EWOULDBLOCK && errno != EINTR &&
138
		    errno != ECONNABORTED)
139
			log_warn("control_accept: accept");
140
		return;
141
	}
142
143
	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
144
		log_warn("control_accept");
145
		close(connfd);
146
		return;
147
	}
148
149
	imsg_init(&c->iev.ibuf, connfd);
150
	c->iev.handler = control_dispatch_imsg;
151
	c->iev.events = EV_READ;
152
	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
153
	    c->iev.handler, &c->iev);
154
	event_add(&c->iev.ev, NULL);
155
156
	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
157
}
158
159
struct ctl_conn *
160
control_connbyfd(int fd)
161
{
162
	struct ctl_conn	*c;
163
164
	TAILQ_FOREACH(c, &ctl_conns, entry) {
165
		if (c->iev.ibuf.fd == fd)
166
			break;
167
	}
168
169
	return (c);
170
}
171
172
struct ctl_conn *
173
control_connbypid(pid_t pid)
174
{
175
	struct ctl_conn	*c;
176
177
	TAILQ_FOREACH(c, &ctl_conns, entry) {
178
		if (c->iev.ibuf.pid == pid)
179
			break;
180
	}
181
182
	return (c);
183
}
184
185
void
186
control_close(int fd)
187
{
188
	struct ctl_conn	*c;
189
190
	if ((c = control_connbyfd(fd)) == NULL) {
191
		log_warn("control_close: fd %d: not found", fd);
192
		return;
193
	}
194
195
	msgbuf_clear(&c->iev.ibuf.w);
196
	TAILQ_REMOVE(&ctl_conns, c, entry);
197
198
	event_del(&c->iev.ev);
199
	close(c->iev.ibuf.fd);
200
201
	/* Some file descriptors are available again. */
202
	if (evtimer_pending(&control_state.evt, NULL)) {
203
		evtimer_del(&control_state.evt);
204
		event_add(&control_state.ev, NULL);
205
	}
206
207
	free(c);
208
}
209
210
/* ARGSUSED */
211
void
212
control_dispatch_imsg(int fd, short event, void *bula)
213
{
214
	struct ctl_conn	*c;
215
	struct imsg	 imsg;
216
	int		 n;
217
	unsigned int	 ifidx;
218
	int		 verbose;
219
220
	if ((c = control_connbyfd(fd)) == NULL) {
221
		log_warn("control_dispatch_imsg: fd %d: not found", fd);
222
		return;
223
	}
224
225
	if (event & EV_READ) {
226
		if (((n = imsg_read(&c->iev.ibuf)) == -1  && errno != EAGAIN) ||
227
		    n == 0) {
228
			control_close(fd);
229
			return;
230
		}
231
	}
232
	if (event & EV_WRITE) {
233
		if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
234
			control_close(fd);
235
			return;
236
		}
237
	}
238
239
	for (;;) {
240
		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
241
			control_close(fd);
242
			return;
243
		}
244
245
		if (n == 0)
246
			break;
247
248
		switch (imsg.hdr.type) {
249
		case IMSG_CTL_MFC_COUPLE:
250
		case IMSG_CTL_MFC_DECOUPLE:
251
		case IMSG_CTL_RELOAD:
252
			dvmrpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
253
			break;
254
		case IMSG_CTL_SHOW_IFACE:
255
			if (imsg.hdr.len == IMSG_HEADER_SIZE +
256
			    sizeof(ifidx)) {
257
				memcpy(&ifidx, imsg.data, sizeof(ifidx));
258
				dvmrpe_iface_ctl(c, ifidx);
259
				imsg_compose_event(&c->iev, IMSG_CTL_END, 0,
260
				    0, -1, NULL, 0);
261
			}
262
			break;
263
		case IMSG_CTL_SHOW_IGMP:
264
			if (imsg.hdr.len == IMSG_HEADER_SIZE +
265
			    sizeof(ifidx)) {
266
				memcpy(&ifidx, imsg.data, sizeof(ifidx));
267
				dvmrpe_iface_igmp_ctl(c, ifidx);
268
				imsg_compose_event(&c->iev, IMSG_CTL_END, 0,
269
				    0, -1, NULL, 0);
270
			}
271
			break;
272
		case IMSG_CTL_SHOW_NBR:
273
			dvmrpe_nbr_ctl(c);
274
			break;
275
		case IMSG_CTL_SHOW_RIB:
276
		case IMSG_CTL_SHOW_MFC:
277
		case IMSG_CTL_SHOW_SUM:
278
			c->iev.ibuf.pid = imsg.hdr.pid;
279
			dvmrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
280
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
281
			break;
282
		case IMSG_CTL_LOG_VERBOSE:
283
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
284
			    sizeof(verbose))
285
				break;
286
287
			/* forward to other processes */
288
			dvmrpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
289
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
290
			dvmrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
291
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
292
293
			memcpy(&verbose, imsg.data, sizeof(verbose));
294
			log_verbose(verbose);
295
			break;
296
		default:
297
			log_debug("control_dispatch_imsg: "
298
			    "error handling imsg %d", imsg.hdr.type);
299
			break;
300
		}
301
		imsg_free(&imsg);
302
	}
303
304
	imsg_event_add(&c->iev);
305
}
306
307
int
308
control_imsg_relay(struct imsg *imsg)
309
{
310
	struct ctl_conn	*c;
311
312
	if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
313
		return (0);
314
315
	return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
316
	    -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
317
}