1# $OpenBSD: Makefile,v 1.7 2023/10/11 18:07:56 anton Exp $ 2 3# Copyright (c) 2022 Alexander Bluhm <bluhm@openbsd.org> 4# 5# Permission to use, copy, modify, and distribute this software for any 6# purpose with or without fee is hereby granted, provided that the above 7# copyright notice and this permission notice appear in all copies. 8# 9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17# Set up two loopback interfaces in different routing domains. 18# One loopback interface has a allow-opts pf rule, the other has 19# default pass policy. Send packets with IP options and IPv6 20# option header and check wheter tcpdump finds them on lo or pflog. 21 22# The following ports must be installed: 23# 24# scapy powerful interactive packet manipulation in python 25 26.if ! exists(/usr/local/bin/scapy) 27regress: 28 @echo Install scapy package to run this regress. 29 @echo SKIPPED 30.endif 31 32# This test uses routing domain and interface number 11 and 12. 33# Adjust it here, if you want to use something else. 34N1 = 11 35N2 = 12 36NUMS = ${N1} ${N2} 37 38.include <bsd.own.mk> 39 40.if ! (make(clean) || make(cleandir) || make(obj)) 41 42PF_STATUS != ${SUDO} /sbin/pfctl -si | sed -n 's/^Status: \([^ ]*\) .*/\1/p' 43.if empty(PF_STATUS:MEnabled) 44regress: 45 @echo pf status: "${PF_STATUS}" 46 @echo Enable pf to run this regress. 47 @echo SKIPPED 48.endif 49 50PF_SKIP != ${SUDO} /sbin/pfctl -sI -v | sed -n 's/ (skip)//p' | \ 51 grep -w -e lo${N1} -e lo${N2} || : 52.if ! empty(PF_SKIP) 53regress: 54 @echo pf skip: "${PF_SKIP}" 55 @echo Do not set skip on interface lo, lo${N1}, or lo${N2}. 56 @echo SKIPPED 57.endif 58 59PF_ANCHOR != ${SUDO} /sbin/pfctl -sr |\ 60 sed -n 's/^anchor "\([^"]*\)" all$$/\1/p' 61.if empty(PF_ANCHOR:Mregress) 62regress: 63 @echo pf anchor: "${PF_ANCHOR}" 64 @echo Need anchor '"regress"' in pf.conf to load additional rules. 65 @echo SKIPPED 66.endif 67 68.endif 69 70.PHONY: busy-rdomains ifconfig unconfig pfctl 71 72REGRESS_SETUP_ONCE += busy-rdomains 73busy-rdomains: 74 # Check if rdomains are busy. 75.for n in ${NUMS} 76 @if /sbin/ifconfig | grep -v '^lo$n:' | grep ' rdomain $n '; then\ 77 echo routing domain $n is already used >&2; exit 1; fi 78.endfor 79 80REGRESS_SETUP_ONCE += ifconfig 81ifconfig: unconfig 82 # Create and configure loopback interfaces. 83.for n in ${NUMS} 84 ${SUDO} /sbin/ifconfig lo$n rdomain $n 85 ${SUDO} /sbin/ifconfig lo$n inet 127.0.0.1/8 86 ${SUDO} /sbin/ifconfig lo$n inet 127.0.0.$n alias 87 ${SUDO} /sbin/ifconfig lo$n inet6 ::1/128 88 ${SUDO} /sbin/ifconfig lo$n inet6 fe80::$n/64 89 ${SUDO} /sbin/route -n -T $n add -inet 224.0.0.0/4 127.0.0.1 90.endfor 91 # Wait until IPv6 addresses are no longer tentative. 92 for i in `jot 50`; do\ 93 if ! { /sbin/ifconfig lo${N1}; /sbin/ifconfig lo${N2}; }\ 94 | fgrep -q tentative; then\ 95 break;\ 96 fi;\ 97 sleep .1;\ 98 done 99 ! { /sbin/ifconfig lo${N1}; /sbin/ifconfig lo${N2}; }\ 100 | fgrep tentative 101 102REGRESS_CLEANUP += unconfig 103unconfig: stamp-stop 104 # Destroy interfaces. 105.for n in ${NUMS} 106 -${SUDO} /sbin/ifconfig lo$n rdomain $n 107 -${SUDO} /sbin/ifconfig lo$n inet 127.0.0.1 delete 108 -${SUDO} /sbin/ifconfig lo$n inet 127.0.0.$n delete 109 -${SUDO} /sbin/ifconfig lo$n inet6 ::1 delete 110 -${SUDO} /sbin/ifconfig lo$n inet6 fe80::$n/64 delete 111.endfor 112 rm -f stamp-ifconfig 113 114addr.py: Makefile 115 # Create python include file containing the addresses. 116 rm -f $@ $@.tmp 117.for var in N1 N2 118 echo '${var}="${${var}}"' >>$@.tmp 119 echo 'IF_${var}="lo${${var}}"' >>$@.tmp 120 echo 'ADDR_${var}="127.0.0.${${var}}"' >>$@.tmp 121 echo 'ADDR6_${var}="fe80::${${var}}"' >>$@.tmp 122.endfor 123 mv $@.tmp $@ 124 125REGRESS_SETUP_ONCE += pfctl 126pfctl: addr.py pf.conf 127 # Load the pf rules into the kernel. 128 cat addr.py ${.CURDIR}/pf.conf | /sbin/pfctl -n -f - 129 cat addr.py ${.CURDIR}/pf.conf | ${SUDO} /sbin/pfctl -a regress -f - 130 131# run tcpdump on lo and pflog device 132DUMPCMD = /usr/sbin/tcpdump -l -e -vvv -s 2048 -ni 133 134stamp-bpf: stamp-bpf-lo${N1} stamp-bpf-lo${N2} stamp-bpf-pflog0 135 sleep 2 # XXX 136 @date >$@ 137 138.for i in lo${N1} lo${N2} pflog0 139 140stamp-bpf-$i: stamp-ifconfig 141 rm -f $i.tcpdump 142 ${SUDO} pkill -f '^${DUMPCMD} $i' || true 143 ${SUDO} ${DUMPCMD} $i >$i.tcpdump & 144 rm -f stamp-stop 145 @date >$@ 146 147.endfor 148 149stamp-stop: 150 sleep 2 # XXX 151 -${SUDO} pkill -f '^${DUMPCMD}' 152 rm -f stamp-bpf* 153 @date >$@ 154 155# Set variables so that make runs with and without obj directory. 156# Only do that if necessary to keep visible output short. 157.if ${.CURDIR} == ${.OBJDIR} 158PYTHON = python3 -u ./ 159.else 160PYTHON = env PYTHONPATH=${.OBJDIR} python3 -u ${.CURDIR}/ 161.endif 162 163# ping 164 165REGRESS_TARGETS += run-ping 166run-ping: stamp-bpf 167 # Ping localhost on loopback 168 /sbin/ping -n -w 1 -c 1 -V ${N1} 127.0.0.${N1} 169 /sbin/ping -n -w 1 -c 1 -V ${N2} 127.0.0.${N2} 170 171REGRESS_TARGETS += run-ping6 172run-ping6: stamp-bpf 173 # Ping localhost on loopback 174 /sbin/ping6 -n -w 1 -c 1 -V ${N1} fe80::${N1}%lo${N1} 175 /sbin/ping6 -n -w 1 -c 1 -V ${N2} fe80::${N2}%lo${N2} 176 177REGRESS_TARGETS += run-bpf-ping 178run-bpf-ping: stamp-stop 179 # Check that ping packet went through loopback. 180 grep ' 127.0.0.${N1}: icmp: echo request' lo${N1}.tcpdump 181 grep ' 127.0.0.${N2}: icmp: echo request' lo${N2}.tcpdump 182 grep ' fe80:.*::${N1}: icmp6: echo request' lo${N1}.tcpdump 183 grep ' fe80:.*::${N2}: icmp6: echo request' lo${N2}.tcpdump 184 ! grep ': icmp: echo request' pflog0.tcpdump 185 ! grep ': icmp6: echo request' pflog0.tcpdump 186 187# ping with RR option 188 189REGRESS_TARGETS += run-ping-record 190run-ping-record: stamp-bpf 191 # Ping localhost with record route option 192 /sbin/ping -n -w 1 -c 1 -V ${N1} -R 127.0.0.${N1} 193 ! /sbin/ping -n -w 1 -c 1 -V ${N2} -R 127.0.0.${N2} 194 195REGRESS_TARGETS += run-bpf-ping-record 196run-bpf-ping-record: stamp-stop 197 # Check that ping packet with options is in pflog0. 198 grep ' 127.0.0.${N1}: icmp: echo request .*\ 199 optlen=40 RR' lo${N1}.tcpdump 200 grep ' 127.0.0.${N2}: icmp: echo request .*\ 201 optlen=40 RR' pflog0.tcpdump 202 203# icmp 204 205REGRESS_TARGETS += run-icmp 206run-icmp: stamp-bpf 207 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp.py N1 208 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp.py N2 209 210REGRESS_TARGETS += run-icmp6 211run-icmp6: stamp-bpf 212 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6.py N1 213 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6.py N2 214 215REGRESS_TARGETS += run-bpf-icmp 216run-bpf-icmp: stamp-stop 217 # Check that icmp packet went through loopback. 218 grep ' 127.0.0.${N1}: icmp: type-#6' lo${N1}.tcpdump 219 grep ' 127.0.0.${N2}: icmp: type-#6' lo${N2}.tcpdump 220 grep ' fe80::${N1}: icmp6: type-#6' lo${N1}.tcpdump 221 grep ' fe80::${N2}: icmp6: type-#6' lo${N2}.tcpdump 222 ! grep ': icmp: type-#6' pflog0.tcpdump 223 ! grep ': icmp6: type-#6' pflog0.tcpdump 224 225# option extension header 226 227REGRESS_TARGETS += run-icmp6-hop 228run-icmp6-hop: stamp-bpf 229 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop.py N1 230 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop.py N2 231 232REGRESS_TARGETS += run-icmp6-dst 233run-icmp6-dst: stamp-bpf 234 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_dst.py N1 235 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_dst.py N2 236 237REGRESS_TARGETS += run-bpf-ext 238run-bpf-ext: stamp-stop 239 # Check that icmp6 packet with extension headers were blocked 240 fgrep ' fe80::${N2}: HBH icmp6:' pflog0.tcpdump 241 fgrep ' fe80::${N2}: DSTOPT icmp6:' pflog0.tcpdump 242 ! grep fe80::${N1} pflog0.tcpdump 243 244# icmp with options 245 246REGRESS_TARGETS += run-icmp-pad 247run-icmp-pad: stamp-bpf 248 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp_pad.py N1 249 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp_pad.py N2 250 251REGRESS_TARGETS += run-icmp-eol 252run-icmp-eol: stamp-bpf 253 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp_eol.py N1 254 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp_eol.py N2 255 256REGRESS_TARGETS += run-icmp6-pad 257run-icmp6-pad: stamp-bpf 258 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_pad.py N1 259 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_pad.py N2 260 261REGRESS_TARGETS += run-icmp-max 262run-icmp-max: stamp-bpf 263 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp_max.py N1 264 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp_max.py N2 265 266REGRESS_TARGETS += run-icmp6-max 267run-icmp6-max: stamp-bpf 268 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_max.py N1 269 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_max.py N2 270 271REGRESS_TARGETS += run-icmp-ra 272run-icmp-ra: stamp-bpf 273 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp_ra.py N1 274 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp_ra.py N2 275 276REGRESS_TARGETS += run-icmp6-ra 277run-icmp6-ra: stamp-bpf 278 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_ra.py N1 279 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_ra.py N2 280 281REGRESS_TARGETS += run-icmp-bad 282run-icmp-bad: stamp-bpf 283 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp_bad.py N1 284 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp_bad.py N2 285 286REGRESS_TARGETS += run-icmp6-bad 287run-icmp6-bad: stamp-bpf 288 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_hop_bad.py N1 289 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_hop_bad.py N2 290 291REGRESS_TARGETS += run-bpf-opts 292run-bpf-opts: stamp-stop 293 # Check that icmp packet with options were blocked 294 grep ' 127.0.0.${N2}:.* optlen=4 NOP NOP NOP NOP)' pflog0.tcpdump 295 grep ' 127.0.0.${N2}:.* optlen=4 NOP EOL-2)' pflog0.tcpdump 296 grep ' 127.0.0.${N2}:.* optlen=40 NOP ' pflog0.tcpdump 297 grep ' 127.0.0.${N2}:.* optlen=8 NOP IPOPT-148{4} NOP ' pflog0.tcpdump 298 grep ' 127.0.0.${N2}:.* optlen=4 IPOPT-3{4})' pflog0.tcpdump 299 grep ' fe80::${N2}: HBH icmp6:.* (len 28,' pflog0.tcpdump 300 grep ' fe80::${N2}: HBH icmp6:.* (len 284,' pflog0.tcpdump 301 grep ' fe80::${N2}: HBH (rtalert: 0x0000) icmp6:' pflog0.tcpdump 302 grep ' fe80::${N2}: HBH (type 0x03: len=0) icmp6:' pflog0.tcpdump 303 ! grep '127.0.0.${N1}' pflog0.tcpdump 304 ! grep 'fe80::${N1}' pflog0.tcpdump 305 306# multicast with router alert 307 308REGRESS_TARGETS += run-igmp 309run-igmp: stamp-bpf 310 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}igmp_ra.py N1 311 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}igmp_ra.py N2 312 313REGRESS_TARGETS += run-icmp6-mld 314run-icmp6-mld: stamp-bpf 315 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_mld_ra.py N1 316 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_mld_ra.py N2 317 318REGRESS_TARGETS += run-bpf-mcast 319run-bpf-mcast: stamp-stop 320 # Check that multicast protocol packet with router alert passed 321 grep '127.0.0.${N2} > 224.0.0.1:\ 322 igmp query .* IPOPT-148{4}' lo${N2}.tcpdump 323 grep 'fe80::${N2} > ff02::1:\ 324 HBH (rtalert:.* icmp6: multicast ' lo${N2}.tcpdump 325 ! grep '127.0.0.${N1}' pflog0.tcpdump 326 ! grep 'fe80::${N1}' pflog0.tcpdump 327 ! grep '127.0.0.${N2}' pflog0.tcpdump 328 ! grep 'fe80::${N2}' pflog0.tcpdump 329 ! grep '224.0.0.1' pflog0.tcpdump 330 ! grep 'ff02::1' pflog0.tcpdump 331 332REGRESS_TARGETS += run-igmp-bad 333run-igmp-bad: stamp-bpf 334 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}igmp_bad.py N1 335 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}igmp_bad.py N2 336 337REGRESS_TARGETS += run-icmp6-mld-bad 338run-icmp6-mld-bad: stamp-bpf 339 ${SUDO} /sbin/route -T ${N1} exec ${PYTHON}icmp6_mld_bad.py N1 340 ${SUDO} /sbin/route -T ${N2} exec ${PYTHON}icmp6_mld_bad.py N2 341 342REGRESS_TARGETS += run-bpf-mcast-bad 343run-bpf-mcast-bad: stamp-stop 344 # Check that multicast protocol packet with options were blocked 345 grep '127.0.0.${N2} > 224.0.0.1:\ 346 igmp query .* IPOPT-3{4}' pflog0.tcpdump 347 grep 'fe80::${N2} > ff02::1:\ 348 HBH (type 0x03:.* icmp6: multicast ' pflog0.tcpdump 349 ! grep '127.0.0.${N1}' pflog0.tcpdump 350 ! grep 'fe80::${N1}' pflog0.tcpdump 351 352CLEANFILES += addr.py *.pyc *.tcpdump *.log stamp-* 353 354.include <bsd.regress.mk> 355