Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netpfil/pf/divert-to.sh
108778 views
1
#
2
# SPDX-License-Identifier: BSD-2-Clause
3
#
4
# Copyright (c) 2023 Igor Ostapenko <[email protected]>
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
#
28
# pf divert-to action test cases
29
#
30
# -----------| |-- |----| ----| |-----------
31
# ( ) inbound |pf_check_in| ) -> |host| -> ( ) |pf_check_out| outbound )
32
# -----------| | |-- |----| ----| | |-----------
33
# | |
34
# \|/ \|/
35
# |------| |------|
36
# |divapp| |divapp|
37
# |------| |------|
38
#
39
# The basic cases:
40
# - inbound > diverted | divapp terminated
41
# - inbound > diverted > inbound | host terminated
42
# - inbound > diverted > outbound | network terminated
43
# - outbound > diverted | divapp terminated
44
# - outbound > diverted > outbound | network terminated
45
# - outbound > diverted > inbound | e.g. host terminated
46
#
47
# When a packet is diverted, forwarded, and possibly diverted again:
48
# - inbound > diverted > inbound > forwarded
49
# > outbound | network terminated
50
# - inbound > diverted > inbound > forwarded
51
# > outbound > diverted > outbound | network terminated
52
#
53
# Test case naming legend:
54
# in - inbound
55
# div - diverted
56
# out - outbound
57
# fwd - forwarded
58
# dn - delayed by dummynet
59
#
60
61
. $(atf_get_srcdir)/utils.subr
62
63
atf_test_case "in_div" "cleanup"
64
in_div_head()
65
{
66
atf_set descr 'Test inbound > diverted | divapp terminated'
67
atf_set require.user root
68
atf_set require.kmods ipdivert
69
}
70
in_div_body()
71
{
72
pft_init
73
74
epair=$(vnet_mkepair)
75
vnet_mkjail div ${epair}b
76
atf_check ifconfig ${epair}a 192.0.2.1/24 up
77
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
78
atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up
79
atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
80
81
# Sanity check
82
atf_check -o ignore ping -c3 192.0.2.2
83
atf_check -o ignore ping -c3 2001:db8::2
84
85
jexec div pfctl -e
86
pft_set_rules div \
87
"pass all" \
88
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000" \
89
"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2000"
90
91
jexec div $(atf_get_srcdir)/../common/divapp 2000 &
92
divapp_pid=$!
93
# Wait for the divapp to be ready
94
sleep 1
95
96
# divapp is expected to "eat" the packet
97
atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
98
99
wait $divapp_pid
100
101
jexec div $(atf_get_srcdir)/../common/divapp 2000 &
102
divapp_pid=$!
103
# Wait for the divapp to be ready
104
sleep 1
105
106
# divapp is expected to "eat" the packet
107
atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2
108
109
wait $divapp_pid
110
}
111
in_div_cleanup()
112
{
113
pft_cleanup
114
}
115
116
atf_test_case "in_div_in" "cleanup"
117
in_div_in_head()
118
{
119
atf_set descr 'Test inbound > diverted > inbound | host terminated'
120
atf_set require.user root
121
atf_set require.kmods ipdivert
122
}
123
in_div_in_body()
124
{
125
pft_init
126
127
epair=$(vnet_mkepair)
128
vnet_mkjail div ${epair}b
129
atf_check ifconfig ${epair}a 192.0.2.1/24 up
130
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
131
atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up
132
atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
133
134
# Sanity check
135
atf_check -o ignore ping -c3 192.0.2.2
136
atf_check -o ignore ping -c3 2001:db8::2
137
138
jexec div pfctl -e
139
pft_set_rules div \
140
"pass all" \
141
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000 no state" \
142
"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2000 no state"
143
144
jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &
145
divapp_pid=$!
146
# Wait for the divapp to be ready
147
sleep 1
148
149
# divapp is NOT expected to "eat" the packet
150
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
151
152
wait $divapp_pid
153
154
jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &
155
divapp_pid=$!
156
# Wait for the divapp to be ready
157
sleep 1
158
159
# divapp is expected to "eat" the packet
160
atf_check -s exit:0 -o ignore ping -c1 -t1 2001:db8::2
161
162
wait $divapp_pid
163
}
164
in_div_in_cleanup()
165
{
166
pft_cleanup
167
}
168
169
atf_test_case "out_div" "cleanup"
170
out_div_head()
171
{
172
atf_set descr 'Test outbound > diverted | divapp terminated'
173
atf_set require.user root
174
atf_set require.kmods ipdivert
175
}
176
out_div_body()
177
{
178
pft_init
179
180
epair=$(vnet_mkepair)
181
vnet_mkjail div ${epair}b
182
atf_check ifconfig ${epair}a 192.0.2.1/24 up
183
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
184
atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up
185
atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
186
187
# Sanity check
188
atf_check -o ignore ping -c3 192.0.2.2
189
atf_check -o ignore ping -c3 2001:db8::2
190
191
jexec div pfctl -e
192
pft_set_rules div \
193
"pass all" \
194
"pass in inet proto icmp icmp-type echoreq no state" \
195
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state" \
196
"pass in inet6 proto icmp6 icmp6-type echoreq no state" \
197
"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 2000 no state"
198
199
jexec div $(atf_get_srcdir)/../common/divapp 2000 &
200
divapp_pid=$!
201
# Wait for the divapp to be ready
202
sleep 1
203
204
# divapp is expected to "eat" the packet
205
atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
206
207
wait $divapp_pid
208
209
jexec div $(atf_get_srcdir)/../common/divapp 2000 &
210
divapp_pid=$!
211
# Wait for the divapp to be ready
212
sleep 1
213
214
# divapp is expected to "eat" the packet
215
atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2
216
217
wait $divapp_pid
218
}
219
out_div_cleanup()
220
{
221
pft_cleanup
222
}
223
224
atf_test_case "out_div_out" "cleanup"
225
out_div_out_head()
226
{
227
atf_set descr 'Test outbound > diverted > outbound | network terminated'
228
atf_set require.user root
229
atf_set require.kmods ipdivert
230
}
231
out_div_out_body()
232
{
233
pft_init
234
235
epair=$(vnet_mkepair)
236
vnet_mkjail div ${epair}b
237
atf_check ifconfig ${epair}a 192.0.2.1/24 up
238
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
239
atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up
240
atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
241
242
# Sanity check
243
atf_check -o ignore ping -c3 192.0.2.2
244
atf_check -o ignore ping -c3 2001:db8::2
245
246
jexec div pfctl -e
247
pft_set_rules div \
248
"pass all" \
249
"pass in inet proto icmp icmp-type echoreq no state" \
250
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state" \
251
"pass in inet6 proto icmp6 icmp6-type echoreq no state" \
252
"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 2000 no state"
253
254
jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &
255
divapp_pid=$!
256
# Wait for the divapp to be ready
257
sleep 1
258
259
# divapp is NOT expected to "eat" the packet
260
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
261
262
wait $divapp_pid
263
264
jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &
265
divapp_pid=$!
266
# Wait for the divapp to be ready
267
sleep 1
268
269
# divapp is NOT expected to "eat" the packet
270
atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
271
272
wait $divapp_pid
273
}
274
out_div_out_cleanup()
275
{
276
pft_cleanup
277
}
278
279
atf_test_case "in_div_in_fwd_out_div_out" "cleanup"
280
in_div_in_fwd_out_div_out_head()
281
{
282
atf_set descr 'Test inbound > diverted > inbound > forwarded > outbound > diverted > outbound | network terminated'
283
atf_set require.user root
284
atf_set require.kmods ipdivert
285
}
286
in_div_in_fwd_out_div_out_body()
287
{
288
pft_init
289
290
# host <a--epair0--b> router <a--epair1--b> site
291
epair0=$(vnet_mkepair)
292
epair1=$(vnet_mkepair)
293
294
vnet_mkjail router ${epair0}b ${epair1}a
295
atf_check ifconfig ${epair0}a 192.0.2.1/24 up
296
atf_check ifconfig ${epair0}a inet6 2001:db8::1/64 no_dad
297
atf_check -o ignore jexec router sysctl net.inet.ip.forwarding=1
298
atf_check -o ignore jexec router sysctl net.inet6.ip6.forwarding=1
299
atf_check jexec router ifconfig ${epair0}b 192.0.2.2/24 up
300
atf_check jexec router ifconfig ${epair0}b inet6 2001:db8::2/64 no_dad
301
atf_check jexec router ifconfig ${epair1}a 198.51.100.1/24 up
302
atf_check jexec router ifconfig ${epair1}a inet6 2001:db9::1/64 no_dad
303
304
vnet_mkjail site ${epair1}b
305
jexec site ifconfig ${epair1}b 198.51.100.2/24 up
306
jexec site ifconfig ${epair1}b inet6 2001:db9::2/64 no_dad
307
jexec site route add default 198.51.100.1
308
jexec site route -6 add default 2001:db9::1
309
310
atf_check -o ignore route add -net 198.51.100.0/24 192.0.2.2
311
atf_check -o ignore route -6 add -net 2001:db9::/64 2001:db8::2
312
313
# Sanity check
314
atf_check -o ignore ping -c3 192.0.2.2
315
atf_check -o ignore ping -c3 2001:db8::2
316
317
# Should be routed without pf
318
atf_check -o ignore ping -c3 198.51.100.2
319
atf_check -o ignore ping -c3 2001:db9::2
320
321
jexec router pfctl -e
322
pft_set_rules router \
323
"pass all" \
324
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \
325
"pass out inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2002 no state" \
326
"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2001 no state" \
327
"pass out inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2002 no state"
328
329
jexec router $(atf_get_srcdir)/../common/divapp 2001 divert-back &
330
indivapp_pid=$!
331
jexec router $(atf_get_srcdir)/../common/divapp 2002 divert-back &
332
outdivapp_pid=$!
333
# Wait for the divapps to be ready
334
sleep 1
335
336
# Both divapps are NOT expected to "eat" the packet
337
atf_check -s exit:0 -o ignore ping -c1 198.51.100.2
338
339
wait $indivapp_pid && wait $outdivapp_pid
340
341
jexec router $(atf_get_srcdir)/../common/divapp 2001 divert-back &
342
indivapp_pid=$!
343
jexec router $(atf_get_srcdir)/../common/divapp 2002 divert-back &
344
outdivapp_pid=$!
345
# Wait for the divapps to be ready
346
sleep 1
347
348
# Both divapps are NOT expected to "eat" the packet
349
atf_check -o ignore ping -c1 2001:db9::2
350
351
wait $indivapp_pid && wait $outdivapp_pid
352
}
353
in_div_in_fwd_out_div_out_cleanup()
354
{
355
pft_cleanup
356
}
357
358
atf_test_case "in_dn_in_div_in_out_div_out_dn_out" "cleanup"
359
in_dn_in_div_in_out_div_out_dn_out_head()
360
{
361
atf_set descr 'Test inbound > delayed+diverted > outbound > diverted+delayed > outbound | network terminated'
362
atf_set require.user root
363
atf_set require.kmods dummynet ipdivert
364
}
365
in_dn_in_div_in_out_div_out_dn_out_body()
366
{
367
pft_init
368
369
epair=$(vnet_mkepair)
370
vnet_mkjail alcatraz ${epair}b
371
atf_check ifconfig ${epair}a 192.0.2.1/24 up
372
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
373
atf_check ifconfig ${epair}a ether 02:00:00:00:00:01
374
atf_check jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
375
atf_check jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
376
377
# Sanity check
378
atf_check -o ignore ping -c3 192.0.2.2
379
atf_check -o ignore ping -c3 2001:db8::2
380
381
# a) ping should time out due to very narrow dummynet pipes {
382
383
jexec alcatraz dnctl pipe 1001 config bw 1Byte/s
384
jexec alcatraz dnctl pipe 1002 config bw 1Byte/s
385
386
jexec alcatraz pfctl -e
387
pft_set_rules alcatraz \
388
"ether pass in from 02:00:00:00:00:01 l3 all dnpipe 1001" \
389
"ether pass out to 02:00:00:00:00:01 l3 all dnpipe 1002 " \
390
"pass all" \
391
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 1001 no state" \
392
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 1002 no state" \
393
"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 1001 no state" \
394
"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 1002 no state"
395
396
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &
397
indivapp_pid=$!
398
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1002 divert-back &
399
outdivapp_pid=$!
400
# Wait for the divapps to be ready
401
sleep 1
402
403
atf_check -s not-exit:0 -o ignore ping -c1 -s56 -t1 192.0.2.2
404
405
wait $indivapp_pid
406
atf_check_not_equal 0 $?
407
wait $outdivapp_pid
408
atf_check_not_equal 0 $?
409
410
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &
411
indivapp_pid=$!
412
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1002 divert-back &
413
outdivapp_pid=$!
414
# Wait for the divapps to be ready
415
sleep 1
416
417
atf_check -s not-exit:0 -o ignore ping -c1 -s56 -t1 2001:db8::2
418
419
wait $indivapp_pid
420
atf_check_not_equal 0 $?
421
wait $outdivapp_pid
422
atf_check_not_equal 0 $?
423
424
# }
425
426
# b) ping should NOT time out due to wide enough dummynet pipes {
427
428
jexec alcatraz dnctl pipe 2001 config bw 100KByte/s
429
jexec alcatraz dnctl pipe 2002 config bw 100KByte/s
430
431
jexec alcatraz pfctl -e
432
pft_set_rules alcatraz \
433
"ether pass in from 02:00:00:00:00:01 l3 all dnpipe 2001" \
434
"ether pass out to 02:00:00:00:00:01 l3 all dnpipe 2002 " \
435
"pass all" \
436
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \
437
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2002 no state" \
438
"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2001 no state" \
439
"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 2002 no state"
440
441
jexec alcatraz $(atf_get_srcdir)/../common/divapp 2001 divert-back &
442
indivapp_pid=$!
443
jexec alcatraz $(atf_get_srcdir)/../common/divapp 2002 divert-back &
444
outdivapp_pid=$!
445
# Wait for the divapps to be ready
446
sleep 1
447
448
atf_check -o ignore ping -c1 -s56 -t1 192.0.2.2
449
450
wait $indivapp_pid
451
atf_check_equal 0 $?
452
wait $outdivapp_pid
453
atf_check_equal 0 $?
454
455
jexec alcatraz $(atf_get_srcdir)/../common/divapp 2001 divert-back &
456
indivapp_pid=$!
457
jexec alcatraz $(atf_get_srcdir)/../common/divapp 2002 divert-back &
458
outdivapp_pid=$!
459
# Wait for the divapps to be ready
460
sleep 1
461
462
atf_check -o ignore ping -c1 -s56 -t1 2001:db8::2
463
464
wait $indivapp_pid
465
atf_check_equal 0 $?
466
wait $outdivapp_pid
467
atf_check_equal 0 $?
468
469
# }
470
}
471
in_dn_in_div_in_out_div_out_dn_out_cleanup()
472
{
473
pft_cleanup
474
}
475
476
atf_test_case "pr260867" "cleanup"
477
pr260867_head()
478
{
479
atf_set descr 'Test for the loop reported in PR260867'
480
atf_set require.user root
481
atf_set require.kmods ipdivert
482
}
483
pr260867_body()
484
{
485
pft_init
486
487
epair=$(vnet_mkepair)
488
489
atf_check ifconfig ${epair}a 192.0.2.1/24 up
490
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
491
492
vnet_mkjail alcatraz ${epair}b
493
atf_check jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
494
atf_check jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
495
496
# Sanity check
497
atf_check -o ignore ping -c3 192.0.2.2
498
atf_check -o ignore ping -c3 2001:db8::2
499
500
jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf
501
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &
502
503
jexec alcatraz pfctl -e
504
pft_set_rules alcatraz \
505
"pass in on ${epair}b proto tcp from any to port 7 divert-to 0.0.0.0 port 1001"
506
507
reply=$(echo "foo" | nc -N 192.0.2.2 7)
508
if [ "${reply}" != "foo" ]; then
509
atf_fail "Did not receive v4 echo reply"
510
fi
511
512
reply=$(echo "foo" | nc -N -6 2001:db8::2 7)
513
if [ "${reply}" != "foo" ]; then
514
atf_fail "Did not receive v6 echo reply"
515
fi
516
}
517
pr260867_cleanup()
518
{
519
pft_cleanup
520
}
521
522
atf_test_case "pr260867_icmp" "cleanup"
523
pr260867_icmp_head()
524
{
525
atf_set descr 'Variant of the PR260867 test'
526
atf_set require.user root
527
atf_set require.kmods ipdivert
528
}
529
pr260867_icmp_body()
530
{
531
pft_init
532
533
epair=$(vnet_mkepair)
534
535
atf_check ifconfig ${epair}a 192.0.2.1/24 up
536
atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
537
538
vnet_mkjail alcatraz ${epair}b
539
atf_check jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
540
atf_check jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 no_dad
541
542
# Sanity check
543
atf_check -o ignore ping -c3 192.0.2.2
544
atf_check -o ignore ping -c3 2001:db8::2
545
546
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &
547
548
jexec alcatraz pfctl -e
549
pft_set_rules alcatraz \
550
"pass in on ${epair}b proto icmp from any to any divert-to 0.0.0.0 port 1001" \
551
"pass in on ${epair}b proto icmp6 from any to any divert-to :: port 1001"
552
553
atf_check -o ignore ping -c 3 192.0.2.2
554
atf_check -o ignore ping -c 3 2001:db8::2
555
}
556
pr260867_icmp_cleanup()
557
{
558
pft_cleanup
559
}
560
561
atf_init_test_cases()
562
{
563
atf_add_test_case "in_div"
564
atf_add_test_case "in_div_in"
565
566
atf_add_test_case "out_div"
567
atf_add_test_case "out_div_out"
568
569
atf_add_test_case "in_div_in_fwd_out_div_out"
570
571
atf_add_test_case "in_dn_in_div_in_out_div_out_dn_out"
572
573
atf_add_test_case "pr260867"
574
atf_add_test_case "pr260867_icmp"
575
}
576
577