From 76ee45fffe33c2b22043e1cf0d65a52d3466ffca Mon Sep 17 00:00:00 2001 From: bluhm Date: Mon, 10 Sep 2018 13:00:58 +0000 Subject: [PATCH] Send many small fragments that exceed the pf reassembly queue limit. --- regress/sys/netinet/frag/Makefile | 7 +- regress/sys/netinet/frag/frag_queuelimit.py | 71 +++++++++++++++++++ regress/sys/netinet6/frag6/Makefile | 7 +- .../sys/netinet6/frag6/frag6_queuelimit.py | 71 +++++++++++++++++++ 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 regress/sys/netinet/frag/frag_queuelimit.py create mode 100644 regress/sys/netinet6/frag6/frag6_queuelimit.py diff --git a/regress/sys/netinet/frag/Makefile b/regress/sys/netinet/frag/Makefile index 6c85de1867c..2cd0c9ef306 100644 --- a/regress/sys/netinet/frag/Makefile +++ b/regress/sys/netinet/frag/Makefile @@ -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 index 00000000000..2edf4b6d3cf --- /dev/null +++ b/regress/sys/netinet/frag/frag_queuelimit.py @@ -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) diff --git a/regress/sys/netinet6/frag6/Makefile b/regress/sys/netinet6/frag6/Makefile index 40432839443..06f5ebae0fb 100644 --- a/regress/sys/netinet6/frag6/Makefile +++ b/regress/sys/netinet6/frag6/Makefile @@ -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 index 00000000000..8f14522f6bd --- /dev/null +++ b/regress/sys/netinet6/frag6/frag6_queuelimit.py @@ -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) -- 2.20.1