Send many small fragments that exceed the pf reassembly queue limit.
authorbluhm <bluhm@openbsd.org>
Mon, 10 Sep 2018 13:00:58 +0000 (13:00 +0000)
committerbluhm <bluhm@openbsd.org>
Mon, 10 Sep 2018 13:00:58 +0000 (13:00 +0000)
regress/sys/netinet/frag/Makefile
regress/sys/netinet/frag/frag_queuelimit.py [new file with mode: 0644]
regress/sys/netinet6/frag6/Makefile
regress/sys/netinet6/frag6/frag6_queuelimit.py [new file with mode: 0644]

index 6c85de1..2cd0c9e 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.3 2018/08/30 19:34:37 bluhm Exp $
+#      $OpenBSD: Makefile,v 1.4 2018/09/10 13:00:58 bluhm Exp $
 
 # The following ports must be installed:
 #
@@ -112,6 +112,11 @@ run-regress-stack-frag_mf1end.py:
        # the stack allows fragments with MF together with fragments without MF
        @echo DISABLED
 
+run-regress-stack-frag_queuelimit.py:
+       @echo '\n======== $@ ========'
+       # the stack does not limit the amount of fragments during reassembly
+       @echo DISABLED
+
 .for sp in stack pf
 
 # Ping all addresses.  This ensures that the ip addresses are configured
diff --git a/regress/sys/netinet/frag/frag_queuelimit.py b/regress/sys/netinet/frag/frag_queuelimit.py
new file mode 100644 (file)
index 0000000..2edf4b6
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/local/bin/python2.7
+
+print "drop too long fragment queue, reassemble less fragments"
+
+# |----|
+#      |----|
+#           |----|
+#                 ...                                           ...
+#                                                                  |----|
+
+import os
+from addr import *
+from scapy.all import *
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload="ABCDEFGHIJKLMNOP" * 70
+frag=[]
+fid=pid & 0xffff
+# send packets with 65 and 64 fragments
+for max in (64, 63):
+       eid = ~eid & 0xffff
+       packet=IP(src=LOCAL_ADDR, dst=REMOTE_ADDR)/ \
+           ICMP(type='echo-request', id=eid)/payload
+       fid = ~fid & 0xffff
+       for i in range(max):
+               frag.append(IP(src=LOCAL_ADDR, dst=REMOTE_ADDR, proto=1, id=fid,
+                   frag=i, flags='MF')/str(packet)[20+i*8:20+(i+1)*8])
+       frag.append(IP(src=LOCAL_ADDR, dst=REMOTE_ADDR, proto=1, id=fid,
+           frag=max)/str(packet)[20+max*8:])
+eth=[]
+for f in frag:
+       eth.append(Ether(src=LOCAL_MAC, dst=REMOTE_MAC)/f)
+
+child = os.fork()
+if child == 0:
+       time.sleep(1)
+       for e in eth:
+               sendp(e, iface=LOCAL_IF)
+               time.sleep(0.001)
+       os._exit(0)
+
+ans=sniff(iface=LOCAL_IF, timeout=6, filter=
+    "ip and src "+REMOTE_ADDR+" and dst "+LOCAL_ADDR+" and icmp")
+os.kill(child, 15)
+os.wait()
+
+reply=False
+for a in ans:
+       if a and a.type == ETH_P_IP and \
+           a.payload.proto == 1 and \
+           a.payload.frag == 0 and a.payload.flags == 0 and \
+           icmptypes[a.payload.payload.type] == 'echo-reply':
+               id=a.payload.payload.id
+               print "id=%#x" % (id)
+               if id == ~eid & 0xffff:
+                       print "ECHO REPLY FROM 65 FRAGMENTS"
+                       exit(1)
+               if id != eid:
+                       print "WRONG ECHO REPLY ID"
+                       exit(2)
+               data=a.payload.payload.payload.load
+               print "payload=%s" % (data)
+               if data != payload:
+                       print "PAYLOAD!=%s" % (payload)
+                       exit(2)
+               reply=True
+if not reply:
+       print "NO ECHO REPLY FROM 64 FRAGMENTS"
+       exit(1)
+exit(0)
index 4043283..06f5eba 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.23 2017/11/14 15:30:35 bluhm Exp $
+#      $OpenBSD: Makefile,v 1.24 2018/09/10 13:00:58 bluhm Exp $
 
 # The following ports must be installed:
 #
@@ -97,6 +97,11 @@ stamp-pf: addr.py pf.conf
 REGRESS_TARGETS =
 FRAG6_SCRIPTS !!=      cd ${.CURDIR} && ls -1 frag6*.py
 
+run-regress-stack-frag6_queuelimit.py:
+       @echo '\n======== $@ ========'
+       # the stack does not limit the amount of fragments during reassembly
+       @echo DISABLED
+
 .for sp in stack pf
 
 # Ping all addresses.  This ensures that the ip addresses are configured
diff --git a/regress/sys/netinet6/frag6/frag6_queuelimit.py b/regress/sys/netinet6/frag6/frag6_queuelimit.py
new file mode 100644 (file)
index 0000000..8f14522
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/local/bin/python2.7
+
+print "drop too long fragment queue, reassemble less fragments"
+
+# |----|
+#      |----|
+#           |----|
+#                 ...                                           ...
+#                                                                  |----|
+
+import os
+from addr import *
+from scapy.all import *
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload="ABCDEFGHIJKLMNOP" * 70
+frag=[]
+fid=pid & 0xffffffff
+# send packets with 65 and 64 fragments
+for max in (64, 63):
+       eid = ~eid & 0xffff
+       packet=IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/ \
+           ICMPv6EchoRequest(id=eid, data=payload)
+       fid = ~fid & 0xffffffff
+       for i in range(max):
+               frag.append(IPv6ExtHdrFragment(nh=58, id=fid, m=1,
+                   offset=i)/str(packet)[40+i*8:40+(i+1)*8])
+       frag.append(IPv6ExtHdrFragment(nh=58, id=fid,
+           offset=max)/str(packet)[40+max*8:])
+eth=[]
+for f in frag:
+       pkt=IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/f
+       eth.append(Ether(src=LOCAL_MAC, dst=REMOTE_MAC)/pkt)
+
+child = os.fork()
+if child == 0:
+       time.sleep(1)
+       for e in eth:
+               sendp(e, iface=LOCAL_IF)
+               time.sleep(0.001)
+       os._exit(0)
+
+ans=sniff(iface=LOCAL_IF, timeout=6, filter=
+    "ip6 and src "+REMOTE_ADDR6+" and dst "+LOCAL_ADDR6+" and icmp6")
+os.kill(child, 15)
+os.wait()
+
+reply=False
+for a in ans:
+       if a and a.type == ETH_P_IPV6 and \
+           ipv6nh[a.payload.nh] == 'ICMPv6' and \
+           icmp6types[a.payload.payload.type] == 'Echo Reply':
+               id=a.payload.payload.id
+               print "id=%#x" % (id)
+               if id == ~eid & 0xffff:
+                       print "ECHO REPLY FROM 65 FRAGMENTS"
+                       exit(1)
+               if id != eid:
+                       print "WRONG ECHO REPLY ID"
+                       exit(2)
+               data=a.payload.payload.data
+               print "payload=%s" % (data)
+               if data != payload:
+                       print "PAYLOAD!=%s" % (payload)
+                       exit(2)
+               reply=True
+if not reply:
+       print "NO ECHO REPLY FROM 64 FRAGMENTS"
+       exit(1)
+exit(0)