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