Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F141977600
D35117.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D35117.diff
View Options
Index: sys/netinet6/ip6_output.c
===================================================================
--- sys/netinet6/ip6_output.c
+++ sys/netinet6/ip6_output.c
@@ -416,7 +416,7 @@
struct mbuf *mprev;
struct route_in6 *ro_pmtu;
struct nhop_object *nh;
- struct sockaddr_in6 *dst, sin6, src_sa, dst_sa;
+ struct sockaddr_in6 *dst, sin6, dst_sa;
struct in6_addr odst;
u_char *nexthdrp;
int tlen, len;
@@ -427,8 +427,6 @@
int alwaysfrag, dontfrag;
u_int32_t optlen, plen = 0, unfragpartlen;
struct ip6_exthdrs exthdrs;
- struct in6_addr src0, dst0;
- u_int32_t zone;
bool hdrsplit;
int sw_csum, tso;
int needfiblookup;
@@ -689,7 +687,6 @@
ro->ro_dst.sin6_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) {
nh = ro->ro_nh;
- ifp = nh->nh_ifp;
} else {
if (ro->ro_lle)
LLE_FREE(ro->ro_lle); /* zeros ro_lle */
@@ -708,8 +705,6 @@
in6_ifstat_inc(ifp, ifs6_out_discard);
goto bad;
}
- if (ifp != NULL)
- mtu = ifp->if_mtu;
}
if (nh == NULL) {
/*
@@ -717,9 +712,12 @@
* dst may not have been updated.
*/
*dst = dst_sa; /* XXX */
+ origifp = ifp;
+ mtu = ifp->if_mtu;
} else {
- if (nh->nh_flags & NHF_HOST)
- mtu = nh->nh_mtu;
+ ifp = nh->nh_ifp;
+ origifp = nh->nh_aifp;
+ mtu = nh->nh_mtu;
ia = (struct in6_ifaddr *)(nh->nh_ifa);
counter_u64_add(nh->nh_pksent, 1);
}
@@ -740,6 +738,7 @@
(ifp = im6o->im6o_multicast_ifp) != NULL) {
/* We do not need a route lookup. */
*dst = dst_sa; /* XXX */
+ origifp = ifp;
goto nonh6lookup;
}
@@ -754,6 +753,7 @@
goto bad;
}
*dst = dst_sa; /* XXX */
+ origifp = ifp;
goto nonh6lookup;
}
}
@@ -768,6 +768,7 @@
}
ifp = nh->nh_ifp;
+ origifp = nh->nh_aifp;
mtu = nh->nh_mtu;
ia = ifatoia6(nh->nh_ifa);
if (nh->nh_flags & NHF_GATEWAY)
@@ -784,65 +785,18 @@
in6_ifstat_inc(ifp, ifs6_out_request);
}
- /* Setup data structures for scope ID checks. */
- src0 = ip6->ip6_src;
- bzero(&src_sa, sizeof(src_sa));
- src_sa.sin6_family = AF_INET6;
- src_sa.sin6_len = sizeof(src_sa);
- src_sa.sin6_addr = ip6->ip6_src;
-
- dst0 = ip6->ip6_dst;
- /* Re-initialize to be sure. */
- bzero(&dst_sa, sizeof(dst_sa));
- dst_sa.sin6_family = AF_INET6;
- dst_sa.sin6_len = sizeof(dst_sa);
- dst_sa.sin6_addr = ip6->ip6_dst;
-
- /* Check for valid scope ID. */
- if (in6_setscope(&src0, ifp, &zone) == 0 &&
- sa6_recoverscope(&src_sa) == 0 && zone == src_sa.sin6_scope_id &&
- in6_setscope(&dst0, ifp, &zone) == 0 &&
- sa6_recoverscope(&dst_sa) == 0 && zone == dst_sa.sin6_scope_id) {
- /*
- * The outgoing interface is in the zone of the source
- * and destination addresses.
- *
- * Because the loopback interface cannot receive
- * packets with a different scope ID than its own,
- * there is a trick to pretend the outgoing packet
- * was received by the real network interface, by
- * setting "origifp" different from "ifp". This is
- * only allowed when "ifp" is a loopback network
- * interface. Refer to code in nd6_output_ifp() for
- * more details.
- */
- origifp = ifp;
-
- /*
- * We should use ia_ifp to support the case of sending
- * packets to an address of our own.
- */
- if (ia != NULL && ia->ia_ifp)
- ifp = ia->ia_ifp;
-
- } else if ((ifp->if_flags & IFF_LOOPBACK) == 0 ||
- sa6_recoverscope(&src_sa) != 0 ||
- sa6_recoverscope(&dst_sa) != 0 ||
- dst_sa.sin6_scope_id == 0 ||
- (src_sa.sin6_scope_id != 0 &&
- src_sa.sin6_scope_id != dst_sa.sin6_scope_id) ||
- (origifp = ifnet_byindex(dst_sa.sin6_scope_id)) == NULL) {
- /*
- * If the destination network interface is not a
- * loopback interface, or the destination network
- * address has no scope ID, or the source address has
- * a scope ID set which is different from the
- * destination address one, or there is no network
- * interface representing this scope ID, the address
- * pair is considered invalid.
- */
+ /*
+ * Check scope for source/destination addresses.
+ * Per RFC 4007, clause 5, it is required to maintain "convex" property -
+ * do not allow packets routed outside their zone.
+ * Separately check the zone for source and destination, using _address interface_ -
+ * "normal" transmit interface if dst is non-local destination and ifp which dst
+ * belongs to otherwise. This allows to pass link-local packets via loopback interface.
+ */
+ if (!in6_checkscope_embedded(&ip6->ip6_src, origifp) ||
+ !in6_checkscope_embedded(&ip6->ip6_dst, origifp)) {
IP6STAT_INC(ip6s_badscope);
- in6_ifstat_inc(ifp, ifs6_out_discard);
+ in6_ifstat_inc(origifp, ifs6_out_discard);
if (error == 0)
error = EHOSTUNREACH; /* XXX */
goto bad;
Index: sys/netinet6/scope6.c
===================================================================
--- sys/netinet6/scope6.c
+++ sys/netinet6/scope6.c
@@ -542,6 +542,57 @@
*scopeid = zoneid;
}
+/*
+ * Checks that @addr_zone of @addr scope spans across @ifp.
+ * Returns true on success.
+ *
+ * @addr - Specified (non ::) valid IPv6 address, w/o embedded scope, used only to determine scope
+ * @addr_zone - zone id (host format) of an @addr zone
+ * @check_multi - if true, verify @addr_zone against the relevant @ifp zone, otherwise pass
+ * @ifp - interface to check scope against (if @addr is a local address, then @ifp is the addr iface)
+ */
+bool
+in6_checkscope(const struct in6_addr *addr, uint32_t addr_zone, bool check_multi, const struct ifnet *ifp)
+{
+ NET_EPOCH_ASSERT();
+
+ if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_LOOPBACK(addr)) {
+ return (addr_zone == ifp->if_index);
+ }
+ if (__predict_false(IN6_IS_ADDR_MULTICAST(addr) && check_multi)) {
+ switch (IPV6_ADDR_MC_SCOPE(addr)) {
+ case 0x0F:
+ return (true); // IPV6_ADDR_SCOPE_GLOBAL
+ case IPV6_ADDR_SCOPE_INTFACELOCAL:
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ return (addr_zone == ifp->if_index);
+ default:
+ if (ifp->if_afdata[AF_INET6] != NULL) {
+ return (addr_zone == SID(ifp)->s6id_list[IPV6_ADDR_MC_SCOPE(addr)]);
+ }
+ return false;
+ }
+ }
+ // Explicitly pass check for global unicast & site-local addresses
+ return (true);
+}
+
+/*
+ * Checks that the zoneid potentially embedded in @addr spans across @ifp.
+ * Returns true on success.
+ */
+bool
+in6_checkscope_embedded(const struct in6_addr *addr, const struct ifnet *ifp)
+{
+ uint32_t zone;
+
+ if (!IN6_IS_ADDR_LOOPBACK(addr))
+ zone = ntohs(addr->s6_addr16[1]);
+ else
+ zone = (ifp->if_flags & IFF_LOOPBACK) ? ifp->if_index : 0;
+ return (in6_checkscope(addr, zone, false, ifp));
+}
+
/*
* This function is for checking sockaddr_in6 structure passed
* from the application level (usually).
Index: sys/netinet6/scope6_var.h
===================================================================
--- sys/netinet6/scope6_var.h
+++ sys/netinet6/scope6_var.h
@@ -66,6 +66,9 @@
struct ifnet* in6_getlinkifnet(uint32_t);
uint32_t in6_get_unicast_scopeid(const struct in6_addr *, const struct ifnet *);
void in6_set_unicast_scopeid(struct in6_addr *, uint32_t);
+bool in6_checkscope(const struct in6_addr *addr, uint32_t addr_zone,
+ bool check_multi, const struct ifnet *ifp);
+bool in6_checkscope_embedded(const struct in6_addr *addr, const struct ifnet *ifp);
#endif /* _KERNEL */
#endif /* _NETINET6_SCOPE6_VAR_H_ */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 15, 11:02 AM (1 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27638475
Default Alt Text
D35117.diff (7 KB)
Attached To
Mode
D35117: netinet6: streamline scope6 checks for loopback traffic in ip6_output().
Attached
Detach File
Event Timeline
Log In to Comment