Send packets with IPv4 option or IPv6 extension header over loopback
authorbluhm <bluhm@openbsd.org>
Wed, 27 Apr 2022 18:28:40 +0000 (18:28 +0000)
committerbluhm <bluhm@openbsd.org>
Wed, 27 Apr 2022 18:28:40 +0000 (18:28 +0000)
interface and check which of the packets are dropped by pf.  The
bad packets appear in pflog0 tcpdump.  This regress is testing rules
with and without allow-opts.

14 files changed:
regress/sys/net/pf_opts/LICENSE [new file with mode: 0644]
regress/sys/net/pf_opts/Makefile [new file with mode: 0644]
regress/sys/net/pf_opts/icmp.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp6.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp6_dst.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp6_hop.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp6_hop_bad.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp6_hop_pad.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp6_hop_ra.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp_bad.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp_eol.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp_pad.py [new file with mode: 0644]
regress/sys/net/pf_opts/icmp_ra.py [new file with mode: 0644]
regress/sys/net/pf_opts/pf.conf [new file with mode: 0644]

diff --git a/regress/sys/net/pf_opts/LICENSE b/regress/sys/net/pf_opts/LICENSE
new file mode 100644 (file)
index 0000000..3033941
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) 2022 Alexander Bluhm <bluhm@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/regress/sys/net/pf_opts/Makefile b/regress/sys/net/pf_opts/Makefile
new file mode 100644 (file)
index 0000000..77e11d2
--- /dev/null
@@ -0,0 +1,286 @@
+# $OpenBSD: Makefile,v 1.1.1.1 2022/04/27 18:28:40 bluhm Exp $
+
+# Copyright (c) 2022 Alexander Bluhm <bluhm@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# Set up two loopback interfaces in different routing domains.
+# One loopback interface has a allow-opts pf rule, the other has
+# default pass policy.  Send packets with IP options and IPv6
+# option header and check wheter tcpdump finds them on lo or pflog.
+
+# The following ports must be installed:
+#
+# scapy                        powerful interactive packet manipulation in python
+
+.if ! exists(/usr/local/bin/scapy)
+regress:
+       @echo Install scapy package to run this regress.
+       @echo SKIPPED
+.endif
+
+# This test uses routing domain and interface number 11 and 12.
+# Adjust it here, if you want to use something else.
+N1 =           11
+N2 =           12
+NUMS =         ${N1} ${N2}
+
+.include <bsd.own.mk>
+
+.if ! (make(clean) || make(cleandir) || make(obj))
+
+PF_STATUS !=   ${SUDO} pfctl -si | sed -n 's/^Status: \([^ ]*\) .*/\1/p'
+.if empty(PF_STATUS:MEnabled)
+regress:
+       @echo pf status: "${PF_STATUS}"
+       @echo Enable pf to run this regress.
+       @echo SKIPPED
+.endif
+
+PF_SKIP !=     ${SUDO} pfctl -sI -v | sed -n 's/ (skip)//p'
+.if ! empty(PF_SKIP:Mlo*:Nlo0)
+regress:
+       @echo pf skip: "${PF_SKIP}"
+       @echo Do not set skip on interface lo, lo${N1}, or lo${N2}.
+       @echo SKIPPED
+.endif
+
+PF_ANCHOR !=   ${SUDO} pfctl -sr | sed -n 's/^anchor "\([^"]*\)" all$$/\1/p'
+.if empty(PF_ANCHOR:Mregress)
+regress:
+       @echo pf anchor: "${PF_ANCHOR}"
+       @echo Need anchor '"regress"' in pf.conf to load additional rules.
+       @echo SKIPPED
+.endif
+
+.endif
+
+.PHONY: busy-rdomains ifconfig unconfig pfctl
+
+REGRESS_SETUP_ONCE +=  busy-rdomains
+busy-rdomains:
+       # Check if rdomains are busy.
+.for n in ${NUMS}
+       @if /sbin/ifconfig | grep -v '^lo$n:' | grep ' rdomain $n '; then\
+           echo routing domain $n is already used >&2; exit 1; fi
+.endfor
+
+REGRESS_SETUP_ONCE +=  ifconfig
+ifconfig: unconfig
+       # Create and configure loopback interfaces.
+.for n in ${NUMS}
+       ${SUDO} ifconfig lo$n rdomain $n
+       ${SUDO} ifconfig lo$n inet 127.0.0.1/8
+       ${SUDO} ifconfig lo$n inet 127.0.0.$n alias
+       ${SUDO} ifconfig lo$n inet6 ::1/128
+       ${SUDO} ifconfig lo$n inet6 fe80::$n/64
+.endfor
+       ${SUDO} route -n -T ${N1} add -inet -host 127.0.0.${N2} 127.0.0.1
+       ${SUDO} route -n -T ${N2} add -inet -host 127.0.0.${N1} 127.0.0.1
+
+REGRESS_CLEANUP +=     unconfig
+unconfig: stamp-stop
+       # Destroy interfaces.
+.for n in ${NUMS}
+       -${SUDO} ifconfig lo$n inet 127.0.0.1 delete
+       -${SUDO} ifconfig lo$n inet 127.0.0.$n delete
+       -${SUDO} ifconfig lo$n inet6 ::1 delete
+       -${SUDO} ifconfig lo$n inet6 fe80::$n/64 delete
+.endfor
+       rm -f stamp-ifconfig
+
+addr.py: Makefile
+       # Create python include file containing the addresses.
+       rm -f $@ $@.tmp
+.for var in N1 N2
+       echo '${var}="${${var}}"' >>$@.tmp
+       echo 'IF_${var}="lo${${var}}"' >>$@.tmp
+       echo 'ADDR_${var}="127.0.0.${${var}}"' >>$@.tmp
+       echo 'ADDR6_${var}="fe80::${${var}}"' >>$@.tmp
+.endfor
+       mv $@.tmp $@
+
+REGRESS_SETUP_ONCE +=  pfctl
+pfctl: addr.py pf.conf
+       # Load the pf rules into the kernel.
+       cat addr.py ${.CURDIR}/pf.conf | /sbin/pfctl -n -f -
+       cat addr.py ${.CURDIR}/pf.conf | ${SUDO} pfctl -a regress -f -
+
+# run tcpdump on lo and pflog device
+DUMPCMD =      /usr/sbin/tcpdump -l -e -vvv -s 2048 -ni
+
+stamp-bpf: stamp-bpf-lo${N1} stamp-bpf-lo${N2} stamp-bpf-pflog0
+       sleep 2  # XXX
+       @date >$@
+
+.for i in lo${N1} lo${N2} pflog0
+
+stamp-bpf-$i: stamp-ifconfig
+       rm -f $i.tcpdump
+       ${SUDO} pkill -f '^${DUMPCMD} $i' || true
+       ${SUDO} ${DUMPCMD} $i >$i.tcpdump &
+       rm -f stamp-stop
+       @date >$@
+
+.endfor
+
+stamp-stop:
+       sleep 2  # XXX
+       -${SUDO} pkill -f '^${DUMPCMD}'
+       rm -f stamp-bpf*
+       @date >$@
+
+# Set variables so that make runs with and without obj directory.
+# Only do that if necessary to keep visible output short.
+.if ${.CURDIR} == ${.OBJDIR}
+PYTHON =       python3 -u ./
+PYPATH =
+.else
+PYTHON =       python3 -u ${.CURDIR}/
+PYPATH =       PYTHONPATH=${.OBJDIR}
+.endif
+
+# ping
+
+REGRESS_TARGETS +=     run-ping
+run-ping: stamp-bpf
+       # Ping localhost on loopback
+       /sbin/ping -n -w 1 -c 1 -V ${N1} 127.0.0.${N1}
+       /sbin/ping -n -w 1 -c 1 -V ${N2} 127.0.0.${N2}
+
+REGRESS_TARGETS +=     run-ping6
+run-ping6: stamp-bpf
+       # Ping localhost on loopback
+       /sbin/ping6 -n -w 1 -c 1 -V ${N1} fe80::${N1}%lo${N1}
+       /sbin/ping6 -n -w 1 -c 1 -V ${N2} fe80::${N2}%lo${N2}
+
+REGRESS_TARGETS +=     run-bpf-ping
+run-bpf-ping: stamp-stop
+       # Check that ping packet went through loopback.
+       grep ' 127.0.0.${N1}: icmp: echo request' lo${N1}.tcpdump
+       grep ' 127.0.0.${N2}: icmp: echo request' lo${N2}.tcpdump
+       grep ' fe80:.*::${N1}: icmp6: echo request' lo${N1}.tcpdump
+       grep ' fe80:.*::${N2}: icmp6: echo request' lo${N2}.tcpdump
+       ! grep ': icmp: echo request' pflog0.tcpdump
+       ! grep ': icmp6: echo request' pflog0.tcpdump
+
+# ping with RR option
+
+REGRESS_TARGETS +=     run-ping-record
+run-ping-record: stamp-bpf
+       # Ping localhost with record route option
+       /sbin/ping -n -w 1 -c 1 -V ${N1} -R 127.0.0.${N1}
+       ! /sbin/ping -n -w 1 -c 1 -V ${N2} -R 127.0.0.${N2}
+
+REGRESS_TARGETS +=     run-bpf-ping-record
+run-bpf-ping-record: stamp-stop
+       # Check that ping packet with options is in pflog0.
+       grep ' 127.0.0.${N1}: icmp: echo request .*\
+           optlen=40 RR' lo${N1}.tcpdump
+       grep ' 127.0.0.${N2}: icmp: echo request .*\
+           optlen=40 RR' pflog0.tcpdump
+
+# icmp
+
+REGRESS_TARGETS +=     run-icmp
+run-icmp: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp.py N2
+
+REGRESS_TARGETS +=     run-icmp6
+run-icmp6: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp6.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp6.py N2
+
+REGRESS_TARGETS +=     run-bpf-icmp
+run-bpf-icmp: stamp-stop
+       # Check that icmp packet went through loopback.
+       grep ' 127.0.0.${N1}: icmp: type-#6' lo${N1}.tcpdump
+       grep ' 127.0.0.${N2}: icmp: type-#6' lo${N2}.tcpdump
+       grep ' fe80::${N1}: icmp6: type-#6' lo${N1}.tcpdump
+       grep ' fe80::${N2}: icmp6: type-#6' lo${N2}.tcpdump
+       ! grep ': icmp: type-#6' pflog0.tcpdump
+       ! grep ': icmp6: type-#6' pflog0.tcpdump
+
+# option extension header
+
+REGRESS_TARGETS +=     run-icmp6-hop
+run-icmp6-hop: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop.py N2
+
+REGRESS_TARGETS +=     run-icmp6-dst
+run-icmp6-dst: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp6_dst.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp6_dst.py N2
+
+REGRESS_TARGETS +=     run-bpf-ext
+run-bpf-ext: stamp-stop
+       # Check that icmp6 packet with extension headers were blocked
+       fgrep ' fe80::${N2}: HBH icmp6' pflog0.tcpdump
+       fgrep ' fe80::${N2}: DSTOPT icmp6' pflog0.tcpdump
+       ! grep fe80::${N1} pflog0.tcpdump
+
+# icmp with options
+
+REGRESS_TARGETS +=     run-icmp-pad
+run-icmp-pad: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp_pad.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp_pad.py N2
+
+REGRESS_TARGETS +=     run-icmp-eol
+run-icmp-eol: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp_eol.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp_eol.py N2
+
+REGRESS_TARGETS +=     run-icmp6-pad
+run-icmp6-pad: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_pad.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_pad.py N2
+
+REGRESS_TARGETS +=     run-icmp-ra
+run-icmp-ra: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp_ra.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp_ra.py N2
+
+REGRESS_TARGETS +=     run-icmp6-ra
+run-icmp6-ra: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_ra.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_ra.py N2
+
+REGRESS_TARGETS +=     run-icmp-bad
+run-icmp-bad: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp_bad.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp_bad.py N2
+
+REGRESS_TARGETS +=     run-icmp6-bad
+run-icmp6-bad: stamp-bpf
+       ${SUDO} ${PYPATH} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_bad.py N1
+       ${SUDO} ${PYPATH} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_bad.py N2
+
+REGRESS_TARGETS +=     run-bpf-opts
+run-bpf-opts: stamp-stop
+       # Check that icmp packet with options were blocked
+       grep ' 127.0.0.${N2}:.* optlen=4 NOP NOP NOP NOP)' pflog0.tcpdump
+       grep ' 127.0.0.${N2}:.* optlen=4 NOP EOL-2)' pflog0.tcpdump
+       grep ' 127.0.0.${N2}:.* optlen=8 NOP IPOPT-148{4} NOP ' pflog0.tcpdump
+       grep ' 127.0.0.${N2}:.* optlen=4 IPOPT-3{4})' pflog0.tcpdump
+       grep ' fe80::${N2}: HBH icmp6' pflog0.tcpdump
+       grep ' fe80::${N2}: HBH (rtalert: 0x0000) icmp6' pflog0.tcpdump
+       grep ' fe80::${N2}: HBH (type 0x03: len=0) icmp6' pflog0.tcpdump
+       ! grep '127.0.0.${N1}' pflog0.tcpdump
+       ! grep 'fe80::${N1}' pflog0.tcpdump
+
+CLEANFILES +=  addr.py *.pyc *.tcpdump *.log stamp-*
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/net/pf_opts/icmp.py b/regress/sys/net/pf_opts/icmp.py
new file mode 100644 (file)
index 0000000..6c7b087
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/local/bin/python3
+
+print("send icmp without options")
+
+import os
+import sys
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR=eval("ADDR_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IP(src=ADDR, dst=ADDR)/ \
+    ICMP(type=6, id=eid)/payload
+
+send(packet, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp6.py b/regress/sys/net/pf_opts/icmp6.py
new file mode 100644 (file)
index 0000000..13223e6
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/local/bin/python3
+
+print("send icmp6 without options")
+
+import os
+import sys
+from struct import pack
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp6.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR6=eval("ADDR6_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IPv6(src=ADDR6, dst=ADDR6)/ \
+    ICMPv6Unknown(type=6, code=0, msgbody=payload)
+
+# send does not work for some reason, add the bpf loopback layer manually
+#send(packet)
+bpf=pack('!I', 24) + bytes(packet)
+sendp(bpf, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp6_dst.py b/regress/sys/net/pf_opts/icmp6_dst.py
new file mode 100644 (file)
index 0000000..4741d45
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/local/bin/python3
+
+print("send icmp6 with destination options header")
+
+import os
+import sys
+from struct import pack
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp6_dst.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR6=eval("ADDR6_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IPv6(src=ADDR6, dst=ADDR6)/ \
+    IPv6ExtHdrDestOpt()/ \
+    ICMPv6Unknown(type=6, code=0, msgbody=payload)
+
+# send does not work for some reason, add the bpf loopback layer manually
+#send(packet)
+bpf=pack('!I', 24) + bytes(packet)
+sendp(bpf, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp6_hop.py b/regress/sys/net/pf_opts/icmp6_hop.py
new file mode 100644 (file)
index 0000000..4d3de96
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/local/bin/python3
+
+print("send icmp6 with hop by hop header")
+
+import os
+import sys
+from struct import pack
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp6_hop.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR6=eval("ADDR6_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IPv6(src=ADDR6, dst=ADDR6)/ \
+    IPv6ExtHdrHopByHop()/ \
+    ICMPv6Unknown(type=6, code=0, msgbody=payload)
+
+# send does not work for some reason, add the bpf loopback layer manually
+#send(packet)
+bpf=pack('!I', 24) + bytes(packet)
+sendp(bpf, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp6_hop_bad.py b/regress/sys/net/pf_opts/icmp6_hop_bad.py
new file mode 100644 (file)
index 0000000..173e749
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/local/bin/python3
+
+print("send icmp6 with hop by hop header with unknown option")
+
+import os
+import sys
+from struct import pack
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp6_hop_bad.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR6=eval("ADDR6_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IPv6(src=ADDR6, dst=ADDR6)/ \
+    IPv6ExtHdrHopByHop(options=HBHOptUnknown(otype=3))/ \
+    ICMPv6Unknown(type=6, code=0, msgbody=payload)
+
+# send does not work for some reason, add the bpf loopback layer manually
+#send(packet)
+bpf=pack('!I', 24) + bytes(packet)
+sendp(bpf, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp6_hop_pad.py b/regress/sys/net/pf_opts/icmp6_hop_pad.py
new file mode 100644 (file)
index 0000000..4e996ca
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/local/bin/python3
+
+print("send icmp6 with hop by hop header with padding")
+
+import os
+import sys
+from struct import pack
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp6_hop_pad.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR6=eval("ADDR6_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IPv6(src=ADDR6, dst=ADDR6)/ \
+    IPv6ExtHdrHopByHop(options=[Pad1(),PadN(optlen=2),Pad1()])/ \
+    ICMPv6Unknown(type=6, code=0, msgbody=payload)
+
+# send does not work for some reason, add the bpf loopback layer manually
+#send(packet)
+bpf=pack('!I', 24) + bytes(packet)
+sendp(bpf, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp6_hop_ra.py b/regress/sys/net/pf_opts/icmp6_hop_ra.py
new file mode 100644 (file)
index 0000000..43b03e2
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/local/bin/python3
+
+print("send icmp6 with hop by hop header with router alert")
+
+import os
+import sys
+from struct import pack
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp6_hop_ra.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR6=eval("ADDR6_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IPv6(src=ADDR6, dst=ADDR6)/ \
+    IPv6ExtHdrHopByHop(options=[Pad1(),Pad1(),RouterAlert(),PadN(optlen=6)])/ \
+    ICMPv6Unknown(type=6, code=0, msgbody=payload)
+
+# send does not work for some reason, add the bpf loopback layer manually
+#send(packet)
+bpf=pack('!I', 24) + bytes(packet)
+sendp(bpf, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp_bad.py b/regress/sys/net/pf_opts/icmp_bad.py
new file mode 100644 (file)
index 0000000..27c662c
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/local/bin/python3
+
+print("send icmp unknown option")
+
+import os
+import sys
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp_bad.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR=eval("ADDR_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IP(src=ADDR, dst=ADDR, options=b"\003\004\000\000")/ \
+    ICMP(type=6, id=eid)/payload
+
+send(packet, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp_eol.py b/regress/sys/net/pf_opts/icmp_eol.py
new file mode 100644 (file)
index 0000000..6c44e88
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/local/bin/python3
+
+print("send icmp option end of list")
+
+import os
+import sys
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp_eol.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR=eval("ADDR_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IP(src=ADDR, dst=ADDR, options=b"\001\000\001\001")/ \
+    ICMP(type=6, id=eid)/payload
+
+send(packet, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp_pad.py b/regress/sys/net/pf_opts/icmp_pad.py
new file mode 100644 (file)
index 0000000..3e4a9f6
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/local/bin/python3
+
+print("send icmp options padding")
+
+import os
+import sys
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp_pad.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR=eval("ADDR_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IP(src=ADDR, dst=ADDR, options=b"\001\001\001\001")/ \
+    ICMP(type=6, id=eid)/payload
+
+send(packet, iface=IF)
diff --git a/regress/sys/net/pf_opts/icmp_ra.py b/regress/sys/net/pf_opts/icmp_ra.py
new file mode 100644 (file)
index 0000000..4eb2979
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/local/bin/python3
+
+print("send icmp option router alert")
+
+import os
+import sys
+from addr import *
+from scapy.all import *
+
+if len(sys.argv) != 2:
+       print("usage: icmp_ra.py Nn")
+       exit(2)
+
+N=sys.argv[1]
+IF=eval("IF_"+N);
+ADDR=eval("ADDR_"+N);
+
+pid=os.getpid()
+eid=pid & 0xffff
+payload=b"ABCDEFGHIJKLMNOP"
+packet=IP(src=ADDR, dst=ADDR, options=b"\001\224\004\000\000\001\000\001")/ \
+    ICMP(type=6, id=eid)/payload
+
+send(packet, iface=IF)
diff --git a/regress/sys/net/pf_opts/pf.conf b/regress/sys/net/pf_opts/pf.conf
new file mode 100644 (file)
index 0000000..b7fbe0b
--- /dev/null
@@ -0,0 +1,2 @@
+pass on $IF_N1 allow-opts
+pass on $IF_N2