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