GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/dvmrpd.c Lines: 0 217 0.0 %
Date: 2017-11-07 Branches: 0 127 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: dvmrpd.c,v 1.25 2016/09/02 16:20:34 benno Exp $ */
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
6
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/socket.h>
23
#include <sys/queue.h>
24
#include <sys/time.h>
25
#include <sys/stat.h>
26
#include <sys/sysctl.h>
27
#include <sys/wait.h>
28
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
31
32
#include <event.h>
33
#include <err.h>
34
#include <errno.h>
35
#include <pwd.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <signal.h>
40
#include <unistd.h>
41
#include <util.h>
42
43
#include "igmp.h"
44
#include "dvmrpd.h"
45
#include "dvmrp.h"
46
#include "dvmrpe.h"
47
#include "control.h"
48
#include "log.h"
49
#include "rde.h"
50
51
void		main_sig_handler(int, short, void *);
52
__dead void	usage(void);
53
__dead void	dvmrpd_shutdown(void);
54
55
void	main_dispatch_dvmrpe(int, short, void *);
56
void	main_dispatch_rde(int, short, void *);
57
void	main_imsg_compose_dvmrpe(int, pid_t, void *, u_int16_t);
58
void	main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
59
60
int	pipe_parent2dvmrpe[2];
61
int	pipe_parent2rde[2];
62
int	pipe_dvmrpe2rde[2];
63
64
struct dvmrpd_conf	*conf = NULL;
65
struct imsgev		*iev_dvmrpe;
66
struct imsgev		*iev_rde;
67
68
pid_t			 dvmrpe_pid;
69
pid_t			 rde_pid;
70
71
void
72
main_sig_handler(int sig, short event, void *arg)
73
{
74
	/* signal handler rules don't apply, libevent decouples for us */
75
	switch (sig) {
76
	case SIGTERM:
77
	case SIGINT:
78
		dvmrpd_shutdown();
79
		/* NOTREACHED */
80
	case SIGHUP:
81
		/* reconfigure */
82
		/* ... */
83
		break;
84
	default:
85
		fatalx("unexpected signal");
86
		/* NOTREACHED */
87
	}
88
}
89
90
__dead void
91
usage(void)
92
{
93
	extern char *__progname;
94
95
	fprintf(stderr, "usage: %s [-dnv] [-f file]\n", __progname);
96
	exit(1);
97
}
98
99
int
100
main(int argc, char *argv[])
101
{
102
	struct event	 ev_sigint, ev_sigterm, ev_sighup;
103
	char		*conffile;
104
	int		 ch, opts = 0;
105
	int		 debug = 0;
106
	int		 ipmforwarding;
107
	int		 mib[4];
108
	size_t		 len;
109
110
	conffile = CONF_FILE;
111
	dvmrpd_process = PROC_MAIN;
112
	log_procname = log_procnames[dvmrpd_process];
113
114
	log_init(1);	/* log to stderr until daemonized */
115
	log_verbose(1);
116
117
	while ((ch = getopt(argc, argv, "df:nv")) != -1) {
118
		switch (ch) {
119
		case 'd':
120
			debug = 1;
121
			break;
122
		case 'f':
123
			conffile = optarg;
124
			break;
125
		case 'n':
126
			opts |= DVMRPD_OPT_NOACTION;
127
			break;
128
		case 'v':
129
			if (opts & DVMRPD_OPT_VERBOSE)
130
				opts |= DVMRPD_OPT_VERBOSE2;
131
			opts |= DVMRPD_OPT_VERBOSE;
132
			log_verbose(1);
133
			break;
134
		default:
135
			usage();
136
			/* NOTREACHED */
137
		}
138
	}
139
140
	argc -= optind;
141
	argv += optind;
142
	if (argc > 0)
143
		usage();
144
145
	log_init(debug);
146
	log_verbose(opts & DVMRPD_OPT_VERBOSE);
147
148
	/* multicast IP forwarding must be enabled */
149
	mib[0] = CTL_NET;
150
	mib[1] = PF_INET;
151
	mib[2] = IPPROTO_IP;
152
	mib[3] = IPCTL_MFORWARDING;
153
	len = sizeof(ipmforwarding);
154
	if (sysctl(mib, 4, &ipmforwarding, &len, NULL, 0) == -1)
155
		err(1, "sysctl");
156
157
	if (!ipmforwarding)
158
		errx(1, "multicast IP forwarding not enabled");
159
160
	/* fetch interfaces early */
161
	kif_init();
162
163
	/* parse config file */
164
	if ((conf = parse_config(conffile, opts)) == NULL )
165
		exit(1);
166
167
	if (conf->opts & DVMRPD_OPT_NOACTION) {
168
		if (conf->opts & DVMRPD_OPT_VERBOSE)
169
			print_config(conf);
170
		else
171
			fprintf(stderr, "configuration OK\n");
172
		exit(0);
173
	}
174
175
	/* check for root privileges  */
176
	if (geteuid())
177
		errx(1, "need root privileges");
178
179
	/* check for dvmrpd user */
180
	if (getpwnam(DVMRPD_USER) == NULL)
181
		errx(1, "unknown user %s", DVMRPD_USER);
182
183
	/* start logging */
184
	log_init(1);
185
186
	if (!debug)
187
		daemon(1, 0);
188
189
	log_info("startup");
190
191
	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
192
	    PF_UNSPEC, pipe_parent2dvmrpe) == -1)
