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
39536 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
divert_init()
64
{
65
if ! kldstat -q -m ipdivert; then
66
atf_skip "This test requires ipdivert"
67
fi
68
}
69
70
dummynet_init()
71
{
72
if ! kldstat -q -m dummynet; then
73
atf_skip "This test requires dummynet"
74
fi
75
}
76
77
atf_test_case "in_div" "cleanup"
78
in_div_head()
79
{
80
atf_set descr 'Test inbound > diverted | divapp terminated'
81
atf_set require.user root
82
}
83
in_div_body()
84
{
85
pft_init
86
divert_init
87
88
epair=$(vnet_mkepair)
89
vnet_mkjail div ${epair}b
90
ifconfig ${epair}a 192.0.2.1/24 up
91
jexec div ifconfig ${epair}b 192.0.2.2/24 up
92
93
# Sanity check
94
atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
95
96
jexec div pfctl -e
97
pft_set_rules div \
98
"pass all" \
99
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000"
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 192.0.2.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
}
122
in_div_in_body()
123
{
124
pft_init
125
divert_init
126
127
epair=$(vnet_mkepair)
128
vnet_mkjail div ${epair}b
129
ifconfig ${epair}a 192.0.2.1/24 up
130
jexec div ifconfig ${epair}b 192.0.2.2/24 up
131
132
# Sanity check
133
atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
134
135
jexec div pfctl -e
136
pft_set_rules div \
137
"pass all" \
138
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000 no state"
139
140
jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &
141
divapp_pid=$!
142
# Wait for the divapp to be ready
143
sleep 1
144
145
# divapp is NOT expected to "eat" the packet
146
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
147
148
wait $divapp_pid
149
}
150
in_div_in_cleanup()
151
{
152
pft_cleanup
153
}
154
155
atf_test_case "out_div" "cleanup"
156
out_div_head()
157
{
158
atf_set descr 'Test outbound > diverted | divapp terminated'
159
atf_set require.user root
160
}
161
out_div_body()
162
{
163
pft_init
164
divert_init
165
166
epair=$(vnet_mkepair)
167
vnet_mkjail div ${epair}b
168
ifconfig ${epair}a 192.0.2.1/24 up
169
jexec div ifconfig ${epair}b 192.0.2.2/24 up
170
171
# Sanity check
172
atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
173
174
jexec div pfctl -e
175
pft_set_rules div \
176
"pass all" \
177
"pass in inet proto icmp icmp-type echoreq no state" \
178
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state"
179
180
jexec div $(atf_get_srcdir)/../common/divapp 2000 &
181
divapp_pid=$!
182
# Wait for the divapp to be ready
183
sleep 1
184
185
# divapp is expected to "eat" the packet
186
atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
187
188
wait $divapp_pid
189
}
190
out_div_cleanup()
191
{
192
pft_cleanup
193
}
194
195
atf_test_case "out_div_out" "cleanup"
196
out_div_out_head()
197
{
198
atf_set descr 'Test outbound > diverted > outbound | network terminated'
199
atf_set require.user root
200
}
201
out_div_out_body()
202
{
203
pft_init
204
divert_init
205
206
epair=$(vnet_mkepair)
207
vnet_mkjail div ${epair}b
208
ifconfig ${epair}a 192.0.2.1/24 up
209
jexec div ifconfig ${epair}b 192.0.2.2/24 up
210
211
# Sanity check
212
atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
213
214
jexec div pfctl -e
215
pft_set_rules div \
216
"pass all" \
217
"pass in inet proto icmp icmp-type echoreq no state" \
218
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state"
219
220
jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &
221
divapp_pid=$!
222
# Wait for the divapp to be ready
223
sleep 1
224
225
# divapp is NOT expected to "eat" the packet
226
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
227
228
wait $divapp_pid
229
}
230
out_div_out_cleanup()
231
{
232
pft_cleanup
233
}
234
235
atf_test_case "in_div_in_fwd_out_div_out" "cleanup"
236
in_div_in_fwd_out_div_out_head()
237
{
238
atf_set descr 'Test inbound > diverted > inbound > forwarded > outbound > diverted > outbound | network terminated'
239
atf_set require.user root
240
}
241
in_div_in_fwd_out_div_out_body()
242
{
243
pft_init
244
divert_init
245
246
# host <a--epair0--b> router <a--epair1--b> site
247
epair0=$(vnet_mkepair)
248
epair1=$(vnet_mkepair)
249
250
vnet_mkjail router ${epair0}b ${epair1}a
251
ifconfig ${epair0}a 192.0.2.1/24 up
252
jexec router sysctl net.inet.ip.forwarding=1
253
jexec router ifconfig ${epair0}b 192.0.2.2/24 up
254
jexec router ifconfig ${epair1}a 198.51.100.1/24 up
255
256
vnet_mkjail site ${epair1}b
257
jexec site ifconfig ${epair1}b 198.51.100.2/24 up
258
jexec site route add default 198.51.100.1
259
260
route add -net 198.51.100.0/24 192.0.2.2
261
262
# Sanity check
263
atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
264
265
# Should be routed without pf
266
atf_check -s exit:0 -o ignore ping -c3 198.51.100.2
267
268
jexec router pfctl -e
269
pft_set_rules router \
270
"pass all" \
271
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \
272
"pass out inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2002 no state"
273
274
jexec router $(atf_get_srcdir)/../common/divapp 2001 divert-back &
275
indivapp_pid=$!
276
jexec router $(atf_get_srcdir)/../common/divapp 2002 divert-back &
277
outdivapp_pid=$!
278
# Wait for the divappS to be ready
279
sleep 1
280
281
# Both divappS are NOT expected to "eat" the packet
282
atf_check -s exit:0 -o ignore ping -c1 198.51.100.2
283
284
wait $indivapp_pid && wait $outdivapp_pid
285
}
286
in_div_in_fwd_out_div_out_cleanup()
287
{
288
pft_cleanup
289
}
290
291
atf_test_case "in_dn_in_div_in_out_div_out_dn_out" "cleanup"
292
in_dn_in_div_in_out_div_out_dn_out_head()
293
{
294
atf_set descr 'Test inbound > delayed+diverted > outbound > diverted+delayed > outbound | network terminated'
295
atf_set require.user root
296
}
297
in_dn_in_div_in_out_div_out_dn_out_body()
298
{
299
pft_init
300
divert_init
301
dummynet_init
302
303
epair=$(vnet_mkepair)
304
vnet_mkjail alcatraz ${epair}b
305
ifconfig ${epair}a 192.0.2.1/24 up
306
ifconfig ${epair}a ether 02:00:00:00:00:01
307
jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
308
309
# Sanity check
310
atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
311
312
# a) ping should time out due to very narrow dummynet pipes {
313
314
jexec alcatraz dnctl pipe 1001 config bw 1Byte/s
315
jexec alcatraz dnctl pipe 1002 config bw 1Byte/s
316
317
jexec alcatraz pfctl -e
318
pft_set_rules alcatraz \
319
"ether pass in from 02:00:00:00:00:01 l3 all dnpipe 1001" \
320
"ether pass out to 02:00:00:00:00:01 l3 all dnpipe 1002 " \
321
"pass all" \
322
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 1001 no state" \
323
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 1002 no state"
324
325
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &
326
indivapp_pid=$!
327
jexec alcatraz $(atf_get_srcdir)/../common/divapp 1002 divert-back &
328
outdivapp_pid=$!
329
# Wait for the divappS to be ready
330
sleep 1
331
332
atf_check -s not-exit:0 -o ignore ping -c1 -s56 -t1 192.0.2.2
333
334
wait $indivapp_pid
335
atf_check_not_equal 0 $?
336
wait $outdivapp_pid
337
atf_check_not_equal 0 $?
338
339
# }
340
341
# b) ping should NOT time out due to wide enough dummynet pipes {
342
343
jexec alcatraz dnctl pipe 2001 config bw 100KByte/s
344
jexec alcatraz dnctl pipe 2002 config bw 100KByte/s
345
346
jexec alcatraz pfctl -e
347
pft_set_rules alcatraz \
348
"ether pass in from 02:00:00:00:00:01 l3 all dnpipe 2001" \
349
"ether pass out to 02:00:00:00:00:01 l3 all dnpipe 2002 " \
350
"pass all" \
351
"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \
352
"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2002 no state"
353
354
jexec alcatraz $(atf_get_srcdir)/../common/divapp 2001 divert-back &
355
indivapp_pid=$!
356
jexec alcatraz $(atf_get_srcdir)/../common/divapp 2002 divert-back &
357
outdivapp_pid=$!
358
# Wait for the divappS to be ready
359
sleep 1
360
361
atf_check -s exit:0 -o ignore ping -c1 -s56 -t1 192.0.2.2
362
363
wait $indivapp_pid
364
atf_check_equal 0 $?
365
wait $outdivapp_pid
366
atf_check_equal 0 $?
367
368
# }
369
}
370
in_dn_in_div_in_out_div_out_dn_out_cleanup()
371
{
372
pft_cleanup
373
}
374
375
atf_init_test_cases()
376
{
377
atf_add_test_case "in_div"
378
atf_add_test_case "in_div_in"
379
380
atf_add_test_case "out_div"
381
atf_add_test_case "out_div_out"
382
383
atf_add_test_case "in_div_in_fwd_out_div_out"
384
385
atf_add_test_case "in_dn_in_div_in_out_div_out_dn_out"
386
}
387
388