summaryrefslogtreecommitdiffstats
path: root/src/if-bsd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2019-04-02 13:35:51 +0100
committerRoy Marples <roy@marples.name>2019-04-02 13:35:51 +0100
commitcf924ee8a31557387b2e4f399ec3f3cf3c221ee9 (patch)
tree23eafecc2e484448b5e4f7aac23bd2e5849f9311 /src/if-bsd.c
parent885986d6b9b32d37ccf8dccda05f4c79c639a6fa (diff)
downloaddhcpcd-cf924ee8a31557387b2e4f399ec3f3cf3c221ee9.tar.xz
BSD: Fix detecting the interface for scoped routes
dhcpcd will now detect the IPv6 default route being deleted by a third party, for example.
Diffstat (limited to 'src/if-bsd.c')
-rw-r--r--src/if-bsd.c51
1 files changed, 40 insertions, 11 deletions
diff --git a/src/if-bsd.c b/src/if-bsd.c
index 5c6347e4..7d5c7806 100644
--- a/src/if-bsd.c
+++ b/src/if-bsd.c
@@ -99,8 +99,8 @@
#endif
#ifdef INET6
-static void
-ifa_scope(struct sockaddr_in6 *, unsigned int);
+static void ifa_setscope(struct sockaddr_in6 *, unsigned int);
+static unsigned int ifa_getscope(const struct sockaddr_in6 *);
#endif
struct priv {
@@ -418,9 +418,13 @@ if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa)
case AF_INET6:
{
const struct sockaddr_in6 *sin;
+ unsigned int scope;
struct ipv6_addr *ia;
sin = (const void *)sa;
+ scope = ifa_getscope(sin);
+ if (scope != 0)
+ return if_findindex(ctx->ifaces, scope);
if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
return ia->iface;
break;
@@ -577,7 +581,7 @@ if_route(unsigned char cmd, const struct rt *rt)
if_copysa(&gateway.sa, &rt->rt_gateway);
#ifdef INET6
if (gateway.sa.sa_family == AF_INET6)
- ifa_scope(&gateway.sin6, rt->rt_ifp->index);
+ ifa_setscope(&gateway.sin6, rt->rt_ifp->index);
#endif
ADDSA(&gateway.sa);
}
@@ -605,19 +609,27 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
{
const struct sockaddr *rti_info[RTAX_MAX];
- if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
+ if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) {
+ errno = EINVAL;
return -1;
+ }
#ifdef RTF_CLONED
- if (rtm->rtm_flags & RTF_CLONED)
+ if (rtm->rtm_flags & RTF_CLONED) {
+ errno = ENOTSUP;
return -1;
+ }
#endif
#ifdef RTF_LOCAL
- if (rtm->rtm_flags & RTF_LOCAL)
+ if (rtm->rtm_flags & RTF_LOCAL) {
+ errno = ENOTSUP;
return -1;
+ }
#endif
#ifdef RTF_BROADCAST
- if (rtm->rtm_flags & RTF_BROADCAST)
+ if (rtm->rtm_flags & RTF_BROADCAST) {
+ errno = ENOTSUP;
return -1;
+ }
#endif
get_addrs(rtm->rtm_addrs, rtm + 1, rti_info);
@@ -751,7 +763,7 @@ if_addrflags(const struct interface *ifp, const struct in_addr *addr,
#ifdef INET6
static void
-ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
+ifa_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
{
#ifdef __KAME__
@@ -771,6 +783,23 @@ ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
#endif
}
+static unsigned int
+ifa_getscope(const struct sockaddr_in6 *sin)
+{
+#ifdef __KAME__
+ uint16_t scope;
+#endif
+
+ if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+ return 0;
+#ifdef __KAME__
+ memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
+ return (unsigned int)ntohs(scope);
+#else
+ return (unsigned int)sin->sin6_scope_id;
+#endif
+}
+
int
if_address6(unsigned char cmd, const struct ipv6_addr *ia)
{
@@ -810,7 +839,7 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
}
ADDADDR(&ifa.ifra_addr, &ia->addr);
- ifa_scope(&ifa.ifra_addr, ia->iface->index);
+ ifa_setscope(&ifa.ifra_addr, ia->iface->index);
ipv6_mask(&mask, ia->prefix_len);
ADDADDR(&ifa.ifra_prefixmask, &mask);
@@ -887,7 +916,7 @@ if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = *addr;
- ifa_scope(&ifr6.ifr_addr, ifp->index);
+ ifa_setscope(&ifr6.ifr_addr, ifp->index);
priv = (struct priv *)ifp->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
flags = ifr6.ifr_ifru.ifru_flags6;
@@ -908,7 +937,7 @@ if_getlifetime6(struct ipv6_addr *ia)
strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = ia->addr;
- ifa_scope(&ifr6.ifr_addr, ia->iface->index);
+ ifa_setscope(&ifr6.ifr_addr, ia->iface->index);
priv = (struct priv *)ia->iface->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1)
return -1;