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