1 /* $OpenBSD: frontend.c,v 1.74 2024/11/21 13:35:20 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/syslog.h> 26 #include <sys/uio.h> 27 28 #include <net/if.h> 29 #include <net/if_dl.h> 30 #include <net/if_types.h> 31 #include <net/route.h> 32 33 #include <arpa/inet.h> 34 35 #include <netinet/in.h> 36 #include <netinet/if_ether.h> 37 #include <netinet6/nd6.h> 38 #include <netinet6/in6_var.h> 39 #include <netinet/ip6.h> 40 #include <netinet/icmp6.h> 41 42 #include <errno.h> 43 #include <event.h> 44 #include <ifaddrs.h> 45 #include <imsg.h> 46 #include <pwd.h> 47 #include <signal.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "log.h" 54 #include "slaacd.h" 55 #include "frontend.h" 56 #include "control.h" 57 58 #define ROUTE_SOCKET_BUF_SIZE 16384 59 #define ALLROUTER "ff02::2" 60 61 struct icmp6_ev { 62 struct event ev; 63 uint8_t answer[1500]; 64 struct msghdr rcvmhdr; 65 struct iovec rcviov[1]; 66 struct sockaddr_in6 from; 67 int refcnt; 68 }; 69 70 struct iface { 71 LIST_ENTRY(iface) entries; 72 struct icmp6_ev *icmp6ev; 73 struct ether_addr hw_address; 74 uint32_t if_index; 75 int rdomain; 76 int send_solicitation; 77 int ll_tentative; 78 }; 79 80 __dead void frontend_shutdown(void); 81 void frontend_sig_handler(int, short, void *); 82 void update_iface(uint32_t, char*); 83 void frontend_startup(void); 84 void route_receive(int, short, void *); 85 void handle_route_message(struct rt_msghdr *, struct sockaddr **); 86 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 87 void icmp6_receive(int, short, void *); 88 int get_flags(char *); 89 int get_xflags(char *); 90 int get_ifrdomain(char *); 91 struct iface *get_iface_by_id(uint32_t); 92 void remove_iface(uint32_t); 93 struct icmp6_ev *get_icmp6ev_by_rdomain(int); 94 void unref_icmp6ev(struct iface *); 95 void set_icmp6sock(int, int); 96 void send_solicitation(uint32_t); 97 #ifndef SMALL 98 const char *flags_to_str(int); 99 #endif /* SMALL */ 100 101 LIST_HEAD(, iface) interfaces; 102 static struct imsgev *iev_main; 103 static struct imsgev *iev_engine; 104 struct event ev_route; 105 struct msghdr sndmhdr; 106 struct iovec sndiov[4]; 107 struct nd_router_solicit rs; 108 struct nd_opt_hdr nd_opt_hdr; 109 struct ether_addr nd_opt_source_link_addr; 110 struct sockaddr_in6 dst; 111 int ioctlsock; 112 113 void 114 frontend_sig_handler(int sig, short event, void *bula) 115 { 116 /* 117 * Normal signal handler rules don't apply because libevent 118 * decouples for us. 119 */ 120 121 switch (sig) { 122 case SIGINT: 123 case SIGTERM: 124 frontend_shutdown(); 125 default: 126 fatalx("unexpected signal"); 127 } 128 } 129 130 void 131 frontend(int debug, int verbose) 132 { 133 struct event ev_sigint, ev_sigterm; 134 struct passwd *pw; 135 struct in6_pktinfo *pi; 136 struct cmsghdr *cm; 137 size_t sndcmsglen; 138 int hoplimit = 255; 139 uint8_t *sndcmsgbuf; 140 141 log_init(debug, LOG_DAEMON); 142 log_setverbose(verbose); 143 144 if ((pw = getpwnam(SLAACD_USER)) == NULL) 145 fatal("getpwnam"); 146 147 if (chdir("/") == -1) 148 fatal("chdir(\"/\")"); 149 150 if (unveil("/", "") == -1) 151 fatal("unveil /"); 152 if (unveil(NULL, NULL) == -1) 153 fatal("unveil"); 154 155 setproctitle("%s", "frontend"); 156 log_procinit("frontend"); 157 158 if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 159 fatal("socket"); 160 161 if (setgroups(1, &pw->pw_gid) || 162 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 163 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 164 fatal("can't drop privileges"); 165 166 if (pledge("stdio unix recvfd route", NULL) == -1) 167 fatal("pledge"); 168 169 event_init(); 170 171 /* Setup signal handler. */ 172 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 173 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 174 signal_add(&ev_sigint, NULL); 175 signal_add(&ev_sigterm, NULL); 176 signal(SIGPIPE, SIG_IGN); 177 signal(SIGHUP, SIG_IGN); 178 179 /* Setup pipe and event handler to the parent process. */ 180 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 181 fatal(NULL); 182 if (imsgbuf_init(&iev_main->ibuf, 3) == -1) 183 fatal(NULL); 184 imsgbuf_allow_fdpass(&iev_main->ibuf); 185 iev_main->handler = frontend_dispatch_main; 186 iev_main->events = EV_READ; 187 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 188 iev_main->handler, iev_main); 189 event_add(&iev_main->ev, NULL); 190 191 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 192 CMSG_SPACE(sizeof(int)); 193 194 if ((sndcmsgbuf = malloc(sndcmsglen)) == NULL) 195 fatal("malloc"); 196 197 rs.nd_rs_type = ND_ROUTER_SOLICIT; 198 rs.nd_rs_code = 0; 199 rs.nd_rs_cksum = 0; 200 rs.nd_rs_reserved = 0; 201 202 nd_opt_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR; 203 nd_opt_hdr.nd_opt_len = 1; 204 205 memset(&dst, 0, sizeof(dst)); 206 dst.sin6_family = AF_INET6; 207 if (inet_pton(AF_INET6, ALLROUTER, &dst.sin6_addr.s6_addr) != 1) 208 fatal("inet_pton"); 209 210 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 211 sndmhdr.msg_iov = sndiov; 212 sndmhdr.msg_iovlen = 3; 213 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 214 sndmhdr.msg_controllen = sndcmsglen; 215 216 sndmhdr.msg_name = (caddr_t)&dst; 217 sndmhdr.msg_iov[0].iov_base = (caddr_t)&rs; 218 sndmhdr.msg_iov[0].iov_len = sizeof(rs); 219 sndmhdr.msg_iov[1].iov_base = (caddr_t)&nd_opt_hdr; 220 sndmhdr.msg_iov[1].iov_len = sizeof(nd_opt_hdr); 221 sndmhdr.msg_iov[2].iov_base = (caddr_t)&nd_opt_source_link_addr; 222 sndmhdr.msg_iov[2].iov_len = sizeof(nd_opt_source_link_addr); 223 224 cm = CMSG_FIRSTHDR(&sndmhdr); 225 226 cm->cmsg_level = IPPROTO_IPV6; 227 cm->cmsg_type = IPV6_PKTINFO; 228 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 229 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 230 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); 231 pi->ipi6_ifindex = 0; 232 233 cm = CMSG_NXTHDR(&sndmhdr, cm); 234 cm->cmsg_level = IPPROTO_IPV6; 235 cm->cmsg_type = IPV6_HOPLIMIT; 236 cm->cmsg_len = CMSG_LEN(sizeof(int)); 237 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 238 239 LIST_INIT(&interfaces); 240 241 event_dispatch(); 242 243 frontend_shutdown(); 244 } 245 246 __dead void 247 frontend_shutdown(void) 248 { 249 /* Close pipes. */ 250 imsgbuf_write(&iev_engine->ibuf); 251 imsgbuf_clear(&iev_engine->ibuf); 252 close(iev_engine->ibuf.fd); 253 imsgbuf_write(&iev_main->ibuf); 254 imsgbuf_clear(&iev_main->ibuf); 255 close(iev_main->ibuf.fd); 256 257 free(iev_engine); 258 free(iev_main); 259 260 log_info("frontend exiting"); 261 exit(0); 262 } 263 264 int 265 frontend_imsg_compose_main(int type, pid_t pid, void *data, 266 uint16_t datalen) 267 { 268 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 269 datalen)); 270 } 271 272 int 273 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, 274 void *data, uint16_t datalen) 275 { 276 return (imsg_compose_event(iev_engine, type, peerid, pid, -1, 277 data, datalen)); 278 } 279 280 void 281 frontend_dispatch_main(int fd, short event, void *bula) 282 { 283 struct imsg imsg; 284 struct imsgev *iev = bula; 285 struct imsgbuf *ibuf = &iev->ibuf; 286 ssize_t n; 287 uint32_t type; 288 int shut = 0, icmp6sock, rdomain; 289 290 if (event & EV_READ) { 291 if ((n = imsgbuf_read(ibuf)) == -1) 292 fatal("imsgbuf_read error"); 293 if (n == 0) /* Connection closed. */ 294 shut = 1; 295 } 296 if (event & EV_WRITE) { 297 if (imsgbuf_write(ibuf) == -1) { 298 if (errno == EPIPE) /* Connection closed. */ 299 shut = 1; 300 else 301 fatal("imsgbuf_write"); 302 } 303 } 304 305 for (;;) { 306 if ((n = imsg_get(ibuf, &imsg)) == -1) 307 fatal("%s: imsg_get error", __func__); 308 if (n == 0) /* No more messages. */ 309 break; 310 311 type = imsg_get_type(&imsg); 312 313 switch (type) { 314 case IMSG_SOCKET_IPC: 315 /* 316 * Setup pipe and event handler to the engine 317 * process. 318 */ 319 if (iev_engine) 320 fatalx("%s: received unexpected imsg fd " 321 "to frontend", __func__); 322 323 if ((fd = imsg_get_fd(&imsg)) == -1) 324 fatalx("%s: expected to receive imsg fd to " 325 "frontend but didn't receive any", 326 __func__); 327 328 iev_engine = malloc(sizeof(struct imsgev)); 329 if (iev_engine == NULL) 330 fatal(NULL); 331 332 if (imsgbuf_init(&iev_engine->ibuf, fd) == -1) 333 fatal(NULL); 334 iev_engine->handler = frontend_dispatch_engine; 335 iev_engine->events = EV_READ; 336 337 event_set(&iev_engine->ev, iev_engine->ibuf.fd, 338 iev_engine->events, iev_engine->handler, iev_engine); 339 event_add(&iev_engine->ev, NULL); 340 break; 341 case IMSG_ICMP6SOCK: 342 if ((icmp6sock = imsg_get_fd(&imsg)) == -1) 343 fatalx("%s: expected to receive imsg " 344 "ICMPv6 fd but didn't receive any", 345 __func__); 346 if (imsg_get_data(&imsg, &rdomain, 347 sizeof(rdomain)) == -1) 348 fatalx("%s: invalid %s", __func__, i2s(type)); 349 350 set_icmp6sock(icmp6sock, rdomain); 351 break; 352 case IMSG_ROUTESOCK: 353 if ((fd = imsg_get_fd(&imsg)) == -1) 354 fatalx("%s: expected to receive imsg " 355 "routesocket fd but didn't receive any", 356 __func__); 357 358 event_set(&ev_route, fd, EV_READ | EV_PERSIST, 359 route_receive, NULL); 360 break; 361 case IMSG_STARTUP: 362 frontend_startup(); 363 break; 364 #ifndef SMALL 365 case IMSG_CONTROLFD: 366 if ((fd = imsg_get_fd(&imsg)) == -1) 367 fatalx("%s: expected to receive imsg " 368 "control fd but didn't receive any", 369 __func__); 370 371 /* Listen on control socket. */ 372 control_listen(fd); 373 break; 374 case IMSG_CTL_END: 375 control_imsg_relay(&imsg); 376 break; 377 #endif /* SMALL */ 378 default: 379 log_debug("%s: error handling imsg %d", __func__, type); 380 break; 381 } 382 imsg_free(&imsg); 383 } 384 if (!shut) 385 imsg_event_add(iev); 386 else { 387 /* This pipe is dead. Remove its event handler. */ 388 event_del(&iev->ev); 389 event_loopexit(NULL); 390 } 391 } 392 393 void 394 frontend_dispatch_engine(int fd, short event, void *bula) 395 { 396 struct imsgev *iev = bula; 397 struct imsgbuf *ibuf = &iev->ibuf; 398 struct imsg imsg; 399 ssize_t n; 400 int shut = 0; 401 uint32_t if_index, type; 402 403 if (event & EV_READ) { 404 if ((n = imsgbuf_read(ibuf)) == -1) 405 fatal("imsgbuf_read error"); 406 if (n == 0) /* Connection closed. */ 407 shut = 1; 408 } 409 if (event & EV_WRITE) { 410 if (imsgbuf_write(ibuf) == -1) { 411 if (errno == EPIPE) /* Connection closed. */ 412 shut = 1; 413 else 414 fatal("imsgbuf_write"); 415 } 416 } 417 418 for (;;) { 419 if ((n = imsg_get(ibuf, &imsg)) == -1) 420 fatal("%s: imsg_get error", __func__); 421 if (n == 0) /* No more messages. */ 422 break; 423 424 type = imsg_get_type(&imsg); 425 426 switch (type) { 427 #ifndef SMALL 428 case IMSG_CTL_END: 429 case IMSG_CTL_SHOW_INTERFACE_INFO: 430 case IMSG_CTL_SHOW_INTERFACE_INFO_RA: 431 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX: 432 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS: 433 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS: 434 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: 435 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: 436 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: 437 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS: 438 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL: 439 control_imsg_relay(&imsg); 440 break; 441 #endif /* SMALL */ 442 case IMSG_CTL_SEND_SOLICITATION: 443 if (imsg_get_data(&imsg, &if_index, 444 sizeof(if_index)) == -1) 445 fatalx("%s: invalid %s", __func__, i2s(type)); 446 447 send_solicitation(if_index); 448 break; 449 default: 450 log_debug("%s: error handling imsg %d", __func__, type); 451 break; 452 } 453 imsg_free(&imsg); 454 } 455 if (!shut) 456 imsg_event_add(iev); 457 else { 458 /* This pipe is dead. Remove its event handler. */ 459 event_del(&iev->ev); 460 event_loopexit(NULL); 461 } 462 } 463 464 int 465 get_flags(char *if_name) 466 { 467 struct ifreq ifr; 468 469 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 470 if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 471 log_warn("SIOCGIFFLAGS"); 472 return -1; 473 } 474 return ifr.ifr_flags; 475 } 476 477 int 478 get_xflags(char *if_name) 479 { 480 struct ifreq ifr; 481 482 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 483 if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) { 484 log_warn("SIOCGIFXFLAGS"); 485 return -1; 486 } 487 return ifr.ifr_flags; 488 } 489 490 int 491 get_ifrdomain(char *if_name) 492 { 493 struct ifreq ifr; 494 495 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 496 if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { 497 log_warn("SIOCGIFRDOMAIN"); 498 return -1; 499 } 500 return ifr.ifr_rdomainid; 501 } 502 503 void 504 update_iface(uint32_t if_index, char* if_name) 505 { 506 struct iface *iface; 507 struct ifaddrs *ifap, *ifa; 508 struct imsg_ifinfo imsg_ifinfo; 509 struct sockaddr_dl *sdl; 510 struct sockaddr_in6 *sin6; 511 struct in6_ifreq ifr6; 512 int flags, xflags, ifrdomain; 513 514 if ((flags = get_flags(if_name)) == -1 || (xflags = 515 get_xflags(if_name)) == -1) 516 return; 517 518 if (!(xflags & (IFXF_AUTOCONF6 | IFXF_AUTOCONF6TEMP))) 519 return; 520 521 if ((ifrdomain = get_ifrdomain(if_name)) == -1) 522 return; 523 524 iface = get_iface_by_id(if_index); 525 526 if (iface != NULL) { 527 if (iface->rdomain != ifrdomain) { 528 unref_icmp6ev(iface); 529 iface->rdomain = ifrdomain; 530 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 531 } 532 } else { 533 if ((iface = calloc(1, sizeof(*iface))) == NULL) 534 fatal("calloc"); 535 iface->if_index = if_index; 536 iface->rdomain = ifrdomain; 537 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 538 iface->ll_tentative = 1; 539 540 LIST_INSERT_HEAD(&interfaces, iface, entries); 541 } 542 543 memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo)); 544 545 imsg_ifinfo.if_index = if_index; 546 imsg_ifinfo.rdomain = ifrdomain; 547 imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | 548 IFF_RUNNING); 549 imsg_ifinfo.autoconf = (xflags & IFXF_AUTOCONF6); 550 imsg_ifinfo.temporary = (xflags & IFXF_AUTOCONF6TEMP); 551 imsg_ifinfo.soii = !(xflags & IFXF_INET6_NOSOII); 552 553 if (getifaddrs(&ifap) != 0) 554 fatal("getifaddrs"); 555 556 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 557 if (strcmp(if_name, ifa->ifa_name) != 0) 558 continue; 559 if (ifa->ifa_addr == NULL) 560 continue; 561 562 switch(ifa->ifa_addr->sa_family) { 563 case AF_LINK: 564 imsg_ifinfo.link_state = 565 ((struct if_data *)ifa->ifa_data)->ifi_link_state; 566 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 567 if (sdl->sdl_type != IFT_ETHER || 568 sdl->sdl_alen != ETHER_ADDR_LEN) 569 continue; 570 memcpy(iface->hw_address.ether_addr_octet, 571 LLADDR(sdl), ETHER_ADDR_LEN); 572 memcpy(imsg_ifinfo.hw_address.ether_addr_octet, 573 LLADDR(sdl), ETHER_ADDR_LEN); 574 case AF_INET6: 575 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 576 #ifdef __KAME__ 577 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 578 sin6->sin6_scope_id == 0) { 579 sin6->sin6_scope_id = ntohs(*(u_int16_t *) 580 &sin6->sin6_addr.s6_addr[2]); 581 sin6->sin6_addr.s6_addr[2] = 582 sin6->sin6_addr.s6_addr[3] = 0; 583 } 584 #endif 585 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 586 memcpy(&imsg_ifinfo.ll_address, sin6, 587 sizeof(imsg_ifinfo.ll_address)); 588 589 if (!iface->ll_tentative) 590 break; 591 592 memset(&ifr6, 0, sizeof(ifr6)); 593 strlcpy(ifr6.ifr_name, if_name, 594 sizeof(ifr6.ifr_name)); 595 memcpy(&ifr6.ifr_addr, sin6, 596 sizeof(ifr6.ifr_addr)); 597 598 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, 599 (caddr_t)&ifr6) == -1) { 600 log_warn("SIOCGIFAFLAG_IN6"); 601 break; 602 } 603 604 if (!(ifr6.ifr_ifru.ifru_flags6 & 605 IN6_IFF_TENTATIVE)) { 606 iface->ll_tentative = 0; 607 if (iface->send_solicitation) 608 send_solicitation( 609 iface->if_index); 610 } 611 } 612 break; 613 default: 614 break; 615 } 616 } 617 618 freeifaddrs(ifap); 619 620 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo, 621 sizeof(imsg_ifinfo)); 622 } 623 624 #ifndef SMALL 625 const char* 626 flags_to_str(int flags) 627 { 628 static char buf[sizeof(" anycast tentative duplicated detached " 629 "deprecated autoconf temporary")]; 630 631 buf[0] = '\0'; 632 if (flags & IN6_IFF_ANYCAST) 633 strlcat(buf, " anycast", sizeof(buf)); 634 if (flags & IN6_IFF_TENTATIVE) 635 strlcat(buf, " tentative", sizeof(buf)); 636 if (flags & IN6_IFF_DUPLICATED) 637 strlcat(buf, " duplicated", sizeof(buf)); 638 if (flags & IN6_IFF_DETACHED) 639 strlcat(buf, " detached", sizeof(buf)); 640 if (flags & IN6_IFF_DEPRECATED) 641 strlcat(buf, " deprecated", sizeof(buf)); 642 if (flags & IN6_IFF_AUTOCONF) 643 strlcat(buf, " autoconf", sizeof(buf)); 644 if (flags & IN6_IFF_TEMPORARY) 645 strlcat(buf, " temporary", sizeof(buf)); 646 647 return (buf); 648 } 649 #endif /* SMALL */ 650 651 void 652 frontend_startup(void) 653 { 654 struct if_nameindex *ifnidxp, *ifnidx; 655 656 if (!event_initialized(&ev_route)) 657 fatalx("%s: did not receive a route socket from the main " 658 "process", __func__); 659 660 event_add(&ev_route, NULL); 661 662 if ((ifnidxp = if_nameindex()) == NULL) 663 fatalx("if_nameindex"); 664 665 for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL; 666 ifnidx++) 667 update_iface(ifnidx->if_index, ifnidx->if_name); 668 669 if_freenameindex(ifnidxp); 670 } 671 672 void 673 route_receive(int fd, short events, void *arg) 674 { 675 static uint8_t *buf; 676 677 struct rt_msghdr *rtm; 678 struct sockaddr *sa, *rti_info[RTAX_MAX]; 679 ssize_t n; 680 681 if (buf == NULL) { 682 buf = malloc(ROUTE_SOCKET_BUF_SIZE); 683 if (buf == NULL) 684 fatal("malloc"); 685 } 686 rtm = (struct rt_msghdr *)buf; 687 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 688 if (errno == EAGAIN || errno == EINTR) 689 return; 690 log_warn("dispatch_rtmsg: read error"); 691 return; 692 } 693 694 if (n == 0) 695 fatal("routing socket closed"); 696 697 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 698 log_warnx("partial rtm of %zd in buffer", n); 699 return; 700 } 701 702 if (rtm->rtm_version != RTM_VERSION) 703 return; 704 705 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 706 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 707 708 handle_route_message(rtm, rti_info); 709 } 710 711 void 712 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 713 { 714 struct if_msghdr *ifm; 715 struct if_announcemsghdr *ifan; 716 struct imsg_del_addr del_addr; 717 struct imsg_del_route del_route; 718 struct imsg_dup_addr dup_addr; 719 struct sockaddr_rtlabel *rl; 720 struct sockaddr_in6 *sin6; 721 struct in6_ifreq ifr6; 722 struct in6_addr *in6; 723 int xflags, if_index; 724 char ifnamebuf[IFNAMSIZ]; 725 char *if_name; 726 727 switch (rtm->rtm_type) { 728 case RTM_IFINFO: 729 ifm = (struct if_msghdr *)rtm; 730 if_index = ifm->ifm_index; 731 if_name = if_indextoname(if_index, ifnamebuf); 732 if (if_name == NULL) { 733 log_debug("RTM_IFINFO: lost if %d", if_index); 734 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 735 &if_index, sizeof(if_index)); 736 remove_iface(if_index); 737 break; 738 } 739 xflags = get_xflags(if_name); 740 if (xflags == -1 || !(xflags & (IFXF_AUTOCONF6 | 741 IFXF_AUTOCONF6TEMP))) { 742 log_debug("RTM_IFINFO: %s(%d) no(longer) autoconf6", 743 if_name, if_index); 744 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 745 0, &if_index, sizeof(if_index)); 746 remove_iface(if_index); 747 } else { 748 update_iface(if_index, if_name); 749 } 750 break; 751 case RTM_IFANNOUNCE: 752 ifan = (struct if_announcemsghdr *)rtm; 753 if_index = ifan->ifan_index; 754 if (ifan->ifan_what == IFAN_DEPARTURE) { 755 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 756 &if_index, sizeof(if_index)); 757 remove_iface(if_index); 758 } 759 break; 760 case RTM_NEWADDR: 761 ifm = (struct if_msghdr *)rtm; 762 if_index = ifm->ifm_index; 763 if_name = if_indextoname(if_index, ifnamebuf); 764 if (if_name == NULL) { 765 log_debug("RTM_NEWADDR: lost if %d", if_index); 766 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 767 &if_index, sizeof(if_index)); 768 remove_iface(if_index); 769 break; 770 } 771 772 log_debug("RTM_NEWADDR: %s[%u]", if_name, if_index); 773 update_iface(if_index, if_name); 774 break; 775 case RTM_DELADDR: 776 ifm = (struct if_msghdr *)rtm; 777 if_index = ifm->ifm_index; 778 if_name = if_indextoname(if_index, ifnamebuf); 779 if (if_name == NULL) { 780 log_debug("RTM_DELADDR: lost if %d", if_index); 781 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 782 &if_index, sizeof(if_index)); 783 remove_iface(if_index); 784 break; 785 } 786 if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family 787 == AF_INET6) { 788 del_addr.if_index = if_index; 789 memcpy(&del_addr.addr, rti_info[RTAX_IFA], sizeof( 790 del_addr.addr)); 791 frontend_imsg_compose_engine(IMSG_DEL_ADDRESS, 792 0, 0, &del_addr, sizeof(del_addr)); 793 log_debug("RTM_DELADDR: %s[%u]", if_name, if_index); 794 } 795 break; 796 case RTM_CHGADDRATTR: 797 ifm = (struct if_msghdr *)rtm; 798 if_index = ifm->ifm_index; 799 if_name = if_indextoname(if_index, ifnamebuf); 800 if (if_name == NULL) { 801 log_debug("RTM_CHGADDRATTR: lost if %d", if_index); 802 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 803 &if_index, sizeof(if_index)); 804 remove_iface(if_index); 805 break; 806 } 807 if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family 808 == AF_INET6) { 809 sin6 = (struct sockaddr_in6 *) rti_info[RTAX_IFA]; 810 811 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 812 update_iface(if_index, if_name); 813 break; 814 } 815 816 memset(&ifr6, 0, sizeof(ifr6)); 817 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 818 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 819 820 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) 821 == -1) { 822 log_warn("SIOCGIFAFLAG_IN6"); 823 break; 824 } 825 826 #ifndef SMALL 827 log_debug("RTM_CHGADDRATTR: %s - %s", 828 sin6_to_str(sin6), 829 flags_to_str(ifr6.ifr_ifru.ifru_flags6)); 830 #endif /* SMALL */ 831 832 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) { 833 dup_addr.if_index = if_index; 834 dup_addr.addr = *sin6; 835 frontend_imsg_compose_engine(IMSG_DUP_ADDRESS, 836 0, 0, &dup_addr, sizeof(dup_addr)); 837 } 838 839 } 840 break; 841 case RTM_DELETE: 842 ifm = (struct if_msghdr *)rtm; 843 if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_LABEL)) != 844 (RTA_DST | RTA_GATEWAY | RTA_LABEL)) 845 break; 846 if (rti_info[RTAX_DST]->sa_family != AF_INET6) 847 break; 848 if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) 849 rti_info[RTAX_DST])->sin6_addr)) 850 break; 851 if (rti_info[RTAX_GATEWAY]->sa_family != AF_INET6) 852 break; 853 if (rti_info[RTAX_LABEL]->sa_len != 854 sizeof(struct sockaddr_rtlabel)) 855 break; 856 857 rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL]; 858 if (strcmp(rl->sr_label, SLAACD_RTA_LABEL) != 0) 859 break; 860 if_index = ifm->ifm_index; 861 if_name = if_indextoname(if_index, ifnamebuf); 862 if (if_name == NULL) { 863 log_debug("RTM_DELETE: lost if %d", if_index); 864 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 865 &if_index, sizeof(if_index)); 866 remove_iface(if_index); 867 break; 868 } 869 870 del_route.if_index = if_index; 871 memcpy(&del_route.gw, rti_info[RTAX_GATEWAY], 872 sizeof(del_route.gw)); 873 in6 = &del_route.gw.sin6_addr; 874 #ifdef __KAME__ 875 /* XXX from route(8) p_sockaddr() */ 876 if ((IN6_IS_ADDR_LINKLOCAL(in6) || 877 IN6_IS_ADDR_MC_LINKLOCAL(in6) || 878 IN6_IS_ADDR_MC_INTFACELOCAL(in6)) && 879 del_route.gw.sin6_scope_id == 0) { 880 del_route.gw.sin6_scope_id = 881 (u_int32_t)ntohs(*(u_short *) &in6->s6_addr[2]); 882 *(u_short *)&in6->s6_addr[2] = 0; 883 } 884 #endif 885 frontend_imsg_compose_engine(IMSG_DEL_ROUTE, 886 0, 0, &del_route, sizeof(del_route)); 887 log_debug("RTM_DELETE: %s[%u]", if_name, 888 ifm->ifm_index); 889 890 break; 891 #ifndef SMALL 892 case RTM_PROPOSAL: 893 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { 894 log_debug("RTP_PROPOSAL_SOLICIT"); 895 frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, 896 0, 0, NULL, 0); 897 } 898 break; 899 #endif /* SMALL */ 900 default: 901 log_debug("unexpected RTM: %d", rtm->rtm_type); 902 break; 903 } 904 905 } 906 907 #define ROUNDUP(a) \ 908 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 909 910 void 911 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 912 { 913 int i; 914 915 for (i = 0; i < RTAX_MAX; i++) { 916 if (addrs & (1 << i)) { 917 rti_info[i] = sa; 918 sa = (struct sockaddr *)((char *)(sa) + 919 ROUNDUP(sa->sa_len)); 920 } else 921 rti_info[i] = NULL; 922 } 923 } 924 925 void 926 icmp6_receive(int fd, short events, void *arg) 927 { 928 struct imsg_ra ra; 929 struct icmp6_hdr *icmp6_hdr; 930 struct icmp6_ev *icmp6ev; 931 struct in6_pktinfo *pi = NULL; 932 struct cmsghdr *cm; 933 ssize_t len; 934 int if_index = 0, *hlimp = NULL; 935 char ntopbuf[INET6_ADDRSTRLEN]; 936 #ifndef SMALL 937 char ifnamebuf[IFNAMSIZ]; 938 #endif /* SMALL */ 939 940 icmp6ev = arg; 941 if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) { 942 log_warn("recvmsg"); 943 return; 944 } 945 946 if ((size_t)len < sizeof(struct icmp6_hdr)) 947 return; 948 949 icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer; 950 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT) 951 return; 952 953 /* extract optional information via Advanced API */ 954 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm; 955 cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) { 956 if (cm->cmsg_level == IPPROTO_IPV6 && 957 cm->cmsg_type == IPV6_PKTINFO && 958 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 959 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 960 if_index = pi->ipi6_ifindex; 961 } 962 if (cm->cmsg_level == IPPROTO_IPV6 && 963 cm->cmsg_type == IPV6_HOPLIMIT && 964 cm->cmsg_len == CMSG_LEN(sizeof(int))) 965 hlimp = (int *)CMSG_DATA(cm); 966 } 967 968 if (if_index == 0) { 969 log_warnx("failed to get receiving interface"); 970 return; 971 } 972 973 if (hlimp == NULL) { 974 log_warnx("failed to get receiving hop limit"); 975 return; 976 } 977 978 if (*hlimp != 255) { 979 log_warnx("invalid RA with hop limit of %d from %s on %s", 980 *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 981 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 982 ifnamebuf)); 983 return; 984 } 985 986 if ((size_t)len > sizeof(ra.packet)) { 987 log_warnx("invalid RA with size %ld from %s on %s", 988 len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 989 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 990 ifnamebuf)); 991 return; 992 } 993 ra.if_index = if_index; 994 memcpy(&ra.from, &icmp6ev->from, sizeof(ra.from)); 995 ra.len = len; 996 memcpy(ra.packet, icmp6ev->answer, len); 997 998 frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra)); 999 } 1000 1001 void 1002 send_solicitation(uint32_t if_index) 1003 { 1004 struct in6_pktinfo *pi; 1005 struct cmsghdr *cm; 1006 struct iface *iface; 1007 1008 log_debug("%s(%u)", __func__, if_index); 1009 1010 if ((iface = get_iface_by_id(if_index)) == NULL) 1011 return; 1012 1013 if (!event_initialized(&iface->icmp6ev->ev)) { 1014 iface->send_solicitation = 1; 1015 return; 1016 } else if (iface->ll_tentative) { 1017 iface->send_solicitation = 1; 1018 return; 1019 } 1020 1021 iface->send_solicitation = 0; 1022 1023 dst.sin6_scope_id = if_index; 1024 1025 cm = CMSG_FIRSTHDR(&sndmhdr); 1026 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1027 pi->ipi6_ifindex = if_index; 1028 1029 memcpy(&nd_opt_source_link_addr, &iface->hw_address, 1030 sizeof(nd_opt_source_link_addr)); 1031 1032 if (sendmsg(EVENT_FD(&iface->icmp6ev->ev), &sndmhdr, 0) != sizeof(rs) + 1033 sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr)) 1034 log_warn("sendmsg"); 1035 } 1036 1037 struct iface* 1038 get_iface_by_id(uint32_t if_index) 1039 { 1040 struct iface *iface; 1041 1042 LIST_FOREACH (iface, &interfaces, entries) { 1043 if (iface->if_index == if_index) 1044 return (iface); 1045 } 1046 1047 return (NULL); 1048 } 1049 1050 void 1051 remove_iface(uint32_t if_index) 1052 { 1053 struct iface *iface; 1054 1055 iface = get_iface_by_id(if_index); 1056 1057 if (iface == NULL) 1058 return; 1059 1060 LIST_REMOVE(iface, entries); 1061 1062 unref_icmp6ev(iface); 1063 free(iface); 1064 } 1065 1066 struct icmp6_ev* 1067 get_icmp6ev_by_rdomain(int rdomain) 1068 { 1069 struct iface *iface; 1070 struct icmp6_ev *icmp6ev = NULL; 1071 1072 LIST_FOREACH (iface, &interfaces, entries) { 1073 if (iface->rdomain == rdomain) { 1074 icmp6ev = iface->icmp6ev; 1075 break; 1076 } 1077 } 1078 1079 if (icmp6ev == NULL) { 1080 if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL) 1081 fatal("calloc"); 1082 icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer; 1083 icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer); 1084 icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from; 1085 icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from); 1086 icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov; 1087 icmp6ev->rcvmhdr.msg_iovlen = 1; 1088 icmp6ev->rcvmhdr.msg_controllen = 1089 CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1090 CMSG_SPACE(sizeof(int)); 1091 if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev-> 1092 rcvmhdr.msg_controllen)) == NULL) 1093 fatal("malloc"); 1094 frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0, 1095 &rdomain, sizeof(rdomain)); 1096 } 1097 icmp6ev->refcnt++; 1098 return (icmp6ev); 1099 } 1100 1101 void 1102 unref_icmp6ev(struct iface *iface) 1103 { 1104 struct icmp6_ev *icmp6ev = iface->icmp6ev; 1105 1106 iface->icmp6ev = NULL; 1107 1108 if (icmp6ev != NULL) { 1109 icmp6ev->refcnt--; 1110 if (icmp6ev->refcnt == 0) { 1111 event_del(&icmp6ev->ev); 1112 close(EVENT_FD(&icmp6ev->ev)); 1113 free(icmp6ev); 1114 } 1115 } 1116 } 1117 1118 void 1119 set_icmp6sock(int icmp6sock, int rdomain) 1120 { 1121 struct iface *iface; 1122 1123 LIST_FOREACH (iface, &interfaces, entries) { 1124 if (!event_initialized(&iface->icmp6ev->ev) && iface->rdomain 1125 == rdomain) { 1126 event_set(&iface->icmp6ev->ev, icmp6sock, EV_READ | 1127 EV_PERSIST, icmp6_receive, iface->icmp6ev); 1128 event_add(&iface->icmp6ev->ev, NULL); 1129 icmp6sock = -1; 1130 break; 1131 } 1132 } 1133 1134 if (icmp6sock != -1) { 1135 /* 1136 * The interface disappeared or changed rdomain while we were 1137 * waiting for the parent process to open the raw socket. 1138 */ 1139 close(icmp6sock); 1140 return; 1141 } 1142 1143 LIST_FOREACH (iface, &interfaces, entries) { 1144 if (event_initialized(&iface->icmp6ev->ev) && 1145 iface->send_solicitation) 1146 send_solicitation(iface->if_index); 1147 } 1148 } 1149