1 /* $OpenBSD: dvmrpe.c,v 1.23 2021/01/19 12:29:46 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 imsg_init(&iev_rde->ibuf, pipe_dvmrpe2rde[0]); 147 iev_rde->handler = dvmrpe_dispatch_rde; 148 149 imsg_init(&iev_main->ibuf, pipe_parent2dvmrpe[1]); 150 iev_main->handler = dvmrpe_dispatch_main; 151 152 /* setup event handler */ 153 iev_rde->events = EV_READ; 154 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 155 iev_rde->handler, iev_rde); 156 event_add(&iev_rde->ev, NULL); 157 158 iev_main->events = EV_READ; 159 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 160 iev_main->handler, iev_main); 161 event_add(&iev_main->ev, NULL); 162 163 event_set(&deconf->ev, deconf->dvmrp_socket, EV_READ|EV_PERSIST, 164 recv_packet, deconf); 165 event_add(&deconf->ev, NULL); 166 167 /* listen on dvmrpd control socket */ 168 control_listen(); 169 170 /* start interfaces */ 171 LIST_FOREACH(iface, &deconf->iface_list, entry) { 172 if_init(xconf, iface); 173 if (if_fsm(iface, IF_EVT_UP)) { 174 log_debug("error starting interface %s", iface->name); 175 } 176 } 177 178 evtimer_set(&deconf->report_timer, report_timer, deconf); 179 start_report_timer(); 180 181 event_dispatch(); 182 183 dvmrpe_shutdown(); 184 /* NOTREACHED */ 185 return (0); 186 } 187 188 __dead void 189 dvmrpe_shutdown(void) 190 { 191 struct iface *iface; 192 193 /* close pipes */ 194 msgbuf_write(&iev_rde->ibuf.w); 195 msgbuf_clear(&iev_rde->ibuf.w); 196 close(iev_rde->ibuf.fd); 197 msgbuf_write(&iev_main->ibuf.w); 198 msgbuf_clear(&iev_main->ibuf.w); 199 close(iev_main->ibuf.fd); 200 201 /* stop all interfaces and delete them */ 202 LIST_FOREACH(iface, &deconf->iface_list, entry) { 203 if (if_fsm(iface, IF_EVT_DOWN)) { 204 log_debug("error stopping interface %s", 205 iface->name); 206 } 207 if_del(iface); 208 } 209 210 /* clean up */ 211 free(iev_rde); 212 free(iev_main); 213 214 log_info("dvmrp engine exiting"); 215 _exit(0); 216 } 217 218 int 219 dvmrpe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) 220 { 221 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 222 } 223 224 int 225 dvmrpe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid, 226 void *data, u_int16_t datalen) 227 { 228 return (imsg_compose_event(iev_rde, type, peerid, pid, 229 -1, data, datalen)); 230 } 231 232 void 233 dvmrpe_dispatch_main(int fd, short event, void *bula) 234 { 235 struct imsg imsg; 236 struct imsgev *iev = bula; 237 struct imsgbuf *ibuf = &iev->ibuf; 238 struct kif *kif; 239 struct iface *iface; 240 ssize_t n; 241 int shut = 0, link_ok; 242 243 if (event & EV_READ) { 244 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 245 fatal("imsg_read error"); 246 if (n == 0) /* connection closed */ 247 shut = 1; 248 } 249 if (event & EV_WRITE) { 250 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 251 fatal("msgbuf_write"); 252 if (n == 0) /* connection closed */ 253 shut = 1; 254 } 255 256 for (;;) { 257 if ((n = imsg_get(ibuf, &imsg)) == -1) 258 fatal("dvmrpe_dispatch_main: imsg_read error"); 259 if (n == 0) 260 break; 261 262 switch (imsg.hdr.type) { 263 case IMSG_IFINFO: 264 if (imsg.hdr.len - IMSG_HEADER_SIZE != 265 sizeof(struct kif)) 266 fatalx("IFINFO imsg with wrong len"); 267 kif = imsg.data; 268 link_ok = (kif->flags & IFF_UP) && 269 LINK_STATE_IS_UP(kif->link_state); 270 271 LIST_FOREACH(iface, &deconf->iface_list, entry) { 272 if (kif->ifindex == iface->ifindex) { 273 iface->flags = kif->flags; 274 iface->linkstate = kif->link_state; 275 276 if (link_ok) { 277 if_fsm(iface, IF_EVT_UP); 278 log_warnx("interface %s up", 279 iface->name); 280 } else { 281 if_fsm(iface, IF_EVT_DOWN); 282 log_warnx("interface %s down", 283 iface->name); 284 } 285 } 286 } 287 break; 288 default: 289 log_debug("dvmrpe_dispatch_main: error handling " 290 "imsg %d", imsg.hdr.type); 291 break; 292 } 293 imsg_free(&imsg); 294 } 295 if (!shut) 296 imsg_event_add(iev); 297 else { 298 /* this pipe is dead, so remove the event handler */ 299 event_del(&iev->ev); 300 event_loopexit(NULL); 301 } 302 } 303 304 void 305 dvmrpe_dispatch_rde(int fd, short event, void *bula) 306 { 307 struct imsgev *iev = bula; 308 struct imsgbuf *ibuf = &iev->ibuf; 309 struct imsg imsg; 310 struct nbr *nbr; 311 struct prune p; 312 struct iface *iface; 313 struct route_report *rr; 314 ssize_t n; 315 int shut = 0; 316 317 if (event & EV_READ) { 318 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 319 fatal("imsg_read error"); 320 if (n == 0) /* connection closed */ 321 shut = 1; 322 } 323 if (event & EV_WRITE) { 324 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 325 fatal("msgbuf_write"); 326 if (n == 0) /* connection closed */ 327 shut = 1; 328 } 329 330 for (;;) { 331 if ((n = imsg_get(ibuf, &imsg)) == -1) 332 fatal("dvmrpe_dispatch_rde: imsg_read error"); 333 if (n == 0) 334 break; 335 336 switch (imsg.hdr.type) { 337 case IMSG_CTL_SHOW_RIB: 338 case IMSG_CTL_SHOW_SUM: 339 case IMSG_CTL_SHOW_MFC: 340 case IMSG_CTL_END: 341 control_imsg_relay(&imsg); 342 break; 343 case IMSG_FULL_ROUTE_REPORT: 344 /* add route reports to list */ 345 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 346 fatalx("invalid size of RDE request"); 347 348 if ((rr = calloc(1, sizeof(*rr))) == NULL) 349 fatal("dvmrpe_dispatch_rde"); 350 351 memcpy(rr, imsg.data, sizeof(*rr)); 352 353 /* general update, per interface */ 354 if (imsg.hdr.peerid == 0) { 355 /* add to interface list */ 356 LIST_FOREACH(iface, &deconf->iface_list, 357 entry) { 358 if (!if_nbr_list_empty(iface)) 359 rr_list_add(&iface->rr_list, 360 rr); 361 } 362 break; 363 } 364 365 /* add to neighbor list */ 366 nbr = nbr_find_peerid(imsg.hdr.peerid); 367 rr_list_add(&nbr->rr_list, rr); 368 break; 369 case IMSG_FULL_ROUTE_REPORT_END: 370 /* transmit route report */ 371 if (imsg.hdr.peerid == 0) { 372 /* 373 * send general route report on all 374 * interfaces with neighbors. 375 */ 376 LIST_FOREACH(iface, &deconf->iface_list, 377 entry) { 378 rr_list_send(&iface->rr_list, 379 iface, NULL); 380 } 381 break; 382 } 383 384 nbr = nbr_find_peerid(imsg.hdr.peerid); 385 rr_list_send(&nbr->rr_list, NULL, nbr); 386 break; 387 case IMSG_SEND_PRUNE: 388 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p)) 389 fatalx("invalid size of RDE request"); 390 391 memcpy(&p, imsg.data, sizeof(p)); 392 393 LIST_FOREACH(iface, &deconf->iface_list, entry) 394 if (p.ifindex == iface->ifindex) 395 break; 396 397 if (iface == NULL) 398 fatalx("invalid interface in mfc"); 399 400 nbr = nbr_find_ip(iface, p.nexthop.s_addr); 401 if (nbr == NULL) 402 fatalx("unknown neighbor to send prune"); 403 404 send_prune(nbr, &p); 405 406 break; 407 case IMSG_FLASH_UPDATE: 408 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 409 fatalx("invalid size of RDE request"); 410 411 if ((rr = calloc(1, sizeof(*rr))) == NULL) 412 fatal("dvmrpe_dispatch_rde"); 413 414 memcpy(rr, imsg.data, sizeof(*rr)); 415 416 LIST_FOREACH(iface, &deconf->iface_list, entry) { 417 if (!if_nbr_list_empty(iface)) { 418 rr_list_add(&iface->rr_list, rr); 419 rr_list_send(&iface->rr_list, iface, 420 NULL); 421 } 422 } 423 break; 424 case IMSG_FLASH_UPDATE_DS: 425 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 426 fatalx("invalid size of RDE request"); 427 428 if ((rr = calloc(1, sizeof(*rr))) == NULL) 429 fatal("dvmrpe_dispatch_rde"); 430 431 memcpy(rr, imsg.data, sizeof(*rr)); 432 433 LIST_FOREACH(iface, &deconf->iface_list, entry) { 434 if (iface->ifindex == rr->ifindex) 435 continue; 436 if (!if_nbr_list_empty(iface)) { 437 rr_list_add(&iface->rr_list, rr); 438 rr_list_send(&iface->rr_list, iface, 439 NULL); 440 } 441 } 442 break; 443 default: 444 log_debug("dvmrpe_dispatch_rde: error handling imsg %d", 445 imsg.hdr.type); 446 break; 447 } 448 imsg_free(&imsg); 449 } 450 if (!shut) 451 imsg_event_add(iev); 452 else { 453 /* this pipe is dead, so remove the event handler */ 454 event_del(&iev->ev); 455 event_loopexit(NULL); 456 } 457 } 458 459 void 460 dvmrpe_iface_ctl(struct ctl_conn *c, unsigned int idx) 461 { 462 struct iface *iface; 463 struct ctl_iface *ictl; 464 465 LIST_FOREACH(iface, &deconf->iface_list, entry) 466 if (idx == 0 || idx == iface->ifindex) { 467 ictl = if_to_ctl(iface); 468 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, 469 0, 0, -1, ictl, sizeof(struct ctl_iface)); 470 } 471 } 472 473 void 474 dvmrpe_iface_igmp_ctl(struct ctl_conn *c, unsigned int idx) 475 { 476 struct iface *iface; 477 struct ctl_iface *ictl; 478 479 LIST_FOREACH(iface, &deconf->iface_list, entry) 480 if (idx == 0 || idx == iface->ifindex) { 481 ictl = if_to_ctl(iface); 482 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, 483 0, 0, -1, ictl, sizeof(struct ctl_iface)); 484 group_list_dump(iface, c); 485 486 } 487 } 488 489 void 490 dvmrpe_nbr_ctl(struct ctl_conn *c) 491 { 492 struct iface *iface; 493 struct nbr *nbr; 494 struct ctl_nbr *nctl; 495 496 LIST_FOREACH(iface, &deconf->iface_list, entry) 497 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 498 nctl = nbr_to_ctl(nbr); 499 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 500 0, 0, -1, nctl, sizeof(struct ctl_nbr)); 501 } 502 503 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 504 } 505