]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/netpfil/pf/syncookie.sh
pf: implement start/stop calls via netlink
[FreeBSD/FreeBSD.git] / tests / sys / netpfil / pf / syncookie.sh
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
29 common_dir=$(atf_get_srcdir)/../common
30
31 syncookie_state()
32 {
33         jail=$1
34
35         jexec $jail pfctl -si -v | grep -A 2 '^Syncookies' | grep active \
36             | awk '{ print($2); }'
37 }
38
39 atf_test_case "basic" "cleanup"
40 basic_head()
41 {
42         atf_set descr 'Basic syncookie test'
43         atf_set require.user root
44 }
45
46 basic_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         # Check that status shows syncookies as being active
75         active=$(syncookie_state alcatraz)
76         if [ "$active" != "active" ];
77         then
78                 atf_fail "syncookies not active"
79         fi
80 }
81
82 basic_cleanup()
83 {
84         rm -f inetd-alcatraz.pid
85         pft_cleanup
86 }
87
88 atf_test_case "basic_v6" "cleanup"
89 basic_v6_head()
90 {
91         atf_set descr 'Basic syncookie IPv6 test'
92         atf_set require.user root
93 }
94
95 basic_v6_body()
96 {
97         pft_init
98
99         epair=$(vnet_mkepair)
100
101         vnet_mkjail alcatraz ${epair}b
102         jexec alcatraz ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
103         jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \
104             $(atf_get_srcdir)/echo_inetd.conf
105
106         ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
107
108         jexec alcatraz pfctl -e
109         pft_set_rules alcatraz \
110                 "set syncookies always" \
111                 "pass in" \
112                 "pass out"
113
114         # Sanity check
115         atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8::1
116
117         reply=$(echo foo | nc -N -w 5 2001:db8::1 7)
118         if [ "${reply}" != "foo" ];
119         then
120                 atf_fail "Failed to connect to syncookie protected echo daemon"
121         fi
122
123         # Check that status shows syncookies as being active
124         active=$(syncookie_state alcatraz)
125         if [ "$active" != "active" ];
126         then
127                 atf_fail "syncookies not active"
128         fi
129 }
130
131 basic_v6_cleanup()
132 {
133         rm -f inetd-alcatraz.pid
134         pft_cleanup
135 }
136
137 atf_test_case "forward" "cleanup"
138 forward_head()
139 {
140         atf_set descr 'Syncookies for forwarded hosts'
141         atf_set require.user root
142 }
143
144 forward_body()
145 {
146         pft_init
147
148         epair_in=$(vnet_mkepair)
149         epair_out=$(vnet_mkepair)
150
151         vnet_mkjail fwd ${epair_in}b ${epair_out}a
152         vnet_mkjail srv ${epair_out}b
153
154         jexec fwd ifconfig ${epair_in}b 192.0.2.1/24 up
155         jexec fwd ifconfig ${epair_out}a 198.51.100.1/24 up
156         jexec fwd sysctl net.inet.ip.forwarding=1
157
158         jexec srv ifconfig ${epair_out}b 198.51.100.2/24 up
159         jexec srv route add default 198.51.100.1
160         jexec srv /usr/sbin/inetd -p inetd-alcatraz.pid \
161             $(atf_get_srcdir)/echo_inetd.conf
162
163         ifconfig ${epair_in}a 192.0.2.2/24 up
164         route add -net 198.51.100.0/24 192.0.2.1
165
166         jexec fwd pfctl -e
167         pft_set_rules fwd \
168                 "set syncookies always" \
169                 "pass in" \
170                 "pass out"
171
172         # Sanity check
173         atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2
174
175         reply=$(echo foo | nc -N -w 5 198.51.100.2 7)
176         if [ "${reply}" != "foo" ];
177         then
178                 atf_fail "Failed to connect to syncookie protected echo daemon"
179         fi
180 }
181
182 forward_cleanup()
183 {
184         rm -f inetd-alcatraz.pid
185         pft_cleanup
186 }
187
188 atf_test_case "forward_v6" "cleanup"
189 forward_v6_head()
190 {
191         atf_set descr 'Syncookies for forwarded hosts'
192         atf_set require.user root
193 }
194
195 forward_v6_body()
196 {
197         pft_init
198
199         epair_in=$(vnet_mkepair)
200         epair_out=$(vnet_mkepair)
201
202         vnet_mkjail fwd ${epair_in}b ${epair_out}a
203         vnet_mkjail srv ${epair_out}b
204
205         jexec fwd ifconfig ${epair_in}b inet6 2001:db8::1/64 up no_dad
206         jexec fwd ifconfig ${epair_out}a inet6 2001:db8:1::1/64 up no_dad
207         jexec fwd sysctl net.inet6.ip6.forwarding=1
208
209         jexec srv ifconfig ${epair_out}b inet6 2001:db8:1::2/64 up no_dad
210         jexec srv route -6 add default 2001:db8:1::1
211         jexec srv /usr/sbin/inetd -p inetd-alcatraz.pid \
212             $(atf_get_srcdir)/echo_inetd.conf
213
214         ifconfig ${epair_in}a inet6 2001:db8::2/64 up no_dad
215         route -6 add -net 2001:db8:1::/64 2001:db8::1
216
217         jexec fwd pfctl -e
218         pft_set_rules fwd \
219                 "set syncookies always" \
220                 "pass in" \
221                 "pass out"
222
223         # Sanity check
224         atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:1::2
225
226         reply=$(echo foo | nc -N -w 5 2001:db8:1::2 7)
227         if [ "${reply}" != "foo" ];
228         then
229                 atf_fail "Failed to connect to syncookie protected echo daemon"
230         fi
231 }
232
233 forward_v6_cleanup()
234 {
235         rm -f inetd-alcatraz.pid
236         pft_cleanup
237 }
238
239 atf_test_case "nostate" "cleanup"
240 nostate_head()
241 {
242         atf_set descr 'Ensure that we do not create until SYN|ACK'
243         atf_set require.user root
244         atf_set require.progs scapy
245 }
246
247 nostate_body()
248 {
249         pft_init
250
251         epair=$(vnet_mkepair)
252         ifconfig ${epair}a 192.0.2.2/24 up
253
254         vnet_mkjail alcatraz ${epair}b
255         jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
256
257         jexec alcatraz pfctl -e
258         pft_set_rules alcatraz \
259                 "set syncookies always" \
260                 "pass in" \
261                 "pass out"
262
263         # Sanity check
264         atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
265
266         # Now syn flood to create many states
267         ${common_dir}/pft_synflood.py \
268                 --sendif ${epair}a \
269                 --to 192.0.2.2 \
270                 --count 20
271
272         states=$(jexec alcatraz pfctl -ss | grep tcp)
273         if [ -n "$states" ];
274         then
275                 echo "$states"
276                 atf_fail "Found unexpected state"
277         fi
278 }
279
280 nostate_cleanup()
281 {
282         pft_cleanup
283 }
284
285 atf_test_case "nostate_v6" "cleanup"
286 nostate_v6_head()
287 {
288         atf_set descr 'Ensure that we do not create until SYN|ACK'
289         atf_set require.user root
290         atf_set require.progs scapy
291 }
292
293 nostate_v6_body()
294 {
295         pft_init
296
297         epair=$(vnet_mkepair)
298         ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
299
300         vnet_mkjail alcatraz ${epair}b
301         jexec alcatraz ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
302
303         jexec alcatraz pfctl -e
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 ping6 -c 1 2001:db8::1
311
312         # Now syn flood to create many states
313         ${common_dir}/pft_synflood.py \
314         --ip6 \
315                 --sendif ${epair}a \
316                 --to 2001:db8::2 \
317                 --count 20
318
319         states=$(jexec alcatraz pfctl -ss | grep tcp)
320         if [ -n "$states" ];
321         then
322                 echo "$states"
323                 atf_fail "Found unexpected state"
324         fi
325 }
326
327 nostate_v6_cleanup()
328 {
329         pft_cleanup
330 }
331
332 atf_test_case "adaptive" "cleanup"
333 adaptive_head()
334 {
335         atf_set descr 'Adaptive mode test'
336         atf_set require.user root
337         atf_set require.progs scapy
338 }
339
340 adaptive_body()
341 {
342         pft_init
343
344         epair=$(vnet_mkepair)
345         ifconfig ${epair}a 192.0.2.2/24 up
346
347         vnet_mkjail alcatraz ${epair}b
348         jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
349
350         jexec alcatraz pfctl -e
351         pft_set_rules alcatraz \
352                 "set limit states 100" \
353                 "set syncookies adaptive (start 10%%, end 5%%)" \
354                 "pass in" \
355                 "pass out"
356
357         # Sanity check
358         atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
359
360         # Check that status shows syncookies as being inactive
361         active=$(syncookie_state alcatraz)
362         if [ "$active" != "inactive" ];
363         then
364                 atf_fail "syncookies active when they should not be"
365         fi
366
367         # Now syn flood to create many states
368         ${common_dir}/pft_synflood.py \
369                 --sendif ${epair}a \
370                 --to 192.0.2.2 \
371                 --count 100
372
373         # Check that status shows syncookies as being active
374         active=$(syncookie_state alcatraz)
375         if [ "$active" != "active" ];
376         then
377                 atf_fail "syncookies not active"
378         fi
379
380         # Adaptive mode should kick in and stop us from creating more than
381         # about 10 states
382         states=$(jexec alcatraz pfctl -ss | grep tcp | wc -l)
383         if [ "$states" -gt 20 ];
384         then
385                 echo "$states"
386                 atf_fail "Found unexpected states"
387         fi
388 }
389
390 adaptive_cleanup()
391 {
392         pft_cleanup
393 }
394
395 atf_test_case "limits" "cleanup"
396 limits_head()
397 {
398         atf_set descr 'Ensure limit calculation works for low or high state limits'
399         atf_set require.user root
400 }
401
402 limits_body()
403 {
404         pft_init
405
406         vnet_mkjail alcatraz
407
408         jexec alcatraz pfctl -e
409         pft_set_rules alcatraz \
410                 "set limit states 1" \
411                 "set syncookies adaptive (start 10%%, end 5%%)" \
412                 "pass in" \
413                 "pass out"
414
415         pft_set_rules alcatraz \
416                 "set limit states 326000000" \
417                 "set syncookies adaptive (start 10%%, end 5%%)" \
418                 "pass in" \
419                 "pass out"
420 }
421
422 limits_cleanup()
423 {
424         pft_cleanup
425 }
426
427 atf_test_case "port_reuse" "cleanup"
428 port_reuse_head()
429 {
430         atf_set descr 'Test rapid port re-use'
431         atf_set require.user root
432 }
433
434 port_reuse_body()
435 {
436         pft_init
437
438         epair=$(vnet_mkepair)
439
440         vnet_mkjail alcatraz ${epair}b
441         vnet_mkjail singsing
442         jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
443         jexec alcatraz /usr/sbin/inetd -p ${HOME}/inetd-alcatraz.pid \
444             $(atf_get_srcdir)/echo_inetd.conf
445
446         ifconfig ${epair}a 192.0.2.2/24 up
447
448         jexec alcatraz pfctl -e
449         jexec alcatraz pfctl -x loud
450         pft_set_rules alcatraz \
451                 "set syncookies always" \
452                 "pass in" \
453                 "pass out"
454
455         # Sanity check
456         atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
457
458         reply=$(echo foo | nc -p 1234 -N -w 5 192.0.2.1 7)
459         if [ "${reply}" != "foo" ];
460         then
461                 atf_fail "Failed to connect to syncookie protected echo daemon"
462         fi
463
464         # We can't re-use the source IP/port combo quickly enough, so we're
465         # going to play a really dirty trick, and move our interface to a new
466         # jail, and do it from there.
467         ifconfig ${epair}a vnet singsing
468         jexec singsing ifconfig ${epair}a 192.0.2.2/24 up
469         atf_check -s exit:0 -o ignore jexec singsing ping -c 1 192.0.2.1
470
471         reply=$(echo bar | jexec singsing nc -p 1234 -N -w 5 192.0.2.1 7)
472         if [ "${reply}" != "bar" ];
473         then
474                 atf_fail "Failed to connect to syncookie protected echo daemon (2)"
475         fi
476 }
477
478 port_reuse_cleanup()
479 {
480         pft_cleanup
481 }
482
483 atf_init_test_cases()
484 {
485         atf_add_test_case "basic"
486         atf_add_test_case "basic_v6"
487         atf_add_test_case "forward"
488         atf_add_test_case "forward_v6"
489         atf_add_test_case "nostate"
490         atf_add_test_case "nostate_v6"
491         atf_add_test_case "adaptive"
492         atf_add_test_case "limits"
493         atf_add_test_case "port_reuse"
494 }