changeset 4422:344851420e71 draft

BSD: Fix detecting the interface for scoped routes dhcpcd will now detect the IPv6 default route being deleted by a third party, for example.
author Roy Marples <roy@marples.name>
date Tue, 02 Apr 2019 13:35:51 +0100
parents 1c0d24d49b16
children 22c551e08f53
files src/if-bsd.c
diffstat 1 files changed, 40 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/if-bsd.c	Tue Apr 02 12:52:31 2019 +0100
+++ b/src/if-bsd.c	Tue Apr 02 13:35:51 2019 +0100
@@ -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 @@
 	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_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 @@
 {
 	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 @@
 
 #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 @@
 #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 @@
 	}
 
 	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 @@
 	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 @@
 	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;