Home | History | Annotate | Line # | Download | only in src
      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