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