1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * BSD interface driver for dhcpcd
4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/ioctl.h>
30 #include <sys/param.h>
31 #include <sys/socket.h>
33 #include <sys/sysctl.h>
35 #include <sys/types.h>
37 #include <sys/utsname.h>
41 #include <arpa/inet.h>
44 #include <net/if_dl.h>
45 #include <net/if_media.h>
46 #include <net/route.h>
47 #include <netinet/if_ether.h>
48 #include <netinet/in.h>
49 #include <netinet/in_var.h>
50 #include <netinet6/in6_var.h>
51 #include <netinet6/nd6.h>
53 #include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
54 #elif defined(__DragonFly__)
55 #include <net/vlan/if_vlan_var.h>
57 #include <net/if_vlan_var.h>
60 # include <netproto/802_11/ieee80211_ioctl.h>
62 # include <net80211/ieee80211.h>
63 # include <net80211/ieee80211_ioctl.h>
77 #if defined(OpenBSD) && OpenBSD >= 201411
78 /* OpenBSD dropped the global setting from sysctl but left the #define
79 * which causes a EPERM error when trying to use it.
80 * I think both the error and keeping the define are wrong, so we #undef it. */
81 #undef IPV6CTL_ACCEPT_RTADV
87 #include "if-options.h"
98 #define RT_ROUNDUP(a) \
99 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
100 #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
103 /* Ignore these interface names which look like ethernet but are virtual or
104 * just won't work without explicit configuration. */
105 static const char * const ifnames_ignore
[] = {
107 "epair", /* Virtual patch cable */
108 "fwe", /* Firewire */
109 "fwip", /* Firewire */
112 "xvif", /* XEN DOM0 -> guest interface */
118 struct rt_msghdr hdr
;
119 char buffer
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
129 if_init(__unused
struct interface
*iface
)
131 /* BSD promotes secondary address by default */
136 if_conf(__unused
struct interface
*iface
)
138 /* No extra checks needed on BSD */
143 if_opensockets_os(struct dhcpcd_ctx
*ctx
)
147 #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
148 unsigned char msgfilter
[] = {
150 #ifdef RTM_IFANNOUNCE
153 RTM_ADD
, RTM_CHANGE
, RTM_DELETE
, RTM_MISS
,
160 RTM_NEWADDR
, RTM_DELADDR
162 #ifdef ROUTE_MSGFILTER
163 unsigned int i
, msgfilter_mask
;
167 if ((priv
= malloc(sizeof(*priv
))) == NULL
)
172 priv
->pf_inet6_fd
= xsocket(PF_INET6
, SOCK_DGRAM
| SOCK_CLOEXEC
, 0);
173 /* Don't return an error so we at least work on kernels witout INET6
174 * even though we expect INET6 support.
175 * We will fail noisily elsewhere anyway. */
176 #ifdef PRIVSEP_RIGHTS
177 if (priv
->pf_inet6_fd
!= -1 && IN_PRIVSEP(ctx
))
178 ps_rights_limit_ioctl(priv
->pf_inet6_fd
);
182 ctx
->link_fd
= xsocket(PF_ROUTE
, SOCK_RAW
| SOCK_CXNB
, AF_UNSPEC
);
183 if (ctx
->link_fd
== -1)
188 if (setsockopt(ctx
->link_fd
, SOL_SOCKET
, SO_RERROR
, &n
,sizeof(n
)) == -1)
189 logerr("%s: SO_RERROR", __func__
);
192 /* Ignore our own route(4) messages.
193 * Sadly there is no way of doing this for route(4) messages
194 * generated from addresses we add/delete. */
196 if (setsockopt(ctx
->link_fd
, SOL_SOCKET
, SO_USELOOPBACK
,
197 &n
, sizeof(n
)) == -1)
198 logerr("%s: SO_USELOOPBACK", __func__
);
200 #if defined(RO_MSGFILTER)
201 if (setsockopt(ctx
->link_fd
, PF_ROUTE
, RO_MSGFILTER
,
202 &msgfilter
, sizeof(msgfilter
)) == -1)
204 #elif defined(ROUTE_MSGFILTER)
205 /* Convert the array into a bitmask. */
207 for (i
= 0; i
< __arraycount(msgfilter
); i
++)
208 msgfilter_mask
|= ROUTE_FILTER(msgfilter
[i
]);
209 if (setsockopt(ctx
->link_fd
, PF_ROUTE
, ROUTE_MSGFILTER
,
210 &msgfilter_mask
, sizeof(msgfilter_mask
)) == -1)
213 #warning kernel does not support route message filtering
216 #ifdef PRIVSEP_RIGHTS
217 /* We need to getsockopt for SO_RCVBUF and
218 * setsockopt for RO_MISSFILTER. */
220 ps_rights_limit_fd_sockopt(ctx
->link_fd
);
224 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
225 priv
->pf_link_fd
= socket(PF_LINK
, SOCK_DGRAM
, 0);
226 if (priv
->pf_link_fd
== -1)
227 logerr("%s: socket(PF_LINK)", __func__
);
233 if_closesockets_os(struct dhcpcd_ctx
*ctx
)
237 priv
= (struct priv
*)ctx
->priv
;
239 if (priv
->pf_inet6_fd
!= -1)
240 close(priv
->pf_inet6_fd
);
242 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
243 if (priv
->pf_link_fd
!= -1)
244 close(priv
->pf_link_fd
);
248 free(ctx
->rt_missfilter
);
251 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
253 if_ioctllink(struct dhcpcd_ctx
*ctx
, unsigned long req
, void *data
, size_t len
)
255 struct priv
*priv
= (struct priv
*)ctx
->priv
;
258 if (ctx
->options
& DHCPCD_PRIVSEP
)
259 return (int)ps_root_ioctllink(ctx
, req
, data
, len
);
262 return ioctl(priv
->pf_link_fd
, req
, data
, len
);
267 if_setmac(struct interface
*ifp
, void *mac
, uint8_t maclen
)
270 if (ifp
->hwlen
!= maclen
) {
275 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
276 struct if_laddrreq iflr
= { .flags
= IFLR_ACTIVE
};
277 struct sockaddr_dl
*sdl
= satosdl(&iflr
.addr
);
280 strlcpy(iflr
.iflr_name
, ifp
->name
, sizeof(iflr
.iflr_name
));
281 sdl
->sdl_family
= AF_LINK
;
282 sdl
->sdl_len
= sizeof(*sdl
);
283 sdl
->sdl_alen
= maclen
;
284 memcpy(LLADDR(sdl
), mac
, maclen
);
285 retval
= if_ioctllink(ifp
->ctx
, SIOCALIFADDR
, &iflr
, sizeof(iflr
));
287 /* Try and remove the old address */
288 memcpy(LLADDR(sdl
), ifp
->hwaddr
, ifp
->hwlen
);
289 if_ioctllink(ifp
->ctx
, SIOCDLIFADDR
, &iflr
, sizeof(iflr
));
294 .ifr_addr
.sa_family
= AF_LINK
,
295 .ifr_addr
.sa_len
= maclen
,
298 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
299 memcpy(ifr
.ifr_addr
.sa_data
, mac
, maclen
);
300 return if_ioctl(ifp
->ctx
, SIOCSIFLLADDR
, &ifr
, sizeof(ifr
));
305 if_ignore1(const char *drvname
)
307 const char * const *p
;
309 for (p
= ifnames_ignore
; *p
; p
++) {
310 if (strcmp(*p
, drvname
) == 0)
318 if_ignoregroup(int s
, const char *ifname
)
320 struct ifgroupreq ifgr
= { .ifgr_len
= 0 };
324 /* Sadly it is possible to remove the device name
325 * from the interface groups, but hopefully this
326 * will be very unlikely.... */
328 strlcpy(ifgr
.ifgr_name
, ifname
, sizeof(ifgr
.ifgr_name
));
329 if (ioctl(s
, SIOCGIFGROUP
, &ifgr
) == -1 ||
330 (ifgr
.ifgr_groups
= malloc(ifgr
.ifgr_len
)) == NULL
||
331 ioctl(s
, SIOCGIFGROUP
, &ifgr
) == -1)
337 for (ifg
= ifgr
.ifgr_groups
, ifg_len
= ifgr
.ifgr_len
;
338 ifg
&& ifg_len
>= sizeof(*ifg
);
339 ifg
++, ifg_len
-= sizeof(*ifg
))
341 if (if_ignore1(ifg
->ifgrq_group
))
349 if_ignore(struct dhcpcd_ctx
*ctx
, const char *ifname
)
353 if (if_nametospec(ifname
, &spec
) != 0)
356 if (if_ignore1(spec
.drvname
))
360 #if defined(PRIVSEP) && defined(HAVE_PLEDGE)
362 return ps_root_ifignoregroup(ctx
, ifname
) == 1 ? true : false;
365 return if_ignoregroup(ctx
->pf_inet_fd
, ifname
) == 1 ?
373 static int if_indirect_ioctl(struct dhcpcd_ctx
*ctx
,
374 const char *ifname
, unsigned long cmd
, void *data
, size_t len
)
376 struct ifreq ifr
= { .ifr_flags
= 0 };
378 #if defined(PRIVSEP) && (defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE))
380 return (int)ps_root_indirectioctl(ctx
, cmd
, ifname
, data
, len
);
385 strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
387 return ioctl(ctx
->pf_inet_fd
, cmd
, &ifr
);
391 if_carrier(struct interface
*ifp
, const void *ifadata
)
393 const struct if_data
*ifi
= ifadata
;
396 * Every BSD returns this and it is the sole source of truth.
397 * Not all BSD's support SIOCGIFDATA and not all interfaces
398 * support SIOCGIFMEDIA.
400 assert(ifadata
!= NULL
);
402 if (ifi
->ifi_link_state
>= LINK_STATE_UP
)
404 if (ifi
->ifi_link_state
== LINK_STATE_UNKNOWN
) {
406 * Work around net80211 issues in some BSDs.
407 * Wireless MUST support link state change.
417 if_roaming(struct interface
*ifp
)
420 /* Check for NetBSD as a safety measure.
421 * If other BSD's gain IN_IFF_TENTATIVE check they re-do DAD
422 * when the carrier comes up again. */
423 #if defined(IN_IFF_TENTATIVE) && defined(__NetBSD__)
424 return ifp
->flags
& IFF_UP
&& ifp
->carrier
== LINK_DOWN
;
432 if_linkaddr(struct sockaddr_dl
*sdl
, const struct interface
*ifp
)
435 memset(sdl
, 0, sizeof(*sdl
));
436 sdl
->sdl_family
= AF_LINK
;
437 sdl
->sdl_len
= sizeof(*sdl
);
438 sdl
->sdl_nlen
= sdl
->sdl_alen
= sdl
->sdl_slen
= 0;
439 sdl
->sdl_index
= (unsigned short)ifp
->index
;
443 if_getssid1(struct dhcpcd_ctx
*ctx
, const char *ifname
, void *ssid
)
446 #if defined(SIOCG80211NWID)
447 struct ieee80211_nwid nwid
;
448 #elif defined(IEEE80211_IOC_SSID)
449 struct ieee80211req ireq
;
450 char nwid
[IEEE80211_NWID_LEN
];
453 #if defined(SIOCG80211NWID) /* NetBSD */
454 memset(&nwid
, 0, sizeof(nwid
));
455 if (if_indirect_ioctl(ctx
, ifname
, SIOCG80211NWID
,
456 &nwid
, sizeof(nwid
)) == 0)
460 else if (nwid
.i_len
> IF_SSIDLEN
)
464 memcpy(ssid
, nwid
.i_nwid
, nwid
.i_len
);
467 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
468 memset(&ireq
, 0, sizeof(ireq
));
469 strlcpy(ireq
.i_name
, ifname
, sizeof(ireq
.i_name
));
470 ireq
.i_type
= IEEE80211_IOC_SSID
;
472 memset(nwid
, 0, sizeof(nwid
));
474 if (ioctl(ctx
->pf_inet_fd
, SIOCG80211
, &ireq
) == 0) {
477 else if (ireq
.i_len
> IF_SSIDLEN
)
481 memcpy(ssid
, nwid
, ireq
.i_len
);
492 if_getssid(struct interface
*ifp
)
496 r
= if_getssid1(ifp
->ctx
, ifp
->name
, ifp
->ssid
);
498 ifp
->ssid_len
= (unsigned int)r
;
501 ifp
->ssid
[ifp
->ssid_len
] = '\0';
506 * FreeBSD allows for Virtual Access Points
507 * We need to check if the interface is a Virtual Interface Master
508 * and if so, don't use it.
509 * This check is made by virtue of being a IEEE80211 device but
510 * returning the SSID gives an error.
513 if_vimaster(struct dhcpcd_ctx
*ctx
, const char *ifname
)
516 struct ifmediareq ifmr
= { .ifm_active
= 0 };
518 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
519 r
= ioctl(ctx
->pf_inet_fd
, SIOCGIFMEDIA
, &ifmr
);
522 if (ifmr
.ifm_status
& IFM_AVALID
&&
523 IFM_TYPE(ifmr
.ifm_active
) == IFM_IEEE80211
)
525 if (if_getssid1(ctx
, ifname
, NULL
) == -1)
532 if_vlanid(const struct interface
*ifp
)
535 struct vlanreq vlr
= { .vlr_tag
= 0 };
537 if (if_indirect_ioctl(ifp
->ctx
, ifp
->name
, SIOCGETVLAN
,
538 &vlr
, sizeof(vlr
)) != 0)
539 return 0; /* 0 means no VLANID */
541 #elif defined(SIOCGVNETID)
542 struct ifreq ifr
= { .ifr_vnetid
= 0 };
544 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
545 if (ioctl(ifp
->ctx
->pf_inet_fd
, SIOCGVNETID
, &ifr
) != 0)
546 return 0; /* 0 means no VLANID */
547 return ifr
.ifr_vnetid
;
550 return 0; /* 0 means no VLANID */
555 get_addrs(int type
, const void *data
, size_t data_len
,
556 const struct sockaddr
**sa
)
563 for (i
= 0; i
< RTAX_MAX
; i
++) {
564 if (type
& (1 << i
)) {
569 sa
[i
] = (const struct sockaddr
*)cp
;
570 RT_ADVANCE(cp
, sa
[i
]);
578 static struct interface
*
579 if_findsdl(struct dhcpcd_ctx
*ctx
, const struct sockaddr_dl
*sdl
)
583 return if_findindex(ctx
->ifaces
, sdl
->sdl_index
);
586 char ifname
[IF_NAMESIZE
];
588 memcpy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
589 ifname
[sdl
->sdl_nlen
] = '\0';
590 return if_find(ctx
->ifaces
, ifname
);
593 struct interface
*ifp
;
595 TAILQ_FOREACH(ifp
, ctx
->ifaces
, next
) {
596 if (ifp
->hwlen
== sdl
->sdl_alen
&&
598 sdl
->sdl_data
, sdl
->sdl_alen
) == 0)
607 static struct interface
*
608 if_findsa(struct dhcpcd_ctx
*ctx
, const struct sockaddr
*sa
)
615 switch (sa
->sa_family
) {
618 const struct sockaddr_dl
*sdl
;
620 sdl
= (const void *)sa
;
621 return if_findsdl(ctx
, sdl
);
626 const struct sockaddr_in
*sin
;
627 struct ipv4_addr
*ia
;
629 sin
= (const void *)sa
;
630 if ((ia
= ipv4_findmaskaddr(ctx
, &sin
->sin_addr
)))
632 if ((ia
= ipv4_findmaskbrd(ctx
, &sin
->sin_addr
)))
640 const struct sockaddr_in6
*sin
;
642 struct ipv6_addr
*ia
;
644 sin
= (const void *)sa
;
645 scope
= ipv6_getscope(sin
);
647 return if_findindex(ctx
->ifaces
, scope
);
648 if ((ia
= ipv6_findmaskaddr(ctx
, &sin
->sin6_addr
)))
654 errno
= EAFNOSUPPORT
;
663 if_copysa(struct sockaddr
*dst
, const struct sockaddr
*src
)
669 memcpy(dst
, src
, src
->sa_len
);
670 #if defined(INET6) && defined(__KAME__)
671 if (dst
->sa_family
== AF_INET6
) {
672 struct in6_addr
*in6
;
674 in6
= &satosin6(dst
)->sin6_addr
;
675 if (IN6_IS_ADDR_LINKLOCAL(in6
))
676 in6
->s6_addr
[2] = in6
->s6_addr
[3] = '\0';
682 if_route(unsigned char cmd
, const struct rt
*rt
)
684 struct dhcpcd_ctx
*ctx
;
686 struct rt_msghdr
*rtm
= &rtmsg
.hdr
;
687 char *bp
= rtmsg
.buffer
;
688 struct sockaddr_dl sdl
;
692 assert(rt
->rt_ifp
!= NULL
);
693 assert(rt
->rt_ifp
->ctx
!= NULL
);
694 ctx
= rt
->rt_ifp
->ctx
;
696 #define ADDSA(sa) do { \
697 memcpy(bp, (sa), (sa)->sa_len); \
698 bp += RT_ROUNDUP((sa)->sa_len); \
699 } while (0 /* CONSTCOND */)
701 memset(&rtmsg
, 0, sizeof(rtmsg
));
702 rtm
->rtm_version
= RTM_VERSION
;
705 rtm
->rtm_pid
= getpid();
707 rtm
->rtm_seq
= ++ctx
->seq
;
708 rtm
->rtm_flags
= (int)rt
->rt_flags
;
709 rtm
->rtm_addrs
= RTA_DST
;
712 rtm
->rtm_flags
|= RTF_PINNED
;
715 gateway_unspec
= sa_is_unspecified(&rt
->rt_gateway
);
717 if (cmd
== RTM_ADD
|| cmd
== RTM_CHANGE
) {
718 bool netmask_bcast
= sa_is_allones(&rt
->rt_netmask
);
720 rtm
->rtm_flags
|= RTF_UP
;
721 rtm
->rtm_addrs
|= RTA_GATEWAY
;
722 if (!(rtm
->rtm_flags
& RTF_REJECT
) &&
723 !sa_is_loopback(&rt
->rt_gateway
))
725 rtm
->rtm_index
= (unsigned short)rt
->rt_ifp
->index
;
727 * OpenBSD rejects the message for on-link routes.
728 * FreeBSD-12 kernel apparently panics.
729 * I can't replicate the panic, but better safe than sorry!
730 * https://roy.marples.name/archives/dhcpcd-discuss/0002286.html
732 * Neither OS currently allows IPv6 address sharing anyway, so let's
733 * try to encourage someone to fix that by logging a waring during compile.
735 #if defined(__FreeBSD__) || defined(__OpenBSD__)
736 #warning kernel does not allow IPv6 address sharing
737 if (!gateway_unspec
|| rt
->rt_dest
.sa_family
!=AF_INET6
)
739 rtm
->rtm_addrs
|= RTA_IFP
;
740 if (!sa_is_unspecified(&rt
->rt_ifa
))
741 rtm
->rtm_addrs
|= RTA_IFA
;
744 rtm
->rtm_flags
|= RTF_HOST
;
745 /* Network routes are cloning or connected if supported.
746 * All other routes are static. */
747 if (gateway_unspec
) {
749 rtm
->rtm_flags
|= RTF_CLONING
;
752 rtm
->rtm_flags
|= RTF_CONNECTED
;
755 rtm
->rtm_priority
= RTP_CONNECTED
;
760 * We add a cloning network route for a single
761 * host. Traffic to the host will generate a
762 * cloned route and the hardware address will
764 * It might be more correct to use RTF_HOST
765 * instead of RTF_CLONING, and that does work,
766 * but some OS generate an arp warning
767 * diagnostic which we don't want to do.
769 rtm
->rtm_flags
&= ~RTF_HOST
;
773 rtm
->rtm_flags
|= RTF_GATEWAY
;
775 if (rt
->rt_dflags
& RTDF_STATIC
)
776 rtm
->rtm_flags
|= RTF_STATIC
;
778 if (rt
->rt_mtu
!= 0) {
779 rtm
->rtm_inits
|= RTV_MTU
;
780 rtm
->rtm_rmx
.rmx_mtu
= rt
->rt_mtu
;
784 if (!(rtm
->rtm_flags
& RTF_HOST
))
785 rtm
->rtm_addrs
|= RTA_NETMASK
;
787 if_linkaddr(&sdl
, rt
->rt_ifp
);
791 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
793 ADDSA((struct sockaddr
*)&sdl
);
797 if_copysa(&gateway
.sa
, &rt
->rt_gateway
);
799 if (gateway
.sa
.sa_family
== AF_INET6
)
800 ipv6_setscope(&gateway
.sin6
, rt
->rt_ifp
->index
);
806 if (rtm
->rtm_addrs
& RTA_NETMASK
)
807 ADDSA(&rt
->rt_netmask
);
809 if (rtm
->rtm_addrs
& RTA_IFP
)
810 ADDSA((struct sockaddr
*)&sdl
);
812 if (rtm
->rtm_addrs
& RTA_IFA
)
817 rtm
->rtm_msglen
= (unsigned short)(bp
- (char *)rtm
);
820 if (ctx
->options
& DHCPCD_PRIVSEP
) {
821 if (ps_root_route(ctx
, rtm
, rtm
->rtm_msglen
) == -1)
826 if (write(ctx
->link_fd
, rtm
, rtm
->rtm_msglen
) == -1)
832 if_realroute(const struct rt_msghdr
*rtm
)
836 if (rtm
->rtm_flags
& RTF_CLONED
)
840 if (rtm
->rtm_flags
& RTF_WASCLONED
)
844 if (rtm
->rtm_flags
& RTF_LOCAL
)
848 if (rtm
->rtm_flags
& RTF_BROADCAST
)
855 if_copyrt(struct dhcpcd_ctx
*ctx
, struct rt
*rt
, const struct rt_msghdr
*rtm
)
857 const struct sockaddr
*rti_info
[RTAX_MAX
];
859 if (!(rtm
->rtm_addrs
& RTA_DST
)) {
863 if (rtm
->rtm_type
!= RTM_MISS
&& !(rtm
->rtm_addrs
& RTA_GATEWAY
)) {
868 if (get_addrs(rtm
->rtm_addrs
, (const char *)rtm
+ sizeof(*rtm
),
869 rtm
->rtm_msglen
- sizeof(*rtm
), rti_info
) == -1)
871 memset(rt
, 0, sizeof(*rt
));
873 rt
->rt_flags
= (unsigned int)rtm
->rtm_flags
;
874 if_copysa(&rt
->rt_dest
, rti_info
[RTAX_DST
]);
875 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
876 if_copysa(&rt
->rt_netmask
, rti_info
[RTAX_NETMASK
]);
877 if (rt
->rt_netmask
.sa_family
== 255) /* Why? */
878 rt
->rt_netmask
.sa_family
= rt
->rt_dest
.sa_family
;
881 /* dhcpcd likes an unspecified gateway to indicate via the link.
882 * However we need to know if gateway was a link with an address. */
883 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
884 if (rti_info
[RTAX_GATEWAY
]->sa_family
== AF_LINK
) {
885 const struct sockaddr_dl
*sdl
;
887 sdl
= (const struct sockaddr_dl
*)
888 (const void *)rti_info
[RTAX_GATEWAY
];
889 if (sdl
->sdl_alen
!= 0)
890 rt
->rt_dflags
|= RTDF_GATELINK
;
891 } else if (rtm
->rtm_flags
& RTF_GATEWAY
)
892 if_copysa(&rt
->rt_gateway
, rti_info
[RTAX_GATEWAY
]);
895 if (rtm
->rtm_addrs
& RTA_IFA
)
896 if_copysa(&rt
->rt_ifa
, rti_info
[RTAX_IFA
]);
898 rt
->rt_mtu
= (unsigned int)rtm
->rtm_rmx
.rmx_mtu
;
901 rt
->rt_ifp
= if_findindex(ctx
->ifaces
, rtm
->rtm_index
);
902 else if (rtm
->rtm_addrs
& RTA_IFP
)
903 rt
->rt_ifp
= if_findsa(ctx
, rti_info
[RTAX_IFP
]);
904 else if (rtm
->rtm_addrs
& RTA_GATEWAY
)
905 rt
->rt_ifp
= if_findsa(ctx
, rti_info
[RTAX_GATEWAY
]);
907 rt
->rt_ifp
= if_findsa(ctx
, rti_info
[RTAX_DST
]);
909 if (rt
->rt_ifp
== NULL
&& rtm
->rtm_type
== RTM_MISS
)
910 rt
->rt_ifp
= if_find(ctx
->ifaces
, "lo0");
912 if (rt
->rt_ifp
== NULL
) {
920 if_sysctl(struct dhcpcd_ctx
*ctx
,
921 const int *name
, u_int namelen
,
922 void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
)
924 #if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
926 return (int)ps_root_sysctl(ctx
, name
, namelen
,
927 oldp
, oldlenp
, newp
, newlen
);
932 return sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
);
936 if_initrt(struct dhcpcd_ctx
*ctx
, rb_tree_t
*kroutes
, int af
)
938 struct rt_msghdr
*rtm
;
939 int mib
[6] = { CTL_NET
, PF_ROUTE
, 0, af
, NET_RT_DUMP
, 0 };
944 if (if_sysctl(ctx
, mib
, __arraycount(mib
), NULL
, &bufl
, NULL
, 0) == -1)
948 if ((buf
= malloc(bufl
)) == NULL
)
950 if (if_sysctl(ctx
, mib
, __arraycount(mib
), buf
, &bufl
, NULL
, 0) == -1)
957 for (p
= buf
; p
< end
; p
+= rtm
->rtm_msglen
) {
959 if (p
+ sizeof(*rtm
) > end
|| p
+ rtm
->rtm_msglen
> end
) {
963 if (!if_realroute(rtm
))
965 if (if_copyrt(ctx
, &rt
, rtm
) != 0)
967 if ((rtn
= rt_new(rt
.rt_ifp
)) == NULL
) {
971 memcpy(rtn
, &rt
, sizeof(*rtn
));
972 if (rb_tree_insert_node(kroutes
, rtn
) != rtn
)
976 return p
== end
? 0 : -1;
981 if_address(unsigned char cmd
, const struct ipv4_addr
*ia
)
984 struct in_aliasreq ifra
;
985 struct dhcpcd_ctx
*ctx
= ia
->iface
->ctx
;
987 memset(&ifra
, 0, sizeof(ifra
));
988 strlcpy(ifra
.ifra_name
, ia
->iface
->name
, sizeof(ifra
.ifra_name
));
990 #define ADDADDR(var, addr) do { \
991 (var)->sin_family = AF_INET; \
992 (var)->sin_len = sizeof(*(var)); \
993 (var)->sin_addr = *(addr); \
994 } while (/*CONSTCOND*/0)
995 ADDADDR(&ifra
.ifra_addr
, &ia
->addr
);
996 ADDADDR(&ifra
.ifra_mask
, &ia
->mask
);
997 if (cmd
== RTM_NEWADDR
&& ia
->brd
.s_addr
!= INADDR_ANY
)
998 ADDADDR(&ifra
.ifra_broadaddr
, &ia
->brd
);
1002 cmd
== RTM_DELADDR
? SIOCDIFADDR
: SIOCAIFADDR
, &ifra
,sizeof(ifra
));
1006 #if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS))
1008 if_addrflags(const struct interface
*ifp
, const struct in_addr
*addr
,
1009 __unused
const char *alias
)
1011 #ifdef SIOCGIFAFLAG_IN
1013 struct sockaddr_in
*sin
;
1015 memset(&ifr
, 0, sizeof(ifr
));
1016 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
1017 sin
= (void *)&ifr
.ifr_addr
;
1018 sin
->sin_family
= AF_INET
;
1019 sin
->sin_addr
= *addr
;
1020 if (ioctl(ifp
->ctx
->pf_inet_fd
, SIOCGIFAFLAG_IN
, &ifr
) == -1)
1022 return ifr
.ifr_addrflags
;
1034 if_ioctl6(struct dhcpcd_ctx
*ctx
, unsigned long req
, void *data
, size_t len
)
1039 if (ctx
->options
& DHCPCD_PRIVSEP
)
1040 return (int)ps_root_ioctl6(ctx
, req
, data
, len
);
1044 return ioctl(priv
->pf_inet6_fd
, req
, data
, len
);
1048 if_address6(unsigned char cmd
, const struct ipv6_addr
*ia
)
1050 struct in6_aliasreq ifa
= { .ifra_flags
= 0 };
1051 struct in6_addr mask
;
1052 struct dhcpcd_ctx
*ctx
= ia
->iface
->ctx
;
1054 strlcpy(ifa
.ifra_name
, ia
->iface
->name
, sizeof(ifa
.ifra_name
));
1055 #if defined(__FreeBSD__) || defined(__DragonFly__)
1056 /* This is a bug - the kernel should work this out. */
1057 if (ia
->addr_flags
& IN6_IFF_TENTATIVE
)
1058 ifa
.ifra_flags
|= IN6_IFF_TENTATIVE
;
1060 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && \
1061 (defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV))
1062 /* These kernels don't accept userland setting IN6_IFF_AUTOCONF */
1064 if (ia
->flags
& IPV6_AF_AUTOCONF
)
1065 ifa
.ifra_flags
|= IN6_IFF_AUTOCONF
;
1067 #ifdef IPV6_MANAGETEMPADDR
1068 if (ia
->flags
& IPV6_AF_TEMPORARY
)
1069 ifa
.ifra_flags
|= IN6_IFF_TEMPORARY
;
1072 #define ADDADDR(v, addr) { \
1073 (v)->sin6_family = AF_INET6; \
1074 (v)->sin6_len = sizeof(*v); \
1075 (v)->sin6_addr = *(addr); \
1078 ADDADDR(&ifa
.ifra_addr
, &ia
->addr
);
1079 ipv6_setscope(&ifa
.ifra_addr
, ia
->iface
->index
);
1080 ipv6_mask(&mask
, ia
->prefix_len
);
1081 ADDADDR(&ifa
.ifra_prefixmask
, &mask
);
1086 * Every BSD kernel wants to add the prefix of the address to it's
1087 * list of RA received prefixes.
1088 * THIS IS WRONG because there (as the comments in the kernel state)
1089 * is no API for managing prefix lifetime and the kernel should not
1090 * pretend it's from a RA either.
1092 * The issue is that the very first assigned prefix will inherit the
1093 * lifetime of the address, but any subsequent alteration of the
1094 * address OR it's lifetime will not affect the prefix lifetime.
1095 * As such, we cannot stop the prefix from timing out and then
1096 * constantly removing the prefix route dhcpcd is capable of adding
1099 * What we can do to mitigate the issue is to add the address with
1100 * infinite lifetimes, so the prefix route will never time out.
1101 * Once done, we can then set lifetimes on the address and all is good.
1102 * The downside of this approach is that we need to manually remove
1103 * the kernel route because it has no lifetime, but this is OK as
1104 * dhcpcd will handle this too.
1106 * This issue is discussed on the NetBSD mailing lists here:
1107 * http://mail-index.netbsd.org/tech-net/2016/08/05/msg006044.html
1109 * Fixed in NetBSD-7.99.36
1110 * NOT fixed in FreeBSD - bug 195197
1111 * Fixed in OpenBSD-5.9
1114 #if !((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003600) || \
1115 (defined(__OpenBSD__) && OpenBSD >= 201605))
1116 if (cmd
== RTM_NEWADDR
&& !(ia
->flags
& IPV6_AF_ADDED
)) {
1117 ifa
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
1118 ifa
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
1119 (void)if_ioctl6(ctx
, SIOCAIFADDR_IN6
, &ifa
, sizeof(ifa
));
1123 #if defined(__OpenBSD__) && OpenBSD <= 201705
1124 /* BUT OpenBSD older than 6.2 does not reset the address lifetime
1125 * for subsequent calls...
1126 * Luckily dhcpcd will remove the lease when it expires so
1127 * just set an infinite lifetime, unless a temporary address. */
1128 if (ifa
.ifra_flags
& IN6_IFF_PRIVACY
) {
1129 ifa
.ifra_lifetime
.ia6t_vltime
= ia
->prefix_vltime
;
1130 ifa
.ifra_lifetime
.ia6t_pltime
= ia
->prefix_pltime
;
1132 ifa
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
1133 ifa
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
1136 ifa
.ifra_lifetime
.ia6t_vltime
= ia
->prefix_vltime
;
1137 ifa
.ifra_lifetime
.ia6t_pltime
= ia
->prefix_pltime
;
1140 return if_ioctl6(ctx
,
1141 cmd
== RTM_DELADDR
? SIOCDIFADDR_IN6
: SIOCAIFADDR_IN6
,
1146 if_addrflags6(const struct interface
*ifp
, const struct in6_addr
*addr
,
1147 __unused
const char *alias
)
1150 struct in6_ifreq ifr6
;
1153 memset(&ifr6
, 0, sizeof(ifr6
));
1154 strlcpy(ifr6
.ifr_name
, ifp
->name
, sizeof(ifr6
.ifr_name
));
1155 ifr6
.ifr_addr
.sin6_family
= AF_INET6
;
1156 ifr6
.ifr_addr
.sin6_addr
= *addr
;
1157 ipv6_setscope(&ifr6
.ifr_addr
, ifp
->index
);
1158 priv
= (struct priv
*)ifp
->ctx
->priv
;
1159 if (ioctl(priv
->pf_inet6_fd
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1160 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
1167 if_getlifetime6(struct ipv6_addr
*ia
)
1169 struct in6_ifreq ifr6
;
1171 struct in6_addrlifetime
*lifetime
;
1174 memset(&ifr6
, 0, sizeof(ifr6
));
1175 strlcpy(ifr6
.ifr_name
, ia
->iface
->name
, sizeof(ifr6
.ifr_name
));
1176 ifr6
.ifr_addr
.sin6_family
= AF_INET6
;
1177 ifr6
.ifr_addr
.sin6_addr
= ia
->addr
;
1178 ipv6_setscope(&ifr6
.ifr_addr
, ia
->iface
->index
);
1179 priv
= (struct priv
*)ia
->iface
->ctx
->priv
;
1180 if (ioctl(priv
->pf_inet6_fd
, SIOCGIFALIFETIME_IN6
, &ifr6
) == -1)
1182 clock_gettime(CLOCK_MONOTONIC
, &ia
->created
);
1184 #if defined(__FreeBSD__) || defined(__DragonFly__)
1185 t
= ia
->created
.tv_sec
;
1190 lifetime
= &ifr6
.ifr_ifru
.ifru_lifetime
;
1191 if (lifetime
->ia6t_preferred
)
1192 ia
->prefix_pltime
= (uint32_t)(lifetime
->ia6t_preferred
-
1193 MIN(t
, lifetime
->ia6t_preferred
));
1195 ia
->prefix_pltime
= ND6_INFINITE_LIFETIME
;
1196 if (lifetime
->ia6t_expire
) {
1197 ia
->prefix_vltime
= (uint32_t)(lifetime
->ia6t_expire
-
1198 MIN(t
, lifetime
->ia6t_expire
));
1199 /* Calculate the created time */
1200 ia
->created
.tv_sec
-= lifetime
->ia6t_vltime
- ia
->prefix_vltime
;
1202 ia
->prefix_vltime
= ND6_INFINITE_LIFETIME
;
1208 if_announce(struct dhcpcd_ctx
*ctx
, const struct if_announcemsghdr
*ifan
)
1211 if (ifan
->ifan_msglen
< sizeof(*ifan
)) {
1216 switch(ifan
->ifan_what
) {
1218 return dhcpcd_handleinterface(ctx
, 1, ifan
->ifan_name
);
1219 case IFAN_DEPARTURE
:
1220 return dhcpcd_handleinterface(ctx
, -1, ifan
->ifan_name
);
1227 if_ifinfo(struct dhcpcd_ctx
*ctx
, const struct if_msghdr
*ifm
)
1229 struct interface
*ifp
;
1232 if (ifm
->ifm_msglen
< sizeof(*ifm
)) {
1237 if ((ifp
= if_findindex(ctx
->ifaces
, ifm
->ifm_index
)) == NULL
)
1240 link_state
= if_carrier(ifp
, &ifm
->ifm_data
);
1241 dhcpcd_handlecarrier(ifp
, link_state
, (unsigned int)ifm
->ifm_flags
);
1246 if_rtm(struct dhcpcd_ctx
*ctx
, const struct rt_msghdr
*rtm
)
1250 if (rtm
->rtm_msglen
< sizeof(*rtm
)) {
1255 /* Ignore errors. */
1256 if (rtm
->rtm_errno
!= 0)
1259 /* Ignore messages from ourself. */
1261 if (ctx
->ps_root
!= NULL
) {
1262 if (rtm
->rtm_pid
== ctx
->ps_root
->psp_pid
)
1267 if (if_copyrt(ctx
, &rt
, rtm
) == -1)
1268 return errno
== ENOTSUP
? 0 : -1;
1272 * BSD announces host routes.
1273 * As such, we should be notified of reachability by its
1274 * existance with a hardware address.
1275 * Ensure we don't call this for a newly incomplete state.
1277 if (rt
.rt_dest
.sa_family
== AF_INET6
&&
1278 (rt
.rt_flags
& RTF_HOST
|| rtm
->rtm_type
== RTM_MISS
) &&
1279 !(rtm
->rtm_type
== RTM_ADD
&& !(rt
.rt_dflags
& RTDF_GATELINK
)))
1283 reachable
= (rtm
->rtm_type
== RTM_ADD
||
1284 rtm
->rtm_type
== RTM_CHANGE
) &&
1285 rt
.rt_dflags
& RTDF_GATELINK
;
1286 ipv6nd_neighbour(ctx
, &rt
.rt_ss_dest
.sin6
.sin6_addr
, reachable
);
1290 if (rtm
->rtm_type
!= RTM_MISS
&& if_realroute(rtm
))
1291 rt_recvrt(rtm
->rtm_type
, &rt
, rtm
->rtm_pid
);
1296 if_ifa(struct dhcpcd_ctx
*ctx
, const struct ifa_msghdr
*ifam
)
1298 struct interface
*ifp
;
1299 const struct sockaddr
*rti_info
[RTAX_MAX
];
1303 if (ifam
->ifam_msglen
< sizeof(*ifam
)) {
1308 #ifdef HAVE_IFAM_PID
1309 /* Ignore address deletions from ourself.
1310 * We need to process address flag changes though. */
1311 if (ifam
->ifam_type
== RTM_DELADDR
) {
1313 if (ctx
->ps_root
!= NULL
) {
1314 if (ifam
->ifam_pid
== ctx
->ps_root
->psp_pid
)
1318 /* address management is done via ioctl,
1319 * so SO_USELOOPBACK has no effect,
1320 * so we do need to check the pid. */
1321 if (ifam
->ifam_pid
== getpid())
1324 pid
= ifam
->ifam_pid
;
1329 if (~ifam
->ifam_addrs
& RTA_IFA
)
1331 if ((ifp
= if_findindex(ctx
->ifaces
, ifam
->ifam_index
)) == NULL
)
1334 if (get_addrs(ifam
->ifam_addrs
, (const char *)ifam
+ sizeof(*ifam
),
1335 ifam
->ifam_msglen
- sizeof(*ifam
), rti_info
) == -1)
1338 /* All BSD's set IFF_UP on the interface when adding an address.
1339 * But not all BSD's emit this via RTM_IFINFO when they do this ... */
1340 if (ifam
->ifam_type
== RTM_NEWADDR
&& !(ifp
->flags
& IFF_UP
))
1341 dhcpcd_handlecarrier(ifp
, ifp
->carrier
, ifp
->flags
| IFF_UP
);
1343 switch (rti_info
[RTAX_IFA
]->sa_family
) {
1346 struct sockaddr_dl sdl
;
1349 if (ifam
->ifam_type
!= RTM_CHGADDR
)
1352 if (ifam
->ifam_type
!= RTM_NEWADDR
)
1355 memcpy(&sdl
, rti_info
[RTAX_IFA
], rti_info
[RTAX_IFA
]->sa_len
);
1356 dhcpcd_handlehwaddr(ifp
, ifp
->hwtype
,
1357 CLLADDR(&sdl
), sdl
.sdl_alen
);
1362 case 255: /* FIXME: Why 255? */
1364 const struct sockaddr_in
*sin
;
1365 struct in_addr addr
, mask
, bcast
;
1367 sin
= (const void *)rti_info
[RTAX_IFA
];
1368 addr
.s_addr
= sin
!= NULL
&& sin
->sin_family
== AF_INET
?
1369 sin
->sin_addr
.s_addr
: INADDR_ANY
;
1370 sin
= (const void *)rti_info
[RTAX_NETMASK
];
1371 mask
.s_addr
= sin
!= NULL
&& sin
->sin_family
== AF_INET
?
1372 sin
->sin_addr
.s_addr
: INADDR_ANY
;
1373 sin
= (const void *)rti_info
[RTAX_BRD
];
1374 bcast
.s_addr
= sin
!= NULL
&& sin
->sin_family
== AF_INET
?
1375 sin
->sin_addr
.s_addr
: INADDR_ANY
;
1378 * NetBSD-7 and older send an invalid broadcast address.
1379 * So we need to query the actual address to get
1381 * We can also use this to test if the address
1382 * has really been added or deleted.
1385 struct in_aliasreq ifra
;
1387 memset(&ifra
, 0, sizeof(ifra
));
1388 strlcpy(ifra
.ifra_name
, ifp
->name
, sizeof(ifra
.ifra_name
));
1389 ifra
.ifra_addr
.sin_family
= AF_INET
;
1390 ifra
.ifra_addr
.sin_len
= sizeof(ifra
.ifra_addr
);
1391 ifra
.ifra_addr
.sin_addr
= addr
;
1392 if (ioctl(ctx
->pf_inet_fd
, SIOCGIFALIAS
, &ifra
) == -1) {
1393 if (errno
!= ENXIO
&& errno
!= EADDRNOTAVAIL
)
1394 logerr("%s: SIOCGIFALIAS", __func__
);
1395 if (ifam
->ifam_type
!= RTM_DELADDR
)
1398 if (ifam
->ifam_type
== RTM_DELADDR
)
1400 #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
1401 bcast
= ifra
.ifra_broadaddr
.sin_addr
;
1405 #warning No SIOCGIFALIAS support
1407 * No SIOCGIFALIAS? That sucks!
1408 * This makes this call very heavy weight, but we
1409 * really need to know if the message is late or not.
1411 const struct sockaddr
*sa
;
1412 struct ifaddrs
*ifaddrs
= NULL
, *ifa
;
1414 sa
= rti_info
[RTAX_IFA
];
1415 #ifdef PRIVSEP_GETIFADDRS
1416 if (IN_PRIVSEP(ctx
)) {
1417 if (ps_root_getifaddrs(ctx
, &ifaddrs
) == -1) {
1418 logerr("ps_root_getifaddrs");
1423 if (getifaddrs(&ifaddrs
) == -1) {
1424 logerr("getifaddrs");
1427 for (ifa
= ifaddrs
; ifa
; ifa
= ifa
->ifa_next
) {
1428 if (ifa
->ifa_addr
== NULL
)
1430 if (sa_cmp(ifa
->ifa_addr
, sa
) == 0 &&
1431 strcmp(ifa
->ifa_name
, ifp
->name
) == 0)
1434 #ifdef PRIVSEP_GETIFADDRS
1435 if (IN_PRIVSEP(ctx
))
1439 freeifaddrs(ifaddrs
);
1440 if (ifam
->ifam_type
== RTM_DELADDR
) {
1449 #ifdef HAVE_IFAM_ADDRFLAGS
1450 flags
= ifam
->ifam_addrflags
;
1455 ipv4_handleifa(ctx
, ifam
->ifam_type
, NULL
, ifp
->name
,
1456 &addr
, &mask
, &bcast
, flags
, pid
);
1463 struct in6_addr addr6
, mask6
;
1464 const struct sockaddr_in6
*sin6
;
1466 sin6
= (const void *)rti_info
[RTAX_IFA
];
1467 addr6
= sin6
->sin6_addr
;
1468 sin6
= (const void *)rti_info
[RTAX_NETMASK
];
1469 mask6
= sin6
->sin6_addr
;
1472 * If the address was deleted, lets check if it's
1473 * a late message and it still exists (maybe modified).
1474 * If so, ignore it as deleting an address causes
1475 * dhcpcd to drop any lease to which it belongs.
1476 * Also check an added address was really added.
1478 flags
= if_addrflags6(ifp
, &addr6
, NULL
);
1480 if (errno
!= ENXIO
&& errno
!= EADDRNOTAVAIL
)
1481 logerr("%s: if_addrflags6", __func__
);
1482 if (ifam
->ifam_type
!= RTM_DELADDR
)
1485 } else if (ifam
->ifam_type
== RTM_DELADDR
)
1489 if (IN6_IS_ADDR_LINKLOCAL(&addr6
))
1490 /* Remove the scope from the address */
1491 addr6
.s6_addr
[2] = addr6
.s6_addr
[3] = '\0';
1494 ipv6_handleifa(ctx
, ifam
->ifam_type
, NULL
,
1495 ifp
->name
, &addr6
, ipv6_prefixlen(&mask6
), flags
, pid
);
1505 if_dispatch(struct dhcpcd_ctx
*ctx
, const struct rt_msghdr
*rtm
)
1508 if (rtm
->rtm_version
!= RTM_VERSION
)
1511 switch(rtm
->rtm_type
) {
1512 #ifdef RTM_IFANNOUNCE
1513 case RTM_IFANNOUNCE
:
1514 return if_announce(ctx
, (const void *)rtm
);
1517 return if_ifinfo(ctx
, (const void *)rtm
);
1518 case RTM_ADD
: /* FALLTHROUGH */
1519 case RTM_CHANGE
: /* FALLTHROUGH */
1520 case RTM_DELETE
: /* FALLTHROUGH */
1522 return if_rtm(ctx
, (const void *)rtm
);
1524 case RTM_CHGADDR
: /* FALLTHROUGH */
1526 case RTM_DELADDR
: /* FALLTHROUGH */
1528 return if_ifa(ctx
, (const void *)rtm
);
1531 dhcpcd_linkoverflow(ctx
);
1532 #elif !defined(SO_RERROR)
1533 #warning cannot detect route socket overflow within kernel
1541 if_missfilter0(struct dhcpcd_ctx
*ctx
, struct interface
*ifp
,
1542 struct sockaddr
*sa
)
1544 size_t salen
= (size_t)RT_ROUNDUP(sa
->sa_len
);
1545 size_t newlen
= ctx
->rt_missfilterlen
+ salen
;
1546 size_t diff
= salen
- (sa
->sa_len
);
1549 if (ctx
->rt_missfiltersize
< newlen
) {
1550 void *n
= realloc(ctx
->rt_missfilter
, newlen
);
1553 ctx
->rt_missfilter
= n
;
1554 ctx
->rt_missfiltersize
= newlen
;
1558 if (sa
->sa_family
== AF_INET6
)
1559 ipv6_setscope(satosin6(sa
), ifp
->index
);
1564 cp
= ctx
->rt_missfilter
+ ctx
->rt_missfilterlen
;
1565 memcpy(cp
, sa
, sa
->sa_len
);
1567 memset(cp
+ sa
->sa_len
, 0, diff
);
1568 ctx
->rt_missfilterlen
+= salen
;
1571 if (sa
->sa_family
== AF_INET6
)
1572 ipv6_setscope(satosin6(sa
), 0);
1579 if_missfilter(struct interface
*ifp
, struct sockaddr
*sa
)
1582 return if_missfilter0(ifp
->ctx
, ifp
, sa
);
1586 if_missfilter_apply(struct dhcpcd_ctx
*ctx
)
1588 #ifdef RO_MISSFILTER
1589 if (ctx
->rt_missfilterlen
== 0) {
1590 struct sockaddr sa
= {
1591 .sa_family
= AF_UNSPEC
,
1592 .sa_len
= sizeof(sa
),
1595 if (if_missfilter0(ctx
, NULL
, &sa
) == -1)
1599 return setsockopt(ctx
->link_fd
, PF_ROUTE
, RO_MISSFILTER
,
1600 ctx
->rt_missfilter
, (socklen_t
)ctx
->rt_missfilterlen
);
1602 #warning kernel does not support RTM_MISS DST filtering
1609 __CTASSERT(offsetof(struct rt_msghdr
, rtm_msglen
) == 0);
1611 if_handlelink(struct dhcpcd_ctx
*ctx
)
1616 len
= read(ctx
->link_fd
, &rtm
, sizeof(rtm
));
1621 if ((size_t)len
< sizeof(rtm
.hdr
.rtm_msglen
) ||
1622 len
!= rtm
.hdr
.rtm_msglen
)
1628 * Coverity thinks that the data could be tainted from here.
1629 * I have no idea how because the length of the data we read
1630 * is guarded by len and checked to match rtm_msglen.
1631 * The issue seems to be related to extracting the addresses
1632 * at the end of the header, but seems to have no issues with the
1633 * equivalent call in if_initrt.
1635 /* coverity[tainted_data] */
1636 return if_dispatch(ctx
, &rtm
.hdr
);
1639 #ifndef SYS_NMLN /* OSX */
1640 # define SYS_NMLN __SYS_NAMELEN
1642 #ifndef HW_MACHINE_ARCH
1643 # ifdef HW_MODEL /* OpenBSD */
1644 # define HW_MACHINE_ARCH HW_MODEL
1648 if_machinearch(char *str
, size_t len
)
1650 int mib
[2] = { CTL_HW
, HW_MACHINE_ARCH
};
1652 return sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), str
, &len
, NULL
, 0);
1656 #if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) || \
1657 defined(IPV6CTL_FORWARDING)
1658 #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
1659 #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
1661 inet6_sysctl(int code
, int val
, int action
)
1663 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1669 if (sysctl(mib
, __arraycount(mib
), NULL
, 0, &val
, size
) == -1)
1673 if (sysctl(mib
, __arraycount(mib
), &val
, &size
, NULL
, 0) == -1)
1680 if_applyra(const struct ra
*rap
)
1682 #ifdef SIOCSIFINFO_IN6
1683 struct in6_ndireq nd
= { .ndi
.chlim
= 0 };
1684 struct dhcpcd_ctx
*ctx
= rap
->iface
->ctx
;
1687 strlcpy(nd
.ifname
, rap
->iface
->name
, sizeof(nd
.ifname
));
1689 #ifdef IPV6CTL_ACCEPT_RTADV
1690 struct priv
*priv
= ctx
->priv
;
1693 * NetBSD changed SIOCSIFINFO_IN6 to NOT set flags when kernel
1694 * RA was removed, however both FreeBSD and DragonFlyBSD still do.
1695 * linkmtu was also removed.
1696 * Hopefully this guard will still work if either remove kernel RA.
1698 if (ioctl(priv
->pf_inet6_fd
, SIOCGIFINFO_IN6
, &nd
, sizeof(nd
)) == -1)
1701 nd
.ndi
.linkmtu
= rap
->mtu
;
1704 nd
.ndi
.chlim
= rap
->hoplimit
;
1705 nd
.ndi
.retrans
= rap
->retrans
;
1706 nd
.ndi
.basereachable
= rap
->reachable
;
1707 error
= if_ioctl6(ctx
, SIOCSIFINFO_IN6
, &nd
, sizeof(nd
));
1708 #ifdef IPV6CTL_ACCEPT_RTADV
1709 if (error
== -1 && errno
== EINVAL
) {
1711 * Very likely that this is caused by a dodgy MTU
1712 * setting specific to the interface.
1713 * Let's set it to "unspecified" and try again.
1714 * Doesn't really matter as we fix the MTU against the
1715 * routes we add as not all OS support SIOCSIFINFO_IN6.
1718 error
= if_ioctl6(ctx
, SIOCSIFINFO_IN6
, &nd
, sizeof(nd
));
1723 #warning OS does not allow setting of RA bits hoplimit, retrans or reachable
1729 #ifndef IPV6CTL_FORWARDING
1730 #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
1731 #define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
1733 inet6_sysctlbyname(const char *name
, int val
, int action
)
1739 if (sysctlbyname(name
, NULL
, 0, &val
, size
) == -1)
1743 if (sysctlbyname(name
, &val
, &size
, NULL
, 0) == -1)
1750 ip6_forwarding(__unused
const char *ifname
)
1754 #ifdef IPV6CTL_FORWARDING
1755 val
= get_inet6_sysctl(IPV6CTL_FORWARDING
);
1757 val
= get_inet6_sysctlbyname("net.inet6.ip6.forwarding");
1759 return val
< 0 ? 0 : val
;
1762 #ifdef SIOCIFAFATTACH
1764 if_af_attach(const struct interface
*ifp
, int af
)
1766 struct if_afreq ifar
= { .ifar_af
= af
};
1768 strlcpy(ifar
.ifar_name
, ifp
->name
, sizeof(ifar
.ifar_name
));
1769 return if_ioctl6(ifp
->ctx
, SIOCIFAFATTACH
, &ifar
, sizeof(ifar
));
1773 #ifdef SIOCGIFXFLAGS
1775 if_set_ifxflags(const struct interface
*ifp
)
1779 struct priv
*priv
= ifp
->ctx
->priv
;
1781 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
1782 if (ioctl(priv
->pf_inet6_fd
, SIOCGIFXFLAGS
, &ifr
) == -1)
1784 flags
= ifr
.ifr_flags
;
1786 flags
&= ~IFXF_NOINET6
;
1789 * If not doing autoconf, don't disable the kernel from doing it.
1790 * If we need to, we should have another option actively disable it.
1792 * OpenBSD moved from kernel based SLAAC to userland via slaacd(8).
1793 * It has a similar featureset to dhcpcd such as stable private
1794 * addresses, but lacks the ability to handle DNS inside the RA
1795 * which is a serious shortfall in this day and age.
1796 * Appease their user base by working alongside slaacd(8) if
1797 * dhcpcd is instructed not to do auto configuration of addresses.
1799 #if defined(ND6_IFF_ACCEPT_RTADV)
1800 #define BSD_AUTOCONF DHCPCD_IPV6RS
1802 #define BSD_AUTOCONF DHCPCD_IPV6RA_AUTOCONF
1804 if (ifp
->options
->options
& BSD_AUTOCONF
)
1805 flags
&= ~IFXF_AUTOCONF6
;
1806 if (ifr
.ifr_flags
== flags
)
1808 ifr
.ifr_flags
= flags
;
1809 return if_ioctl6(ifp
->ctx
, SIOCSIFXFLAGS
, &ifr
, sizeof(ifr
));
1813 /* OpenBSD removed ND6 flags entirely, so we need to check for their
1815 #if defined(ND6_IFF_AUTO_LINKLOCAL) || \
1816 defined(ND6_IFF_PERFORMNUD) || \
1817 defined(ND6_IFF_ACCEPT_RTADV) || \
1818 defined(ND6_IFF_OVERRIDE_RTADV) || \
1819 defined(ND6_IFF_IFDISABLED)
1820 #define ND6_NDI_FLAGS
1824 if_disable_rtadv(void)
1826 #if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)
1827 int ra
= get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV
);
1830 if (errno
!= ENOENT
)
1831 logerr("IPV6CTL_ACCEPT_RTADV");
1833 if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV
, 0) == -1)
1834 logerr("IPV6CTL_ACCEPT_RTADV");
1840 if_setup_inet6(const struct interface
*ifp
)
1842 #ifdef ND6_NDI_FLAGS
1845 struct in6_ndireq nd
;
1848 priv
= (struct priv
*)ifp
->ctx
->priv
;
1849 s
= priv
->pf_inet6_fd
;
1851 memset(&nd
, 0, sizeof(nd
));
1852 strlcpy(nd
.ifname
, ifp
->name
, sizeof(nd
.ifname
));
1853 if (ioctl(s
, SIOCGIFINFO_IN6
, &nd
) == -1)
1854 logerr("%s: SIOCGIFINFO_FLAGS", ifp
->name
);
1855 flags
= (int)nd
.ndi
.flags
;
1857 #ifdef ND6_IFF_AUTO_LINKLOCAL
1858 /* Unlike the kernel, dhcpcd make make a stable private address. */
1859 flags
&= ~ND6_IFF_AUTO_LINKLOCAL
;
1862 #ifdef ND6_IFF_PERFORMNUD
1863 /* NUD is kind of essential. */
1864 flags
|= ND6_IFF_PERFORMNUD
;
1867 #ifdef ND6_IFF_IFDISABLED
1868 /* Ensure the interface is not disabled. */
1869 flags
&= ~ND6_IFF_IFDISABLED
;
1873 * If not doing autoconf, don't disable the kernel from doing it.
1874 * If we need to, we should have another option actively disable it.
1876 #ifdef ND6_IFF_ACCEPT_RTADV
1877 if (ifp
->options
->options
& DHCPCD_IPV6RS
)
1878 flags
&= ~ND6_IFF_ACCEPT_RTADV
;
1879 #ifdef ND6_IFF_OVERRIDE_RTADV
1880 if (ifp
->options
->options
& DHCPCD_IPV6RS
)
1881 flags
|= ND6_IFF_OVERRIDE_RTADV
;
1885 if (nd
.ndi
.flags
!= (uint32_t)flags
) {
1886 nd
.ndi
.flags
= (uint32_t)flags
;
1887 if (if_ioctl6(ifp
->ctx
, SIOCSIFINFO_FLAGS
,
1888 &nd
, sizeof(nd
)) == -1)
1889 logerr("%s: SIOCSIFINFO_FLAGS", ifp
->name
);
1891 #endif /* ND6_NDI_FLAGS */
1893 /* Enabling IPv6 by whatever means must be the
1894 * last action undertaken to ensure kernel RS and
1895 * LLADDR auto configuration are disabled where applicable. */
1896 #ifdef SIOCIFAFATTACH
1897 if (if_af_attach(ifp
, AF_INET6
) == -1)
1898 logerr("%s: if_af_attach", ifp
->name
);
1901 #ifdef SIOCGIFXFLAGS
1902 if (if_set_ifxflags(ifp
) == -1)
1903 logerr("%s: set_ifxflags", ifp
->name
);
1906 #ifdef SIOCSRTRFLUSH_IN6
1907 /* Flush the kernel knowledge of advertised routers
1908 * and prefixes so the kernel does not expire prefixes
1909 * and default routes we are trying to own. */
1910 if (ifp
->options
->options
& DHCPCD_IPV6RS
) {
1911 struct in6_ifreq ifr
;
1913 memset(&ifr
, 0, sizeof(ifr
));
1914 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
1915 if (if_ioctl6(ifp
->ctx
, SIOCSRTRFLUSH_IN6
,
1916 &ifr
, sizeof(ifr
)) == -1 &&
1917 errno
!= ENOTSUP
&& errno
!= ENOTTY
)
1918 logwarn("SIOCSRTRFLUSH_IN6 %d", errno
);
1919 #ifdef SIOCSPFXFLUSH_IN6
1920 if (if_ioctl6(ifp
->ctx
, SIOCSPFXFLUSH_IN6
,
1921 &ifr
, sizeof(ifr
)) == -1 &&
1922 errno
!= ENOTSUP
&& errno
!= ENOTTY
)
1923 logwarn("SIOCSPFXFLUSH_IN6");