xref: /openbsd/usr.sbin/dvmrpd/dvmrpd.c (revision 20d80477)
1 /*	$OpenBSD: dvmrpd.c,v 1.11 2009/11/02 20:31:50 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/param.h>
27 #include <sys/sysctl.h>
28 #include <sys/wait.h>
29 
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 
33 #include <event.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <pwd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <signal.h>
41 #include <unistd.h>
42 #include <util.h>
43 
44 #include "igmp.h"
45 #include "dvmrpd.h"
46 #include "dvmrp.h"
47 #include "dvmrpe.h"
48 #include "control.h"
49 #include "log.h"
50 #include "rde.h"
51 
52 void		main_sig_handler(int, short, void *);
53 __dead void	usage(void);
54 void		dvmrpd_shutdown(void);
55 int		check_child(pid_t, const char *);
56 
57 void	main_dispatch_dvmrpe(int, short, void *);
58 void	main_dispatch_rde(int, short, void *);
59 void	main_imsg_compose_dvmrpe(int, pid_t, void *, u_int16_t);
60 void	main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
61 
62 int	pipe_parent2dvmrpe[2];
63 int	pipe_parent2rde[2];
64 int	pipe_dvmrpe2rde[2];
65 
66 struct dvmrpd_conf	*conf = NULL;
67 struct imsgev		*iev_dvmrpe;
68 struct imsgev		*iev_rde;
69 
70 pid_t			 dvmrpe_pid;
71 pid_t			 rde_pid;
72 
73 void
74 main_sig_handler(int sig, short event, void *arg)
75 {
76 	/*
77 	 * signal handler rules don't apply, libevent decouples for us
78 	 */
79 	int	die = 0;
80 
81 	switch (sig) {
82 	case SIGTERM:
83 	case SIGINT:
84 		die = 1;
85 		/* FALLTHROUGH */
86 	case SIGCHLD:
87 		if (check_child(dvmrpe_pid, "dvmrp engine")) {
88 			dvmrpe_pid = 0;
89 			die = 1;
90 		}
91 		if (check_child(rde_pid, "route decision engine")) {
92 			rde_pid = 0;
93 			die = 1;
94 		}
95 		if (die)
96 			dvmrpd_shutdown();
97 		break;
98 	case SIGHUP:
99 		/* reconfigure */
100 		/* ... */
101 		break;
102 	default:
103 		fatalx("unexpected signal");
104 		/* NOTREACHED */
105 	}
106 }
107 
108 __dead void
109 usage(void)
110 {
111 	extern char *__progname;
112 
113 	fprintf(stderr, "usage: %s [-dnv] [-f file]\n", __progname);
114 	exit(1);
115 }
116 
117 int
118 main(int argc, char *argv[])
119 {
120 	struct event	 ev_sigint, ev_sigterm, ev_sigchld, ev_sighup;
121 	char		*conffile;
122 	int		 ch, opts = 0;
123 	int		 debug = 0;
124 	int		 ipmforwarding;
125 	int		 mib[4];
126 	size_t		 len;
127 
128 	conffile = CONF_FILE;
129 	dvmrpd_process = PROC_MAIN;
130 
131 	log_init(1);	/* log to stderr until daemonized */
132 
133 	while ((ch = getopt(argc, argv, "df:nv")) != -1) {
134 		switch (ch) {
135 		case 'd':
136 			debug = 1;
137 			break;
138 		case 'f':
139 			conffile = optarg;
140 			break;
141 		case 'n':
142 			opts |= DVMRPD_OPT_NOACTION;
143 			break;
144 		case 'v':
145 			if (opts & DVMRPD_OPT_VERBOSE)
146 				opts |= DVMRPD_OPT_VERBOSE2;
147 			opts |= DVMRPD_OPT_VERBOSE;
148 			log_verbose(1);
149 			break;
150 		default:
151 			usage();
152 			/* NOTREACHED */
153 		}
154 	}
155 
156 	argc -= optind;
157 	argv += optind;
158 	if (argc > 0)
159 		usage();
160 
161 	log_init(debug);
162 
163 	/* multicast IP forwarding must be enabled */
164 	mib[0] = CTL_NET;
165 	mib[1] = PF_INET;
166 	mib[2] = IPPROTO_IP;
167 	mib[3] = IPCTL_MFORWARDING;
168 	len = sizeof(ipmforwarding);
169 	if (sysctl(mib, 4, &ipmforwarding, &len, NULL, 0) == -1)
170 		err(1, "sysctl");
171 
172 	if (!ipmforwarding)
173 		errx(1, "multicast IP forwarding not enabled");
174 
175 	/* fetch interfaces early */
176 	kif_init();
177 
178 	/* parse config file */
179 	if ((conf = parse_config(conffile, opts)) == NULL )
180 		exit(1);
181 
182 	if (conf->opts & DVMRPD_OPT_NOACTION) {
183 		if (conf->opts & DVMRPD_OPT_VERBOSE)
184 			print_config(conf);
185 		else
186 			fprintf(stderr, "configuration OK\n");
187 		exit(0);
188 	}
189 
190 	/* check for root privileges  */
191 	if (geteuid())
192 		errx(1, "need root privileges");
193 
194 	/* check for dvmrpd user */
195 	if (getpwnam(DVMRPD_USER) == NULL)
196 		errx(1, "unknown user %s", DVMRPD_USER);
197 
198 	/* start logging */
199 	log_init(1);
200 
201 	if (!debug)
202 		daemon(1, 0);
203 
204 	log_info("startup");
205 
206 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
207 	    pipe_parent2dvmrpe) == -1)
208 		fatal("socketpair");
209 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2rde) == -1)
210 		fatal("socketpair");
211 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_dvmrpe2rde) == -1)
212 		fatal("socketpair");
213 	session_socket_blockmode(pipe_parent2dvmrpe[0], BM_NONBLOCK);
214 	session_socket_blockmode(pipe_parent2dvmrpe[1], BM_NONBLOCK);
215 	session_socket_blockmode(pipe_parent2rde[0], BM_NONBLOCK);
216 	session_socket_blockmode(pipe_parent2rde[1], BM_NONBLOCK);
217 	session_socket_blockmode(pipe_dvmrpe2rde[0], BM_NONBLOCK);
218 	session_socket_blockmode(pipe_dvmrpe2rde[1], BM_NONBLOCK);
219 
220 	/* start children */
221 	rde_pid = rde(conf, pipe_parent2rde, pipe_dvmrpe2rde,
222 	    pipe_parent2dvmrpe);
223 	dvmrpe_pid = dvmrpe(conf, pipe_parent2dvmrpe, pipe_dvmrpe2rde,
224 	    pipe_parent2rde);
225 
226 	/* create the raw ip socket */
227 	if ((conf->mroute_socket = socket(AF_INET, SOCK_RAW,
228 	    IPPROTO_IGMP)) == -1)
229 		fatal("error creating raw socket");
230 
231 	if_set_recvbuf(conf->mroute_socket);
232 
233 	if (mrt_init(conf->mroute_socket))
234 		fatal("multicast routing not enabled in kernel");
235 
236 	/* show who we are */
237 	setproctitle("parent");
238 
239 	event_init();
240 
241 	/* setup signal handler */
242 	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
243 	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
244 	signal_set(&ev_sigchld, SIGINT, main_sig_handler, NULL);
245 	signal_set(&ev_sighup, SIGTERM, main_sig_handler, NULL);
246 	signal_add(&ev_sigint, NULL);
247 	signal_add(&ev_sigterm, NULL);
248 	signal_add(&ev_sigchld, NULL);
249 	signal_add(&ev_sighup, NULL);
250 	signal(SIGPIPE, SIG_IGN);
251 
252 	/* setup pipes to children */
253 	close(pipe_parent2dvmrpe[1]);
254 	close(pipe_parent2rde[1]);
255 	close(pipe_dvmrpe2rde[0]);
256 	close(pipe_dvmrpe2rde[1]);
257 
258 	if ((iev_dvmrpe = malloc(sizeof(struct imsgev))) == NULL ||
259 	    (iev_rde = malloc(sizeof(struct imsgev))) == NULL)
260 		fatal(NULL);
261 	imsg_init(&iev_dvmrpe->ibuf, pipe_parent2dvmrpe[0]);
262 	imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]);
263 	iev_dvmrpe->handler =  main_dispatch_dvmrpe;
264 	iev_rde->handler = main_dispatch_rde;
265 
266 	/* setup event handler */
267 	iev_dvmrpe->events = EV_READ;
268 	event_set(&iev_dvmrpe->ev, iev_dvmrpe->ibuf.fd, iev_dvmrpe->events,
269 	    iev_dvmrpe->handler, iev_dvmrpe);
270 	event_add(&iev_dvmrpe->ev, NULL);
271 
272 	iev_rde->events = EV_READ;
273 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
274 	    iev_rde->handler, iev_rde);
275 	event_add(&iev_rde->ev, NULL);
276 
277 	if (kmr_init(!(conf->flags & DVMRPD_FLAG_NO_FIB_UPDATE)) == -1)
278 		dvmrpd_shutdown();
279 	if (kr_init() == -1)
280 		dvmrpd_shutdown();
281 
282 	event_set(&conf->ev, conf->mroute_socket, EV_READ|EV_PERSIST,
283 	    kmr_recv_msg, conf);
284 	event_add(&conf->ev, NULL);
285 
286 	event_dispatch();
287 
288 	dvmrpd_shutdown();
289 	/* NOTREACHED */
290 	return (0);
291 }
292 
293 void
294 dvmrpd_shutdown(void)
295 {
296 	struct iface	*iface;
297 	pid_t		 pid;
298 
299 	if (dvmrpe_pid)
300 		kill(dvmrpe_pid, SIGTERM);
301 
302 	if (rde_pid)
303 		kill(rde_pid, SIGTERM);
304 
305 	control_cleanup();
306 	kmr_shutdown();
307 	kr_shutdown();
308 
309 	LIST_FOREACH(iface, &conf->iface_list, entry) {
310 		if_del(iface);
311 	}
312 
313 	mrt_done(conf->mroute_socket);
314 
315 	do {
316 		if ((pid = wait(NULL)) == -1 &&
317 		    errno != EINTR && errno != ECHILD)
318 			fatal("wait");
319 	} while (pid != -1 || (pid == -1 && errno == EINTR));
320 
321 	msgbuf_clear(&iev_dvmrpe->ibuf.w);
322 	free(iev_dvmrpe);
323 	msgbuf_clear(&iev_rde->ibuf.w);
324 	free(iev_rde);
325 
326 	log_info("terminating");
327 	exit(0);
328 }
329 
330 int
331 check_child(pid_t pid, const char *pname)
332 {
333 	int	status;
334 
335 	if (waitpid(pid, &status, WNOHANG) > 0) {
336 		if (WIFEXITED(status)) {
337 			log_warnx("lost child: %s exited", pname);
338 			return (1);
339 		}
340 		if (WIFSIGNALED(status)) {
341 			log_warnx("lost child: %s terminated; signal %d",
342 			    pname, WTERMSIG(status));
343 			return (1);
344 		}
345 	}
346 
347 	return (0);
348 }
349 
350 /* imsg handling */
351 void
352 main_dispatch_dvmrpe(int fd, short event, void *bula)
353 {
354 	struct imsgev	*iev = bula;
355 	struct imsgbuf  *ibuf = &iev->ibuf;
356 	struct imsg	 imsg;
357 	ssize_t		 n;
358 	int		 verbose;
359 
360 	if (event & EV_READ) {
361 		if ((n = imsg_read(ibuf)) == -1)
362 			fatal("imsg_read error");
363 		if (n == 0)	/* connection closed */
364 			fatalx("pipe closed");
365 	}
366 	if (event & EV_WRITE) {
367 		if (msgbuf_write(&ibuf->w) == -1)
368 			fatal("msgbuf_write");
369 	}
370 
371 	for (;;) {
372 		if ((n = imsg_get(ibuf, &imsg)) == -1)
373 			fatal("imsg_get");
374 
375 		if (n == 0)
376 			break;
377 
378 		switch (imsg.hdr.type) {
379 		case IMSG_CTL_RELOAD:
380 			log_debug("main_dispatch_dvmrpe: IMSG_CTL_RELOAD");
381 			/* reconfig */
382 			break;
383 		case IMSG_CTL_MFC_COUPLE:
384 			kmr_mfc_couple();
385 			break;
386 		case IMSG_CTL_MFC_DECOUPLE:
387 			kmr_mfc_decouple();
388 			break;
389 		case IMSG_CTL_LOG_VERBOSE:
390 			/* already checked by dvmrpe */
391 			memcpy(&verbose, imsg.data, sizeof(verbose));
392 			log_verbose(verbose);
393 			break;
394 		default:
395 			log_debug("main_dispatch_dvmrpe: error handling "
396 			    "imsg %d", imsg.hdr.type);
397 			break;
398 		}
399 		imsg_free(&imsg);
400 	}
401 	imsg_event_add(iev);
402 }
403 
404 void
405 main_dispatch_rde(int fd, short event, void *bula)
406 {
407 	struct mfc	 mfc;
408 	struct imsgev	*iev = bula;
409 	struct imsgbuf  *ibuf = &iev->ibuf;
410 	struct imsg	 imsg;
411 	ssize_t		 n;
412 
413 	if (event & EV_READ) {
414 		if ((n = imsg_read(ibuf)) == -1)
415 			fatal("imsg_read error");
416 		if (n == 0)	/* connection closed */
417 			fatalx("pipe closed");
418 	}
419 	if (event & EV_WRITE) {
420 		if (msgbuf_write(&ibuf->w) == -1)
421 			fatal("msgbuf_write");
422 	}
423 
424 	for (;;) {
425 		if ((n = imsg_get(ibuf, &imsg)) == -1)
426 			fatal("imsg_get");
427 
428 		if (n == 0)
429 			break;
430 
431 		switch (imsg.hdr.type) {
432 		case IMSG_MFC_ADD:
433 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
434 				fatalx("invalid size of RDE request");
435 			memcpy(&mfc, imsg.data, sizeof(mfc));
436 
437 			/* add to MFC */
438 			mrt_add_mfc(conf->mroute_socket, &mfc);
439 			break;
440 		case IMSG_MFC_DEL:
441 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
442 				fatalx("invalid size of RDE request");
443 			memcpy(&mfc, imsg.data, sizeof(mfc));
444 
445 			/* remove from MFC */
446 			mrt_del_mfc(conf->mroute_socket, &mfc);
447 			break;
448 		default:
449 			log_debug("main_dispatch_rde: error handling imsg %d",
450 			    imsg.hdr.type);
451 			break;
452 		}
453 		imsg_free(&imsg);
454 	}
455 	imsg_event_add(iev);
456 }
457 
458 void
459 main_imsg_compose_dvmrpe(int type, pid_t pid, void *data, u_int16_t datalen)
460 {
461 	imsg_compose_event(iev_dvmrpe, type, 0, pid, -1, data, datalen);
462 }
463 
464 void
465 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
466 {
467 	imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
468 }
469 
470 void
471 imsg_event_add(struct imsgev *iev)
472 {
473 	iev->events = EV_READ;
474 	if (iev->ibuf.w.queued)
475 		iev->events |= EV_WRITE;
476 
477 	event_del(&iev->ev);
478 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
479 	event_add(&iev->ev, NULL);
480 }
481 
482 int
483 imsg_compose_event(struct imsgev *iev, u_int16_t type,
484     u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
485 {
486 	int	ret;
487 
488 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
489 	    pid, fd, data, datalen)) != -1)
490 		imsg_event_add(iev);
491 	return (ret);
492 }
493