xref: /openbsd/regress/sys/net/pf_divert/Makefile (revision 1073f88e)
1#	$OpenBSD: Makefile,v 1.24 2021/12/12 21:16:53 bluhm Exp $
2
3# The following ports must be installed for the regression tests:
4# p5-Socket6		Perl defines relating to AF_INET6 sockets
5#
6# Check wether all required perl packages are installed.  If some
7# are missing print a warning and skip the tests, but do not fail.
8
9PERL_REQUIRE !=	perl -Mstrict -Mwarnings -e ' \
10    eval { require Socket6 } or print $@; \
11'
12.if ! empty(PERL_REQUIRE)
13regress:
14	@echo "${PERL_REQUIRE}"
15	@echo install these perl packages for additional tests
16	@echo SKIPPED
17.endif
18
19# Fill out these variables as you have to test divert with the pf
20# kernel running on a remote machine.  You have to specify a local
21# and remote ip address for the test connections.  The fake ip address
22# will be routed via the remote address to test divert with non-existing
23# addresses.  To control the remote machine you need a hostname for
24# ssh to log in.  All the test files must be in the same directory
25# local and remote.
26# You must have an anchor "regress" for the divert rules in the pf.conf
27# of the remote machine.  The kernel of the remote machine gets testet.
28#
29# Run make check-setup to see if you got the setup correct.
30
31LOCAL_ADDR ?=
32REMOTE_ADDR ?=
33FAKE_ADDR ?=
34LOCAL_ADDR6 ?=
35REMOTE_ADDR6 ?=
36FAKE_ADDR6 ?=
37REMOTE_SSH ?=
38
39.if empty (LOCAL_ADDR) || empty (REMOTE_ADDR) || empty (FAKE_ADDR) || \
40    empty (LOCAL_ADDR6) || empty (REMOTE_ADDR6) || empty (FAKE_ADDR6) || \
41    empty (REMOTE_SSH)
42regress:
43	@echo This tests needs a remote machine to operate on.
44	@echo LOCAL_ADDR REMOTE_ADDR FAKE_ADDR LOCAL_ADDR6
45	@echo REMOTE_ADDR6 FAKE_ADDR6 REMOTE_SSH are empty.
46	@echo Fill out these variables for additional tests.
47	@echo SKIPPED
48.endif
49
50# Automatically generate regress targets from test cases in directory.
51
52PERLS =			Client.pm Packet.pm Proc.pm Remote.pm Server.pm \
53			funcs.pl remote.pl
54ARGS !=			cd ${.CURDIR} && ls args-*.pl
55TARGETS ?=		\
56	inet-args-tcp-to inet6-args-tcp-to \
57	inet-args-tcp-reply inet6-args-tcp-reply \
58	inet-args-udp-to inet6-args-udp-to \
59	inet-args-udp-reply inet6-args-udp-reply \
60	inet-args-udp-reply-to inet6-args-udp-reply-to \
61	inet-args-rip-to inet6-args-rip-to \
62	inet-args-rip-reply inet6-args-rip-reply \
63	inet-args-rip-reply-to inet6-args-rip-reply-to \
64	inet-args-icmp-to inet6-args-icmp-to \
65	inet-args-icmp-reply-to inet6-args-icmp-reply-to \
66	inet-args-icmp-reply-reuse inet6-args-icmp-reply-reuse \
67	inet-reuse-tcp-to-to inet6-reuse-tcp-to-to \
68	inet-reuse-tcp-to-reply inet6-reuse-tcp-to-reply \
69	inet-reuse-tcp-reply-to inet6-reuse-tcp-reply-to \
70	inet-reuse-tcp-reply-reply inet6-reuse-tcp-reply-reply \
71	inet-reuse-udp-to-to inet6-reuse-udp-to-to \
72	inet-reuse-udp-to-reply inet6-reuse-udp-to-reply \
73	inet-reuse-udp-to-reply-to inet6-reuse-udp-to-reply-to \
74	inet-reuse-udp-reply-to inet6-reuse-udp-reply-to \
75	inet-reuse-udp-reply-reply inet6-reuse-udp-reply-reply \
76	inet-reuse-udp-reply-reply-to inet6-reuse-udp-reply-reply-to \
77	inet-reuse-udp-reply-to-to inet6-reuse-udp-reply-to-to \
78	inet-reuse-udp-reply-to-reply inet6-reuse-udp-reply-to-reply \
79	inet-reuse-udp-reply-to-reply-to inet6-reuse-udp-reply-to-reply-to \
80	inet-reuse-rip-to-to inet6-reuse-rip-to-to \
81	inet-reuse-rip-to-reply inet6-reuse-rip-to-reply \
82	inet-reuse-rip-to-reply-to inet6-reuse-rip-to-reply-to \
83	inet-reuse-rip-reply-to inet6-reuse-rip-reply-to \
84	inet-reuse-rip-reply-reply inet6-reuse-rip-reply-reply \
85	inet-reuse-rip-reply-reply-to inet6-reuse-rip-reply-reply-to \
86	inet-reuse-rip-reply-to-to inet6-reuse-rip-reply-to-to \
87	inet-reuse-rip-reply-to-reply inet6-reuse-rip-reply-to-reply \
88	inet-reuse-rip-reply-to-reply-to inet6-reuse-rip-reply-to-reply-to \
89	inet-args-udp-packet-in inet6-args-udp-packet-in \
90	inet-args-udp-packet-out inet6-args-udp-packet-out
91REGRESS_TARGETS =	${TARGETS:S/^/run-/}
92CLEANFILES +=		*.log *.port *.ktrace ktrace.out stamp-*
93
94.MAIN: all
95
96.if ! empty (REMOTE_SSH)
97.if make (regress) || make (all)
98.BEGIN:
99	@echo
100	${SUDO} true
101	ssh -t ${REMOTE_SSH} ${SUDO} true
102.if ! empty (FAKE_ADDR) && ! empty (REMOTE_ADDR)
103	-${SUDO} route -n delete -inet -host ${FAKE_ADDR} 2>/dev/null
104	${SUDO} route -n add -inet -host ${FAKE_ADDR} ${REMOTE_ADDR}
105.endif
106.if ! empty (FAKE_ADDR6) && ! empty (REMOTE_ADDR6)
107	-${SUDO} route -n delete -inet6 -host ${FAKE_ADDR6} 2>/dev/null
108	${SUDO} route -n add -inet6 -host ${FAKE_ADDR6} ${REMOTE_ADDR6}
109.endif
110.endif
111.endif
112
113# Set variables so that make runs with and without obj directory.
114# Only do that if necessary to keep visible output short.
115
116.if ${.CURDIR} == ${.OBJDIR}
117PERLINC =	-I.
118PERLPATH =
119.else
120PERLINC =	-I${.CURDIR}
121PERLPATH =	${.CURDIR}/
122.endif
123
124# The arg tests take a perl hash with arguments controlling the test
125# parameters.  The remote.pl test has local client or server and the
126# diverted process is running on the remote machine reachable with
127# ssh.
128
129.for  inet addr  in  inet ADDR  inet6 ADDR6
130
131run-${inet}-reuse-rip-to-reply-to:
132	@echo 'rip to before reply is broken, it does not remove the state.'
133	@echo DISABLED
134
135.for a in ${ARGS}
136run-${inet}-${a:R}: ${a}
137.if ${@:M*-packet-*}
138	time ${SUDO} SUDO=${SUDO} KTRACE=${KTRACE} \
139	    perl ${PERLINC} ${PERLPATH}remote.pl -f ${inet} \
140	    ${LOCAL_${addr}} ${REMOTE_${addr}} ${REMOTE_SSH} \
141	    ${PERLPATH}${a}
142.else
143	time ${SUDO} SUDO=${SUDO} KTRACE=${KTRACE} \
144	    perl ${PERLINC} ${PERLPATH}remote.pl -f ${inet} \
145	    ${LOCAL_${addr}} ${FAKE_${addr}} ${REMOTE_SSH} \
146	    ${PERLPATH}${a}
147.endif
148.endfor
149
150STATE_EXIST_tcp_to =		!
151STATE_EXIST_udp_to =
152STATE_EXIST_rip_to =
153STATE_EXIST_tcp_reply =		!
154STATE_EXIST_udp_reply =		!
155STATE_EXIST_rip_reply =		!
156STATE_EXIST_tcp_reply-to =	!
157STATE_EXIST_udp_reply-to =	!
158STATE_EXIST_rip_reply-to =	!
159
160.for proto in tcp udp rip
161
162.for  first second  in  to to  to reply  to reply-to  reply to  reply reply  reply reply-to  reply-to to  reply-to reply  reply-to reply-to
163
164run-${inet}-reuse-${proto}-${first}-${second}:
165	# create state with ${first} divert rule
166	time ${SUDO} SUDO=${SUDO} KTRACE=${KTRACE} \
167	    perl ${PERLINC} ${PERLPATH}remote.pl -f ${inet} \
168	    ${LOCAL_${addr}} ${FAKE_${addr}} ${REMOTE_SSH} \
169	    ${PERLPATH}args-${proto}-${first}.pl
170	sed -n '/^connect peer:/s/.* //p' client.log >client.port
171	sed -n '/^connect sock:/s/.* //p' client.log >server.port
172.if "tcp" == ${proto}
173	# drop client tcp socket still in time wait to allow reuse
174.if "reply" == ${first} || "reply-to" == ${first}
175	${SUDO} tcpdrop \
176	    ${LOCAL_${addr}} `cat client.port` \
177	    ${FAKE_${addr}} `cat server.port`
178	# to avoid SYN retransmit, kill local tcp state that will be reused
179.if "inet" == ${inet}
180	${SUDO} pfctl -k key -k '${proto} ${LOCAL_${addr}}:'`cat client.port`' <- ${FAKE_${addr}}:'`cat server.port`''
181.elif "inet6" == ${inet}
182	${SUDO} pfctl -k key -k '${proto} ${LOCAL_${addr}}['`cat client.port`'] <- ${FAKE_${addr}}['`cat server.port`']'
183.endif
184.else # "to" == ${first}
185	# to avoid SYN retransmit, kill local tcp state that will be reused
186.if "inet" == ${inet}
187	${SUDO} pfctl -k key -k '${proto} ${LOCAL_${addr}}:'`cat server.port`' -> ${FAKE_${addr}}:'`cat client.port`''
188.elif "inet6" == ${inet}
189	${SUDO} pfctl -k key -k '${proto} ${LOCAL_${addr}}['`cat server.port`'] -> ${FAKE_${addr}}['`cat client.port`']'
190.endif
191	# tcp socket is in time wait so state must still exist
192	ssh ${REMOTE_SSH} ${SUDO} pfctl -ss | \
193	    egrep 'all ${proto} ${FAKE_${addr}}:?\[?'`cat client.port`'\]? .. ${LOCAL_${addr}}:?\[?'`cat server.port`'\]? '
194	ssh ${REMOTE_SSH} ${SUDO} tcpdrop \
195	    ${FAKE_${addr}} `cat client.port` \
196	    ${LOCAL_${addr}} `cat server.port`
197	# divert-to state disappeared when the tcp socket was dropped
198	ssh ${REMOTE_SSH} ${SUDO} pfctl -ss | ! \
199	    egrep 'all ${proto} ${FAKE_${addr}}:?\[?'`cat client.port`'\]? .. ${LOCAL_${addr}}:?\[?'`cat server.port`'\]? '
200.endif
201.endif
202.if "to" == ${first}
203.if "tcp" == ${proto}
204	# divert-to state has disappeared as tcp socket is always connected
205.else
206	# divert-to state still exists as the socket is unconnected
207.endif
208.else
209	# divert-reply state has disappeared when the connected socket closed
210.endif
211	ssh ${REMOTE_SSH} ${SUDO} pfctl -ss | ${STATE_EXIST_${proto}_${first}} \
212	    egrep ' (tcp|udp|254) ${FAKE_${addr}}[][0-9:]* .. ${LOCAL_${addr}}[][0-9:]* '
213	# create state again with ${second} divert rule
214	time ${SUDO} SUDO=${SUDO} KTRACE=${KTRACE} \
215	    perl ${PERLINC} ${PERLPATH}remote.pl ${inet} \
216	    ${LOCAL_${addr}} ${FAKE_${addr}} ${REMOTE_SSH} \
217	    `cat client.port` `cat server.port` \
218	    ${PERLPATH}args-${proto}-${second}.pl
219.if "tcp" == ${proto}
220.if "reply" == ${second} || "reply-to" == ${second}
221	# drop client tcp socket still in time wait to clean up
222	${SUDO} tcpdrop \
223	    ${LOCAL_${addr}} `cat server.port` \
224	    ${FAKE_${addr}} `cat client.port`
225.else # "to" == ${second}
226	# dropping the server tcp socket in time wait must remove the state
227	ssh ${REMOTE_SSH} ${SUDO} pfctl -ss | \
228	    egrep 'all ${proto} ${FAKE_${addr}}:?\[?'`cat server.port`'\]? .. ${LOCAL_${addr}}:?\[?'`cat client.port`'\]? '
229	ssh ${REMOTE_SSH} ${SUDO} tcpdrop \
230	    ${FAKE_${addr}} `cat server.port` \
231	    ${LOCAL_${addr}} `cat client.port`
232	ssh ${REMOTE_SSH} ${SUDO} pfctl -ss | ! \
233	    egrep 'all ${proto} ${FAKE_${addr}}:?\[?'`cat server.port`'\]? .. ${LOCAL_${addr}}:?\[?'`cat client.port`'\]? '
234.endif
235.endif
236	# states must disappear after connected socket has been closed
237	ssh ${REMOTE_SSH} ${SUDO} pfctl -ss | ${STATE_EXIST_${proto}_${second}} \
238	    egrep ' (tcp|udp|254) ${FAKE_${addr}}[][0-9:]* .. ${LOCAL_${addr}}[][0-9:]* '
239
240.endfor
241.endfor
242.endfor
243
244.PHONY: syntax check-setup
245
246# make perl syntax check for all args files
247syntax: stamp-syntax
248
249stamp-syntax: ${PERLS} ${ARGS}
250.for p in ${PERLS}
251	@perl -c ${PERLINC} ${PERLPATH}$p
252.endfor
253.for a in ${ARGS}
254	@perl -c ${PERLPATH}$a
255.endfor
256	@date >$@
257
258# Check wether the address, route and remote setup is correct
259check-setup:
260	@echo '\n======== $@ ========'
261	ping -n -c 1 ${LOCAL_ADDR}
262	ping -n -c 1 ${REMOTE_ADDR}
263	ping6 -n -c 1 ${LOCAL_ADDR6}
264	ping6 -n -c 1 ${REMOTE_ADDR6}
265	route -n get -inet ${FAKE_ADDR} | grep 'if address: ${LOCAL_ADDR}$$'
266	route -n get -inet ${FAKE_ADDR} | grep 'gateway: ${REMOTE_ADDR}$$'
267	route -n get -inet6 ${FAKE_ADDR6} | grep 'if address: ${LOCAL_ADDR6}$$'
268	route -n get -inet6 ${FAKE_ADDR6} | grep 'gateway: ${REMOTE_ADDR6}$$'
269	ssh ${REMOTE_SSH} ${SUDO} pfctl -sr | grep '^anchor "regress" all$$'
270	ssh ${REMOTE_SSH} ${SUDO} pfctl -si | grep '^Status: Enabled '
271	ssh ${REMOTE_SSH} perl -MSocket6 -e 1
272
273.include <bsd.regress.mk>
274