Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netpfil/pf/nat.sh
39507 views
1
#
2
# SPDX-License-Identifier: BSD-2-Clause
3
#
4
# Copyright (c) 2018 Kristof Provost <[email protected]>
5
# Copyright (c) 2025 Kajetan Staszkiewicz <[email protected]>
6
# Copyright (c) 2021 KUROSAWA Takahiro <[email protected]>
7
#
8
# Redistribution and use in source and binary forms, with or without
9
# modification, are permitted provided that the following conditions
10
# are met:
11
# 1. Redistributions of source code must retain the above copyright
12
# notice, this list of conditions and the following disclaimer.
13
# 2. Redistributions in binary form must reproduce the above copyright
14
# notice, this list of conditions and the following disclaimer in the
15
# documentation and/or other materials provided with the distribution.
16
#
17
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
# SUCH DAMAGE.
28
29
. $(atf_get_srcdir)/utils.subr
30
31
atf_test_case "exhaust" "cleanup"
32
exhaust_head()
33
{
34
atf_set descr 'Test exhausting the NAT pool'
35
atf_set require.user root
36
}
37
38
exhaust_body()
39
{
40
pft_init
41
42
epair_nat=$(vnet_mkepair)
43
epair_echo=$(vnet_mkepair)
44
45
vnet_mkjail nat ${epair_nat}b ${epair_echo}a
46
vnet_mkjail echo ${epair_echo}b
47
48
ifconfig ${epair_nat}a 192.0.2.2/24 up
49
route add -net 198.51.100.0/24 192.0.2.1
50
51
jexec nat ifconfig ${epair_nat}b 192.0.2.1/24 up
52
jexec nat ifconfig ${epair_echo}a 198.51.100.1/24 up
53
jexec nat sysctl net.inet.ip.forwarding=1
54
55
jexec echo ifconfig ${epair_echo}b 198.51.100.2/24 up
56
jexec echo /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf
57
58
# Enable pf!
59
jexec nat pfctl -e
60
pft_set_rules nat \
61
"nat pass on ${epair_echo}a inet from 192.0.2.0/24 to any -> (${epair_echo}a) port 30000:30001 sticky-address"
62
63
# Sanity check
64
atf_check -s exit:0 -o ignore ping -c 3 198.51.100.2
65
66
atf_check -s exit:0 -o match:foo* echo "foo" | nc -N 198.51.100.2 7
67
atf_check -s exit:0 -o match:foo* echo "foo" | nc -N 198.51.100.2 7
68
69
# This one will fail, but that's expected
70
echo "foo" | nc -N 198.51.100.2 7 &
71
72
sleep 1
73
74
# If the kernel is stuck in pf_get_sport() this will not succeed either.
75
timeout 2 jexec nat pfctl -sa
76
if [ $? -eq 124 ]; then
77
# Timed out
78
atf_fail "pfctl timeout"
79
fi
80
}
81
82
exhaust_cleanup()
83
{
84
pft_cleanup
85
}
86
87
atf_test_case "nested_anchor" "cleanup"
88
nested_anchor_head()
89
{
90
atf_set descr 'Test setting and retrieving nested nat anchors'
91
atf_set require.user root
92
}
93
94
nested_anchor_body()
95
{
96
pft_init
97
98
epair=$(vnet_mkepair)
99
100
vnet_mkjail nat ${epair}a
101
102
pft_set_rules nat \
103
"nat-anchor \"foo\""
104
105
echo "nat-anchor \"bar\"" | jexec nat pfctl -g -a foo -f -
106
echo "nat on ${epair}a from any to any -> (${epair}a)" | jexec nat pfctl -g -a "foo/bar" -f -
107
108
atf_check -s exit:0 -o inline:"nat-anchor \"foo\" all {
109
nat-anchor \"bar\" all {
110
nat on ${epair}a all -> (${epair}a) round-robin
111
}
112
}
113
" jexec nat pfctl -sn -a "*"
114
115
}
116
117
endpoint_independent_setup()
118
{
119
pft_init
120
filter="udp and dst port 1234" # only capture udp pings
121
122
epair_client=$(vnet_mkepair)
123
epair_nat=$(vnet_mkepair)
124
epair_server1=$(vnet_mkepair)
125
epair_server2=$(vnet_mkepair)
126
bridge=$(vnet_mkbridge)
127
128
vnet_mkjail nat ${epair_client}b ${epair_nat}a
129
vnet_mkjail client ${epair_client}a
130
vnet_mkjail server1 ${epair_server1}a
131
vnet_mkjail server2 ${epair_server2}a
132
133
ifconfig ${epair_server1}b up
134
ifconfig ${epair_server2}b up
135
ifconfig ${epair_nat}b up
136
ifconfig ${bridge} \
137
addm ${epair_server1}b \
138
addm ${epair_server2}b \
139
addm ${epair_nat}b \
140
up
141
142
jexec nat ifconfig ${epair_client}b 192.0.2.1/24 up
143
jexec nat ifconfig ${epair_nat}a 198.51.100.42/24 up
144
jexec nat sysctl net.inet.ip.forwarding=1
145
146
jexec client ifconfig ${epair_client}a 192.0.2.2/24 up
147
jexec client route add default 192.0.2.1
148
149
jexec server1 ifconfig ${epair_server1}a 198.51.100.32/24 up
150
jexec server2 ifconfig ${epair_server2}a 198.51.100.22/24 up
151
}
152
153
endpoint_independent_common()
154
{
155
# Enable pf!
156
jexec nat pfctl -e
157
158
# validate non-endpoint independent nat rule behaviour
159
pft_set_rules nat "${1}"
160
161
jexec server1 tcpdump -i ${epair_server1}a -w ${PWD}/server1.pcap \
162
--immediate-mode $filter &
163
server1tcppid="$!"
164
jexec server2 tcpdump -i ${epair_server2}a -w ${PWD}/server2.pcap \
165
--immediate-mode $filter &
166
server2tcppid="$!"
167
168
# send out multiple packets
169
for i in $(seq 1 10); do
170
echo "ping" | jexec client nc -u 198.51.100.32 1234 -p 4242 -w 0
171
echo "ping" | jexec client nc -u 198.51.100.22 1234 -p 4242 -w 0
172
done
173
174
kill $server1tcppid
175
kill $server2tcppid
176
177
tuple_server1=$(tcpdump -r ${PWD}/server1.pcap | awk '{addr=$3} END {print addr}')
178
tuple_server2=$(tcpdump -r ${PWD}/server2.pcap | awk '{addr=$3} END {print addr}')
179
180
if [ -z $tuple_server1 ]
181
then
182
atf_fail "server1 did not receive connection from client (default)"
183
fi
184
185
if [ -z $tuple_server2 ]
186
then
187
atf_fail "server2 did not receive connection from client (default)"
188
fi
189
190
if [ "$tuple_server1" = "$tuple_server2" ]
191
then
192
echo "server1 tcpdump: $tuple_server1"
193
echo "server2 tcpdump: $tuple_server2"
194
atf_fail "Received same IP:port on server1 and server2 (default)"
195
fi
196
197
# validate endpoint independent nat rule behaviour
198
pft_set_rules nat "${2}"
199
200
jexec server1 tcpdump -i ${epair_server1}a -w ${PWD}/server1.pcap \
201
--immediate-mode $filter &
202
server1tcppid="$!"
203
jexec server2 tcpdump -i ${epair_server2}a -w ${PWD}/server2.pcap \
204
--immediate-mode $filter &
205
server2tcppid="$!"
206
207
# send out multiple packets, sometimes one fails to go through
208
for i in $(seq 1 10); do
209
echo "ping" | jexec client nc -u 198.51.100.32 1234 -p 4242 -w 0
210
echo "ping" | jexec client nc -u 198.51.100.22 1234 -p 4242 -w 0
211
done
212
213
kill $server1tcppid
214
kill $server2tcppid
215
216
tuple_server1=$(tcpdump -r ${PWD}/server1.pcap | awk '{addr=$3} END {print addr}')
217
tuple_server2=$(tcpdump -r ${PWD}/server2.pcap | awk '{addr=$3} END {print addr}')
218
219
if [ -z $tuple_server1 ]
220
then
221
atf_fail "server1 did not receive connection from client (endpoint-independent)"
222
fi
223
224
if [ -z $tuple_server2 ]
225
then
226
atf_fail "server2 did not receive connection from client (endpoint-independent)"
227
fi
228
229
if [ ! "$tuple_server1" = "$tuple_server2" ]
230
then
231
echo "server1 tcpdump: $tuple_server1"
232
echo "server2 tcpdump: $tuple_server2"
233
atf_fail "Received different IP:port on server1 than server2 (endpoint-independent)"
234
fi
235
}
236
237
atf_test_case "endpoint_independent_compat" "cleanup"
238
endpoint_independent_compat_head()
239
{
240
atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers'
241
atf_set require.user root
242
}
243
244
endpoint_independent_compat_body()
245
{
246
endpoint_independent_setup # Sets ${epair_…} variables
247
248
endpoint_independent_common \
249
"nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a)" \
250
"nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a) endpoint-independent"
251
}
252
253
endpoint_independent_compat_cleanup()
254
{
255
pft_cleanup
256
rm -f server1.out
257
rm -f server2.out
258
}
259
260
atf_test_case "endpoint_independent_pass" "cleanup"
261
endpoint_independent_pass_head()
262
{
263
atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers'
264
atf_set require.user root
265
}
266
267
endpoint_independent_pass_body()
268
{
269
endpoint_independent_setup # Sets ${epair_…} variables
270
271
endpoint_independent_common \
272
"pass out on ${epair_nat}a inet from ! (${epair_nat}a) to any nat-to (${epair_nat}a) keep state" \
273
"pass out on ${epair_nat}a inet from ! (${epair_nat}a) to any nat-to (${epair_nat}a) endpoint-independent keep state"
274
275
}
276
277
endpoint_independent_pass_cleanup()
278
{
279
pft_cleanup
280
rm -f server1.out
281
rm -f server2.out
282
}
283
284
nested_anchor_cleanup()
285
{
286
pft_cleanup
287
}
288
289
atf_test_case "nat6_nolinklocal" "cleanup"
290
nat6_nolinklocal_head()
291
{
292
atf_set descr 'Ensure we do not use link-local addresses'
293
atf_set require.user root
294
}
295
296
nat6_nolinklocal_body()
297
{
298
pft_init
299
300
epair_nat=$(vnet_mkepair)
301
epair_echo=$(vnet_mkepair)
302
303
vnet_mkjail nat ${epair_nat}b ${epair_echo}a
304
vnet_mkjail echo ${epair_echo}b
305
306
ifconfig ${epair_nat}a inet6 2001:db8::2/64 no_dad up
307
route add -6 -net 2001:db8:1::/64 2001:db8::1
308
309
jexec nat ifconfig ${epair_nat}b inet6 2001:db8::1/64 no_dad up
310
jexec nat ifconfig ${epair_echo}a inet6 2001:db8:1::1/64 no_dad up
311
jexec nat sysctl net.inet6.ip6.forwarding=1
312
313
jexec echo ifconfig ${epair_echo}b inet6 2001:db8:1::2/64 no_dad up
314
# Ensure we can't reply to link-local pings
315
jexec echo pfctl -e
316
pft_set_rules echo \
317
"pass" \
318
"block in inet6 proto icmp6 from fe80::/10 to any icmp6-type echoreq"
319
320
jexec nat pfctl -e
321
pft_set_rules nat \
322
"nat pass on ${epair_echo}a inet6 from 2001:db8::/64 to any -> (${epair_echo}a)" \
323
"pass"
324
325
# Sanity check
326
atf_check -s exit:0 -o ignore \
327
ping -6 -c 1 2001:db8::1
328
for i in `seq 0 10`
329
do
330
atf_check -s exit:0 -o ignore \
331
ping -6 -c 1 2001:db8:1::2
332
done
333
}
334
335
nat6_nolinklocal_cleanup()
336
{
337
pft_cleanup
338
}
339
340
empty_table_common()
341
{
342
option=$1
343
344
pft_init
345
346
epair_wan=$(vnet_mkepair)
347
epair_lan=$(vnet_mkepair)
348
349
vnet_mkjail srv ${epair_wan}a
350
jexec srv ifconfig ${epair_wan}a 192.0.2.2/24 up
351
352
vnet_mkjail rtr ${epair_wan}b ${epair_lan}a
353
jexec rtr ifconfig ${epair_wan}b 192.0.2.1/24 up
354
jexec rtr ifconfig ${epair_lan}a 198.51.100.1/24 up
355
jexec rtr sysctl net.inet.ip.forwarding=1
356
357
ifconfig ${epair_lan}b 198.51.100.2/24 up
358
route add default 198.51.100.1
359
360
jexec rtr pfctl -e
361
pft_set_rules rtr \
362
"table <empty>" \
363
"nat on ${epair_wan}b inet from 198.51.100.0/24 -> <empty> ${option}" \
364
"pass"
365
366
# Sanity checks
367
atf_check -s exit:0 -o ignore \
368
jexec rtr ping -c 1 192.0.2.2
369
atf_check -s exit:0 -o ignore \
370
ping -c 1 198.51.100.1
371
atf_check -s exit:0 -o ignore \
372
ping -c 1 192.0.2.1
373
374
# Provoke divide by zero
375
ping -c 1 192.0.2.2
376
true
377
}
378
379
atf_test_case "empty_table_source_hash" "cleanup"
380
empty_table_source_hash_head()
381
{
382
atf_set descr 'Test source-hash on an emtpy table'
383
atf_set require.user root
384
}
385
386
empty_table_source_hash_body()
387
{
388
empty_table_common "source-hash"
389
}
390
391
empty_table_source_hash_cleanup()
392
{
393
pft_cleanup
394
}
395
396
atf_test_case "empty_table_random" "cleanup"
397
empty_table_random_head()
398
{
399
atf_set descr 'Test random on an emtpy table'
400
atf_set require.user root
401
}
402
403
empty_table_random_body()
404
{
405
empty_table_common "random"
406
}
407
408
empty_table_random_cleanup()
409
{
410
pft_cleanup
411
}
412
413
no_addrs_common()
414
{
415
option=$1
416
417
pft_init
418
419
epair_wan=$(vnet_mkepair)
420
epair_lan=$(vnet_mkepair)
421
422
vnet_mkjail srv ${epair_wan}a
423
jexec srv ifconfig ${epair_wan}a 192.0.2.2/24 up
424
425
vnet_mkjail rtr ${epair_wan}b ${epair_lan}a
426
jexec rtr route add -net 192.0.2.0/24 -iface ${epair_wan}b
427
jexec rtr ifconfig ${epair_lan}a 198.51.100.1/24 up
428
jexec rtr sysctl net.inet.ip.forwarding=1
429
430
ifconfig ${epair_lan}b 198.51.100.2/24 up
431
route add default 198.51.100.1
432
433
jexec rtr pfctl -e
434
pft_set_rules rtr \
435
"nat on ${epair_wan}b inet from 198.51.100.0/24 -> (${epair_wan}b) ${option}" \
436
"pass"
437
438
# Provoke divide by zero
439
ping -c 1 192.0.2.2
440
true
441
}
442
443
atf_test_case "no_addrs_source_hash" "cleanup"
444
no_addrs_source_hash_head()
445
{
446
atf_set descr 'Test source-hash on an interface with no addresses'
447
atf_set require.user root
448
}
449
450
no_addrs_source_hash_body()
451
{
452
no_addrs_common "source-hash"
453
}
454
455
no_addrs_source_hash_cleanup()
456
{
457
pft_cleanup
458
}
459
460
atf_test_case "no_addrs_random" "cleanup"
461
no_addrs_random_head()
462
{
463
atf_set descr 'Test random on an interface with no addresses'
464
atf_set require.user root
465
}
466
467
no_addrs_random_body()
468
{
469
no_addrs_common "random"
470
}
471
472
no_addrs_random_cleanup()
473
{
474
pft_cleanup
475
}
476
477
nat_pass_head()
478
{
479
atf_set descr 'IPv4 NAT on pass rule'
480
atf_set require.user root
481
atf_set require.progs scapy
482
}
483
484
nat_pass_body()
485
{
486
setup_router_server_ipv4
487
# Delete the route back to make sure that the traffic has been NAT-ed
488
jexec server route del -net ${net_tester} ${net_server_host_router}
489
490
pft_set_rules router \
491
"block" \
492
"pass in on ${epair_tester}b inet proto tcp keep state" \
493
"pass out on ${epair_server}a inet proto tcp nat-to ${epair_server}a keep state"
494
495
ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
496
497
jexec router pfctl -qvvsr
498
jexec router pfctl -qvvss
499
jexec router ifconfig
500
jexec router netstat -rn
501
}
502
503
nat_pass_cleanup()
504
{
505
pft_cleanup
506
}
507
508
nat_match_head()
509
{
510
atf_set descr 'IPv4 NAT on match rule'
511
atf_set require.user root
512
atf_set require.progs scapy
513
}
514
515
nat_match_body()
516
{
517
setup_router_server_ipv4
518
# Delete the route back to make sure that the traffic has been NAT-ed
519
jexec server route del -net ${net_tester} ${net_server_host_router}
520
521
# NAT is applied during ruleset evaluation:
522
# rules after "match" match on NAT-ed address
523
pft_set_rules router \
524
"block" \
525
"pass in on ${epair_tester}b inet proto tcp keep state" \
526
"match out on ${epair_server}a inet proto tcp nat-to ${epair_server}a" \
527
"pass out on ${epair_server}a inet proto tcp from ${epair_server}a keep state"
528
529
ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
530
531
jexec router pfctl -qvvsr
532
jexec router pfctl -qvvss
533
jexec router ifconfig
534
jexec router netstat -rn
535
}
536
537
nat_match_cleanup()
538
{
539
pft_cleanup
540
}
541
542
map_e_common()
543
{
544
NC_TRY_COUNT=12
545
546
pft_init
547
548
epair_map_e=$(vnet_mkepair)
549
epair_echo=$(vnet_mkepair)
550
551
vnet_mkjail map_e ${epair_map_e}b ${epair_echo}a
552
vnet_mkjail echo ${epair_echo}b
553
554
ifconfig ${epair_map_e}a 192.0.2.2/24 up
555
route add -net 198.51.100.0/24 192.0.2.1
556
557
jexec map_e ifconfig ${epair_map_e}b 192.0.2.1/24 up
558
jexec map_e ifconfig ${epair_echo}a 198.51.100.1/24 up
559
jexec map_e sysctl net.inet.ip.forwarding=1
560
561
jexec echo ifconfig ${epair_echo}b 198.51.100.2/24 up
562
jexec echo /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf
563
564
# Enable pf!
565
jexec map_e pfctl -e
566
}
567
568
atf_test_case "map_e_compat" "cleanup"
569
map_e_compat_head()
570
{
571
atf_set descr 'map-e-portset test'
572
atf_set require.user root
573
}
574
575
map_e_compat_body()
576
{
577
map_e_common
578
579
pft_set_rules map_e \
580
"nat pass on ${epair_echo}a inet from 192.0.2.0/24 to any -> (${epair_echo}a) map-e-portset 2/12/0x342"
581
582
# Only allow specified ports.
583
jexec echo pfctl -e
584
pft_set_rules echo "block return all" \
585
"pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 19720:19723 to (${epair_echo}b) port 7" \
586
"pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 36104:36107 to (${epair_echo}b) port 7" \
587
"pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 52488:52491 to (${epair_echo}b) port 7" \
588
"set skip on lo"
589
590
i=0
591
while [ ${i} -lt ${NC_TRY_COUNT} ]
592
do
593
echo "foo ${i}" | timeout 2 nc -N 198.51.100.2 7
594
if [ $? -ne 0 ]; then
595
atf_fail "nc failed (${i})"
596
fi
597
i=$((${i}+1))
598
done
599
}
600
601
map_e_compat_cleanup()
602
{
603
pft_cleanup
604
}
605
606
607
atf_test_case "map_e_pass" "cleanup"
608
map_e_pass_head()
609
{
610
atf_set descr 'map-e-portset test'
611
atf_set require.user root
612
}
613
614
map_e_pass_body()
615
{
616
map_e_common
617
618
pft_set_rules map_e \
619
"pass out on ${epair_echo}a inet from 192.0.2.0/24 to any nat-to (${epair_echo}a) map-e-portset 2/12/0x342 keep state"
620
621
jexec map_e pfctl -qvvsr
622
623
# Only allow specified ports.
624
jexec echo pfctl -e
625
pft_set_rules echo "block return all" \
626
"pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 19720:19723 to (${epair_echo}b) port 7" \
627
"pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 36104:36107 to (${epair_echo}b) port 7" \
628
"pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 52488:52491 to (${epair_echo}b) port 7" \
629
"set skip on lo"
630
631
i=0
632
while [ ${i} -lt ${NC_TRY_COUNT} ]
633
do
634
echo "foo ${i}" | timeout 2 nc -N 198.51.100.2 7
635
if [ $? -ne 0 ]; then
636
atf_fail "nc failed (${i})"
637
fi
638
i=$((${i}+1))
639
done
640
}
641
642
map_e_pass_cleanup()
643
{
644
pft_cleanup
645
}
646
647
binat_compat_head()
648
{
649
atf_set descr 'IPv4 BINAT with nat ruleset'
650
atf_set require.user root
651
atf_set require.progs scapy
652
}
653
654
binat_compat_body()
655
{
656
setup_router_server_ipv4
657
# Delete the route back to make sure that the traffic has been NAT-ed
658
jexec server route del -net ${net_tester} ${net_server_host_router}
659
660
pft_set_rules router \
661
"set state-policy if-bound" \
662
"set ruleset-optimization none" \
663
"binat on ${epair_server}a inet proto tcp from ${net_tester_host_tester} to any tag sometag -> ${epair_server}a" \
664
"block" \
665
"pass in on ${epair_tester}b inet proto tcp !tagged sometag keep state" \
666
"pass out on ${epair_server}a inet proto tcp tagged sometag keep state" \
667
"pass in on ${epair_server}a inet proto tcp tagged sometag keep state" \
668
"pass out on ${epair_tester}b inet proto tcp tagged sometag keep state"
669
670
# Test the outbound NAT part of BINAT.
671
ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
672
673
states=$(mktemp) || exit 1
674
jexec router pfctl -qvss | normalize_pfctl_s > $states
675
676
for state_regexp in \
677
"${epair_tester}b tcp ${net_server_host_server}:9 <- ${net_tester_host_tester}:4201 .* 3:2 pkts,.* rule 1" \
678
"${epair_server}a tcp ${net_server_host_router}:4201 \(${net_tester_host_tester}:4201\) -> ${net_server_host_server}:9 .* 3:2 pkts,.* rule 2" \
679
; do
680
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
681
done
682
683
# Test the inbound RDR part of BINAT.
684
# The "tester" becomes "server" and vice versa.
685
inetd_conf=$(mktemp)
686
echo "discard stream tcp nowait root internal" > $inetd_conf
687
inetd -p ${PWD}/inetd_tester.pid $inetd_conf
688
689
atf_check -s exit:0 \
690
jexec server ${common_dir}/pft_ping.py \
691
--ping-type=tcp3way --send-sport=4202 \
692
--sendif ${epair_server}b \
693
--to ${net_server_host_router} \
694
--replyif ${epair_server}b
695
696
states=$(mktemp) || exit 1
697
jexec router pfctl -qvss | normalize_pfctl_s > $states
698
699
for state_regexp in \
700
"${epair_server}a tcp ${net_tester_host_tester}:9 \(${net_server_host_router}:9\) <- ${net_server_host_server}:4202 .* 3:2 pkts,.* rule 3" \
701
"${epair_tester}b tcp ${net_server_host_server}:4202 -> ${net_tester_host_tester}:9 .* 3:2 pkts,.* rule 4" \
702
; do
703
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
704
done
705
}
706
707
binat_compat_cleanup()
708
{
709
pft_cleanup
710
kill $(cat ${PWD}/inetd_tester.pid)
711
}
712
713
binat_match_head()
714
{
715
atf_set descr 'IPv4 BINAT with nat ruleset'
716
atf_set require.user root
717
atf_set require.progs scapy
718
}
719
720
binat_match_body()
721
{
722
setup_router_server_ipv4
723
# Delete the route back to make sure that the traffic has been NAT-ed
724
jexec server route del -net ${net_tester} ${net_server_host_router}
725
726
# The "binat-to" rule expands to 2 rules so the ""pass" rules start at 3!
727
pft_set_rules router \
728
"set state-policy if-bound" \
729
"set ruleset-optimization none" \
730
"block" \
731
"match on ${epair_server}a inet proto tcp from ${net_tester_host_tester} to any tag sometag binat-to ${epair_server}a" \
732
"pass in on ${epair_tester}b inet proto tcp !tagged sometag keep state" \
733
"pass out on ${epair_server}a inet proto tcp tagged sometag keep state" \
734
"pass in on ${epair_server}a inet proto tcp tagged sometag keep state" \
735
"pass out on ${epair_tester}b inet proto tcp tagged sometag keep state"
736
737
# Test the outbound NAT part of BINAT.
738
ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
739
740
states=$(mktemp) || exit 1
741
jexec router pfctl -qvss | normalize_pfctl_s > $states
742
743
for state_regexp in \
744
"${epair_tester}b tcp ${net_server_host_server}:9 <- ${net_tester_host_tester}:4201 .* 3:2 pkts,.* rule 3" \
745
"${epair_server}a tcp ${net_server_host_router}:4201 \(${net_tester_host_tester}:4201\) -> ${net_server_host_server}:9 .* 3:2 pkts,.* rule 4" \
746
; do
747
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
748
done
749
750
# Test the inbound RDR part of BINAT.
751
# The "tester" becomes "server" and vice versa.
752
inetd_conf=$(mktemp)
753
echo "discard stream tcp nowait root internal" > $inetd_conf
754
inetd -p ${PWD}/inetd_tester.pid $inetd_conf
755
756
atf_check -s exit:0 \
757
jexec server ${common_dir}/pft_ping.py \
758
--ping-type=tcp3way --send-sport=4202 \
759
--sendif ${epair_server}b \
760
--to ${net_server_host_router} \
761
--replyif ${epair_server}b
762
763
states=$(mktemp) || exit 1
764
jexec router pfctl -qvss | normalize_pfctl_s > $states
765
766
for state_regexp in \
767
"${epair_server}a tcp ${net_tester_host_tester}:9 \(${net_server_host_router}:9\) <- ${net_server_host_server}:4202 .* 3:2 pkts,.* rule 5" \
768
"${epair_tester}b tcp ${net_server_host_server}:4202 -> ${net_tester_host_tester}:9 .* 3:2 pkts,.* rule 6" \
769
; do
770
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
771
done
772
}
773
774
binat_match_cleanup()
775
{
776
pft_cleanup
777
kill $(cat ${PWD}/inetd_tester.pid)
778
}
779
780
atf_test_case "empty_pool" "cleanup"
781
empty_pool_head()
782
{
783
atf_set descr 'NAT with empty pool'
784
atf_set require.user root
785
atf_set require.progs python3 scapy
786
}
787
788
empty_pool_body()
789
{
790
pft_init
791
setup_router_server_ipv6
792
793
794
pft_set_rules router \
795
"block" \
796
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
797
"pass in on ${epair_tester}b" \
798
"pass out on ${epair_server}a inet6 from any to ${net_server_host_server} nat-to <nonexistent>" \
799
800
# pf_map_addr_sn() won't be able to pick a target address, because
801
# the table used in redireciton pool is empty. Packet will not be
802
# forwarded, error counter will be increased.
803
ping_server_check_reply exit:1
804
# Ignore warnings about not-loaded ALTQ
805
atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null"
806
}
807
808
empty_pool_cleanup()
809
{
810
pft_cleanup
811
}
812
813
atf_test_case "dummynet_mask" "cleanup"
814
dummynet_mask_head()
815
{
816
atf_set descr 'Verify that dummynet uses the pre-nat address for masking'
817
atf_set require.user root
818
}
819
820
dummynet_mask_body()
821
{
822
dummynet_init
823
824
epair_srv=$(vnet_mkepair)
825
epair_cl=$(vnet_mkepair)
826
827
ifconfig ${epair_cl}b 192.0.2.2/24 up
828
route add default 192.0.2.1
829
830
vnet_mkjail srv ${epair_srv}a
831
jexec srv ifconfig ${epair_srv}a 198.51.100.2/24 up
832
833
vnet_mkjail gw ${epair_srv}b ${epair_cl}a
834
jexec gw ifconfig ${epair_srv}b 198.51.100.1/24 up
835
jexec gw ifconfig ${epair_cl}a 192.0.2.1/24 up
836
jexec gw sysctl net.inet.ip.forwarding=1
837
838
jexec gw dnctl pipe 1 config delay 100 mask src-ip 0xffffff00
839
jexec gw pfctl -e
840
pft_set_rules gw \
841
"nat on ${epair_srv}b inet from 192.0.2.0/24 to any -> (${epair_srv}b)" \
842
"pass out dnpipe 1"
843
844
atf_check -s exit:0 -o ignore \
845
ping -c 3 198.51.100.2
846
847
# Now check that dummynet looked at the correct address
848
atf_check -s exit:0 -o match:"ip.*192.0.2.0/0" \
849
jexec gw dnctl pipe show
850
}
851
852
dummynet_mask_cleanup()
853
{
854
pft_cleanup
855
}
856
857
atf_init_test_cases()
858
{
859
atf_add_test_case "exhaust"
860
atf_add_test_case "nested_anchor"
861
atf_add_test_case "endpoint_independent_compat"
862
atf_add_test_case "endpoint_independent_pass"
863
atf_add_test_case "nat6_nolinklocal"
864
atf_add_test_case "empty_table_source_hash"
865
atf_add_test_case "no_addrs_source_hash"
866
atf_add_test_case "empty_table_random"
867
atf_add_test_case "no_addrs_random"
868
atf_add_test_case "map_e_compat"
869
atf_add_test_case "map_e_pass"
870
atf_add_test_case "nat_pass"
871
atf_add_test_case "nat_match"
872
atf_add_test_case "binat_compat"
873
atf_add_test_case "binat_match"
874
atf_add_test_case "empty_pool"
875
atf_add_test_case "dummynet_mask"
876
}
877
878