18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI * BSD interface driver for dhcpcd
480aa9461SRoy Marples * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI * All rights reserved
67827cba2SAaron LI
77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI * modification, are permitted provided that the following conditions
97827cba2SAaron LI * are met:
107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI * notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI * documentation and/or other materials provided with the distribution.
157827cba2SAaron LI *
167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI * SUCH DAMAGE.
277827cba2SAaron LI */
287827cba2SAaron LI
297827cba2SAaron LI #include <sys/ioctl.h>
307827cba2SAaron LI #include <sys/param.h>
317827cba2SAaron LI #include <sys/socket.h>
327827cba2SAaron LI #include <sys/stat.h>
337827cba2SAaron LI #include <sys/sysctl.h>
347827cba2SAaron LI #include <sys/time.h>
357827cba2SAaron LI #include <sys/types.h>
367827cba2SAaron LI #include <sys/uio.h>
377827cba2SAaron LI #include <sys/utsname.h>
387827cba2SAaron LI
397827cba2SAaron LI #include "config.h"
407827cba2SAaron LI
417827cba2SAaron LI #include <arpa/inet.h>
427827cba2SAaron LI #include <net/bpf.h>
437827cba2SAaron LI #include <net/if.h>
447827cba2SAaron LI #include <net/if_dl.h>
457827cba2SAaron LI #include <net/if_media.h>
467827cba2SAaron LI #include <net/route.h>
477827cba2SAaron LI #include <netinet/if_ether.h>
487827cba2SAaron LI #include <netinet/in.h>
497827cba2SAaron LI #include <netinet/in_var.h>
507827cba2SAaron LI #include <netinet6/in6_var.h>
517827cba2SAaron LI #include <netinet6/nd6.h>
527827cba2SAaron LI #ifdef __NetBSD__
537827cba2SAaron LI #include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
548d36e1dfSRoy Marples #elif defined(__DragonFly__)
558d36e1dfSRoy Marples #include <net/vlan/if_vlan_var.h>
567827cba2SAaron LI #else
577827cba2SAaron LI #include <net/if_vlan_var.h>
587827cba2SAaron LI #endif
597827cba2SAaron LI #ifdef __DragonFly__
607827cba2SAaron LI # include <netproto/802_11/ieee80211_ioctl.h>
617827cba2SAaron LI #else
627827cba2SAaron LI # include <net80211/ieee80211.h>
637827cba2SAaron LI # include <net80211/ieee80211_ioctl.h>
647827cba2SAaron LI #endif
657827cba2SAaron LI
667827cba2SAaron LI #include <assert.h>
677827cba2SAaron LI #include <errno.h>
687827cba2SAaron LI #include <fcntl.h>
697827cba2SAaron LI #include <fnmatch.h>
707827cba2SAaron LI #include <paths.h>
717827cba2SAaron LI #include <stddef.h>
727827cba2SAaron LI #include <stdio.h>
737827cba2SAaron LI #include <stdlib.h>
747827cba2SAaron LI #include <string.h>
757827cba2SAaron LI #include <unistd.h>
767827cba2SAaron LI
777827cba2SAaron LI #if defined(OpenBSD) && OpenBSD >= 201411
787827cba2SAaron LI /* OpenBSD dropped the global setting from sysctl but left the #define
797827cba2SAaron LI * which causes a EPERM error when trying to use it.
807827cba2SAaron LI * I think both the error and keeping the define are wrong, so we #undef it. */
817827cba2SAaron LI #undef IPV6CTL_ACCEPT_RTADV
827827cba2SAaron LI #endif
837827cba2SAaron LI
847827cba2SAaron LI #include "common.h"
857827cba2SAaron LI #include "dhcp.h"
867827cba2SAaron LI #include "if.h"
877827cba2SAaron LI #include "if-options.h"
887827cba2SAaron LI #include "ipv4.h"
897827cba2SAaron LI #include "ipv4ll.h"
907827cba2SAaron LI #include "ipv6.h"
917827cba2SAaron LI #include "ipv6nd.h"
927827cba2SAaron LI #include "logerr.h"
936e63cc1fSRoy Marples #include "privsep.h"
947827cba2SAaron LI #include "route.h"
957827cba2SAaron LI #include "sa.h"
967827cba2SAaron LI
977827cba2SAaron LI #ifndef RT_ROUNDUP
987827cba2SAaron LI #define RT_ROUNDUP(a) \
997827cba2SAaron LI ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1007827cba2SAaron LI #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
1017827cba2SAaron LI #endif
1027827cba2SAaron LI
103acd7a309SRoy Marples /* Ignore these interface names which look like ethernet but are virtual or
104acd7a309SRoy Marples * just won't work without explicit configuration. */
1051b3b16a2SRoy Marples static const char * const ifnames_ignore[] = {
1061b3b16a2SRoy Marples "bridge",
10780aa9461SRoy Marples "epair", /* Virtual patch cable */
1081b3b16a2SRoy Marples "fwe", /* Firewire */
109acd7a309SRoy Marples "fwip", /* Firewire */
1101b3b16a2SRoy Marples "tap",
111a0d9933aSRoy Marples "vether",
1126e63cc1fSRoy Marples "xvif", /* XEN DOM0 -> guest interface */
1131b3b16a2SRoy Marples NULL
1141b3b16a2SRoy Marples };
1151b3b16a2SRoy Marples
1168d36e1dfSRoy Marples struct rtm
1178d36e1dfSRoy Marples {
1188d36e1dfSRoy Marples struct rt_msghdr hdr;
1198d36e1dfSRoy Marples char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
1208d36e1dfSRoy Marples };
1218d36e1dfSRoy Marples
1227827cba2SAaron LI int
os_init(void)123a0d9933aSRoy Marples os_init(void)
124a0d9933aSRoy Marples {
125a0d9933aSRoy Marples return 0;
126a0d9933aSRoy Marples }
127a0d9933aSRoy Marples
128a0d9933aSRoy Marples int
if_init(__unused struct interface * iface)1297827cba2SAaron LI if_init(__unused struct interface *iface)
1307827cba2SAaron LI {
1317827cba2SAaron LI /* BSD promotes secondary address by default */
1327827cba2SAaron LI return 0;
1337827cba2SAaron LI }
1347827cba2SAaron LI
1357827cba2SAaron LI int
if_conf(__unused struct interface * iface)1367827cba2SAaron LI if_conf(__unused struct interface *iface)
1377827cba2SAaron LI {
1387827cba2SAaron LI /* No extra checks needed on BSD */
1397827cba2SAaron LI return 0;
1407827cba2SAaron LI }
1417827cba2SAaron LI
1427827cba2SAaron LI int
if_opensockets_os(struct dhcpcd_ctx * ctx)1437827cba2SAaron LI if_opensockets_os(struct dhcpcd_ctx *ctx)
1447827cba2SAaron LI {
1457827cba2SAaron LI struct priv *priv;
1468d36e1dfSRoy Marples int n;
1477827cba2SAaron LI #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
1487827cba2SAaron LI unsigned char msgfilter[] = {
1497827cba2SAaron LI RTM_IFINFO,
1507827cba2SAaron LI #ifdef RTM_IFANNOUNCE
1517827cba2SAaron LI RTM_IFANNOUNCE,
1527827cba2SAaron LI #endif
1538d36e1dfSRoy Marples RTM_ADD, RTM_CHANGE, RTM_DELETE, RTM_MISS,
1547827cba2SAaron LI #ifdef RTM_CHGADDR
1557827cba2SAaron LI RTM_CHGADDR,
1567827cba2SAaron LI #endif
157f3744ac9SRoy Marples #ifdef RTM_DESYNC
158f3744ac9SRoy Marples RTM_DESYNC,
159f3744ac9SRoy Marples #endif
1607827cba2SAaron LI RTM_NEWADDR, RTM_DELADDR
1617827cba2SAaron LI };
1627827cba2SAaron LI #ifdef ROUTE_MSGFILTER
1637827cba2SAaron LI unsigned int i, msgfilter_mask;
1647827cba2SAaron LI #endif
1657827cba2SAaron LI #endif
1667827cba2SAaron LI
1677827cba2SAaron LI if ((priv = malloc(sizeof(*priv))) == NULL)
1687827cba2SAaron LI return -1;
1697827cba2SAaron LI ctx->priv = priv;
1707827cba2SAaron LI
1717827cba2SAaron LI #ifdef INET6
1727827cba2SAaron LI priv->pf_inet6_fd = xsocket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1737827cba2SAaron LI /* Don't return an error so we at least work on kernels witout INET6
1747827cba2SAaron LI * even though we expect INET6 support.
1757827cba2SAaron LI * We will fail noisily elsewhere anyway. */
176f3744ac9SRoy Marples #ifdef PRIVSEP_RIGHTS
177f3744ac9SRoy Marples if (priv->pf_inet6_fd != -1 && IN_PRIVSEP(ctx))
178f3744ac9SRoy Marples ps_rights_limit_ioctl(priv->pf_inet6_fd);
179f3744ac9SRoy Marples #endif
1807827cba2SAaron LI #endif
1817827cba2SAaron LI
182d4fb1e02SRoy Marples ctx->link_fd = xsocket(PF_ROUTE, SOCK_RAW | SOCK_CXNB, AF_UNSPEC);
1837827cba2SAaron LI if (ctx->link_fd == -1)
1847827cba2SAaron LI return -1;
1857827cba2SAaron LI
186d4fb1e02SRoy Marples #ifdef SO_RERROR
187d4fb1e02SRoy Marples n = 1;
188d4fb1e02SRoy Marples if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RERROR, &n,sizeof(n)) == -1)
189d4fb1e02SRoy Marples logerr("%s: SO_RERROR", __func__);
190d4fb1e02SRoy Marples #endif
191d4fb1e02SRoy Marples
1928d36e1dfSRoy Marples /* Ignore our own route(4) messages.
1938d36e1dfSRoy Marples * Sadly there is no way of doing this for route(4) messages
1948d36e1dfSRoy Marples * generated from addresses we add/delete. */
1958d36e1dfSRoy Marples n = 0;
1968d36e1dfSRoy Marples if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_USELOOPBACK,
1978d36e1dfSRoy Marples &n, sizeof(n)) == -1)
1988d36e1dfSRoy Marples logerr("%s: SO_USELOOPBACK", __func__);
1998d36e1dfSRoy Marples
200*54175cefSRoy Marples #ifdef PRIVSEP
201*54175cefSRoy Marples if (ctx->options & DHCPCD_PRIVSEPROOT) {
202*54175cefSRoy Marples /* We only want to write to this socket, so set
203*54175cefSRoy Marples * a small as possible buffer size. */
204*54175cefSRoy Marples socklen_t smallbuf = 1;
205*54175cefSRoy Marples
206*54175cefSRoy Marples if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RCVBUF,
207*54175cefSRoy Marples &smallbuf, (socklen_t)sizeof(smallbuf)) == -1)
208*54175cefSRoy Marples logerr("%s: setsockopt(SO_RCVBUF)", __func__);
209*54175cefSRoy Marples }
210*54175cefSRoy Marples #endif
211*54175cefSRoy Marples
2127827cba2SAaron LI #if defined(RO_MSGFILTER)
2137827cba2SAaron LI if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER,
2147827cba2SAaron LI &msgfilter, sizeof(msgfilter)) == -1)
2157827cba2SAaron LI logerr(__func__);
2167827cba2SAaron LI #elif defined(ROUTE_MSGFILTER)
2177827cba2SAaron LI /* Convert the array into a bitmask. */
2187827cba2SAaron LI msgfilter_mask = 0;
2197827cba2SAaron LI for (i = 0; i < __arraycount(msgfilter); i++)
2207827cba2SAaron LI msgfilter_mask |= ROUTE_FILTER(msgfilter[i]);
2217827cba2SAaron LI if (setsockopt(ctx->link_fd, PF_ROUTE, ROUTE_MSGFILTER,
2227827cba2SAaron LI &msgfilter_mask, sizeof(msgfilter_mask)) == -1)
2237827cba2SAaron LI logerr(__func__);
2248d36e1dfSRoy Marples #else
2258d36e1dfSRoy Marples #warning kernel does not support route message filtering
2267827cba2SAaron LI #endif
2277827cba2SAaron LI
228a0d9933aSRoy Marples #ifdef PRIVSEP_RIGHTS
229a0d9933aSRoy Marples /* We need to getsockopt for SO_RCVBUF and
230a0d9933aSRoy Marples * setsockopt for RO_MISSFILTER. */
231a0d9933aSRoy Marples if (IN_PRIVSEP(ctx))
232a0d9933aSRoy Marples ps_rights_limit_fd_sockopt(ctx->link_fd);
233a0d9933aSRoy Marples #endif
234a0d9933aSRoy Marples
23580aa9461SRoy Marples #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
236*54175cefSRoy Marples priv->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0);
23780aa9461SRoy Marples if (priv->pf_link_fd == -1)
23880aa9461SRoy Marples logerr("%s: socket(PF_LINK)", __func__);
23980aa9461SRoy Marples #endif
2407827cba2SAaron LI return 0;
2417827cba2SAaron LI }
2427827cba2SAaron LI
2437827cba2SAaron LI void
if_closesockets_os(struct dhcpcd_ctx * ctx)2447827cba2SAaron LI if_closesockets_os(struct dhcpcd_ctx *ctx)
2457827cba2SAaron LI {
2467827cba2SAaron LI struct priv *priv;
2477827cba2SAaron LI
2487827cba2SAaron LI priv = (struct priv *)ctx->priv;
249*54175cefSRoy Marples if (priv == NULL)
250*54175cefSRoy Marples return;
251*54175cefSRoy Marples
252f3744ac9SRoy Marples #ifdef INET6
253*54175cefSRoy Marples if (priv->pf_inet6_fd != -1) {
2547827cba2SAaron LI close(priv->pf_inet6_fd);
255*54175cefSRoy Marples priv->pf_inet6_fd = -1;
256*54175cefSRoy Marples }
257f3744ac9SRoy Marples #endif
25880aa9461SRoy Marples #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
259*54175cefSRoy Marples if (priv->pf_link_fd != -1) {
26080aa9461SRoy Marples close(priv->pf_link_fd);
261*54175cefSRoy Marples priv->pf_link_fd = -1;
262*54175cefSRoy Marples }
26380aa9461SRoy Marples #endif
2646e63cc1fSRoy Marples free(priv);
2656e63cc1fSRoy Marples ctx->priv = NULL;
2660a68f8d2SRoy Marples free(ctx->rt_missfilter);
2676e63cc1fSRoy Marples }
2686e63cc1fSRoy Marples
2696e63cc1fSRoy Marples #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
2706e63cc1fSRoy Marples static int
if_ioctllink(struct dhcpcd_ctx * ctx,unsigned long req,void * data,size_t len)2716e63cc1fSRoy Marples if_ioctllink(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
2726e63cc1fSRoy Marples {
27380aa9461SRoy Marples struct priv *priv = (struct priv *)ctx->priv;
2746e63cc1fSRoy Marples
2756e63cc1fSRoy Marples #ifdef PRIVSEP
2766e63cc1fSRoy Marples if (ctx->options & DHCPCD_PRIVSEP)
2776e63cc1fSRoy Marples return (int)ps_root_ioctllink(ctx, req, data, len);
2786e63cc1fSRoy Marples #endif
2796e63cc1fSRoy Marples
28080aa9461SRoy Marples return ioctl(priv->pf_link_fd, req, data, len);
2816e63cc1fSRoy Marples }
2826e63cc1fSRoy Marples #endif
2836e63cc1fSRoy Marples
2846e63cc1fSRoy Marples int
if_setmac(struct interface * ifp,void * mac,uint8_t maclen)2856e63cc1fSRoy Marples if_setmac(struct interface *ifp, void *mac, uint8_t maclen)
2866e63cc1fSRoy Marples {
2876e63cc1fSRoy Marples
2886e63cc1fSRoy Marples if (ifp->hwlen != maclen) {
2896e63cc1fSRoy Marples errno = EINVAL;
2906e63cc1fSRoy Marples return -1;
2916e63cc1fSRoy Marples }
2926e63cc1fSRoy Marples
2936e63cc1fSRoy Marples #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
2946e63cc1fSRoy Marples struct if_laddrreq iflr = { .flags = IFLR_ACTIVE };
2956e63cc1fSRoy Marples struct sockaddr_dl *sdl = satosdl(&iflr.addr);
2966e63cc1fSRoy Marples int retval;
2976e63cc1fSRoy Marples
2986e63cc1fSRoy Marples strlcpy(iflr.iflr_name, ifp->name, sizeof(iflr.iflr_name));
2996e63cc1fSRoy Marples sdl->sdl_family = AF_LINK;
3006e63cc1fSRoy Marples sdl->sdl_len = sizeof(*sdl);
3016e63cc1fSRoy Marples sdl->sdl_alen = maclen;
3026e63cc1fSRoy Marples memcpy(LLADDR(sdl), mac, maclen);
3036e63cc1fSRoy Marples retval = if_ioctllink(ifp->ctx, SIOCALIFADDR, &iflr, sizeof(iflr));
3046e63cc1fSRoy Marples
3056e63cc1fSRoy Marples /* Try and remove the old address */
3066e63cc1fSRoy Marples memcpy(LLADDR(sdl), ifp->hwaddr, ifp->hwlen);
3076e63cc1fSRoy Marples if_ioctllink(ifp->ctx, SIOCDLIFADDR, &iflr, sizeof(iflr));
3086e63cc1fSRoy Marples
3096e63cc1fSRoy Marples return retval;
3106e63cc1fSRoy Marples #else
3116e63cc1fSRoy Marples struct ifreq ifr = {
3126e63cc1fSRoy Marples .ifr_addr.sa_family = AF_LINK,
3136e63cc1fSRoy Marples .ifr_addr.sa_len = maclen,
3146e63cc1fSRoy Marples };
3156e63cc1fSRoy Marples
3166e63cc1fSRoy Marples strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
3176e63cc1fSRoy Marples memcpy(ifr.ifr_addr.sa_data, mac, maclen);
3186e63cc1fSRoy Marples return if_ioctl(ifp->ctx, SIOCSIFLLADDR, &ifr, sizeof(ifr));
3196e63cc1fSRoy Marples #endif
3207827cba2SAaron LI }
3217827cba2SAaron LI
3221b3b16a2SRoy Marples static bool
if_ignore1(const char * drvname)3231b3b16a2SRoy Marples if_ignore1(const char *drvname)
3241b3b16a2SRoy Marples {
3251b3b16a2SRoy Marples const char * const *p;
3261b3b16a2SRoy Marples
3271b3b16a2SRoy Marples for (p = ifnames_ignore; *p; p++) {
3281b3b16a2SRoy Marples if (strcmp(*p, drvname) == 0)
3291b3b16a2SRoy Marples return true;
3301b3b16a2SRoy Marples }
3311b3b16a2SRoy Marples return false;
3321b3b16a2SRoy Marples }
3331b3b16a2SRoy Marples
3347f8103cdSRoy Marples #ifdef SIOCGIFGROUP
3357f8103cdSRoy Marples int
if_ignoregroup(int s,const char * ifname)3367f8103cdSRoy Marples if_ignoregroup(int s, const char *ifname)
3377f8103cdSRoy Marples {
3387f8103cdSRoy Marples struct ifgroupreq ifgr = { .ifgr_len = 0 };
3397f8103cdSRoy Marples struct ifg_req *ifg;
3407f8103cdSRoy Marples size_t ifg_len;
3417f8103cdSRoy Marples
3427f8103cdSRoy Marples /* Sadly it is possible to remove the device name
3437f8103cdSRoy Marples * from the interface groups, but hopefully this
3447f8103cdSRoy Marples * will be very unlikely.... */
3457f8103cdSRoy Marples
3467f8103cdSRoy Marples strlcpy(ifgr.ifgr_name, ifname, sizeof(ifgr.ifgr_name));
3477f8103cdSRoy Marples if (ioctl(s, SIOCGIFGROUP, &ifgr) == -1 ||
3487f8103cdSRoy Marples (ifgr.ifgr_groups = malloc(ifgr.ifgr_len)) == NULL ||
3497f8103cdSRoy Marples ioctl(s, SIOCGIFGROUP, &ifgr) == -1)
3507f8103cdSRoy Marples {
3517f8103cdSRoy Marples logerr(__func__);
3527f8103cdSRoy Marples return -1;
3537f8103cdSRoy Marples }
3547f8103cdSRoy Marples
3557f8103cdSRoy Marples for (ifg = ifgr.ifgr_groups, ifg_len = ifgr.ifgr_len;
3567f8103cdSRoy Marples ifg && ifg_len >= sizeof(*ifg);
3577f8103cdSRoy Marples ifg++, ifg_len -= sizeof(*ifg))
3587f8103cdSRoy Marples {
3597f8103cdSRoy Marples if (if_ignore1(ifg->ifgrq_group))
3607f8103cdSRoy Marples return 1;
3617f8103cdSRoy Marples }
3627f8103cdSRoy Marples return 0;
3637f8103cdSRoy Marples }
3647f8103cdSRoy Marples #endif
3657f8103cdSRoy Marples
3661b3b16a2SRoy Marples bool
if_ignore(struct dhcpcd_ctx * ctx,const char * ifname)3671b3b16a2SRoy Marples if_ignore(struct dhcpcd_ctx *ctx, const char *ifname)
3681b3b16a2SRoy Marples {
3691b3b16a2SRoy Marples struct if_spec spec;
3701b3b16a2SRoy Marples
3711b3b16a2SRoy Marples if (if_nametospec(ifname, &spec) != 0)
3721b3b16a2SRoy Marples return false;
3731b3b16a2SRoy Marples
3741b3b16a2SRoy Marples if (if_ignore1(spec.drvname))
3751b3b16a2SRoy Marples return true;
3761b3b16a2SRoy Marples
3771b3b16a2SRoy Marples #ifdef SIOCGIFGROUP
3787f8103cdSRoy Marples #if defined(PRIVSEP) && defined(HAVE_PLEDGE)
3797f8103cdSRoy Marples if (IN_PRIVSEP(ctx))
3807f8103cdSRoy Marples return ps_root_ifignoregroup(ctx, ifname) == 1 ? true : false;
381d4fb1e02SRoy Marples #endif
3827f8103cdSRoy Marples else
3837f8103cdSRoy Marples return if_ignoregroup(ctx->pf_inet_fd, ifname) == 1 ?
3847f8103cdSRoy Marples true : false;
3851b3b16a2SRoy Marples #else
3861b3b16a2SRoy Marples UNUSED(ctx);
3871b3b16a2SRoy Marples return false;
3887f8103cdSRoy Marples #endif
3891b3b16a2SRoy Marples }
3901b3b16a2SRoy Marples
if_indirect_ioctl(struct dhcpcd_ctx * ctx,const char * ifname,unsigned long cmd,void * data,size_t len)391a0d9933aSRoy Marples static int if_indirect_ioctl(struct dhcpcd_ctx *ctx,
392a0d9933aSRoy Marples const char *ifname, unsigned long cmd, void *data, size_t len)
3938d36e1dfSRoy Marples {
394a0d9933aSRoy Marples struct ifreq ifr = { .ifr_flags = 0 };
3958d36e1dfSRoy Marples
396a0d9933aSRoy Marples #if defined(PRIVSEP) && (defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE))
397a0d9933aSRoy Marples if (IN_PRIVSEP(ctx))
398a0d9933aSRoy Marples return (int)ps_root_indirectioctl(ctx, cmd, ifname, data, len);
399a0d9933aSRoy Marples #else
400a0d9933aSRoy Marples UNUSED(len);
401a0d9933aSRoy Marples #endif
402a0d9933aSRoy Marples
403a0d9933aSRoy Marples strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
404a0d9933aSRoy Marples ifr.ifr_data = data;
405a0d9933aSRoy Marples return ioctl(ctx->pf_inet_fd, cmd, &ifr);
406a0d9933aSRoy Marples }
407a0d9933aSRoy Marples
408a0d9933aSRoy Marples int
if_carrier(struct interface * ifp,const void * ifadata)40993ddca5eSRoy Marples if_carrier(struct interface *ifp, const void *ifadata)
410a0d9933aSRoy Marples {
411a0d9933aSRoy Marples const struct if_data *ifi = ifadata;
412a0d9933aSRoy Marples
413a0d9933aSRoy Marples /*
414a0d9933aSRoy Marples * Every BSD returns this and it is the sole source of truth.
415a0d9933aSRoy Marples * Not all BSD's support SIOCGIFDATA and not all interfaces
416a0d9933aSRoy Marples * support SIOCGIFMEDIA.
417a0d9933aSRoy Marples */
418a0d9933aSRoy Marples assert(ifadata != NULL);
419a0d9933aSRoy Marples
420a0d9933aSRoy Marples if (ifi->ifi_link_state >= LINK_STATE_UP)
421a0d9933aSRoy Marples return LINK_UP;
42293ddca5eSRoy Marples if (ifi->ifi_link_state == LINK_STATE_UNKNOWN) {
42393ddca5eSRoy Marples /*
42493ddca5eSRoy Marples * Work around net80211 issues in some BSDs.
42593ddca5eSRoy Marples * Wireless MUST support link state change.
42693ddca5eSRoy Marples */
42793ddca5eSRoy Marples if (ifp->wireless)
42893ddca5eSRoy Marples return LINK_DOWN;
429cc34ba0cSRoy Marples return LINK_UNKNOWN;
43093ddca5eSRoy Marples }
431a0d9933aSRoy Marples return LINK_DOWN;
4328d36e1dfSRoy Marples }
4338d36e1dfSRoy Marples
4340aaf6155SRoy Marples bool
if_roaming(struct interface * ifp)4350aaf6155SRoy Marples if_roaming(struct interface *ifp)
4360aaf6155SRoy Marples {
4370aaf6155SRoy Marples
4380aaf6155SRoy Marples /* Check for NetBSD as a safety measure.
4390aaf6155SRoy Marples * If other BSD's gain IN_IFF_TENTATIVE check they re-do DAD
4400aaf6155SRoy Marples * when the carrier comes up again. */
4410aaf6155SRoy Marples #if defined(IN_IFF_TENTATIVE) && defined(__NetBSD__)
4420aaf6155SRoy Marples return ifp->flags & IFF_UP && ifp->carrier == LINK_DOWN;
4430aaf6155SRoy Marples #else
4440aaf6155SRoy Marples UNUSED(ifp);
4450aaf6155SRoy Marples return false;
4460aaf6155SRoy Marples #endif
4470aaf6155SRoy Marples }
4480aaf6155SRoy Marples
4497827cba2SAaron LI static void
if_linkaddr(struct sockaddr_dl * sdl,const struct interface * ifp)4507827cba2SAaron LI if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
4517827cba2SAaron LI {
4527827cba2SAaron LI
4537827cba2SAaron LI memset(sdl, 0, sizeof(*sdl));
4547827cba2SAaron LI sdl->sdl_family = AF_LINK;
4557827cba2SAaron LI sdl->sdl_len = sizeof(*sdl);
4567827cba2SAaron LI sdl->sdl_nlen = sdl->sdl_alen = sdl->sdl_slen = 0;
4577827cba2SAaron LI sdl->sdl_index = (unsigned short)ifp->index;
4587827cba2SAaron LI }
4597827cba2SAaron LI
4607827cba2SAaron LI static int
if_getssid1(struct dhcpcd_ctx * ctx,const char * ifname,void * ssid)461d4fb1e02SRoy Marples if_getssid1(struct dhcpcd_ctx *ctx, const char *ifname, void *ssid)
4627827cba2SAaron LI {
4637827cba2SAaron LI int retval = -1;
4647827cba2SAaron LI #if defined(SIOCG80211NWID)
4657827cba2SAaron LI struct ieee80211_nwid nwid;
4667827cba2SAaron LI #elif defined(IEEE80211_IOC_SSID)
4677827cba2SAaron LI struct ieee80211req ireq;
4687827cba2SAaron LI char nwid[IEEE80211_NWID_LEN];
4697827cba2SAaron LI #endif
4707827cba2SAaron LI
4717827cba2SAaron LI #if defined(SIOCG80211NWID) /* NetBSD */
4727827cba2SAaron LI memset(&nwid, 0, sizeof(nwid));
473d4fb1e02SRoy Marples if (if_indirect_ioctl(ctx, ifname, SIOCG80211NWID,
474d4fb1e02SRoy Marples &nwid, sizeof(nwid)) == 0)
475d4fb1e02SRoy Marples {
4767827cba2SAaron LI if (ssid == NULL)
4777827cba2SAaron LI retval = nwid.i_len;
4787827cba2SAaron LI else if (nwid.i_len > IF_SSIDLEN)
4797827cba2SAaron LI errno = ENOBUFS;
4807827cba2SAaron LI else {
4817827cba2SAaron LI retval = nwid.i_len;
4827827cba2SAaron LI memcpy(ssid, nwid.i_nwid, nwid.i_len);
4837827cba2SAaron LI }
4847827cba2SAaron LI }
4857827cba2SAaron LI #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
4867827cba2SAaron LI memset(&ireq, 0, sizeof(ireq));
4877827cba2SAaron LI strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
4887827cba2SAaron LI ireq.i_type = IEEE80211_IOC_SSID;
4897827cba2SAaron LI ireq.i_val = -1;
4907827cba2SAaron LI memset(nwid, 0, sizeof(nwid));
4917827cba2SAaron LI ireq.i_data = &nwid;
492d4fb1e02SRoy Marples if (ioctl(ctx->pf_inet_fd, SIOCG80211, &ireq) == 0) {
4937827cba2SAaron LI if (ssid == NULL)
4947827cba2SAaron LI retval = ireq.i_len;
4957827cba2SAaron LI else if (ireq.i_len > IF_SSIDLEN)
4967827cba2SAaron LI errno = ENOBUFS;
4977827cba2SAaron LI else {
4987827cba2SAaron LI retval = ireq.i_len;
4997827cba2SAaron LI memcpy(ssid, nwid, ireq.i_len);
5007827cba2SAaron LI }
5017827cba2SAaron LI }
5027827cba2SAaron LI #else
5037827cba2SAaron LI errno = ENOSYS;
5047827cba2SAaron LI #endif
5057827cba2SAaron LI
5067827cba2SAaron LI return retval;
5077827cba2SAaron LI }
5087827cba2SAaron LI
5097827cba2SAaron LI int
if_getssid(struct interface * ifp)5107827cba2SAaron LI if_getssid(struct interface *ifp)
5117827cba2SAaron LI {
5127827cba2SAaron LI int r;
5137827cba2SAaron LI
514d4fb1e02SRoy Marples r = if_getssid1(ifp->ctx, ifp->name, ifp->ssid);
5157827cba2SAaron LI if (r != -1)
5167827cba2SAaron LI ifp->ssid_len = (unsigned int)r;
5177827cba2SAaron LI else
5187827cba2SAaron LI ifp->ssid_len = 0;
5197827cba2SAaron LI ifp->ssid[ifp->ssid_len] = '\0';
5207827cba2SAaron LI return r;
5217827cba2SAaron LI }
5227827cba2SAaron LI
5237827cba2SAaron LI /*
5247827cba2SAaron LI * FreeBSD allows for Virtual Access Points
5257827cba2SAaron LI * We need to check if the interface is a Virtual Interface Master
5267827cba2SAaron LI * and if so, don't use it.
5277827cba2SAaron LI * This check is made by virtue of being a IEEE80211 device but
5287827cba2SAaron LI * returning the SSID gives an error.
5297827cba2SAaron LI */
5307827cba2SAaron LI int
if_vimaster(struct dhcpcd_ctx * ctx,const char * ifname)531d4fb1e02SRoy Marples if_vimaster(struct dhcpcd_ctx *ctx, const char *ifname)
5327827cba2SAaron LI {
5337827cba2SAaron LI int r;
534d4fb1e02SRoy Marples struct ifmediareq ifmr = { .ifm_active = 0 };
5357827cba2SAaron LI
5367827cba2SAaron LI strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
5377827cba2SAaron LI r = ioctl(ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr);
5387827cba2SAaron LI if (r == -1)
5397827cba2SAaron LI return -1;
5407827cba2SAaron LI if (ifmr.ifm_status & IFM_AVALID &&
5417827cba2SAaron LI IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211)
5427827cba2SAaron LI {
543d4fb1e02SRoy Marples if (if_getssid1(ctx, ifname, NULL) == -1)
5447827cba2SAaron LI return 1;
5457827cba2SAaron LI }
5467827cba2SAaron LI return 0;
5477827cba2SAaron LI }
5487827cba2SAaron LI
5497827cba2SAaron LI unsigned short
if_vlanid(const struct interface * ifp)5507827cba2SAaron LI if_vlanid(const struct interface *ifp)
5517827cba2SAaron LI {
5527827cba2SAaron LI #ifdef SIOCGETVLAN
553d4fb1e02SRoy Marples struct vlanreq vlr = { .vlr_tag = 0 };
5547827cba2SAaron LI
555d4fb1e02SRoy Marples if (if_indirect_ioctl(ifp->ctx, ifp->name, SIOCGETVLAN,
556d4fb1e02SRoy Marples &vlr, sizeof(vlr)) != 0)
5577827cba2SAaron LI return 0; /* 0 means no VLANID */
5587827cba2SAaron LI return vlr.vlr_tag;
5597827cba2SAaron LI #elif defined(SIOCGVNETID)
560d4fb1e02SRoy Marples struct ifreq ifr = { .ifr_vnetid = 0 };
5617827cba2SAaron LI
5627827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
5637827cba2SAaron LI if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0)
5647827cba2SAaron LI return 0; /* 0 means no VLANID */
5657827cba2SAaron LI return ifr.ifr_vnetid;
5667827cba2SAaron LI #else
5677827cba2SAaron LI UNUSED(ifp);
5687827cba2SAaron LI return 0; /* 0 means no VLANID */
5697827cba2SAaron LI #endif
5707827cba2SAaron LI }
5717827cba2SAaron LI
5728d36e1dfSRoy Marples static int
get_addrs(int type,const void * data,size_t data_len,const struct sockaddr ** sa)5738d36e1dfSRoy Marples get_addrs(int type, const void *data, size_t data_len,
5748d36e1dfSRoy Marples const struct sockaddr **sa)
5757827cba2SAaron LI {
5768d36e1dfSRoy Marples const char *cp, *ep;
5777827cba2SAaron LI int i;
5787827cba2SAaron LI
5797827cba2SAaron LI cp = data;
5808d36e1dfSRoy Marples ep = cp + data_len;
5817827cba2SAaron LI for (i = 0; i < RTAX_MAX; i++) {
5827827cba2SAaron LI if (type & (1 << i)) {
5838d36e1dfSRoy Marples if (cp >= ep) {
5848d36e1dfSRoy Marples errno = EINVAL;
5858d36e1dfSRoy Marples return -1;
5868d36e1dfSRoy Marples }
5877827cba2SAaron LI sa[i] = (const struct sockaddr *)cp;
5887827cba2SAaron LI RT_ADVANCE(cp, sa[i]);
5897827cba2SAaron LI } else
5907827cba2SAaron LI sa[i] = NULL;
5917827cba2SAaron LI }
5928d36e1dfSRoy Marples
5938d36e1dfSRoy Marples return 0;
5947827cba2SAaron LI }
5957827cba2SAaron LI
5967827cba2SAaron LI static struct interface *
if_findsdl(struct dhcpcd_ctx * ctx,const struct sockaddr_dl * sdl)5977827cba2SAaron LI if_findsdl(struct dhcpcd_ctx *ctx, const struct sockaddr_dl *sdl)
5987827cba2SAaron LI {
5997827cba2SAaron LI
6007827cba2SAaron LI if (sdl->sdl_index)
6017827cba2SAaron LI return if_findindex(ctx->ifaces, sdl->sdl_index);
6027827cba2SAaron LI
6037827cba2SAaron LI if (sdl->sdl_nlen) {
6047827cba2SAaron LI char ifname[IF_NAMESIZE];
6057827cba2SAaron LI
6067827cba2SAaron LI memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
6077827cba2SAaron LI ifname[sdl->sdl_nlen] = '\0';
6087827cba2SAaron LI return if_find(ctx->ifaces, ifname);
6097827cba2SAaron LI }
6107827cba2SAaron LI if (sdl->sdl_alen) {
6117827cba2SAaron LI struct interface *ifp;
6127827cba2SAaron LI
6137827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) {
6147827cba2SAaron LI if (ifp->hwlen == sdl->sdl_alen &&
6157827cba2SAaron LI memcmp(ifp->hwaddr,
6167827cba2SAaron LI sdl->sdl_data, sdl->sdl_alen) == 0)
6177827cba2SAaron LI return ifp;
6187827cba2SAaron LI }
6197827cba2SAaron LI }
6207827cba2SAaron LI
6217827cba2SAaron LI errno = ENOENT;
6227827cba2SAaron LI return NULL;
6237827cba2SAaron LI }
6247827cba2SAaron LI
6257827cba2SAaron LI static struct interface *
if_findsa(struct dhcpcd_ctx * ctx,const struct sockaddr * sa)6267827cba2SAaron LI if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa)
6277827cba2SAaron LI {
6287827cba2SAaron LI if (sa == NULL) {
6297827cba2SAaron LI errno = EINVAL;
6307827cba2SAaron LI return NULL;
6317827cba2SAaron LI }
6327827cba2SAaron LI
6337827cba2SAaron LI switch (sa->sa_family) {
6347827cba2SAaron LI case AF_LINK:
6357827cba2SAaron LI {
6367827cba2SAaron LI const struct sockaddr_dl *sdl;
6377827cba2SAaron LI
6387827cba2SAaron LI sdl = (const void *)sa;
6397827cba2SAaron LI return if_findsdl(ctx, sdl);
6407827cba2SAaron LI }
6417827cba2SAaron LI #ifdef INET
6427827cba2SAaron LI case AF_INET:
6437827cba2SAaron LI {
6447827cba2SAaron LI const struct sockaddr_in *sin;
6457827cba2SAaron LI struct ipv4_addr *ia;
6467827cba2SAaron LI
6477827cba2SAaron LI sin = (const void *)sa;
6487827cba2SAaron LI if ((ia = ipv4_findmaskaddr(ctx, &sin->sin_addr)))
6497827cba2SAaron LI return ia->iface;
6500a68f8d2SRoy Marples if ((ia = ipv4_findmaskbrd(ctx, &sin->sin_addr)))
6510a68f8d2SRoy Marples return ia->iface;
6527827cba2SAaron LI break;
6537827cba2SAaron LI }
6547827cba2SAaron LI #endif
6557827cba2SAaron LI #ifdef INET6
6567827cba2SAaron LI case AF_INET6:
6577827cba2SAaron LI {
6587827cba2SAaron LI const struct sockaddr_in6 *sin;
6598d36e1dfSRoy Marples unsigned int scope;
6607827cba2SAaron LI struct ipv6_addr *ia;
6617827cba2SAaron LI
6627827cba2SAaron LI sin = (const void *)sa;
663d4fb1e02SRoy Marples scope = ipv6_getscope(sin);
6648d36e1dfSRoy Marples if (scope != 0)
6658d36e1dfSRoy Marples return if_findindex(ctx->ifaces, scope);
6667827cba2SAaron LI if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
6677827cba2SAaron LI return ia->iface;
6687827cba2SAaron LI break;
6697827cba2SAaron LI }
6707827cba2SAaron LI #endif
6717827cba2SAaron LI default:
6727827cba2SAaron LI errno = EAFNOSUPPORT;
6737827cba2SAaron LI return NULL;
6747827cba2SAaron LI }
6757827cba2SAaron LI
6767827cba2SAaron LI errno = ENOENT;
6777827cba2SAaron LI return NULL;
6787827cba2SAaron LI }
6797827cba2SAaron LI
6807827cba2SAaron LI static void
if_copysa(struct sockaddr * dst,const struct sockaddr * src)6817827cba2SAaron LI if_copysa(struct sockaddr *dst, const struct sockaddr *src)
6827827cba2SAaron LI {
6837827cba2SAaron LI
6847827cba2SAaron LI assert(dst != NULL);
6857827cba2SAaron LI assert(src != NULL);
6867827cba2SAaron LI
6877827cba2SAaron LI memcpy(dst, src, src->sa_len);
6887827cba2SAaron LI #if defined(INET6) && defined(__KAME__)
6897827cba2SAaron LI if (dst->sa_family == AF_INET6) {
6907827cba2SAaron LI struct in6_addr *in6;
6917827cba2SAaron LI
6927827cba2SAaron LI in6 = &satosin6(dst)->sin6_addr;
6937827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(in6))
6947827cba2SAaron LI in6->s6_addr[2] = in6->s6_addr[3] = '\0';
6957827cba2SAaron LI }
6967827cba2SAaron LI #endif
6977827cba2SAaron LI }
6987827cba2SAaron LI
6997827cba2SAaron LI int
if_route(unsigned char cmd,const struct rt * rt)7007827cba2SAaron LI if_route(unsigned char cmd, const struct rt *rt)
7017827cba2SAaron LI {
7027827cba2SAaron LI struct dhcpcd_ctx *ctx;
7038d36e1dfSRoy Marples struct rtm rtmsg;
7047827cba2SAaron LI struct rt_msghdr *rtm = &rtmsg.hdr;
7057827cba2SAaron LI char *bp = rtmsg.buffer;
7067827cba2SAaron LI struct sockaddr_dl sdl;
7077827cba2SAaron LI bool gateway_unspec;
7087827cba2SAaron LI
7097827cba2SAaron LI assert(rt != NULL);
7108d36e1dfSRoy Marples assert(rt->rt_ifp != NULL);
7118d36e1dfSRoy Marples assert(rt->rt_ifp->ctx != NULL);
7127827cba2SAaron LI ctx = rt->rt_ifp->ctx;
7137827cba2SAaron LI
7147827cba2SAaron LI #define ADDSA(sa) do { \
7157827cba2SAaron LI memcpy(bp, (sa), (sa)->sa_len); \
7167827cba2SAaron LI bp += RT_ROUNDUP((sa)->sa_len); \
7177827cba2SAaron LI } while (0 /* CONSTCOND */)
7187827cba2SAaron LI
7197827cba2SAaron LI memset(&rtmsg, 0, sizeof(rtmsg));
7207827cba2SAaron LI rtm->rtm_version = RTM_VERSION;
7217827cba2SAaron LI rtm->rtm_type = cmd;
7227827cba2SAaron LI #ifdef __OpenBSD__
7237827cba2SAaron LI rtm->rtm_pid = getpid();
7247827cba2SAaron LI #endif
7257827cba2SAaron LI rtm->rtm_seq = ++ctx->seq;
7267827cba2SAaron LI rtm->rtm_flags = (int)rt->rt_flags;
7277827cba2SAaron LI rtm->rtm_addrs = RTA_DST;
7287827cba2SAaron LI #ifdef RTF_PINNED
7297827cba2SAaron LI if (cmd != RTM_ADD)
7307827cba2SAaron LI rtm->rtm_flags |= RTF_PINNED;
7317827cba2SAaron LI #endif
7327827cba2SAaron LI
7337827cba2SAaron LI gateway_unspec = sa_is_unspecified(&rt->rt_gateway);
7347827cba2SAaron LI
7357827cba2SAaron LI if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
7367827cba2SAaron LI bool netmask_bcast = sa_is_allones(&rt->rt_netmask);
7377827cba2SAaron LI
7387827cba2SAaron LI rtm->rtm_flags |= RTF_UP;
7397827cba2SAaron LI rtm->rtm_addrs |= RTA_GATEWAY;
7407827cba2SAaron LI if (!(rtm->rtm_flags & RTF_REJECT) &&
7417827cba2SAaron LI !sa_is_loopback(&rt->rt_gateway))
7427827cba2SAaron LI {
7437827cba2SAaron LI rtm->rtm_index = (unsigned short)rt->rt_ifp->index;
7448d36e1dfSRoy Marples /*
7458d36e1dfSRoy Marples * OpenBSD rejects the message for on-link routes.
7468d36e1dfSRoy Marples * FreeBSD-12 kernel apparently panics.
7478d36e1dfSRoy Marples * I can't replicate the panic, but better safe than sorry!
7488d36e1dfSRoy Marples * https://roy.marples.name/archives/dhcpcd-discuss/0002286.html
7498d36e1dfSRoy Marples *
7508d36e1dfSRoy Marples * Neither OS currently allows IPv6 address sharing anyway, so let's
7518d36e1dfSRoy Marples * try to encourage someone to fix that by logging a waring during compile.
7528d36e1dfSRoy Marples */
7538d36e1dfSRoy Marples #if defined(__FreeBSD__) || defined(__OpenBSD__)
7548d36e1dfSRoy Marples #warning kernel does not allow IPv6 address sharing
7558d36e1dfSRoy Marples if (!gateway_unspec || rt->rt_dest.sa_family!=AF_INET6)
7568d36e1dfSRoy Marples #endif
7577827cba2SAaron LI rtm->rtm_addrs |= RTA_IFP;
7587827cba2SAaron LI if (!sa_is_unspecified(&rt->rt_ifa))
7597827cba2SAaron LI rtm->rtm_addrs |= RTA_IFA;
7607827cba2SAaron LI }
7617827cba2SAaron LI if (netmask_bcast)
7627827cba2SAaron LI rtm->rtm_flags |= RTF_HOST;
7637827cba2SAaron LI /* Network routes are cloning or connected if supported.
7647827cba2SAaron LI * All other routes are static. */
7657827cba2SAaron LI if (gateway_unspec) {
7667827cba2SAaron LI #ifdef RTF_CLONING
7677827cba2SAaron LI rtm->rtm_flags |= RTF_CLONING;
7687827cba2SAaron LI #endif
7697827cba2SAaron LI #ifdef RTF_CONNECTED
7707827cba2SAaron LI rtm->rtm_flags |= RTF_CONNECTED;
7717827cba2SAaron LI #endif
7727827cba2SAaron LI #ifdef RTP_CONNECTED
7737827cba2SAaron LI rtm->rtm_priority = RTP_CONNECTED;
7747827cba2SAaron LI #endif
7757827cba2SAaron LI #ifdef RTF_CLONING
7767827cba2SAaron LI if (netmask_bcast) {
7777827cba2SAaron LI /*
7787827cba2SAaron LI * We add a cloning network route for a single
7797827cba2SAaron LI * host. Traffic to the host will generate a
7807827cba2SAaron LI * cloned route and the hardware address will
7817827cba2SAaron LI * resolve correctly.
7827827cba2SAaron LI * It might be more correct to use RTF_HOST
7837827cba2SAaron LI * instead of RTF_CLONING, and that does work,
7847827cba2SAaron LI * but some OS generate an arp warning
7857827cba2SAaron LI * diagnostic which we don't want to do.
7867827cba2SAaron LI */
7877827cba2SAaron LI rtm->rtm_flags &= ~RTF_HOST;
7887827cba2SAaron LI }
7897827cba2SAaron LI #endif
7907827cba2SAaron LI } else
7917827cba2SAaron LI rtm->rtm_flags |= RTF_GATEWAY;
7927827cba2SAaron LI
7937f8103cdSRoy Marples if (rt->rt_dflags & RTDF_STATIC)
7947827cba2SAaron LI rtm->rtm_flags |= RTF_STATIC;
7957827cba2SAaron LI
7967827cba2SAaron LI if (rt->rt_mtu != 0) {
7977827cba2SAaron LI rtm->rtm_inits |= RTV_MTU;
7987827cba2SAaron LI rtm->rtm_rmx.rmx_mtu = rt->rt_mtu;
7997827cba2SAaron LI }
8007827cba2SAaron LI }
8017827cba2SAaron LI
8027827cba2SAaron LI if (!(rtm->rtm_flags & RTF_HOST))
8037827cba2SAaron LI rtm->rtm_addrs |= RTA_NETMASK;
8047827cba2SAaron LI
8057827cba2SAaron LI if_linkaddr(&sdl, rt->rt_ifp);
8067827cba2SAaron LI
8077827cba2SAaron LI ADDSA(&rt->rt_dest);
8087827cba2SAaron LI
8097827cba2SAaron LI if (rtm->rtm_addrs & RTA_GATEWAY) {
8107827cba2SAaron LI if (gateway_unspec)
8117827cba2SAaron LI ADDSA((struct sockaddr *)&sdl);
8127827cba2SAaron LI else {
8137827cba2SAaron LI union sa_ss gateway;
8147827cba2SAaron LI
8157827cba2SAaron LI if_copysa(&gateway.sa, &rt->rt_gateway);
8167827cba2SAaron LI #ifdef INET6
8177827cba2SAaron LI if (gateway.sa.sa_family == AF_INET6)
818d4fb1e02SRoy Marples ipv6_setscope(&gateway.sin6, rt->rt_ifp->index);
8197827cba2SAaron LI #endif
8207827cba2SAaron LI ADDSA(&gateway.sa);
8217827cba2SAaron LI }
8227827cba2SAaron LI }
8237827cba2SAaron LI
8247827cba2SAaron LI if (rtm->rtm_addrs & RTA_NETMASK)
8257827cba2SAaron LI ADDSA(&rt->rt_netmask);
8267827cba2SAaron LI
8277827cba2SAaron LI if (rtm->rtm_addrs & RTA_IFP)
8287827cba2SAaron LI ADDSA((struct sockaddr *)&sdl);
8297827cba2SAaron LI
8307827cba2SAaron LI if (rtm->rtm_addrs & RTA_IFA)
8317827cba2SAaron LI ADDSA(&rt->rt_ifa);
8327827cba2SAaron LI
8337827cba2SAaron LI #undef ADDSA
8347827cba2SAaron LI
8357827cba2SAaron LI rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
8366e63cc1fSRoy Marples
8376e63cc1fSRoy Marples #ifdef PRIVSEP
8386e63cc1fSRoy Marples if (ctx->options & DHCPCD_PRIVSEP) {
8396e63cc1fSRoy Marples if (ps_root_route(ctx, rtm, rtm->rtm_msglen) == -1)
8406e63cc1fSRoy Marples return -1;
8416e63cc1fSRoy Marples return 0;
8426e63cc1fSRoy Marples }
8436e63cc1fSRoy Marples #endif
8447827cba2SAaron LI if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1)
8457827cba2SAaron LI return -1;
8467827cba2SAaron LI return 0;
8477827cba2SAaron LI }
8487827cba2SAaron LI
8496e63cc1fSRoy Marples static bool
if_realroute(const struct rt_msghdr * rtm)8506e63cc1fSRoy Marples if_realroute(const struct rt_msghdr *rtm)
8516e63cc1fSRoy Marples {
8526e63cc1fSRoy Marples
8536e63cc1fSRoy Marples #ifdef RTF_CLONED
8546e63cc1fSRoy Marples if (rtm->rtm_flags & RTF_CLONED)
8556e63cc1fSRoy Marples return false;
8566e63cc1fSRoy Marples #endif
8576e63cc1fSRoy Marples #ifdef RTF_WASCLONED
8586e63cc1fSRoy Marples if (rtm->rtm_flags & RTF_WASCLONED)
8596e63cc1fSRoy Marples return false;
8606e63cc1fSRoy Marples #endif
8616e63cc1fSRoy Marples #ifdef RTF_LOCAL
8626e63cc1fSRoy Marples if (rtm->rtm_flags & RTF_LOCAL)
8636e63cc1fSRoy Marples return false;
8646e63cc1fSRoy Marples #endif
8656e63cc1fSRoy Marples #ifdef RTF_BROADCAST
8666e63cc1fSRoy Marples if (rtm->rtm_flags & RTF_BROADCAST)
8676e63cc1fSRoy Marples return false;
8686e63cc1fSRoy Marples #endif
8696e63cc1fSRoy Marples return true;
8706e63cc1fSRoy Marples }
8716e63cc1fSRoy Marples
8727827cba2SAaron LI static int
if_copyrt(struct dhcpcd_ctx * ctx,struct rt * rt,const struct rt_msghdr * rtm)8737827cba2SAaron LI if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
8747827cba2SAaron LI {
8757827cba2SAaron LI const struct sockaddr *rti_info[RTAX_MAX];
8767827cba2SAaron LI
8778d36e1dfSRoy Marples if (!(rtm->rtm_addrs & RTA_DST)) {
8788d36e1dfSRoy Marples errno = EINVAL;
8797827cba2SAaron LI return -1;
8808d36e1dfSRoy Marples }
8818d36e1dfSRoy Marples if (rtm->rtm_type != RTM_MISS && !(rtm->rtm_addrs & RTA_GATEWAY)) {
8828d36e1dfSRoy Marples errno = EINVAL;
8838d36e1dfSRoy Marples return -1;
8848d36e1dfSRoy Marples }
8857827cba2SAaron LI
8868d36e1dfSRoy Marples if (get_addrs(rtm->rtm_addrs, (const char *)rtm + sizeof(*rtm),
8878d36e1dfSRoy Marples rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1)
8888d36e1dfSRoy Marples return -1;
8897827cba2SAaron LI memset(rt, 0, sizeof(*rt));
8907827cba2SAaron LI
8917827cba2SAaron LI rt->rt_flags = (unsigned int)rtm->rtm_flags;
8927827cba2SAaron LI if_copysa(&rt->rt_dest, rti_info[RTAX_DST]);
8937827cba2SAaron LI if (rtm->rtm_addrs & RTA_NETMASK) {
8947827cba2SAaron LI if_copysa(&rt->rt_netmask, rti_info[RTAX_NETMASK]);
8957827cba2SAaron LI if (rt->rt_netmask.sa_family == 255) /* Why? */
8967827cba2SAaron LI rt->rt_netmask.sa_family = rt->rt_dest.sa_family;
8977827cba2SAaron LI }
8988d36e1dfSRoy Marples
8998d36e1dfSRoy Marples /* dhcpcd likes an unspecified gateway to indicate via the link.
9008d36e1dfSRoy Marples * However we need to know if gateway was a link with an address. */
9018d36e1dfSRoy Marples if (rtm->rtm_addrs & RTA_GATEWAY) {
9028d36e1dfSRoy Marples if (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) {
9038d36e1dfSRoy Marples const struct sockaddr_dl *sdl;
9048d36e1dfSRoy Marples
9058d36e1dfSRoy Marples sdl = (const struct sockaddr_dl*)
9068d36e1dfSRoy Marples (const void *)rti_info[RTAX_GATEWAY];
9078d36e1dfSRoy Marples if (sdl->sdl_alen != 0)
9088d36e1dfSRoy Marples rt->rt_dflags |= RTDF_GATELINK;
9098d36e1dfSRoy Marples } else if (rtm->rtm_flags & RTF_GATEWAY)
9107827cba2SAaron LI if_copysa(&rt->rt_gateway, rti_info[RTAX_GATEWAY]);
9118d36e1dfSRoy Marples }
9128d36e1dfSRoy Marples
9137827cba2SAaron LI if (rtm->rtm_addrs & RTA_IFA)
9147827cba2SAaron LI if_copysa(&rt->rt_ifa, rti_info[RTAX_IFA]);
9158d36e1dfSRoy Marples
9167827cba2SAaron LI rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
9177827cba2SAaron LI
9187827cba2SAaron LI if (rtm->rtm_index)
9197827cba2SAaron LI rt->rt_ifp = if_findindex(ctx->ifaces, rtm->rtm_index);
9207827cba2SAaron LI else if (rtm->rtm_addrs & RTA_IFP)
9217827cba2SAaron LI rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_IFP]);
9227827cba2SAaron LI else if (rtm->rtm_addrs & RTA_GATEWAY)
9237827cba2SAaron LI rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_GATEWAY]);
9247827cba2SAaron LI else
9257827cba2SAaron LI rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_DST]);
9267827cba2SAaron LI
9278d36e1dfSRoy Marples if (rt->rt_ifp == NULL && rtm->rtm_type == RTM_MISS)
9288d36e1dfSRoy Marples rt->rt_ifp = if_find(ctx->ifaces, "lo0");
9298d36e1dfSRoy Marples
9307827cba2SAaron LI if (rt->rt_ifp == NULL) {
9317827cba2SAaron LI errno = ESRCH;
9327827cba2SAaron LI return -1;
9337827cba2SAaron LI }
9347827cba2SAaron LI return 0;
9357827cba2SAaron LI }
9367827cba2SAaron LI
93780aa9461SRoy Marples static int
if_sysctl(struct dhcpcd_ctx * ctx,const int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)93880aa9461SRoy Marples if_sysctl(struct dhcpcd_ctx *ctx,
93980aa9461SRoy Marples const int *name, u_int namelen,
94080aa9461SRoy Marples void *oldp, size_t *oldlenp, void *newp, size_t newlen)
94180aa9461SRoy Marples {
94280aa9461SRoy Marples #if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
94380aa9461SRoy Marples if (IN_PRIVSEP(ctx))
94480aa9461SRoy Marples return (int)ps_root_sysctl(ctx, name, namelen,
94580aa9461SRoy Marples oldp, oldlenp, newp, newlen);
94680aa9461SRoy Marples #else
94780aa9461SRoy Marples UNUSED(ctx);
94880aa9461SRoy Marples #endif
94980aa9461SRoy Marples
95080aa9461SRoy Marples return sysctl(name, namelen, oldp, oldlenp, newp, newlen);
95180aa9461SRoy Marples }
95280aa9461SRoy Marples
9537827cba2SAaron LI int
if_initrt(struct dhcpcd_ctx * ctx,rb_tree_t * kroutes,int af)9548d36e1dfSRoy Marples if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af)
9557827cba2SAaron LI {
9567827cba2SAaron LI struct rt_msghdr *rtm;
95780aa9461SRoy Marples int mib[6] = { CTL_NET, PF_ROUTE, 0, af, NET_RT_DUMP, 0 };
95880aa9461SRoy Marples size_t bufl;
9597827cba2SAaron LI char *buf, *p, *end;
9608d36e1dfSRoy Marples struct rt rt, *rtn;
9617827cba2SAaron LI
96280aa9461SRoy Marples if (if_sysctl(ctx, mib, __arraycount(mib), NULL, &bufl, NULL, 0) == -1)
9637827cba2SAaron LI return -1;
96480aa9461SRoy Marples if (bufl == 0)
9657827cba2SAaron LI return 0;
96680aa9461SRoy Marples if ((buf = malloc(bufl)) == NULL)
9677827cba2SAaron LI return -1;
96880aa9461SRoy Marples if (if_sysctl(ctx, mib, __arraycount(mib), buf, &bufl, NULL, 0) == -1)
96980aa9461SRoy Marples {
9707827cba2SAaron LI free(buf);
9717827cba2SAaron LI return -1;
9727827cba2SAaron LI }
9737827cba2SAaron LI
97480aa9461SRoy Marples end = buf + bufl;
9757827cba2SAaron LI for (p = buf; p < end; p += rtm->rtm_msglen) {
9767827cba2SAaron LI rtm = (void *)p;
97780aa9461SRoy Marples if (p + sizeof(*rtm) > end || p + rtm->rtm_msglen > end) {
9788d36e1dfSRoy Marples errno = EINVAL;
9798d36e1dfSRoy Marples break;
9807827cba2SAaron LI }
9816e63cc1fSRoy Marples if (!if_realroute(rtm))
9826e63cc1fSRoy Marples continue;
9838d36e1dfSRoy Marples if (if_copyrt(ctx, &rt, rtm) != 0)
9848d36e1dfSRoy Marples continue;
9858d36e1dfSRoy Marples if ((rtn = rt_new(rt.rt_ifp)) == NULL) {
9868d36e1dfSRoy Marples logerr(__func__);
9878d36e1dfSRoy Marples break;
9888d36e1dfSRoy Marples }
9898d36e1dfSRoy Marples memcpy(rtn, &rt, sizeof(*rtn));
9908d36e1dfSRoy Marples if (rb_tree_insert_node(kroutes, rtn) != rtn)
9918d36e1dfSRoy Marples rt_free(rtn);
9927827cba2SAaron LI }
9937827cba2SAaron LI free(buf);
9948d36e1dfSRoy Marples return p == end ? 0 : -1;
9957827cba2SAaron LI }
9967827cba2SAaron LI
9977827cba2SAaron LI #ifdef INET
9987827cba2SAaron LI int
if_address(unsigned char cmd,const struct ipv4_addr * ia)9997827cba2SAaron LI if_address(unsigned char cmd, const struct ipv4_addr *ia)
10007827cba2SAaron LI {
10017827cba2SAaron LI int r;
10027827cba2SAaron LI struct in_aliasreq ifra;
10036e63cc1fSRoy Marples struct dhcpcd_ctx *ctx = ia->iface->ctx;
10047827cba2SAaron LI
10057827cba2SAaron LI memset(&ifra, 0, sizeof(ifra));
10067827cba2SAaron LI strlcpy(ifra.ifra_name, ia->iface->name, sizeof(ifra.ifra_name));
10077827cba2SAaron LI
10087827cba2SAaron LI #define ADDADDR(var, addr) do { \
10097827cba2SAaron LI (var)->sin_family = AF_INET; \
10107827cba2SAaron LI (var)->sin_len = sizeof(*(var)); \
10117827cba2SAaron LI (var)->sin_addr = *(addr); \
10127827cba2SAaron LI } while (/*CONSTCOND*/0)
10137827cba2SAaron LI ADDADDR(&ifra.ifra_addr, &ia->addr);
10147827cba2SAaron LI ADDADDR(&ifra.ifra_mask, &ia->mask);
10157827cba2SAaron LI if (cmd == RTM_NEWADDR && ia->brd.s_addr != INADDR_ANY)
10167827cba2SAaron LI ADDADDR(&ifra.ifra_broadaddr, &ia->brd);
10177827cba2SAaron LI #undef ADDADDR
10187827cba2SAaron LI
10196e63cc1fSRoy Marples r = if_ioctl(ctx,
10206e63cc1fSRoy Marples cmd == RTM_DELADDR ? SIOCDIFADDR : SIOCAIFADDR, &ifra,sizeof(ifra));
10217827cba2SAaron LI return r;
10227827cba2SAaron LI }
10237827cba2SAaron LI
10247827cba2SAaron LI #if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS))
10257827cba2SAaron LI int
if_addrflags(const struct interface * ifp,const struct in_addr * addr,__unused const char * alias)10267827cba2SAaron LI if_addrflags(const struct interface *ifp, const struct in_addr *addr,
10277827cba2SAaron LI __unused const char *alias)
10287827cba2SAaron LI {
10297827cba2SAaron LI #ifdef SIOCGIFAFLAG_IN
10307827cba2SAaron LI struct ifreq ifr;
10317827cba2SAaron LI struct sockaddr_in *sin;
10327827cba2SAaron LI
10337827cba2SAaron LI memset(&ifr, 0, sizeof(ifr));
10347827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
10357827cba2SAaron LI sin = (void *)&ifr.ifr_addr;
10367827cba2SAaron LI sin->sin_family = AF_INET;
10377827cba2SAaron LI sin->sin_addr = *addr;
10387827cba2SAaron LI if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFAFLAG_IN, &ifr) == -1)
10397827cba2SAaron LI return -1;
10407827cba2SAaron LI return ifr.ifr_addrflags;
10417827cba2SAaron LI #else
10427827cba2SAaron LI UNUSED(ifp);
10437827cba2SAaron LI UNUSED(addr);
10447827cba2SAaron LI return 0;
10457827cba2SAaron LI #endif
10467827cba2SAaron LI }
10477827cba2SAaron LI #endif
10487827cba2SAaron LI #endif /* INET */
10497827cba2SAaron LI
10507827cba2SAaron LI #ifdef INET6
10516e63cc1fSRoy Marples static int
if_ioctl6(struct dhcpcd_ctx * ctx,unsigned long req,void * data,size_t len)10526e63cc1fSRoy Marples if_ioctl6(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
10536e63cc1fSRoy Marples {
10546e63cc1fSRoy Marples struct priv *priv;
10556e63cc1fSRoy Marples
10566e63cc1fSRoy Marples #ifdef PRIVSEP
10576e63cc1fSRoy Marples if (ctx->options & DHCPCD_PRIVSEP)
10586e63cc1fSRoy Marples return (int)ps_root_ioctl6(ctx, req, data, len);
10596e63cc1fSRoy Marples #endif
10606e63cc1fSRoy Marples
10616e63cc1fSRoy Marples priv = ctx->priv;
10626e63cc1fSRoy Marples return ioctl(priv->pf_inet6_fd, req, data, len);
10636e63cc1fSRoy Marples }
10646e63cc1fSRoy Marples
10657827cba2SAaron LI int
if_address6(unsigned char cmd,const struct ipv6_addr * ia)10667827cba2SAaron LI if_address6(unsigned char cmd, const struct ipv6_addr *ia)
10677827cba2SAaron LI {
10687a0236bfSRoy Marples struct in6_aliasreq ifa = { .ifra_flags = 0 };
10697827cba2SAaron LI struct in6_addr mask;
10706e63cc1fSRoy Marples struct dhcpcd_ctx *ctx = ia->iface->ctx;
10717827cba2SAaron LI
10727827cba2SAaron LI strlcpy(ifa.ifra_name, ia->iface->name, sizeof(ifa.ifra_name));
10738d36e1dfSRoy Marples #if defined(__FreeBSD__) || defined(__DragonFly__)
10747a0236bfSRoy Marples /* This is a bug - the kernel should work this out. */
10758d36e1dfSRoy Marples if (ia->addr_flags & IN6_IFF_TENTATIVE)
10768d36e1dfSRoy Marples ifa.ifra_flags |= IN6_IFF_TENTATIVE;
10778d36e1dfSRoy Marples #endif
1078cc34ba0cSRoy Marples #if (defined(__NetBSD__) || defined(__OpenBSD__)) && \
1079cc34ba0cSRoy Marples (defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV))
1080cc34ba0cSRoy Marples /* These kernels don't accept userland setting IN6_IFF_AUTOCONF */
1081cc34ba0cSRoy Marples #else
10827a0236bfSRoy Marples if (ia->flags & IPV6_AF_AUTOCONF)
10837a0236bfSRoy Marples ifa.ifra_flags |= IN6_IFF_AUTOCONF;
10847a0236bfSRoy Marples #endif
1085280986e4SRoy Marples #ifdef IPV6_MANAGETEMPADDR
10867827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY)
10877827cba2SAaron LI ifa.ifra_flags |= IN6_IFF_TEMPORARY;
10887827cba2SAaron LI #endif
10897827cba2SAaron LI
10907827cba2SAaron LI #define ADDADDR(v, addr) { \
10917827cba2SAaron LI (v)->sin6_family = AF_INET6; \
10927827cba2SAaron LI (v)->sin6_len = sizeof(*v); \
10937827cba2SAaron LI (v)->sin6_addr = *(addr); \
10947827cba2SAaron LI }
10957827cba2SAaron LI
10967827cba2SAaron LI ADDADDR(&ifa.ifra_addr, &ia->addr);
1097d4fb1e02SRoy Marples ipv6_setscope(&ifa.ifra_addr, ia->iface->index);
10987827cba2SAaron LI ipv6_mask(&mask, ia->prefix_len);
10997827cba2SAaron LI ADDADDR(&ifa.ifra_prefixmask, &mask);
11007827cba2SAaron LI
11017827cba2SAaron LI #undef ADDADDR
11027827cba2SAaron LI
11037827cba2SAaron LI /*
11047827cba2SAaron LI * Every BSD kernel wants to add the prefix of the address to it's
11057827cba2SAaron LI * list of RA received prefixes.
11067827cba2SAaron LI * THIS IS WRONG because there (as the comments in the kernel state)
11077827cba2SAaron LI * is no API for managing prefix lifetime and the kernel should not
11087827cba2SAaron LI * pretend it's from a RA either.
11097827cba2SAaron LI *
11107827cba2SAaron LI * The issue is that the very first assigned prefix will inherit the
11117827cba2SAaron LI * lifetime of the address, but any subsequent alteration of the
11127827cba2SAaron LI * address OR it's lifetime will not affect the prefix lifetime.
11137827cba2SAaron LI * As such, we cannot stop the prefix from timing out and then
11147827cba2SAaron LI * constantly removing the prefix route dhcpcd is capable of adding
11157827cba2SAaron LI * in it's absense.
11167827cba2SAaron LI *
11177827cba2SAaron LI * What we can do to mitigate the issue is to add the address with
11187827cba2SAaron LI * infinite lifetimes, so the prefix route will never time out.
11197827cba2SAaron LI * Once done, we can then set lifetimes on the address and all is good.
11207827cba2SAaron LI * The downside of this approach is that we need to manually remove
11217827cba2SAaron LI * the kernel route because it has no lifetime, but this is OK as
11227827cba2SAaron LI * dhcpcd will handle this too.
11237827cba2SAaron LI *
11247827cba2SAaron LI * This issue is discussed on the NetBSD mailing lists here:
11257827cba2SAaron LI * http://mail-index.netbsd.org/tech-net/2016/08/05/msg006044.html
11267827cba2SAaron LI *
11277827cba2SAaron LI * Fixed in NetBSD-7.99.36
11287827cba2SAaron LI * NOT fixed in FreeBSD - bug 195197
11297827cba2SAaron LI * Fixed in OpenBSD-5.9
11307827cba2SAaron LI */
11317827cba2SAaron LI
11327827cba2SAaron LI #if !((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003600) || \
11337827cba2SAaron LI (defined(__OpenBSD__) && OpenBSD >= 201605))
11347827cba2SAaron LI if (cmd == RTM_NEWADDR && !(ia->flags & IPV6_AF_ADDED)) {
11357827cba2SAaron LI ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
11367827cba2SAaron LI ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
11376e63cc1fSRoy Marples (void)if_ioctl6(ctx, SIOCAIFADDR_IN6, &ifa, sizeof(ifa));
11387827cba2SAaron LI }
11397827cba2SAaron LI #endif
11407827cba2SAaron LI
11417827cba2SAaron LI #if defined(__OpenBSD__) && OpenBSD <= 201705
11427827cba2SAaron LI /* BUT OpenBSD older than 6.2 does not reset the address lifetime
11437827cba2SAaron LI * for subsequent calls...
11447827cba2SAaron LI * Luckily dhcpcd will remove the lease when it expires so
11457827cba2SAaron LI * just set an infinite lifetime, unless a temporary address. */
11467827cba2SAaron LI if (ifa.ifra_flags & IN6_IFF_PRIVACY) {
11477827cba2SAaron LI ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime;
11487827cba2SAaron LI ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime;
11497827cba2SAaron LI } else {
11507827cba2SAaron LI ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
11517827cba2SAaron LI ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
11527827cba2SAaron LI }
11537827cba2SAaron LI #else
11547827cba2SAaron LI ifa.ifra_lifetime.ia6t_vltime = ia->prefix_vltime;
11557827cba2SAaron LI ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime;
11567827cba2SAaron LI #endif
11577827cba2SAaron LI
11586e63cc1fSRoy Marples return if_ioctl6(ctx,
11596e63cc1fSRoy Marples cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6,
11606e63cc1fSRoy Marples &ifa, sizeof(ifa));
11617827cba2SAaron LI }
11627827cba2SAaron LI
11637827cba2SAaron LI int
if_addrflags6(const struct interface * ifp,const struct in6_addr * addr,__unused const char * alias)11647827cba2SAaron LI if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
11657827cba2SAaron LI __unused const char *alias)
11667827cba2SAaron LI {
11677827cba2SAaron LI int flags;
11687827cba2SAaron LI struct in6_ifreq ifr6;
11697827cba2SAaron LI struct priv *priv;
11707827cba2SAaron LI
11717827cba2SAaron LI memset(&ifr6, 0, sizeof(ifr6));
11727827cba2SAaron LI strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
11737827cba2SAaron LI ifr6.ifr_addr.sin6_family = AF_INET6;
11747827cba2SAaron LI ifr6.ifr_addr.sin6_addr = *addr;
1175d4fb1e02SRoy Marples ipv6_setscope(&ifr6.ifr_addr, ifp->index);
11767827cba2SAaron LI priv = (struct priv *)ifp->ctx->priv;
11777827cba2SAaron LI if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
11787827cba2SAaron LI flags = ifr6.ifr_ifru.ifru_flags6;
11797827cba2SAaron LI else
11807827cba2SAaron LI flags = -1;
11817827cba2SAaron LI return flags;
11827827cba2SAaron LI }
11837827cba2SAaron LI
11847827cba2SAaron LI int
if_getlifetime6(struct ipv6_addr * ia)11857827cba2SAaron LI if_getlifetime6(struct ipv6_addr *ia)
11867827cba2SAaron LI {
11877827cba2SAaron LI struct in6_ifreq ifr6;
11887827cba2SAaron LI time_t t;
11897827cba2SAaron LI struct in6_addrlifetime *lifetime;
11907827cba2SAaron LI struct priv *priv;
11917827cba2SAaron LI
11927827cba2SAaron LI memset(&ifr6, 0, sizeof(ifr6));
11937827cba2SAaron LI strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name));
11947827cba2SAaron LI ifr6.ifr_addr.sin6_family = AF_INET6;
11957827cba2SAaron LI ifr6.ifr_addr.sin6_addr = ia->addr;
1196d4fb1e02SRoy Marples ipv6_setscope(&ifr6.ifr_addr, ia->iface->index);
11977827cba2SAaron LI priv = (struct priv *)ia->iface->ctx->priv;
11987827cba2SAaron LI if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1)
11997827cba2SAaron LI return -1;
12008d36e1dfSRoy Marples clock_gettime(CLOCK_MONOTONIC, &ia->created);
12017827cba2SAaron LI
12028d36e1dfSRoy Marples #if defined(__FreeBSD__) || defined(__DragonFly__)
12038d36e1dfSRoy Marples t = ia->created.tv_sec;
12048d36e1dfSRoy Marples #else
12057827cba2SAaron LI t = time(NULL);
12068d36e1dfSRoy Marples #endif
12077827cba2SAaron LI
12088d36e1dfSRoy Marples lifetime = &ifr6.ifr_ifru.ifru_lifetime;
12097827cba2SAaron LI if (lifetime->ia6t_preferred)
12107827cba2SAaron LI ia->prefix_pltime = (uint32_t)(lifetime->ia6t_preferred -
12117827cba2SAaron LI MIN(t, lifetime->ia6t_preferred));
12127827cba2SAaron LI else
12137827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME;
12147827cba2SAaron LI if (lifetime->ia6t_expire) {
12157827cba2SAaron LI ia->prefix_vltime = (uint32_t)(lifetime->ia6t_expire -
12167827cba2SAaron LI MIN(t, lifetime->ia6t_expire));
12177827cba2SAaron LI /* Calculate the created time */
12187827cba2SAaron LI ia->created.tv_sec -= lifetime->ia6t_vltime - ia->prefix_vltime;
12197827cba2SAaron LI } else
12207827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME;
12217827cba2SAaron LI return 0;
12227827cba2SAaron LI }
12237827cba2SAaron LI #endif
12247827cba2SAaron LI
12258d36e1dfSRoy Marples static int
if_announce(struct dhcpcd_ctx * ctx,const struct if_announcemsghdr * ifan)12267827cba2SAaron LI if_announce(struct dhcpcd_ctx *ctx, const struct if_announcemsghdr *ifan)
12277827cba2SAaron LI {
12287827cba2SAaron LI
12298d36e1dfSRoy Marples if (ifan->ifan_msglen < sizeof(*ifan)) {
12308d36e1dfSRoy Marples errno = EINVAL;
12318d36e1dfSRoy Marples return -1;
12327827cba2SAaron LI }
12337827cba2SAaron LI
12348d36e1dfSRoy Marples switch(ifan->ifan_what) {
12358d36e1dfSRoy Marples case IFAN_ARRIVAL:
12368d36e1dfSRoy Marples return dhcpcd_handleinterface(ctx, 1, ifan->ifan_name);
12378d36e1dfSRoy Marples case IFAN_DEPARTURE:
12388d36e1dfSRoy Marples return dhcpcd_handleinterface(ctx, -1, ifan->ifan_name);
12398d36e1dfSRoy Marples }
12408d36e1dfSRoy Marples
12418d36e1dfSRoy Marples return 0;
12428d36e1dfSRoy Marples }
12438d36e1dfSRoy Marples
12448d36e1dfSRoy Marples static int
if_ifinfo(struct dhcpcd_ctx * ctx,const struct if_msghdr * ifm)12457827cba2SAaron LI if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm)
12467827cba2SAaron LI {
12477827cba2SAaron LI struct interface *ifp;
12487827cba2SAaron LI int link_state;
12497827cba2SAaron LI
12508d36e1dfSRoy Marples if (ifm->ifm_msglen < sizeof(*ifm)) {
12518d36e1dfSRoy Marples errno = EINVAL;
12528d36e1dfSRoy Marples return -1;
12538d36e1dfSRoy Marples }
12548d36e1dfSRoy Marples
12557827cba2SAaron LI if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL)
12568d36e1dfSRoy Marples return 0;
12578d36e1dfSRoy Marples
1258a0d9933aSRoy Marples link_state = if_carrier(ifp, &ifm->ifm_data);
1259a0d9933aSRoy Marples dhcpcd_handlecarrier(ifp, link_state, (unsigned int)ifm->ifm_flags);
12607827cba2SAaron LI return 0;
12617827cba2SAaron LI }
12627827cba2SAaron LI
12638d36e1dfSRoy Marples static int
if_rtm(struct dhcpcd_ctx * ctx,const struct rt_msghdr * rtm)12647827cba2SAaron LI if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
12657827cba2SAaron LI {
12667827cba2SAaron LI struct rt rt;
12677827cba2SAaron LI
12688d36e1dfSRoy Marples if (rtm->rtm_msglen < sizeof(*rtm)) {
12698d36e1dfSRoy Marples errno = EINVAL;
12708d36e1dfSRoy Marples return -1;
12718d36e1dfSRoy Marples }
12727827cba2SAaron LI
12737827cba2SAaron LI /* Ignore errors. */
12747827cba2SAaron LI if (rtm->rtm_errno != 0)
12758d36e1dfSRoy Marples return 0;
12767827cba2SAaron LI
12776e63cc1fSRoy Marples /* Ignore messages from ourself. */
12786e63cc1fSRoy Marples #ifdef PRIVSEP
127980aa9461SRoy Marples if (ctx->ps_root != NULL) {
128080aa9461SRoy Marples if (rtm->rtm_pid == ctx->ps_root->psp_pid)
12816e63cc1fSRoy Marples return 0;
12826e63cc1fSRoy Marples }
12836e63cc1fSRoy Marples #endif
12846e63cc1fSRoy Marples
12857827cba2SAaron LI if (if_copyrt(ctx, &rt, rtm) == -1)
12868d36e1dfSRoy Marples return errno == ENOTSUP ? 0 : -1;
12877827cba2SAaron LI
12887827cba2SAaron LI #ifdef INET6
12897827cba2SAaron LI /*
12907827cba2SAaron LI * BSD announces host routes.
12917827cba2SAaron LI * As such, we should be notified of reachability by its
12927827cba2SAaron LI * existance with a hardware address.
12938d36e1dfSRoy Marples * Ensure we don't call this for a newly incomplete state.
12947827cba2SAaron LI */
12958d36e1dfSRoy Marples if (rt.rt_dest.sa_family == AF_INET6 &&
12968d36e1dfSRoy Marples (rt.rt_flags & RTF_HOST || rtm->rtm_type == RTM_MISS) &&
12978d36e1dfSRoy Marples !(rtm->rtm_type == RTM_ADD && !(rt.rt_dflags & RTDF_GATELINK)))
12988d36e1dfSRoy Marples {
12998d36e1dfSRoy Marples bool reachable;
13007827cba2SAaron LI
13018d36e1dfSRoy Marples reachable = (rtm->rtm_type == RTM_ADD ||
13028d36e1dfSRoy Marples rtm->rtm_type == RTM_CHANGE) &&
13038d36e1dfSRoy Marples rt.rt_dflags & RTDF_GATELINK;
13048d36e1dfSRoy Marples ipv6nd_neighbour(ctx, &rt.rt_ss_dest.sin6.sin6_addr, reachable);
13057827cba2SAaron LI }
13067827cba2SAaron LI #endif
13077827cba2SAaron LI
13086e63cc1fSRoy Marples if (rtm->rtm_type != RTM_MISS && if_realroute(rtm))
13098d36e1dfSRoy Marples rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
13108d36e1dfSRoy Marples return 0;
13117827cba2SAaron LI }
13127827cba2SAaron LI
13138d36e1dfSRoy Marples static int
if_ifa(struct dhcpcd_ctx * ctx,const struct ifa_msghdr * ifam)13147827cba2SAaron LI if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
13157827cba2SAaron LI {
13167827cba2SAaron LI struct interface *ifp;
13177827cba2SAaron LI const struct sockaddr *rti_info[RTAX_MAX];
13186e63cc1fSRoy Marples int flags;
13197827cba2SAaron LI pid_t pid;
13207827cba2SAaron LI
13218d36e1dfSRoy Marples if (ifam->ifam_msglen < sizeof(*ifam)) {
13228d36e1dfSRoy Marples errno = EINVAL;
13238d36e1dfSRoy Marples return -1;
13248d36e1dfSRoy Marples }
13256e63cc1fSRoy Marples
13266e63cc1fSRoy Marples #ifdef HAVE_IFAM_PID
13276e63cc1fSRoy Marples /* Ignore address deletions from ourself.
13286e63cc1fSRoy Marples * We need to process address flag changes though. */
13296e63cc1fSRoy Marples if (ifam->ifam_type == RTM_DELADDR) {
13306e63cc1fSRoy Marples #ifdef PRIVSEP
133180aa9461SRoy Marples if (ctx->ps_root != NULL) {
133280aa9461SRoy Marples if (ifam->ifam_pid == ctx->ps_root->psp_pid)
13336e63cc1fSRoy Marples return 0;
13346e63cc1fSRoy Marples } else
13356e63cc1fSRoy Marples #endif
13366e63cc1fSRoy Marples /* address management is done via ioctl,
13376e63cc1fSRoy Marples * so SO_USELOOPBACK has no effect,
13386e63cc1fSRoy Marples * so we do need to check the pid. */
13396e63cc1fSRoy Marples if (ifam->ifam_pid == getpid())
13406e63cc1fSRoy Marples return 0;
13416e63cc1fSRoy Marples }
13426e63cc1fSRoy Marples pid = ifam->ifam_pid;
13436e63cc1fSRoy Marples #else
13446e63cc1fSRoy Marples pid = 0;
13456e63cc1fSRoy Marples #endif
13466e63cc1fSRoy Marples
13478d36e1dfSRoy Marples if (~ifam->ifam_addrs & RTA_IFA)
13488d36e1dfSRoy Marples return 0;
13497827cba2SAaron LI if ((ifp = if_findindex(ctx->ifaces, ifam->ifam_index)) == NULL)
13508d36e1dfSRoy Marples return 0;
13518d36e1dfSRoy Marples
13528d36e1dfSRoy Marples if (get_addrs(ifam->ifam_addrs, (const char *)ifam + sizeof(*ifam),
13538d36e1dfSRoy Marples ifam->ifam_msglen - sizeof(*ifam), rti_info) == -1)
13548d36e1dfSRoy Marples return -1;
13557827cba2SAaron LI
1356f3744ac9SRoy Marples /* All BSD's set IFF_UP on the interface when adding an address.
1357f3744ac9SRoy Marples * But not all BSD's emit this via RTM_IFINFO when they do this ... */
1358f3744ac9SRoy Marples if (ifam->ifam_type == RTM_NEWADDR && !(ifp->flags & IFF_UP))
1359f3744ac9SRoy Marples dhcpcd_handlecarrier(ifp, ifp->carrier, ifp->flags | IFF_UP);
1360f3744ac9SRoy Marples
13617827cba2SAaron LI switch (rti_info[RTAX_IFA]->sa_family) {
13627827cba2SAaron LI case AF_LINK:
13637827cba2SAaron LI {
13647827cba2SAaron LI struct sockaddr_dl sdl;
13657827cba2SAaron LI
13667827cba2SAaron LI #ifdef RTM_CHGADDR
13677827cba2SAaron LI if (ifam->ifam_type != RTM_CHGADDR)
13687827cba2SAaron LI break;
13697827cba2SAaron LI #else
13707827cba2SAaron LI if (ifam->ifam_type != RTM_NEWADDR)
13717827cba2SAaron LI break;
13727827cba2SAaron LI #endif
13737827cba2SAaron LI memcpy(&sdl, rti_info[RTAX_IFA], rti_info[RTAX_IFA]->sa_len);
1374d4fb1e02SRoy Marples dhcpcd_handlehwaddr(ifp, ifp->hwtype,
1375d4fb1e02SRoy Marples CLLADDR(&sdl), sdl.sdl_alen);
13767827cba2SAaron LI break;
13777827cba2SAaron LI }
13787827cba2SAaron LI #ifdef INET
13797827cba2SAaron LI case AF_INET:
13807827cba2SAaron LI case 255: /* FIXME: Why 255? */
13817827cba2SAaron LI {
13827827cba2SAaron LI const struct sockaddr_in *sin;
13837827cba2SAaron LI struct in_addr addr, mask, bcast;
13847827cba2SAaron LI
13857827cba2SAaron LI sin = (const void *)rti_info[RTAX_IFA];
13867827cba2SAaron LI addr.s_addr = sin != NULL && sin->sin_family == AF_INET ?
13877827cba2SAaron LI sin->sin_addr.s_addr : INADDR_ANY;
13887827cba2SAaron LI sin = (const void *)rti_info[RTAX_NETMASK];
13897827cba2SAaron LI mask.s_addr = sin != NULL && sin->sin_family == AF_INET ?
13907827cba2SAaron LI sin->sin_addr.s_addr : INADDR_ANY;
13918d36e1dfSRoy Marples sin = (const void *)rti_info[RTAX_BRD];
13928d36e1dfSRoy Marples bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ?
13938d36e1dfSRoy Marples sin->sin_addr.s_addr : INADDR_ANY;
13947827cba2SAaron LI
13958d36e1dfSRoy Marples /*
13968d36e1dfSRoy Marples * NetBSD-7 and older send an invalid broadcast address.
13977827cba2SAaron LI * So we need to query the actual address to get
13988d36e1dfSRoy Marples * the right one.
13996e63cc1fSRoy Marples * We can also use this to test if the address
14006e63cc1fSRoy Marples * has really been added or deleted.
14018d36e1dfSRoy Marples */
14028d36e1dfSRoy Marples #ifdef SIOCGIFALIAS
14037827cba2SAaron LI struct in_aliasreq ifra;
14047827cba2SAaron LI
14057827cba2SAaron LI memset(&ifra, 0, sizeof(ifra));
14066e63cc1fSRoy Marples strlcpy(ifra.ifra_name, ifp->name, sizeof(ifra.ifra_name));
14077827cba2SAaron LI ifra.ifra_addr.sin_family = AF_INET;
14087827cba2SAaron LI ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr);
14097827cba2SAaron LI ifra.ifra_addr.sin_addr = addr;
14107827cba2SAaron LI if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) {
14118d36e1dfSRoy Marples if (errno != ENXIO && errno != EADDRNOTAVAIL)
14127827cba2SAaron LI logerr("%s: SIOCGIFALIAS", __func__);
14138d36e1dfSRoy Marples if (ifam->ifam_type != RTM_DELADDR)
14147827cba2SAaron LI break;
14156e63cc1fSRoy Marples } else {
14166e63cc1fSRoy Marples if (ifam->ifam_type == RTM_DELADDR)
14176e63cc1fSRoy Marples break;
14188d36e1dfSRoy Marples #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
14197827cba2SAaron LI bcast = ifra.ifra_broadaddr.sin_addr;
14207827cba2SAaron LI #endif
14216e63cc1fSRoy Marples }
14228d36e1dfSRoy Marples #else
14238d36e1dfSRoy Marples #warning No SIOCGIFALIAS support
14248d36e1dfSRoy Marples /*
14258d36e1dfSRoy Marples * No SIOCGIFALIAS? That sucks!
14268d36e1dfSRoy Marples * This makes this call very heavy weight, but we
14278d36e1dfSRoy Marples * really need to know if the message is late or not.
14288d36e1dfSRoy Marples */
14298d36e1dfSRoy Marples const struct sockaddr *sa;
14308d36e1dfSRoy Marples struct ifaddrs *ifaddrs = NULL, *ifa;
14317827cba2SAaron LI
14328d36e1dfSRoy Marples sa = rti_info[RTAX_IFA];
14337f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
14347f8103cdSRoy Marples if (IN_PRIVSEP(ctx)) {
14357f8103cdSRoy Marples if (ps_root_getifaddrs(ctx, &ifaddrs) == -1) {
14367f8103cdSRoy Marples logerr("ps_root_getifaddrs");
14377f8103cdSRoy Marples break;
14387f8103cdSRoy Marples }
14397f8103cdSRoy Marples } else
14407f8103cdSRoy Marples #endif
14417f8103cdSRoy Marples if (getifaddrs(&ifaddrs) == -1) {
14427f8103cdSRoy Marples logerr("getifaddrs");
14437f8103cdSRoy Marples break;
14447f8103cdSRoy Marples }
14458d36e1dfSRoy Marples for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
14468d36e1dfSRoy Marples if (ifa->ifa_addr == NULL)
14478d36e1dfSRoy Marples continue;
14488d36e1dfSRoy Marples if (sa_cmp(ifa->ifa_addr, sa) == 0 &&
14498d36e1dfSRoy Marples strcmp(ifa->ifa_name, ifp->name) == 0)
14507827cba2SAaron LI break;
14517827cba2SAaron LI }
14527f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
14537f8103cdSRoy Marples if (IN_PRIVSEP(ctx))
14547f8103cdSRoy Marples free(ifaddrs);
14557f8103cdSRoy Marples else
14567f8103cdSRoy Marples #endif
14578d36e1dfSRoy Marples freeifaddrs(ifaddrs);
14586e63cc1fSRoy Marples if (ifam->ifam_type == RTM_DELADDR) {
14598d36e1dfSRoy Marples if (ifa != NULL)
14606e63cc1fSRoy Marples break;
14616e63cc1fSRoy Marples } else {
14626e63cc1fSRoy Marples if (ifa == NULL)
14637827cba2SAaron LI break;
14647827cba2SAaron LI }
14657827cba2SAaron LI #endif
14667827cba2SAaron LI
14676e63cc1fSRoy Marples #ifdef HAVE_IFAM_ADDRFLAGS
14686e63cc1fSRoy Marples flags = ifam->ifam_addrflags;
14696e63cc1fSRoy Marples #else
14706e63cc1fSRoy Marples flags = 0;
14716e63cc1fSRoy Marples #endif
14726e63cc1fSRoy Marples
14737827cba2SAaron LI ipv4_handleifa(ctx, ifam->ifam_type, NULL, ifp->name,
14746e63cc1fSRoy Marples &addr, &mask, &bcast, flags, pid);
14757827cba2SAaron LI break;
14767827cba2SAaron LI }
14777827cba2SAaron LI #endif
14787827cba2SAaron LI #ifdef INET6
14797827cba2SAaron LI case AF_INET6:
14807827cba2SAaron LI {
14817827cba2SAaron LI struct in6_addr addr6, mask6;
14827827cba2SAaron LI const struct sockaddr_in6 *sin6;
14837827cba2SAaron LI
14847827cba2SAaron LI sin6 = (const void *)rti_info[RTAX_IFA];
14857827cba2SAaron LI addr6 = sin6->sin6_addr;
14867827cba2SAaron LI sin6 = (const void *)rti_info[RTAX_NETMASK];
14877827cba2SAaron LI mask6 = sin6->sin6_addr;
14887827cba2SAaron LI
14898d36e1dfSRoy Marples /*
14908d36e1dfSRoy Marples * If the address was deleted, lets check if it's
14918d36e1dfSRoy Marples * a late message and it still exists (maybe modified).
14928d36e1dfSRoy Marples * If so, ignore it as deleting an address causes
14938d36e1dfSRoy Marples * dhcpcd to drop any lease to which it belongs.
14946e63cc1fSRoy Marples * Also check an added address was really added.
14958d36e1dfSRoy Marples */
14968d36e1dfSRoy Marples flags = if_addrflags6(ifp, &addr6, NULL);
14976e63cc1fSRoy Marples if (flags == -1) {
14986e63cc1fSRoy Marples if (errno != ENXIO && errno != EADDRNOTAVAIL)
14997827cba2SAaron LI logerr("%s: if_addrflags6", __func__);
15006e63cc1fSRoy Marples if (ifam->ifam_type != RTM_DELADDR)
15017827cba2SAaron LI break;
15026e63cc1fSRoy Marples flags = 0;
15036e63cc1fSRoy Marples } else if (ifam->ifam_type == RTM_DELADDR)
15046e63cc1fSRoy Marples break;
15057827cba2SAaron LI
15067827cba2SAaron LI #ifdef __KAME__
15077827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&addr6))
15087827cba2SAaron LI /* Remove the scope from the address */
15097827cba2SAaron LI addr6.s6_addr[2] = addr6.s6_addr[3] = '\0';
15107827cba2SAaron LI #endif
15117827cba2SAaron LI
15127827cba2SAaron LI ipv6_handleifa(ctx, ifam->ifam_type, NULL,
15136e63cc1fSRoy Marples ifp->name, &addr6, ipv6_prefixlen(&mask6), flags, pid);
15147827cba2SAaron LI break;
15157827cba2SAaron LI }
15167827cba2SAaron LI #endif
15177827cba2SAaron LI }
15188d36e1dfSRoy Marples
15198d36e1dfSRoy Marples return 0;
15207827cba2SAaron LI }
15217827cba2SAaron LI
15228d36e1dfSRoy Marples static int
if_dispatch(struct dhcpcd_ctx * ctx,const struct rt_msghdr * rtm)15237827cba2SAaron LI if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
15247827cba2SAaron LI {
15257827cba2SAaron LI
15267827cba2SAaron LI if (rtm->rtm_version != RTM_VERSION)
15278d36e1dfSRoy Marples return 0;
15287827cba2SAaron LI
15297827cba2SAaron LI switch(rtm->rtm_type) {
15307827cba2SAaron LI #ifdef RTM_IFANNOUNCE
15317827cba2SAaron LI case RTM_IFANNOUNCE:
15328d36e1dfSRoy Marples return if_announce(ctx, (const void *)rtm);
15337827cba2SAaron LI #endif
15347827cba2SAaron LI case RTM_IFINFO:
15358d36e1dfSRoy Marples return if_ifinfo(ctx, (const void *)rtm);
15367827cba2SAaron LI case RTM_ADD: /* FALLTHROUGH */
15377827cba2SAaron LI case RTM_CHANGE: /* FALLTHROUGH */
15388d36e1dfSRoy Marples case RTM_DELETE: /* FALLTHROUGH */
15398d36e1dfSRoy Marples case RTM_MISS:
15408d36e1dfSRoy Marples return if_rtm(ctx, (const void *)rtm);
15417827cba2SAaron LI #ifdef RTM_CHGADDR
15427827cba2SAaron LI case RTM_CHGADDR: /* FALLTHROUGH */
15437827cba2SAaron LI #endif
15447827cba2SAaron LI case RTM_DELADDR: /* FALLTHROUGH */
15457827cba2SAaron LI case RTM_NEWADDR:
15468d36e1dfSRoy Marples return if_ifa(ctx, (const void *)rtm);
15477827cba2SAaron LI #ifdef RTM_DESYNC
15487827cba2SAaron LI case RTM_DESYNC:
15497827cba2SAaron LI dhcpcd_linkoverflow(ctx);
15508d36e1dfSRoy Marples #elif !defined(SO_RERROR)
15518d36e1dfSRoy Marples #warning cannot detect route socket overflow within kernel
15527827cba2SAaron LI #endif
15537827cba2SAaron LI }
15548d36e1dfSRoy Marples
15558d36e1dfSRoy Marples return 0;
15567827cba2SAaron LI }
15577827cba2SAaron LI
15586e63cc1fSRoy Marples static int
if_missfilter0(struct dhcpcd_ctx * ctx,struct interface * ifp,struct sockaddr * sa)15596e63cc1fSRoy Marples if_missfilter0(struct dhcpcd_ctx *ctx, struct interface *ifp,
15606e63cc1fSRoy Marples struct sockaddr *sa)
15616e63cc1fSRoy Marples {
15626e63cc1fSRoy Marples size_t salen = (size_t)RT_ROUNDUP(sa->sa_len);
15636e63cc1fSRoy Marples size_t newlen = ctx->rt_missfilterlen + salen;
15646e63cc1fSRoy Marples size_t diff = salen - (sa->sa_len);
15656e63cc1fSRoy Marples uint8_t *cp;
15666e63cc1fSRoy Marples
15676e63cc1fSRoy Marples if (ctx->rt_missfiltersize < newlen) {
15686e63cc1fSRoy Marples void *n = realloc(ctx->rt_missfilter, newlen);
15696e63cc1fSRoy Marples if (n == NULL)
15706e63cc1fSRoy Marples return -1;
15716e63cc1fSRoy Marples ctx->rt_missfilter = n;
15726e63cc1fSRoy Marples ctx->rt_missfiltersize = newlen;
15736e63cc1fSRoy Marples }
15746e63cc1fSRoy Marples
15756e63cc1fSRoy Marples #ifdef INET6
15766e63cc1fSRoy Marples if (sa->sa_family == AF_INET6)
1577d4fb1e02SRoy Marples ipv6_setscope(satosin6(sa), ifp->index);
1578280986e4SRoy Marples #else
1579280986e4SRoy Marples UNUSED(ifp);
15806e63cc1fSRoy Marples #endif
15816e63cc1fSRoy Marples
15826e63cc1fSRoy Marples cp = ctx->rt_missfilter + ctx->rt_missfilterlen;
15836e63cc1fSRoy Marples memcpy(cp, sa, sa->sa_len);
15846e63cc1fSRoy Marples if (diff != 0)
15856e63cc1fSRoy Marples memset(cp + sa->sa_len, 0, diff);
15866e63cc1fSRoy Marples ctx->rt_missfilterlen += salen;
15876e63cc1fSRoy Marples
15886e63cc1fSRoy Marples #ifdef INET6
15896e63cc1fSRoy Marples if (sa->sa_family == AF_INET6)
1590d4fb1e02SRoy Marples ipv6_setscope(satosin6(sa), 0);
15916e63cc1fSRoy Marples #endif
15926e63cc1fSRoy Marples
15936e63cc1fSRoy Marples return 0;
15946e63cc1fSRoy Marples }
15956e63cc1fSRoy Marples
15966e63cc1fSRoy Marples int
if_missfilter(struct interface * ifp,struct sockaddr * sa)15976e63cc1fSRoy Marples if_missfilter(struct interface *ifp, struct sockaddr *sa)
15986e63cc1fSRoy Marples {
15996e63cc1fSRoy Marples
16006e63cc1fSRoy Marples return if_missfilter0(ifp->ctx, ifp, sa);
16016e63cc1fSRoy Marples }
16026e63cc1fSRoy Marples
16036e63cc1fSRoy Marples int
if_missfilter_apply(struct dhcpcd_ctx * ctx)16046e63cc1fSRoy Marples if_missfilter_apply(struct dhcpcd_ctx *ctx)
16056e63cc1fSRoy Marples {
16066e63cc1fSRoy Marples #ifdef RO_MISSFILTER
16076e63cc1fSRoy Marples if (ctx->rt_missfilterlen == 0) {
16086e63cc1fSRoy Marples struct sockaddr sa = {
16096e63cc1fSRoy Marples .sa_family = AF_UNSPEC,
16106e63cc1fSRoy Marples .sa_len = sizeof(sa),
16116e63cc1fSRoy Marples };
16126e63cc1fSRoy Marples
16136e63cc1fSRoy Marples if (if_missfilter0(ctx, NULL, &sa) == -1)
16146e63cc1fSRoy Marples return -1;
16156e63cc1fSRoy Marples }
16166e63cc1fSRoy Marples
16176e63cc1fSRoy Marples return setsockopt(ctx->link_fd, PF_ROUTE, RO_MISSFILTER,
16186e63cc1fSRoy Marples ctx->rt_missfilter, (socklen_t)ctx->rt_missfilterlen);
16196e63cc1fSRoy Marples #else
16206e63cc1fSRoy Marples #warning kernel does not support RTM_MISS DST filtering
16216e63cc1fSRoy Marples UNUSED(ctx);
16226e63cc1fSRoy Marples errno = ENOTSUP;
16236e63cc1fSRoy Marples return -1;
16246e63cc1fSRoy Marples #endif
16256e63cc1fSRoy Marples }
16266e63cc1fSRoy Marples
16278d36e1dfSRoy Marples __CTASSERT(offsetof(struct rt_msghdr, rtm_msglen) == 0);
16287827cba2SAaron LI int
if_handlelink(struct dhcpcd_ctx * ctx)16297827cba2SAaron LI if_handlelink(struct dhcpcd_ctx *ctx)
16307827cba2SAaron LI {
16318d36e1dfSRoy Marples struct rtm rtm;
16327827cba2SAaron LI ssize_t len;
16337827cba2SAaron LI
16348d36e1dfSRoy Marples len = read(ctx->link_fd, &rtm, sizeof(rtm));
16357827cba2SAaron LI if (len == -1)
16367827cba2SAaron LI return -1;
16378d36e1dfSRoy Marples if (len == 0)
16387827cba2SAaron LI return 0;
16398d36e1dfSRoy Marples if ((size_t)len < sizeof(rtm.hdr.rtm_msglen) ||
16408d36e1dfSRoy Marples len != rtm.hdr.rtm_msglen)
16418d36e1dfSRoy Marples {
16428d36e1dfSRoy Marples errno = EINVAL;
16438d36e1dfSRoy Marples return -1;
16448d36e1dfSRoy Marples }
16458d36e1dfSRoy Marples /*
16468d36e1dfSRoy Marples * Coverity thinks that the data could be tainted from here.
16478d36e1dfSRoy Marples * I have no idea how because the length of the data we read
16488d36e1dfSRoy Marples * is guarded by len and checked to match rtm_msglen.
16498d36e1dfSRoy Marples * The issue seems to be related to extracting the addresses
16508d36e1dfSRoy Marples * at the end of the header, but seems to have no issues with the
16518d36e1dfSRoy Marples * equivalent call in if_initrt.
16528d36e1dfSRoy Marples */
16538d36e1dfSRoy Marples /* coverity[tainted_data] */
16548d36e1dfSRoy Marples return if_dispatch(ctx, &rtm.hdr);
16557827cba2SAaron LI }
16567827cba2SAaron LI
16577827cba2SAaron LI #ifndef SYS_NMLN /* OSX */
1658d4fb1e02SRoy Marples # define SYS_NMLN __SYS_NAMELEN
16597827cba2SAaron LI #endif
16607827cba2SAaron LI #ifndef HW_MACHINE_ARCH
16617827cba2SAaron LI # ifdef HW_MODEL /* OpenBSD */
16627827cba2SAaron LI # define HW_MACHINE_ARCH HW_MODEL
16637827cba2SAaron LI # endif
16647827cba2SAaron LI #endif
16657827cba2SAaron LI int
if_machinearch(char * str,size_t len)16667827cba2SAaron LI if_machinearch(char *str, size_t len)
16677827cba2SAaron LI {
16687827cba2SAaron LI int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
16697827cba2SAaron LI
1670d4fb1e02SRoy Marples return sysctl(mib, sizeof(mib) / sizeof(mib[0]), str, &len, NULL, 0);
16717827cba2SAaron LI }
16727827cba2SAaron LI
16737827cba2SAaron LI #ifdef INET6
16747827cba2SAaron LI #if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) || \
16758d36e1dfSRoy Marples defined(IPV6CTL_FORWARDING)
16767827cba2SAaron LI #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
16777827cba2SAaron LI #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
16787827cba2SAaron LI static int
inet6_sysctl(int code,int val,int action)16797827cba2SAaron LI inet6_sysctl(int code, int val, int action)
16807827cba2SAaron LI {
16817827cba2SAaron LI int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
16827827cba2SAaron LI size_t size;
16837827cba2SAaron LI
16847827cba2SAaron LI mib[3] = code;
16857827cba2SAaron LI size = sizeof(val);
16867827cba2SAaron LI if (action) {
168780aa9461SRoy Marples if (sysctl(mib, __arraycount(mib), NULL, 0, &val, size) == -1)
16887827cba2SAaron LI return -1;
16897827cba2SAaron LI return 0;
16907827cba2SAaron LI }
169180aa9461SRoy Marples if (sysctl(mib, __arraycount(mib), &val, &size, NULL, 0) == -1)
16927827cba2SAaron LI return -1;
16937827cba2SAaron LI return val;
16947827cba2SAaron LI }
16957827cba2SAaron LI #endif
16967827cba2SAaron LI
1697b9ccd228SRoy Marples int
if_applyra(const struct ra * rap)1698b9ccd228SRoy Marples if_applyra(const struct ra *rap)
1699b9ccd228SRoy Marples {
1700b9ccd228SRoy Marples #ifdef SIOCSIFINFO_IN6
17016e63cc1fSRoy Marples struct in6_ndireq nd = { .ndi.chlim = 0 };
17026e63cc1fSRoy Marples struct dhcpcd_ctx *ctx = rap->iface->ctx;
1703b9ccd228SRoy Marples int error;
1704b9ccd228SRoy Marples
17056e63cc1fSRoy Marples strlcpy(nd.ifname, rap->iface->name, sizeof(nd.ifname));
1706d4fb1e02SRoy Marples
1707d4fb1e02SRoy Marples #ifdef IPV6CTL_ACCEPT_RTADV
1708d4fb1e02SRoy Marples struct priv *priv = ctx->priv;
1709d4fb1e02SRoy Marples
1710d4fb1e02SRoy Marples /*
1711d4fb1e02SRoy Marples * NetBSD changed SIOCSIFINFO_IN6 to NOT set flags when kernel
1712d4fb1e02SRoy Marples * RA was removed, however both FreeBSD and DragonFlyBSD still do.
1713d4fb1e02SRoy Marples * linkmtu was also removed.
1714d4fb1e02SRoy Marples * Hopefully this guard will still work if either remove kernel RA.
1715d4fb1e02SRoy Marples */
17166e63cc1fSRoy Marples if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &nd, sizeof(nd)) == -1)
1717b9ccd228SRoy Marples return -1;
1718b9ccd228SRoy Marples
17196e63cc1fSRoy Marples nd.ndi.linkmtu = rap->mtu;
1720d4fb1e02SRoy Marples #endif
1721d4fb1e02SRoy Marples
17226e63cc1fSRoy Marples nd.ndi.chlim = rap->hoplimit;
17236e63cc1fSRoy Marples nd.ndi.retrans = rap->retrans;
17246e63cc1fSRoy Marples nd.ndi.basereachable = rap->reachable;
17256e63cc1fSRoy Marples error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd));
1726d4fb1e02SRoy Marples #ifdef IPV6CTL_ACCEPT_RTADV
1727b9ccd228SRoy Marples if (error == -1 && errno == EINVAL) {
1728b9ccd228SRoy Marples /*
1729b9ccd228SRoy Marples * Very likely that this is caused by a dodgy MTU
1730b9ccd228SRoy Marples * setting specific to the interface.
1731b9ccd228SRoy Marples * Let's set it to "unspecified" and try again.
1732b9ccd228SRoy Marples * Doesn't really matter as we fix the MTU against the
1733b9ccd228SRoy Marples * routes we add as not all OS support SIOCSIFINFO_IN6.
1734b9ccd228SRoy Marples */
17356e63cc1fSRoy Marples nd.ndi.linkmtu = 0;
17366e63cc1fSRoy Marples error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd));
1737b9ccd228SRoy Marples }
1738d4fb1e02SRoy Marples #endif
1739b9ccd228SRoy Marples return error;
1740b9ccd228SRoy Marples #else
1741b9ccd228SRoy Marples #warning OS does not allow setting of RA bits hoplimit, retrans or reachable
1742b9ccd228SRoy Marples UNUSED(rap);
1743b9ccd228SRoy Marples return 0;
1744b9ccd228SRoy Marples #endif
1745b9ccd228SRoy Marples }
1746b9ccd228SRoy Marples
17477a0236bfSRoy Marples #ifndef IPV6CTL_FORWARDING
17487827cba2SAaron LI #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
17497827cba2SAaron LI #define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
17507827cba2SAaron LI static int
inet6_sysctlbyname(const char * name,int val,int action)17517827cba2SAaron LI inet6_sysctlbyname(const char *name, int val, int action)
17527827cba2SAaron LI {
17537827cba2SAaron LI size_t size;
17547827cba2SAaron LI
17557827cba2SAaron LI size = sizeof(val);
17567827cba2SAaron LI if (action) {
17577827cba2SAaron LI if (sysctlbyname(name, NULL, 0, &val, size) == -1)
17587827cba2SAaron LI return -1;
17597827cba2SAaron LI return 0;
17607827cba2SAaron LI }
17617827cba2SAaron LI if (sysctlbyname(name, &val, &size, NULL, 0) == -1)
17627827cba2SAaron LI return -1;
17637827cba2SAaron LI return val;
17647827cba2SAaron LI }
17657827cba2SAaron LI #endif
17667827cba2SAaron LI
17678d36e1dfSRoy Marples int
ip6_forwarding(__unused const char * ifname)17688d36e1dfSRoy Marples ip6_forwarding(__unused const char *ifname)
17698d36e1dfSRoy Marples {
17708d36e1dfSRoy Marples int val;
17718d36e1dfSRoy Marples
17728d36e1dfSRoy Marples #ifdef IPV6CTL_FORWARDING
17738d36e1dfSRoy Marples val = get_inet6_sysctl(IPV6CTL_FORWARDING);
17748d36e1dfSRoy Marples #else
17758d36e1dfSRoy Marples val = get_inet6_sysctlbyname("net.inet6.ip6.forwarding");
17768d36e1dfSRoy Marples #endif
17778d36e1dfSRoy Marples return val < 0 ? 0 : val;
17788d36e1dfSRoy Marples }
17798d36e1dfSRoy Marples
17807827cba2SAaron LI #ifdef SIOCIFAFATTACH
17817827cba2SAaron LI static int
if_af_attach(const struct interface * ifp,int af)17826e63cc1fSRoy Marples if_af_attach(const struct interface *ifp, int af)
17837827cba2SAaron LI {
1784f3744ac9SRoy Marples struct if_afreq ifar = { .ifar_af = af };
17857827cba2SAaron LI
17867827cba2SAaron LI strlcpy(ifar.ifar_name, ifp->name, sizeof(ifar.ifar_name));
17876e63cc1fSRoy Marples return if_ioctl6(ifp->ctx, SIOCIFAFATTACH, &ifar, sizeof(ifar));
17887827cba2SAaron LI }
17897827cba2SAaron LI #endif
17907827cba2SAaron LI
17917827cba2SAaron LI #ifdef SIOCGIFXFLAGS
17927827cba2SAaron LI static int
if_set_ifxflags(const struct interface * ifp)17936e63cc1fSRoy Marples if_set_ifxflags(const struct interface *ifp)
17947827cba2SAaron LI {
17957827cba2SAaron LI struct ifreq ifr;
17967827cba2SAaron LI int flags;
17976e63cc1fSRoy Marples struct priv *priv = ifp->ctx->priv;
17987827cba2SAaron LI
17997827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
18006e63cc1fSRoy Marples if (ioctl(priv->pf_inet6_fd, SIOCGIFXFLAGS, &ifr) == -1)
18017827cba2SAaron LI return -1;
18027827cba2SAaron LI flags = ifr.ifr_flags;
18037827cba2SAaron LI #ifdef IFXF_NOINET6
18047827cba2SAaron LI flags &= ~IFXF_NOINET6;
18057827cba2SAaron LI #endif
18067827cba2SAaron LI /*
18077827cba2SAaron LI * If not doing autoconf, don't disable the kernel from doing it.
18087827cba2SAaron LI * If we need to, we should have another option actively disable it.
18098d36e1dfSRoy Marples *
18108d36e1dfSRoy Marples * OpenBSD moved from kernel based SLAAC to userland via slaacd(8).
18118d36e1dfSRoy Marples * It has a similar featureset to dhcpcd such as stable private
18128d36e1dfSRoy Marples * addresses, but lacks the ability to handle DNS inside the RA
18138d36e1dfSRoy Marples * which is a serious shortfall in this day and age.
18148d36e1dfSRoy Marples * Appease their user base by working alongside slaacd(8) if
18158d36e1dfSRoy Marples * dhcpcd is instructed not to do auto configuration of addresses.
18167827cba2SAaron LI */
18178d36e1dfSRoy Marples #if defined(ND6_IFF_ACCEPT_RTADV)
18188d36e1dfSRoy Marples #define BSD_AUTOCONF DHCPCD_IPV6RS
18198d36e1dfSRoy Marples #else
18208d36e1dfSRoy Marples #define BSD_AUTOCONF DHCPCD_IPV6RA_AUTOCONF
18218d36e1dfSRoy Marples #endif
18228d36e1dfSRoy Marples if (ifp->options->options & BSD_AUTOCONF)
18237827cba2SAaron LI flags &= ~IFXF_AUTOCONF6;
18247827cba2SAaron LI if (ifr.ifr_flags == flags)
18257827cba2SAaron LI return 0;
18267827cba2SAaron LI ifr.ifr_flags = flags;
18276e63cc1fSRoy Marples return if_ioctl6(ifp->ctx, SIOCSIFXFLAGS, &ifr, sizeof(ifr));
18287827cba2SAaron LI }
18297827cba2SAaron LI #endif
18307827cba2SAaron LI
18317827cba2SAaron LI /* OpenBSD removed ND6 flags entirely, so we need to check for their
18327827cba2SAaron LI * existance. */
18337827cba2SAaron LI #if defined(ND6_IFF_AUTO_LINKLOCAL) || \
18347827cba2SAaron LI defined(ND6_IFF_PERFORMNUD) || \
18357827cba2SAaron LI defined(ND6_IFF_ACCEPT_RTADV) || \
18367827cba2SAaron LI defined(ND6_IFF_OVERRIDE_RTADV) || \
18377827cba2SAaron LI defined(ND6_IFF_IFDISABLED)
18387827cba2SAaron LI #define ND6_NDI_FLAGS
18397827cba2SAaron LI #endif
18407827cba2SAaron LI
18417827cba2SAaron LI void
if_disable_rtadv(void)1842b9ccd228SRoy Marples if_disable_rtadv(void)
1843b9ccd228SRoy Marples {
1844b9ccd228SRoy Marples #if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)
1845b9ccd228SRoy Marples int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV);
1846b9ccd228SRoy Marples
1847b9ccd228SRoy Marples if (ra == -1) {
1848b9ccd228SRoy Marples if (errno != ENOENT)
1849b9ccd228SRoy Marples logerr("IPV6CTL_ACCEPT_RTADV");
1850b9ccd228SRoy Marples else if (ra != 0)
1851b9ccd228SRoy Marples if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1)
1852b9ccd228SRoy Marples logerr("IPV6CTL_ACCEPT_RTADV");
1853b9ccd228SRoy Marples }
1854b9ccd228SRoy Marples #endif
1855b9ccd228SRoy Marples }
1856b9ccd228SRoy Marples
1857b9ccd228SRoy Marples void
if_setup_inet6(const struct interface * ifp)18587827cba2SAaron LI if_setup_inet6(const struct interface *ifp)
18597827cba2SAaron LI {
1860f3744ac9SRoy Marples #ifdef ND6_NDI_FLAGS
18617827cba2SAaron LI struct priv *priv;
18627827cba2SAaron LI int s;
18637827cba2SAaron LI struct in6_ndireq nd;
18647827cba2SAaron LI int flags;
18657827cba2SAaron LI
18667827cba2SAaron LI priv = (struct priv *)ifp->ctx->priv;
18677827cba2SAaron LI s = priv->pf_inet6_fd;
18687827cba2SAaron LI
18697827cba2SAaron LI memset(&nd, 0, sizeof(nd));
18707827cba2SAaron LI strlcpy(nd.ifname, ifp->name, sizeof(nd.ifname));
18717827cba2SAaron LI if (ioctl(s, SIOCGIFINFO_IN6, &nd) == -1)
18727827cba2SAaron LI logerr("%s: SIOCGIFINFO_FLAGS", ifp->name);
18737827cba2SAaron LI flags = (int)nd.ndi.flags;
18747827cba2SAaron LI
18757827cba2SAaron LI #ifdef ND6_IFF_AUTO_LINKLOCAL
1876d4fb1e02SRoy Marples /* Unlike the kernel, dhcpcd make make a stable private address. */
18777827cba2SAaron LI flags &= ~ND6_IFF_AUTO_LINKLOCAL;
18787827cba2SAaron LI #endif
18797827cba2SAaron LI
18807827cba2SAaron LI #ifdef ND6_IFF_PERFORMNUD
18817827cba2SAaron LI /* NUD is kind of essential. */
18827827cba2SAaron LI flags |= ND6_IFF_PERFORMNUD;
18837827cba2SAaron LI #endif
18847827cba2SAaron LI
18857827cba2SAaron LI #ifdef ND6_IFF_IFDISABLED
18867827cba2SAaron LI /* Ensure the interface is not disabled. */
18877827cba2SAaron LI flags &= ~ND6_IFF_IFDISABLED;
18887827cba2SAaron LI #endif
18897827cba2SAaron LI
18907827cba2SAaron LI /*
18917827cba2SAaron LI * If not doing autoconf, don't disable the kernel from doing it.
18927827cba2SAaron LI * If we need to, we should have another option actively disable it.
18937827cba2SAaron LI */
18947827cba2SAaron LI #ifdef ND6_IFF_ACCEPT_RTADV
18957827cba2SAaron LI if (ifp->options->options & DHCPCD_IPV6RS)
18967827cba2SAaron LI flags &= ~ND6_IFF_ACCEPT_RTADV;
18977827cba2SAaron LI #ifdef ND6_IFF_OVERRIDE_RTADV
18987827cba2SAaron LI if (ifp->options->options & DHCPCD_IPV6RS)
18997827cba2SAaron LI flags |= ND6_IFF_OVERRIDE_RTADV;
19007827cba2SAaron LI #endif
19017827cba2SAaron LI #endif
19027827cba2SAaron LI
19037827cba2SAaron LI if (nd.ndi.flags != (uint32_t)flags) {
19047827cba2SAaron LI nd.ndi.flags = (uint32_t)flags;
19056e63cc1fSRoy Marples if (if_ioctl6(ifp->ctx, SIOCSIFINFO_FLAGS,
19066e63cc1fSRoy Marples &nd, sizeof(nd)) == -1)
19077827cba2SAaron LI logerr("%s: SIOCSIFINFO_FLAGS", ifp->name);
19087827cba2SAaron LI }
1909f3744ac9SRoy Marples #endif /* ND6_NDI_FLAGS */
19107827cba2SAaron LI
19117827cba2SAaron LI /* Enabling IPv6 by whatever means must be the
19127827cba2SAaron LI * last action undertaken to ensure kernel RS and
19137827cba2SAaron LI * LLADDR auto configuration are disabled where applicable. */
19147827cba2SAaron LI #ifdef SIOCIFAFATTACH
19156e63cc1fSRoy Marples if (if_af_attach(ifp, AF_INET6) == -1)
19166e63cc1fSRoy Marples logerr("%s: if_af_attach", ifp->name);
19177827cba2SAaron LI #endif
19187827cba2SAaron LI
19197827cba2SAaron LI #ifdef SIOCGIFXFLAGS
19206e63cc1fSRoy Marples if (if_set_ifxflags(ifp) == -1)
19217827cba2SAaron LI logerr("%s: set_ifxflags", ifp->name);
19227827cba2SAaron LI #endif
19237827cba2SAaron LI
19247a0236bfSRoy Marples #ifdef SIOCSRTRFLUSH_IN6
19257827cba2SAaron LI /* Flush the kernel knowledge of advertised routers
19267827cba2SAaron LI * and prefixes so the kernel does not expire prefixes
19277827cba2SAaron LI * and default routes we are trying to own. */
19287827cba2SAaron LI if (ifp->options->options & DHCPCD_IPV6RS) {
19298d36e1dfSRoy Marples struct in6_ifreq ifr;
19307827cba2SAaron LI
19318d36e1dfSRoy Marples memset(&ifr, 0, sizeof(ifr));
19328d36e1dfSRoy Marples strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
19336e63cc1fSRoy Marples if (if_ioctl6(ifp->ctx, SIOCSRTRFLUSH_IN6,
19346e63cc1fSRoy Marples &ifr, sizeof(ifr)) == -1 &&
19357a0236bfSRoy Marples errno != ENOTSUP && errno != ENOTTY)
19367a0236bfSRoy Marples logwarn("SIOCSRTRFLUSH_IN6 %d", errno);
19377a0236bfSRoy Marples #ifdef SIOCSPFXFLUSH_IN6
19386e63cc1fSRoy Marples if (if_ioctl6(ifp->ctx, SIOCSPFXFLUSH_IN6,
19396e63cc1fSRoy Marples &ifr, sizeof(ifr)) == -1 &&
19407a0236bfSRoy Marples errno != ENOTSUP && errno != ENOTTY)
19417827cba2SAaron LI logwarn("SIOCSPFXFLUSH_IN6");
19427a0236bfSRoy Marples #endif
19437827cba2SAaron LI }
19447827cba2SAaron LI #endif
19457827cba2SAaron LI }
19467827cba2SAaron LI #endif
1947