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