diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2012-01-10 17:09:03 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2012-01-10 17:09:03 +0000 |
commit | 30934d0bf3ba08c4af68407d9c14505a351b67dc (patch) | |
tree | 53f75a30f77f06c6a3a20bd649acf33df463c159 /sys | |
parent | 819a8c17b408d72423a4265321955fa34c3bac53 (diff) |
Implement RFC 5722 and drop all IPv6 fragments that belong to a
packet with overlapping fragments.
ok henning@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet6/frag6.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index 0293f673a0c..779740399ed 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frag6.c,v 1.39 2012/01/10 12:50:32 bluhm Exp $ */ +/* $OpenBSD: frag6.c,v 1.40 2012/01/10 17:09:02 bluhm Exp $ */ /* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */ /* @@ -284,8 +284,15 @@ frag6_input(struct mbuf **mp, int *offp, int proto) q6->ip6q_src = ip6->ip6_src; q6->ip6q_dst = ip6->ip6_dst; q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ - q6->ip6q_nfrag = 0; + } else if (LIST_EMPTY(&q6->ip6q_asfrag)) { + /* + * Overlapping fragments have been detected. Do not + * reassemble packet but also drop future fragments. + * This will be done for this ident/src/dst combination + * until fragment queue timeout. + */ + goto dropfrag; } /* @@ -402,11 +409,10 @@ frag6_input(struct mbuf **mp, int *offp, int proto) break; /* - * If the incoming fragment overlaps some existing fragments in - * the reassembly queue, drop it, since it is dangerous to override - * existing fragments from a security point of view. - * We don't know which fragment is the bad guy - here we trust - * fragment that came in earlier, with no real reason. + * RFC5722: When reassembling an IPv6 datagram, if one or more its + * constituent fragments is determined to be an overlapping fragment, + * the entire datagram (and any constituent fragments, including those + * not yet received) MUST be silently discarded. */ if (paf6 != LIST_END(&q6->ip6q_asfrag)) { i = (paf6->ip6af_off + paf6->ip6af_frglen) - ip6af->ip6af_off; @@ -417,7 +423,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto) i, ip6_sprintf(&q6->ip6q_src)); #endif free(ip6af, M_FTABLE); - goto dropfrag; + goto flushfrags; } } if (af6 != LIST_END(&q6->ip6q_asfrag)) { @@ -429,7 +435,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto) i, ip6_sprintf(&q6->ip6q_src)); #endif free(ip6af, M_FTABLE); - goto dropfrag; + goto flushfrags; } } @@ -535,6 +541,17 @@ frag6_input(struct mbuf **mp, int *offp, int proto) IP6Q_UNLOCK(); return nxt; + flushfrags: + while ((af6 = LIST_FIRST(&q6->ip6q_asfrag)) != + LIST_END(&q6->ip6q_asfrag)) { + LIST_REMOVE(af6, ip6af_list); + m_freem(IP6_REASS_MBUF(af6)); + free(af6, M_FTABLE); + } + ip6stat.ip6s_fragdropped += q6->ip6q_nfrag; + frag6_nfrags -= q6->ip6q_nfrag; + q6->ip6q_nfrag = 0; + dropfrag: in6_ifstat_inc(dstifp, ifs6_reass_fail); ip6stat.ip6s_fragdropped++; |