xref: /openbsd/regress/sys/net/pf_fragment/Makefile (revision 8199ec72)
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