1 /* 2 * BSD interface driver for dhcpcd 3 * Copyright (c) 2006-2018 Roy Marples <roy@marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/ioctl.h> 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 #include <sys/sysctl.h> 33 #include <sys/time.h> 34 #include <sys/types.h> 35 #include <sys/uio.h> 36 #include <sys/utsname.h> 37 38 #include "config.h" 39 40 #include <arpa/inet.h> 41 #include <net/bpf.h> 42 #include <net/if.h> 43 #include <net/if_dl.h> 44 #include <net/if_media.h> 45 #include <net/route.h> 46 #include <netinet/if_ether.h> 47 #include <netinet/in.h> 48 #include <netinet/in_var.h> 49 #include <netinet6/in6_var.h> 50 #include <netinet6/nd6.h> 51 #ifdef __NetBSD__ 52 #include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */ 53 #elif defined(__DragonFly__) 54 #include <net/vlan/if_vlan_var.h> 55 #else 56 #include <net/if_vlan_var.h> 57 #endif 58 #ifdef __DragonFly__ 59 # include <netproto/802_11/ieee80211_ioctl.h> 60 #elif __APPLE__ 61 /* FIXME: Add apple includes so we can work out SSID */ 62 #else 63 # include <net80211/ieee80211.h> 64 # include <net80211/ieee80211_ioctl.h> 65 #endif 66 67 #include <assert.h> 68 #include <errno.h> 69 #include <fcntl.h> 70 #include <fnmatch.h> 71 #include <paths.h> 72 #include <stddef.h> 73 #include <stdio.h> 74 #include <stdlib.h> 75 #include <string.h> 76 #include <unistd.h> 77 78 #if defined(OpenBSD) && OpenBSD >= 201411 79 /* OpenBSD dropped the global setting from sysctl but left the #define 80 * which causes a EPERM error when trying to use it. 81 * I think both the error and keeping the define are wrong, so we #undef it. */ 82 #undef IPV6CTL_ACCEPT_RTADV 83 #endif 84 85 #include "common.h" 86 #include "dhcp.h" 87 #include "if.h" 88 #include "if-options.h" 89 #include "ipv4.h" 90 #include "ipv4ll.h" 91 #include "ipv6.h" 92 #include "ipv6nd.h" 93 #include "logerr.h" 94 #include "route.h" 95 #include "sa.h" 96 97 #ifndef RT_ROUNDUP 98 #define RT_ROUNDUP(a) \ 99 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 100 #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len)) 101 #endif 102 103 #ifdef INET6 104 static void 105 ifa_scope(struct sockaddr_in6 *, unsigned int); 106 #endif 107 108 struct priv { 109 int pf_inet6_fd; 110 }; 111 112 int 113 if_init(__unused struct interface *iface) 114 { 115 /* BSD promotes secondary address by default */ 116 return 0; 117 } 118 119 int 120 if_conf(__unused struct interface *iface) 121 { 122 /* No extra checks needed on BSD */ 123 return 0; 124 } 125 126 int 127 if_opensockets_os(struct dhcpcd_ctx *ctx) 128 { 129 struct priv *priv; 130 #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER) 131 unsigned char msgfilter[] = { 132 RTM_IFINFO, 133 #ifdef RTM_IFANNOUNCE 134 RTM_IFANNOUNCE, 135 #endif 136 RTM_ADD, RTM_CHANGE, RTM_DELETE, 137 #ifdef RTM_CHGADDR 138 RTM_CHGADDR, 139 #endif 140 RTM_NEWADDR, RTM_DELADDR 141 }; 142 #ifdef ROUTE_MSGFILTER 143 unsigned int i, msgfilter_mask; 144 #endif 145 #endif 146 147 if ((priv = malloc(sizeof(*priv))) == NULL) 148 return -1; 149 ctx->priv = priv; 150 151 #ifdef INET6 152 priv->pf_inet6_fd = xsocket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); 153 /* Don't return an error so we at least work on kernels witout INET6 154 * even though we expect INET6 support. 155 * We will fail noisily elsewhere anyway. */ 156 #else 157 priv->pf_inet6_fd = -1; 158 #endif 159 160 #define SOCK_FLAGS (SOCK_CLOEXEC | SOCK_NONBLOCK) 161 ctx->link_fd = xsocket(PF_ROUTE, SOCK_RAW | SOCK_FLAGS, AF_UNSPEC); 162 #undef SOCK_FLAGS 163 if (ctx->link_fd == -1) 164 return -1; 165 166 #if defined(RO_MSGFILTER) 167 if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER, 168 &msgfilter, sizeof(msgfilter)) == -1) 169 logerr(__func__); 170 #elif defined(ROUTE_MSGFILTER) 171 /* Convert the array into a bitmask. */ 172 msgfilter_mask = 0; 173 for (i = 0; i < __arraycount(msgfilter); i++) 174 msgfilter_mask |= ROUTE_FILTER(msgfilter[i]); 175 if (setsockopt(ctx->link_fd, PF_ROUTE, ROUTE_MSGFILTER, 176 &msgfilter_mask, sizeof(msgfilter_mask)) == -1) 177 logerr(__func__); 178 #endif 179 180 return 0; 181 } 182 183 void 184 if_closesockets_os(struct dhcpcd_ctx *ctx) 185 { 186 struct priv *priv; 187 188 priv = (struct priv *)ctx->priv; 189 if (priv->pf_inet6_fd != -1) 190 close(priv->pf_inet6_fd); 191 } 192 193 #if defined(INET) || defined(INET6) 194 static void 195 if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp) 196 { 197 198 memset(sdl, 0, sizeof(*sdl)); 199 sdl->sdl_family = AF_LINK; 200 sdl->sdl_len = sizeof(*sdl); 201 sdl->sdl_nlen = sdl->sdl_alen = sdl->sdl_slen = 0; 202 sdl->sdl_index = (unsigned short)ifp->index; 203 } 204 #endif 205 206 #if defined(SIOCG80211NWID) || defined(SIOCGETVLAN) 207 static int if_direct_ioctl(int s, const char *ifname, 208 unsigned long cmd, void *data) 209 { 210 211 strlcpy(data, ifname, IFNAMSIZ); 212 return ioctl(s, cmd, data); 213 } 214 215 static int if_indirect_ioctl(int s, const char *ifname, 216 unsigned long cmd, void *data) 217 { 218 struct ifreq ifr; 219 220 memset(&ifr, 0, sizeof(ifr)); 221 ifr.ifr_data = data; 222 return if_direct_ioctl(s, ifname, cmd, &ifr); 223 } 224 #endif 225 226 static int 227 if_getssid1(int s, const char *ifname, void *ssid) 228 { 229 int retval = -1; 230 #if defined(SIOCG80211NWID) 231 struct ieee80211_nwid nwid; 232 #elif defined(IEEE80211_IOC_SSID) 233 struct ieee80211req ireq; 234 char nwid[IEEE80211_NWID_LEN]; 235 #endif 236 237 #if defined(SIOCG80211NWID) /* NetBSD */ 238 memset(&nwid, 0, sizeof(nwid)); 239 if (if_indirect_ioctl(s, ifname, SIOCG80211NWID, &nwid) == 0) { 240 if (ssid == NULL) 241 retval = nwid.i_len; 242 else if (nwid.i_len > IF_SSIDLEN) 243 errno = ENOBUFS; 244 else { 245 retval = nwid.i_len; 246 memcpy(ssid, nwid.i_nwid, nwid.i_len); 247 } 248 } 249 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */ 250 memset(&ireq, 0, sizeof(ireq)); 251 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name)); 252 ireq.i_type = IEEE80211_IOC_SSID; 253 ireq.i_val = -1; 254 memset(nwid, 0, sizeof(nwid)); 255 ireq.i_data = &nwid; 256 if (ioctl(s, SIOCG80211, &ireq) == 0) { 257 if (ssid == NULL) 258 retval = ireq.i_len; 259 else if (ireq.i_len > IF_SSIDLEN) 260 errno = ENOBUFS; 261 else { 262 retval = ireq.i_len; 263 memcpy(ssid, nwid, ireq.i_len); 264 } 265 } 266 #else 267 errno = ENOSYS; 268 #endif 269 270 return retval; 271 } 272 273 int 274 if_getssid(struct interface *ifp) 275 { 276 int r; 277 278 r = if_getssid1(ifp->ctx->pf_inet_fd, ifp->name, ifp->ssid); 279 if (r != -1) 280 ifp->ssid_len = (unsigned int)r; 281 else 282 ifp->ssid_len = 0; 283 ifp->ssid[ifp->ssid_len] = '\0'; 284 return r; 285 } 286 287 /* 288 * FreeBSD allows for Virtual Access Points 289 * We need to check if the interface is a Virtual Interface Master 290 * and if so, don't use it. 291 * This check is made by virtue of being a IEEE80211 device but 292 * returning the SSID gives an error. 293 */ 294 int 295 if_vimaster(const struct dhcpcd_ctx *ctx, const char *ifname) 296 { 297 int r; 298 struct ifmediareq ifmr; 299 300 memset(&ifmr, 0, sizeof(ifmr)); 301 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 302 r = ioctl(ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr); 303 if (r == -1) 304 return -1; 305 if (ifmr.ifm_status & IFM_AVALID && 306 IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211) 307 { 308 if (if_getssid1(ctx->pf_inet_fd, ifname, NULL) == -1) 309 return 1; 310 } 311 return 0; 312 } 313 314 unsigned short 315 if_vlanid(const struct interface *ifp) 316 { 317 #ifdef SIOCGETVLAN 318 struct vlanreq vlr; 319 320 memset(&vlr, 0, sizeof(vlr)); 321 if (if_indirect_ioctl(ifp->ctx->pf_inet_fd, 322 ifp->name, SIOCGETVLAN, &vlr) != 0) 323 return 0; /* 0 means no VLANID */ 324 return vlr.vlr_tag; 325 #elif defined(SIOCGVNETID) 326 struct ifreq ifr; 327 328 memset(&ifr, 0, sizeof(ifr)); 329 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 330 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0) 331 return 0; /* 0 means no VLANID */ 332 return ifr.ifr_vnetid; 333 #else 334 UNUSED(ifp); 335 return 0; /* 0 means no VLANID */ 336 #endif 337 } 338 339 static void 340 get_addrs(int type, const void *data, const struct sockaddr **sa) 341 { 342 const char *cp; 343 int i; 344 345 cp = data; 346 for (i = 0; i < RTAX_MAX; i++) { 347 if (type & (1 << i)) { 348 sa[i] = (const struct sockaddr *)cp; 349 RT_ADVANCE(cp, sa[i]); 350 } else 351 sa[i] = NULL; 352 } 353 } 354 355 #if defined(INET) || defined(INET6) 356 static struct interface * 357 if_findsdl(struct dhcpcd_ctx *ctx, const struct sockaddr_dl *sdl) 358 { 359 360 if (sdl->sdl_index) 361 return if_findindex(ctx->ifaces, sdl->sdl_index); 362 363 if (sdl->sdl_nlen) { 364 char ifname[IF_NAMESIZE]; 365 366 memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen); 367 ifname[sdl->sdl_nlen] = '\0'; 368 return if_find(ctx->ifaces, ifname); 369 } 370 if (sdl->sdl_alen) { 371 struct interface *ifp; 372 373 TAILQ_FOREACH(ifp, ctx->ifaces, next) { 374 if (ifp->hwlen == sdl->sdl_alen && 375 memcmp(ifp->hwaddr, 376 sdl->sdl_data, sdl->sdl_alen) == 0) 377 return ifp; 378 } 379 } 380 381 errno = ENOENT; 382 return NULL; 383 } 384 385 static struct interface * 386 if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa) 387 { 388 if (sa == NULL) { 389 errno = EINVAL; 390 return NULL; 391 } 392 393 switch (sa->sa_family) { 394 case AF_LINK: 395 { 396 const struct sockaddr_dl *sdl; 397 398 sdl = (const void *)sa; 399 return if_findsdl(ctx, sdl); 400 } 401 #ifdef INET 402 case AF_INET: 403 { 404 const struct sockaddr_in *sin; 405 struct ipv4_addr *ia; 406 407 sin = (const void *)sa; 408 if ((ia = ipv4_findmaskaddr(ctx, &sin->sin_addr))) 409 return ia->iface; 410 break; 411 } 412 #endif 413 #ifdef INET6 414 case AF_INET6: 415 { 416 const struct sockaddr_in6 *sin; 417 struct ipv6_addr *ia; 418 419 sin = (const void *)sa; 420 if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr))) 421 return ia->iface; 422 break; 423 } 424 #endif 425 default: 426 errno = EAFNOSUPPORT; 427 return NULL; 428 } 429 430 errno = ENOENT; 431 return NULL; 432 } 433 434 static void 435 if_copysa(struct sockaddr *dst, const struct sockaddr *src) 436 { 437 438 assert(dst != NULL); 439 assert(src != NULL); 440 441 memcpy(dst, src, src->sa_len); 442 #if defined(INET6) && defined(__KAME__) 443 if (dst->sa_family == AF_INET6) { 444 struct in6_addr *in6; 445 446 in6 = &satosin6(dst)->sin6_addr; 447 if (IN6_IS_ADDR_LINKLOCAL(in6)) 448 in6->s6_addr[2] = in6->s6_addr[3] = '\0'; 449 } 450 #endif 451 } 452 453 int 454 if_route(unsigned char cmd, const struct rt *rt) 455 { 456 struct dhcpcd_ctx *ctx; 457 struct rtm 458 { 459 struct rt_msghdr hdr; 460 char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX]; 461 } rtmsg; 462 struct rt_msghdr *rtm = &rtmsg.hdr; 463 char *bp = rtmsg.buffer; 464 struct sockaddr_dl sdl; 465 bool gateway_unspec; 466 467 assert(rt != NULL); 468 ctx = rt->rt_ifp->ctx; 469 470 if ((cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE) && 471 ctx->options & DHCPCD_DAEMONISE && 472 !(ctx->options & DHCPCD_DAEMONISED)) 473 ctx->options |= DHCPCD_RTM_PPID; 474 475 #define ADDSA(sa) do { \ 476 memcpy(bp, (sa), (sa)->sa_len); \ 477 bp += RT_ROUNDUP((sa)->sa_len); \ 478 } while (0 /* CONSTCOND */) 479 480 memset(&rtmsg, 0, sizeof(rtmsg)); 481 rtm->rtm_version = RTM_VERSION; 482 rtm->rtm_type = cmd; 483 #ifdef __OpenBSD__ 484 rtm->rtm_pid = getpid(); 485 #endif 486 rtm->rtm_seq = ++ctx->seq; 487 rtm->rtm_flags = (int)rt->rt_flags; 488 rtm->rtm_addrs = RTA_DST; 489 #ifdef RTF_PINNED 490 if (cmd != RTM_ADD) 491 rtm->rtm_flags |= RTF_PINNED; 492 #endif 493 494 gateway_unspec = sa_is_unspecified(&rt->rt_gateway); 495 496 if (cmd == RTM_ADD || cmd == RTM_CHANGE) { 497 bool netmask_bcast = sa_is_allones(&rt->rt_netmask); 498 499 rtm->rtm_flags |= RTF_UP; 500 rtm->rtm_addrs |= RTA_GATEWAY; 501 if (!(rtm->rtm_flags & RTF_REJECT) && 502 !sa_is_loopback(&rt->rt_gateway)) 503 { 504 rtm->rtm_index = (unsigned short)rt->rt_ifp->index; 505 if (!gateway_unspec) 506 rtm->rtm_addrs |= RTA_IFP; 507 if (!sa_is_unspecified(&rt->rt_ifa)) 508 rtm->rtm_addrs |= RTA_IFA; 509 } 510 if (netmask_bcast) 511 rtm->rtm_flags |= RTF_HOST; 512 /* Network routes are cloning or connected if supported. 513 * All other routes are static. */ 514 if (gateway_unspec) { 515 #ifdef RTF_CLONING 516 rtm->rtm_flags |= RTF_CLONING; 517 #endif 518 #ifdef RTF_CONNECTED 519 rtm->rtm_flags |= RTF_CONNECTED; 520 #endif 521 #ifdef RTP_CONNECTED 522 rtm->rtm_priority = RTP_CONNECTED; 523 #endif 524 #ifdef RTF_CLONING 525 if (netmask_bcast) { 526 /* 527 * We add a cloning network route for a single 528 * host. Traffic to the host will generate a 529 * cloned route and the hardware address will 530 * resolve correctly. 531 * It might be more correct to use RTF_HOST 532 * instead of RTF_CLONING, and that does work, 533 * but some OS generate an arp warning 534 * diagnostic which we don't want to do. 535 */ 536 rtm->rtm_flags &= ~RTF_HOST; 537 } 538 #endif 539 } else 540 rtm->rtm_flags |= RTF_GATEWAY; 541 542 /* Emulate the kernel by marking address generated 543 * network routes non-static. */ 544 if (!(rt->rt_dflags & RTDF_IFA_ROUTE)) 545 rtm->rtm_flags |= RTF_STATIC; 546 547 if (rt->rt_mtu != 0) { 548 rtm->rtm_inits |= RTV_MTU; 549 rtm->rtm_rmx.rmx_mtu = rt->rt_mtu; 550 } 551 } 552 553 if (!(rtm->rtm_flags & RTF_HOST)) 554 rtm->rtm_addrs |= RTA_NETMASK; 555 556 if_linkaddr(&sdl, rt->rt_ifp); 557 558 ADDSA(&rt->rt_dest); 559 560 if (rtm->rtm_addrs & RTA_GATEWAY) { 561 if (gateway_unspec) 562 ADDSA((struct sockaddr *)&sdl); 563 else { 564 union sa_ss gateway; 565 566 if_copysa(&gateway.sa, &rt->rt_gateway); 567 #ifdef INET6 568 if (gateway.sa.sa_family == AF_INET6) 569 ifa_scope(&gateway.sin6, rt->rt_ifp->index); 570 #endif 571 ADDSA(&gateway.sa); 572 } 573 } 574 575 if (rtm->rtm_addrs & RTA_NETMASK) 576 ADDSA(&rt->rt_netmask); 577 578 if (rtm->rtm_addrs & RTA_IFP) 579 ADDSA((struct sockaddr *)&sdl); 580 581 if (rtm->rtm_addrs & RTA_IFA) 582 ADDSA(&rt->rt_ifa); 583 584 #undef ADDSA 585 586 rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm); 587 if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1) 588 return -1; 589 ctx->sseq = ctx->seq; 590 return 0; 591 } 592 593 static int 594 if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm) 595 { 596 const struct sockaddr *rti_info[RTAX_MAX]; 597 598 if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) 599 return -1; 600 #ifdef RTF_CLONED 601 if (rtm->rtm_flags & RTF_CLONED) 602 return -1; 603 #endif 604 #ifdef RTF_LOCAL 605 if (rtm->rtm_flags & RTF_LOCAL) 606 return -1; 607 #endif 608 #ifdef RTF_BROADCAST 609 if (rtm->rtm_flags & RTF_BROADCAST) 610 return -1; 611 #endif 612 613 get_addrs(rtm->rtm_addrs, rtm + 1, rti_info); 614 memset(rt, 0, sizeof(*rt)); 615 616 rt->rt_flags = (unsigned int)rtm->rtm_flags; 617 if_copysa(&rt->rt_dest, rti_info[RTAX_DST]); 618 if (rtm->rtm_addrs & RTA_NETMASK) { 619 if_copysa(&rt->rt_netmask, rti_info[RTAX_NETMASK]); 620 if (rt->rt_netmask.sa_family == 255) /* Why? */ 621 rt->rt_netmask.sa_family = rt->rt_dest.sa_family; 622 } 623 /* dhcpcd likes an unspecified gateway to indicate via the link. */ 624 if (rt->rt_flags & RTF_GATEWAY && 625 rti_info[RTAX_GATEWAY]->sa_family != AF_LINK) 626 if_copysa(&rt->rt_gateway, rti_info[RTAX_GATEWAY]); 627 if (rtm->rtm_addrs & RTA_IFA) 628 if_copysa(&rt->rt_ifa, rti_info[RTAX_IFA]); 629 rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu; 630 631 if (rtm->rtm_index) 632 rt->rt_ifp = if_findindex(ctx->ifaces, rtm->rtm_index); 633 else if (rtm->rtm_addrs & RTA_IFP) 634 rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_IFP]); 635 else if (rtm->rtm_addrs & RTA_GATEWAY) 636 rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_GATEWAY]); 637 else 638 rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_DST]); 639 640 if (rt->rt_ifp == NULL) { 641 errno = ESRCH; 642 return -1; 643 } 644 return 0; 645 } 646 647 int 648 if_initrt(struct dhcpcd_ctx *ctx, int af) 649 { 650 struct rt_msghdr *rtm; 651 int mib[6]; 652 size_t needed; 653 char *buf, *p, *end; 654 struct rt rt; 655 656 rt_headclear(&ctx->kroutes, af); 657 658 mib[0] = CTL_NET; 659 mib[1] = PF_ROUTE; 660 mib[2] = 0; 661 mib[3] = af; 662 mib[4] = NET_RT_DUMP; 663 mib[5] = 0; 664 665 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 666 return -1; 667 if (needed == 0) 668 return 0; 669 if ((buf = malloc(needed)) == NULL) 670 return -1; 671 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { 672 free(buf); 673 return -1; 674 } 675 676 end = buf + needed; 677 for (p = buf; p < end; p += rtm->rtm_msglen) { 678 rtm = (void *)p; 679 if (if_copyrt(ctx, &rt, rtm) == 0) { 680 rt.rt_dflags |= RTDF_INIT; 681 rt_recvrt(RTM_ADD, &rt); 682 } 683 } 684 free(buf); 685 return 0; 686 } 687 688 #endif 689 690 #ifdef INET 691 int 692 if_address(unsigned char cmd, const struct ipv4_addr *ia) 693 { 694 int r; 695 struct in_aliasreq ifra; 696 697 memset(&ifra, 0, sizeof(ifra)); 698 strlcpy(ifra.ifra_name, ia->iface->name, sizeof(ifra.ifra_name)); 699 700 #define ADDADDR(var, addr) do { \ 701 (var)->sin_family = AF_INET; \ 702 (var)->sin_len = sizeof(*(var)); \ 703 (var)->sin_addr = *(addr); \ 704 } while (/*CONSTCOND*/0) 705 ADDADDR(&ifra.ifra_addr, &ia->addr); 706 ADDADDR(&ifra.ifra_mask, &ia->mask); 707 if (cmd == RTM_NEWADDR && ia->brd.s_addr != INADDR_ANY) 708 ADDADDR(&ifra.ifra_broadaddr, &ia->brd); 709 #undef ADDADDR 710 711 r = ioctl(ia->iface->ctx->pf_inet_fd, 712 cmd == RTM_DELADDR ? SIOCDIFADDR : SIOCAIFADDR, &ifra); 713 return r; 714 } 715 716 717 718 #if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS)) 719 int 720 if_addrflags(const struct interface *ifp, const struct in_addr *addr, 721 __unused const char *alias) 722 { 723 #ifdef SIOCGIFAFLAG_IN 724 struct ifreq ifr; 725 struct sockaddr_in *sin; 726 727 memset(&ifr, 0, sizeof(ifr)); 728 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 729 sin = (void *)&ifr.ifr_addr; 730 sin->sin_family = AF_INET; 731 sin->sin_addr = *addr; 732 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFAFLAG_IN, &ifr) == -1) 733 return -1; 734 return ifr.ifr_addrflags; 735 #else 736 UNUSED(ifp); 737 UNUSED(addr); 738 return 0; 739 #endif 740 } 741 #endif 742 #endif /* INET */ 743 744 #ifdef INET6 745 static void 746 ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex) 747 { 748 749 #ifdef __KAME__ 750 /* KAME based systems want to store the scope inside the sin6_addr 751 * for link local addresses */ 752 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 753 uint16_t scope = htons((uint16_t)ifindex); 754 memcpy(&sin->sin6_addr.s6_addr[2], &scope, 755 sizeof(scope)); 756 } 757 sin->sin6_scope_id = 0; 758 #else 759 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) 760 sin->sin6_scope_id = ifindex; 761 else 762 sin->sin6_scope_id = 0; 763 #endif 764 } 765 766 int 767 if_address6(unsigned char cmd, const struct ipv6_addr *ia) 768 { 769 struct in6_aliasreq ifa; 770 struct in6_addr mask; 771 struct priv *priv; 772 773 priv = (struct priv *)ia->iface->ctx->priv; 774 775 memset(&ifa, 0, sizeof(ifa)); 776 strlcpy(ifa.ifra_name, ia->iface->name, sizeof(ifa.ifra_name)); 777 /* 778 * We should not set IN6_IFF_TENTATIVE as the kernel should be 779 * able to work out if it's a new address or not. 780 * 781 * We should set IN6_IFF_AUTOCONF, but the kernel won't let us. 782 * This is probably a safety measure, but still it's not entirely right 783 * either. 784 */ 785 #if 0 786 if (ia->autoconf) 787 ifa.ifra_flags |= IN6_IFF_AUTOCONF; 788 #endif 789 #ifdef IPV6_MANGETEMPADDR 790 if (ia->flags & IPV6_AF_TEMPORARY) 791 ifa.ifra_flags |= IN6_IFF_TEMPORARY; 792 #endif 793 794 #define ADDADDR(v, addr) { \ 795 (v)->sin6_family = AF_INET6; \ 796 (v)->sin6_len = sizeof(*v); \ 797 (v)->sin6_addr = *(addr); \ 798 } 799 800 ADDADDR(&ifa.ifra_addr, &ia->addr); 801 ifa_scope(&ifa.ifra_addr, ia->iface->index); 802 ipv6_mask(&mask, ia->prefix_len); 803 ADDADDR(&ifa.ifra_prefixmask, &mask); 804 805 #undef ADDADDR 806 807 /* 808 * Every BSD kernel wants to add the prefix of the address to it's 809 * list of RA received prefixes. 810 * THIS IS WRONG because there (as the comments in the kernel state) 811 * is no API for managing prefix lifetime and the kernel should not 812 * pretend it's from a RA either. 813 * 814 * The issue is that the very first assigned prefix will inherit the 815 * lifetime of the address, but any subsequent alteration of the 816 * address OR it's lifetime will not affect the prefix lifetime. 817 * As such, we cannot stop the prefix from timing out and then 818 * constantly removing the prefix route dhcpcd is capable of adding 819 * in it's absense. 820 * 821 * What we can do to mitigate the issue is to add the address with 822 * infinite lifetimes, so the prefix route will never time out. 823 * Once done, we can then set lifetimes on the address and all is good. 824 * The downside of this approach is that we need to manually remove 825 * the kernel route because it has no lifetime, but this is OK as 826 * dhcpcd will handle this too. 827 * 828 * This issue is discussed on the NetBSD mailing lists here: 829 * http://mail-index.netbsd.org/tech-net/2016/08/05/msg006044.html 830 * 831 * Fixed in NetBSD-7.99.36 832 * NOT fixed in FreeBSD - bug 195197 833 * Fixed in OpenBSD-5.9 834 */ 835 836 #if !((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003600) || \ 837 (defined(__OpenBSD__) && OpenBSD >= 201605)) 838 if (cmd == RTM_NEWADDR && !(ia->flags & IPV6_AF_ADDED)) { 839 ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 840 ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 841 (void)ioctl(priv->pf_inet6_fd, SIOCAIFADDR_IN6, &ifa); 842 } 843 #endif 844 845 #if defined(__OpenBSD__) && OpenBSD <= 201705 846 /* BUT OpenBSD older than 6.2 does not reset the address lifetime 847 * for subsequent calls... 848 * Luckily dhcpcd will remove the lease when it expires so 849 * just set an infinite lifetime, unless a temporary address. */ 850 if (ifa.ifra_flags & IN6_IFF_PRIVACY) { 851 ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime; 852 ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime; 853 } else { 854 ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 855 ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 856 } 857 #else 858 ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime; 859 ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime; 860 #endif 861 862 return ioctl(priv->pf_inet6_fd, 863 cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa); 864 } 865 866 #if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS)) 867 int 868 if_addrflags6(const struct interface *ifp, const struct in6_addr *addr, 869 __unused const char *alias) 870 { 871 int flags; 872 struct in6_ifreq ifr6; 873 struct priv *priv; 874 875 memset(&ifr6, 0, sizeof(ifr6)); 876 strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name)); 877 ifr6.ifr_addr.sin6_family = AF_INET6; 878 ifr6.ifr_addr.sin6_addr = *addr; 879 ifa_scope(&ifr6.ifr_addr, ifp->index); 880 priv = (struct priv *)ifp->ctx->priv; 881 if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) 882 flags = ifr6.ifr_ifru.ifru_flags6; 883 else 884 flags = -1; 885 return flags; 886 } 887 #endif 888 889 int 890 if_getlifetime6(struct ipv6_addr *ia) 891 { 892 struct in6_ifreq ifr6; 893 time_t t; 894 struct in6_addrlifetime *lifetime; 895 struct priv *priv; 896 897 memset(&ifr6, 0, sizeof(ifr6)); 898 strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name)); 899 ifr6.ifr_addr.sin6_family = AF_INET6; 900 ifr6.ifr_addr.sin6_addr = ia->addr; 901 ifa_scope(&ifr6.ifr_addr, ia->iface->index); 902 priv = (struct priv *)ia->iface->ctx->priv; 903 if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1) 904 return -1; 905 906 t = time(NULL); 907 lifetime = &ifr6.ifr_ifru.ifru_lifetime; 908 909 if (lifetime->ia6t_preferred) 910 ia->prefix_pltime = (uint32_t)(lifetime->ia6t_preferred - 911 MIN(t, lifetime->ia6t_preferred)); 912 else 913 ia->prefix_pltime = ND6_INFINITE_LIFETIME; 914 if (lifetime->ia6t_expire) { 915 ia->prefix_vltime = (uint32_t)(lifetime->ia6t_expire - 916 MIN(t, lifetime->ia6t_expire)); 917 /* Calculate the created time */ 918 clock_gettime(CLOCK_MONOTONIC, &ia->created); 919 ia->created.tv_sec -= lifetime->ia6t_vltime - ia->prefix_vltime; 920 } else 921 ia->prefix_vltime = ND6_INFINITE_LIFETIME; 922 return 0; 923 } 924 #endif 925 926 static void 927 if_announce(struct dhcpcd_ctx *ctx, const struct if_announcemsghdr *ifan) 928 { 929 930 switch(ifan->ifan_what) { 931 case IFAN_ARRIVAL: 932 dhcpcd_handleinterface(ctx, 1, ifan->ifan_name); 933 break; 934 case IFAN_DEPARTURE: 935 dhcpcd_handleinterface(ctx, -1, ifan->ifan_name); 936 break; 937 } 938 } 939 940 static void 941 if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) 942 { 943 struct interface *ifp; 944 int link_state; 945 946 if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL) 947 return; 948 switch (ifm->ifm_data.ifi_link_state) { 949 case LINK_STATE_DOWN: 950 link_state = LINK_DOWN; 951 break; 952 case LINK_STATE_UP: 953 /* dhcpcd considers the link down if IFF_UP is not set. */ 954 link_state = ifm->ifm_flags & IFF_UP ? LINK_UP : LINK_DOWN; 955 break; 956 default: 957 /* handle_carrier will re-load the interface flags and check for 958 * IFF_RUNNING as some drivers that don't handle link state also 959 * don't set IFF_RUNNING when this routing message is generated. 960 * As such, it is a race ...*/ 961 link_state = LINK_UNKNOWN; 962 break; 963 } 964 dhcpcd_handlecarrier(ctx, link_state, 965 (unsigned int)ifm->ifm_flags, ifp->name); 966 } 967 968 static int 969 if_ownmsgpid(struct dhcpcd_ctx *ctx, pid_t pid, int seq) 970 { 971 972 /* Ignore messages generated by us */ 973 if (getpid() == pid) { 974 ctx->options &= ~DHCPCD_RTM_PPID; 975 return 1; 976 } 977 978 /* Ignore messages sent by the parent after forking */ 979 if ((ctx->options & 980 (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED)) == 981 (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED) && 982 ctx->ppid == pid) 983 { 984 /* If this is the last successful message sent, 985 * clear the check flag as it's possible another 986 * process could re-use the same pid and also 987 * manipulate the routing table. */ 988 if (ctx->pseq == seq) 989 ctx->options &= ~DHCPCD_RTM_PPID; 990 return 1; 991 } 992 993 /* Not a message we made. */ 994 return 0; 995 } 996 997 static void 998 if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) 999 { 1000 struct rt rt; 1001 1002 if (if_ownmsgpid(ctx, rtm->rtm_pid, rtm->rtm_seq)) 1003 return; 1004 1005 /* Ignore errors. */ 1006 if (rtm->rtm_errno != 0) 1007 return; 1008 1009 if (if_copyrt(ctx, &rt, rtm) == -1) 1010 return; 1011 1012 #ifdef INET6 1013 /* 1014 * BSD announces host routes. 1015 * As such, we should be notified of reachability by its 1016 * existance with a hardware address. 1017 */ 1018 if (rt.rt_dest.sa_family == AF_INET6 && rt.rt_flags & RTF_HOST) { 1019 struct sockaddr_in6 dest; 1020 struct sockaddr_dl sdl; 1021 1022 memcpy(&dest, &rt.rt_dest, rt.rt_dest.sa_len); 1023 if (rt.rt_gateway.sa_family == AF_LINK) 1024 memcpy(&sdl, &rt.rt_gateway, rt.rt_gateway.sa_len); 1025 else 1026 sdl.sdl_alen = 0; 1027 ipv6nd_neighbour(ctx, &dest.sin6_addr, 1028 rtm->rtm_type != RTM_DELETE && sdl.sdl_alen ? 1029 IPV6ND_REACHABLE : 0); 1030 } 1031 #endif 1032 1033 rt_recvrt(rtm->rtm_type, &rt); 1034 } 1035 1036 static void 1037 if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) 1038 { 1039 struct interface *ifp; 1040 const struct sockaddr *rti_info[RTAX_MAX]; 1041 int addrflags; 1042 pid_t pid; 1043 1044 if ((ifp = if_findindex(ctx->ifaces, ifam->ifam_index)) == NULL) 1045 return; 1046 get_addrs(ifam->ifam_addrs, ifam + 1, rti_info); 1047 if (rti_info[RTAX_IFA] == NULL) 1048 return; 1049 1050 #ifdef HAVE_IFAM_PID 1051 if (if_ownmsgpid(ctx, ifam->ifam_pid, 0)) { 1052 #ifdef HAVE_IFAM_ADDRFLAGS 1053 /* If the kernel isn't doing DAD for the newly added 1054 * address we need to let it through. */ 1055 if (ifam->ifam_type != RTM_NEWADDR) 1056 return; 1057 switch (rti_info[RTAX_IFA]->sa_family) { 1058 case AF_INET: 1059 if (ifam->ifam_addrflags & IN_IFF_TENTATIVE) 1060 return; 1061 break; 1062 case AF_INET6: 1063 if (ifam->ifam_addrflags & IN6_IFF_TENTATIVE) 1064 return; 1065 break; 1066 default: 1067 return; 1068 } 1069 #endif 1070 } 1071 pid = ifam->ifam_pid; 1072 #else 1073 pid = 0; 1074 #endif 1075 1076 #ifdef HAVE_IFAM_ADDRFLAGS 1077 addrflags = ifam->ifam_addrflags; 1078 #endif 1079 switch (rti_info[RTAX_IFA]->sa_family) { 1080 case AF_LINK: 1081 { 1082 struct sockaddr_dl sdl; 1083 1084 #ifdef RTM_CHGADDR 1085 if (ifam->ifam_type != RTM_CHGADDR) 1086 break; 1087 #else 1088 if (ifam->ifam_type != RTM_NEWADDR) 1089 break; 1090 #endif 1091 memcpy(&sdl, rti_info[RTAX_IFA], rti_info[RTAX_IFA]->sa_len); 1092 dhcpcd_handlehwaddr(ctx, ifp->name, CLLADDR(&sdl),sdl.sdl_alen); 1093 break; 1094 } 1095 #ifdef INET 1096 case AF_INET: 1097 case 255: /* FIXME: Why 255? */ 1098 { 1099 const struct sockaddr_in *sin; 1100 struct in_addr addr, mask, bcast; 1101 1102 sin = (const void *)rti_info[RTAX_IFA]; 1103 addr.s_addr = sin != NULL && sin->sin_family == AF_INET ? 1104 sin->sin_addr.s_addr : INADDR_ANY; 1105 sin = (const void *)rti_info[RTAX_NETMASK]; 1106 mask.s_addr = sin != NULL && sin->sin_family == AF_INET ? 1107 sin->sin_addr.s_addr : INADDR_ANY; 1108 1109 #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000 1110 /* NetBSD-7 and older send an invalid broadcast address. 1111 * So we need to query the actual address to get 1112 * the right one. */ 1113 { 1114 struct in_aliasreq ifra; 1115 1116 memset(&ifra, 0, sizeof(ifra)); 1117 strlcpy(ifra.ifra_name, ifp->name, 1118 sizeof(ifra.ifra_name)); 1119 ifra.ifra_addr.sin_family = AF_INET; 1120 ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr); 1121 ifra.ifra_addr.sin_addr = addr; 1122 if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) { 1123 if (errno != EADDRNOTAVAIL) 1124 logerr("%s: SIOCGIFALIAS", __func__); 1125 break; 1126 } 1127 bcast = ifra.ifra_broadaddr.sin_addr; 1128 } 1129 #else 1130 sin = (const void *)rti_info[RTAX_BRD]; 1131 bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ? 1132 sin->sin_addr.s_addr : INADDR_ANY; 1133 #endif 1134 1135 #if defined(__FreeBSD__) || defined(__DragonFly__) 1136 /* FreeBSD sends RTM_DELADDR for each assigned address 1137 * to an interface just brought down. 1138 * This is wrong, because the address still exists. 1139 * So we need to ignore it. 1140 * Oddly enough this only happens for INET addresses. */ 1141 if (ifam->ifam_type == RTM_DELADDR) { 1142 struct ifreq ifr; 1143 struct sockaddr_in *ifr_sin; 1144 1145 memset(&ifr, 0, sizeof(ifr)); 1146 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1147 ifr_sin = (void *)&ifr.ifr_addr; 1148 ifr_sin->sin_family = AF_INET; 1149 ifr_sin->sin_addr = addr; 1150 if (ioctl(ctx->pf_inet_fd, SIOCGIFADDR, &ifr) == 0) { 1151 logwarnx("%s: ignored false RTM_DELADDR for %s", 1152 ifp->name, inet_ntoa(addr)); 1153 break; 1154 } 1155 } 1156 #endif 1157 1158 #ifndef HAVE_IFAM_ADDRFLAGS 1159 if (ifam->ifam_type == RTM_DELADDR) 1160 addrflags = 0 ; 1161 else if ((addrflags = if_addrflags(ifp, &addr, NULL)) == -1) { 1162 if (errno != EADDRNOTAVAIL) 1163 logerr("%s: if_addrflags", __func__); 1164 break; 1165 } 1166 #endif 1167 1168 ipv4_handleifa(ctx, ifam->ifam_type, NULL, ifp->name, 1169 &addr, &mask, &bcast, addrflags, pid); 1170 break; 1171 } 1172 #endif 1173 #ifdef INET6 1174 case AF_INET6: 1175 { 1176 struct in6_addr addr6, mask6; 1177 const struct sockaddr_in6 *sin6; 1178 1179 sin6 = (const void *)rti_info[RTAX_IFA]; 1180 addr6 = sin6->sin6_addr; 1181 sin6 = (const void *)rti_info[RTAX_NETMASK]; 1182 mask6 = sin6->sin6_addr; 1183 1184 #ifndef HAVE_IFAM_ADDRFLAGS 1185 if (ifam->ifam_type == RTM_DELADDR) 1186 addrflags = 0; 1187 else if ((addrflags = if_addrflags6(ifp, &addr6, NULL)) == -1) { 1188 if (errno != EADDRNOTAVAIL) 1189 logerr("%s: if_addrflags6", __func__); 1190 break; 1191 } 1192 #endif 1193 1194 #ifdef __KAME__ 1195 if (IN6_IS_ADDR_LINKLOCAL(&addr6)) 1196 /* Remove the scope from the address */ 1197 addr6.s6_addr[2] = addr6.s6_addr[3] = '\0'; 1198 #endif 1199 1200 ipv6_handleifa(ctx, ifam->ifam_type, NULL, 1201 ifp->name, &addr6, ipv6_prefixlen(&mask6), addrflags, pid); 1202 break; 1203 } 1204 #endif 1205 } 1206 } 1207 1208 static void 1209 if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) 1210 { 1211 1212 if (rtm->rtm_version != RTM_VERSION) 1213 return; 1214 1215 switch(rtm->rtm_type) { 1216 #ifdef RTM_IFANNOUNCE 1217 case RTM_IFANNOUNCE: 1218 if_announce(ctx, (const void *)rtm); 1219 break; 1220 #endif 1221 case RTM_IFINFO: 1222 if_ifinfo(ctx, (const void *)rtm); 1223 break; 1224 case RTM_ADD: /* FALLTHROUGH */ 1225 case RTM_CHANGE: /* FALLTHROUGH */ 1226 case RTM_DELETE: 1227 if_rtm(ctx, (const void *)rtm); 1228 break; 1229 #ifdef RTM_CHGADDR 1230 case RTM_CHGADDR: /* FALLTHROUGH */ 1231 #endif 1232 case RTM_DELADDR: /* FALLTHROUGH */ 1233 case RTM_NEWADDR: 1234 if_ifa(ctx, (const void *)rtm); 1235 break; 1236 #ifdef RTM_DESYNC 1237 case RTM_DESYNC: 1238 dhcpcd_linkoverflow(ctx); 1239 break; 1240 #endif 1241 } 1242 } 1243 1244 int 1245 if_handlelink(struct dhcpcd_ctx *ctx) 1246 { 1247 struct msghdr msg; 1248 ssize_t len; 1249 1250 memset(&msg, 0, sizeof(msg)); 1251 msg.msg_iov = ctx->iov; 1252 msg.msg_iovlen = 1; 1253 1254 len = recvmsg_realloc(ctx->link_fd, &msg, 0); 1255 if (len == -1) 1256 return -1; 1257 if (len != 0) 1258 if_dispatch(ctx, ctx->iov[0].iov_base); 1259 return 0; 1260 } 1261 1262 #ifndef SYS_NMLN /* OSX */ 1263 # define SYS_NMLN 256 1264 #endif 1265 #ifndef HW_MACHINE_ARCH 1266 # ifdef HW_MODEL /* OpenBSD */ 1267 # define HW_MACHINE_ARCH HW_MODEL 1268 # endif 1269 #endif 1270 int 1271 if_machinearch(char *str, size_t len) 1272 { 1273 int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1274 char march[SYS_NMLN]; 1275 size_t marchlen = sizeof(march); 1276 1277 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 1278 march, &marchlen, NULL, 0) != 0) 1279 return -1; 1280 return snprintf(str, len, ":%s", march); 1281 } 1282 1283 #ifdef INET6 1284 #if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) || \ 1285 defined(IPV6CTL_USETEMPADDR) || defined(IPV6CTL_TEMPVLTIME) 1286 #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0) 1287 #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1) 1288 static int 1289 inet6_sysctl(int code, int val, int action) 1290 { 1291 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 1292 size_t size; 1293 1294 mib[3] = code; 1295 size = sizeof(val); 1296 if (action) { 1297 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), 1298 NULL, 0, &val, size) == -1) 1299 return -1; 1300 return 0; 1301 } 1302 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &val, &size, NULL, 0) == -1) 1303 return -1; 1304 return val; 1305 } 1306 #endif 1307 1308 #ifdef IPV6_MANAGETEMPADDR 1309 #ifndef IPV6CTL_TEMPVLTIME 1310 #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0) 1311 #define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1) 1312 static int 1313 inet6_sysctlbyname(const char *name, int val, int action) 1314 { 1315 size_t size; 1316 1317 size = sizeof(val); 1318 if (action) { 1319 if (sysctlbyname(name, NULL, 0, &val, size) == -1) 1320 return -1; 1321 return 0; 1322 } 1323 if (sysctlbyname(name, &val, &size, NULL, 0) == -1) 1324 return -1; 1325 return val; 1326 } 1327 #endif 1328 1329 int 1330 ip6_use_tempaddr(__unused const char *ifname) 1331 { 1332 int val; 1333 1334 #ifdef IPV6CTL_USETEMPADDR 1335 val = get_inet6_sysctl(IPV6CTL_USETEMPADDR); 1336 #else 1337 val = get_inet6_sysctlbyname("net.inet6.ip6.use_tempaddr"); 1338 #endif 1339 return val == -1 ? 0 : val; 1340 } 1341 1342 int 1343 ip6_temp_preferred_lifetime(__unused const char *ifname) 1344 { 1345 int val; 1346 1347 #ifdef IPV6CTL_TEMPPLTIME 1348 val = get_inet6_sysctl(IPV6CTL_TEMPPLTIME); 1349 #else 1350 val = get_inet6_sysctlbyname("net.inet6.ip6.temppltime"); 1351 #endif 1352 return val < 0 ? TEMP_PREFERRED_LIFETIME : val; 1353 } 1354 1355 int 1356 ip6_temp_valid_lifetime(__unused const char *ifname) 1357 { 1358 int val; 1359 1360 #ifdef IPV6CTL_TEMPVLTIME 1361 val = get_inet6_sysctl(IPV6CTL_TEMPVLTIME); 1362 #else 1363 val = get_inet6_sysctlbyname("net.inet6.ip6.tempvltime"); 1364 #endif 1365 return val < 0 ? TEMP_VALID_LIFETIME : val; 1366 } 1367 #endif 1368 1369 #ifdef SIOCIFAFATTACH 1370 static int 1371 af_attach(int s, const struct interface *ifp, int af) 1372 { 1373 struct if_afreq ifar; 1374 1375 strlcpy(ifar.ifar_name, ifp->name, sizeof(ifar.ifar_name)); 1376 ifar.ifar_af = af; 1377 return ioctl(s, SIOCIFAFATTACH, (void *)&ifar); 1378 } 1379 #endif 1380 1381 #ifdef SIOCGIFXFLAGS 1382 static int 1383 set_ifxflags(int s, const struct interface *ifp) 1384 { 1385 struct ifreq ifr; 1386 int flags; 1387 1388 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1389 if (ioctl(s, SIOCGIFXFLAGS, (void *)&ifr) == -1) 1390 return -1; 1391 flags = ifr.ifr_flags; 1392 #ifdef IFXF_NOINET6 1393 flags &= ~IFXF_NOINET6; 1394 #endif 1395 /* 1396 * If not doing autoconf, don't disable the kernel from doing it. 1397 * If we need to, we should have another option actively disable it. 1398 */ 1399 if (ifp->options->options & DHCPCD_IPV6RS) 1400 flags &= ~IFXF_AUTOCONF6; 1401 if (ifr.ifr_flags == flags) 1402 return 0; 1403 ifr.ifr_flags = flags; 1404 return ioctl(s, SIOCSIFXFLAGS, (void *)&ifr); 1405 } 1406 #endif 1407 1408 /* OpenBSD removed ND6 flags entirely, so we need to check for their 1409 * existance. */ 1410 #if defined(ND6_IFF_AUTO_LINKLOCAL) || \ 1411 defined(ND6_IFF_PERFORMNUD) || \ 1412 defined(ND6_IFF_ACCEPT_RTADV) || \ 1413 defined(ND6_IFF_OVERRIDE_RTADV) || \ 1414 defined(ND6_IFF_IFDISABLED) 1415 #define ND6_NDI_FLAGS 1416 #endif 1417 1418 void 1419 if_setup_inet6(const struct interface *ifp) 1420 { 1421 struct priv *priv; 1422 int s; 1423 #ifdef ND6_NDI_FLAGS 1424 struct in6_ndireq nd; 1425 int flags; 1426 #endif 1427 1428 priv = (struct priv *)ifp->ctx->priv; 1429 s = priv->pf_inet6_fd; 1430 1431 #ifdef ND6_NDI_FLAGS 1432 memset(&nd, 0, sizeof(nd)); 1433 strlcpy(nd.ifname, ifp->name, sizeof(nd.ifname)); 1434 if (ioctl(s, SIOCGIFINFO_IN6, &nd) == -1) 1435 logerr("%s: SIOCGIFINFO_FLAGS", ifp->name); 1436 flags = (int)nd.ndi.flags; 1437 #endif 1438 1439 #ifdef ND6_IFF_AUTO_LINKLOCAL 1440 /* Unlike the kernel, 1441 * dhcpcd make make a stable private address. */ 1442 flags &= ~ND6_IFF_AUTO_LINKLOCAL; 1443 #endif 1444 1445 #ifdef ND6_IFF_PERFORMNUD 1446 /* NUD is kind of essential. */ 1447 flags |= ND6_IFF_PERFORMNUD; 1448 #endif 1449 1450 #ifdef ND6_IFF_IFDISABLED 1451 /* Ensure the interface is not disabled. */ 1452 flags &= ~ND6_IFF_IFDISABLED; 1453 #endif 1454 1455 /* 1456 * If not doing autoconf, don't disable the kernel from doing it. 1457 * If we need to, we should have another option actively disable it. 1458 */ 1459 #ifdef ND6_IFF_ACCEPT_RTADV 1460 if (ifp->options->options & DHCPCD_IPV6RS) 1461 flags &= ~ND6_IFF_ACCEPT_RTADV; 1462 #ifdef ND6_IFF_OVERRIDE_RTADV 1463 if (ifp->options->options & DHCPCD_IPV6RS) 1464 flags |= ND6_IFF_OVERRIDE_RTADV; 1465 #endif 1466 #endif 1467 1468 #ifdef ND6_NDI_FLAGS 1469 if (nd.ndi.flags != (uint32_t)flags) { 1470 nd.ndi.flags = (uint32_t)flags; 1471 if (ioctl(s, SIOCSIFINFO_FLAGS, &nd) == -1) 1472 logerr("%s: SIOCSIFINFO_FLAGS", ifp->name); 1473 } 1474 #endif 1475 1476 /* Enabling IPv6 by whatever means must be the 1477 * last action undertaken to ensure kernel RS and 1478 * LLADDR auto configuration are disabled where applicable. */ 1479 #ifdef SIOCIFAFATTACH 1480 if (af_attach(s, ifp, AF_INET6) == -1) 1481 logerr("%s: af_attach", ifp->name); 1482 #endif 1483 1484 #ifdef SIOCGIFXFLAGS 1485 if (set_ifxflags(s, ifp) == -1) 1486 logerr("%s: set_ifxflags", ifp->name); 1487 #endif 1488 1489 #if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV) 1490 /* If we cannot control ra per interface, disable it globally. */ 1491 if (ifp->options->options & DHCPCD_IPV6RS) { 1492 int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV); 1493 1494 if (ra == -1) { 1495 if (errno != ENOENT) 1496 logerr("IPV6CTL_ACCEPT_RTADV"); 1497 else if (ra != 0) 1498 if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) 1499 logerr("IPV6CTL_ACCEPT_RTADV"); 1500 } 1501 } 1502 #endif 1503 1504 #if defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV) 1505 /* Flush the kernel knowledge of advertised routers 1506 * and prefixes so the kernel does not expire prefixes 1507 * and default routes we are trying to own. */ 1508 if (ifp->options->options & DHCPCD_IPV6RS) { 1509 char ifname[IFNAMSIZ + 8]; 1510 1511 strlcpy(ifname, ifp->name, sizeof(ifname)); 1512 if (ioctl(s, SIOCSRTRFLUSH_IN6, (void *)&ifname) == -1 && 1513 errno != ENOTSUP) 1514 logwarn("SIOCSRTRFLUSH_IN6"); 1515 if (ioctl(s, SIOCSPFXFLUSH_IN6, (void *)&ifname) == -1 && 1516 errno != ENOTSUP) 1517 logwarn("SIOCSPFXFLUSH_IN6"); 1518 } 1519 #endif 1520 } 1521 #endif 1522