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