193
		fatal("socketpair");
194
	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
195
	    PF_UNSPEC, pipe_parent2rde) == -1)
196
		fatal("socketpair");
197
	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
198
	    PF_UNSPEC, pipe_dvmrpe2rde) == -1)
199
		fatal("socketpair");
200
201
	/* start children */
202
	rde_pid = rde(conf, pipe_parent2rde, pipe_dvmrpe2rde,
203
	    pipe_parent2dvmrpe);
204
	dvmrpe_pid = dvmrpe(conf, pipe_parent2dvmrpe, pipe_dvmrpe2rde,
205
	    pipe_parent2rde);
206
207
	/* create the raw ip socket */
208
	if ((conf->mroute_socket = socket(AF_INET,
209
	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
210
	    IPPROTO_IGMP)) == -1)
211
		fatal("error creating raw socket");
212
213
	if_set_recvbuf(conf->mroute_socket);
214
215
	if (mrt_init(conf->mroute_socket))
216
		fatal("multicast routing not enabled in kernel");
217
218
	event_init();
219
220
	/* setup signal handler */
221
	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
222
	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
223
	signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
224
	signal_add(&ev_sigint, NULL);
225
	signal_add(&ev_sigterm, NULL);
226
	signal_add(&ev_sighup, NULL);
227
	signal(SIGPIPE, SIG_IGN);
228
229
	/* setup pipes to children */
230
	close(pipe_parent2dvmrpe[1]);
231
	close(pipe_parent2rde[1]);
232
	close(pipe_dvmrpe2rde[0]);
233
	close(pipe_dvmrpe2rde[1]);
234
235
	if ((iev_dvmrpe = malloc(sizeof(struct imsgev))) == NULL ||
236
	    (iev_rde = malloc(sizeof(struct imsgev))) == NULL)
237
		fatal(NULL);
238
	imsg_init(&iev_dvmrpe->ibuf, pipe_parent2dvmrpe[0]);
239
	imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]);
240
	iev_dvmrpe->handler =  main_dispatch_dvmrpe;
241
	iev_rde->handler = main_dispatch_rde;
242
243
	/* setup event handler */
244
	iev_dvmrpe->events = EV_READ;
245
	event_set(&iev_dvmrpe->ev, iev_dvmrpe->ibuf.fd, iev_dvmrpe->events,
246
	    iev_dvmrpe->handler, iev_dvmrpe);
247
	event_add(&iev_dvmrpe->ev, NULL);
248
249
	iev_rde->events = EV_READ;
250
	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
251
	    iev_rde->handler, iev_rde);
252
	event_add(&iev_rde->ev, NULL);
253
254
	if (kmr_init(!(conf->flags & DVMRPD_FLAG_NO_FIB_UPDATE)) == -1)
255
		dvmrpd_shutdown();
256
	if (kr_init() == -1)
257
		dvmrpd_shutdown();
258
259
	event_set(&conf->ev, conf->mroute_socket, EV_READ|EV_PERSIST,
260
	    kmr_recv_msg, conf);
261
	event_add(&conf->ev, NULL);
262
263
	event_dispatch();
264
265
	dvmrpd_shutdown();
266
	/* NOTREACHED */
267
	return (0);
