xref: /openbsd-src/usr.sbin/dvmrpd/dvmrpd.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1 /*	$OpenBSD: dvmrpd.c,v 1.34 2024/11/21 13:38:14 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 static struct imsgev	*iev_dvmrpe;
66 static 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 	if (imsgbuf_init(&iev_dvmrpe->ibuf, pipe_parent2dvmrpe[0]) == -1 ||
238 	    imsgbuf_init(&iev_rde->ibuf, pipe_parent2rde[0]) == -1)
239 		fatal(NULL);
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 	imsgbuf_clear(&iev_dvmrpe->ibuf);
279 	close(iev_dvmrpe->ibuf.fd);
280 	imsgbuf_clear(&iev_rde->ibuf);
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 = imsgbuf_read(ibuf)) == -1)
322 			fatal("imsgbuf_read error");
323 		if (n == 0)	/* connection closed */
324 			shut = 1;
325 	}
326 	if (event & EV_WRITE) {
327 		if (imsgbuf_write(ibuf) == -1) {
328 			if (errno == EPIPE)	/* connection closed */
329 				shut = 1;
330 			else
331 				fatal("imsgbuf_write");
332 		}
333 	}
334 
335 	for (;;) {
336 		if ((n = imsg_get(ibuf, &imsg)) == -1)
337 			fatal("imsg_get");
338 
339 		if (n == 0)
340 			break;
341 
342 		switch (imsg.hdr.type) {
343 		case IMSG_CTL_RELOAD:
344 			log_debug("main_dispatch_dvmrpe: IMSG_CTL_RELOAD");
345 			/* reconfig */
346 			break;
347 		case IMSG_CTL_MFC_COUPLE:
348 			kmr_mfc_couple();
349 			break;
350 		case IMSG_CTL_MFC_DECOUPLE:
351 			kmr_mfc_decouple();
352 			break;
353 		case IMSG_CTL_LOG_VERBOSE:
354 			/* already checked by dvmrpe */
355 			memcpy(&verbose, imsg.data, sizeof(verbose));
356 			log_verbose(verbose);
357 			break;
358 		default:
359 			log_debug("main_dispatch_dvmrpe: error handling "
360 			    "imsg %d", imsg.hdr.type);
361 			break;
362 		}
363 		imsg_free(&imsg);
364 	}
365 	if (!shut)
366 		imsg_event_add(iev);
367 	else {
368 		/* this pipe is dead, so remove the event handler */
369 		event_del(&iev->ev);
370 		event_loopexit(NULL);
371 	}
372 }
373 
374 void
375 main_dispatch_rde(int fd, short event, void *bula)
376 {
377 	struct mfc	 mfc;
378 	struct imsgev	*iev = bula;
379 	struct imsgbuf  *ibuf = &iev->ibuf;
380 	struct imsg	 imsg;
381 	ssize_t		 n;
382 	int		 shut = 0;
383 
384 	if (event & EV_READ) {
385 		if ((n = imsgbuf_read(ibuf)) == -1)
386 			fatal("imsgbuf_read error");
387 		if (n == 0)	/* connection closed */
388 			shut = 1;
389 	}
390 	if (event & EV_WRITE) {
391 		if (imsgbuf_write(ibuf) == -1) {
392 			if (errno == EPIPE)	/* connection closed */
393 				shut = 1;
394 			else
395 				fatal("imsgbuf_write");
396 		}
397 	}
398 
399 	for (;;) {
400 		if ((n = imsg_get(ibuf, &imsg)) == -1)
401 			fatal("imsg_get");
402 
403 		if (n == 0)
404 			break;
405 
406 		switch (imsg.hdr.type) {
407 		case IMSG_MFC_ADD:
408 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
409 				fatalx("invalid size of RDE request");
410 			memcpy(&mfc, imsg.data, sizeof(mfc));
411 
412 			/* add to MFC */
413 			mrt_add_mfc(conf->mroute_socket, &mfc);
414 			break;
415 		case IMSG_MFC_DEL:
416 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
417 				fatalx("invalid size of RDE request");
418 			memcpy(&mfc, imsg.data, sizeof(mfc));
419 
420 			/* remove from MFC */
421 			mrt_del_mfc(conf->mroute_socket, &mfc);
422 			break;
423 		default:
424 			log_debug("main_dispatch_rde: error handling imsg %d",
425 			    imsg.hdr.type);
426 			break;
427 		}
428 		imsg_free(&imsg);
429 	}
430 	if (!shut)
431 		imsg_event_add(iev);
432 	else {
433 		/* this pipe is dead, so remove the event handler */
434 		event_del(&iev->ev);
435 		event_loopexit(NULL);
436 	}
437 }
438 
439 void
440 main_imsg_compose_dvmrpe(int type, pid_t pid, void *data, u_int16_t datalen)
441 {
442 	imsg_compose_event(iev_dvmrpe, type, 0, pid, -1, data, datalen);
443 }
444 
445 void
446 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
447 {
448 	imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
449 }
450 
451 void
452 imsg_event_add(struct imsgev *iev)
453 {
454 	iev->events = EV_READ;
455 	if (imsgbuf_queuelen(&iev->ibuf) > 0)
456 		iev->events |= EV_WRITE;
457 
458 	event_del(&iev->ev);
459 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
460 	event_add(&iev->ev, NULL);
461 }
462 
463 int
464 imsg_compose_event(struct imsgev *iev, u_int16_t type,
465     u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
466 {
467 	int	ret;
468 
469 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
470 	    pid, fd, data, datalen)) != -1)
471 		imsg_event_add(iev);
472 	return (ret);
473 }
474