1 /* 2 * BSD interface driver for dhcpcd 3 * SPDX-License-Identifier: BSD-2-Clause 4 * Copyright (c) 2006-2025 Roy Marples <roy (at) marples.name> 5 * All rights reserved 6 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 #include <sys/stat.h> 34 #include <sys/sysctl.h> 35 #include <sys/time.h> 36 #include <sys/uio.h> 37 #include <sys/utsname.h> 38 39 #include <net/bpf.h> 40 #include <net/if.h> 41 #include <net/if_dl.h> 42 #include <net/if_media.h> 43 #include <net/route.h> 44 #include <netinet/in.h> 45 #include <netinet/in_var.h> 46 #include <netinet6/in6_var.h> 47 #include <netinet6/nd6.h> 48 #include <netinet/if_ether.h> 49 50 #include <arpa/inet.h> 51 52 #include "config.h" // IWYU pragma: keep 53 #include "dhcpcd.h" 54 #ifdef __NetBSD__ 55 #include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */ 56 #elif defined(__DragonFly__) 57 #include <net/vlan/if_vlan_var.h> 58 #elif defined(__APPLE__) 59 /* Apple doesn't ship this in include/net ... */ 60 struct vlanreq { 61 char vlr_parent[IFNAMSIZ]; 62 u_short vlr_tag; 63 }; 64 #else 65 #include <net/if_vlan_var.h> 66 #endif 67 #ifdef __DragonFly__ 68 #include <netproto/802_11/ieee80211_ioctl.h> 69 #elif !defined(__APPLE__) 70 #include <net80211/ieee80211.h> 71 #include <net80211/ieee80211_ioctl.h> 72 #endif 73 74 #include <assert.h> 75 #include <errno.h> 76 #include <fcntl.h> 77 #include <fnmatch.h> 78 #include <paths.h> 79 #include <stddef.h> 80 #include <stdio.h> 81 #include <stdlib.h> 82 #include <string.h> 83 #include <unistd.h> 84 85 #if defined(OpenBSD) && OpenBSD >= 201411 86 /* OpenBSD dropped the global setting from sysctl but left the #define 87 * which causes a EPERM error when trying to use it. 88 * I think both the error and keeping the define are wrong, so we #undef it. */ 89 #undef IPV6CTL_ACCEPT_RTADV 90 #endif 91 92 #include "common.h" 93 #include "dhcp.h" 94 #include "if-options.h" 95 #include "if.h" 96 #include "ipv4.h" 97 #include "ipv4ll.h" 98 #include "ipv6.h" 99 #include "ipv6nd.h" 100 #include "logerr.h" 101 #include "privsep.h" 102 #include "route.h" 103 #include "sa.h" 104 105 #ifndef RT_ROUNDUP 106 #ifdef __APPLE__ 107 #define RT_ROUNDUP(a) \ 108 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : \ 109 sizeof(uint32_t)) 110 #else 111 #define RT_ROUNDUP(a) \ 112 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 113 #endif 114 #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len)) 115 #endif 116 /* Ignore these interface names which look like ethernet but are virtual or 117 * just won't work without explicit configuration. */ 118 static const char *const ifnames_ignore[] = { "bridge", 119 "epair", /* Virtual patch cable */ 120 "fwe", /* Firewire */ 121 "fwip", /* Firewire */ 122 "tap", "vether", "xvif", /* XEN DOM0 -> guest interface */ 123 #ifdef __APPLE__ 124 "ap", "awdl", "llw", 125 #endif 126 NULL }; 127 128 struct rtm { 129 struct rt_msghdr hdr; 130 char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX]; 131 }; 132 133 int 134 os_init(void) 135 { 136 return 0; 137 } 138 139 int 140 if_init(__unused struct interface *iface) 141 { 142 /* No extra init needed. */ 143 return 0; 144 } 145 146 int 147 if_init_os(__unused struct interface *iface) 148 { 149 /* BSD promotes secondary address by default */ 150 return 0; 151 } 152 153 int 154 if_conf(__unused struct interface *iface) 155 { 156 /* No extra checks needed on BSD */ 157 return 0; 158 } 159 160 int 161 if_opensockets_os(struct dhcpcd_ctx *ctx) 162 { 163 struct priv *priv; 164 int n; 165 #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER) 166 unsigned char msgfilter[] = { RTM_IFINFO, 167 #ifdef RTM_IFANNOUNCE 168 RTM_IFANNOUNCE, 169 #endif 170 RTM_ADD, RTM_CHANGE, RTM_DELETE, RTM_MISS, 171 #ifdef RTM_CHGADDR 172 RTM_CHGADDR, 173 #endif 174 #ifdef RTM_DESYNC 175 RTM_DESYNC, 176 #endif 177 RTM_NEWADDR, RTM_DELADDR }; 178 #ifdef ROUTE_MSGFILTER 179 unsigned int i, msgfilter_mask; 180 #endif 181 #endif 182 183 if ((priv = malloc(sizeof(*priv))) == NULL) 184 return -1; 185 ctx->priv = priv; 186 187 #ifdef INET6 188 priv->pf_inet6_fd = xsocket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); 189 /* Don't return an error so we at least work on kernels witout INET6 190 * even though we expect INET6 support. 191 * We will fail noisily elsewhere anyway. */ 192 #ifdef PRIVSEP_RIGHTS 193 if (priv->pf_inet6_fd != -1 && IN_PRIVSEP(ctx)) 194 ps_rights_limit_ioctl(priv->pf_inet6_fd); 195 #endif 196 #endif 197 198 ctx->link_fd = xsocket(PF_ROUTE, SOCK_RAW | SOCK_CXNB, AF_UNSPEC); 199 if (ctx->link_fd == -1) 200 return -1; 201 202 #ifdef SO_RERROR 203 n = 1; 204 if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == 205 -1) 206 logerr("%s: SO_RERROR", __func__); 207 #endif 208 209 /* Ignore our own route(4) messages. 210 * Sadly there is no way of doing this for route(4) messages 211 * generated from addresses we add/delete. */ 212 n = 0; 213 if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_USELOOPBACK, &n, 214 sizeof(n)) == -1) 215 logerr("%s: SO_USELOOPBACK", __func__); 216 217 #ifdef PRIVSEP 218 if (ctx->options & DHCPCD_PRIVSEPROOT) { 219 /* We only want to write to this socket, so set 220 * a small as possible buffer size. */ 221 socklen_t smallbuf = 1; 222 223 if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RCVBUF, &smallbuf, 224 (socklen_t)sizeof(smallbuf)) == -1) 225 logerr("%s: setsockopt(SO_RCVBUF)", __func__); 226 } 227 #endif 228 229 #if defined(RO_MSGFILTER) 230 if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER, &msgfilter, 231 sizeof(msgfilter)) == -1) 232 logerr(__func__); 233 #elif defined(ROUTE_MSGFILTER) 234 /* Convert the array into a bitmask. */ 235 msgfilter_mask = 0; 236 for (i = 0; i < __arraycount(msgfilter); i++) 237 msgfilter_mask |= ROUTE_FILTER(msgfilter[i]); 238 if (setsockopt(ctx->link_fd, PF_ROUTE, ROUTE_MSGFILTER, &msgfilter_mask, 239 sizeof(msgfilter_mask)) == -1) 240 logerr(__func__); 241 #else 242 #warning kernel does not support route message filtering 243 #endif 244 245 #ifdef PRIVSEP_RIGHTS 246 /* We need to getsockopt for SO_RCVBUF and 247 * setsockopt for RO_MISSFILTER. */ 248 if (IN_PRIVSEP(ctx)) 249 ps_rights_limit_fd_sockopt(ctx->link_fd); 250 #endif 251 252 #if (defined(SIOCALIFADDR) && defined(IFLR_ACTIVE)) 253 priv->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0); 254 if (priv->pf_link_fd == -1) 255 logerr("%s: socket(PF_LINK)", __func__); 256 #endif 257 return 0; 258 } 259 260 void 261 if_closesockets_os(struct dhcpcd_ctx *ctx) 262 { 263 struct priv *priv; 264 265 priv = (struct priv *)ctx->priv; 266 if (priv == NULL) 267 return; 268 269 #ifdef INET6 270 if (priv->pf_inet6_fd != -1) { 271 close(priv->pf_inet6_fd); 272 priv->pf_inet6_fd = -1; 273 } 274 #endif 275 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */ 276 if (priv->pf_link_fd != -1) { 277 close(priv->pf_link_fd); 278 priv->pf_link_fd = -1; 279 } 280 #endif 281 free(priv); 282 ctx->priv = NULL; 283 free(ctx->rt_missfilter); 284 } 285 286 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */ 287 static int 288 if_ioctllink(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len) 289 { 290 struct priv *priv = (struct priv *)ctx->priv; 291 292 #ifdef PRIVSEP 293 if (ctx->options & DHCPCD_PRIVSEP) 294 return (int)ps_root_ioctllink(ctx, req, data, len); 295 #endif 296 297 return ioctl(priv->pf_link_fd, req, data, len); 298 } 299 #endif 300 301 int 302 if_setmac(struct interface *ifp, void *mac, uint8_t maclen) 303 { 304 if (ifp->hwlen != maclen) { 305 errno = EINVAL; 306 return -1; 307 } 308 309 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */ 310 struct if_laddrreq iflr = { .flags = IFLR_ACTIVE }; 311 struct sockaddr_dl *sdl = satosdl(&iflr.addr); 312 int retval; 313 314 strlcpy(iflr.iflr_name, ifp->name, sizeof(iflr.iflr_name)); 315 sdl->sdl_family = AF_LINK; 316 sdl->sdl_len = sizeof(*sdl); 317 sdl->sdl_alen = maclen; 318 memcpy(LLADDR(sdl), mac, maclen); 319 retval = if_ioctllink(ifp->ctx, SIOCALIFADDR, &iflr, sizeof(iflr)); 320 321 /* Try and remove the old address */ 322 memcpy(LLADDR(sdl), ifp->hwaddr, ifp->hwlen); 323 if_ioctllink(ifp->ctx, SIOCDLIFADDR, &iflr, sizeof(iflr)); 324 325 return retval; 326 #else 327 struct ifreq ifr = { 328 .ifr_addr.sa_family = AF_LINK, 329 .ifr_addr.sa_len = maclen, 330 }; 331 332 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 333 memcpy(ifr.ifr_addr.sa_data, mac, maclen); 334 return if_ioctl(ifp->ctx, SIOCSIFLLADDR, &ifr, sizeof(ifr)); 335 #endif 336 } 337 338 static bool 339 if_ignore1(const char *drvname) 340 { 341 const char *const *p; 342 343 for (p = ifnames_ignore; *p; p++) { 344 if (strcmp(*p, drvname) == 0) 345 return true; 346 } 347 return false; 348 } 349 350 #ifdef SIOCGIFGROUP 351 int 352 if_ignoregroup(int s, const char *ifname) 353 { 354 struct ifgroupreq ifgr = { .ifgr_len = 0 }; 355 struct ifg_req *ifg; 356 size_t ifg_len; 357 358 /* Sadly it is possible to remove the device name 359 * from the interface groups, but hopefully this 360 * will be very unlikely.... */ 361 362 strlcpy(ifgr.ifgr_name, ifname, sizeof(ifgr.ifgr_name)); 363 if (ioctl(s, SIOCGIFGROUP, &ifgr) == -1 || 364 (ifgr.ifgr_groups = malloc(ifgr.ifgr_len)) == NULL || 365 ioctl(s, SIOCGIFGROUP, &ifgr) == -1) { 366 logerr(__func__); 367 return -1; 368 } 369 370 for (ifg = ifgr.ifgr_groups, ifg_len = ifgr.ifgr_len; 371 ifg && ifg_len >= sizeof(*ifg); ifg++, ifg_len -= sizeof(*ifg)) { 372 if (if_ignore1(ifg->ifgrq_group)) 373 return 1; 374 } 375 return 0; 376 } 377 #endif 378 379 bool 380 if_ignore(struct dhcpcd_ctx *ctx, const char *ifname) 381 { 382 struct if_spec spec; 383 384 if (if_nametospec(ifname, &spec) != 0) 385 return false; 386 387 if (if_ignore1(spec.drvname)) 388 return true; 389 390 #ifdef SIOCGIFGROUP 391 #if defined(PRIVSEP) && defined(HAVE_PLEDGE) 392 if (IN_PRIVSEP(ctx)) 393 return ps_root_ifignoregroup(ctx, ifname) == 1 ? true : false; 394 #endif 395 else 396 return if_ignoregroup(ctx->pf_inet_fd, ifname) == 1 ? true : 397 false; 398 #else 399 UNUSED(ctx); 400 return false; 401 #endif 402 } 403 404 static int 405 if_indirect_ioctl(struct dhcpcd_ctx *ctx, const char *ifname, unsigned long cmd, 406 void *data, size_t len) 407 { 408 struct ifreq ifr = { .ifr_flags = 0 }; 409 410 #if defined(PRIVSEP) && (defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)) 411 if (IN_PRIVSEP(ctx)) 412 return (int)ps_root_indirectioctl(ctx, cmd, ifname, data, len); 413 #else 414 UNUSED(len); 415 #endif 416 417 strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 418 ifr.ifr_data = data; 419 return ioctl(ctx->pf_inet_fd, cmd, &ifr); 420 } 421 422 int 423 if_carrier(struct interface *ifp, const void *ifadata) 424 { 425 #ifdef LINK_STATE_UP 426 const struct if_data *ifi = ifadata; 427 428 /* 429 * Every BSD returns this and it is the sole source of truth. 430 * Not all BSD's support SIOCGIFDATA and not all interfaces 431 * support SIOCGIFMEDIA. 432 */ 433 assert(ifadata != NULL); 434 if (ifi->ifi_link_state >= LINK_STATE_UP) 435 return LINK_UP; 436 if (ifi->ifi_link_state == LINK_STATE_UNKNOWN) { 437 /* 438 * Work around net80211 issues in some BSDs. 439 * Wireless MUST support link state change. 440 */ 441 if (ifp->wireless) 442 return LINK_DOWN; 443 return LINK_UNKNOWN; 444 } 445 return LINK_DOWN; 446 #elif defined(SIOCGIFXMEDIA) 447 struct dhcpcd_ctx *ctx = ifp->ctx; 448 struct ifmediareq ifmr = { .ifm_active = 0 }; 449 450 UNUSED(ifadata); 451 strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); 452 if (ioctl(ctx->pf_inet_fd, SIOCGIFXMEDIA, &ifmr) == -1) 453 return LINK_UNKNOWN; 454 if (!(ifmr.ifm_status & IFM_AVALID)) 455 return LINK_UNKNOWN; 456 return ifmr.ifm_status & IFM_ACTIVE ? LINK_UP : LINK_DOWN; 457 #else 458 #warning OS does not report interface link state 459 UNUSED(ifp); 460 UNUSED(ifadata); 461 return LINK_UNKNOWN; 462 #endif 463 } 464 465 bool 466 if_roaming(struct interface *ifp) 467 { 468 /* Check for NetBSD as a safety measure. 469 * If other BSD's gain IN_IFF_TENTATIVE check they re-do DAD 470 * when the carrier comes up again. */ 471 #if defined(IN_IFF_TENTATIVE) && defined(__NetBSD__) 472 return ifp->flags & IFF_UP && ifp->carrier == LINK_DOWN; 473 #else 474 UNUSED(ifp); 475 return false; 476 #endif 477 } 478 479 static void 480 if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp) 481 { 482 memset(sdl, 0, sizeof(*sdl)); 483 sdl->sdl_family = AF_LINK; 484 sdl->sdl_len = sizeof(*sdl); 485 sdl->sdl_nlen = sdl->sdl_alen = sdl->sdl_slen = 0; 486 sdl->sdl_index = (unsigned short)ifp->index; 487 } 488 489 static int 490 if_getssid1(struct dhcpcd_ctx *ctx, const char *ifname, void *ssid) 491 { 492 int retval = -1; 493 #if defined(SIOCG80211NWID) 494 struct ieee80211_nwid nwid; 495 #elif defined(IEEE80211_IOC_SSID) 496 struct ieee80211req ireq; 497 char nwid[IEEE80211_NWID_LEN]; 498 #endif 499 500 #if defined(SIOCG80211NWID) /* NetBSD */ 501 memset(&nwid, 0, sizeof(nwid)); 502 if (if_indirect_ioctl(ctx, ifname, SIOCG80211NWID, &nwid, 503 sizeof(nwid)) == 0) { 504 if (ssid == NULL) 505 retval = nwid.i_len; 506 else if (nwid.i_len > IF_SSIDLEN) 507 errno = ENOBUFS; 508 else { 509 retval = nwid.i_len; 510 memcpy(ssid, nwid.i_nwid, nwid.i_len); 511 } 512 } 513 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */ 514 memset(&ireq, 0, sizeof(ireq)); 515 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name)); 516 ireq.i_type = IEEE80211_IOC_SSID; 517 ireq.i_val = -1; 518 memset(nwid, 0, sizeof(nwid)); 519 ireq.i_data = &nwid; 520 if (ioctl(ctx->pf_inet_fd, SIOCG80211, &ireq) == 0) { 521 if (ssid == NULL) 522 retval = ireq.i_len; 523 else if (ireq.i_len > IF_SSIDLEN) 524 errno = ENOBUFS; 525 else { 526 retval = ireq.i_len; 527 memcpy(ssid, nwid, ireq.i_len); 528 } 529 } 530 #else 531 #warning OS does not report interface SSID 532 UNUSED(ctx); 533 UNUSED(ifname); 534 UNUSED(ssid); 535 errno = ENOSYS; 536 #endif 537 538 return retval; 539 } 540 541 int 542 if_getssid(struct interface *ifp) 543 { 544 int r; 545 546 r = if_getssid1(ifp->ctx, ifp->name, ifp->ssid); 547 if (r != -1) 548 ifp->ssid_len = (unsigned int)r; 549 else 550 ifp->ssid_len = 0; 551 ifp->ssid[ifp->ssid_len] = '\0'; 552 return r; 553 } 554 555 /* 556 * FreeBSD allows for Virtual Access Points 557 * We need to check if the interface is a Virtual Interface Master 558 * and if so, don't use it. 559 * This check is made by virtue of being a IEEE80211 device but 560 * returning the SSID gives an error. 561 */ 562 int 563 if_vimaster(struct dhcpcd_ctx *ctx, const char *ifname) 564 { 565 int r; 566 struct ifmediareq ifmr = { .ifm_active = 0 }; 567 568 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 569 r = ioctl(ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr); 570 if (r == -1) 571 return -1; 572 if (ifmr.ifm_status & IFM_AVALID && 573 IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211) { 574 if (if_getssid1(ctx, ifname, NULL) == -1 && errno != ENOSYS) 575 return 1; 576 } 577 return 0; 578 } 579 580 unsigned short 581 if_vlanid(const struct interface *ifp) 582 { 583 #if defined(SIOCGETVLAN) 584 struct vlanreq vlr = { .vlr_tag = 0 }; 585 586 if (if_indirect_ioctl(ifp->ctx, ifp->name, SIOCGETVLAN, &vlr, 587 sizeof(vlr)) != 0) 588 return 0; /* 0 means no VLANID */ 589 return vlr.vlr_tag; 590 #elif defined(SIOCGVNETID) 591 struct ifreq ifr = { .ifr_vnetid = 0 }; 592 593 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 594 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0) 595 return 0; /* 0 means no VLANID */ 596 return ifr.ifr_vnetid; 597 #else 598 UNUSED(ifp); 599 return 0; /* 0 means no VLANID */ 600 #endif 601 } 602 603 static int 604 get_addrs(int type, const void *data, size_t data_len, 605 const struct sockaddr **sa) 606 { 607 const char *cp, *ep; 608 int i; 609 610 cp = data; 611 ep = cp + data_len; 612 for (i = 0; i < RTAX_MAX; i++) { 613 if (type & (1 << i)) { 614 if (cp >= ep) { 615 errno = EINVAL; 616 return -1; 617 } 618 sa[i] = (const struct sockaddr *)cp; 619 RT_ADVANCE(cp, sa[i]); 620 } else 621 sa[i] = NULL; 622 } 623 624 return 0; 625 } 626 627 static struct interface * 628 if_findsdl(struct dhcpcd_ctx *ctx, const struct sockaddr_dl *sdl) 629 { 630 if (sdl->sdl_index) 631 return if_findindex(ctx->ifaces, sdl->sdl_index); 632 633 if (sdl->sdl_nlen) { 634 char ifname[IF_NAMESIZE]; 635 636 memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen); 637 ifname[sdl->sdl_nlen] = '\0'; 638 return if_find(ctx->ifaces, ifname); 639 } 640 if (sdl->sdl_alen) { 641 struct interface *ifp; 642 643 TAILQ_FOREACH(ifp, ctx->ifaces, next) { 644 if (ifp->hwlen == sdl->sdl_alen && 645 memcmp(ifp->hwaddr, sdl->sdl_data, sdl->sdl_alen) == 646 0) 647 return ifp; 648 } 649 } 650 651 errno = ENOENT; 652 return NULL; 653 } 654 655 static struct interface * 656 if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa) 657 { 658 if (sa == NULL) { 659 errno = EINVAL; 660 return NULL; 661 } 662 663 switch (sa->sa_family) { 664 case AF_LINK: { 665 const struct sockaddr_dl *sdl; 666 667 sdl = (const void *)sa; 668 return if_findsdl(ctx, sdl); 669 } 670 #ifdef INET 671 case AF_INET: { 672 const struct sockaddr_in *sin; 673 struct ipv4_addr *ia; 674 675 sin = (const void *)sa; 676 if ((ia = ipv4_findmaskaddr(ctx, &sin->sin_addr))) 677 return ia->iface; 678 if ((ia = ipv4_findmaskbrd(ctx, &sin->sin_addr))) 679 return ia->iface; 680 break; 681 } 682 #endif 683 #ifdef INET6 684 case AF_INET6: { 685 const struct sockaddr_in6 *sin; 686 unsigned int scope; 687 struct ipv6_addr *ia; 688 689 sin = (const void *)sa; 690 scope = ipv6_getscope(sin); 691 if (scope != 0) 692 return if_findindex(ctx->ifaces, scope); 693 if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr))) 694 return ia->iface; 695 if ((ia = ipv6_finddstaddr(ctx, &sin->sin6_addr))) 696 return ia->iface; 697 break; 698 } 699 #endif 700 default: 701 errno = EAFNOSUPPORT; 702 return NULL; 703 } 704 705 errno = ENOENT; 706 return NULL; 707 } 708 709 static void 710 if_copysa(struct sockaddr *dst, const struct sockaddr *src) 711 { 712 assert(dst != NULL); 713 assert(src != NULL); 714 715 memcpy(dst, src, src->sa_len); 716 #if defined(INET6) && defined(__KAME__) 717 if (dst->sa_family == AF_INET6) { 718 struct in6_addr *in6; 719 720 in6 = &satosin6(dst)->sin6_addr; 721 if (IN6_IS_ADDR_LINKLOCAL(in6)) 722 in6->s6_addr[2] = in6->s6_addr[3] = '\0'; 723 } 724 #endif 725 } 726 727 int 728 if_route(unsigned char cmd, const struct rt *rt) 729 { 730 struct dhcpcd_ctx *ctx; 731 struct rtm rtmsg; 732 struct rt_msghdr *rtm = &rtmsg.hdr; 733 char *bp = rtmsg.buffer; 734 struct sockaddr_dl sdl; 735 bool gateway_unspec; 736 737 assert(rt != NULL); 738 assert(rt->rt_ifp != NULL); 739 assert(rt->rt_ifp->ctx != NULL); 740 ctx = rt->rt_ifp->ctx; 741 742 #define ADDSA(sa) \ 743 do { \ 744 memcpy(bp, (sa), (sa)->sa_len); \ 745 bp += RT_ROUNDUP((sa)->sa_len); \ 746 } while (0 /* CONSTCOND */) 747 748 memset(&rtmsg, 0, sizeof(rtmsg)); 749 rtm->rtm_version = RTM_VERSION; 750 rtm->rtm_type = cmd; 751 #ifdef __OpenBSD__ 752 rtm->rtm_pid = getpid(); 753 #endif 754 rtm->rtm_seq = ++ctx->seq; 755 rtm->rtm_flags = (int)rt->rt_flags; 756 rtm->rtm_addrs = RTA_DST; 757 #ifdef RTF_PINNED 758 if (cmd != RTM_ADD) 759 rtm->rtm_flags |= RTF_PINNED; 760 #endif 761 762 gateway_unspec = sa_is_unspecified(rt->rt_gateway); 763 764 if (cmd == RTM_ADD || cmd == RTM_CHANGE) { 765 bool netmask_bcast = sa_is_allones(rt->rt_netmask); 766 767 rtm->rtm_flags |= RTF_UP; 768 rtm->rtm_addrs |= RTA_GATEWAY; 769 if (!(rtm->rtm_flags & RTF_REJECT) && 770 !sa_is_loopback(rt->rt_gateway)) { 771 rtm->rtm_index = (unsigned short)rt->rt_ifp->index; 772 /* 773 * OpenBSD rejects this for on-link routes when there is no default route 774 * OpenBSD does not allow the same IPv6 address on different 775 * interfaces on the same network, so let's try to encourage someone to 776 * fix that by logging a waring during compile. 777 */ 778 #ifdef __OpenBSD__ 779 #warning kernel does not allow IPv6 address sharing 780 if (!gateway_unspec || 781 rt->rt_dest->sa_family != AF_INET6) 782 #endif 783 rtm->rtm_addrs |= RTA_IFP; 784 if (!sa_is_unspecified(rt->rt_ifa)) 785 rtm->rtm_addrs |= RTA_IFA; 786 } 787 if (netmask_bcast) 788 rtm->rtm_flags |= RTF_HOST; 789 /* Network routes are cloning or connected if supported. 790 * All other routes are static. */ 791 if (gateway_unspec && !(rtm->rtm_flags & RTF_REJECT)) { 792 #ifdef RTF_CLONING 793 rtm->rtm_flags |= RTF_CLONING; 794 #endif 795 #ifdef RTF_CONNECTED 796 rtm->rtm_flags |= RTF_CONNECTED; 797 #endif 798 #ifdef RTP_CONNECTED 799 rtm->rtm_priority = RTP_CONNECTED; 800 #endif 801 #ifdef RTF_CLONING 802 if (netmask_bcast) { 803 /* 804 * We add a cloning network route for a single 805 * host. Traffic to the host will generate a 806 * cloned route and the hardware address will 807 * resolve correctly. 808 * It might be more correct to use RTF_HOST 809 * instead of RTF_CLONING, and that does work, 810 * but some OS generate an arp warning 811 * diagnostic which we don't want to do. 812 */ 813 rtm->rtm_flags &= ~RTF_HOST; 814 } 815 #endif 816 } else 817 rtm->rtm_flags |= RTF_GATEWAY; 818 819 if (rt->rt_dflags & RTDF_STATIC) 820 rtm->rtm_flags |= RTF_STATIC; 821 822 if (rt->rt_mtu != 0) { 823 rtm->rtm_inits |= RTV_MTU; 824 rtm->rtm_rmx.rmx_mtu = rt->rt_mtu; 825 } 826 } 827 828 if (!(rtm->rtm_flags & RTF_HOST)) 829 rtm->rtm_addrs |= RTA_NETMASK; 830 831 if_linkaddr(&sdl, rt->rt_ifp); 832 833 ADDSA(rt->rt_dest); 834 835 if (rtm->rtm_addrs & RTA_GATEWAY) { 836 if (gateway_unspec) 837 ADDSA((struct sockaddr *)&sdl); 838 else { 839 struct sockaddr_storage gss; 840 struct sockaddr *gsa = (struct sockaddr *)&gss; 841 842 if_copysa(gsa, rt->rt_gateway); 843 #ifdef INET6 844 if (gss.ss_family == AF_INET6) 845 ipv6_setscope((struct sockaddr_in6 *)&gss, 846 rt->rt_ifp->index); 847 #endif 848 ADDSA(gsa); 849 } 850 } 851 852 if (rtm->rtm_addrs & RTA_NETMASK) 853 ADDSA(rt->rt_netmask); 854 855 if (rtm->rtm_addrs & RTA_IFP) 856 ADDSA((struct sockaddr *)&sdl); 857 858 if (rtm->rtm_addrs & RTA_IFA) 859 ADDSA(rt->rt_ifa); 860 861 #undef ADDSA 862 863 rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm); 864 865 #ifdef PRIVSEP 866 if (ctx->options & DHCPCD_PRIVSEP) { 867 if (ps_root_route(ctx, rtm, rtm->rtm_msglen) == -1) 868 return -1; 869 return 0; 870 } 871 #endif 872 if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1) 873 return -1; 874 return 0; 875 } 876 877 static bool 878 if_realroute(const struct rt_msghdr *rtm) 879 { 880 #ifdef RTF_CLONED 881 if (rtm->rtm_flags & RTF_CLONED) 882 return false; 883 #endif 884 #ifdef RTF_WASCLONED 885 if (rtm->rtm_flags & RTF_WASCLONED) 886 return false; 887 #endif 888 #ifdef RTF_LOCAL 889 if (rtm->rtm_flags & RTF_LOCAL) 890 return false; 891 #endif 892 #ifdef RTF_BROADCAST 893 if (rtm->rtm_flags & RTF_BROADCAST) 894 return false; 895 #endif 896 return true; 897 } 898 899 static int 900 if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm) 901 { 902 const struct sockaddr *rti_info[RTAX_MAX]; 903 904 if (!(rtm->rtm_addrs & RTA_DST)) { 905 errno = EINVAL; 906 return -1; 907 } 908 if (rtm->rtm_type != RTM_MISS && !(rtm->rtm_addrs & RTA_GATEWAY)) { 909 errno = EINVAL; 910 return -1; 911 } 912 913 if (get_addrs(rtm->rtm_addrs, (const char *)rtm + sizeof(*rtm), 914 rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1) 915 return -1; 916 917 rt_init(rt); 918 rt->rt_flags = (unsigned int)rtm->rtm_flags; 919 if_copysa(rt->rt_dest, rti_info[RTAX_DST]); 920 921 if (rtm->rtm_addrs & RTA_NETMASK) { 922 if_copysa(rt->rt_netmask, rti_info[RTAX_NETMASK]); 923 /* 924 * Netmask family and length are ignored by traditional 925 * userland tools such as route and netstat and are assumed 926 * to match the destination sockaddr. 927 * This is fortunate because BSD kernels use a radix tree 928 * to store routes which adjusts the netmask at the point 929 * of insertion where this information is lost. 930 * We can just sub in the values from the destination address. 931 * 932 * This is currently true for all BSD kernels. 933 */ 934 rt->rt_netmask->sa_family = rt->rt_dest->sa_family; 935 rt->rt_netmask->sa_len = rt->rt_dest->sa_len; 936 } 937 938 /* dhcpcd likes an unspecified gateway to indicate via the link. 939 * However we need to know if gateway was a link with an address. */ 940 if (rtm->rtm_addrs & RTA_GATEWAY) { 941 if (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) { 942 const struct sockaddr_dl *sdl; 943 944 sdl = (const struct sockaddr_dl *)(const void *) 945 rti_info[RTAX_GATEWAY]; 946 if (sdl->sdl_alen != 0) 947 rt->rt_dflags |= RTDF_GATELINK; 948 } else if (rtm->rtm_flags & RTF_GATEWAY) 949 if_copysa(rt->rt_gateway, rti_info[RTAX_GATEWAY]); 950 } 951 952 if (rtm->rtm_addrs & RTA_IFA) 953 if_copysa(rt->rt_ifa, rti_info[RTAX_IFA]); 954 955 rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu; 956 957 if (rtm->rtm_index) 958 rt->rt_ifp = if_findindex(ctx->ifaces, rtm->rtm_index); 959 else if (rtm->rtm_addrs & RTA_IFP) 960 rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_IFP]); 961 else if (rtm->rtm_addrs & RTA_GATEWAY) 962 rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_GATEWAY]); 963 else 964 rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_DST]); 965 966 if (rt->rt_ifp == NULL && rtm->rtm_type == RTM_MISS) 967 rt->rt_ifp = if_find(ctx->ifaces, "lo0"); 968 969 if (rt->rt_ifp == NULL) { 970 errno = ESRCH; 971 return -1; 972 } 973 return 0; 974 } 975 976 static int 977 if_sysctl(struct dhcpcd_ctx *ctx, int *name, u_int namelen, void *oldp, 978 size_t *oldlenp, void *newp, size_t newlen) 979 { 980 #if defined(PRIVSEP) && defined(HAVE_CAPSICUM) 981 if (IN_PRIVSEP(ctx)) 982 return (int)ps_root_sysctl(ctx, name, namelen, oldp, oldlenp, 983 newp, newlen); 984 #else 985 UNUSED(ctx); 986 #endif 987 988 return sysctl(name, namelen, oldp, oldlenp, newp, newlen); 989 } 990 991 int 992 if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af) 993 { 994 struct rt_msghdr *rtm; 995 int mib[6] = { CTL_NET, PF_ROUTE, 0, af, NET_RT_DUMP, 0 }; 996 size_t bufl; 997 char *buf = NULL, *p, *end; 998 struct rt rt, *rtn; 999 1000 again: 1001 if (if_sysctl(ctx, mib, __arraycount(mib), NULL, &bufl, NULL, 0) == -1) 1002 goto err; 1003 if (bufl == 0) { 1004 free(buf); 1005 return 0; 1006 } 1007 if ((p = realloc(buf, bufl)) == NULL) 1008 goto err; 1009 buf = p; 1010 if (if_sysctl(ctx, mib, __arraycount(mib), buf, &bufl, NULL, 0) == -1) { 1011 if (errno == ENOMEM) 1012 goto again; 1013 goto err; 1014 } 1015 1016 end = buf + bufl; 1017 for (p = buf; p < end; p += rtm->rtm_msglen) { 1018 rtm = (void *)p; 1019 if (p + sizeof(*rtm) > end || p + rtm->rtm_msglen > end) { 1020 errno = EINVAL; 1021 break; 1022 } 1023 if (!if_realroute(rtm)) 1024 continue; 1025 if (if_copyrt(ctx, &rt, rtm) != 0) 1026 continue; 1027 if ((rtn = rt_new(rt.rt_ifp)) == NULL) { 1028 logerr(__func__); 1029 break; 1030 } 1031 rt_copy(rtn, &rt); 1032 if (rb_tree_insert_node(kroutes, rtn) != rtn) 1033 rt_free(rtn); 1034 } 1035 free(buf); 1036 return p == end ? 0 : -1; 1037 1038 err: 1039 free(buf); 1040 return -1; 1041 } 1042 1043 #ifdef INET 1044 int 1045 if_address(unsigned char cmd, const struct ipv4_addr *ia) 1046 { 1047 int r; 1048 struct in_aliasreq ifra; 1049 struct dhcpcd_ctx *ctx = ia->iface->ctx; 1050 1051 memset(&ifra, 0, sizeof(ifra)); 1052 strlcpy(ifra.ifra_name, ia->iface->name, sizeof(ifra.ifra_name)); 1053 1054 #define ADDADDR(var, addr) \ 1055 do { \ 1056 (var)->sin_family = AF_INET; \ 1057 (var)->sin_len = sizeof(*(var)); \ 1058 (var)->sin_addr = *(addr); \ 1059 } while (/*CONSTCOND*/ 0) 1060 ADDADDR(&ifra.ifra_addr, &ia->addr); 1061 ADDADDR(&ifra.ifra_mask, &ia->mask); 1062 if (cmd == RTM_NEWADDR && ia->brd.s_addr != INADDR_ANY) 1063 ADDADDR(&ifra.ifra_broadaddr, &ia->brd); 1064 #undef ADDADDR 1065 1066 r = if_ioctl(ctx, cmd == RTM_DELADDR ? SIOCDIFADDR : SIOCAIFADDR, &ifra, 1067 sizeof(ifra)); 1068 return r; 1069 } 1070 1071 #if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS)) 1072 int 1073 if_addrflags(const struct interface *ifp, const struct in_addr *addr, 1074 __unused const char *alias) 1075 { 1076 #ifdef SIOCGIFAFLAG_IN 1077 struct ifreq ifr; 1078 struct sockaddr_in *sin; 1079 1080 memset(&ifr, 0, sizeof(ifr)); 1081 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1082 sin = (void *)&ifr.ifr_addr; 1083 sin->sin_family = AF_INET; 1084 sin->sin_addr = *addr; 1085 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFAFLAG_IN, &ifr) == -1) 1086 return -1; 1087 return ifr.ifr_addrflags; 1088 #else 1089 UNUSED(ifp); 1090 UNUSED(addr); 1091 return 0; 1092 #endif 1093 } 1094 #endif 1095 #endif /* INET */ 1096 1097 #ifdef INET6 1098 static int 1099 if_ioctl6(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len) 1100 { 1101 struct priv *priv; 1102 1103 #ifdef PRIVSEP 1104 if (ctx->options & DHCPCD_PRIVSEP) 1105 return (int)ps_root_ioctl6(ctx, req, data, len); 1106 #endif 1107 1108 priv = ctx->priv; 1109 return ioctl(priv->pf_inet6_fd, req, data, len); 1110 } 1111 1112 int 1113 if_address6(unsigned char cmd, const struct ipv6_addr *ia) 1114 { 1115 struct in6_aliasreq ifa = { .ifra_flags = 0 }; 1116 struct in6_addr mask; 1117 struct dhcpcd_ctx *ctx = ia->iface->ctx; 1118 1119 strlcpy(ifa.ifra_name, ia->iface->name, sizeof(ifa.ifra_name)); 1120 #if defined(__FreeBSD__) || defined(__DragonFly__) 1121 /* This is a bug - the kernel should work this out. */ 1122 if (ia->addr_flags & IN6_IFF_TENTATIVE) 1123 ifa.ifra_flags |= IN6_IFF_TENTATIVE; 1124 #endif 1125 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && \ 1126 (defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV)) 1127 /* These kernels don't accept userland setting IN6_IFF_AUTOCONF */ 1128 #else 1129 if (ia->flags & IPV6_AF_AUTOCONF) 1130 ifa.ifra_flags |= IN6_IFF_AUTOCONF; 1131 #endif 1132 #ifdef IPV6_MANAGETEMPADDR 1133 if (ia->flags & IPV6_AF_TEMPORARY) 1134 ifa.ifra_flags |= IN6_IFF_TEMPORARY; 1135 #endif 1136 1137 #define ADDADDR(v, addr) \ 1138 { \ 1139 (v)->sin6_family = AF_INET6; \ 1140 (v)->sin6_len = sizeof(*v); \ 1141 (v)->sin6_addr = *(addr); \ 1142 } 1143 1144 ADDADDR(&ifa.ifra_addr, &ia->addr); 1145 ipv6_setscope(&ifa.ifra_addr, ia->iface->index); 1146 ipv6_mask(&mask, ia->prefix_len); 1147 ADDADDR(&ifa.ifra_prefixmask, &mask); 1148 1149 #undef ADDADDR 1150 1151 /* 1152 * Every BSD kernel wants to add the prefix of the address to it's 1153 * list of RA received prefixes. 1154 * THIS IS WRONG because there (as the comments in the kernel state) 1155 * is no API for managing prefix lifetime and the kernel should not 1156 * pretend it's from a RA either. 1157 * 1158 * The issue is that the very first assigned prefix will inherit the 1159 * lifetime of the address, but any subsequent alteration of the 1160 * address OR it's lifetime will not affect the prefix lifetime. 1161 * As such, we cannot stop the prefix from timing out and then 1162 * constantly removing the prefix route dhcpcd is capable of adding 1163 * in it's absense. 1164 * 1165 * What we can do to mitigate the issue is to add the address with 1166 * infinite lifetimes, so the prefix route will never time out. 1167 * Once done, we can then set lifetimes on the address and all is good. 1168 * The downside of this approach is that we need to manually remove 1169 * the kernel route because it has no lifetime, but this is OK as 1170 * dhcpcd will handle this too. 1171 * 1172 * This issue is discussed on the NetBSD mailing lists here: 1173 * http://mail-index.netbsd.org/tech-net/2016/08/05/msg006044.html 1174 * 1175 * Fixed in NetBSD-7.99.36 1176 * NOT fixed in FreeBSD - bug 195197 1177 * Fixed in OpenBSD-5.9 1178 */ 1179 1180 #if !((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003600) || \ 1181 (defined(__OpenBSD__) && OpenBSD >= 201605)) 1182 if (cmd == RTM_NEWADDR && !(ia->flags & IPV6_AF_ADDED)) { 1183 ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 1184 ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 1185 (void)if_ioctl6(ctx, SIOCAIFADDR_IN6, &ifa, sizeof(ifa)); 1186 } 1187 #endif 1188 1189 #if defined(__OpenBSD__) && OpenBSD <= 201705 1190 /* BUT OpenBSD older than 6.2 does not reset the address lifetime 1191 * for subsequent calls... 1192 * Luckily dhcpcd will remove the lease when it expires so 1193 * just set an infinite lifetime, unless a temporary address. */ 1194 if (ifa.ifra_flags & IN6_IFF_PRIVACY) { 1195 ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime; 1196 ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime; 1197 } else { 1198 ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 1199 ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 1200 } 1201 #else 1202 ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime; 1203 ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime; 1204 #endif 1205 1206 return if_ioctl6(ctx, 1207 cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa, 1208 sizeof(ifa)); 1209 } 1210 1211 int 1212 if_addrflags6(const struct interface *ifp, const struct in6_addr *addr, 1213 __unused const char *alias) 1214 { 1215 int flags; 1216 struct in6_ifreq ifr6; 1217 struct priv *priv; 1218 1219 memset(&ifr6, 0, sizeof(ifr6)); 1220 strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name)); 1221 ifr6.ifr_addr.sin6_family = AF_INET6; 1222 ifr6.ifr_addr.sin6_addr = *addr; 1223 ipv6_setscope(&ifr6.ifr_addr, ifp->index); 1224 priv = (struct priv *)ifp->ctx->priv; 1225 if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) 1226 flags = ifr6.ifr_ifru.ifru_flags6; 1227 else 1228 flags = -1; 1229 return flags; 1230 } 1231 1232 int 1233 if_getlifetime6(struct ipv6_addr *ia) 1234 { 1235 struct in6_ifreq ifr6; 1236 time_t t; 1237 struct in6_addrlifetime *lifetime; 1238 struct priv *priv; 1239 1240 memset(&ifr6, 0, sizeof(ifr6)); 1241 strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name)); 1242 ifr6.ifr_addr.sin6_family = AF_INET6; 1243 ifr6.ifr_addr.sin6_addr = ia->addr; 1244 ipv6_setscope(&ifr6.ifr_addr, ia->iface->index); 1245 priv = (struct priv *)ia->iface->ctx->priv; 1246 if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1) 1247 return -1; 1248 clock_gettime(CLOCK_MONOTONIC, &ia->created); 1249 1250 #if defined(__FreeBSD__) || defined(__DragonFly__) 1251 t = ia->created.tv_sec; 1252 #else 1253 t = time(NULL); 1254 #endif 1255 1256 lifetime = &ifr6.ifr_ifru.ifru_lifetime; 1257 if (lifetime->ia6t_preferred) 1258 ia->prefix_pltime = (uint32_t)(lifetime->ia6t_preferred - 1259 MIN(t, lifetime->ia6t_preferred)); 1260 else 1261 ia->prefix_pltime = ND6_INFINITE_LIFETIME; 1262 if (lifetime->ia6t_expire) { 1263 ia->prefix_vltime = (uint32_t)(lifetime->ia6t_expire - 1264 MIN(t, lifetime->ia6t_expire)); 1265 /* Calculate the created time */ 1266 ia->created.tv_sec -= lifetime->ia6t_vltime - ia->prefix_vltime; 1267 } else 1268 ia->prefix_vltime = ND6_INFINITE_LIFETIME; 1269 return 0; 1270 } 1271 #endif 1272 1273 #ifdef IFAN_ARRIVAL 1274 static int 1275 if_announce(struct dhcpcd_ctx *ctx, const struct if_announcemsghdr *ifan) 1276 { 1277 if (ifan->ifan_msglen < sizeof(*ifan)) { 1278 errno = EINVAL; 1279 return -1; 1280 } 1281 1282 switch (ifan->ifan_what) { 1283 case IFAN_ARRIVAL: 1284 return dhcpcd_handleinterface(ctx, 1, ifan->ifan_name); 1285 case IFAN_DEPARTURE: 1286 return dhcpcd_handleinterface(ctx, -1, ifan->ifan_name); 1287 } 1288 1289 return 0; 1290 } 1291 #endif 1292 1293 static int 1294 if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) 1295 { 1296 struct interface *ifp; 1297 int link_state; 1298 1299 if (ifm->ifm_msglen < sizeof(*ifm)) { 1300 errno = EINVAL; 1301 return -1; 1302 } 1303 1304 if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL) 1305 return 0; 1306 1307 ifp->mtu = if_getmtu(ifp); 1308 link_state = if_carrier(ifp, &ifm->ifm_data); 1309 dhcpcd_handlecarrier(ifp, link_state, (unsigned int)ifm->ifm_flags); 1310 return 0; 1311 } 1312 1313 static int 1314 if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) 1315 { 1316 struct rt rt; 1317 1318 if (rtm->rtm_msglen < sizeof(*rtm)) { 1319 errno = EINVAL; 1320 return -1; 1321 } 1322 1323 /* Ignore errors. */ 1324 if (rtm->rtm_errno != 0) 1325 return 0; 1326 1327 /* Ignore messages from ourself. */ 1328 #ifdef PRIVSEP 1329 if (ctx->ps_root != NULL) { 1330 if (rtm->rtm_pid == ctx->ps_root->psp_pid) 1331 return 0; 1332 } 1333 #endif 1334 1335 if (if_copyrt(ctx, &rt, rtm) == -1) 1336 return errno == ENOTSUP ? 0 : -1; 1337 1338 #ifdef INET6 1339 /* 1340 * BSD announces host routes. 1341 * As such, we should be notified of reachability by its 1342 * existance with a hardware address. 1343 * Ensure we don't call this for a newly incomplete state. 1344 */ 1345 if (rt.rt_dest->sa_family == AF_INET6 && 1346 (rt.rt_flags & RTF_HOST || rtm->rtm_type == RTM_MISS) && 1347 !(rtm->rtm_type == RTM_ADD && !(rt.rt_dflags & RTDF_GATELINK))) { 1348 bool reachable; 1349 struct sockaddr_in6 *dest = 1350 (struct sockaddr_in6 *)&rt.rt_ss_dest; 1351 1352 reachable = (rtm->rtm_type == RTM_ADD || 1353 rtm->rtm_type == RTM_CHANGE) && 1354 rt.rt_dflags & RTDF_GATELINK; 1355 ipv6nd_neighbour(ctx, &dest->sin6_addr, reachable); 1356 } 1357 #endif 1358 1359 if (rtm->rtm_type != RTM_MISS && if_realroute(rtm)) 1360 rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid); 1361 return 0; 1362 } 1363 1364 static int 1365 if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) 1366 { 1367 struct interface *ifp; 1368 const struct sockaddr *rti_info[RTAX_MAX]; 1369 int flags; 1370 pid_t pid; 1371 1372 if (ifam->ifam_msglen < sizeof(*ifam)) { 1373 errno = EINVAL; 1374 return -1; 1375 } 1376 1377 #ifdef HAVE_IFAM_PID 1378 /* Ignore address deletions from ourself. 1379 * We need to process address flag changes though. */ 1380 if (ifam->ifam_type == RTM_DELADDR) { 1381 #ifdef PRIVSEP 1382 if (ctx->ps_root != NULL) { 1383 if (ifam->ifam_pid == ctx->ps_root->psp_pid) 1384 return 0; 1385 } else 1386 #endif 1387 /* address management is done via ioctl, 1388 * so SO_USELOOPBACK has no effect, 1389 * so we do need to check the pid. */ 1390 if (ifam->ifam_pid == getpid()) 1391 return 0; 1392 } 1393 pid = ifam->ifam_pid; 1394 #else 1395 pid = 0; 1396 #endif 1397 1398 if (~ifam->ifam_addrs & RTA_IFA) 1399 return 0; 1400 if ((ifp = if_findindex(ctx->ifaces, ifam->ifam_index)) == NULL) 1401 return 0; 1402 1403 if (get_addrs(ifam->ifam_addrs, (const char *)ifam + sizeof(*ifam), 1404 ifam->ifam_msglen - sizeof(*ifam), rti_info) == -1) 1405 return -1; 1406 1407 /* All BSD's set IFF_UP on the interface when adding an address. 1408 * But not all BSD's emit this via RTM_IFINFO when they do this ... */ 1409 if (ifam->ifam_type == RTM_NEWADDR && !(ifp->flags & IFF_UP)) { 1410 struct ifreq ifr = { .ifr_flags = 0 }; 1411 1412 /* Don't blindly assume the interface is up though. 1413 * We might get the address via a state change. */ 1414 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1415 if (ioctl(ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1) 1416 return -1; 1417 if (ifr.ifr_flags & IFF_UP) 1418 dhcpcd_handlecarrier(ifp, ifp->carrier, 1419 ifp->flags | IFF_UP); 1420 } 1421 1422 switch (rti_info[RTAX_IFA]->sa_family) { 1423 case AF_LINK: { 1424 struct sockaddr_dl sdl; 1425 1426 #ifdef RTM_CHGADDR 1427 if (ifam->ifam_type != RTM_CHGADDR) 1428 break; 1429 #else 1430 if (ifam->ifam_type != RTM_NEWADDR) 1431 break; 1432 #endif 1433 memcpy(&sdl, rti_info[RTAX_IFA], rti_info[RTAX_IFA]->sa_len); 1434 dhcpcd_handlehwaddr(ifp, ifp->hwtype, CLLADDR(&sdl), 1435 sdl.sdl_alen); 1436 break; 1437 } 1438 #ifdef INET 1439 case AF_INET: 1440 case 255: /* FIXME: Why 255? */ 1441 { 1442 const struct sockaddr_in *sin; 1443 struct in_addr addr, mask, bcast; 1444 1445 sin = (const void *)rti_info[RTAX_IFA]; 1446 addr.s_addr = sin != NULL && sin->sin_family == AF_INET ? 1447 sin->sin_addr.s_addr : 1448 INADDR_ANY; 1449 sin = (const void *)rti_info[RTAX_NETMASK]; 1450 mask.s_addr = sin != NULL && sin->sin_family == AF_INET ? 1451 sin->sin_addr.s_addr : 1452 INADDR_ANY; 1453 sin = (const void *)rti_info[RTAX_BRD]; 1454 bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ? 1455 sin->sin_addr.s_addr : 1456 INADDR_ANY; 1457 1458 /* 1459 * NetBSD-7 and older send an invalid broadcast address. 1460 * So we need to query the actual address to get 1461 * the right one. 1462 * We can also use this to test if the address 1463 * has really been added or deleted. 1464 */ 1465 #ifdef SIOCGIFALIAS 1466 struct in_aliasreq ifra; 1467 1468 memset(&ifra, 0, sizeof(ifra)); 1469 strlcpy(ifra.ifra_name, ifp->name, sizeof(ifra.ifra_name)); 1470 ifra.ifra_addr.sin_family = AF_INET; 1471 ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr); 1472 ifra.ifra_addr.sin_addr = addr; 1473 if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) { 1474 if (errno != ENXIO && errno != EADDRNOTAVAIL) 1475 logerr("%s: SIOCGIFALIAS", __func__); 1476 if (ifam->ifam_type != RTM_DELADDR) 1477 break; 1478 } else { 1479 if (ifam->ifam_type == RTM_DELADDR) 1480 break; 1481 #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000 1482 bcast = ifra.ifra_broadaddr.sin_addr; 1483 #endif 1484 } 1485 #else 1486 #warning No SIOCGIFALIAS support 1487 /* 1488 * No SIOCGIFALIAS? That sucks! 1489 * This makes this call very heavy weight, but we 1490 * really need to know if the message is late or not. 1491 */ 1492 const struct sockaddr *sa; 1493 struct ifaddrs *ifaddrs = NULL, *ifa; 1494 1495 sa = rti_info[RTAX_IFA]; 1496 #ifdef PRIVSEP_GETIFADDRS 1497 if (IN_PRIVSEP(ctx)) { 1498 if (ps_root_getifaddrs(ctx, &ifaddrs) == -1) { 1499 logerr("ps_root_getifaddrs"); 1500 break; 1501 } 1502 } else 1503 #endif 1504 if (getifaddrs(&ifaddrs) == -1) { 1505 logerr("getifaddrs"); 1506 break; 1507 } 1508 for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { 1509 if (ifa->ifa_addr == NULL) 1510 continue; 1511 if (sa_cmp(ifa->ifa_addr, sa) == 0 && 1512 strcmp(ifa->ifa_name, ifp->name) == 0) 1513 break; 1514 } 1515 #ifdef PRIVSEP_GETIFADDRS 1516 if (IN_PRIVSEP(ctx)) 1517 free(ifaddrs); 1518 else 1519 #endif 1520 freeifaddrs(ifaddrs); 1521 if (ifam->ifam_type == RTM_DELADDR) { 1522 if (ifa != NULL) 1523 break; 1524 } else { 1525 if (ifa == NULL) 1526 break; 1527 } 1528 #endif 1529 1530 #ifdef HAVE_IFAM_ADDRFLAGS 1531 flags = ifam->ifam_addrflags; 1532 #else 1533 flags = 0; 1534 #endif 1535 1536 ipv4_handleifa(ctx, ifam->ifam_type, NULL, ifp->name, &addr, 1537 &mask, &bcast, flags, pid); 1538 break; 1539 } 1540 #endif 1541 #ifdef INET6 1542 case AF_INET6: { 1543 struct in6_addr addr6, mask6; 1544 const struct in6_addr *dstaddr6; 1545 const struct sockaddr_in6 *sin6; 1546 1547 sin6 = (const void *)rti_info[RTAX_IFA]; 1548 addr6 = sin6->sin6_addr; 1549 sin6 = (const void *)rti_info[RTAX_NETMASK]; 1550 mask6 = sin6->sin6_addr; 1551 sin6 = (const void *)rti_info[RTAX_BRD]; 1552 dstaddr6 = sin6 ? &sin6->sin6_addr : NULL; 1553 1554 /* 1555 * If the address was deleted, lets check if it's 1556 * a late message and it still exists (maybe modified). 1557 * If so, ignore it as deleting an address causes 1558 * dhcpcd to drop any lease to which it belongs. 1559 * Also check an added address was really added. 1560 */ 1561 flags = if_addrflags6(ifp, &addr6, NULL); 1562 if (flags == -1) { 1563 if (errno != ENXIO && errno != EADDRNOTAVAIL) 1564 logerr("%s: if_addrflags6", __func__); 1565 if (ifam->ifam_type != RTM_DELADDR) 1566 break; 1567 flags = 0; 1568 } else if (ifam->ifam_type == RTM_DELADDR) 1569 break; 1570 1571 #ifdef __KAME__ 1572 if (IN6_IS_ADDR_LINKLOCAL(&addr6)) 1573 /* Remove the scope from the address */ 1574 addr6.s6_addr[2] = addr6.s6_addr[3] = '\0'; 1575 #endif 1576 1577 ipv6_handleifa(ctx, ifam->ifam_type, NULL, ifp->name, &addr6, 1578 ipv6_prefixlen(&mask6), dstaddr6, flags, pid); 1579 break; 1580 } 1581 #endif 1582 } 1583 1584 return 0; 1585 } 1586 1587 static int 1588 if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) 1589 { 1590 if (rtm->rtm_version != RTM_VERSION) 1591 return 0; 1592 1593 switch (rtm->rtm_type) { 1594 #ifdef RTM_IFANNOUNCE 1595 case RTM_IFANNOUNCE: 1596 return if_announce(ctx, (const void *)rtm); 1597 #endif 1598 case RTM_IFINFO: 1599 return if_ifinfo(ctx, (const void *)rtm); 1600 case RTM_ADD: /* FALLTHROUGH */ 1601 case RTM_CHANGE: /* FALLTHROUGH */ 1602 case RTM_DELETE: /* FALLTHROUGH */ 1603 case RTM_MISS: 1604 return if_rtm(ctx, (const void *)rtm); 1605 #ifdef RTM_CHGADDR 1606 case RTM_CHGADDR: /* FALLTHROUGH */ 1607 #endif 1608 case RTM_DELADDR: /* FALLTHROUGH */ 1609 case RTM_NEWADDR: 1610 return if_ifa(ctx, (const void *)rtm); 1611 #ifdef RTM_DESYNC 1612 case RTM_DESYNC: 1613 dhcpcd_linkoverflow(ctx); 1614 #elif !defined(SO_RERROR) 1615 #warning cannot detect route socket overflow within kernel 1616 #endif 1617 } 1618 1619 return 0; 1620 } 1621 1622 static int 1623 if_missfilter0(struct dhcpcd_ctx *ctx, struct interface *ifp, 1624 struct sockaddr *sa) 1625 { 1626 size_t salen = (size_t)RT_ROUNDUP(sa->sa_len); 1627 size_t newlen = ctx->rt_missfilterlen + salen; 1628 size_t diff = salen - (sa->sa_len); 1629 uint8_t *cp; 1630 1631 if (ctx->rt_missfiltersize < newlen) { 1632 void *n = realloc(ctx->rt_missfilter, newlen); 1633 if (n == NULL) 1634 return -1; 1635 ctx->rt_missfilter = n; 1636 ctx->rt_missfiltersize = newlen; 1637 } 1638 1639 #ifdef INET6 1640 if (sa->sa_family == AF_INET6) 1641 ipv6_setscope(satosin6(sa), ifp->index); 1642 #else 1643 UNUSED(ifp); 1644 #endif 1645 1646 cp = ctx->rt_missfilter + ctx->rt_missfilterlen; 1647 memcpy(cp, sa, sa->sa_len); 1648 if (diff != 0) 1649 memset(cp + sa->sa_len, 0, diff); 1650 ctx->rt_missfilterlen += salen; 1651 1652 #ifdef INET6 1653 if (sa->sa_family == AF_INET6) 1654 ipv6_setscope(satosin6(sa), 0); 1655 #endif 1656 1657 return 0; 1658 } 1659 1660 int 1661 if_missfilter(struct interface *ifp, struct sockaddr *sa) 1662 { 1663 return if_missfilter0(ifp->ctx, ifp, sa); 1664 } 1665 1666 int 1667 if_missfilter_apply(struct dhcpcd_ctx *ctx) 1668 { 1669 #ifdef RO_MISSFILTER 1670 if (ctx->rt_missfilterlen == 0) { 1671 struct sockaddr sa = { 1672 .sa_family = AF_UNSPEC, 1673 .sa_len = sizeof(sa), 1674 }; 1675 1676 if (if_missfilter0(ctx, NULL, &sa) == -1) 1677 return -1; 1678 } 1679 1680 return setsockopt(ctx->link_fd, PF_ROUTE, RO_MISSFILTER, 1681 ctx->rt_missfilter, (socklen_t)ctx->rt_missfilterlen); 1682 #else 1683 #warning kernel does not support RTM_MISS DST filtering 1684 UNUSED(ctx); 1685 errno = ENOTSUP; 1686 return -1; 1687 #endif 1688 } 1689 1690 __CTASSERT(offsetof(struct rt_msghdr, rtm_msglen) == 0); 1691 int 1692 if_handlelink(struct dhcpcd_ctx *ctx) 1693 { 1694 struct rtm rtm; 1695 ssize_t len; 1696 1697 len = read(ctx->link_fd, &rtm, sizeof(rtm)); 1698 if (len == -1) 1699 return -1; 1700 if (len == 0) 1701 return 0; 1702 if ((size_t)len < sizeof(rtm.hdr.rtm_msglen) || 1703 len != rtm.hdr.rtm_msglen) { 1704 errno = EINVAL; 1705 return -1; 1706 } 1707 /* 1708 * Coverity thinks that the data could be tainted from here. 1709 * I have no idea how because the length of the data we read 1710 * is guarded by len and checked to match rtm_msglen. 1711 * The issue seems to be related to extracting the addresses 1712 * at the end of the header, but seems to have no issues with the 1713 * equivalent call in if_initrt. 1714 */ 1715 /* coverity[tainted_data] */ 1716 return if_dispatch(ctx, &rtm.hdr); 1717 } 1718 1719 #ifndef SYS_NMLN /* OSX */ 1720 #define SYS_NMLN __SYS_NAMELEN 1721 #endif 1722 #ifndef HW_MACHINE_ARCH 1723 #ifdef HW_MODEL /* OpenBSD */ 1724 #define HW_MACHINE_ARCH HW_MODEL 1725 #endif 1726 #endif 1727 int 1728 if_machinearch(char *str, size_t len) 1729 { 1730 int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1731 1732 return sysctl(mib, sizeof(mib) / sizeof(mib[0]), str, &len, NULL, 0); 1733 } 1734 1735 #ifdef INET6 1736 #if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) 1737 #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0) 1738 #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1) 1739 static int 1740 inet6_sysctl(int code, int val, int action) 1741 { 1742 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 1743 size_t size; 1744 1745 mib[3] = code; 1746 size = sizeof(val); 1747 if (action) { 1748 if (sysctl(mib, __arraycount(mib), NULL, 0, &val, size) == -1) 1749 return -1; 1750 return 0; 1751 } 1752 if (sysctl(mib, __arraycount(mib), &val, &size, NULL, 0) == -1) 1753 return -1; 1754 return val; 1755 } 1756 #endif 1757 1758 int 1759 if_applyra(const struct ra *rap) 1760 { 1761 #ifdef SIOCSIFINFO_IN6 1762 struct in6_ndireq nd = { .ndi.chlim = 0 }; 1763 struct dhcpcd_ctx *ctx = rap->iface->ctx; 1764 int error; 1765 1766 strlcpy(nd.ifname, rap->iface->name, sizeof(nd.ifname)); 1767 1768 #ifdef IPV6CTL_ACCEPT_RTADV 1769 struct priv *priv = ctx->priv; 1770 1771 /* 1772 * NetBSD changed SIOCSIFINFO_IN6 to NOT set flags when kernel 1773 * RA was removed, however both FreeBSD and DragonFlyBSD still do. 1774 * linkmtu was also removed. 1775 * Hopefully this guard will still work if either remove kernel RA. 1776 */ 1777 if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &nd, sizeof(nd)) == -1) 1778 return -1; 1779 1780 nd.ndi.linkmtu = rap->mtu; 1781 #endif 1782 1783 nd.ndi.chlim = rap->hoplimit; 1784 nd.ndi.retrans = rap->retrans; 1785 nd.ndi.basereachable = rap->reachable; 1786 error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd)); 1787 #ifdef IPV6CTL_ACCEPT_RTADV 1788 if (error == -1 && errno == EINVAL) { 1789 /* 1790 * Very likely that this is caused by a dodgy MTU 1791 * setting specific to the interface. 1792 * Let's set it to "unspecified" and try again. 1793 * Doesn't really matter as we fix the MTU against the 1794 * routes we add as not all OS support SIOCSIFINFO_IN6. 1795 */ 1796 nd.ndi.linkmtu = 0; 1797 error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd)); 1798 } 1799 #endif 1800 return error; 1801 #else 1802 #warning OS does not allow setting of RA bits hoplimit, retrans or reachable 1803 UNUSED(rap); 1804 return 0; 1805 #endif 1806 } 1807 1808 #ifdef SIOCIFAFATTACH 1809 static int 1810 if_af_attach(const struct interface *ifp, int af) 1811 { 1812 struct if_afreq ifar = { .ifar_af = af }; 1813 1814 strlcpy(ifar.ifar_name, ifp->name, sizeof(ifar.ifar_name)); 1815 return if_ioctl6(ifp->ctx, SIOCIFAFATTACH, &ifar, sizeof(ifar)); 1816 } 1817 #endif 1818 1819 #ifdef SIOCGIFXFLAGS 1820 static int 1821 if_set_ifxflags(const struct interface *ifp) 1822 { 1823 struct ifreq ifr; 1824 int flags; 1825 struct priv *priv = ifp->ctx->priv; 1826 1827 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1828 if (ioctl(priv->pf_inet6_fd, SIOCGIFXFLAGS, &ifr) == -1) 1829 return -1; 1830 flags = ifr.ifr_flags; 1831 #ifdef IFXF_NOINET6 1832 flags &= ~IFXF_NOINET6; 1833 #endif 1834 /* 1835 * If not doing autoconf, don't disable the kernel from doing it. 1836 * If we need to, we should have another option actively disable it. 1837 * 1838 * OpenBSD moved from kernel based SLAAC to userland via slaacd(8). 1839 * It has a similar featureset to dhcpcd such as stable private 1840 * addresses, but lacks the ability to handle DNS inside the RA 1841 * which is a serious shortfall in this day and age. 1842 * Appease their user base by working alongside slaacd(8) if 1843 * dhcpcd is instructed not to do auto configuration of addresses. 1844 */ 1845 #if defined(ND6_IFF_ACCEPT_RTADV) 1846 #define BSD_AUTOCONF DHCPCD_IPV6RS 1847 #else 1848 #define BSD_AUTOCONF DHCPCD_IPV6RA_AUTOCONF 1849 #endif 1850 if (ifp->options->options & BSD_AUTOCONF) 1851 flags &= ~IFXF_AUTOCONF6; 1852 if (ifr.ifr_flags == flags) 1853 return 0; 1854 ifr.ifr_flags = flags; 1855 return if_ioctl6(ifp->ctx, SIOCSIFXFLAGS, &ifr, sizeof(ifr)); 1856 } 1857 #endif 1858 1859 /* OpenBSD removed ND6 flags entirely, so we need to check for their 1860 * existance. */ 1861 #if defined(ND6_IFF_AUTO_LINKLOCAL) || defined(ND6_IFF_PERFORMNUD) || \ 1862 defined(ND6_IFF_ACCEPT_RTADV) || defined(ND6_IFF_OVERRIDE_RTADV) || \ 1863 defined(ND6_IFF_IFDISABLED) 1864 #define ND6_NDI_FLAGS 1865 #endif 1866 1867 void 1868 if_disable_rtadv(void) 1869 { 1870 #if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV) 1871 int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV); 1872 1873 if (ra == -1) { 1874 if (errno != ENOENT) 1875 logerr("IPV6CTL_ACCEPT_RTADV"); 1876 else if (ra != 0) 1877 if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) 1878 logerr("IPV6CTL_ACCEPT_RTADV"); 1879 } 1880 #endif 1881 } 1882 1883 void 1884 if_setup_inet6(const struct interface *ifp) 1885 { 1886 #ifdef ND6_NDI_FLAGS 1887 struct priv *priv; 1888 int s; 1889 struct in6_ndireq nd; 1890 int flags; 1891 1892 priv = (struct priv *)ifp->ctx->priv; 1893 s = priv->pf_inet6_fd; 1894 1895 memset(&nd, 0, sizeof(nd)); 1896 strlcpy(nd.ifname, ifp->name, sizeof(nd.ifname)); 1897 if (ioctl(s, SIOCGIFINFO_IN6, &nd) == -1) 1898 logerr("%s: SIOCGIFINFO_FLAGS", ifp->name); 1899 flags = (int)nd.ndi.flags; 1900 1901 #ifdef ND6_IFF_AUTO_LINKLOCAL 1902 /* Unlike the kernel, dhcpcd make make a stable private address. */ 1903 flags &= ~ND6_IFF_AUTO_LINKLOCAL; 1904 #endif 1905 1906 #ifdef ND6_IFF_PERFORMNUD 1907 /* NUD is kind of essential. */ 1908 flags |= ND6_IFF_PERFORMNUD; 1909 #endif 1910 1911 #ifdef ND6_IFF_IFDISABLED 1912 /* Ensure the interface is not disabled. */ 1913 flags &= ~ND6_IFF_IFDISABLED; 1914 #endif 1915 1916 /* 1917 * If not doing autoconf, don't disable the kernel from doing it. 1918 * If we need to, we should have another option actively disable it. 1919 */ 1920 #ifdef ND6_IFF_ACCEPT_RTADV 1921 if (ifp->options->options & DHCPCD_IPV6RS) 1922 flags &= ~ND6_IFF_ACCEPT_RTADV; 1923 #ifdef ND6_IFF_OVERRIDE_RTADV 1924 if (ifp->options->options & DHCPCD_IPV6RS) 1925 flags |= ND6_IFF_OVERRIDE_RTADV; 1926 #endif 1927 #endif 1928 1929 if (nd.ndi.flags != (uint32_t)flags) { 1930 nd.ndi.flags = (uint32_t)flags; 1931 if (if_ioctl6(ifp->ctx, SIOCSIFINFO_FLAGS, &nd, sizeof(nd)) == 1932 -1) 1933 logerr("%s: SIOCSIFINFO_FLAGS", ifp->name); 1934 } 1935 #endif /* ND6_NDI_FLAGS */ 1936 1937 /* Enabling IPv6 by whatever means must be the 1938 * last action undertaken to ensure kernel RS and 1939 * LLADDR auto configuration are disabled where applicable. */ 1940 #ifdef SIOCIFAFATTACH 1941 if (if_af_attach(ifp, AF_INET6) == -1) 1942 logerr("%s: if_af_attach", ifp->name); 1943 #endif 1944 1945 #ifdef SIOCGIFXFLAGS 1946 if (if_set_ifxflags(ifp) == -1) 1947 logerr("%s: set_ifxflags", ifp->name); 1948 #endif 1949 1950 #ifdef SIOCSRTRFLUSH_IN6 1951 /* Flush the kernel knowledge of advertised routers 1952 * and prefixes so the kernel does not expire prefixes 1953 * and default routes we are trying to own. */ 1954 if (ifp->options->options & DHCPCD_IPV6RS) { 1955 struct in6_ifreq ifr; 1956 1957 memset(&ifr, 0, sizeof(ifr)); 1958 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1959 if (if_ioctl6(ifp->ctx, SIOCSRTRFLUSH_IN6, &ifr, sizeof(ifr)) == 1960 -1 && 1961 errno != ENOTSUP && errno != ENOTTY) 1962 logwarn("SIOCSRTRFLUSH_IN6 %d", errno); 1963 #ifdef SIOCSPFXFLUSH_IN6 1964 if (if_ioctl6(ifp->ctx, SIOCSPFXFLUSH_IN6, &ifr, sizeof(ifr)) == 1965 -1 && 1966 errno != ENOTSUP && errno != ENOTTY) 1967 logwarn("SIOCSPFXFLUSH_IN6"); 1968 #endif 1969 } 1970 #endif 1971 } 1972 #endif 1973