1 /* $OpenBSD: dvmrpe.c,v 1.15 2015/12/05 13:11:00 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 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 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 TAILQ_INIT(&ctl_conns); 170 control_listen(); 171 172 if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL) 173 fatal("dvmrpe"); 174 175 /* start interfaces */ 176 LIST_FOREACH(iface, &deconf->iface_list, entry) { 177 if_init(xconf, iface); 178 if (if_fsm(iface, IF_EVT_UP)) { 179 log_debug("error starting interface %s", iface->name); 180 } 181 } 182 183 evtimer_set(&deconf->report_timer, report_timer, deconf); 184 start_report_timer(); 185 186 event_dispatch(); 187 188 dvmrpe_shutdown(); 189 /* NOTREACHED */ 190 return (0); 191 } 192 193 void 194 dvmrpe_shutdown(void) 195 { 196 struct iface *iface; 197 198 /* stop all interfaces and delete them */ 199 LIST_FOREACH(iface, &deconf->iface_list, entry) { 200 if (if_fsm(iface, IF_EVT_DOWN)) { 201 log_debug("error stopping interface %s", 202 iface->name); 203 } 204 if_del(iface); 205 } 206 207 /* clean up */ 208 msgbuf_write(&iev_rde->ibuf.w); 209 msgbuf_clear(&iev_rde->ibuf.w); 210 free(iev_rde); 211 msgbuf_write(&iev_main->ibuf.w); 212 msgbuf_clear(&iev_main->ibuf.w); 213 free(iev_main); 214 free(pkt_ptr); 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 link_ok; 244 245 if (event & EV_READ) { 246 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 247 fatal("imsg_read error"); 248 if (n == 0) /* connection closed */ 249 fatalx("pipe closed"); 250 } 251 if (event & EV_WRITE) { 252 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 253 fatal("msgbuf_write"); 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 imsg_event_add(iev); 296 } 297 298 void 299 dvmrpe_dispatch_rde(int fd, short event, void *bula) 300 { 301 struct imsgev *iev = bula; 302 struct imsgbuf *ibuf = &iev->ibuf; 303 struct imsg imsg; 304 struct nbr *nbr; 305 struct prune p; 306 struct iface *iface; 307 struct route_report *rr; 308 ssize_t n; 309 310 if (event & EV_READ) { 311 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 312 fatal("imsg_read error"); 313 if (n == 0) /* connection closed */ 314 fatalx("pipe closed"); 315 } 316 if (event & EV_WRITE) { 317 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 318 fatal("msgbuf_write"); 319 } 320 321 for (;;) { 322 if ((n = imsg_get(ibuf, &imsg)) == -1) 323 fatal("dvmrpe_dispatch_rde: imsg_read error"); 324 if (n == 0) 325 break; 326 327 switch (imsg.hdr.type) { 328 case IMSG_CTL_SHOW_RIB: 329 case IMSG_CTL_SHOW_SUM: 330 case IMSG_CTL_SHOW_MFC: 331 case IMSG_CTL_END: 332 control_imsg_relay(&imsg); 333 break; 334 case IMSG_FULL_ROUTE_REPORT: 335 /* add route reports to list */ 336 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 337 fatalx("invalid size of RDE request"); 338 339 if ((rr = calloc(1, sizeof(*rr))) == NULL) 340 fatal("dvmrpe_dispatch_rde"); 341 342 memcpy(rr, imsg.data, sizeof(*rr)); 343 344 /* general update, per interface */ 345 if (imsg.hdr.peerid == 0) { 346 /* add to interface list */ 347 LIST_FOREACH(iface, &deconf->iface_list, 348 entry) { 349 if (!if_nbr_list_empty(iface)) 350 rr_list_add(&iface->rr_list, 351 rr); 352 } 353 break; 354 } 355 356 /* add to neighbor list */ 357 nbr = nbr_find_peerid(imsg.hdr.peerid); 358 rr_list_add(&nbr->rr_list, rr); 359 break; 360 case IMSG_FULL_ROUTE_REPORT_END: 361 /* transmit route report */ 362 if (imsg.hdr.peerid == 0) { 363 /* 364 * send general route report on all 365 * interfaces with neighbors. 366 */ 367 LIST_FOREACH(iface, &deconf->iface_list, 368 entry) { 369 rr_list_send(&iface->rr_list, 370 iface, NULL); 371 } 372 break; 373 } 374 375 nbr = nbr_find_peerid(imsg.hdr.peerid); 376 rr_list_send(&nbr->rr_list, NULL, nbr); 377 break; 378 case IMSG_SEND_PRUNE: 379 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p)) 380 fatalx("invalid size of RDE request"); 381 382 memcpy(&p, imsg.data, sizeof(p)); 383 384 LIST_FOREACH(iface, &deconf->iface_list, entry) 385 if (p.ifindex == iface->ifindex) 386 break; 387 388 if (iface == NULL) 389 fatalx("invalid interface in mfc"); 390 391 nbr = nbr_find_ip(iface, p.nexthop.s_addr); 392 if (nbr == NULL) 393 fatalx("unknown neighbor to send prune"); 394 395 send_prune(nbr, &p); 396 397 break; 398 case IMSG_FLASH_UPDATE: 399 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 400 fatalx("invalid size of RDE request"); 401 402 if ((rr = calloc(1, sizeof(*rr))) == NULL) 403 fatal("dvmrpe_dispatch_rde"); 404 405 memcpy(rr, imsg.data, sizeof(*rr)); 406 407 LIST_FOREACH(iface, &deconf->iface_list, entry) { 408 if (!if_nbr_list_empty(iface)) { 409 rr_list_add(&iface->rr_list, rr); 410 rr_list_send(&iface->rr_list, iface, 411 NULL); 412 } 413 } 414 break; 415 case IMSG_FLASH_UPDATE_DS: 416 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr)) 417 fatalx("invalid size of RDE request"); 418 419 if ((rr = calloc(1, sizeof(*rr))) == NULL) 420 fatal("dvmrpe_dispatch_rde"); 421 422 memcpy(rr, imsg.data, sizeof(*rr)); 423 424 LIST_FOREACH(iface, &deconf->iface_list, entry) { 425 if (iface->ifindex == rr->ifindex) 426 continue; 427 if (!if_nbr_list_empty(iface)) { 428 rr_list_add(&iface->rr_list, rr); 429 rr_list_send(&iface->rr_list, iface, 430 NULL); 431 } 432 } 433 break; 434 default: 435 log_debug("dvmrpe_dispatch_rde: error handling imsg %d", 436 imsg.hdr.type); 437 break; 438 } 439 imsg_free(&imsg); 440 } 441 imsg_event_add(iev); 442 } 443 444 void 445 dvmrpe_iface_ctl(struct ctl_conn *c, unsigned int idx) 446 { 447 struct iface *iface; 448 struct ctl_iface *ictl; 449 450 LIST_FOREACH(iface, &deconf->iface_list, entry) 451 if (idx == 0 || idx == iface->ifindex) { 452 ictl = if_to_ctl(iface); 453 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, 454 0, 0, -1, ictl, sizeof(struct ctl_iface)); 455 } 456 } 457 458 void 459 dvmrpe_iface_igmp_ctl(struct ctl_conn *c, unsigned int idx) 460 { 461 struct iface *iface; 462 struct ctl_iface *ictl; 463 464 LIST_FOREACH(iface, &deconf->iface_list, entry) 465 if (idx == 0 || idx == iface->ifindex) { 466 ictl = if_to_ctl(iface); 467 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE, 468 0, 0, -1, ictl, sizeof(struct ctl_iface)); 469 group_list_dump(iface, c); 470 471 } 472 } 473 474 void 475 dvmrpe_nbr_ctl(struct ctl_conn *c) 476 { 477 struct iface *iface; 478 struct nbr *nbr; 479 struct ctl_nbr *nctl; 480 481 LIST_FOREACH(iface, &deconf->iface_list, entry) 482 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 483 nctl = nbr_to_ctl(nbr); 484 imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 485 0, 0, -1, nctl, sizeof(struct ctl_nbr)); 486 } 487 488 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 489 } 490