svn commit: r354542 - in head: sys/netinet6 tests/sys/netinet6/frag6

Bjoern A. Zeeb bz at FreeBSD.org
Fri Nov 8 14:36:45 UTC 2019


Author: bz
Date: Fri Nov  8 14:36:44 2019
New Revision: 354542
URL: https://svnweb.freebsd.org/changeset/base/354542

Log:
  frag6: properly handle atomic fragments according to RFCs.
  
  RFC 8200 says:
  	"If the fragment is a whole datagram (that is, both the Fragment
           Offset field and the M flag are zero), then it does not need
           any further reassembly and should be processed as a fully
           reassembled packet (i.e., updating Next Header, adjust Payload
           Length, removing the Fragment header, etc.).  .."
  
  That means we should remove the fragment header and make all the adjustments
  rather than just skipping over the fragment header.  The difference should
  be noticeable in that a properly handled atomic fragment triggering an ICMPv6
  message at an upper layer (e.g. dest unreach, unreachable port) will not
  include the fragment header.
  
  Update the test cases to also test for an unfragmentable part.  That is
  needed so that the next header is properly updated (not just lengths).
  
  MFC after:	3 weeks
  Sponsored by:	Netflix
  Differential Revision:	https://reviews.freebsd.org/D22155

Modified:
  head/sys/netinet6/frag6.c
  head/tests/sys/netinet6/frag6/frag6_03.py
  head/tests/sys/netinet6/frag6/frag6_03.sh

Modified: head/sys/netinet6/frag6.c
==============================================================================
--- head/sys/netinet6/frag6.c	Fri Nov  8 14:28:39 2019	(r354541)
+++ head/sys/netinet6/frag6.c	Fri Nov  8 14:36:44 2019	(r354542)
@@ -395,6 +395,8 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 	m = *mp;
 	offset = *offp;
 
+	M_ASSERTPKTHDR(m);
+
 	ip6 = mtod(m, struct ip6_hdr *);
 #ifndef PULLDOWN_TEST
 	IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
@@ -437,22 +439,35 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 	IP6STAT_INC(ip6s_fragments);
 	in6_ifstat_inc(dstifp, ifs6_reass_reqd);
 
-	/* Offset now points to data portion. */
-	offset += sizeof(struct ip6_frag);
-
 	/*
 	 * Handle "atomic" fragments (offset and m bit set to 0) upfront,
-	 * unrelated to any reassembly.  Still need to remove the frag hdr.
+	 * unrelated to any reassembly.  We need to remove the frag hdr
+	 * which is ugly.
 	 * See RFC 6946 and section 4.5 of RFC 8200.
 	 */
 	if ((ip6f->ip6f_offlg & ~IP6F_RESERVED_MASK) == 0) {
 		IP6STAT_INC(ip6s_atomicfrags);
-		/* XXX-BZ handle correctly. */
+		nxt = ip6f->ip6f_nxt;
+		/*
+		 * Set nxt(-hdr field value) to the original value.
+		 * We cannot just set ip6->ip6_nxt as there might be
+		 * an unfragmentable part with extension headers and
+		 * we must update the last one.
+		 */
+		m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t),
+		    (caddr_t)&nxt);
+		ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) -
+		    sizeof(struct ip6_frag));
+		if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0)
+			goto dropfrag2;
+		m->m_pkthdr.len -= sizeof(struct ip6_frag);
 		in6_ifstat_inc(dstifp, ifs6_reass_ok);
-		*offp = offset;
-		m->m_flags |= M_FRAGMENTED;
-		return (ip6f->ip6f_nxt);
+		*mp = m;
+		return (nxt);
 	}
+
+	/* Offset now points to data portion. */
+	offset += sizeof(struct ip6_frag);
 
 	/* Get fragment length and discard 0-byte fragments. */
 	frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;

Modified: head/tests/sys/netinet6/frag6/frag6_03.py
==============================================================================
--- head/tests/sys/netinet6/frag6/frag6_03.py	Fri Nov  8 14:28:39 2019	(r354541)
+++ head/tests/sys/netinet6/frag6/frag6_03.py	Fri Nov  8 14:36:44 2019	(r354542)
@@ -101,6 +101,33 @@ def main():
 	if not sniffer.foundCorrectPacket:
 		sys.exit(1)
 
