1 /* $OpenBSD: dvmrpe.c,v 1.30 2024/11/21 13:38:14 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 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 <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/if_types.h> 27 #include <stdlib.h> 28 #include <signal.h> 29 #include <string.h> 30 #include <fcntl.h> 31 #include <pwd.h> 32 #include <unistd.h> 33 #include <event.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <stdio.h> 37 38 #include "igmp.h" 39 #include "dvmrp.h" 40 #include "dvmrpd.h" 41 #include "dvmrpe.h" 42 #include "control.h" 43 #include "log.h" 44 45 void dvmrpe_sig_handler(int, short, void *); 46 __dead void dvmrpe_shutdown(void); 47 48 volatile sig_atomic_t dvmrpe_quit = 0; 49 struct dvmrpd_conf *deconf = NULL; 50 static struct imsgev *iev_main; 51 static struct imsgev *iev_rde; 52 53 void 54 dvmrpe_sig_handler(int sig, short event, void *bula) 55 { 56 switch (sig) { 57 case SIGINT: 58 case SIGTERM: 59 dvmrpe_shutdown(); 60 /* NOTREACHED */ 61 default: 62 fatalx("unexpected signal"); 63 } 64 } 65 66 /* dvmrp engine */ 67 pid_t 68 dvmrpe(struct dvmrpd_conf *xconf, int pipe_parent2dvmrpe[2], 69 int pipe_dvmrpe2rde[2], int pipe_parent2rde[2]) 70 { 71 struct iface *iface = NULL; 72 struct passwd *pw; 73 struct event ev_sigint, ev_sigterm; 74 pid_t pid; 75 76 switch (pid = fork()) { 77 case -1: 78 fatal("cannot fork"); 79 case 0: 80 break; 81 default: 82 83 return (pid); 84 } 85 86 /* create the raw ip socket */ 87 if ((xconf->dvmrp_socket = socket(AF_INET, 88 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 89 IPPROTO_IGMP)) == -1) 90 fatal("error creating raw socket"); 91 92 /* create dvmrpd control socket outside chroot */ 93 if (control_init() == -1) 94 fatalx("control socket setup failed"); 95 96 /* set some defaults */ 97 if (if_set_mcast_ttl(xconf->dvmrp_socket, 98 IP_DEFAULT_MULTICAST_TTL) == -1) 99 fatal("if_set_mcast_ttl"); 100 101 if (if_set_mcast_loop(xconf->dvmrp_socket) == -1) 102 fatal("if_set_mcast_loop"); 103 104 if (if_set_tos(xconf->dvmrp_socket, IPTOS_PREC_INTERNETCONTROL) == -1) 105 fatal("if_set_tos"); 106 107 if_set_recvbuf(xconf->dvmrp_socket); 108 109 deconf = xconf; 110 111 if ((pw = getpwnam(DVMRPD_USER)) == NULL) 112 fatal("getpwnam"); 113 114 if (chroot(pw->pw_dir) == -1) 115 fatal("chroot"); 116 if (chdir("/") == -1) 117 fatal("chdir(\"/\")"); 118 119 setproctitle("dvmrp engine"); 120 log_procname = "dvmrpe"; 121 122 if (setgroups(1, &pw->pw_gid) || 123 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 124 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 125 fatal("can't drop privileges"); 126 127 event_init(); 128 nbr_init(NBR_HASHSIZE); 129 130 /* setup signal handler */ 131 signal_set(&ev_sigint, SIGINT, dvmrpe_sig_handler, NULL); 132 signal_set(&ev_sigterm, SIGTERM, dvmrpe_sig_handler, NULL); 133 signal_add(&ev_sigint, NULL); 134 signal_add(&ev_sigterm, NULL); 135 signal(SIGPIPE, SIG_IGN); 136 137 /* setup pipes */ 138 close(pipe_parent2dvmrpe[0]); 139 close(pipe_dvmrpe2rde[1]); 140 close(pipe_parent2rde[0]); 141 close(pipe_parent2rde[1]); 142 143 if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL || 144 (iev_main = malloc(sizeof(struct imsgev))) == NULL) 145 fatal(NULL); 146 if (imsgbuf_init(&iev_rde->ibuf, pipe_dvmrpe2rde[0]) == -1) 147 fatal(NULL); 148 iev_rde->handler = dvmrpe_dispatch_rde; 149 150 if (imsgbuf_init(&iev_main->ibuf, pipe_parent2dvmrpe[1]) == -1) 151 fatal(NULL); 152 iev_main->handler = dvmrpe_dispatch_main; 153 154 /* setup event handler */ 155 iev_rde->events = EV_READ; 156 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 157 iev_rde->handler, iev_rde); 158 event_add(&iev_rde->ev, NULL); 159 160 iev_main->events = EV_READ; 161 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 162 iev_main->handler, iev_main); 163 event_add(&iev_main->ev, NULL); 164 165 event_set(&deconf->ev, deconf->dvmrp_socket, EV_READ|EV_PERSIST, 166 recv_packet, deconf); 167 event_add(&deconf->ev, NULL); 168 169 /* listen on dvmrpd control socket */ 170 control_listen(); 171 172 /* start interfaces */ 173 LIST_FOREACH(iface, &deconf->iface_list, entry) { 174 if_init(xconf, iface); 175 if (if_fsm(iface, IF_EVT_UP)) { 176 log_debug("error starting interface %s", iface->name); 177 } 178 } 179 180 evtimer_set(&deconf->report_timer, report_timer, deconf); 181 start_report_timer(); 182 183 event_dispatch(); 184 185 dvmrpe_shutdown(); 186 /* NOTREACHED */ 187 return (0); 188 } 189 190 __dead void 191 dvmrpe_shutdown(void) 192 { 193 struct iface *iface; 194 195 /* close pipes */ 196 imsgbuf_write(&iev_rde->ibuf); 197 imsgbuf_clear(&iev_rde->ibuf); 198 close(iev_rde->ibuf.fd); 199 imsgbuf_write(&iev_main->ibuf); 200 imsgbuf_clear(&iev_main->ibuf); 201 close(iev_main->ibuf.fd); 202 203 /* stop all interfaces and delete them */ 204 LIST_FOREACH(iface, &deconf->iface_list, entry) { 205 if (if_fsm(iface, IF_EVT_DOWN)) { 206 log_debug("error stopping interface %s", 207 iface->name); 208 } 209 if_del(iface); 210 } 211 212 /* clean up */ 213 free(iev_rde); 214 free(iev_main); 215 216 log_info("dvmrp engine exiting"); 217 _exit(0); 218 } 219 220 int 221 dvmrpe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) 222 { 223 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 224 } 225 226 int 227 dvmrpe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid, 228 void *data, u_int16_t datalen) 229 { 230 return (imsg_compose_event(iev_rde, type, peerid, pid, 231 -1, data, datalen)); 232 } 233 234 void 235 dvmrpe_dispatch_main(int fd, short event, void *bula) 236 { 237 struct imsg imsg; 238 struct imsgev *iev = bula; 239 struct imsgbuf *ibuf = &iev->ibuf; 240 struct kif *kif; 241 struct iface *iface; 242 ssize_t n; 243 int shut = 0, link_ok; 244 245 if (event & EV_READ) { 246 if ((n = imsgbuf_read(ibuf)) == -1) 247 fatal("imsgbuf_read error"); 248 if (n == 0) /* connection closed */ 249 shut = 1; 250 } 251 if (event & EV_WRITE) { 252 if (imsgbuf_write(ibuf) == -1) { 253 if (errno == EPIPE) /* connection closed */ 254 shut = 1; 255 else 256 fatal("imsgbuf_write"); 257 } 258 } 259 260 for (;;) { 261 if ((n = imsg_get(ibuf, &imsg)) == -1) 262 fatal("dvmrpe_dispatch_main: imsg_get error"); 263 if (n == 0) 264 break; 265 266 switch (imsg.hdr.type) { 267 case IMSG_IFINFO: 268 if (imsg.hdr.len - IMSG_HEADER_SIZE != 269 sizeof(struct kif)) 270 fatalx("IFINFO imsg with wrong len"); 271 kif = imsg.data; 272 link_ok = (kif->flags & IFF_UP) && 273 LINK_STATE_IS_UP(kif->link_state); 274 275 LIST_FOREACH(iface, &deconf->iface_list, entry) { 276 if (kif->ifindex == iface->ifindex) { 277 iface->flags = kif->flags; 278 iface->linkstate = kif->link_state; 279 280 if (link_ok) { 281 if_fsm(iface, IF_EVT_UP); 282 log_warnx("interface %s up", 283 iface->name); 284 } else { 285 if_fsm(iface, IF_EVT_DOWN); 286 log_warnx("interface %s down", 287 iface->name); 288 } 289 } 290 } 291 break; 292 default: 293 log_debug("dvmrpe_dispatch_main: error handling " 294 "imsg %d", imsg.hdr.type); 295 break; 296 } 297 imsg_free(&imsg); 298 } 299 if (!shut) 300 imsg_event_add(iev); 301 else { 302 /* this pipe is dead, so remove the event handler */ 303 event_del(&iev->ev); 304 event_loopexit(NULL); 305 } 306 } 307 308 void 309 dvmrpe_dispatch_rde(int fd, short event, void *bula) 310 { 311 struct imsgev *iev = bula; 312 struct imsgbuf *ibuf = &iev->ibuf; 313 struct imsg imsg; 314 struct nbr *nbr; 315 struct prune p; 316 struct iface *iface; 317 struct route_report *rr; 318 ssize_t n; 319 int shut = 0; 320 321 if (event & EV_READ) { 322 if ((n = imsgbuf_read(ibuf)) == -1) 323 fatal("imsgbuf_read error"); 324 if (n == 0) /* connection closed */ 325 shut = 1; 326 } 327 if (event & EV_WRITE) { 328 if (imsgbuf_write(ibuf) == -1) { 329 if (errno == EPIPE) /* connection closed */ 330 shut = 1; 331 else 332 fatal("imsgbuf_write"); 333 } 334 } 335 336 for (;;) { 337 if ((n = imsg_get(ibuf, &imsg)) == -1) 338 fatal("dvmrpe_dispatch_rde: imsgbuf_get error"); 339 if (n == 0) 340 break; 341 342 switch (imsg.hdr.type) { 343 case IMSG_CTL_SHOW_RIB: 344 case IMSG_CTL_SHOW_SUM: 345 case IMSG_CTL_SHOW_MFC: 346 case IMSG_CTL_END: 347 control_imsg_relay(&imsg); 348 break; 349 case IMSG_FULL_ROUTE_REPORT: 350 /* add route reports to list */ 351 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 352 fatalx("invalid size of RDE request"); 353 354 if ((rr = calloc(1, sizeof(*rr))) == NULL) 355 fatal("dvmrpe_dispatch_rde"); 356 357 memcpy(rr, imsg.data, sizeof(*rr)); 358 359 /* general update, per interface */ 360 if (imsg.hdr.peerid == 0) { 361 /* add to interface list */ 362 LIST_FOREACH(iface, &deconf->iface_list, 363 entry) { 364 if (!if_nbr_list_empty(iface)) 365 rr_list_add(&iface->rr_list, 366 rr); 367 } 368 break; 369 } 370 371 /* add to neighbor list */ 372 nbr = nbr_find_peerid(imsg.hdr.peerid); 373 rr_list_add(&nbr->rr_list, rr); 374 break; 375 case IMSG_FULL_ROUTE_REPORT_END: 376 /* transmit route report */ 377 if (imsg.hdr.peerid == 0) { 378 /* 379 * send general route report on all 380 * interfaces with neighbors. 381 */ 382 LIST_FOREACH(iface, &deconf->iface_list, 383 entry) { 384 rr_list_send(&iface->rr_list, 385 iface, NULL); 386 } 387 break; 388 } 389 390 nbr = nbr_find_peerid(imsg.hdr.peerid); 391 rr_list_send(&nbr->rr_list, NULL, nbr); 392 break; 393 case IMSG_SEND_PRUNE: 394 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p)) 395 fatalx("invalid size of RDE request"); 396 397 memcpy(&p, imsg.data, sizeof(p)); 398 399 LIST_FOREACH(iface, &deconf->iface_list, entry) 400 if (p.ifindex == iface->ifindex) 401 break; 402 403 if (iface == NULL) 404 fatalx("invalid interface in mfc"); 405 406 nbr = nbr_find_ip(iface, p.nexthop.s_addr); 407 if (nbr == NULL) 408 fatalx("unknown neighbor to send prune"); 409 410 send_prune(nbr, &p); 411 412 break; 413 case IMSG_FLASH_UPDATE: 414 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 415 fatalx("invalid size of RDE request"); 416 417 if ((rr = calloc(1, sizeof(*rr))) == NULL) 418 fatal("dvmrpe_dispatch_rde"); 419 420 memcpy(rr, imsg.data, sizeof(*rr)); 421 422 LIST_FOREACH(iface, &deconf->iface_list, entry) { 423 if (!if_nbr_list_empty(iface)) { 424 rr_list_add(&iface->rr_list, rr); 425 rr_list_send(&iface->rr_list, iface, 426 NULL); 427 } 428 } 429 break; 430 case IMSG_FLASH_UPDATE_DS: 431 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 432 fatalx("invalid size of RDE request"); 433 434 if ((rr = calloc(1, sizeof(*rr))) == NULL) 435 fatal("dvmrpe_dispatch_rde"); 436 437 memcpy(rr, imsg.data, sizeof(*rr)); 438 439 LIST_FOREACH(iface, &deconf->iface_list, entry) { 440 if (iface->ifindex == rr->ifindex) 441 continue; 442 if (!if_nbr_list_empty(iface)) { 443 rr_list_add(&iface->rr_list, rr); 444 rr_list_send(&iface->rr_list, iface, 445 NULL); 446 } 447 } 448 break; 449 default: 450 log_debug("dvmrpe_dispatch_rde: error handling imsg %d", 451 imsg.hdr.type); 452 break; 453 } 454 imsg_free(&imsg); 455 } 456 if (!shut) 457 imsg_event_add(iev); 458 else { 459 /* this pipe is dead, so remove the event handler */ 460 event_del(&iev->ev); 461 event_loopexit(NULL); 462 } 463 } 464 465 void 466 dvmrpe_iface_ctl(struct ctl_conn *c, unsigned int idx) 467 { 468 struct iface *iface; 469 struct ctl_iface *ictl; 470 471 LIST_FOREACH(iface, &deconf->iface_list, entry) 472 if (idx == 0 || idx == iface->ifindex) { 473 ictl = if_to_ctl(iface); 474 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, 475 0, 0, -1, ictl, sizeof(struct ctl_iface)); 476 } 477 } 478 479 void 480 dvmrpe_iface_igmp_ctl(struct ctl_conn *c, unsigned int idx) 481 { 482 struct iface *iface; 483 struct ctl_iface *ictl; 484 485 LIST_FOREACH(iface, &deconf->iface_list, entry) 486 if (idx == 0 || idx == iface->ifindex) { 487 ictl = if_to_ctl(iface); 488 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, 489 0, 0, -1, ictl, sizeof(struct ctl_iface)); 490 group_list_dump(iface, c); 491 492 } 493 } 494 495 void 496 dvmrpe_nbr_ctl(struct ctl_conn *c) 497 { 498 struct iface *iface; 499 struct nbr *nbr; 500 struct ctl_nbr *nctl; 501 502 LIST_FOREACH(iface, &deconf->iface_list, entry) 503 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 504 nctl = nbr_to_ctl(nbr); 505 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 506 0, 0, -1, nctl, sizeof(struct ctl_nbr)); 507 } 508 509 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 510 } 511