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