+
+	# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+	#
+	# Atomic fragment with extension header.
+	#
+	# A:  Nothing listening on UDP port.
+	# R:  ICMPv6 dst unreach, unreach port.
+	#
+	# Start sniffing on recvif
+	sniffer = Sniffer(args, check_icmp6_error)
+
+	ip6f01 = sp.Ether() / \
+		sp.IPv6(src=args.src[0], dst=args.to[0]) / \
+		sp.IPv6ExtHdrDestOpt(options = \
+		    sp.PadN(optdata="\x00\x00\x00\x00\x00\x00")) / \
+		sp.IPv6ExtHdrFragment(offset=0, m=0, id=0x3001) / \
+		sp.UDP(dport=3456, sport=6543)
+	if args.debug :
+		ip6f01.display()
+	sp.sendp(ip6f01, iface=args.sendif[0], verbose=False)
+
+	sleep(0.10)
+	sniffer.setEnd()
+	sniffer.join()
+	if not sniffer.foundCorrectPacket:
+		sys.exit(1)
+
 	sys.exit(0)
 
 if __name__ == '__main__':

Modified: head/tests/sys/netinet6/frag6/frag6_03.sh
==============================================================================
--- head/tests/sys/netinet6/frag6/frag6_03.sh	Fri Nov  8 14:28:39 2019	(r354541)
+++ head/tests/sys/netinet6/frag6/frag6_03.sh	Fri Nov  8 14:36:44 2019	(r354542)
@@ -67,12 +67,12 @@ frag6_03_check_stats() {
 	# Check selection of global UDP stats.
 	#
 	cat <<EOF > ${HOME}/filter-${jname}.txt
-    <received-datagrams>1</received-datagrams>
+    <received-datagrams>2</received-datagrams>
     <dropped-incomplete-headers>0</dropped-incomplete-headers>
     <dropped-bad-data-length>0</dropped-bad-data-length>
     <dropped-bad-checksum>0</dropped-bad-checksum>
     <dropped-no-checksum>0</dropped-no-checksum>
-    <dropped-no-socket>1</dropped-no-socket>
+    <dropped-no-socket>2</dropped-no-socket>
     <dropped-broadcast-multicast>0</dropped-broadcast-multicast>
     <dropped-full-socket-buffer>0</dropped-full-socket-buffer>
     <not-for-hashed-pcb>0</not-for-hashed-pcb>
@@ -94,11 +94,11 @@ EOF
     <dropped-short-packets>0</dropped-short-packets>
     <dropped-bad-options>0</dropped-bad-options>
     <dropped-bad-version>0</dropped-bad-version>
-    <received-fragments>1</received-fragments>
+    <received-fragments>2</received-fragments>
     <dropped-fragment>0</dropped-fragment>
     <dropped-fragment-after-timeout>0</dropped-fragment-after-timeout>
     <dropped-fragments-overflow>0</dropped-fragments-overflow>
-    <atomic-fragments>1</atomic-fragments>
+    <atomic-fragments>2</atomic-fragments>
     <reassembled-packets>0</reassembled-packets>
     <forwarded-packets>0</forwarded-packets>
     <packets-not-forwardable>0</packets-not-forwardable>
@@ -124,12 +124,12 @@ EOF
 	# XXX-TODO check output histogram (just too hard to parse [no multi-line-grep])
 	#
 	cat <<EOF > ${HOME}/filter-${jname}.txt
-    <icmp6-calls>1</icmp6-calls>
+    <icmp6-calls>2</icmp6-calls>
       <no-route>0</no-route>
       <admin-prohibited>0</admin-prohibited>
       <beyond-scope>0</beyond-scope>
       <address-unreachable>0</address-unreachable>
-      <port-unreachable>1</port-unreachable>
+      <port-unreachable>2</port-unreachable>
       <packet-too-big>0</packet-too-big>
       <time-exceed-transmit>0</time-exceed-transmit>
       <time-exceed-reassembly>0</time-exceed-reassembly>
@@ -170,8 +170,8 @@ EOF
     <discard-fragments>0</discard-fragments>
     <fragments-failed>0</fragments-failed>
     <fragments-created>0</fragments-created>
-    <reassembly-required>1</reassembly-required>
-    <reassembled-packets>1</reassembled-packets>
+    <reassembly-required>2</reassembly-required>
+    <reassembled-packets>2</reassembled-packets>
     <reassembly-failed>0</reassembly-failed>
 EOF
 	count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt`
@@ -196,8 +196,8 @@ EOF
     <received-echo-replies>0</received-echo-replies>
     <received-router-solicitation>0</received-router-solicitation>
     <received-router-advertisement>0</received-router-advertisement>
-    <sent-errors>1</sent-errors>
-    <sent-destination-unreachable>1</sent-destination-unreachable>
+    <sent-errors>2</sent-errors>
+    <sent-destination-unreachable>2</sent-destination-unreachable>
     <sent-admin-prohibited>0</sent-admin-prohibited>
     <sent-time-exceeded>0</sent-time-exceeded>
     <sent-bad-parameter>0</sent-bad-parameter>


More information about the svn-src-head mailing list