diff options
author | Hajimu UMEMOTO <ume@FreeBSD.org> | 2005-07-25 12:31:43 +0000 |
---|---|---|
committer | Hajimu UMEMOTO <ume@FreeBSD.org> | 2005-07-25 12:31:43 +0000 |
commit | a1f7e5f8ee7fee62414af8d3a3008313cfd2cb17 (patch) | |
tree | 5a678f63b25976c30f74f3bad9edb6f708c52930 /sys/netinet6/ip6_forward.c | |
parent | 869de95743d527dda9d81d06b0e74cd5e95f8f9c (diff) | |
download | src-a1f7e5f8ee7fee62414af8d3a3008313cfd2cb17.tar.gz src-a1f7e5f8ee7fee62414af8d3a3008313cfd2cb17.zip |
scope cleanup. with this change
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
Submitted by: JINMEI Tatuya <jinmei__at__isl.rdc.toshiba.co.jp>
Obtained from: KAME
Notes
Notes:
svn path=/head/; revision=148385
Diffstat (limited to 'sys/netinet6/ip6_forward.c')
-rw-r--r-- | sys/netinet6/ip6_forward.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index f0b1cf05e27f..e003452d79f1 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -59,6 +59,7 @@ #include <netinet6/in6_var.h> #include <netinet/ip6.h> #include <netinet6/ip6_var.h> +#include <netinet6/scope6_var.h> #include <netinet/icmp6.h> #include <netinet6/nd6.h> @@ -111,7 +112,8 @@ ip6_forward(m, srcrt) int error, type = 0, code = 0; struct mbuf *mcopy = NULL; struct ifnet *origifp; /* maybe unnecessary */ - u_int32_t srczone, dstzone; + u_int32_t inzone, outzone; + struct in6_addr src_in6, dst_in6; #ifdef IPSEC struct secpolicy *sp = NULL; int ipsecrt = 0; @@ -400,21 +402,29 @@ ip6_forward(m, srcrt) #endif /* - * Scope check: if a packet can't be delivered to its destination - * for the reason that the destination is beyond the scope of the - * source address, discard the packet and return an icmp6 destination - * unreachable error with Code 2 (beyond scope of source address). - * [draft-ietf-ipngwg-icmp-v3-02.txt, Section 3.1] + * Source scope check: if a packet can't be delivered to its + * destination for the reason that the destination is beyond the scope + * of the source address, discard the packet and return an icmp6 + * destination unreachable error with Code 2 (beyond scope of source + * address). We use a local copy of ip6_src, since in6_setscope() + * will possibly modify its first argument. + * [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1] */ - if (in6_addr2zoneid(m->m_pkthdr.rcvif, &ip6->ip6_src, &srczone) || - in6_addr2zoneid(rt->rt_ifp, &ip6->ip6_src, &dstzone)) { + src_in6 = ip6->ip6_src; + if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) { /* XXX: this should not happen */ ip6stat.ip6s_cantforward++; ip6stat.ip6s_badscope++; m_freem(m); return; } - if (srczone != dstzone + if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) { + ip6stat.ip6s_cantforward++; + ip6stat.ip6s_badscope++; + m_freem(m); + return; + } + if (inzone != outzone #ifdef IPSEC && !ipsecrt #endif @@ -440,6 +450,23 @@ ip6_forward(m, srcrt) return; } + /* + * Destination scope check: if a packet is going to break the scope + * zone of packet's destination address, discard it. This case should + * usually be prevented by appropriately-configured routing table, but + * we need an explicit check because we may mistakenly forward the + * packet to a different zone by (e.g.) a default route. + */ + dst_in6 = ip6->ip6_dst; + if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 || + in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 || + inzone != outzone) { + ip6stat.ip6s_cantforward++; + ip6stat.ip6s_badscope++; + m_freem(m); + return; + } + if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) { in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); if (mcopy) { |