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