xref: /openbsd/usr.sbin/dvmrpd/dvmrpd.c (revision b2cc5ec6)
1 /*	$OpenBSD: dvmrpd.c,v 1.26 2021/01/19 12:26:38 claudio 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 	log_procname = "parent";
112 
113 	log_init(1);	/* log to stderr until daemonized */
114 	log_verbose(1);
115 
116 	while ((ch = getopt(argc, argv, "df:nv")) != -1) {
117 		switch (ch) {
118 		case 'd':
119 			debug = 1;
120 			break;
121 		case 'f':
122 			conffile = optarg;
123 			break;
124 		case 'n':
125 			opts |= DVMRPD_OPT_NOACTION;
126 			break;
127 		case 'v':
128 			if (opts & DVMRPD_OPT_VERBOSE)
129 				opts |= DVMRPD_OPT_VERBOSE2;
130 			opts |= DVMRPD_OPT_VERBOSE;
131 			log_verbose(1);
132 			break;
133 		default:
134 			usage();
135 			/* NOTREACHED */
136 		}
137 	}
138 
139 	argc -= optind;
140 	argv += optind;
141 	if (argc > 0)
142 		usage();
143 
144 	log_init(debug);
145 	log_verbose(opts & DVMRPD_OPT_VERBOSE);
146 
147 	/* multicast IP forwarding must be enabled */
148 	mib[0] = CTL_NET;
149 	mib[1] = PF_INET;
150 	mib[2] = IPPROTO_IP;
151 	mib[3] = IPCTL_MFORWARDING;
152 	len = sizeof(ipmforwarding);
153 	if (sysctl(mib, 4, &ipmforwarding, &len, NULL, 0) == -1)
154 		err(1, "sysctl");
155 
156 	if (!ipmforwarding)
157 		errx(1, "multicast IP forwarding not enabled");
158 
159 	/* fetch interfaces early */
160 	kif_init();
161 
162 	/* parse config file */
163 	if ((conf = parse_config(conffile, opts)) == NULL )
164 		exit(1);
165 
166 	if (conf->opts & DVMRPD_OPT_NOACTION) {
167 		if (conf->opts & DVMRPD_OPT_VERBOSE)
168 			print_config(conf);
169 		else
170 			fprintf(stderr, "configuration OK\n");
171 		exit(0);
172 	}
173 
174 	/* check for root privileges  */
175 	if (geteuid())
176 		errx(1, "need root privileges");
177 
178 	/* check for dvmrpd user */
179 	if (getpwnam(DVMRPD_USER) == NULL)
180 		errx(1, "unknown user %s", DVMRPD_USER);
181 
182 	/* start logging */
183 	log_init(1);
184 
185 	if (!debug)
186 		daemon(1, 0);
187 
188 	log_info("startup");
189 
190 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
191 	    PF_UNSPEC, pipe_parent2dvmrpe) == -1)
192 		fatal("socketpair");
193 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
194 	    PF_UNSPEC, pipe_parent2rde) == -1)
195 		fatal("socketpair");
196 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
197 	    PF_UNSPEC, pipe_dvmrpe2rde) == -1)
198 		fatal("socketpair");
199 
200 	/* start children */
201 	rde_pid = rde(conf, pipe_parent2rde, pipe_dvmrpe2rde,
202 	    pipe_parent2dvmrpe);
203 	dvmrpe_pid = dvmrpe(conf, pipe_parent2dvmrpe, pipe_dvmrpe2rde,
204 	    pipe_parent2rde);
205 
206 	/* create the raw ip socket */
207 	if ((conf->mroute_socket = socket(AF_INET,
208 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
209 	    IPPROTO_IGMP)) == -1)
210 		fatal("error creating raw socket");
211 
212 	if_set_recvbuf(conf->mroute_socket);
213 
214 	if (mrt_init(conf->mroute_socket))
215 		fatal("multicast routing not enabled in kernel");
216 
217 	event_init();
218 
219 	/* setup signal handler */
220 	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
221 	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
222 	signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
223 	signal_add(&ev_sigint, NULL);
224 	signal_add(&ev_sigterm, NULL);
225 	signal_add(&ev_sighup, NULL);
226 	signal(SIGPIPE, SIG_IGN);
227 
228 	/* setup pipes to children */
229 	close(pipe_parent2dvmrpe[1]);
230 	close(pipe_parent2rde[1]);
231 	close(pipe_dvmrpe2rde[0]);
232 	close(pipe_dvmrpe2rde[1]);
233 
234 	if ((iev_dvmrpe = malloc(sizeof(struct imsgev))) == NULL ||
235 	    (iev_rde = malloc(sizeof(struct imsgev))) == NULL)
236 		fatal(NULL);
237 	imsg_init(&iev_dvmrpe->ibuf, pipe_parent2dvmrpe[0]);
238 	imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]);
239 	iev_dvmrpe->handler =  main_dispatch_dvmrpe;
240 	iev_rde->handler = main_dispatch_rde;
241 
242 	/* setup event handler */
243 	iev_dvmrpe->events = EV_READ;
244 	event_set(&iev_dvmrpe->ev, iev_dvmrpe->ibuf.fd, iev_dvmrpe->events,
245 	    iev_dvmrpe->handler, iev_dvmrpe);
246 	event_add(&iev_dvmrpe->ev, NULL);
247 
248 	iev_rde->events = EV_READ;
249 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
250 	    iev_rde->handler, iev_rde);
251 	event_add(&iev_rde->ev, NULL);
252 
253 	if (kmr_init(!(conf->flags & DVMRPD_FLAG_NO_FIB_UPDATE)) == -1)
254 		dvmrpd_shutdown();
255 	if (kr_init() == -1)
256 		dvmrpd_shutdown();
257 
258 	event_set(&conf->ev, conf->mroute_socket, EV_READ|EV_PERSIST,
259 	    kmr_recv_msg, conf);
260 	event_add(&conf->ev, NULL);
261 
262 	event_dispatch();
263 
264 	dvmrpd_shutdown();
265 	/* NOTREACHED */
266 	return (0);
267 }
268 
269 __dead void
270 dvmrpd_shutdown(void)
271 {
272 	struct iface	*iface;
273 	pid_t		 pid;
274 	int		 status;
275 
276 	/* close pipes */
277 	msgbuf_clear(&iev_dvmrpe->ibuf.w);
278 	close(iev_dvmrpe->ibuf.fd);
279 	msgbuf_clear(&iev_rde->ibuf.w);
280 	close(iev_rde->ibuf.fd);
281 
282 	control_cleanup();
283 	kmr_shutdown();
284 	kr_shutdown();
285 	LIST_FOREACH(iface, &conf->iface_list, entry) {
286 		if_del(iface);
287 	}
288 	mrt_done(conf->mroute_socket);
289 
290 	log_debug("waiting for children to terminate");
291 	do {
292 		pid = wait(&status);
293 		if (pid == -1) {
294 			if (errno != EINTR && errno != ECHILD)
295 				fatal("wait");
296 		} else if (WIFSIGNALED(status))
297 			log_warnx("%s terminated; signal %d",
298 			    (pid == rde_pid) ? "route decision engine" :
299 			    "dvmrp engine", WTERMSIG(status));
300 	} while (pid != -1 || (pid == -1 && errno == EINTR));
301 
302 	free(iev_dvmrpe);
303 	free(iev_rde);
304 
305 	log_info("terminating");
306 	exit(0);
307 }
308 
309 /* imsg handling */
310 void
311 main_dispatch_dvmrpe(int fd, short event, void *bula)
312 {
313 	struct imsgev	*iev = bula;
314 	struct imsgbuf  *ibuf = &iev->ibuf;
315 	struct imsg	 imsg;
316 	ssize_t		 n;
317 	int		 shut = 0, verbose;
318 
319 	if (event & EV_READ) {
320 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
321 			fatal("imsg_read error");
322 		if (n == 0)	/* connection closed */
323 			shut = 1;
324 	}
325 	if (event & EV_WRITE) {
326 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
327 			fatal("msgbuf_write");
328 		if (n == 0)	/* connection closed */
329 			shut = 1;
330 	}
331 
332 	for (;;) {
333 		if ((n = imsg_get(ibuf, &imsg)) == -1)
334 			fatal("imsg_get");
335 
336 		if (n == 0)
337 			break;
338 
339 		switch (imsg.hdr.type) {
340 		case IMSG_CTL_RELOAD:
341 			log_debug("main_dispatch_dvmrpe: IMSG_CTL_RELOAD");
342 			/* reconfig */
343 			break;
344 		case IMSG_CTL_MFC_COUPLE:
345 			kmr_mfc_couple();
346 			break;
347 		case IMSG_CTL_MFC_DECOUPLE:
348 			kmr_mfc_decouple();
349 			break;
350 		case IMSG_CTL_LOG_VERBOSE:
351 			/* already checked by dvmrpe */
352 			memcpy(&verbose, imsg.data, sizeof(verbose));
353 			log_verbose(verbose);
354 			break;
355 		default:
356 			log_debug("main_dispatch_dvmrpe: error handling "
357 			    "imsg %d", imsg.hdr.type);
358 			break;
359 		}
360 		imsg_free(&imsg);
361 	}
362 	if (!shut)
363 		imsg_event_add(iev);
364 	else {
365 		/* this pipe is dead, so remove the event handler */
366 		event_del(&iev->ev);
367 		event_loopexit(NULL);
368 	}
369 }
370 
371 void
372 main_dispatch_rde(int fd, short event, void *bula)
373 {
374 	struct mfc	 mfc;
375 	struct imsgev	*iev = bula;
376 	struct imsgbuf  *ibuf = &iev->ibuf;
377 	struct imsg	 imsg;
378 	ssize_t		 n;
379 	int		 shut = 0;
380 
381 	if (event & EV_READ) {
382 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
383 			fatal("imsg_read error");
384 		if (n == 0)	/* connection closed */
385 			shut = 1;
386 	}
387 	if (event & EV_WRITE) {
388 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
389 			fatal("msgbuf_write");
390 		if (n == 0)	/* connection closed */
391 			shut = 1;
392 	}
393 
394 	for (;;) {
395 		if ((n = imsg_get(ibuf, &imsg)) == -1)
396 			fatal("imsg_get");
397 
398 		if (n == 0)
399 			break;
400 
401 		switch (imsg.hdr.type) {
402 		case IMSG_MFC_ADD:
403 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
404 				fatalx("invalid size of RDE request");
405 			memcpy(&mfc, imsg.data, sizeof(mfc));
406 
407 			/* add to MFC */
408 			mrt_add_mfc(conf->mroute_socket, &mfc);
409 			break;
410 		case IMSG_MFC_DEL:
411 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
412 				fatalx("invalid size of RDE request");
413 			memcpy(&mfc, imsg.data, sizeof(mfc));
414 
415 			/* remove from MFC */
416 			mrt_del_mfc(conf->mroute_socket, &mfc);
417 			break;
418 		default:
419 			log_debug("main_dispatch_rde: error handling imsg %d",
420 			    imsg.hdr.type);
421 			break;
422 		}
423 		imsg_free(&imsg);
424 	}
425 	if (!shut)
426 		imsg_event_add(iev);
427 	else {
428 		/* this pipe is dead, so remove the event handler */
429 		event_del(&iev->ev);
430 		event_loopexit(NULL);
431 	}
432 }
433 
434 void
435 main_imsg_compose_dvmrpe(int type, pid_t pid, void *data, u_int16_t datalen)
436 {
437 	imsg_compose_event(iev_dvmrpe, type, 0, pid, -1, data, datalen);
438 }
439 
440 void
441 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
442 {
443 	imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
444 }
445 
446 void
447 imsg_event_add(struct imsgev *iev)
448 {
449 	iev->events = EV_READ;
450 	if (iev->ibuf.w.queued)
451 		iev->events |= EV_WRITE;
452 
453 	event_del(&iev->ev);
454 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
455 	event_add(&iev->ev, NULL);
456 }
457 
458 int
459 imsg_compose_event(struct imsgev *iev, u_int16_t type,
460     u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
461 {
462 	int	ret;
463 
464 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
465 	    pid, fd, data, datalen)) != -1)
466 		imsg_event_add(iev);
467 	return (ret);
468 }
469