1 /* $OpenBSD: frontend.c,v 1.63 2022/03/21 16:25:47 florian 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 <netinet6/ip6_var.h> 41 #include <netinet/icmp6.h> 42 43 #include <errno.h> 44 #include <event.h> 45 #include <ifaddrs.h> 46 #include <imsg.h> 47 #include <pwd.h> 48 #include <signal.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include "log.h" 55 #include "slaacd.h" 56 #include "frontend.h" 57 #include "control.h" 58 59 #define ROUTE_SOCKET_BUF_SIZE 16384 60 #define ALLROUTER "ff02::2" 61 62 struct icmp6_ev { 63 struct event ev; 64 uint8_t answer[1500]; 65 struct msghdr rcvmhdr; 66 struct iovec rcviov[1]; 67 struct sockaddr_in6 from; 68 int refcnt; 69 }; 70 71 struct iface { 72 LIST_ENTRY(iface) entries; 73 struct icmp6_ev *icmp6ev; 74 struct ether_addr hw_address; 75 uint32_t if_index; 76 int rdomain; 77 int send_solicitation; 78 int ll_tentative; 79 }; 80 81 __dead void frontend_shutdown(void); 82 void frontend_sig_handler(int, short, void *); 83 void update_iface(uint32_t, char*); 84 void frontend_startup(void); 85 void route_receive(int, short, void *); 86 void handle_route_message(struct rt_msghdr *, struct sockaddr **); 87 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 88 void icmp6_receive(int, short, void *); 89 int get_flags(char *); 90 int get_xflags(char *); 91 int get_ifrdomain(char *); 92 struct iface *get_iface_by_id(uint32_t); 93 void remove_iface(uint32_t); 94 struct icmp6_ev *get_icmp6ev_by_rdomain(int); 95 void unref_icmp6ev(struct iface *); 96 void set_icmp6sock(int, int); 97 void send_solicitation(uint32_t); 98 #ifndef SMALL 99 void update_autoconf_addresses(uint32_t, char*); 100 const char *flags_to_str(int); 101 #endif /* SMALL */ 102 103 LIST_HEAD(, iface) interfaces; 104 static struct imsgev *iev_main; 105 static struct imsgev *iev_engine; 106 struct event ev_route; 107 struct msghdr sndmhdr; 108 struct iovec sndiov[4]; 109 struct nd_router_solicit rs; 110 struct nd_opt_hdr nd_opt_hdr; 111 struct ether_addr nd_opt_source_link_addr; 112 struct sockaddr_in6 dst; 113 int ioctlsock; 114 115 void 116 frontend_sig_handler(int sig, short event, void *bula) 117 { 118 /* 119 * Normal signal handler rules don't apply because libevent 120 * decouples for us. 121 */ 122 123 switch (sig) { 124 case SIGINT: 125 case SIGTERM: 126 frontend_shutdown(); 127 default: 128 fatalx("unexpected signal"); 129 } 130 } 131 132 void 133 frontend(int debug, int verbose) 134 { 135 struct event ev_sigint, ev_sigterm; 136 struct passwd *pw; 137 struct in6_pktinfo *pi; 138 struct cmsghdr *cm; 139 size_t sndcmsglen; 140 int hoplimit = 255; 141 uint8_t *sndcmsgbuf; 142 143 log_init(debug, LOG_DAEMON); 144 log_setverbose(verbose); 145 146 if ((pw = getpwnam(SLAACD_USER)) == NULL) 147 fatal("getpwnam"); 148 149 if (chdir("/") == -1) 150 fatal("chdir(\"/\")"); 151 152 if (unveil("/", "") == -1) 153 fatal("unveil /"); 154 if (unveil(NULL, NULL) == -1) 155 fatal("unveil"); 156 157 setproctitle("%s", "frontend"); 158 log_procinit("frontend"); 159 160 if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 161 fatal("socket"); 162 163 if (setgroups(1, &pw->pw_gid) || 164 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 165 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 166 fatal("can't drop privileges"); 167 168 if (pledge("stdio unix recvfd route", NULL) == -1) 169 fatal("pledge"); 170 171 event_init(); 172 173 /* Setup signal handler. */ 174 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 175 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 176 signal_add(&ev_sigint, NULL); 177 signal_add(&ev_sigterm, NULL); 178 signal(SIGPIPE, SIG_IGN); 179 signal(SIGHUP, SIG_IGN); 180 181 /* Setup pipe and event handler to the parent process. */ 182 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 183 fatal(NULL); 184 imsg_init(&iev_main->ibuf, 3); 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 msgbuf_write(&iev_engine->ibuf.w); 251 msgbuf_clear(&iev_engine->ibuf.w); 252 close(iev_engine->ibuf.fd); 253 msgbuf_write(&iev_main->ibuf.w); 254 msgbuf_clear(&iev_main->ibuf.w); 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 int shut = 0, icmp6sock, rdomain; 288 289 if (event & EV_READ) { 290 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 291 fatal("imsg_read error"); 292 if (n == 0) /* Connection closed. */ 293 shut = 1; 294 } 295 if (event & EV_WRITE) { 296 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 297 fatal("msgbuf_write"); 298 if (n == 0) /* Connection closed. */ 299 shut = 1; 300 } 301 302 for (;;) { 303 if ((n = imsg_get(ibuf, &imsg)) == -1) 304 fatal("%s: imsg_get error", __func__); 305 if (n == 0) /* No more messages. */ 306 break; 307 308 switch (imsg.hdr.type) { 309 case IMSG_SOCKET_IPC: 310 /* 311 * Setup pipe and event handler to the engine 312 * process. 313 */ 314 if (iev_engine) 315 fatalx("%s: received unexpected imsg fd " 316 "to frontend", __func__); 317 318 if ((fd = imsg.fd) == -1) 319 fatalx("%s: expected to receive imsg fd to " 320 "frontend but didn't receive any", 321 __func__); 322 323 iev_engine = malloc(sizeof(struct imsgev)); 324 if (iev_engine == NULL) 325 fatal(NULL); 326 327 imsg_init(&iev_engine->ibuf, fd); 328 iev_engine->handler = frontend_dispatch_engine; 329 iev_engine->events = EV_READ; 330 331 event_set(&iev_engine->ev, iev_engine->ibuf.fd, 332 iev_engine->events, iev_engine->handler, iev_engine); 333 event_add(&iev_engine->ev, NULL); 334 break; 335 case IMSG_ICMP6SOCK: 336 if ((icmp6sock = imsg.fd) == -1) 337 fatalx("%s: expected to receive imsg " 338 "ICMPv6 fd but didn't receive any", 339 __func__); 340 if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) 341 fatalx("%s: IMSG_ICMP6SOCK wrong length: " 342 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 343 memcpy(&rdomain, imsg.data, sizeof(rdomain)); 344 set_icmp6sock(icmp6sock, rdomain); 345 break; 346 case IMSG_ROUTESOCK: 347 if ((fd = imsg.fd) == -1) 348 fatalx("%s: expected to receive imsg " 349 "routesocket fd but didn't receive any", 350 __func__); 351 event_set(&ev_route, fd, EV_READ | EV_PERSIST, 352 route_receive, NULL); 353 break; 354 case IMSG_STARTUP: 355 frontend_startup(); 356 break; 357 #ifndef SMALL 358 case IMSG_CONTROLFD: 359 if ((fd = imsg.fd) == -1) 360 fatalx("%s: expected to receive imsg " 361 "control fd but didn't receive any", 362 __func__); 363 /* Listen on control socket. */ 364 control_listen(fd); 365 break; 366 case IMSG_CTL_END: 367 control_imsg_relay(&imsg); 368 break; 369 #endif /* SMALL */ 370 default: 371 log_debug("%s: error handling imsg %d", __func__, 372 imsg.hdr.type); 373 break; 374 } 375 imsg_free(&imsg); 376 } 377 if (!shut) 378 imsg_event_add(iev); 379 else { 380 /* This pipe is dead. Remove its event handler. */ 381 event_del(&iev->ev); 382 event_loopexit(NULL); 383 } 384 } 385 386 void 387 frontend_dispatch_engine(int fd, short event, void *bula) 388 { 389 struct imsgev *iev = bula; 390 struct imsgbuf *ibuf = &iev->ibuf; 391 struct imsg imsg; 392 ssize_t n; 393 int shut = 0; 394 uint32_t if_index; 395 396 if (event & EV_READ) { 397 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 398 fatal("imsg_read error"); 399 if (n == 0) /* Connection closed. */ 400 shut = 1; 401 } 402 if (event & EV_WRITE) { 403 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 404 fatal("msgbuf_write"); 405 if (n == 0) /* Connection closed. */ 406 shut = 1; 407 } 408 409 for (;;) { 410 if ((n = imsg_get(ibuf, &imsg)) == -1) 411 fatal("%s: imsg_get error", __func__); 412 if (n == 0) /* No more messages. */ 413 break; 414 415 switch (imsg.hdr.type) { 416 #ifndef SMALL 417 case IMSG_CTL_END: 418 case IMSG_CTL_SHOW_INTERFACE_INFO: 419 case IMSG_CTL_SHOW_INTERFACE_INFO_RA: 420 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX: 421 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS: 422 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS: 423 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: 424 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: 425 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: 426 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS: 427 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL: 428 control_imsg_relay(&imsg); 429 break; 430 #endif /* SMALL */ 431 case IMSG_CTL_SEND_SOLICITATION: 432 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 433 fatalx("%s: IMSG_CTL_SEND_SOLICITATION wrong " 434 "length: %lu", __func__, 435 IMSG_DATA_SIZE(imsg)); 436 if_index = *((uint32_t *)imsg.data); 437 send_solicitation(if_index); 438 break; 439 default: 440 log_debug("%s: error handling imsg %d", __func__, 441 imsg.hdr.type); 442 break; 443 } 444 imsg_free(&imsg); 445 } 446 if (!shut) 447 imsg_event_add(iev); 448 else { 449 /* This pipe is dead. Remove its event handler. */ 450 event_del(&iev->ev); 451 event_loopexit(NULL); 452 } 453 } 454 455 int 456 get_flags(char *if_name) 457 { 458 struct ifreq ifr; 459 460 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 461 if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 462 log_warn("SIOCGIFFLAGS"); 463 return -1; 464 } 465 return ifr.ifr_flags; 466 } 467 468 int 469 get_xflags(char *if_name) 470 { 471 struct ifreq ifr; 472 473 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 474 if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) { 475 log_warn("SIOCGIFXFLAGS"); 476 return -1; 477 } 478 return ifr.ifr_flags; 479 } 480 481 int 482 get_ifrdomain(char *if_name) 483 { 484 struct ifreq ifr; 485 486 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 487 if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { 488 log_warn("SIOCGIFRDOMAIN"); 489 return -1; 490 } 491 return ifr.ifr_rdomainid; 492 } 493 494 void 495 update_iface(uint32_t if_index, char* if_name) 496 { 497 struct iface *iface; 498 struct ifaddrs *ifap, *ifa; 499 struct imsg_ifinfo imsg_ifinfo; 500 struct sockaddr_dl *sdl; 501 struct sockaddr_in6 *sin6; 502 struct in6_ifreq ifr6; 503 int flags, xflags, ifrdomain; 504 505 if ((flags = get_flags(if_name)) == -1 || (xflags = 506 get_xflags(if_name)) == -1) 507 return; 508 509 if (!(xflags & (IFXF_AUTOCONF6 | IFXF_AUTOCONF6TEMP))) 510 return; 511 512 if((ifrdomain = get_ifrdomain(if_name)) == -1) 513 return; 514 515 iface = get_iface_by_id(if_index); 516 517 if (iface != NULL) { 518 if (iface->rdomain != ifrdomain) { 519 unref_icmp6ev(iface); 520 iface->rdomain = ifrdomain; 521 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 522 } 523 } else { 524 if ((iface = calloc(1, sizeof(*iface))) == NULL) 525 fatal("calloc"); 526 iface->if_index = if_index; 527 iface->rdomain = ifrdomain; 528 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 529 iface->ll_tentative = 1; 530 531 LIST_INSERT_HEAD(&interfaces, iface, entries); 532 } 533 534 memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo)); 535 536 imsg_ifinfo.if_index = if_index; 537 imsg_ifinfo.rdomain = ifrdomain; 538 imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | 539 IFF_RUNNING); 540 imsg_ifinfo.autoconf = (xflags & IFXF_AUTOCONF6); 541 imsg_ifinfo.temporary = (xflags & IFXF_AUTOCONF6TEMP); 542 imsg_ifinfo.soii = !(xflags & IFXF_INET6_NOSOII); 543 544 if (getifaddrs(&ifap) != 0) 545 fatal("getifaddrs"); 546 547 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 548 if (strcmp(if_name, ifa->ifa_name) != 0) 549 continue; 550 if (ifa->ifa_addr == NULL) 551 continue; 552 553 switch(ifa->ifa_addr->sa_family) { 554 case AF_LINK: 555 imsg_ifinfo.link_state = 556 ((struct if_data *)ifa->ifa_data)->ifi_link_state; 557 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 558 if (sdl->sdl_type != IFT_ETHER || 559 sdl->sdl_alen != ETHER_ADDR_LEN) 560 continue; 561 memcpy(iface->hw_address.ether_addr_octet, 562 LLADDR(sdl), ETHER_ADDR_LEN); 563 memcpy(imsg_ifinfo.hw_address.ether_addr_octet, 564 LLADDR(sdl), ETHER_ADDR_LEN); 565 case AF_INET6: 566 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 567 #ifdef __KAME__ 568 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 569 sin6->sin6_scope_id == 0) { 570 sin6->sin6_scope_id = ntohs(*(u_int16_t *) 571 &sin6->sin6_addr.s6_addr[2]); 572 sin6->sin6_addr.s6_addr[2] = 573 sin6->sin6_addr.s6_addr[3] = 0; 574 } 575 #endif 576 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 577 memcpy(&imsg_ifinfo.ll_address, sin6, 578 sizeof(imsg_ifinfo.ll_address)); 579 580 if (!iface->ll_tentative) 581 break; 582 583 memset(&ifr6, 0, sizeof(ifr6)); 584 strlcpy(ifr6.ifr_name, if_name, 585 sizeof(ifr6.ifr_name)); 586 memcpy(&ifr6.ifr_addr, sin6, 587 sizeof(ifr6.ifr_addr)); 588 589 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, 590 (caddr_t)&ifr6) == -1) { 591 log_warn("SIOCGIFAFLAG_IN6"); 592 break; 593 } 594 595 if (!(ifr6.ifr_ifru.ifru_flags6 & 596 IN6_IFF_TENTATIVE)) { 597 iface->ll_tentative = 0; 598 if (iface->send_solicitation) 599 send_solicitation( 600 iface->if_index); 601 } 602 } 603 break; 604 default: 605 break; 606 } 607 } 608 609 freeifaddrs(ifap); 610 611 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo, 612 sizeof(imsg_ifinfo)); 613 } 614 615 #ifndef SMALL 616 void 617 update_autoconf_addresses(uint32_t if_index, char* if_name) 618 { 619 struct in6_ifreq ifr6; 620 struct imsg_addrinfo imsg_addrinfo; 621 struct ifaddrs *ifap, *ifa; 622 struct in6_addrlifetime *lifetime; 623 struct sockaddr_in6 *sin6; 624 time_t t; 625 int xflags; 626 627 if ((xflags = get_xflags(if_name)) == -1) 628 return; 629 630 if (!(xflags & (IFXF_AUTOCONF6 | IFXF_AUTOCONF6TEMP))) 631 return; 632 633 memset(&imsg_addrinfo, 0, sizeof(imsg_addrinfo)); 634 imsg_addrinfo.if_index = if_index; 635 636 if (getifaddrs(&ifap) != 0) 637 fatal("getifaddrs"); 638 639 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 640 if (strcmp(if_name, ifa->ifa_name) != 0) 641 continue; 642 if (ifa->ifa_addr == NULL) 643 continue; 644 645 if (ifa->ifa_addr->sa_family != AF_INET6) 646 continue; 647 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 648 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 649 continue; 650 651 log_debug("%s: IP: %s", __func__, sin6_to_str(sin6)); 652 imsg_addrinfo.addr = *sin6; 653 654 memset(&ifr6, 0, sizeof(ifr6)); 655 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 656 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 657 658 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) { 659 log_warn("SIOCGIFAFLAG_IN6"); 660 continue; 661 } 662 663 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | 664 IN6_IFF_TEMPORARY))) 665 continue; 666 667 imsg_addrinfo.temporary = ifr6.ifr_ifru.ifru_flags6 & 668 IN6_IFF_TEMPORARY ? 1 : 0; 669 670 memset(&ifr6, 0, sizeof(ifr6)); 671 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 672 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 673 674 if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == 675 -1) { 676 log_warn("SIOCGIFNETMASK_IN6"); 677 continue; 678 } 679 680 imsg_addrinfo.mask = ((struct sockaddr_in6 *)&ifr6.ifr_addr) 681 ->sin6_addr; 682 683 memset(&ifr6, 0, sizeof(ifr6)); 684 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 685 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 686 lifetime = &ifr6.ifr_ifru.ifru_lifetime; 687 688 if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == 689 -1) { 690 log_warn("SIOCGIFALIFETIME_IN6"); 691 continue; 692 } 693 694 imsg_addrinfo.vltime = ND6_INFINITE_LIFETIME; 695 imsg_addrinfo.pltime = ND6_INFINITE_LIFETIME; 696 t = time(NULL); 697 698 if (lifetime->ia6t_preferred) 699 imsg_addrinfo.pltime = lifetime->ia6t_preferred < t ? 0 700 : lifetime->ia6t_preferred - t; 701 702 if (lifetime->ia6t_expire) 703 imsg_addrinfo.vltime = lifetime->ia6t_expire < t ? 0 : 704 lifetime->ia6t_expire - t; 705 706 frontend_imsg_compose_main(IMSG_UPDATE_ADDRESS, 0, 707 &imsg_addrinfo, sizeof(imsg_addrinfo)); 708 709 } 710 freeifaddrs(ifap); 711 } 712 713 const char* 714 flags_to_str(int flags) 715 { 716 static char buf[sizeof(" anycast tentative duplicated detached " 717 "deprecated autoconf temporary")]; 718 719 buf[0] = '\0'; 720 if (flags & IN6_IFF_ANYCAST) 721 strlcat(buf, " anycast", sizeof(buf)); 722 if (flags & IN6_IFF_TENTATIVE) 723 strlcat(buf, " tentative", sizeof(buf)); 724 if (flags & IN6_IFF_DUPLICATED) 725 strlcat(buf, " duplicated", sizeof(buf)); 726 if (flags & IN6_IFF_DETACHED) 727 strlcat(buf, " detached", sizeof(buf)); 728 if (flags & IN6_IFF_DEPRECATED) 729 strlcat(buf, " deprecated", sizeof(buf)); 730 if (flags & IN6_IFF_AUTOCONF) 731 strlcat(buf, " autoconf", sizeof(buf)); 732 if (flags & IN6_IFF_TEMPORARY) 733 strlcat(buf, " temporary", sizeof(buf)); 734 735 return (buf); 736 } 737 #endif /* SMALL */ 738 739 void 740 frontend_startup(void) 741 { 742 struct if_nameindex *ifnidxp, *ifnidx; 743 744 if (!event_initialized(&ev_route)) 745 fatalx("%s: did not receive a route socket from the main " 746 "process", __func__); 747 748 event_add(&ev_route, NULL); 749 750 if ((ifnidxp = if_nameindex()) == NULL) 751 fatalx("if_nameindex"); 752 753 for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL; 754 ifnidx++) { 755 update_iface(ifnidx->if_index, ifnidx->if_name); 756 #ifndef SMALL 757 update_autoconf_addresses(ifnidx->if_index, ifnidx->if_name); 758 #endif /* SMALL */ 759 } 760 761 if_freenameindex(ifnidxp); 762 } 763 764 void 765 route_receive(int fd, short events, void *arg) 766 { 767 static uint8_t *buf; 768 769 struct rt_msghdr *rtm; 770 struct sockaddr *sa, *rti_info[RTAX_MAX]; 771 ssize_t n; 772 773 if (buf == NULL) { 774 buf = malloc(ROUTE_SOCKET_BUF_SIZE); 775 if (buf == NULL) 776 fatal("malloc"); 777 } 778 rtm = (struct rt_msghdr *)buf; 779 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 780 if (errno == EAGAIN || errno == EINTR) 781 return; 782 log_warn("dispatch_rtmsg: read error"); 783 return; 784 } 785 786 if (n == 0) 787 fatal("routing socket closed"); 788 789 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 790 log_warnx("partial rtm of %zd in buffer", n); 791 return; 792 } 793 794 if (rtm->rtm_version != RTM_VERSION) 795 return; 796 797 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 798 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 799 800 handle_route_message(rtm, rti_info); 801 } 802 803 void 804 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 805 { 806 struct if_msghdr *ifm; 807 struct if_announcemsghdr *ifan; 808 struct imsg_del_addr del_addr; 809 struct imsg_del_route del_route; 810 struct imsg_dup_addr dup_addr; 811 struct sockaddr_rtlabel *rl; 812 struct sockaddr_in6 *sin6; 813 struct in6_ifreq ifr6; 814 struct in6_addr *in6; 815 int xflags, if_index; 816 char ifnamebuf[IFNAMSIZ]; 817 char *if_name; 818 819 switch (rtm->rtm_type) { 820 case RTM_IFINFO: 821 ifm = (struct if_msghdr *)rtm; 822 if_index = ifm->ifm_index; 823 if_name = if_indextoname(if_index, ifnamebuf); 824 if (if_name == NULL) { 825 log_debug("RTM_IFINFO: lost if %d", if_index); 826 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 827 &if_index, sizeof(if_index)); 828 remove_iface(if_index); 829 break; 830 } 831 xflags = get_xflags(if_name); 832 if (xflags == -1 || !(xflags & (IFXF_AUTOCONF6 | 833 IFXF_AUTOCONF6TEMP))) { 834 log_debug("RTM_IFINFO: %s(%d) no(longer) autoconf6", if_name, 835 if_index); 836 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 837 0, &if_index, sizeof(if_index)); 838 remove_iface(if_index); 839 } else { 840 update_iface(if_index, if_name); 841 #ifndef SMALL 842 update_autoconf_addresses(if_index, if_name); 843 #endif /* SMALL */ 844 } 845 break; 846 case RTM_IFANNOUNCE: 847 ifan = (struct if_announcemsghdr *)rtm; 848 if_index = ifan->ifan_index; 849 if (ifan->ifan_what == IFAN_DEPARTURE) { 850 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 851 &if_index, sizeof(if_index)); 852 remove_iface(if_index); 853 } 854 break; 855 case RTM_NEWADDR: 856 ifm = (struct if_msghdr *)rtm; 857 if_index = ifm->ifm_index; 858 if_name = if_indextoname(if_index, ifnamebuf); 859 if (if_name == NULL) { 860 log_debug("RTM_NEWADDR: lost if %d", if_index); 861 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 862 &if_index, sizeof(if_index)); 863 remove_iface(if_index); 864 break; 865 } 866 867 log_debug("RTM_NEWADDR: %s[%u]", if_name, if_index); 868 update_iface(if_index, if_name); 869 break; 870 case RTM_DELADDR: 871 ifm = (struct if_msghdr *)rtm; 872 if_index = ifm->ifm_index; 873 if_name = if_indextoname(if_index, ifnamebuf); 874 if (if_name == NULL) { 875 log_debug("RTM_DELADDR: lost if %d", if_index); 876 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 877 &if_index, sizeof(if_index)); 878 remove_iface(if_index); 879 break; 880 } 881 if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family 882 == AF_INET6) { 883 del_addr.if_index = if_index; 884 memcpy(&del_addr.addr, rti_info[RTAX_IFA], sizeof( 885 del_addr.addr)); 886 frontend_imsg_compose_engine(IMSG_DEL_ADDRESS, 887 0, 0, &del_addr, sizeof(del_addr)); 888 log_debug("RTM_DELADDR: %s[%u]", if_name, if_index); 889 } 890 break; 891 case RTM_CHGADDRATTR: 892 ifm = (struct if_msghdr *)rtm; 893 if_index = ifm->ifm_index; 894 if_name = if_indextoname(if_index, ifnamebuf); 895 if (if_name == NULL) { 896 log_debug("RTM_CHGADDRATTR: lost if %d", if_index); 897 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 898 &if_index, sizeof(if_index)); 899 remove_iface(if_index); 900 break; 901 } 902 if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family 903 == AF_INET6) { 904 sin6 = (struct sockaddr_in6 *) rti_info[RTAX_IFA]; 905 906 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 907 update_iface(if_index, if_name); 908 break; 909 } 910 911 memset(&ifr6, 0, sizeof(ifr6)); 912 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 913 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 914 915 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) 916 == -1) { 917 log_warn("SIOCGIFAFLAG_IN6"); 918 break; 919 } 920 921 #ifndef SMALL 922 log_debug("RTM_CHGADDRATTR: %s - %s", 923 sin6_to_str(sin6), 924 flags_to_str(ifr6.ifr_ifru.ifru_flags6)); 925 #endif /* SMALL */ 926 927 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) { 928 dup_addr.if_index = if_index; 929 dup_addr.addr = *sin6; 930 frontend_imsg_compose_engine(IMSG_DUP_ADDRESS, 931 0, 0, &dup_addr, sizeof(dup_addr)); 932 } 933 934 } 935 break; 936 case RTM_DELETE: 937 ifm = (struct if_msghdr *)rtm; 938 if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_LABEL)) != 939 (RTA_DST | RTA_GATEWAY | RTA_LABEL)) 940 break; 941 if (rti_info[RTAX_DST]->sa_family != AF_INET6) 942 break; 943 if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) 944 rti_info[RTAX_DST])->sin6_addr)) 945 break; 946 if (rti_info[RTAX_GATEWAY]->sa_family != AF_INET6) 947 break; 948 if (rti_info[RTAX_LABEL]->sa_len != 949 sizeof(struct sockaddr_rtlabel)) 950 break; 951 952 rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL]; 953 if (strcmp(rl->sr_label, SLAACD_RTA_LABEL) != 0) 954 break; 955 if_index = ifm->ifm_index; 956 if_name = if_indextoname(if_index, ifnamebuf); 957 if (if_name == NULL) { 958 log_debug("RTM_DELETE: lost if %d", if_index); 959 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 960 &if_index, sizeof(if_index)); 961 remove_iface(if_index); 962 break; 963 } 964 965 del_route.if_index = if_index; 966 memcpy(&del_route.gw, rti_info[RTAX_GATEWAY], 967 sizeof(del_route.gw)); 968 in6 = &del_route.gw.sin6_addr; 969 #ifdef __KAME__ 970 /* XXX from route(8) p_sockaddr() */ 971 if ((IN6_IS_ADDR_LINKLOCAL(in6) || 972 IN6_IS_ADDR_MC_LINKLOCAL(in6) || 973 IN6_IS_ADDR_MC_INTFACELOCAL(in6)) && 974 del_route.gw.sin6_scope_id == 0) { 975 del_route.gw.sin6_scope_id = 976 (u_int32_t)ntohs(*(u_short *) &in6->s6_addr[2]); 977 *(u_short *)&in6->s6_addr[2] = 0; 978 } 979 #endif 980 frontend_imsg_compose_engine(IMSG_DEL_ROUTE, 981 0, 0, &del_route, sizeof(del_route)); 982 log_debug("RTM_DELETE: %s[%u]", if_name, 983 ifm->ifm_index); 984 985 break; 986 #ifndef SMALL 987 case RTM_PROPOSAL: 988 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { 989 log_debug("RTP_PROPOSAL_SOLICIT"); 990 frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, 991 0, 0, NULL, 0); 992 } 993 break; 994 #endif /* SMALL */ 995 default: 996 log_debug("unexpected RTM: %d", rtm->rtm_type); 997 break; 998 } 999 1000 } 1001 1002 #define ROUNDUP(a) \ 1003 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 1004 1005 void 1006 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1007 { 1008 int i; 1009 1010 for (i = 0; i < RTAX_MAX; i++) { 1011 if (addrs & (1 << i)) { 1012 rti_info[i] = sa; 1013 sa = (struct sockaddr *)((char *)(sa) + 1014 ROUNDUP(sa->sa_len)); 1015 } else 1016 rti_info[i] = NULL; 1017 } 1018 } 1019 1020 void 1021 icmp6_receive(int fd, short events, void *arg) 1022 { 1023 struct imsg_ra ra; 1024 struct icmp6_hdr *icmp6_hdr; 1025 struct icmp6_ev *icmp6ev; 1026 struct in6_pktinfo *pi = NULL; 1027 struct cmsghdr *cm; 1028 ssize_t len; 1029 int if_index = 0, *hlimp = NULL; 1030 char ntopbuf[INET6_ADDRSTRLEN]; 1031 #ifndef SMALL 1032 char ifnamebuf[IFNAMSIZ]; 1033 #endif /* SMALL */ 1034 1035 icmp6ev = arg; 1036 if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) { 1037 log_warn("recvmsg"); 1038 return; 1039 } 1040 1041 if ((size_t)len < sizeof(struct icmp6_hdr)) 1042 return; 1043 1044 icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer; 1045 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT) 1046 return; 1047 1048 /* extract optional information via Advanced API */ 1049 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm; 1050 cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) { 1051 if (cm->cmsg_level == IPPROTO_IPV6 && 1052 cm->cmsg_type == IPV6_PKTINFO && 1053 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 1054 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1055 if_index = pi->ipi6_ifindex; 1056 } 1057 if (cm->cmsg_level == IPPROTO_IPV6 && 1058 cm->cmsg_type == IPV6_HOPLIMIT && 1059 cm->cmsg_len == CMSG_LEN(sizeof(int))) 1060 hlimp = (int *)CMSG_DATA(cm); 1061 } 1062 1063 if (if_index == 0) { 1064 log_warnx("failed to get receiving interface"); 1065 return; 1066 } 1067 1068 if (hlimp == NULL) { 1069 log_warnx("failed to get receiving hop limit"); 1070 return; 1071 } 1072 1073 if (*hlimp != 255) { 1074 log_warnx("invalid RA with hop limit of %d from %s on %s", 1075 *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 1076 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 1077 ifnamebuf)); 1078 return; 1079 } 1080 1081 if ((size_t)len > sizeof(ra.packet)) { 1082 log_warnx("invalid RA with size %ld from %s on %s", 1083 len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 1084 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 1085 ifnamebuf)); 1086 return; 1087 } 1088 ra.if_index = if_index; 1089 memcpy(&ra.from, &icmp6ev->from, sizeof(ra.from)); 1090 ra.len = len; 1091 memcpy(ra.packet, icmp6ev->answer, len); 1092 1093 frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra)); 1094 } 1095 1096 void 1097 send_solicitation(uint32_t if_index) 1098 { 1099 struct in6_pktinfo *pi; 1100 struct cmsghdr *cm; 1101 struct iface *iface; 1102 1103 log_debug("%s(%u)", __func__, if_index); 1104 1105 if ((iface = get_iface_by_id(if_index)) == NULL) 1106 return; 1107 1108 if (!event_initialized(&iface->icmp6ev->ev)) { 1109 iface->send_solicitation = 1; 1110 return; 1111 } else if (iface->ll_tentative) { 1112 iface->send_solicitation = 1; 1113 return; 1114 } 1115 1116 iface->send_solicitation = 0; 1117 1118 dst.sin6_scope_id = if_index; 1119 1120 cm = CMSG_FIRSTHDR(&sndmhdr); 1121 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1122 pi->ipi6_ifindex = if_index; 1123 1124 memcpy(&nd_opt_source_link_addr, &iface->hw_address, 1125 sizeof(nd_opt_source_link_addr)); 1126 1127 if (sendmsg(EVENT_FD(&iface->icmp6ev->ev), &sndmhdr, 0) != sizeof(rs) + 1128 sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr)) 1129 log_warn("sendmsg"); 1130 } 1131 1132 struct iface* 1133 get_iface_by_id(uint32_t if_index) 1134 { 1135 struct iface *iface; 1136 1137 LIST_FOREACH (iface, &interfaces, entries) { 1138 if (iface->if_index == if_index) 1139 return (iface); 1140 } 1141 1142 return (NULL); 1143 } 1144 1145 void 1146 remove_iface(uint32_t if_index) 1147 { 1148 struct iface *iface; 1149 1150 iface = get_iface_by_id(if_index); 1151 1152 if (iface == NULL) 1153 return; 1154 1155 LIST_REMOVE(iface, entries); 1156 1157 unref_icmp6ev(iface); 1158 free(iface); 1159 } 1160 1161 struct icmp6_ev* 1162 get_icmp6ev_by_rdomain(int rdomain) 1163 { 1164 struct iface *iface; 1165 struct icmp6_ev *icmp6ev = NULL; 1166 1167 LIST_FOREACH (iface, &interfaces, entries) { 1168 if (iface->rdomain == rdomain) { 1169 icmp6ev = iface->icmp6ev; 1170 break; 1171 } 1172 } 1173 1174 if (icmp6ev == NULL) { 1175 if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL) 1176 fatal("calloc"); 1177 icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer; 1178 icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer); 1179 icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from; 1180 icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from); 1181 icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov; 1182 icmp6ev->rcvmhdr.msg_iovlen = 1; 1183 icmp6ev->rcvmhdr.msg_controllen = 1184 CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1185 CMSG_SPACE(sizeof(int)); 1186 if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev-> 1187 rcvmhdr.msg_controllen)) == NULL) 1188 fatal("malloc"); 1189 frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0, 1190 &rdomain, sizeof(rdomain)); 1191 } 1192 icmp6ev->refcnt++; 1193 return (icmp6ev); 1194 } 1195 1196 void 1197 unref_icmp6ev(struct iface *iface) 1198 { 1199 struct icmp6_ev *icmp6ev = iface->icmp6ev; 1200 1201 iface->icmp6ev = NULL; 1202 1203 if (icmp6ev != NULL) { 1204 icmp6ev->refcnt--; 1205 if (icmp6ev->refcnt == 0) { 1206 event_del(&icmp6ev->ev); 1207 close(EVENT_FD(&icmp6ev->ev)); 1208 free(icmp6ev); 1209 } 1210 } 1211 } 1212 1213 void 1214 set_icmp6sock(int icmp6sock, int rdomain) 1215 { 1216 struct iface *iface; 1217 1218 LIST_FOREACH (iface, &interfaces, entries) { 1219 if (!event_initialized(&iface->icmp6ev->ev) && iface->rdomain 1220 == rdomain) { 1221 event_set(&iface->icmp6ev->ev, icmp6sock, EV_READ | 1222 EV_PERSIST, icmp6_receive, iface->icmp6ev); 1223 event_add(&iface->icmp6ev->ev, NULL); 1224 icmp6sock = -1; 1225 break; 1226 } 1227 } 1228 1229 if (icmp6sock != -1) { 1230 /* 1231 * The interface disappeared or changed rdomain while we were 1232 * waiting for the parent process to open the raw socket. 1233 */ 1234 close(icmp6sock); 1235 return; 1236 } 1237 1238 LIST_FOREACH (iface, &interfaces, entries) { 1239 if (event_initialized(&iface->icmp6ev->ev) && 1240 iface->send_solicitation) 1241 send_solicitation(iface->if_index); 1242 } 1243 } 1244