xref: /openbsd-src/usr.sbin/dvmrpd/dvmrpd.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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 }
470