mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
pf tests: add more fragmentation test cases
Add more test cases for pf fragment hole counter. Also look into
final fragment of echo reply and check total length of IP packet.
MFC after: 1 week
Obtained from: OpenBSD, bluhm <bluhm@openbsd.org>, 640736615b
Sponsored by: Rubicon Communications, LLC ("Netgate")
(cherry picked from commit db100bd930)
This commit is contained in:
parent
2e0f053ad5
commit
5ff91b71bb
4 changed files with 183 additions and 0 deletions
|
|
@ -62,6 +62,8 @@ ${PACKAGE}FILES+= CVE-2019-5597.py \
|
|||
frag-overindex.py \
|
||||
frag-overlimit.py \
|
||||
frag-overreplace.py \
|
||||
frag-overhole.py \
|
||||
frag-adjhole.py \
|
||||
pfsync_defer.py \
|
||||
pft_ether.py \
|
||||
rdr-srcport.py \
|
||||
|
|
@ -73,6 +75,8 @@ ${PACKAGE}FILESMODE_fragcommon.py= 0555
|
|||
${PACKAGE}FILESMODE_frag-overindex.py= 0555
|
||||
${PACKAGE}FILESMODE_frag-overlimit.py= 0555
|
||||
${PACKAGE}FILESMODE_frag-overreplace.py= 0555
|
||||
${PACKAGE}FILESMODE_frag-overhole.py= 0555
|
||||
${PACKAGE}FILESMODE_frag-adjhole.py= 0555
|
||||
${PACKAGE}FILESMODE_pfsync_defer.py= 0555
|
||||
${PACKAGE}FILESMODE_pft_ether.py= 0555
|
||||
|
||||
|
|
|
|||
58
tests/sys/netpfil/pf/frag-adjhole.py
Normal file
58
tests/sys/netpfil/pf/frag-adjhole.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2025 Alexander Bluhm <bluhm@openbsd.org>
|
||||
|
||||
from fragcommon import *
|
||||
|
||||
# |--------|
|
||||
# |--------|
|
||||
# |-------|
|
||||
# |----|
|
||||
|
||||
def send(src, dst, send_if, recv_if):
|
||||
pid = os.getpid()
|
||||
eid = pid & 0xffff
|
||||
payload = b"ABCDEFGHIJKLMNOP" * 2
|
||||
packet = sp.IP(src=src, dst=dst)/ \
|
||||
sp.ICMP(type='echo-request', id=eid) / payload
|
||||
frag = []
|
||||
fid = pid & 0xffff
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
flags='MF') / bytes(packet)[20:36])
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=2, flags='MF') / bytes(packet)[36:52])
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=1, flags='MF') / bytes(packet)[28:44])
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=4) / bytes(packet)[52:60])
|
||||
eth=[]
|
||||
for f in frag:
|
||||
eth.append(sp.Ether()/f)
|
||||
if os.fork() == 0:
|
||||
time.sleep(1)
|
||||
sp.sendp(eth, iface=send_if)
|
||||
os._exit(0)
|
||||
|
||||
ans = sp.sniff(iface=recv_if, timeout=3, filter=
|
||||
"ip and src " + dst + " and dst " + src + " and icmp")
|
||||
for a in ans:
|
||||
if a and a.type == sp.ETH_P_IP and \
|
||||
a.payload.proto == 1 and \
|
||||
a.payload.frag == 0 and a.payload.flags == 0 and \
|
||||
sp.icmptypes[a.payload.payload.type] == 'echo-reply':
|
||||
id = a.payload.payload.id
|
||||
print("id=%#x" % (id))
|
||||
if id != eid:
|
||||
print("WRONG ECHO REPLY ID")
|
||||
exit(2)
|
||||
data = a.payload.payload.payload.load
|
||||
print("payload=%s" % (data))
|
||||
if data == payload:
|
||||
exit(0)
|
||||
print("PAYLOAD!=%s" % (payload))
|
||||
exit(1)
|
||||
print("NO ECHO REPLY")
|
||||
exit(2)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(send)
|
||||
83
tests/sys/netpfil/pf/frag-overhole.py
Normal file
83
tests/sys/netpfil/pf/frag-overhole.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2025 Alexander Bluhm <bluhm@openbsd.org>
|
||||
|
||||
from fragcommon import *
|
||||
|
||||
# index boundary 4096 |
|
||||
# |--------------|
|
||||
# ....
|
||||
# |--------------|
|
||||
# |----------|
|
||||
# |XXXX----------|
|
||||
# |XXXX----|
|
||||
# |---|
|
||||
|
||||
# this should trigger "frag tail overlap %d" and "frag head overlap %d"
|
||||
def send(src, dst, send_if, recv_if):
|
||||
pid = os.getpid()
|
||||
eid = pid & 0xffff
|
||||
payload = b"ABCDEFGHIJKLMNOP"
|
||||
dummy = b"01234567"
|
||||
fragsize = 1024
|
||||
boundary = 4096
|
||||
fragnum = int(boundary / fragsize)
|
||||
packet = sp.IP(src=src, dst=dst)/ \
|
||||
sp.ICMP(type='echo-request', id=eid)/ \
|
||||
((int((boundary + fragsize) / len(payload)) + 1) * payload)
|
||||
packet_length = len(packet)
|
||||
frag = []
|
||||
fid = pid & 0xffff
|
||||
for i in range(fragnum-1):
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=(i * fragsize)>>3, flags='MF')/
|
||||
bytes(packet)[20 + i * fragsize:20 + (i + 1) * fragsize])
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=(boundary - fragsize) >> 3, flags='MF')/
|
||||
bytes(packet)[20 + boundary - fragsize:20 + boundary - len(dummy)])
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=(boundary - len(dummy)) >> 3, flags='MF')/
|
||||
(dummy+bytes(packet)[20 + boundary:20 + boundary + fragsize]))
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=(boundary - 8 - len(dummy)) >> 3, flags='MF')/
|
||||
(dummy+bytes(packet)[20 + boundary - 8:20 + boundary]))
|
||||
frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
|
||||
frag=(boundary + fragsize) >> 3)/bytes(packet)[20 + boundary + fragsize:])
|
||||
eth=[]
|
||||
for f in frag:
|
||||
eth.append(sp.Ether() / f)
|
||||
|
||||
if os.fork() == 0:
|
||||
time.sleep(1)
|
||||
for e in eth:
|
||||
sp.sendp(e, iface=send_if)
|
||||
time.sleep(0.001)
|
||||
os._exit(0)
|
||||
|
||||
ans = sp.sniff(iface=recv_if, timeout=3, filter=
|
||||
"ip and src " + dst + " and dst " + src + " and icmp")
|
||||
for a in ans:
|
||||
if a and a.type == sp.ETH_P_IP and \
|
||||
a.payload.proto == 1 and \
|
||||
a.payload.frag == 0 and \
|
||||
sp.icmptypes[a.payload.payload.type] == 'echo-reply':
|
||||
id = a.payload.payload.id
|
||||
print("id=%#x" % (id))
|
||||
if id != eid:
|
||||
print("WRONG ECHO REPLY ID")
|
||||
exit(2)
|
||||
if a and a.type == sp.ETH_P_IP and \
|
||||
a.payload.proto == 1 and \
|
||||
a.payload.frag > 0 and \
|
||||
a.payload.flags == '':
|
||||
length = (a.payload.frag << 3) + a.payload.len
|
||||
print("len=%d" % (length))
|
||||
if length != packet_length:
|
||||
print("WRONG ECHO REPLY LENGTH")
|
||||
exit(1)
|
||||
exit(0)
|
||||
print("NO ECHO REPLY")
|
||||
exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(send)
|
||||
|
|
@ -285,6 +285,42 @@ overlimit_cleanup()
|
|||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "overhole" "cleanup"
|
||||
overhole_head()
|
||||
{
|
||||
atf_set descr 'ping fragment at index boundary which modifies pf hole counter'
|
||||
atf_set require.user root
|
||||
atf_set require.progs scapy
|
||||
}
|
||||
|
||||
overhole_body()
|
||||
{
|
||||
frag_common overhole
|
||||
}
|
||||
|
||||
overhole_cleanup()
|
||||
{
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "adjhole" "cleanup"
|
||||
adjhole_head()
|
||||
{
|
||||
atf_set descr 'overlapping ping fragments which modifies pf hole counter'
|
||||
atf_set require.user root
|
||||
atf_set require.progs scapy
|
||||
}
|
||||
|
||||
adjhole_body()
|
||||
{
|
||||
frag_common adjhole
|
||||
}
|
||||
|
||||
adjhole_cleanup()
|
||||
{
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "reassemble" "cleanup"
|
||||
reassemble_head()
|
||||
{
|
||||
|
|
@ -476,6 +512,8 @@ atf_init_test_cases()
|
|||
atf_add_test_case "overreplace"
|
||||
atf_add_test_case "overindex"
|
||||
atf_add_test_case "overlimit"
|
||||
atf_add_test_case "overhole"
|
||||
atf_add_test_case "adjhole"
|
||||
atf_add_test_case "reassemble"
|
||||
atf_add_test_case "no_df"
|
||||
atf_add_test_case "reassemble_slowpath"
|
||||
|
|
|
|||
Loading…
Reference in a new issue