1# $OpenBSD: Makefile,v 1.30 2021/02/01 12:52:07 bluhm Exp $ 2 3# Copyright (c) 2011-2021 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# The following ports must be installed: 18# 19# scapy powerful interactive packet manipulation in python 20 21.if ! exists(/usr/local/bin/scapy) 22regress: 23 @echo Install scapy package to run this regress. 24 @echo SKIPPED 25.endif 26 27# This test needs a manual setup of four machines 28# The setup is the same as for regress/sys/net/pf_forward 29# Set up machines: SRC PF RT ECO 30# SRC is the machine where this makefile is running. 31# PF is running OpenBSD forwarding through pf, it is the test target. 32# RT is a router forwarding packets, maximum MTU is 1300. 33# ECO is reflecting the ping and UDP echo packets. 34# RDR does not exist, PF redirects the traffic to ECO. 35# RTT addresses exist on ECO, PF has no route and must use route-to RT 36# 37# +---+ 0 +--+ 1 +--+ 2 +---+ 7 4 +---+ 7 +---+ 38# |SRC| ----> |PF| ----> |RT| ----> |ECO| |RDR| |RTT| 39# +---+ +--+ +--+ +---+ +---+ +---+ 40# out in out in out in rtt in in 41 42# Configure Addresses on the machines, there must be routes for the 43# networks. Adapt interface and address variables to your local 44# setup. To control the remote machine you need a hostname for 45# ssh to log in. 46# You must have an anchor "regress" for the divert rules in the pf.conf 47# of the PF machine. The kernel of the PF machine gets tested. 48# 49# Run make check-setup to see if you got the setup correct. 50 51SRC_IF ?= tap0 52SRC_MAC ?= fe:e1:ba:d1:0a:dc 53PF_IFIN ?= vio0 54PF_IFOUT ?= vio1 55PF_MAC ?= 52:54:00:12:34:50 56PF_SSH ?= 57RT_SSH ?= 58ECO_SSH ?= 59 60SRC_OUT ?= 10.188.210.10 61PF_IN ?= 10.188.210.50 62PF_OUT ?= 10.188.211.50 63RT_IN ?= 10.188.211.51 64RT_OUT ?= 10.188.212.51 65ECO_IN ?= 10.188.212.52 66RDR_IN ?= 10.188.214.188 67RTT_IN ?= 10.188.217.52 68 69SRC_OUT6 ?= fdd7:e83e:66bc:210:fce1:baff:fed1:561f 70PF_IN6 ?= fdd7:e83e:66bc:210:5054:ff:fe12:3450 71PF_OUT6 ?= fdd7:e83e:66bc:211:5054:ff:fe12:3450 72RT_IN6 ?= fdd7:e83e:66bc:211:5054:ff:fe12:3451 73RT_OUT6 ?= fdd7:e83e:66bc:212:5054:ff:fe12:3451 74ECO_IN6 ?= fdd7:e83e:66bc:212:5054:ff:fe12:3452 75RDR_IN6 ?= fdd7:e83e:66bc:214::188 76RTT_IN6 ?= fdd7:e83e:66bc:217:5054:ff:fe12:3452 77 78.if empty (PF_SSH) || empty (RT_SSH) || empty (ECO_SSH) 79regress: 80 @echo this test needs three remote machines to operate on 81 @echo PF_SSH RT_SSH ECO_SSH are empty 82 @echo fill out these variables for additional tests, then 83 @echo check whether your test machines are set up properly 84 @echo SKIPPED 85.endif 86 87.MAIN: all 88 89.if ! empty (PF_SSH) 90.if make (regress) || make (all) 91.BEGIN: 92 ${SUDO} true 93 ssh -t ${PF_SSH} ${SUDO} true 94 rm -f stamp-pfctl 95 @echo 96.endif 97.endif 98 99# Create python include file containing the addresses. 100addr.py: Makefile 101 rm -f $@ $@.tmp 102 echo 'SRC_IF="${SRC_IF}"' >>$@.tmp 103 echo 'SRC_MAC="${SRC_MAC}"' >>$@.tmp 104 echo 'PF_IFIN="${PF_IFIN}"' >>$@.tmp 105 echo 'PF_IFOUT="${PF_IFOUT}"' >>$@.tmp 106 echo 'PF_MAC="${PF_MAC}"' >>$@.tmp 107.for var in SRC_OUT PF_IN PF_OUT RT_IN RT_OUT ECO_IN RDR_IN RTT_IN 108 echo '${var}="${${var}}"' >>$@.tmp 109 echo '${var}6="${${var}6}"' >>$@.tmp 110.endfor 111 mv $@.tmp $@ 112 113# load the pf rules into the kernel of the PF machine 114# XXX pfctl does not replace variables after @ 115REGRESS_SETUP += stamp-pfctl 116stamp-pfctl: addr.py pf.conf 117 cat addr.py ${.CURDIR}/pf.conf | /sbin/pfctl -n -f - 118 cat addr.py ${.CURDIR}/pf.conf | \ 119 sed 's/@$$PF_IFIN /@${PF_IFIN} /;s/@$$PF_IFOUT /@${PF_IFOUT} /' | \ 120 ssh ${PF_SSH} ${SUDO} pfctl -a regress -f - 121 @date >$@ 122 123# Set variables so that make runs with and without obj directory. 124# Only do that if necessary to keep visible output short. 125.if ${.CURDIR} == ${.OBJDIR} 126PYTHON = python3 -u ./ 127.else 128PYTHON = PYTHONPATH=${.OBJDIR} python3 -u ${.CURDIR}/ 129.endif 130 131# Ping all addresses. This ensures that the IP addresses are configured 132# and all routing table are set up to allow bidirectional packet flow. 133# Note that RDR does not exist physically. So this traffic is rewritten 134# by PF and handled by ECO. 135 136REGRESS_TARGETS += run-ping 137run-ping: 138.for ip in SRC_OUT PF_IN PF_OUT RT_IN RT_OUT ECO_IN RDR_IN RTT_IN 139 @echo Check ping ${ip}: 140 ping -n -c 1 ${${ip}} 141.endfor 142 143REGRESS_TARGETS += run-ping6 144run-ping6: 145.for ip in SRC_OUT PF_IN PF_OUT RT_IN RT_OUT ECO_IN RDR_IN RTT_IN 146 @echo Check ping ${ip}6: 147 ping6 -n -c 1 ${${ip}6} 148.endfor 149 150# Ping all addresses again but with 5000 bytes payload. These large 151# packets get fragmented by SRC and must be handled by PF. 152# Send 1 packet in advance for Path-MTU discovery. 153 154REGRESS_TARGETS += run-fragping 155run-fragping: 156.for ip in PF_IN PF_OUT RT_IN RT_OUT ECO_IN RDR_IN RTT_IN 157 @echo Check ping ${ip}: 158 ping -n -c 1 -s 5000 ${${ip}} 159.endfor 160 161REGRESS_TARGETS += run-fragping6 162run-fragping6: 163.for ip in PF_IN PF_OUT RT_IN RT_OUT 164 @echo Check ping ${ip}6: 165 ${SUDO} route -n delete -host -inet6 ${${ip}6} || true 166 ping6 -n -c 1 -s 1452 -m ${${ip}6} & sleep 1; kill $$! || true 167 ping6 -n -c 1 -s 5000 -m ${${ip}6} 168.endfor 169.for ip in ECO_IN RDR_IN RTT_IN 170 @echo Check ping ${ip}6: 171 ${SUDO} route -n delete -host -inet6 ${${ip}6} || true 172 ping6 -n -c 1 -s 1352 -m ${${ip}6} & sleep 1; kill $$! || true 173 ping6 -n -c 1 -s 5000 -m ${${ip}6} 174.endfor 175 176# Send a large IPv4/ICMP-Echo-Request packet with enabled DF bit and 177# parse response packet to determine MTU of the router. The MTU has 178# to be 1300 octets. The MTU has to be defined at out interface of 179# the router RT before. 180 181REGRESS_TARGETS += run-ping-mtu 182run-ping-mtu: addr.py 183.for ip in ECO_IN RDR_IN RTT_IN 184 @echo Check path MTU to ${ip} 185 ${SUDO} ${PYTHON}ping_mtu_1300.py ${${ip}} 186.endfor 187 188REGRESS_TARGETS += run-ping6-mtu 189run-ping6-mtu: addr.py 190.for ip in ECO_IN RDR_IN RTT_IN 191 @echo Check path MTU to ${ip}6 192 ${SUDO} ${PYTHON}ping6_mtu_1300.py ${${ip}6} 193.endfor 194 195# Send packet too big to get to destination. 196# Check that checksum of the quoted original packet in ICMP is correct. 197 198# Currently these test fail as pf does not fix the checksum of 199# NATed packets inside of ICMP packets. 200# XXX REGRESS_TARGETS += run-ping-cksum ping6-cksum run-udp-cksum udp6-cksum 201 202run-ping-cksum: addr.py 203.for ip in ECO_IN RDR_IN RTT_IN 204 @echo Check ICMP chksum in fragmentation needed to ${ip} 205 ${SUDO} ${PYTHON}ping_cksum.py ${${ip}} 206.endfor 207 208run-ping6-cksum: addr.py 209.for ip in ECO_IN RDR_IN RTT_IN 210 @echo Check ICMP6 chksum in packet too big to ${ip}6 211 ${SUDO} ${PYTHON}ping6_cksum.py ${${ip}6} 212.endfor 213 214run-udp-cksum: addr.py 215.for ip in ECO_IN RDR_IN RTT_IN 216 @echo Check UDP chksum in packet too big to ${ip} 217 ${SUDO} ${PYTHON}udp_cksum.py ${${ip}} 218.endfor 219 220run-udp6-cksum: addr.py 221.for ip in ECO_IN RDR_IN RTT_IN 222 @echo Check UDP6 chksum in packet too big to ${ip}6 223 ${SUDO} ${PYTHON}udp6_cksum.py ${${ip}6} 224.endfor 225 226# Send handcrafted fragmented packets with overlaps 227 228REGRESS_TARGETS += run-frag6 229run-frag: addr.py 230.for ip in ECO_IN RDR_IN RTT_IN 231 @echo Check ping reassembly ${ip} 232 ${SUDO} ${PYTHON}frag.py ${${ip}} 233.endfor 234 235REGRESS_TARGETS += run-frag 236run-frag6: addr.py 237.for ip in ECO_IN RDR_IN RTT_IN 238 @echo Check ping6 reassembly ${ip}6 239 ${SUDO} ${PYTHON}frag6.py ${${ip}6} 240.endfor 241 242REGRESS_TARGETS += run-frag6-ext 243run-frag6-ext: addr.py 244.for ip in ECO_IN RDR_IN RTT_IN 245 @echo Check ping6 extension header reassembly ${ip}6 246 ${SUDO} ${PYTHON}frag6_ext.py ${${ip}6} 247.endfor 248 249REGRESS_TARGETS += run-frag-cutnew 250run-frag-cutnew: addr.py 251.for ip in ECO_IN RDR_IN RTT_IN 252 @echo Check ping head overlap reassembly ${ip} 253 ${SUDO} ${PYTHON}frag_cutnew.py ${${ip}} 254.endfor 255 256REGRESS_TARGETS += run-frag6-cutnew 257run-frag6-cutnew: addr.py 258.for ip in ECO_IN RDR_IN RTT_IN 259 @echo Check ping6 head overlap reassembly ${ip}6 260 ${SUDO} ${PYTHON}frag6_cutnew.py ${${ip}6} 261.endfor 262 263REGRESS_TARGETS += run-frag-cutold 264run-frag-cutold: addr.py 265.for ip in ECO_IN RDR_IN RTT_IN 266 @echo Check ping tail overlap reassembly ${ip} 267 ${SUDO} ${PYTHON}frag_cutold.py ${${ip}} 268.endfor 269 270REGRESS_TARGETS += run-frag6-cutold 271run-frag6-cutold: addr.py 272.for ip in ECO_IN RDR_IN RTT_IN 273 @echo Check ping6 tail overlap reassembly ${ip}6 274 ${SUDO} ${PYTHON}frag6_cutold.py ${${ip}6} 275.endfor 276 277REGRESS_TARGETS += run-frag-dropold 278run-frag-dropold: addr.py 279.for ip in ECO_IN RDR_IN RTT_IN 280 @echo Check ping total overlapping reassembly ${ip} 281 ${SUDO} ${PYTHON}frag_dropold.py ${${ip}} 282.endfor 283 284REGRESS_TARGETS += run-frag6-dropold 285run-frag6-dropold: addr.py 286.for ip in ECO_IN RDR_IN RTT_IN 287 @echo Check ping6 total overlapping reassembly ${ip}6 288 ${SUDO} ${PYTHON}frag6_dropold.py ${${ip}6} 289.endfor 290 291REGRESS_TARGETS += run-frag-dropnew 292run-frag-dropnew: addr.py 293.for ip in ECO_IN RDR_IN RTT_IN 294 @echo Check ping total overlaped reassembly ${ip} 295 ${SUDO} ${PYTHON}frag_dropnew.py ${${ip}} 296.endfor 297 298REGRESS_TARGETS += run-frag6-dropnew 299run-frag6-dropnew: addr.py 300.for ip in ECO_IN RDR_IN RTT_IN 301 @echo Check ping6 total overlaped reassembly ${ip}6 302 ${SUDO} ${PYTHON}frag6_dropnew.py ${${ip}6} 303.endfor 304 305CLEANFILES += addr.py *.pyc *.log stamp-* 306 307.PHONY: check-setup 308 309# Check whether the address, route and remote setup are correct 310check-setup: check-setup-src check-setup-pf check-setup-rt check-setup-eco 311 312check-setup-src: 313 @echo '\n======== $@ ========' 314.for ip in SRC_OUT 315 ping -n -c 1 ${${ip}} # ${ip} 316 route -n get -inet ${${ip}} | grep -q 'flags: .*LOCAL' # ${ip} 317.endfor 318 ping -n -c 1 ${PF_IN} # PF_IN 319 route -n get -inet ${PF_IN} | fgrep -q 'interface: ${SRC_IF}' # PF_IN SRC_IF 320.for ip in PF_OUT RT_IN RT_OUT ECO_IN RDR_IN RTT_IN 321 route -n get -inet ${${ip}} | fgrep -q 'gateway: ${PF_IN}' # ${ip} PF_IN 322.endfor 323.for ip in SRC_OUT 324 ping6 -n -c 1 ${${ip}6} # ${ip}6 325 route -n get -inet6 ${${ip}6} | grep -q 'flags: .*LOCAL' # ${ip}6 326.endfor 327 ping6 -n -c 1 ${PF_IN6} # PF_IN6 328 route -n get -inet6 ${PF_IN6} | fgrep -q 'interface: ${SRC_IF}' # PF_IN6 SRC_IF 329.for ip in PF_OUT RT_IN RT_OUT ECO_IN RDR_IN RTT_IN 330 route -n get -inet6 ${${ip}6} | fgrep -q 'gateway: ${PF_IN6}' # ${ip}6 PF_IN6 331.endfor 332 333check-setup-pf: 334 @echo '\n======== $@ ========' 335 ssh ${PF_SSH} ping -n -c 1 ${PF_IN} # PF_IN 336 ssh ${PF_SSH} route -n get -inet ${PF_IN} | grep -q 'flags: .*LOCAL' # PF_IN 337 ssh ${PF_SSH} ping -n -c 1 ${SRC_OUT} # SRC_OUT 338 ssh ${PF_SSH} ping -n -c 1 ${PF_OUT} # PF_OUT 339 ssh ${PF_SSH} route -n get -inet ${PF_OUT} | grep -q 'flags: .*LOCAL' # PF_OUT 340 ssh ${PF_SSH} ping -n -c 1 ${RT_IN} # RT_IN 341.for ip in RT_OUT ECO_IN 342 ssh ${PF_SSH} route -n get -inet ${${ip}} | fgrep -q 'gateway: ${RT_IN}' # ${ip} RT_IN 343.endfor 344.for ip in RTT_IN 345 ssh ${PF_SSH} route -n get -inet ${${ip}} | grep -q 'flags: .*REJECT' # ${ip} reject 346.endfor 347 ssh ${PF_SSH} ping6 -n -c 1 ${PF_IN6} # PF_IN6 348 ssh ${PF_SSH} route -n get -inet6 ${PF_IN6} | grep -q 'flags: .*LOCAL' # PF_IN6 349 ssh ${PF_SSH} ping6 -n -c 1 ${SRC_OUT6} # SRC_OUT6 350 ssh ${PF_SSH} ping6 -n -c 1 ${PF_OUT6} # PF_OUT6 351 ssh ${PF_SSH} route -n get -inet6 ${PF_OUT6} | grep -q 'flags: .*LOCAL' # PF_OUT6 352 ssh ${PF_SSH} ping6 -n -c 1 ${RT_IN6} # RT_IN6 353.for ip in RT_OUT ECO_IN 354 ssh ${PF_SSH} route -n get -inet6 ${${ip}6} | fgrep -q 'gateway: ${RT_IN6}' # ${ip}6 RT_IN6 355.endfor 356.for ip in RTT_IN 357 ssh ${PF_SSH} route -n get -inet6 ${${ip}6} | grep -q 'flags: .*REJECT' # ${ip}6 reject 358.endfor 359 ssh ${PF_SSH} ${SUDO} pfctl -sr | grep '^anchor "regress" all$$' 360 ssh ${PF_SSH} ${SUDO} pfctl -si | grep '^Status: Enabled ' 361 ssh ${PF_SSH} sysctl net.inet.ip.forwarding | fgrep =1 362 ssh ${PF_SSH} sysctl net.inet6.ip6.forwarding | fgrep =1 363 364check-setup-rt: 365 @echo '\n======== $@ ========' 366 ssh ${RT_SSH} ping -n -c 1 ${RT_IN} # RT_IN 367 ssh ${RT_SSH} route -n get -inet ${RT_IN} | grep -q 'flags: .*LOCAL' # RT_IN 368 ssh ${RT_SSH} ping -n -c 1 ${PF_OUT} # PF_OUT 369.for ip in PF_IN SRC_OUT 370 ssh ${RT_SSH} route -n get -inet ${${ip}} | fgrep -q 'gateway: ${PF_OUT}' # ${ip} PF_OUT 371.endfor 372 ssh ${RT_SSH} ping -n -c 1 ${RT_OUT} # RT_OUT 373 ssh ${RT_SSH} route -n get -inet ${RT_OUT} | grep -q 'flags: .*LOCAL' # RT_OUT 374 ssh ${RT_SSH} ping -n -c 1 ${ECO_IN} # ECO_IN 375.for ip in RTT_IN 376 ssh ${RT_SSH} route -n get -inet ${${ip}} | fgrep -q 'gateway: ${ECO_IN}' # ${ip} ECO_IN 377.endfor 378 ssh ${RT_SSH} ping6 -n -c 1 ${RT_IN6} # RT_IN6 379 ssh ${RT_SSH} route -n get -inet6 ${RT_IN6} | grep -q 'flags: .*LOCAL' # RT_IN6 380 ssh ${RT_SSH} ping6 -n -c 1 ${PF_OUT6} # PF_OUT6 381.for ip in PF_IN SRC_OUT 382 ssh ${RT_SSH} route -n get -inet6 ${${ip}6} | fgrep -q 'gateway: ${PF_OUT6}' # ${ip}6 PF_OUT6 383.endfor 384 ssh ${RT_SSH} ping6 -n -c 1 ${RT_OUT6} # RT_OUT6 385 ssh ${RT_SSH} route -n get -inet6 ${RT_OUT6} | grep -q 'flags: .*LOCAL' # RT_OUT6 386 ssh ${RT_SSH} ping6 -n -c 1 ${ECO_IN6} # ECO_IN6 387.for ip in RTT_IN 388 ssh ${RT_SSH} route -n get -inet6 ${${ip}6} | fgrep -q 'gateway: ${ECO_IN6}' # ${ip}6 ECO_IN6 389.endfor 390 ssh ${RT_SSH} sysctl net.inet.ip.forwarding | fgrep =1 391 ssh ${RT_SSH} sysctl net.inet6.ip6.forwarding | fgrep =1 392 ssh ${RT_SSH} ifconfig | fgrep 'mtu 1300' 393 394check-setup-eco: 395 @echo '\n======== $@ ========' 396.for ip in ECO_IN RTT_IN 397 ssh ${ECO_SSH} ping -n -c 1 ${${ip}} # ${ip} 398 ssh ${ECO_SSH} route -n get -inet ${${ip}} | grep -q 'flags: .*LOCAL' # ${ip} 399.endfor 400 ssh ${ECO_SSH} ping -n -c 1 ${RT_OUT} # RT_OUT 401.for ip in RT_IN PF_OUT PF_IN SRC_OUT 402 ssh ${ECO_SSH} route -n get -inet ${${ip}} | fgrep -q 'gateway: ${RT_OUT}' # ${ip} RT_OUT 403.endfor 404.for ip in ECO_IN RTT_IN 405 ssh ${ECO_SSH} ping6 -n -c 1 ${${ip}6} # ${ip}6 406 ssh ${ECO_SSH} route -n get -inet6 ${${ip}6} | grep -q 'flags: .*LOCAL' # ${ip}6 407.endfor 408 ssh ${ECO_SSH} ping6 -n -c 1 ${RT_OUT6} # RT_OUT6 409.for ip in RT_IN PF_OUT PF_IN SRC_OUT 410 ssh ${ECO_SSH} route -n get -inet6 ${${ip}6} | fgrep -q 'gateway: ${RT_OUT6}' # ${ip}6 RT_OUT6 411 ssh ${ECO_SSH} sysctl net.inet.ip.forwarding | fgrep =1 412 ssh ${ECO_SSH} sysctl net.inet6.ip6.forwarding | fgrep =1 413.endfor 414 415.include <bsd.regress.mk> 416