1 /* $OpenBSD: frontend.c,v 1.43 2020/12/29 19:51:15 benno 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 }; 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 void get_lladdr(char *, struct ether_addr *, struct sockaddr_in6 *); 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 struct imsgev *iev_main; 105 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 #ifndef SMALL 147 control_state.fd = -1; 148 #endif /* SMALL */ 149 150 if ((pw = getpwnam(SLAACD_USER)) == NULL) 151 fatal("getpwnam"); 152 153 if (chroot(pw->pw_dir) == -1) 154 fatal("chroot"); 155 if (chdir("/") == -1) 156 fatal("chdir(\"/\")"); 157 158 slaacd_process = PROC_FRONTEND; 159 setproctitle("%s", log_procnames[slaacd_process]); 160 log_procinit(log_procnames[slaacd_process]); 161 162 if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 163 fatal("socket"); 164 165 if (setgroups(1, &pw->pw_gid) || 166 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 167 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 168 fatal("can't drop privileges"); 169 170 if (pledge("stdio unix recvfd route", NULL) == -1) 171 fatal("pledge"); 172 173 event_init(); 174 175 /* Setup signal handler. */ 176 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 177 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 178 signal_add(&ev_sigint, NULL); 179 signal_add(&ev_sigterm, NULL); 180 signal(SIGPIPE, SIG_IGN); 181 signal(SIGHUP, SIG_IGN); 182 183 /* Setup pipe and event handler to the parent process. */ 184 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 185 fatal(NULL); 186 imsg_init(&iev_main->ibuf, 3); 187 iev_main->handler = frontend_dispatch_main; 188 iev_main->events = EV_READ; 189 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 190 iev_main->handler, iev_main); 191 event_add(&iev_main->ev, NULL); 192 193 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 194 CMSG_SPACE(sizeof(int)); 195 196 if ((sndcmsgbuf = malloc(sndcmsglen)) == NULL) 197 fatal("malloc"); 198 199 rs.nd_rs_type = ND_ROUTER_SOLICIT; 200 rs.nd_rs_code = 0; 201 rs.nd_rs_cksum = 0; 202 rs.nd_rs_reserved = 0; 203 204 nd_opt_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR; 205 nd_opt_hdr.nd_opt_len = 1; 206 207 memset(&dst, 0, sizeof(dst)); 208 dst.sin6_family = AF_INET6; 209 if (inet_pton(AF_INET6, ALLROUTER, &dst.sin6_addr.s6_addr) != 1) 210 fatal("inet_pton"); 211 212 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 213 sndmhdr.msg_iov = sndiov; 214 sndmhdr.msg_iovlen = 3; 215 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 216 sndmhdr.msg_controllen = sndcmsglen; 217 218 sndmhdr.msg_name = (caddr_t)&dst; 219 sndmhdr.msg_iov[0].iov_base = (caddr_t)&rs; 220 sndmhdr.msg_iov[0].iov_len = sizeof(rs); 221 sndmhdr.msg_iov[1].iov_base = (caddr_t)&nd_opt_hdr; 222 sndmhdr.msg_iov[1].iov_len = sizeof(nd_opt_hdr); 223 sndmhdr.msg_iov[2].iov_base = (caddr_t)&nd_opt_source_link_addr; 224 sndmhdr.msg_iov[2].iov_len = sizeof(nd_opt_source_link_addr); 225 226 cm = CMSG_FIRSTHDR(&sndmhdr); 227 228 cm->cmsg_level = IPPROTO_IPV6; 229 cm->cmsg_type = IPV6_PKTINFO; 230 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 231 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 232 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); 233 pi->ipi6_ifindex = 0; 234 235 cm = CMSG_NXTHDR(&sndmhdr, cm); 236 cm->cmsg_level = IPPROTO_IPV6; 237 cm->cmsg_type = IPV6_HOPLIMIT; 238 cm->cmsg_len = CMSG_LEN(sizeof(int)); 239 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 240 241 LIST_INIT(&interfaces); 242 243 event_dispatch(); 244 245 frontend_shutdown(); 246 } 247 248 __dead void 249 frontend_shutdown(void) 250 { 251 /* Close pipes. */ 252 msgbuf_write(&iev_engine->ibuf.w); 253 msgbuf_clear(&iev_engine->ibuf.w); 254 close(iev_engine->ibuf.fd); 255 msgbuf_write(&iev_main->ibuf.w); 256 msgbuf_clear(&iev_main->ibuf.w); 257 close(iev_main->ibuf.fd); 258 259 free(iev_engine); 260 free(iev_main); 261 262 log_info("frontend exiting"); 263 exit(0); 264 } 265 266 int 267 frontend_imsg_compose_main(int type, pid_t pid, void *data, 268 uint16_t datalen) 269 { 270 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 271 datalen)); 272 } 273 274 int 275 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, 276 void *data, uint16_t datalen) 277 { 278 return (imsg_compose_event(iev_engine, type, peerid, pid, -1, 279 data, datalen)); 280 } 281 282 void 283 frontend_dispatch_main(int fd, short event, void *bula) 284 { 285 struct imsg imsg; 286 struct imsgev *iev = bula; 287 struct imsgbuf *ibuf = &iev->ibuf; 288 ssize_t n; 289 int shut = 0, icmp6sock, rdomain; 290 291 if (event & EV_READ) { 292 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 293 fatal("imsg_read error"); 294 if (n == 0) /* Connection closed. */ 295 shut = 1; 296 } 297 if (event & EV_WRITE) { 298 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 299 fatal("msgbuf_write"); 300 if (n == 0) /* Connection closed. */ 301 shut = 1; 302 } 303 304 for (;;) { 305 if ((n = imsg_get(ibuf, &imsg)) == -1) 306 fatal("%s: imsg_get error", __func__); 307 if (n == 0) /* No more messages. */ 308 break; 309 310 switch (imsg.hdr.type) { 311 case IMSG_SOCKET_IPC: 312 /* 313 * Setup pipe and event handler to the engine 314 * process. 315 */ 316 if (iev_engine) 317 fatalx("%s: received unexpected imsg fd " 318 "to frontend", __func__); 319 320 if ((fd = imsg.fd) == -1) 321 fatalx("%s: expected to receive imsg fd to " 322 "frontend but didn't receive any", 323 __func__); 324 325 iev_engine = malloc(sizeof(struct imsgev)); 326 if (iev_engine == NULL) 327 fatal(NULL); 328 329 imsg_init(&iev_engine->ibuf, fd); 330 iev_engine->handler = frontend_dispatch_engine; 331 iev_engine->events = EV_READ; 332 333 event_set(&iev_engine->ev, iev_engine->ibuf.fd, 334 iev_engine->events, iev_engine->handler, iev_engine); 335 event_add(&iev_engine->ev, NULL); 336 break; 337 case IMSG_ICMP6SOCK: 338 if ((icmp6sock = imsg.fd) == -1) 339 fatalx("%s: expected to receive imsg " 340 "ICMPv6 fd but didn't receive any", 341 __func__); 342 if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) 343 fatalx("%s: IMSG_ICMP6SOCK wrong length: " 344 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 345 memcpy(&rdomain, imsg.data, sizeof(rdomain)); 346 set_icmp6sock(icmp6sock, rdomain); 347 break; 348 case IMSG_ROUTESOCK: 349 if ((fd = imsg.fd) == -1) 350 fatalx("%s: expected to receive imsg " 351 "routesocket fd but didn't receive any", 352 __func__); 353 event_set(&ev_route, fd, EV_READ | EV_PERSIST, 354 route_receive, NULL); 355 break; 356 case IMSG_STARTUP: 357 frontend_startup(); 358 break; 359 #ifndef SMALL 360 case IMSG_CONTROLFD: 361 if (control_state.fd != -1) 362 fatalx("%s: received unexpected controlsock", 363 __func__); 364 if ((fd = imsg.fd) == -1) 365 fatalx("%s: expected to receive imsg " 366 "control fd but didn't receive any", 367 __func__); 368 control_state.fd = fd; 369 /* Listen on control socket. */ 370 TAILQ_INIT(&ctl_conns); 371 control_listen(); 372 break; 373 case IMSG_CTL_END: 374 control_imsg_relay(&imsg); 375 break; 376 #endif /* SMALL */ 377 default: 378 log_debug("%s: error handling imsg %d", __func__, 379 imsg.hdr.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; 402 403 if (event & EV_READ) { 404 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 405 fatal("imsg_read error"); 406 if (n == 0) /* Connection closed. */ 407 shut = 1; 408 } 409 if (event & EV_WRITE) { 410 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 411 fatal("msgbuf_write"); 412 if (n == 0) /* Connection closed. */ 413 shut = 1; 414 } 415 416 for (;;) { 417 if ((n = imsg_get(ibuf, &imsg)) == -1) 418 fatal("%s: imsg_get error", __func__); 419 if (n == 0) /* No more messages. */ 420 break; 421 422 switch (imsg.hdr.type) { 423 #ifndef SMALL 424 case IMSG_CTL_END: 425 case IMSG_CTL_SHOW_INTERFACE_INFO: 426 case IMSG_CTL_SHOW_INTERFACE_INFO_RA: 427 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX: 428 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS: 429 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL: 430 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS: 431 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: 432 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: 433 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: 434 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS: 435 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL: 436 control_imsg_relay(&imsg); 437 break; 438 #endif /* SMALL */ 439 case IMSG_CTL_SEND_SOLICITATION: 440 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 441 fatalx("%s: IMSG_CTL_SEND_SOLICITATION wrong " 442 "length: %lu", __func__, 443 IMSG_DATA_SIZE(imsg)); 444 if_index = *((uint32_t *)imsg.data); 445 send_solicitation(if_index); 446 break; 447 default: 448 log_debug("%s: error handling imsg %d", __func__, 449 imsg.hdr.type); 450 break; 451 } 452 imsg_free(&imsg); 453 } 454 if (!shut) 455 imsg_event_add(iev); 456 else { 457 /* This pipe is dead. Remove its event handler. */ 458 event_del(&iev->ev); 459 event_loopexit(NULL); 460 } 461 } 462 463 int 464 get_flags(char *if_name) 465 { 466 struct ifreq ifr; 467 468 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 469 if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 470 log_warn("SIOCGIFFLAGS"); 471 return -1; 472 } 473 return ifr.ifr_flags; 474 } 475 476 int 477 get_xflags(char *if_name) 478 { 479 struct ifreq ifr; 480 481 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 482 if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) { 483 log_warn("SIOCGIFXFLAGS"); 484 return -1; 485 } 486 return ifr.ifr_flags; 487 } 488 489 int 490 get_ifrdomain(char *if_name) 491 { 492 struct ifreq ifr; 493 494 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 495 if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { 496 log_warn("SIOCGIFRDOMAIN"); 497 return -1; 498 } 499 return ifr.ifr_rdomainid; 500 } 501 502 void 503 update_iface(uint32_t if_index, char* if_name) 504 { 505 struct iface *iface; 506 struct imsg_ifinfo imsg_ifinfo; 507 int flags, xflags, ifrdomain; 508 509 if ((flags = get_flags(if_name)) == -1 || (xflags = 510 get_xflags(if_name)) == -1) 511 return; 512 513 if (!(xflags & IFXF_AUTOCONF6)) 514 return; 515 516 if((ifrdomain = get_ifrdomain(if_name)) == -1) 517 return; 518 519 iface = get_iface_by_id(if_index); 520 521 if (iface != NULL) { 522 if (iface->rdomain != ifrdomain) { 523 unref_icmp6ev(iface); 524 iface->rdomain = ifrdomain; 525 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 526 } 527 } else { 528 if ((iface = calloc(1, sizeof(*iface))) == NULL) 529 fatal("calloc"); 530 iface->if_index = if_index; 531 iface->rdomain = ifrdomain; 532 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 533 534 LIST_INSERT_HEAD(&interfaces, iface, entries); 535 } 536 537 memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo)); 538 539 imsg_ifinfo.if_index = if_index; 540 imsg_ifinfo.rdomain = ifrdomain; 541 imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | 542 IFF_RUNNING); 543 imsg_ifinfo.autoconfprivacy = !(xflags & IFXF_INET6_NOPRIVACY); 544 imsg_ifinfo.soii = !(xflags & IFXF_INET6_NOSOII); 545 get_lladdr(if_name, &imsg_ifinfo.hw_address, &imsg_ifinfo.ll_address); 546 547 memcpy(&iface->hw_address, &imsg_ifinfo.hw_address, 548 sizeof(iface->hw_address)); 549 550 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo, 551 sizeof(imsg_ifinfo)); 552 } 553 554 #ifndef SMALL 555 void 556 update_autoconf_addresses(uint32_t if_index, char* if_name) 557 { 558 struct in6_ifreq ifr6; 559 struct imsg_addrinfo imsg_addrinfo; 560 struct ifaddrs *ifap, *ifa; 561 struct in6_addrlifetime *lifetime; 562 struct sockaddr_in6 *sin6; 563 struct imsg_link_state imsg_link_state; 564 time_t t; 565 int xflags; 566 567 if ((xflags = get_xflags(if_name)) == -1) 568 return; 569 570 if (!(xflags & IFXF_AUTOCONF6)) 571 return; 572 573 memset(&imsg_addrinfo, 0, sizeof(imsg_addrinfo)); 574 imsg_addrinfo.if_index = if_index; 575 get_lladdr(if_name, &imsg_addrinfo.hw_address, 576 &imsg_addrinfo.ll_address); 577 578 memset(&imsg_link_state, 0, sizeof(imsg_link_state)); 579 imsg_link_state.if_index = if_index; 580 581 if (getifaddrs(&ifap) != 0) 582 fatal("getifaddrs"); 583 584 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 585 if (strcmp(if_name, ifa->ifa_name) != 0) 586 continue; 587 if (ifa->ifa_addr == NULL) 588 continue; 589 590 if (ifa->ifa_addr->sa_family == AF_LINK) 591 imsg_link_state.link_state = 592 ((struct if_data *)ifa->ifa_data)->ifi_link_state; 593 594 if (ifa->ifa_addr->sa_family != AF_INET6) 595 continue; 596 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 597 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 598 continue; 599 600 log_debug("%s: IP: %s", __func__, sin6_to_str(sin6)); 601 imsg_addrinfo.addr = *sin6; 602 603 memset(&ifr6, 0, sizeof(ifr6)); 604 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 605 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 606 607 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) { 608 log_warn("SIOCGIFAFLAG_IN6"); 609 continue; 610 } 611 612 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | 613 IN6_IFF_TEMPORARY))) 614 continue; 615 616 imsg_addrinfo.privacy = ifr6.ifr_ifru.ifru_flags6 & 617 IN6_IFF_TEMPORARY ? 1 : 0; 618 619 memset(&ifr6, 0, sizeof(ifr6)); 620 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 621 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 622 623 if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == 624 -1) { 625 log_warn("SIOCGIFNETMASK_IN6"); 626 continue; 627 } 628 629 imsg_addrinfo.mask = ((struct sockaddr_in6 *)&ifr6.ifr_addr) 630 ->sin6_addr; 631 632 memset(&ifr6, 0, sizeof(ifr6)); 633 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 634 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 635 lifetime = &ifr6.ifr_ifru.ifru_lifetime; 636 637 if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == 638 -1) { 639 log_warn("SIOCGIFALIFETIME_IN6"); 640 continue; 641 } 642 643 imsg_addrinfo.vltime = ND6_INFINITE_LIFETIME; 644 imsg_addrinfo.pltime = ND6_INFINITE_LIFETIME; 645 t = time(NULL); 646 647 if (lifetime->ia6t_preferred) 648 imsg_addrinfo.pltime = lifetime->ia6t_preferred < t ? 0 649 : lifetime->ia6t_preferred - t; 650 651 if (lifetime->ia6t_expire) 652 imsg_addrinfo.vltime = lifetime->ia6t_expire < t ? 0 : 653 lifetime->ia6t_expire - t; 654 655 frontend_imsg_compose_main(IMSG_UPDATE_ADDRESS, 0, 656 &imsg_addrinfo, sizeof(imsg_addrinfo)); 657 658 } 659 freeifaddrs(ifap); 660 661 log_debug("%s: %s link state down? %s", __func__, if_name, 662 imsg_link_state.link_state == LINK_STATE_DOWN ? "yes" : "no"); 663 664 frontend_imsg_compose_main(IMSG_UPDATE_LINK_STATE, 0, 665 &imsg_link_state, sizeof(imsg_link_state)); 666 } 667 668 const char* 669 flags_to_str(int flags) 670 { 671 static char buf[sizeof(" anycast tentative duplicated detached " 672 "deprecated autoconf autoconfprivacy")]; 673 674 buf[0] = '\0'; 675 if (flags & IN6_IFF_ANYCAST) 676 strlcat(buf, " anycast", sizeof(buf)); 677 if (flags & IN6_IFF_TENTATIVE) 678 strlcat(buf, " tentative", sizeof(buf)); 679 if (flags & IN6_IFF_DUPLICATED) 680 strlcat(buf, " duplicated", sizeof(buf)); 681 if (flags & IN6_IFF_DETACHED) 682 strlcat(buf, " detached", sizeof(buf)); 683 if (flags & IN6_IFF_DEPRECATED) 684 strlcat(buf, " deprecated", sizeof(buf)); 685 if (flags & IN6_IFF_AUTOCONF) 686 strlcat(buf, " autoconf", sizeof(buf)); 687 if (flags & IN6_IFF_TEMPORARY) 688 strlcat(buf, " autoconfprivacy", sizeof(buf)); 689 690 return (buf); 691 } 692 #endif /* SMALL */ 693 694 void 695 frontend_startup(void) 696 { 697 struct if_nameindex *ifnidxp, *ifnidx; 698 699 if (!event_initialized(&ev_route)) 700 fatalx("%s: did not receive a route socket from the main " 701 "process", __func__); 702 703 event_add(&ev_route, NULL); 704 705 if ((ifnidxp = if_nameindex()) == NULL) 706 fatalx("if_nameindex"); 707 708 for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL; 709 ifnidx++) { 710 update_iface(ifnidx->if_index, ifnidx->if_name); 711 #ifndef SMALL 712 update_autoconf_addresses(ifnidx->if_index, ifnidx->if_name); 713 #endif /* SMALL */ 714 } 715 716 if_freenameindex(ifnidxp); 717 } 718 719 void 720 route_receive(int fd, short events, void *arg) 721 { 722 static uint8_t *buf; 723 724 struct rt_msghdr *rtm; 725 struct sockaddr *sa, *rti_info[RTAX_MAX]; 726 ssize_t n; 727 728 if (buf == NULL) { 729 buf = malloc(ROUTE_SOCKET_BUF_SIZE); 730 if (buf == NULL) 731 fatal("malloc"); 732 } 733 rtm = (struct rt_msghdr *)buf; 734 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 735 if (errno == EAGAIN || errno == EINTR) 736 return; 737 log_warn("dispatch_rtmsg: read error"); 738 return; 739 } 740 741 if (n == 0) 742 fatal("routing socket closed"); 743 744 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 745 log_warnx("partial rtm of %zd in buffer", n); 746 return; 747 } 748 749 if (rtm->rtm_version != RTM_VERSION) 750 return; 751 752 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 753 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 754 755 handle_route_message(rtm, rti_info); 756 } 757 758 void 759 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 760 { 761 struct if_msghdr *ifm; 762 struct imsg_del_addr del_addr; 763 struct imsg_del_route del_route; 764 struct imsg_dup_addr dup_addr; 765 struct sockaddr_rtlabel *rl; 766 struct sockaddr_in6 *sin6; 767 struct in6_ifreq ifr6; 768 struct in6_addr *in6; 769 int xflags, if_index; 770 char ifnamebuf[IFNAMSIZ]; 771 char *if_name; 772 773 switch (rtm->rtm_type) { 774 case RTM_IFINFO: 775 ifm = (struct if_msghdr *)rtm; 776 if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 777 if (if_name == NULL) { 778 log_debug("RTM_IFINFO: lost if %d", ifm->ifm_index); 779 if_index = ifm->ifm_index; 780 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 781 &if_index, sizeof(if_index)); 782 } else { 783 xflags = get_xflags(if_name); 784 if (xflags == -1 || !(xflags & IFXF_AUTOCONF6)) { 785 log_debug("RTM_IFINFO: %s(%d) no(longer) " 786 "autoconf6", if_name, ifm->ifm_index); 787 if_index = ifm->ifm_index; 788 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 789 0, &if_index, sizeof(if_index)); 790 remove_iface(if_index); 791 } else { 792 update_iface(ifm->ifm_index, if_name); 793 #ifndef SMALL 794 update_autoconf_addresses(ifm->ifm_index, 795 if_name); 796 #endif /* SMALL */ 797 } 798 } 799 break; 800 case RTM_NEWADDR: 801 ifm = (struct if_msghdr *)rtm; 802 if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 803 log_debug("RTM_NEWADDR: %s[%u]", if_name, ifm->ifm_index); 804 update_iface(ifm->ifm_index, if_name); 805 break; 806 case RTM_DELADDR: 807 ifm = (struct if_msghdr *)rtm; 808 if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 809 if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family 810 == AF_INET6) { 811 del_addr.if_index = ifm->ifm_index; 812 memcpy(&del_addr.addr, rti_info[RTAX_IFA], sizeof( 813 del_addr.addr)); 814 frontend_imsg_compose_engine(IMSG_DEL_ADDRESS, 815 0, 0, &del_addr, sizeof(del_addr)); 816 log_debug("RTM_DELADDR: %s[%u]", if_name, 817 ifm->ifm_index); 818 } 819 break; 820 case RTM_CHGADDRATTR: 821 ifm = (struct if_msghdr *)rtm; 822 if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 823 if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family 824 == AF_INET6) { 825 sin6 = (struct sockaddr_in6 *) rti_info[RTAX_IFA]; 826 827 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 828 break; 829 830 memset(&ifr6, 0, sizeof(ifr6)); 831 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 832 memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 833 834 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) 835 == -1) { 836 log_warn("SIOCGIFAFLAG_IN6"); 837 break; 838 } 839 840 #ifndef SMALL 841 log_debug("RTM_CHGADDRATTR: %s -%s", 842 sin6_to_str(sin6), 843 flags_to_str(ifr6.ifr_ifru.ifru_flags6)); 844 #endif /* SMALL */ 845 846 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) { 847 dup_addr.if_index = ifm->ifm_index; 848 dup_addr.addr = *sin6; 849 frontend_imsg_compose_engine(IMSG_DUP_ADDRESS, 850 0, 0, &dup_addr, sizeof(dup_addr)); 851 } 852 853 } 854 break; 855 case RTM_DELETE: 856 ifm = (struct if_msghdr *)rtm; 857 if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_LABEL)) != 858 (RTA_DST | RTA_GATEWAY | RTA_LABEL)) 859 break; 860 if (rti_info[RTAX_DST]->sa_family != AF_INET6) 861 break; 862 if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) 863 rti_info[RTAX_DST])->sin6_addr)) 864 break; 865 if (rti_info[RTAX_GATEWAY]->sa_family != AF_INET6) 866 break; 867 if (rti_info[RTAX_LABEL]->sa_len != 868 sizeof(struct sockaddr_rtlabel)) 869 break; 870 871 rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL]; 872 if (strcmp(rl->sr_label, SLAACD_RTA_LABEL) != 0) 873 break; 874 875 if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 876 877 del_route.if_index = ifm->ifm_index; 878 memcpy(&del_route.gw, rti_info[RTAX_GATEWAY], 879 sizeof(del_route.gw)); 880 in6 = &del_route.gw.sin6_addr; 881 /* XXX from route(8) p_sockaddr() */ 882 if (IN6_IS_ADDR_LINKLOCAL(in6) || 883 IN6_IS_ADDR_MC_LINKLOCAL(in6) || 884 IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 885 del_route.gw.sin6_scope_id = 886 (u_int32_t)ntohs(*(u_short *) &in6->s6_addr[2]); 887 *(u_short *)&in6->s6_addr[2] = 0; 888 } 889 frontend_imsg_compose_engine(IMSG_DEL_ROUTE, 890 0, 0, &del_route, sizeof(del_route)); 891 log_debug("RTM_DELETE: %s[%u]", if_name, 892 ifm->ifm_index); 893 894 break; 895 #ifndef SMALL 896 case RTM_PROPOSAL: 897 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { 898 log_debug("RTP_PROPOSAL_SOLICIT"); 899 frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, 900 0, 0, NULL, 0); 901 } 902 break; 903 #endif /* SMALL */ 904 default: 905 log_debug("unexpected RTM: %d", rtm->rtm_type); 906 break; 907 } 908 909 } 910 911 #define ROUNDUP(a) \ 912 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 913 914 void 915 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 916 { 917 int i; 918 919 for (i = 0; i < RTAX_MAX; i++) { 920 if (addrs & (1 << i)) { 921 rti_info[i] = sa; 922 sa = (struct sockaddr *)((char *)(sa) + 923 ROUNDUP(sa->sa_len)); 924 } else 925 rti_info[i] = NULL; 926 } 927 } 928 929 void 930 get_lladdr(char *if_name, struct ether_addr *mac, struct sockaddr_in6 *ll) 931 { 932 struct ifaddrs *ifap, *ifa; 933 struct sockaddr_dl *sdl; 934 struct sockaddr_in6 *sin6; 935 936 if (getifaddrs(&ifap) != 0) 937 fatal("getifaddrs"); 938 939 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 940 if (strcmp(if_name, ifa->ifa_name) != 0) 941 continue; 942 if (ifa->ifa_addr == NULL) 943 continue; 944 945 switch(ifa->ifa_addr->sa_family) { 946 case AF_LINK: 947 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 948 if (sdl->sdl_type != IFT_ETHER || 949 sdl->sdl_alen != ETHER_ADDR_LEN) 950 continue; 951 952 memcpy(mac->ether_addr_octet, LLADDR(sdl), 953 ETHER_ADDR_LEN); 954 break; 955 case AF_INET6: 956 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 957 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 958 sin6->sin6_scope_id = ntohs(*(u_int16_t *) 959 &sin6->sin6_addr.s6_addr[2]); 960 sin6->sin6_addr.s6_addr[2] = 961 sin6->sin6_addr.s6_addr[3] = 0; 962 memcpy(ll, sin6, sizeof(*ll)); 963 } 964 break; 965 default: 966 break; 967 } 968 } 969 freeifaddrs(ifap); 970 } 971 972 void 973 icmp6_receive(int fd, short events, void *arg) 974 { 975 struct imsg_ra ra; 976 struct icmp6_hdr *icmp6_hdr; 977 struct icmp6_ev *icmp6ev; 978 struct in6_pktinfo *pi = NULL; 979 struct cmsghdr *cm; 980 ssize_t len; 981 int if_index = 0, *hlimp = NULL; 982 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 983 984 icmp6ev = arg; 985 if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) { 986 log_warn("recvmsg"); 987 return; 988 } 989 990 if ((size_t)len < sizeof(struct icmp6_hdr)) 991 return; 992 993 icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer; 994 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT) 995 return; 996 997 /* extract optional information via Advanced API */ 998 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm; 999 cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) { 1000 if (cm->cmsg_level == IPPROTO_IPV6 && 1001 cm->cmsg_type == IPV6_PKTINFO && 1002 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 1003 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1004 if_index = pi->ipi6_ifindex; 1005 } 1006 if (cm->cmsg_level == IPPROTO_IPV6 && 1007 cm->cmsg_type == IPV6_HOPLIMIT && 1008 cm->cmsg_len == CMSG_LEN(sizeof(int))) 1009 hlimp = (int *)CMSG_DATA(cm); 1010 } 1011 1012 if (if_index == 0) { 1013 log_warnx("failed to get receiving interface"); 1014 return; 1015 } 1016 1017 if (hlimp == NULL) { 1018 log_warnx("failed to get receiving hop limit"); 1019 return; 1020 } 1021 1022 if (*hlimp != 255) { 1023 log_warnx("invalid RA with hop limit of %d from %s on %s", 1024 *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 1025 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 1026 ifnamebuf)); 1027 return; 1028 } 1029 1030 if ((size_t)len > sizeof(ra.packet)) { 1031 log_warnx("invalid RA with size %ld from %s on %s", 1032 len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 1033 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 1034 ifnamebuf)); 1035 return; 1036 } 1037 ra.if_index = if_index; 1038 memcpy(&ra.from, &icmp6ev->from, sizeof(ra.from)); 1039 ra.len = len; 1040 memcpy(ra.packet, icmp6ev->answer, len); 1041 1042 frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra)); 1043 } 1044 1045 void 1046 send_solicitation(uint32_t if_index) 1047 { 1048 struct in6_pktinfo *pi; 1049 struct cmsghdr *cm; 1050 struct iface *iface; 1051 1052 log_debug("%s(%u)", __func__, if_index); 1053 1054 if ((iface = get_iface_by_id(if_index)) == NULL) 1055 return; 1056 1057 if (!event_initialized(&iface->icmp6ev->ev)) { 1058 iface->send_solicitation = 1; 1059 return; 1060 } 1061 1062 dst.sin6_scope_id = if_index; 1063 1064 cm = CMSG_FIRSTHDR(&sndmhdr); 1065 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1066 pi->ipi6_ifindex = if_index; 1067 1068 memcpy(&nd_opt_source_link_addr, &iface->hw_address, 1069 sizeof(nd_opt_source_link_addr)); 1070 1071 if (sendmsg(EVENT_FD(&iface->icmp6ev->ev), &sndmhdr, 0) != sizeof(rs) + 1072 sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr)) 1073 log_warn("sendmsg"); 1074 } 1075 1076 struct iface* 1077 get_iface_by_id(uint32_t if_index) 1078 { 1079 struct iface *iface; 1080 1081 LIST_FOREACH (iface, &interfaces, entries) { 1082 if (iface->if_index == if_index) 1083 return (iface); 1084 } 1085 1086 return (NULL); 1087 } 1088 1089 void 1090 remove_iface(uint32_t if_index) 1091 { 1092 struct iface *iface; 1093 1094 iface = get_iface_by_id(if_index); 1095 1096 if (iface == NULL) 1097 return; 1098 1099 LIST_REMOVE(iface, entries); 1100 1101 unref_icmp6ev(iface); 1102 free(iface); 1103 } 1104 1105 struct icmp6_ev* 1106 get_icmp6ev_by_rdomain(int rdomain) 1107 { 1108 struct iface *iface; 1109 struct icmp6_ev *icmp6ev = NULL; 1110 1111 LIST_FOREACH (iface, &interfaces, entries) { 1112 if (iface->rdomain == rdomain) { 1113 icmp6ev = iface->icmp6ev; 1114 break; 1115 } 1116 } 1117 1118 if (icmp6ev == NULL) { 1119 if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL) 1120 fatal("calloc"); 1121 icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer; 1122 icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer); 1123 icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from; 1124 icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from); 1125 icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov; 1126 icmp6ev->rcvmhdr.msg_iovlen = 1; 1127 icmp6ev->rcvmhdr.msg_controllen = 1128 CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1129 CMSG_SPACE(sizeof(int)); 1130 if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev-> 1131 rcvmhdr.msg_controllen)) == NULL) 1132 fatal("malloc"); 1133 frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0, 1134 &rdomain, sizeof(rdomain)); 1135 } 1136 icmp6ev->refcnt++; 1137 return (icmp6ev); 1138 } 1139 1140 void 1141 unref_icmp6ev(struct iface *iface) 1142 { 1143 struct icmp6_ev *icmp6ev = iface->icmp6ev; 1144 1145 iface->icmp6ev = NULL; 1146 1147 if (icmp6ev != NULL) { 1148 icmp6ev->refcnt--; 1149 if (icmp6ev->refcnt == 0) { 1150 event_del(&icmp6ev->ev); 1151 close(EVENT_FD(&icmp6ev->ev)); 1152 free(icmp6ev); 1153 } 1154 } 1155 } 1156 1157 void 1158 set_icmp6sock(int icmp6sock, int rdomain) 1159 { 1160 struct iface *iface; 1161 1162 LIST_FOREACH (iface, &interfaces, entries) { 1163 if (!event_initialized(&iface->icmp6ev->ev) && iface->rdomain 1164 == rdomain) { 1165 event_set(&iface->icmp6ev->ev, icmp6sock, EV_READ | 1166 EV_PERSIST, icmp6_receive, iface->icmp6ev); 1167 event_add(&iface->icmp6ev->ev, NULL); 1168 icmp6sock = -1; 1169 break; 1170 } 1171 } 1172 1173 if (icmp6sock != -1) { 1174 /* 1175 * The interface disappeared or changed rdomain while we were 1176 * waiting for the parent process to open the raw socket. 1177 */ 1178 close(icmp6sock); 1179 return; 1180 } 1181 1182 LIST_FOREACH (iface, &interfaces, entries) { 1183 if (event_initialized(&iface->icmp6ev->ev) && 1184 iface->send_solicitation) { 1185 iface->send_solicitation = 0; 1186 send_solicitation(iface->if_index); 1187 } 1188 } 1189 } 1190