xref: /freebsd/tests/sys/netpfil/pf/syncookie.sh (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2021 Modirum MDPay
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26
27. $(atf_get_srcdir)/utils.subr
28
29common_dir=$(atf_get_srcdir)/../common
30
31syncookie_state()
32{
33	jail=$1
34
35	jexec $jail pfctl -si -v | grep -A 2 '^Syncookies' | grep active \
36	    | awk '{ print($2); }'
37}
38
39atf_test_case "basic" "cleanup"
40basic_head()
41{
42	atf_set descr 'Basic syncookie test'
43	atf_set require.user root
44}
45
46basic_body()
47{
48	pft_init
49
50	epair=$(vnet_mkepair)
51
52	vnet_mkjail alcatraz ${epair}b
53	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
54	jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \
55	    $(atf_get_srcdir)/echo_inetd.conf
56
57	ifconfig ${epair}a 192.0.2.2/24 up
58
59	jexec alcatraz pfctl -e
60	pft_set_rules alcatraz \
61		"set syncookies always" \
62		"pass in" \
63		"pass out"
64
65	# Sanity check
66	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
67
68	reply=$(echo foo | nc -N -w 5 192.0.2.1 7)
69	if [ "${reply}" != "foo" ];
70	then
71		atf_fail "Failed to connect to syncookie protected echo daemon"
72	fi
73
74
75	# Check that status shows syncookies as being active
76	active=$(syncookie_state alcatraz)
77	if [ "$active" != "active" ];
78	then
79		atf_fail "syncookies not active"
80	fi
81}
82
83basic_cleanup()
84{
85	rm -f inetd-alcatraz.pid
86	pft_cleanup
87}
88
89atf_test_case "forward" "cleanup"
90forward_head()
91{
92	atf_set descr 'Syncookies for forwarded hosts'
93	atf_set require.user root
94}
95
96forward_body()
97{
98	pft_init
99
100	epair_in=$(vnet_mkepair)
101	epair_out=$(vnet_mkepair)
102
103	vnet_mkjail fwd ${epair_in}b ${epair_out}a
104	vnet_mkjail srv ${epair_out}b
105
106	jexec fwd ifconfig ${epair_in}b 192.0.2.1/24 up
107	jexec fwd ifconfig ${epair_out}a 198.51.100.1/24 up
108	jexec fwd sysctl net.inet.ip.forwarding=1
109
110	jexec srv ifconfig ${epair_out}b 198.51.100.2/24 up
111	jexec srv route add default 198.51.100.1
112	jexec srv /usr/sbin/inetd -p inetd-alcatraz.pid \
113	    $(atf_get_srcdir)/echo_inetd.conf
114
115	ifconfig ${epair_in}a 192.0.2.2/24 up
116	route add -net 198.51.100.0/24 192.0.2.1
117
118	jexec fwd pfctl -e
119	pft_set_rules fwd \
120		"set syncookies always" \
121		"pass in" \
122		"pass out"
123
124	# Sanity check
125	atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2
126
127	reply=$(echo foo | nc -N -w 5 198.51.100.2 7)
128	if [ "${reply}" != "foo" ];
129	then
130		atf_fail "Failed to connect to syncookie protected echo daemon"
131	fi
132}
133
134forward_cleanup()
135{
136	rm -f inetd-alcatraz.pid
137	pft_cleanup
138}
139
140atf_test_case "nostate" "cleanup"
141nostate_head()
142{
143	atf_set descr 'Ensure that we do not create until SYN|ACK'
144	atf_set require.user root
145	atf_set require.progs scapy
146}
147
148nostate_body()
149{
150	pft_init
151
152	epair=$(vnet_mkepair)
153	ifconfig ${epair}a 192.0.2.2/24 up
154
155	vnet_mkjail alcatraz ${epair}b
156	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
157
158	jexec alcatraz pfctl -e
159	pft_set_rules alcatraz \
160		"set syncookies always" \
161		"pass in" \
162		"pass out"
163
164	# Sanity check
165	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
166
167	# Now syn flood to create many states
168	${common_dir}/pft_synflood.py \
169		--sendif ${epair}a \
170		--to 192.0.2.2 \
171		--count 20
172
173	states=$(jexec alcatraz pfctl -ss | grep tcp)
174	if [ -n "$states" ];
175	then
176		echo "$states"
177		atf_fail "Found unexpected state"
178	fi
179}
180
181nostate_cleanup()
182{
183	pft_cleanup
184}
185
186atf_test_case "adaptive" "cleanup"
187adaptive_head()
188{
189	atf_set descr 'Adaptive mode test'
190	atf_set require.user root
191	atf_set require.progs scapy
192}
193
194adaptive_body()
195{
196	pft_init
197
198	epair=$(vnet_mkepair)
199	ifconfig ${epair}a 192.0.2.2/24 up
200
201	vnet_mkjail alcatraz ${epair}b
202	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
203
204	jexec alcatraz pfctl -e
205	pft_set_rules alcatraz \
206		"set limit states 100" \
207		"set syncookies adaptive (start 10%%, end 5%%)" \
208		"pass in" \
209		"pass out"
210
211	# Sanity check
212	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
213
214	# Check that status shows syncookies as being inactive
215	active=$(syncookie_state alcatraz)
216	if [ "$active" != "inactive" ];
217	then
218		atf_fail "syncookies active when they should not be"
219	fi
220
221	# Now syn flood to create many states
222	${common_dir}/pft_synflood.py \
223		--sendif ${epair}a \
224		--to 192.0.2.2 \
225		--count 100
226
227	# Check that status shows syncookies as being active
228	active=$(syncookie_state alcatraz)
229	if [ "$active" != "active" ];
230	then
231		atf_fail "syncookies not active"
232	fi
233
234	# Adaptive mode should kick in and stop us from creating more than
235	# about 10 states
236	states=$(jexec alcatraz pfctl -ss | grep tcp | wc -l)
237	if [ "$states" -gt 20 ];
238	then
239		echo "$states"
240		atf_fail "Found unexpected states"
241	fi
242}
243
244adaptive_cleanup()
245{
246	pft_cleanup
247}
248
249atf_test_case "limits" "cleanup"
250limits_head()
251{
252	atf_set descr 'Ensure limit calculation works for low or high state limits'
253	atf_set require.user root
254}
255
256limits_body()
257{
258	pft_init
259
260	vnet_mkjail alcatraz
261
262	jexec alcatraz pfctl -e
263	pft_set_rules alcatraz \
264		"set limit states 1" \
265		"set syncookies adaptive (start 10%%, end 5%%)" \
266		"pass in" \
267		"pass out"
268
269	pft_set_rules alcatraz \
270		"set limit states 326000000" \
271		"set syncookies adaptive (start 10%%, end 5%%)" \
272		"pass in" \
273		"pass out"
274}
275
276limits_cleanup()
277{
278	pft_cleanup
279}
280
281atf_test_case "port_reuse" "cleanup"
282port_reuse_head()
283{
284	atf_set descr 'Test rapid port re-use'
285	atf_set require.user root
286}
287
288port_reuse_body()
289{
290	pft_init
291
292	epair=$(vnet_mkepair)
293
294	vnet_mkjail alcatraz ${epair}b
295	vnet_mkjail singsing
296	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
297	jexec alcatraz /usr/sbin/inetd -p ${HOME}/inetd-alcatraz.pid \
298	    $(atf_get_srcdir)/echo_inetd.conf
299
300	ifconfig ${epair}a 192.0.2.2/24 up
301
302	jexec alcatraz pfctl -e
303	jexec alcatraz pfctl -x loud
304	pft_set_rules alcatraz \
305		"set syncookies always" \
306		"pass in" \
307		"pass out"
308
309	# Sanity check
310	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
311
312	reply=$(echo foo | nc -p 1234 -N -w 5 192.0.2.1 7)
313	if [ "${reply}" != "foo" ];
314	then
315		atf_fail "Failed to connect to syncookie protected echo daemon"
316	fi
317
318	# We can't re-use the source IP/port combo quickly enough, so we're
319	# going to play a really dirty trick, and move our interface to a new
320	# jail, and do it from there.
321	ifconfig ${epair}a vnet singsing
322	jexec singsing ifconfig ${epair}a 192.0.2.2/24 up
323	atf_check -s exit:0 -o ignore jexec singsing ping -c 1 192.0.2.1
324
325	reply=$(echo bar | jexec singsing nc -p 1234 -N -w 5 192.0.2.1 7)
326	if [ "${reply}" != "bar" ];
327	then
328		atf_fail "Failed to connect to syncookie protected echo daemon (2)"
329	fi
330}
331
332port_reuse_cleanup()
333{
334	pft_cleanup
335}
336
337atf_init_test_cases()
338{
339	atf_add_test_case "basic"
340	atf_add_test_case "forward"
341	atf_add_test_case "nostate"
342	atf_add_test_case "adaptive"
343	atf_add_test_case "limits"
344	atf_add_test_case "port_reuse"
345}
346