268
}
269
270
__dead void
271
dvmrpd_shutdown(void)
272
{
273
	struct iface	*iface;
274
	pid_t		 pid;
275
	int		 status;
276
277
	/* close pipes */
278
	msgbuf_clear(&iev_dvmrpe->ibuf.w);
279
	close(iev_dvmrpe->ibuf.fd);
280
	msgbuf_clear(&iev_rde->ibuf.w);
281
	close(iev_rde->ibuf.fd);
282
283
	control_cleanup();
284
	kmr_shutdown();
285
	kr_shutdown();
286
	LIST_FOREACH(iface, &conf->iface_list, entry) {
287
		if_del(iface);
288
	}
289
	mrt_done(conf->mroute_socket);
290
291
	log_debug("waiting for children to terminate");
292
	do {
293
		pid = wait(&status);
294
		if (pid == -1) {
295
			if (errno != EINTR && errno != ECHILD)
296
				fatal("wait");
297
		} else if (WIFSIGNALED(status))
298
			log_warnx("%s terminated; signal %d",
299
			    (pid == rde_pid) ? "route decision engine" :
300
			    "dvmrp engine", WTERMSIG(status));
301
	} while (pid != -1 || (pid == -1 && errno == EINTR));
302
303
	free(iev_dvmrpe);
304
	free(iev_rde);
305
306
	log_info("terminating");
307
	exit(0);
308
}
309
310
/* imsg handling */
311
void
312
main_dispatch_dvmrpe(int fd, short event, void *bula)
313
{
314
	struct imsgev	*iev = bula;
315
	struct imsgbuf  *ibuf = &iev->ibuf;
316
	struct imsg	 imsg;
317
	ssize_t		 n;
318
	int		 shut = 0, verbose;
319
320
	if (event & EV_READ) {
321
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
322
			fatal("imsg_read error");
323
		if (n == 0)	/* connection closed */
324
			shut = 1;
325
	}
326
	if (event & EV_WRITE) {
327
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
328
			fatal("msgbuf_write");
329
		if (n == 0)	/* connection closed */
330
			shut = 1;
331
	}
332
333
	for (;;) {
334
		if ((n = imsg_get(ibuf, &imsg)) == -1)
335
			fatal("imsg_get");
336
337
		if (n == 0)
338
			break;
339
340
		switch (imsg.hdr.type) {
341
		case IMSG_CTL_RELOAD:
342
			log_debug("main_dispatch_dvmrpe: IMSG_CTL_RELOAD");
343
			/* reconfig */
344
			break;
345
		case IMSG_CTL_MFC_COUPLE:
346
			kmr_mfc_couple();
347
			break;
348
		case IMSG_CTL_MFC_DECOUPLE:
349
			kmr_mfc_decouple();
350
			break;
351
		case IMSG_CTL_LOG_VERBOSE:
352
			/* already checked by dvmrpe */
353
			memcpy(&verbose, imsg.data, sizeof(verbose));
354
			log_verbose(verbose);
355
			break;
356
		default:
357
			log_debug("main_dispatch_dvmrpe: error handling "
358
			    "imsg %d", imsg.hdr.type);
359
			break;
360
		}
361
		imsg_free(&imsg);
362
	}
363
	if (!shut)
364
		imsg_event_add(iev);
365
	else {
366
		/* this pipe is dead, so remove the event handler */
367
		event_del(&iev->ev);
368
		event_loopexit(NULL);
369
	}
370
}
371
372
void
373
main_dispatch_rde(int fd, short event, void *bula)
374
{
375
	struct mfc	 mfc;
376
	struct imsgev	*iev = bula;
377
	struct imsgbuf  *ibuf = &iev->ibuf;
378
	struct imsg	 imsg;
379
	ssize_t		 n;
380
	int		 shut = 0;
381
382
	if (event & EV_READ) {
383
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
384
			fatal("imsg_read error");
385
		if (n == 0)	/* connection closed */
386
			shut = 1;
387
	}
388
	if (event & EV_WRITE) {
389
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
390
			fatal("msgbuf_write");
391
		if (n == 0)	/* connection closed */
392
			shut = 1;
393
	}
394
395
	for (;;) {
396
		if ((n = imsg_get(ibuf, &imsg)) == -1)
397
			fatal("imsg_get");
398
399
		if (n == 0)
400
			break;
401
402
		switch (imsg.hdr.type) {
403
		case IMSG_MFC_ADD:
404
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
405
				fatalx("invalid size of RDE request");
406
			memcpy(&mfc, imsg.data, sizeof(mfc));
407
408
			/* add to MFC */
409
			mrt_add_mfc(conf->mroute_socket, &mfc);
410
			break;
411
		case IMSG_MFC_DEL:
412
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
413
				fatalx("invalid size of RDE request");
414
			memcpy(&mfc, imsg.data, sizeof(mfc));
415
416
			/* remove from MFC */
417
			mrt_del_mfc(conf->mroute_socket, &mfc);
418
			break;
419
		default:
420
			log_debug("main_dispatch_rde: error handling imsg %d",
421
			    imsg.hdr.type);
422
			break;
423
		}
424
		imsg_free(&imsg);
425
	}
426
	if (!shut)
427
		imsg_event_add(iev);
428
	else {
429
		/* this pipe is dead, so remove the event handler */
430
		event_del(&iev->ev);
431
		event_loopexit(NULL);
432
	}
433
}
434
435
void
436
main_imsg_compose_dvmrpe(int type, pid_t pid, void *data, u_int16_t datalen)
437
{
438
	imsg_compose_event(iev_dvmrpe, type, 0, pid, -1, data, datalen);
439
}
440
441
void
442
main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
443
{
444
	imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
445
}
446
447
void
448
imsg_event_add(struct imsgev *iev)
449
{
450
	iev->events = EV_READ;
451
	if (iev->ibuf.w.queued)
452
		iev->events |= EV_WRITE;
453
454
	event_del(&iev->ev);
455
	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
456
	event_add(&iev->ev, NULL);
457
}
458
459
int
460
imsg_compose_event(struct imsgev *iev, u_int16_t type,
461
    u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
462
{
463
	int	ret;
464
465
	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
466
	    pid, fd, data, datalen)) != -1)
467
		imsg_event_add(iev);
468
	return (ret);
469
}