Hi,
Implement RFC 5722 and drop all IPv6 fragments that belong to a
packet with overlapping fragments.
ok?
bluhm
Index: netinet6/frag6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/frag6.c,v
retrieving revision 1.39
diff -u -p -r1.39 frag6.c
--- netinet6/frag6.c 10 Jan 2012 12:50:32 -0000 1.39
+++ netinet6/frag6.c 10 Jan 2012 16:15:46 -0000
@@ -284,8 +284,15 @@ frag6_input(struct mbuf **mp, int *offp,
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;
+ 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,
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,
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,
i, ip6_sprintf(&q6->ip6q_src));
#endif
free(ip6af, M_FTABLE);
- goto dropfrag;
+ goto flushfrags;
}
}
@@ -534,6 +540,17 @@ frag6_input(struct mbuf **mp, int *offp,
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);