xref: /openbsd/regress/sys/net/pf_opts/Makefile (revision 4be5cdd0)
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