1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * BSD interface driver for dhcpcd
4 * Copyright (c) 2006-2019 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 /* FIXME: Add apple includes so we can work out SSID */
64 # include <net80211/ieee80211.h>
65 # include <net80211/ieee80211_ioctl.h>
79 #if defined(OpenBSD) && OpenBSD >= 201411
80 /* OpenBSD dropped the global setting from sysctl but left the #define
81 * which causes a EPERM error when trying to use it.
82 * I think both the error and keeping the define are wrong, so we #undef it. */
83 #undef IPV6CTL_ACCEPT_RTADV
89 #include "if-options.h"
99 #define RT_ROUNDUP(a) \
100 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
101 #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
105 static void ifa_setscope(struct sockaddr_in6
*, unsigned int);
106 static unsigned int ifa_getscope(const struct sockaddr_in6
*);
115 struct rt_msghdr hdr
;
116 char buffer
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
120 if_init(__unused
struct interface
*iface
)
122 /* BSD promotes secondary address by default */
127 if_conf(__unused
struct interface
*iface
)
129 /* No extra checks needed on BSD */
134 if_opensockets_os(struct dhcpcd_ctx
*ctx
)
138 #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
139 unsigned char msgfilter
[] = {
141 #ifdef RTM_IFANNOUNCE
144 RTM_ADD
, RTM_CHANGE
, RTM_DELETE
, RTM_MISS
,
148 RTM_NEWADDR
, RTM_DELADDR
150 #ifdef ROUTE_MSGFILTER
151 unsigned int i
, msgfilter_mask
;
155 if ((priv
= malloc(sizeof(*priv
))) == NULL
)
160 priv
->pf_inet6_fd
= xsocket(PF_INET6
, SOCK_DGRAM
| SOCK_CLOEXEC
, 0);
161 /* Don't return an error so we at least work on kernels witout INET6
162 * even though we expect INET6 support.
163 * We will fail noisily elsewhere anyway. */
165 priv
->pf_inet6_fd
= -1;
168 #define SOCK_FLAGS (SOCK_CLOEXEC | SOCK_NONBLOCK)
169 ctx
->link_fd
= xsocket(PF_ROUTE
, SOCK_RAW
| SOCK_FLAGS
, AF_UNSPEC
);
171 if (ctx
->link_fd
== -1)
174 /* Ignore our own route(4) messages.
175 * Sadly there is no way of doing this for route(4) messages
176 * generated from addresses we add/delete. */
178 if (setsockopt(ctx
->link_fd
, SOL_SOCKET
, SO_USELOOPBACK
,
179 &n
, sizeof(n
)) == -1)
180 logerr("%s: SO_USELOOPBACK", __func__
);
182 #if defined(RO_MSGFILTER)
183 if (setsockopt(ctx
->link_fd
, PF_ROUTE
, RO_MSGFILTER
,
184 &msgfilter
, sizeof(msgfilter
)) == -1)
186 #elif defined(ROUTE_MSGFILTER)
187 /* Convert the array into a bitmask. */
189 for (i
= 0; i
< __arraycount(msgfilter
); i
++)
190 msgfilter_mask
|= ROUTE_FILTER(msgfilter
[i
]);
191 if (setsockopt(ctx
->link_fd
, PF_ROUTE
, ROUTE_MSGFILTER
,
192 &msgfilter_mask
, sizeof(msgfilter_mask
)) == -1)
195 #warning kernel does not support route message filtering
202 if_closesockets_os(struct dhcpcd_ctx
*ctx
)
206 priv
= (struct priv
*)ctx
->priv
;
207 if (priv
->pf_inet6_fd
!= -1)
208 close(priv
->pf_inet6_fd
);
212 if_carrier(struct interface
*ifp
)
214 struct ifmediareq ifmr
= { .ifm_status
= 0 };
216 strlcpy(ifmr
.ifm_name
, ifp
->name
, sizeof(ifmr
.ifm_name
));
217 if (ioctl(ifp
->ctx
->pf_inet_fd
, SIOCGIFMEDIA
, &ifmr
) == -1 ||
218 !(ifmr
.ifm_status
& IFM_AVALID
))
221 return (ifmr
.ifm_status
& IFM_ACTIVE
) ? LINK_UP
: LINK_DOWN
;
225 if_linkaddr(struct sockaddr_dl
*sdl
, const struct interface
*ifp
)
228 memset(sdl
, 0, sizeof(*sdl
));
229 sdl
->sdl_family
= AF_LINK
;
230 sdl
->sdl_len
= sizeof(*sdl
);
231 sdl
->sdl_nlen
= sdl
->sdl_alen
= sdl
->sdl_slen
= 0;
232 sdl
->sdl_index
= (unsigned short)ifp
->index
;
235 #if defined(SIOCG80211NWID) || defined(SIOCGETVLAN)
236 static int if_direct_ioctl(int s
, const char *ifname
,
237 unsigned long cmd
, void *data
)
240 strlcpy(data
, ifname
, IFNAMSIZ
);
241 return ioctl(s
, cmd
, data
);
244 static int if_indirect_ioctl(int s
, const char *ifname
,
245 unsigned long cmd
, void *data
)
249 memset(&ifr
, 0, sizeof(ifr
));
251 return if_direct_ioctl(s
, ifname
, cmd
, &ifr
);
256 if_getssid1(int s
, const char *ifname
, void *ssid
)
259 #if defined(SIOCG80211NWID)
260 struct ieee80211_nwid nwid
;
261 #elif defined(IEEE80211_IOC_SSID)
262 struct ieee80211req ireq
;
263 char nwid
[IEEE80211_NWID_LEN
];
266 #if defined(SIOCG80211NWID) /* NetBSD */
267 memset(&nwid
, 0, sizeof(nwid
));
268 if (if_indirect_ioctl(s
, ifname
, SIOCG80211NWID
, &nwid
) == 0) {
271 else if (nwid
.i_len
> IF_SSIDLEN
)
275 memcpy(ssid
, nwid
.i_nwid
, nwid
.i_len
);
278 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
279 memset(&ireq
, 0, sizeof(ireq
));
280 strlcpy(ireq
.i_name
, ifname
, sizeof(ireq
.i_name
));
281 ireq
.i_type
= IEEE80211_IOC_SSID
;
283 memset(nwid
, 0, sizeof(nwid
));
285 if (ioctl(s
, SIOCG80211
, &ireq
) == 0) {
288 else if (ireq
.i_len
> IF_SSIDLEN
)
292 memcpy(ssid
, nwid
, ireq
.i_len
);
303 if_getssid(struct interface
*ifp
)
307 r
= if_getssid1(ifp
->ctx
->pf_inet_fd
, ifp
->name
, ifp
->ssid
);
309 ifp
->ssid_len
= (unsigned int)r
;
312 ifp
->ssid
[ifp
->ssid_len
] = '\0';
317 * FreeBSD allows for Virtual Access Points
318 * We need to check if the interface is a Virtual Interface Master
319 * and if so, don't use it.
320 * This check is made by virtue of being a IEEE80211 device but
321 * returning the SSID gives an error.
324 if_vimaster(const struct dhcpcd_ctx
*ctx
, const char *ifname
)
327 struct ifmediareq ifmr
;
329 memset(&ifmr
, 0, sizeof(ifmr
));
330 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
331 r
= ioctl(ctx
->pf_inet_fd
, SIOCGIFMEDIA
, &ifmr
);
334 if (ifmr
.ifm_status
& IFM_AVALID
&&
335 IFM_TYPE(ifmr
.ifm_active
) == IFM_IEEE80211
)
337 if (if_getssid1(ctx
->pf_inet_fd
, ifname
, NULL
) == -1)
344 if_vlanid(const struct interface
*ifp
)
349 memset(&vlr
, 0, sizeof(vlr
));
350 if (if_indirect_ioctl(ifp
->ctx
->pf_inet_fd
,
351 ifp
->name
, SIOCGETVLAN
, &vlr
) != 0)
352 return 0; /* 0 means no VLANID */
354 #elif defined(SIOCGVNETID)
357 memset(&ifr
, 0, sizeof(ifr
));
358 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
359 if (ioctl(ifp
->ctx
->pf_inet_fd
, SIOCGVNETID
, &ifr
) != 0)
360 return 0; /* 0 means no VLANID */
361 return ifr
.ifr_vnetid
;
364 return 0; /* 0 means no VLANID */
369 get_addrs(int type
, const void *data
, size_t data_len
,
370 const struct sockaddr
**sa
)
377 for (i
= 0; i
< RTAX_MAX
; i
++) {
378 if (type
& (1 << i
)) {
383 sa
[i
] = (const struct sockaddr
*)cp
;
384 RT_ADVANCE(cp
, sa
[i
]);
392 static struct interface
*
393 if_findsdl(struct dhcpcd_ctx
*ctx
, const struct sockaddr_dl
*sdl
)
397 return if_findindex(ctx
->ifaces
, sdl
->sdl_index
);
400 char ifname
[IF_NAMESIZE
];
402 memcpy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
403 ifname
[sdl
->sdl_nlen
] = '\0';
404 return if_find(ctx
->ifaces
, ifname
);
407 struct interface
*ifp
;
409 TAILQ_FOREACH(ifp
, ctx
->ifaces
, next
) {
410 if (ifp
->hwlen
== sdl
->sdl_alen
&&
412 sdl
->sdl_data
, sdl
->sdl_alen
) == 0)
421 static struct interface
*
422 if_findsa(struct dhcpcd_ctx
*ctx
, const struct sockaddr
*sa
)
429 switch (sa
->sa_family
) {
432 const struct sockaddr_dl
*sdl
;
434 sdl
= (const void *)sa
;
435 return if_findsdl(ctx
, sdl
);
440 const struct sockaddr_in
*sin
;
441 struct ipv4_addr
*ia
;
443 sin
= (const void *)sa
;
444 if ((ia
= ipv4_findmaskaddr(ctx
, &sin
->sin_addr
)))
452 const struct sockaddr_in6
*sin
;
454 struct ipv6_addr
*ia
;
456 sin
= (const void *)sa
;
457 scope
= ifa_getscope(sin
);
459 return if_findindex(ctx
->ifaces
, scope
);
460 if ((ia
= ipv6_findmaskaddr(ctx
, &sin
->sin6_addr
)))
466 errno
= EAFNOSUPPORT
;
475 if_copysa(struct sockaddr
*dst
, const struct sockaddr
*src
)
481 memcpy(dst
, src
, src
->sa_len
);
482 #if defined(INET6) && defined(__KAME__)
483 if (dst
->sa_family
== AF_INET6
) {
484 struct in6_addr
*in6
;
486 in6
= &satosin6(dst
)->sin6_addr
;
487 if (IN6_IS_ADDR_LINKLOCAL(in6
))
488 in6
->s6_addr
[2] = in6
->s6_addr
[3] = '\0';
494 if_route(unsigned char cmd
, const struct rt
*rt
)
496 struct dhcpcd_ctx
*ctx
;
498 struct rt_msghdr
*rtm
= &rtmsg
.hdr
;
499 char *bp
= rtmsg
.buffer
;
500 struct sockaddr_dl sdl
;
504 assert(rt
->rt_ifp
!= NULL
);
505 assert(rt
->rt_ifp
->ctx
!= NULL
);
506 ctx
= rt
->rt_ifp
->ctx
;
508 #define ADDSA(sa) do { \
509 memcpy(bp, (sa), (sa)->sa_len); \
510 bp += RT_ROUNDUP((sa)->sa_len); \
511 } while (0 /* CONSTCOND */)
513 memset(&rtmsg
, 0, sizeof(rtmsg
));
514 rtm
->rtm_version
= RTM_VERSION
;
517 rtm
->rtm_pid
= getpid();
519 rtm
->rtm_seq
= ++ctx
->seq
;
520 rtm
->rtm_flags
= (int)rt
->rt_flags
;
521 rtm
->rtm_addrs
= RTA_DST
;
524 rtm
->rtm_flags
|= RTF_PINNED
;
527 gateway_unspec
= sa_is_unspecified(&rt
->rt_gateway
);
529 if (cmd
== RTM_ADD
|| cmd
== RTM_CHANGE
) {
530 bool netmask_bcast
= sa_is_allones(&rt
->rt_netmask
);
532 rtm
->rtm_flags
|= RTF_UP
;
533 rtm
->rtm_addrs
|= RTA_GATEWAY
;
534 if (!(rtm
->rtm_flags
& RTF_REJECT
) &&
535 !sa_is_loopback(&rt
->rt_gateway
))
537 rtm
->rtm_index
= (unsigned short)rt
->rt_ifp
->index
;
539 * OpenBSD rejects the message for on-link routes.
540 * FreeBSD-12 kernel apparently panics.
541 * I can't replicate the panic, but better safe than sorry!
542 * https://roy.marples.name/archives/dhcpcd-discuss/0002286.html
544 * Neither OS currently allows IPv6 address sharing anyway, so let's
545 * try to encourage someone to fix that by logging a waring during compile.
547 #if defined(__FreeBSD__) || defined(__OpenBSD__)
548 #warning kernel does not allow IPv6 address sharing
549 if (!gateway_unspec
|| rt
->rt_dest
.sa_family
!=AF_INET6
)
551 rtm
->rtm_addrs
|= RTA_IFP
;
552 if (!sa_is_unspecified(&rt
->rt_ifa
))
553 rtm
->rtm_addrs
|= RTA_IFA
;
556 rtm
->rtm_flags
|= RTF_HOST
;
557 /* Network routes are cloning or connected if supported.
558 * All other routes are static. */
559 if (gateway_unspec
) {
561 rtm
->rtm_flags
|= RTF_CLONING
;
564 rtm
->rtm_flags
|= RTF_CONNECTED
;
567 rtm
->rtm_priority
= RTP_CONNECTED
;
572 * We add a cloning network route for a single
573 * host. Traffic to the host will generate a
574 * cloned route and the hardware address will
576 * It might be more correct to use RTF_HOST
577 * instead of RTF_CLONING, and that does work,
578 * but some OS generate an arp warning
579 * diagnostic which we don't want to do.
581 rtm
->rtm_flags
&= ~RTF_HOST
;
585 rtm
->rtm_flags
|= RTF_GATEWAY
;
587 /* Emulate the kernel by marking address generated
588 * network routes non-static. */
589 if (!(rt
->rt_dflags
& RTDF_IFA_ROUTE
))
590 rtm
->rtm_flags
|= RTF_STATIC
;
592 if (rt
->rt_mtu
!= 0) {
593 rtm
->rtm_inits
|= RTV_MTU
;
594 rtm
->rtm_rmx
.rmx_mtu
= rt
->rt_mtu
;
598 if (!(rtm
->rtm_flags
& RTF_HOST
))
599 rtm
->rtm_addrs
|= RTA_NETMASK
;
601 if_linkaddr(&sdl
, rt
->rt_ifp
);
605 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
607 ADDSA((struct sockaddr
*)&sdl
);
611 if_copysa(&gateway
.sa
, &rt
->rt_gateway
);
613 if (gateway
.sa
.sa_family
== AF_INET6
)
614 ifa_setscope(&gateway
.sin6
, rt
->rt_ifp
->index
);
620 if (rtm
->rtm_addrs
& RTA_NETMASK
)
621 ADDSA(&rt
->rt_netmask
);
623 if (rtm
->rtm_addrs
& RTA_IFP
)
624 ADDSA((struct sockaddr
*)&sdl
);
626 if (rtm
->rtm_addrs
& RTA_IFA
)
631 rtm
->rtm_msglen
= (unsigned short)(bp
- (char *)rtm
);
632 if (write(ctx
->link_fd
, rtm
, rtm
->rtm_msglen
) == -1)
638 if_copyrt(struct dhcpcd_ctx
*ctx
, struct rt
*rt
, const struct rt_msghdr
*rtm
)
640 const struct sockaddr
*rti_info
[RTAX_MAX
];
642 if (!(rtm
->rtm_addrs
& RTA_DST
)) {
646 if (rtm
->rtm_type
!= RTM_MISS
&& !(rtm
->rtm_addrs
& RTA_GATEWAY
)) {
651 if (rtm
->rtm_flags
& RTF_CLONED
) {
657 if (rtm
->rtm_flags
& RTF_LOCAL
) {
663 if (rtm
->rtm_flags
& RTF_BROADCAST
) {
669 if (get_addrs(rtm
->rtm_addrs
, (const char *)rtm
+ sizeof(*rtm
),
670 rtm
->rtm_msglen
- sizeof(*rtm
), rti_info
) == -1)
672 memset(rt
, 0, sizeof(*rt
));
674 rt
->rt_flags
= (unsigned int)rtm
->rtm_flags
;
675 if_copysa(&rt
->rt_dest
, rti_info
[RTAX_DST
]);
676 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
677 if_copysa(&rt
->rt_netmask
, rti_info
[RTAX_NETMASK
]);
678 if (rt
->rt_netmask
.sa_family
== 255) /* Why? */
679 rt
->rt_netmask
.sa_family
= rt
->rt_dest
.sa_family
;
682 /* dhcpcd likes an unspecified gateway to indicate via the link.
683 * However we need to know if gateway was a link with an address. */
684 if (rtm
->rtm_addrs
& RTA_GATEWAY
) {
685 if (rti_info
[RTAX_GATEWAY
]->sa_family
== AF_LINK
) {
686 const struct sockaddr_dl
*sdl
;
688 sdl
= (const struct sockaddr_dl
*)
689 (const void *)rti_info
[RTAX_GATEWAY
];
690 if (sdl
->sdl_alen
!= 0)
691 rt
->rt_dflags
|= RTDF_GATELINK
;
692 } else if (rtm
->rtm_flags
& RTF_GATEWAY
)
693 if_copysa(&rt
->rt_gateway
, rti_info
[RTAX_GATEWAY
]);
696 if (rtm
->rtm_addrs
& RTA_IFA
)
697 if_copysa(&rt
->rt_ifa
, rti_info
[RTAX_IFA
]);
699 rt
->rt_mtu
= (unsigned int)rtm
->rtm_rmx
.rmx_mtu
;
702 rt
->rt_ifp
= if_findindex(ctx
->ifaces
, rtm
->rtm_index
);
703 else if (rtm
->rtm_addrs
& RTA_IFP
)
704 rt
->rt_ifp
= if_findsa(ctx
, rti_info
[RTAX_IFP
]);
705 else if (rtm
->rtm_addrs
& RTA_GATEWAY
)
706 rt
->rt_ifp
= if_findsa(ctx
, rti_info
[RTAX_GATEWAY
]);
708 rt
->rt_ifp
= if_findsa(ctx
, rti_info
[RTAX_DST
]);
710 if (rt
->rt_ifp
== NULL
&& rtm
->rtm_type
== RTM_MISS
)
711 rt
->rt_ifp
= if_find(ctx
->ifaces
, "lo0");
713 if (rt
->rt_ifp
== NULL
) {
721 if_initrt(struct dhcpcd_ctx
*ctx
, rb_tree_t
*kroutes
, int af
)
723 struct rt_msghdr
*rtm
;
733 mib
[4] = NET_RT_DUMP
;
736 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
740 if ((buf
= malloc(needed
)) == NULL
)
742 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1) {
748 for (p
= buf
; p
< end
; p
+= rtm
->rtm_msglen
) {
750 if (p
+ rtm
->rtm_msglen
>= end
) {
754 if (if_copyrt(ctx
, &rt
, rtm
) != 0)
756 if ((rtn
= rt_new(rt
.rt_ifp
)) == NULL
) {
760 memcpy(rtn
, &rt
, sizeof(*rtn
));
761 if (rb_tree_insert_node(kroutes
, rtn
) != rtn
)
765 return p
== end
? 0 : -1;
770 if_address(unsigned char cmd
, const struct ipv4_addr
*ia
)
773 struct in_aliasreq ifra
;
775 memset(&ifra
, 0, sizeof(ifra
));
776 strlcpy(ifra
.ifra_name
, ia
->iface
->name
, sizeof(ifra
.ifra_name
));
778 #define ADDADDR(var, addr) do { \
779 (var)->sin_family = AF_INET; \
780 (var)->sin_len = sizeof(*(var)); \
781 (var)->sin_addr = *(addr); \
782 } while (/*CONSTCOND*/0)
783 ADDADDR(&ifra
.ifra_addr
, &ia
->addr
);
784 ADDADDR(&ifra
.ifra_mask
, &ia
->mask
);
785 if (cmd
== RTM_NEWADDR
&& ia
->brd
.s_addr
!= INADDR_ANY
)
786 ADDADDR(&ifra
.ifra_broadaddr
, &ia
->brd
);
789 r
= ioctl(ia
->iface
->ctx
->pf_inet_fd
,
790 cmd
== RTM_DELADDR
? SIOCDIFADDR
: SIOCAIFADDR
, &ifra
);
796 #if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS))
798 if_addrflags(const struct interface
*ifp
, const struct in_addr
*addr
,
799 __unused
const char *alias
)
801 #ifdef SIOCGIFAFLAG_IN
803 struct sockaddr_in
*sin
;
805 memset(&ifr
, 0, sizeof(ifr
));
806 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
807 sin
= (void *)&ifr
.ifr_addr
;
808 sin
->sin_family
= AF_INET
;
809 sin
->sin_addr
= *addr
;
810 if (ioctl(ifp
->ctx
->pf_inet_fd
, SIOCGIFAFLAG_IN
, &ifr
) == -1)
812 return ifr
.ifr_addrflags
;
824 ifa_setscope(struct sockaddr_in6
*sin
, unsigned int ifindex
)
828 /* KAME based systems want to store the scope inside the sin6_addr
829 * for link local addresses */
830 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
)) {
831 uint16_t scope
= htons((uint16_t)ifindex
);
832 memcpy(&sin
->sin6_addr
.s6_addr
[2], &scope
,
835 sin
->sin6_scope_id
= 0;
837 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
))
838 sin
->sin6_scope_id
= ifindex
;
840 sin
->sin6_scope_id
= 0;
845 ifa_getscope(const struct sockaddr_in6
*sin
)
851 if (!IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
))
854 memcpy(&scope
, &sin
->sin6_addr
.s6_addr
[2], sizeof(scope
));
855 return (unsigned int)ntohs(scope
);
857 return (unsigned int)sin
->sin6_scope_id
;
862 if_address6(unsigned char cmd
, const struct ipv6_addr
*ia
)
864 struct in6_aliasreq ifa
;
865 struct in6_addr mask
;
868 priv
= (struct priv
*)ia
->iface
->ctx
->priv
;
870 memset(&ifa
, 0, sizeof(ifa
));
871 strlcpy(ifa
.ifra_name
, ia
->iface
->name
, sizeof(ifa
.ifra_name
));
873 * We should not set IN6_IFF_TENTATIVE as the kernel should be
874 * able to work out if it's a new address or not.
876 * We should set IN6_IFF_AUTOCONF, but the kernel won't let us.
877 * This is probably a safety measure, but still it's not entirely right
882 ifa
.ifra_flags
|= IN6_IFF_AUTOCONF
;
884 #if defined(__FreeBSD__) || defined(__DragonFly__)
885 if (ia
->addr_flags
& IN6_IFF_TENTATIVE
)
886 ifa
.ifra_flags
|= IN6_IFF_TENTATIVE
;
888 #ifdef IPV6_MANGETEMPADDR
889 if (ia
->flags
& IPV6_AF_TEMPORARY
)
890 ifa
.ifra_flags
|= IN6_IFF_TEMPORARY
;
893 #define ADDADDR(v, addr) { \
894 (v)->sin6_family = AF_INET6; \
895 (v)->sin6_len = sizeof(*v); \
896 (v)->sin6_addr = *(addr); \
899 ADDADDR(&ifa
.ifra_addr
, &ia
->addr
);
900 ifa_setscope(&ifa
.ifra_addr
, ia
->iface
->index
);
901 ipv6_mask(&mask
, ia
->prefix_len
);
902 ADDADDR(&ifa
.ifra_prefixmask
, &mask
);
907 * Every BSD kernel wants to add the prefix of the address to it's
908 * list of RA received prefixes.
909 * THIS IS WRONG because there (as the comments in the kernel state)
910 * is no API for managing prefix lifetime and the kernel should not
911 * pretend it's from a RA either.
913 * The issue is that the very first assigned prefix will inherit the
914 * lifetime of the address, but any subsequent alteration of the
915 * address OR it's lifetime will not affect the prefix lifetime.
916 * As such, we cannot stop the prefix from timing out and then
917 * constantly removing the prefix route dhcpcd is capable of adding
920 * What we can do to mitigate the issue is to add the address with
921 * infinite lifetimes, so the prefix route will never time out.
922 * Once done, we can then set lifetimes on the address and all is good.
923 * The downside of this approach is that we need to manually remove
924 * the kernel route because it has no lifetime, but this is OK as
925 * dhcpcd will handle this too.
927 * This issue is discussed on the NetBSD mailing lists here:
928 * http://mail-index.netbsd.org/tech-net/2016/08/05/msg006044.html
930 * Fixed in NetBSD-7.99.36
931 * NOT fixed in FreeBSD - bug 195197
932 * Fixed in OpenBSD-5.9
935 #if !((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003600) || \
936 (defined(__OpenBSD__) && OpenBSD >= 201605))
937 if (cmd
== RTM_NEWADDR
&& !(ia
->flags
& IPV6_AF_ADDED
)) {
938 ifa
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
939 ifa
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
940 (void)ioctl(priv
->pf_inet6_fd
, SIOCAIFADDR_IN6
, &ifa
);
944 #if defined(__OpenBSD__) && OpenBSD <= 201705
945 /* BUT OpenBSD older than 6.2 does not reset the address lifetime
946 * for subsequent calls...
947 * Luckily dhcpcd will remove the lease when it expires so
948 * just set an infinite lifetime, unless a temporary address. */
949 if (ifa
.ifra_flags
& IN6_IFF_PRIVACY
) {
950 ifa
.ifra_lifetime
.ia6t_vltime
= ia
->prefix_vltime
;
951 ifa
.ifra_lifetime
.ia6t_pltime
= ia
->prefix_pltime
;
953 ifa
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
954 ifa
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
957 ifa
.ifra_lifetime
.ia6t_vltime
= ia
->prefix_vltime
;
958 ifa
.ifra_lifetime
.ia6t_pltime
= ia
->prefix_pltime
;
961 return ioctl(priv
->pf_inet6_fd
,
962 cmd
== RTM_DELADDR
? SIOCDIFADDR_IN6
: SIOCAIFADDR_IN6
, &ifa
);
966 if_addrflags6(const struct interface
*ifp
, const struct in6_addr
*addr
,
967 __unused
const char *alias
)
970 struct in6_ifreq ifr6
;
973 memset(&ifr6
, 0, sizeof(ifr6
));
974 strlcpy(ifr6
.ifr_name
, ifp
->name
, sizeof(ifr6
.ifr_name
));
975 ifr6
.ifr_addr
.sin6_family
= AF_INET6
;
976 ifr6
.ifr_addr
.sin6_addr
= *addr
;
977 ifa_setscope(&ifr6
.ifr_addr
, ifp
->index
);
978 priv
= (struct priv
*)ifp
->ctx
->priv
;
979 if (ioctl(priv
->pf_inet6_fd
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
980 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
987 if_getlifetime6(struct ipv6_addr
*ia
)
989 struct in6_ifreq ifr6
;
991 struct in6_addrlifetime
*lifetime
;
994 memset(&ifr6
, 0, sizeof(ifr6
));
995 strlcpy(ifr6
.ifr_name
, ia
->iface
->name
, sizeof(ifr6
.ifr_name
));
996 ifr6
.ifr_addr
.sin6_family
= AF_INET6
;
997 ifr6
.ifr_addr
.sin6_addr
= ia
->addr
;
998 ifa_setscope(&ifr6
.ifr_addr
, ia
->iface
->index
);
999 priv
= (struct priv
*)ia
->iface
->ctx
->priv
;
1000 if (ioctl(priv
->pf_inet6_fd
, SIOCGIFALIFETIME_IN6
, &ifr6
) == -1)
1002 clock_gettime(CLOCK_MONOTONIC
, &ia
->created
);
1004 #if defined(__FreeBSD__) || defined(__DragonFly__)
1005 t
= ia
->created
.tv_sec
;
1010 lifetime
= &ifr6
.ifr_ifru
.ifru_lifetime
;
1011 if (lifetime
->ia6t_preferred
)
1012 ia
->prefix_pltime
= (uint32_t)(lifetime
->ia6t_preferred
-
1013 MIN(t
, lifetime
->ia6t_preferred
));
1015 ia
->prefix_pltime
= ND6_INFINITE_LIFETIME
;
1016 if (lifetime
->ia6t_expire
) {
1017 ia
->prefix_vltime
= (uint32_t)(lifetime
->ia6t_expire
-
1018 MIN(t
, lifetime
->ia6t_expire
));
1019 /* Calculate the created time */
1020 ia
->created
.tv_sec
-= lifetime
->ia6t_vltime
- ia
->prefix_vltime
;
1022 ia
->prefix_vltime
= ND6_INFINITE_LIFETIME
;
1028 if_announce(struct dhcpcd_ctx
*ctx
, const struct if_announcemsghdr
*ifan
)
1031 if (ifan
->ifan_msglen
< sizeof(*ifan
)) {
1036 switch(ifan
->ifan_what
) {
1038 return dhcpcd_handleinterface(ctx
, 1, ifan
->ifan_name
);
1039 case IFAN_DEPARTURE
:
1040 return dhcpcd_handleinterface(ctx
, -1, ifan
->ifan_name
);
1047 if_ifinfo(struct dhcpcd_ctx
*ctx
, const struct if_msghdr
*ifm
)
1049 struct interface
*ifp
;
1052 if (ifm
->ifm_msglen
< sizeof(*ifm
)) {
1057 if ((ifp
= if_findindex(ctx
->ifaces
, ifm
->ifm_index
)) == NULL
)
1060 switch (ifm
->ifm_data
.ifi_link_state
) {
1061 case LINK_STATE_UNKNOWN
:
1062 link_state
= LINK_UNKNOWN
;
1065 link_state
= LINK_UP
;
1068 link_state
= LINK_DOWN
;
1072 dhcpcd_handlecarrier(ctx
, link_state
,
1073 (unsigned int)ifm
->ifm_flags
, ifp
->name
);
1078 if_rtm(struct dhcpcd_ctx
*ctx
, const struct rt_msghdr
*rtm
)
1082 if (rtm
->rtm_msglen
< sizeof(*rtm
)) {
1087 /* Ignore errors. */
1088 if (rtm
->rtm_errno
!= 0)
1091 if (if_copyrt(ctx
, &rt
, rtm
) == -1)
1092 return errno
== ENOTSUP
? 0 : -1;
1096 * BSD announces host routes.
1097 * As such, we should be notified of reachability by its
1098 * existance with a hardware address.
1099 * Ensure we don't call this for a newly incomplete state.
1101 if (rt
.rt_dest
.sa_family
== AF_INET6
&&
1102 (rt
.rt_flags
& RTF_HOST
|| rtm
->rtm_type
== RTM_MISS
) &&
1103 !(rtm
->rtm_type
== RTM_ADD
&& !(rt
.rt_dflags
& RTDF_GATELINK
)))
1107 reachable
= (rtm
->rtm_type
== RTM_ADD
||
1108 rtm
->rtm_type
== RTM_CHANGE
) &&
1109 rt
.rt_dflags
& RTDF_GATELINK
;
1110 ipv6nd_neighbour(ctx
, &rt
.rt_ss_dest
.sin6
.sin6_addr
, reachable
);
1114 if (rtm
->rtm_type
!= RTM_MISS
)
1115 rt_recvrt(rtm
->rtm_type
, &rt
, rtm
->rtm_pid
);
1120 if_ifa(struct dhcpcd_ctx
*ctx
, const struct ifa_msghdr
*ifam
)
1122 struct interface
*ifp
;
1123 const struct sockaddr
*rti_info
[RTAX_MAX
];
1127 if (ifam
->ifam_msglen
< sizeof(*ifam
)) {
1131 if (~ifam
->ifam_addrs
& RTA_IFA
)
1133 if ((ifp
= if_findindex(ctx
->ifaces
, ifam
->ifam_index
)) == NULL
)
1136 if (get_addrs(ifam
->ifam_addrs
, (const char *)ifam
+ sizeof(*ifam
),
1137 ifam
->ifam_msglen
- sizeof(*ifam
), rti_info
) == -1)
1140 #ifdef HAVE_IFAM_PID
1141 pid
= ifam
->ifam_pid
;
1146 #ifdef HAVE_IFAM_ADDRFLAGS
1147 addrflags
= ifam
->ifam_addrflags
;
1149 switch (rti_info
[RTAX_IFA
]->sa_family
) {
1152 struct sockaddr_dl sdl
;
1155 if (ifam
->ifam_type
!= RTM_CHGADDR
)
1158 if (ifam
->ifam_type
!= RTM_NEWADDR
)
1161 memcpy(&sdl
, rti_info
[RTAX_IFA
], rti_info
[RTAX_IFA
]->sa_len
);
1162 dhcpcd_handlehwaddr(ctx
, ifp
->name
, CLLADDR(&sdl
),sdl
.sdl_alen
);
1167 case 255: /* FIXME: Why 255? */
1169 const struct sockaddr_in
*sin
;
1170 struct in_addr addr
, mask
, bcast
;
1172 sin
= (const void *)rti_info
[RTAX_IFA
];
1173 addr
.s_addr
= sin
!= NULL
&& sin
->sin_family
== AF_INET
?
1174 sin
->sin_addr
.s_addr
: INADDR_ANY
;
1175 sin
= (const void *)rti_info
[RTAX_NETMASK
];
1176 mask
.s_addr
= sin
!= NULL
&& sin
->sin_family
== AF_INET
?
1177 sin
->sin_addr
.s_addr
: INADDR_ANY
;
1178 sin
= (const void *)rti_info
[RTAX_BRD
];
1179 bcast
.s_addr
= sin
!= NULL
&& sin
->sin_family
== AF_INET
?
1180 sin
->sin_addr
.s_addr
: INADDR_ANY
;
1182 #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
1184 * NetBSD-7 and older send an invalid broadcast address.
1185 * So we need to query the actual address to get
1191 * If the address was deleted, lets check if it's
1192 * a late message and it still exists (maybe modified).
1193 * If so, ignore it as deleting an address causes
1194 * dhcpcd to drop any lease to which it belongs.
1196 if (ifam
->ifam_type
== RTM_DELADDR
) {
1199 struct in_aliasreq ifra
;
1201 memset(&ifra
, 0, sizeof(ifra
));
1202 strlcpy(ifra
.ifra_name
, ifp
->name
,
1203 sizeof(ifra
.ifra_name
));
1204 ifra
.ifra_addr
.sin_family
= AF_INET
;
1205 ifra
.ifra_addr
.sin_len
= sizeof(ifra
.ifra_addr
);
1206 ifra
.ifra_addr
.sin_addr
= addr
;
1207 if (ioctl(ctx
->pf_inet_fd
, SIOCGIFALIAS
, &ifra
) == -1) {
1208 if (errno
!= ENXIO
&& errno
!= EADDRNOTAVAIL
)
1209 logerr("%s: SIOCGIFALIAS", __func__
);
1210 if (ifam
->ifam_type
!= RTM_DELADDR
)
1213 #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
1215 bcast
= ifra
.ifra_broadaddr
.sin_addr
;
1218 #warning No SIOCGIFALIAS support
1220 * No SIOCGIFALIAS? That sucks!
1221 * This makes this call very heavy weight, but we
1222 * really need to know if the message is late or not.
1224 const struct sockaddr
*sa
;
1225 struct ifaddrs
*ifaddrs
= NULL
, *ifa
;
1227 sa
= rti_info
[RTAX_IFA
];
1228 getifaddrs(&ifaddrs
);
1229 for (ifa
= ifaddrs
; ifa
; ifa
= ifa
->ifa_next
) {
1230 if (ifa
->ifa_addr
== NULL
)
1232 if (sa_cmp(ifa
->ifa_addr
, sa
) == 0 &&
1233 strcmp(ifa
->ifa_name
, ifp
->name
) == 0)
1236 freeifaddrs(ifaddrs
);
1242 #ifndef HAVE_IFAM_ADDRFLAGS
1243 if (ifam
->ifam_type
== RTM_DELADDR
)
1245 else if ((addrflags
= if_addrflags(ifp
, &addr
, NULL
)) == -1) {
1246 if (errno
!= EADDRNOTAVAIL
)
1247 logerr("%s: if_addrflags", __func__
);
1252 ipv4_handleifa(ctx
, ifam
->ifam_type
, NULL
, ifp
->name
,
1253 &addr
, &mask
, &bcast
, addrflags
, pid
);
1260 struct in6_addr addr6
, mask6
;
1261 const struct sockaddr_in6
*sin6
;
1264 sin6
= (const void *)rti_info
[RTAX_IFA
];
1265 addr6
= sin6
->sin6_addr
;
1266 sin6
= (const void *)rti_info
[RTAX_NETMASK
];
1267 mask6
= sin6
->sin6_addr
;
1270 * If the address was deleted, lets check if it's
1271 * a late message and it still exists (maybe modified).
1272 * If so, ignore it as deleting an address causes
1273 * dhcpcd to drop any lease to which it belongs.
1275 if (ifam
->ifam_type
== RTM_DELADDR
) {
1276 flags
= if_addrflags6(ifp
, &addr6
, NULL
);
1281 #ifndef HAVE_IFAM_ADDRFLAGS
1282 else if ((addrflags
= if_addrflags6(ifp
, &addr6
, NULL
)) == -1) {
1283 if (errno
!= EADDRNOTAVAIL
)
1284 logerr("%s: if_addrflags6", __func__
);
1290 if (IN6_IS_ADDR_LINKLOCAL(&addr6
))
1291 /* Remove the scope from the address */
1292 addr6
.s6_addr
[2] = addr6
.s6_addr
[3] = '\0';
1295 ipv6_handleifa(ctx
, ifam
->ifam_type
, NULL
,
1296 ifp
->name
, &addr6
, ipv6_prefixlen(&mask6
), addrflags
, pid
);
1306 if_dispatch(struct dhcpcd_ctx
*ctx
, const struct rt_msghdr
*rtm
)
1309 if (rtm
->rtm_version
!= RTM_VERSION
)
1312 switch(rtm
->rtm_type
) {
1313 #ifdef RTM_IFANNOUNCE
1314 case RTM_IFANNOUNCE
:
1315 return if_announce(ctx
, (const void *)rtm
);
1318 return if_ifinfo(ctx
, (const void *)rtm
);
1319 case RTM_ADD
: /* FALLTHROUGH */
1320 case RTM_CHANGE
: /* FALLTHROUGH */
1321 case RTM_DELETE
: /* FALLTHROUGH */
1323 return if_rtm(ctx
, (const void *)rtm
);
1325 case RTM_CHGADDR
: /* FALLTHROUGH */
1327 case RTM_DELADDR
: /* FALLTHROUGH */
1329 return if_ifa(ctx
, (const void *)rtm
);
1332 dhcpcd_linkoverflow(ctx
);
1333 #elif !defined(SO_RERROR)
1334 #warning cannot detect route socket overflow within kernel
1341 __CTASSERT(offsetof(struct rt_msghdr
, rtm_msglen
) == 0);
1343 if_handlelink(struct dhcpcd_ctx
*ctx
)
1348 len
= read(ctx
->link_fd
, &rtm
, sizeof(rtm
));
1353 if ((size_t)len
< sizeof(rtm
.hdr
.rtm_msglen
) ||
1354 len
!= rtm
.hdr
.rtm_msglen
)
1360 * Coverity thinks that the data could be tainted from here.
1361 * I have no idea how because the length of the data we read
1362 * is guarded by len and checked to match rtm_msglen.
1363 * The issue seems to be related to extracting the addresses
1364 * at the end of the header, but seems to have no issues with the
1365 * equivalent call in if_initrt.
1367 /* coverity[tainted_data] */
1368 return if_dispatch(ctx
, &rtm
.hdr
);
1371 #ifndef SYS_NMLN /* OSX */
1372 # define SYS_NMLN 256
1374 #ifndef HW_MACHINE_ARCH
1375 # ifdef HW_MODEL /* OpenBSD */
1376 # define HW_MACHINE_ARCH HW_MODEL
1380 if_machinearch(char *str
, size_t len
)
1382 int mib
[2] = { CTL_HW
, HW_MACHINE_ARCH
};
1383 char march
[SYS_NMLN
];
1384 size_t marchlen
= sizeof(march
);
1386 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]),
1387 march
, &marchlen
, NULL
, 0) != 0)
1389 return snprintf(str
, len
, ":%s", march
);
1393 #if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) || \
1394 defined(IPV6CTL_USETEMPADDR) || defined(IPV6CTL_TEMPVLTIME) || \
1395 defined(IPV6CTL_FORWARDING)
1396 #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
1397 #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
1399 inet6_sysctl(int code
, int val
, int action
)
1401 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1407 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]),
1408 NULL
, 0, &val
, size
) == -1)
1412 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &val
, &size
, NULL
, 0) == -1)
1418 #ifdef IPV6_MANAGETEMPADDR
1419 #ifndef IPV6CTL_TEMPVLTIME
1420 #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
1421 #define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
1423 inet6_sysctlbyname(const char *name
, int val
, int action
)
1429 if (sysctlbyname(name
, NULL
, 0, &val
, size
) == -1)
1433 if (sysctlbyname(name
, &val
, &size
, NULL
, 0) == -1)
1440 ip6_use_tempaddr(__unused
const char *ifname
)
1444 #ifdef IPV6CTL_USETEMPADDR
1445 val
= get_inet6_sysctl(IPV6CTL_USETEMPADDR
);
1447 val
= get_inet6_sysctlbyname("net.inet6.ip6.use_tempaddr");
1449 return val
== -1 ? 0 : val
;
1453 ip6_temp_preferred_lifetime(__unused
const char *ifname
)
1457 #ifdef IPV6CTL_TEMPPLTIME
1458 val
= get_inet6_sysctl(IPV6CTL_TEMPPLTIME
);
1460 val
= get_inet6_sysctlbyname("net.inet6.ip6.temppltime");
1462 return val
< 0 ? TEMP_PREFERRED_LIFETIME
: val
;
1466 ip6_temp_valid_lifetime(__unused
const char *ifname
)
1470 #ifdef IPV6CTL_TEMPVLTIME
1471 val
= get_inet6_sysctl(IPV6CTL_TEMPVLTIME
);
1473 val
= get_inet6_sysctlbyname("net.inet6.ip6.tempvltime");
1475 return val
< 0 ? TEMP_VALID_LIFETIME
: val
;
1480 ip6_forwarding(__unused
const char *ifname
)
1484 #ifdef IPV6CTL_FORWARDING
1485 val
= get_inet6_sysctl(IPV6CTL_FORWARDING
);
1487 val
= get_inet6_sysctlbyname("net.inet6.ip6.forwarding");
1489 return val
< 0 ? 0 : val
;
1492 #ifdef SIOCIFAFATTACH
1494 af_attach(int s
, const struct interface
*ifp
, int af
)
1496 struct if_afreq ifar
;
1498 strlcpy(ifar
.ifar_name
, ifp
->name
, sizeof(ifar
.ifar_name
));
1500 return ioctl(s
, SIOCIFAFATTACH
, (void *)&ifar
);
1504 #ifdef SIOCGIFXFLAGS
1506 set_ifxflags(int s
, const struct interface
*ifp
)
1511 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
1512 if (ioctl(s
, SIOCGIFXFLAGS
, (void *)&ifr
) == -1)
1514 flags
= ifr
.ifr_flags
;
1516 flags
&= ~IFXF_NOINET6
;
1519 * If not doing autoconf, don't disable the kernel from doing it.
1520 * If we need to, we should have another option actively disable it.
1522 * OpenBSD moved from kernel based SLAAC to userland via slaacd(8).
1523 * It has a similar featureset to dhcpcd such as stable private
1524 * addresses, but lacks the ability to handle DNS inside the RA
1525 * which is a serious shortfall in this day and age.
1526 * Appease their user base by working alongside slaacd(8) if
1527 * dhcpcd is instructed not to do auto configuration of addresses.
1529 #if defined(ND6_IFF_ACCEPT_RTADV)
1530 #define BSD_AUTOCONF DHCPCD_IPV6RS
1532 #define BSD_AUTOCONF DHCPCD_IPV6RA_AUTOCONF
1534 if (ifp
->options
->options
& BSD_AUTOCONF
)
1535 flags
&= ~IFXF_AUTOCONF6
;
1536 if (ifr
.ifr_flags
== flags
)
1538 ifr
.ifr_flags
= flags
;
1539 return ioctl(s
, SIOCSIFXFLAGS
, (void *)&ifr
);
1543 /* OpenBSD removed ND6 flags entirely, so we need to check for their
1545 #if defined(ND6_IFF_AUTO_LINKLOCAL) || \
1546 defined(ND6_IFF_PERFORMNUD) || \
1547 defined(ND6_IFF_ACCEPT_RTADV) || \
1548 defined(ND6_IFF_OVERRIDE_RTADV) || \
1549 defined(ND6_IFF_IFDISABLED)
1550 #define ND6_NDI_FLAGS
1554 if_setup_inet6(const struct interface
*ifp
)
1558 #ifdef ND6_NDI_FLAGS
1559 struct in6_ndireq nd
;
1563 priv
= (struct priv
*)ifp
->ctx
->priv
;
1564 s
= priv
->pf_inet6_fd
;
1566 #ifdef ND6_NDI_FLAGS
1567 memset(&nd
, 0, sizeof(nd
));
1568 strlcpy(nd
.ifname
, ifp
->name
, sizeof(nd
.ifname
));
1569 if (ioctl(s
, SIOCGIFINFO_IN6
, &nd
) == -1)
1570 logerr("%s: SIOCGIFINFO_FLAGS", ifp
->name
);
1571 flags
= (int)nd
.ndi
.flags
;
1574 #ifdef ND6_IFF_AUTO_LINKLOCAL
1575 /* Unlike the kernel,
1576 * dhcpcd make make a stable private address. */
1577 flags
&= ~ND6_IFF_AUTO_LINKLOCAL
;
1580 #ifdef ND6_IFF_PERFORMNUD
1581 /* NUD is kind of essential. */
1582 flags
|= ND6_IFF_PERFORMNUD
;
1585 #ifdef ND6_IFF_IFDISABLED
1586 /* Ensure the interface is not disabled. */
1587 flags
&= ~ND6_IFF_IFDISABLED
;
1591 * If not doing autoconf, don't disable the kernel from doing it.
1592 * If we need to, we should have another option actively disable it.
1594 #ifdef ND6_IFF_ACCEPT_RTADV
1595 if (ifp
->options
->options
& DHCPCD_IPV6RS
)
1596 flags
&= ~ND6_IFF_ACCEPT_RTADV
;
1597 #ifdef ND6_IFF_OVERRIDE_RTADV
1598 if (ifp
->options
->options
& DHCPCD_IPV6RS
)
1599 flags
|= ND6_IFF_OVERRIDE_RTADV
;
1603 #ifdef ND6_NDI_FLAGS
1604 if (nd
.ndi
.flags
!= (uint32_t)flags
) {
1605 nd
.ndi
.flags
= (uint32_t)flags
;
1606 if (ioctl(s
, SIOCSIFINFO_FLAGS
, &nd
) == -1)
1607 logerr("%s: SIOCSIFINFO_FLAGS", ifp
->name
);
1611 /* Enabling IPv6 by whatever means must be the
1612 * last action undertaken to ensure kernel RS and
1613 * LLADDR auto configuration are disabled where applicable. */
1614 #ifdef SIOCIFAFATTACH
1615 if (af_attach(s
, ifp
, AF_INET6
) == -1)
1616 logerr("%s: af_attach", ifp
->name
);
1619 #ifdef SIOCGIFXFLAGS
1620 if (set_ifxflags(s
, ifp
) == -1)
1621 logerr("%s: set_ifxflags", ifp
->name
);
1624 #if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)
1625 /* If we cannot control ra per interface, disable it globally. */
1626 if (ifp
->options
->options
& DHCPCD_IPV6RS
) {
1627 int ra
= get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV
);
1630 if (errno
!= ENOENT
)
1631 logerr("IPV6CTL_ACCEPT_RTADV");
1633 if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV
, 0) == -1)
1634 logerr("IPV6CTL_ACCEPT_RTADV");
1639 #if defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV)
1640 /* Flush the kernel knowledge of advertised routers
1641 * and prefixes so the kernel does not expire prefixes
1642 * and default routes we are trying to own. */
1643 if (ifp
->options
->options
& DHCPCD_IPV6RS
) {
1644 struct in6_ifreq ifr
;
1646 memset(&ifr
, 0, sizeof(ifr
));
1647 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
1648 if (ioctl(s
, SIOCSRTRFLUSH_IN6
, &ifr
) == -1 &&
1650 logwarn("SIOCSRTRFLUSH_IN6");
1651 if (ioctl(s
, SIOCSPFXFLUSH_IN6
, &ifr
) == -1 &&
1653 logwarn("SIOCSPFXFLUSH_IN6");