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