1 /* $OpenBSD: dvmrpd.c,v 1.27 2021/01/19 12:29:46 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
main_sig_handler(int sig,short event,void * arg)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
usage(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
main(int argc,char * argv[])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
dvmrpd_shutdown(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
main_dispatch_dvmrpe(int fd,short event,void * bula)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
main_dispatch_rde(int fd,short event,void * bula)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
main_imsg_compose_dvmrpe(int type,pid_t pid,void * data,u_int16_t datalen)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
main_imsg_compose_rde(int type,pid_t pid,void * data,u_int16_t datalen)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
imsg_event_add(struct imsgev * iev)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
imsg_compose_event(struct imsgev * iev,u_int16_t type,u_int32_t peerid,pid_t pid,int fd,void * data,u_int16_t datalen)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