summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/icmp6.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2005-07-25 12:31:43 +0000
committerume <ume@FreeBSD.org>2005-07-25 12:31:43 +0000
commitda2cf62b280b8450d5f8e0d810e810cdcc59a8c0 (patch)
tree5a678f63b25976c30f74f3bad9edb6f708c52930 /sys/netinet6/icmp6.c
parent59bc7b0da19f008a39ee92249e92f8246f04394e (diff)
downloadFreeBSD-src-da2cf62b280b8450d5f8e0d810e810cdcc59a8c0.zip
FreeBSD-src-da2cf62b280b8450d5f8e0d810e810cdcc59a8c0.tar.gz
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
Diffstat (limited to 'sys/netinet6/icmp6.c')
-rw-r--r--sys/netinet6/icmp6.c189
1 files changed, 95 insertions, 94 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 3f3cbd6..129704e 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -95,6 +95,7 @@
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6protosw.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/scope6_var.h>
#include <netinet6/mld6_var.h>
#include <netinet6/nd6.h>
@@ -205,6 +206,41 @@ icmp6_errcount(stat, type, code)
}
/*
+ * A wrapper function for icmp6_error() necessary when the erroneous packet
+ * may not contain enough scope zone information.
+ */
+void
+icmp6_error2(m, type, code, param, ifp)
+ struct mbuf *m;
+ int type, code, param;
+ struct ifnet *ifp;
+{
+ struct ip6_hdr *ip6;
+
+ if (ifp == NULL)
+ return;
+
+#ifndef PULLDOWN_TEST
+ IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
+#else
+ if (m->m_len < sizeof(struct ip6_hdr)) {
+ m = m_pullup(m, sizeof(struct ip6_hdr));
+ if (m == NULL)
+ return;
+ }
+#endif
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ if (in6_setscope(&ip6->ip6_src, ifp, NULL) != 0)
+ return;
+ if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
+ return;
+
+ icmp6_error(m, type, code, param);
+}
+
+/*
* Generate an error packet of type error in response to bad IP6 packet.
*/
void
@@ -1024,37 +1060,16 @@ icmp6_notify_error(mp, off, icmp6len, code)
icmp6dst.sin6_addr = eip6->ip6_dst;
else
icmp6dst.sin6_addr = *finaldst;
- if (in6_addr2zoneid(m->m_pkthdr.rcvif, &icmp6dst.sin6_addr,
- &icmp6dst.sin6_scope_id))
- goto freeit;
- if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
- NULL, NULL)) {
- /* should be impossible */
- nd6log((LOG_DEBUG,
- "icmp6_notify_error: in6_embedscope failed\n"));
+ if (in6_setscope(&icmp6dst.sin6_addr, m->m_pkthdr.rcvif, NULL))
goto freeit;
- }
-
- /*
- * retrieve parameters from the inner IPv6 header, and convert
- * them into sockaddr structures.
- */
bzero(&icmp6src, sizeof(icmp6src));
icmp6src.sin6_len = sizeof(struct sockaddr_in6);
icmp6src.sin6_family = AF_INET6;
icmp6src.sin6_addr = eip6->ip6_src;
- if (in6_addr2zoneid(m->m_pkthdr.rcvif, &icmp6src.sin6_addr,
- &icmp6src.sin6_scope_id)) {
- goto freeit;
- }
- if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
- NULL, NULL)) {
- /* should be impossible */
- nd6log((LOG_DEBUG,
- "icmp6_notify_error: in6_embedscope failed\n"));
+ if (in6_setscope(&icmp6src.sin6_addr, m->m_pkthdr.rcvif, NULL))
goto freeit;
- }
- icmp6src.sin6_flowinfo = (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
+ icmp6src.sin6_flowinfo =
+ (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
if (finaldst == NULL)
finaldst = &eip6->ip6_dst;
@@ -1124,11 +1139,8 @@ icmp6_mtudisc_update(ip6cp, validated)
bzero(&inc, sizeof(inc));
inc.inc_flags = 1; /* IPv6 */
inc.inc6_faddr = *dst;
- /* XXX normally, this won't happen */
- if (IN6_IS_ADDR_LINKLOCAL(dst)) {
- inc.inc6_faddr.s6_addr16[1] =
- htons(m->m_pkthdr.rcvif->if_index);
- }
+ if (in6_setscope(&inc.inc6_faddr, m->m_pkthdr.rcvif, NULL))
+ return;
if (mtu < tcp_maxmtu6(&inc)) {
tcp_hc_updatemtu(&inc, mtu);
@@ -1161,7 +1173,7 @@ ni6_input(m, off)
struct ni_reply_fqdn *fqdn;
int addrs; /* for NI_QTYPE_NODEADDR */
struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
- struct sockaddr_in6 sin6_sbj; /* subject address */
+ struct in6_addr in6_subj; /* subject address */
struct ip6_hdr *ip6;
int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
char *subj = NULL;
@@ -1252,22 +1264,13 @@ ni6_input(m, off)
* We do not do proxy at this moment.
*/
/* m_pulldown instead of copy? */
- bzero(&sin6_sbj, sizeof(sin6_sbj));
- sin6_sbj.sin6_family = AF_INET6;
- sin6_sbj.sin6_len = sizeof(sin6_sbj);
m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
- subjlen, (caddr_t)&sin6_sbj.sin6_addr);
- if (in6_addr2zoneid(m->m_pkthdr.rcvif,
- &sin6_sbj.sin6_addr, &sin6_sbj.sin6_scope_id)) {
+ subjlen, (caddr_t)&in6_subj);
+ if (in6_setscope(&in6_subj, m->m_pkthdr.rcvif, NULL))
goto bad;
- }
- if (in6_embedscope(&sin6_sbj.sin6_addr, &sin6_sbj,
- NULL, NULL))
- goto bad; /* XXX should not happen */
- subj = (char *)&sin6_sbj;
- if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
- &sin6_sbj.sin6_addr))
+ subj = (char *)&in6_subj;
+ if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &in6_subj))
break;
/*
@@ -1884,11 +1887,18 @@ icmp6_rip6_input(mp, off)
}
#endif
+ /*
+ * XXX: the address may have embedded scope zone ID, which should be
+ * hidden from applications.
+ */
bzero(&fromsa, sizeof(fromsa));
- fromsa.sin6_len = sizeof(struct sockaddr_in6);
fromsa.sin6_family = AF_INET6;
- /* KAME hack: recover scopeid */
- (void)in6_recoverscope(&fromsa, &ip6->ip6_src, m->m_pkthdr.rcvif);
+ fromsa.sin6_len = sizeof(struct sockaddr_in6);
+ fromsa.sin6_addr = ip6->ip6_src;
+ if (sa6_recoverscope(&fromsa)) {
+ m_freem(m);
+ return (IPPROTO_DONE);
+ }
INP_INFO_RLOCK(&ripcbinfo);
LIST_FOREACH(in6p, &ripcb, inp_list) {
@@ -2019,11 +2029,10 @@ icmp6_reflect(m, off)
struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia;
- struct in6_addr t, *src = 0;
int plen;
int type, code;
struct ifnet *outif = NULL;
- struct sockaddr_in6 sa6_src, sa6_dst;
+ struct in6_addr origdst, *src = NULL;
#ifdef COMPAT_RFC1885
int mtu = IPV6_MMTU;
struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
@@ -2074,35 +2083,13 @@ icmp6_reflect(m, off)
type = icmp6->icmp6_type; /* keep type for statistics */
code = icmp6->icmp6_code; /* ditto. */
- t = ip6->ip6_dst;
+ origdst = ip6->ip6_dst;
/*
* ip6_input() drops a packet if its src is multicast.
* So, the src is never multicast.
*/
ip6->ip6_dst = ip6->ip6_src;
- /*
- * XXX: make sure to embed scope zone information, using
- * already embedded IDs or the received interface (if any).
- * Note that rcvif may be NULL.
- * TODO: scoped routing case (XXX).
- */
- bzero(&sa6_src, sizeof(sa6_src));
- sa6_src.sin6_family = AF_INET6;
- sa6_src.sin6_len = sizeof(sa6_src);
- sa6_src.sin6_addr = ip6->ip6_dst;
- in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif);
- if (in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL))
- goto bad;
-
- bzero(&sa6_dst, sizeof(sa6_dst));
- sa6_dst.sin6_family = AF_INET6;
- sa6_dst.sin6_len = sizeof(sa6_dst);
- sa6_dst.sin6_addr = t;
- in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif);
- if (in6_embedscope(&t, &sa6_dst, NULL, NULL))
- goto bad;
-
#ifdef COMPAT_RFC1885
/*
* xxx guess MTU
@@ -2136,29 +2123,42 @@ icmp6_reflect(m, off)
m_adj(m, mtu - m->m_pkthdr.len);
}
#endif
+
/*
* If the incoming packet was addressed directly to us (i.e. unicast),
* use dst as the src for the reply.
* The IN6_IFF_NOTREADY case should be VERY rare, but is possible
* (for example) when we encounter an error while forwarding procedure
* destined to a duplicated address of ours.
+ * Note that ip6_getdstifaddr() may fail if we are in an error handling
+ * procedure of an outgoing packet of our own, in which case we need
+ * to search in the ifaddr list.
*/
- for (ia = in6_ifaddr; ia; ia = ia->ia_next)
- if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
- (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
- src = &t;
- break;
+ if (!IN6_IS_ADDR_MULTICAST(&origdst)) {
+ if ((ia = ip6_getdstifaddr(m))) {
+ if (!(ia->ia6_flags &
+ (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
+ src = &ia->ia_addr.sin6_addr;
+ } else {
+ struct sockaddr_in6 d;
+
+ bzero(&d, sizeof(d));
+ d.sin6_family = AF_INET6;
+ d.sin6_len = sizeof(d);
+ d.sin6_addr = origdst;
+ ia = (struct in6_ifaddr *)
+ ifa_ifwithaddr((struct sockaddr *)&d);
+ if (ia &&
+ !(ia->ia6_flags &
+ (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
+ src = &ia->ia_addr.sin6_addr;
+ }
}
- if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
- /*
- * This is the case if the dst is our link-local address
- * and the sender is also ourselves.
- */
- src = &t;
}
- if (src == 0) {
+ if (src == NULL) {
int e;
+ struct sockaddr_in6 sin6;
struct route_in6 ro;
/*
@@ -2166,21 +2166,25 @@ icmp6_reflect(m, off)
* that we do not own. Select a source address based on the
* source address of the erroneous packet.
*/
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
+
bzero(&ro, sizeof(ro));
- src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e);
+ src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &e);
if (ro.ro_rt)
RTFREE(ro.ro_rt); /* XXX: we could use this */
if (src == NULL) {
nd6log((LOG_DEBUG,
"icmp6_reflect: source can't be determined: "
"dst=%s, error=%d\n",
- ip6_sprintf(&sa6_src.sin6_addr), e));
+ ip6_sprintf(&sin6.sin6_addr), e));
goto bad;
}
}
ip6->ip6_src = *src;
-
ip6->ip6_flow = 0;
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION;
@@ -2280,10 +2284,10 @@ icmp6_redirect_input(m, off)
redtgt6 = nd_rd->nd_rd_target;
reddst6 = nd_rd->nd_rd_dst;
- if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
- redtgt6.s6_addr16[1] = htons(ifp->if_index);
- if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
- reddst6.s6_addr16[1] = htons(ifp->if_index);
+ if (in6_setscope(&redtgt6, m->m_pkthdr.rcvif, NULL) ||
+ in6_setscope(&reddst6, m->m_pkthdr.rcvif, NULL)) {
+ goto freeit;
+ }
/* validation */
if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
@@ -2477,9 +2481,6 @@ icmp6_redirect_output(m0, rt)
src_sa.sin6_family = AF_INET6;
src_sa.sin6_len = sizeof(src_sa);
src_sa.sin6_addr = sip6->ip6_src;
- /* we don't currently use sin6_scope_id, but eventually use it */
- if (in6_addr2zoneid(ifp, &sip6->ip6_src, &src_sa.sin6_scope_id))
- goto fail;
if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
goto fail;
if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
OpenPOWER on IntegriCloud