Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netpfil/pf/nat64.sh
39536 views
1
#
2
# SPDX-License-Identifier: BSD-2-Clause
3
#
4
# Copyright (c) 2024 Rubicon Communications, LLC (Netgate)
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
nat64_setup_base()
30
{
31
pft_init
32
33
epair_link=$(vnet_mkepair)
34
epair=$(vnet_mkepair)
35
36
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
37
route -6 add default 2001:db8::1
38
39
vnet_mkjail rtr ${epair}b ${epair_link}a
40
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
41
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
42
43
vnet_mkjail dst ${epair_link}b
44
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
45
jexec dst route add default 192.0.2.1
46
47
# Sanity checks
48
atf_check -s exit:0 -o ignore \
49
ping6 -c 1 2001:db8::1
50
atf_check -s exit:0 -o ignore \
51
jexec dst ping -c 1 192.0.2.1
52
53
jexec rtr pfctl -e
54
}
55
56
nat64_setup_in()
57
{
58
state_policy="${1:-if-bound}"
59
nat64_setup_base
60
pft_set_rules rtr \
61
"set reassemble yes" \
62
"set state-policy ${state_policy}" \
63
"block" \
64
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
65
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_link}a)"
66
}
67
68
nat64_setup_out()
69
{
70
state_policy="${1:-if-bound}"
71
nat64_setup_base
72
jexec rtr sysctl net.inet6.ip6.forwarding=1
73
# AF translation happens post-routing, traffic must be directed
74
# towards the outbound interface using routes for the original AF.
75
# jexec rtr ifconfig ${epair_link}a inet6 2001:db8:2::1/64 up no_dad
76
jexec rtr route add -inet6 64:ff9b::/96 -iface ${epair_link}a;
77
pft_set_rules rtr \
78
"set reassemble yes" \
79
"set state-policy ${state_policy}" \
80
"block" \
81
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
82
"pass in on ${epair}b from any to 64:ff9b::/96" \
83
"pass out on ${epair_link}a from any to 64:ff9b::/96 af-to inet from (${epair_link}a)"
84
}
85
86
atf_test_case "icmp_echo_in" "cleanup"
87
icmp_echo_in_head()
88
{
89
atf_set descr 'Basic NAT64 ICMP echo test on inbound interface'
90
atf_set require.user root
91
}
92
93
icmp_echo_in_body()
94
{
95
nat64_setup_in
96
97
# One ping
98
atf_check -s exit:0 -o ignore \
99
ping6 -c 1 64:ff9b::192.0.2.2
100
101
# Make sure packets make it even when state is established
102
atf_check -s exit:0 \
103
-o match:'5 packets transmitted, 5 packets received, 0.0% packet loss' \
104
ping6 -c 5 64:ff9b::192.0.2.2
105
}
106
107
icmp_echo_in_cleanup()
108
{
109
pft_cleanup
110
}
111
112
atf_test_case "icmp_echo_out" "cleanup"
113
icmp_echo_out_head()
114
{
115
atf_set descr 'Basic NAT64 ICMP echo test on outbound interface'
116
atf_set require.user root
117
}
118
119
icmp_echo_out_body()
120
{
121
nat64_setup_out
122
123
# One ping
124
atf_check -s exit:0 -o ignore \
125
ping6 -c 1 64:ff9b::192.0.2.2
126
127
# Make sure packets make it even when state is established
128
atf_check -s exit:0 \
129
-o match:'5 packets transmitted, 5 packets received, 0.0% packet loss' \
130
ping6 -c 5 64:ff9b::192.0.2.2
131
}
132
133
icmp_echo_out_cleanup()
134
{
135
pft_cleanup
136
}
137
138
atf_test_case "fragmentation_in" "cleanup"
139
fragmentation_in_head()
140
{
141
atf_set descr 'Test fragmented packets on inbound interface'
142
atf_set require.user root
143
}
144
145
fragmentation_in_body()
146
{
147
nat64_setup_in
148
149
atf_check -s exit:0 -o ignore \
150
ping6 -c 1 -s 1280 64:ff9b::192.0.2.2
151
152
atf_check -s exit:0 \
153
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
154
ping6 -c 3 -s 2000 64:ff9b::192.0.2.2
155
atf_check -s exit:0 \
156
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
157
ping6 -c 3 -s 10000 -b 20000 64:ff9b::192.0.2.2
158
}
159
160
fragmentation_in_cleanup()
161
{
162
pft_cleanup
163
}
164
165
atf_test_case "fragmentation_out" "cleanup"
166
fragmentation_out_head()
167
{
168
atf_set descr 'Test fragmented packets on outbound interface'
169
atf_set require.user root
170
}
171
172
fragmentation_out_body()
173
{
174
nat64_setup_out
175
176
atf_check -s exit:0 -o ignore \
177
ping6 -c 1 -s 1280 64:ff9b::192.0.2.2
178
179
atf_check -s exit:0 \
180
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
181
ping6 -c 3 -s 2000 64:ff9b::192.0.2.2
182
atf_check -s exit:0 \
183
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
184
ping6 -c 3 -s 10000 -b 20000 64:ff9b::192.0.2.2
185
}
186
187
fragmentation_out_cleanup()
188
{
189
pft_cleanup
190
}
191
192
atf_test_case "tcp_in_if_bound" "cleanup"
193
tcp_in_if_bound_head()
194
{
195
atf_set descr 'TCP NAT64 test on inbound interface, if-bound states'
196
atf_set require.user root
197
}
198
199
tcp_in_if_bound_body()
200
{
201
nat64_setup_in
202
203
echo "foo" | jexec dst nc -l 1234 &
204
205
# Sanity check & delay for nc startup
206
atf_check -s exit:0 -o ignore \
207
ping6 -c 3 64:ff9b::192.0.2.2
208
209
rcv=$(nc -w 3 -6 64:ff9b::c000:202 1234)
210
if [ "${rcv}" != "foo" ];
211
then
212
echo "rcv=${rcv}"
213
atf_fail "Failed to connect to TCP server"
214
fi
215
216
sleep 1
217
218
# Interfaces of the state are reversed when doing inbound NAT64!
219
# FIXME: Packets from both directions are counted only on the inbound direction!
220
states=$(mktemp) || exit 1
221
jexec rtr pfctl -qvvss | normalize_pfctl_s > $states
222
for state_regexp in \
223
"${epair_link}a tcp 192.0.2.1:[0-9]+ \(2001:db8::2\[[0-9]+\]\) -> 192.0.2.2:1234 \(64:ff9b::c000:202\[1234\]\) .* 5:4 pkts.* rule 3 .* origif: ${epair}b" \
224
; do
225
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
226
done
227
[ $(cat $states | grep tcp | wc -l) -eq 1 ] || atf_fail "Not exactly 1 state found!"
228
}
229
230
tcp_in_if_bound_cleanup()
231
{
232
pft_cleanup
233
}
234
235
atf_test_case "tcp_out_if_bound" "cleanup"
236
tcp_out_if_bound_head()
237
{
238
atf_set descr 'TCP NAT64 test on outbound interface, if-bound states'
239
atf_set require.user root
240
}
241
242
tcp_out_if_bound_body()
243
{
244
nat64_setup_out
245
246
echo "foo" | jexec dst nc -l 1234 &
247
248
# Sanity check & delay for nc startup
249
atf_check -s exit:0 -o ignore \
250
ping6 -c 3 64:ff9b::192.0.2.2
251
252
rcv=$(nc -w 3 -6 64:ff9b::c000:202 1234)
253
if [ "${rcv}" != "foo" ];
254
then
255
echo "rcv=${rcv}"
256
atf_fail "Failed to connect to TCP server"
257
fi
258
259
sleep 1
260
261
# Origif is not printed when identical as if.
262
states=$(mktemp) || exit 1
263
jexec rtr pfctl -qvvss | normalize_pfctl_s > $states
264
for state_regexp in \
265
"${epair}b tcp 64:ff9b::c000:202\[1234\] <- 2001:db8::2\[[0-9]+\] .* 5:4 pkts.* rule 3 .*creatorid" \
266
"${epair_link}a tcp 192.0.2.1:[0-9]+ \(64:ff9b::c000:202\[1234\]\) -> 192.0.2.2:1234 \(2001:db8::2\[[0-9]+\]\).* 5:4 pkts.* rule 4 .*creatorid" \
267
; do
268
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
269
done
270
[ $(cat $states | grep tcp | wc -l) -eq 2 ] || atf_fail "Not exactly 2 states found!"
271
}
272
273
tcp_out_if_bound_cleanup()
274
{
275
pft_cleanup
276
}
277
278
atf_test_case "tcp_in_floating" "cleanup"
279
tcp_in_floating_head()
280
{
281
atf_set descr 'TCP NAT64 test on inbound interface, floating states'
282
atf_set require.user root
283
}
284
285
tcp_in_floating_body()
286
{
287
nat64_setup_in "floating"
288
289
echo "foo" | jexec dst nc -l 1234 &
290
291
# Sanity check & delay for nc startup
292
atf_check -s exit:0 -o ignore \
293
ping6 -c 3 64:ff9b::192.0.2.2
294
295
rcv=$(nc -w 3 -6 64:ff9b::c000:202 1234)
296
if [ "${rcv}" != "foo" ];
297
then
298
echo "rcv=${rcv}"
299
atf_fail "Failed to connect to TCP server"
300
fi
301
302
sleep 1
303
304
# Interfaces of the state are reversed when doing inbound NAT64!
305
# FIXME: Packets from both directions are counted only on the inbound direction!
306
states=$(mktemp) || exit 1
307
jexec rtr pfctl -qvvss | normalize_pfctl_s > $states
308
for state_regexp in \
309
"all tcp 192.0.2.1:[0-9]+ \(2001:db8::2\[[0-9]+\]\) -> 192.0.2.2:1234 \(64:ff9b::c000:202\[1234\]\).* 5:4 pkts.* rule 3 .* origif: ${epair}b" \
310
; do
311
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
312
done
313
[ $(cat $states | grep tcp | wc -l) -eq 1 ] || atf_fail "Not exactly 1 state found!"
314
}
315
316
tcp_in_floating_cleanup()
317
{
318
pft_cleanup
319
}
320
321
atf_test_case "tcp_out_floating" "cleanup"
322
tcp_out_floating_head()
323
{
324
atf_set descr 'TCP NAT64 test on outbound interface, floating states'
325
atf_set require.user root
326
}
327
328
tcp_out_floating_body()
329
{
330
nat64_setup_out "floating"
331
332
echo "foo" | jexec dst nc -l 1234 &
333
334
# Sanity check & delay for nc startup
335
atf_check -s exit:0 -o ignore \
336
ping6 -c 3 64:ff9b::192.0.2.2
337
338
rcv=$(nc -w 3 -6 64:ff9b::c000:202 1234)
339
if [ "${rcv}" != "foo" ];
340
then
341
echo "rcv=${rcv}"
342
atf_fail "Failed to connect to TCP server"
343
fi
344
345
sleep 1
346
347
# Origif is not printed when identical as if.
348
states=$(mktemp) || exit 1
349
jexec rtr pfctl -qvvss | normalize_pfctl_s > $states
350
for state_regexp in \
351
"all tcp 64:ff9b::c000:202\[1234\] <- 2001:db8::2\[[0-9]+\] .* 5:4 pkts,.* rule 3 .*creatorid"\
352
"all tcp 192.0.2.1:[0-9]+ \(64:ff9b::c000:202\[1234\]\) -> 192.0.2.2:1234 \(2001:db8::2\[[0-9]+\]\) .* 5:4 pkts,.* rule 4 .*creatorid"\
353
; do
354
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
355
done
356
[ $(cat $states | grep tcp | wc -l) -eq 2 ] || atf_fail "Not exactly 2 states found!"
357
}
358
359
tcp_out_floating_cleanup()
360
{
361
pft_cleanup
362
}
363
364
atf_test_case "udp_in" "cleanup"
365
udp_in_head()
366
{
367
atf_set descr 'UDP NAT64 test on inbound interface'
368
atf_set require.user root
369
}
370
371
udp_in_body()
372
{
373
nat64_setup_in
374
375
echo "foo" | jexec dst nc -u -l 1234 &
376
377
# Sanity check & delay for nc startup
378
atf_check -s exit:0 -o ignore \
379
ping6 -c 3 64:ff9b::192.0.2.2
380
381
rcv=$(echo bar | nc -w 3 -6 -u 64:ff9b::c000:202 1234)
382
if [ "${rcv}" != "foo" ];
383
then
384
echo "rcv=${rcv}"
385
atf_fail "Failed to connect to UDP server"
386
fi
387
}
388
389
udp_in_cleanup()
390
{
391
pft_cleanup
392
}
393
394
atf_test_case "udp_out" "cleanup"
395
udp_out_head()
396
{
397
atf_set descr 'UDP NAT64 test on outbound interface'
398
atf_set require.user root
399
}
400
401
udp_out_body()
402
{
403
nat64_setup_out
404
405
echo "foo" | jexec dst nc -u -l 1234 &
406
407
# Sanity check & delay for nc startup
408
atf_check -s exit:0 -o ignore \
409
ping6 -c 3 64:ff9b::192.0.2.2
410
411
rcv=$(echo bar | nc -w 3 -6 -u 64:ff9b::c000:202 1234)
412
if [ "${rcv}" != "foo" ];
413
then
414
echo "rcv=${rcv}"
415
atf_fail "Failed to connect to UDP server"
416
fi
417
}
418
419
udp_out_cleanup()
420
{
421
pft_cleanup
422
}
423
424
atf_test_case "sctp_in" "cleanup"
425
sctp_in_head()
426
{
427
atf_set descr 'SCTP NAT64 test on inbound interface'
428
atf_set require.user root
429
}
430
431
sctp_in_body()
432
{
433
nat64_setup_in
434
if ! kldstat -q -m sctp; then
435
atf_skip "This test requires SCTP"
436
fi
437
438
echo "foo" | jexec dst nc --sctp -N -l 1234 &
439
440
# Sanity check & delay for nc startup
441
atf_check -s exit:0 -o ignore \
442
ping6 -c 3 64:ff9b::192.0.2.2
443
444
rcv=$(echo bar | nc --sctp -w 3 -6 64:ff9b::c000:202 1234)
445
if [ "${rcv}" != "foo" ];
446
then
447
echo "rcv=${rcv}"
448
atf_fail "Failed to connect to SCTP server"
449
fi
450
}
451
452
sctp_in_cleanup()
453
{
454
pft_cleanup
455
}
456
457
atf_test_case "sctp_out" "cleanup"
458
sctp_out_head()
459
{
460
atf_set descr 'SCTP NAT64 test on outbound interface'
461
atf_set require.user root
462
}
463
464
sctp_out_body()
465
{
466
nat64_setup_out
467
if ! kldstat -q -m sctp; then
468
atf_skip "This test requires SCTP"
469
fi
470
471
echo "foo" | jexec dst nc --sctp -N -l 1234 &
472
473
# Sanity check & delay for nc startup
474
atf_check -s exit:0 -o ignore \
475
ping6 -c 3 64:ff9b::192.0.2.2
476
477
rcv=$(echo bar | nc --sctp -w 3 -6 64:ff9b::c000:202 1234)
478
if [ "${rcv}" != "foo" ];
479
then
480
echo "rcv=${rcv}"
481
atf_fail "Failed to connect to SCTP server"
482
fi
483
}
484
485
sctp_out_cleanup()
486
{
487
pft_cleanup
488
}
489
490
atf_test_case "tos" "cleanup"
491
tos_head()
492
{
493
atf_set descr 'ToS translation test'
494
atf_set require.user root
495
}
496
497
tos_body()
498
{
499
nat64_setup_in
500
501
# Ensure we can distinguish ToS on the destination
502
jexec dst pfctl -e
503
pft_set_rules dst \
504
"pass" \
505
"block in inet tos 8"
506
507
atf_check -s exit:0 -o ignore \
508
ping6 -c 1 -z 4 64:ff9b::192.0.2.2
509
atf_check -s exit:2 -o ignore \
510
ping6 -c 1 -z 8 64:ff9b::192.0.2.2
511
atf_check -s exit:0 -o ignore \
512
ping6 -c 1 -z 16 64:ff9b::192.0.2.2
513
514
jexec dst pfctl -sr -vv
515
}
516
517
tos_cleanup()
518
{
519
pft_cleanup
520
}
521
522
atf_test_case "no_v4" "cleanup"
523
no_v4_head()
524
{
525
atf_set descr 'Test error handling when there is no IPv4 address to translate to'
526
atf_set require.user root
527
}
528
529
no_v4_body()
530
{
531
pft_init
532
533
epair_link=$(vnet_mkepair)
534
epair=$(vnet_mkepair)
535
536
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
537
route -6 add default 2001:db8::1
538
539
vnet_mkjail rtr ${epair}b ${epair_link}a
540
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
541
542
vnet_mkjail dst ${epair_link}b
543
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
544
jexec dst route add default 192.0.2.1
545
546
# Sanity check
547
atf_check -s exit:0 -o ignore \
548
ping6 -c 1 2001:db8::1
549
550
jexec rtr pfctl -e
551
pft_set_rules rtr \
552
"block" \
553
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
554
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_link}a)" \
555
556
atf_check -s exit:2 -o ignore \
557
ping6 -c 3 64:ff9b::192.0.2.2
558
}
559
560
no_v4_cleanup()
561
{
562
pft_cleanup
563
}
564
565
atf_test_case "range" "cleanup"
566
range_head()
567
{
568
atf_set descr 'Test using an address range for the IPv4 side'
569
atf_set require.user root
570
}
571
572
range_body()
573
{
574
pft_init
575
576
epair_link=$(vnet_mkepair)
577
epair=$(vnet_mkepair)
578
579
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
580
route -6 add default 2001:db8::1
581
582
vnet_mkjail rtr ${epair}b ${epair_link}a
583
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
584
jexec rtr ifconfig ${epair_link}a 192.0.2.2/24 up
585
jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.3/24 up
586
587
vnet_mkjail dst ${epair_link}b
588
jexec dst ifconfig ${epair_link}b 192.0.2.254/24 up
589
jexec dst route add default 192.0.2.2
590
591
# Sanity checks
592
atf_check -s exit:0 -o ignore \
593
jexec rtr ping -c 1 192.0.2.254
594
atf_check -s exit:0 -o ignore \
595
ping6 -c 1 2001:db8::1
596
atf_check -s exit:0 -o ignore \
597
jexec dst ping -c 1 192.0.2.2
598
atf_check -s exit:0 -o ignore \
599
jexec dst ping -c 1 192.0.2.3
600
601
jexec rtr pfctl -e
602
pft_set_rules rtr \
603
"set reassemble yes" \
604
"set state-policy if-bound" \
605
"block" \
606
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
607
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from 192.0.2.2/31 round-robin" \
608
609
# Use pf to count sources
610
jexec dst pfctl -e
611
pft_set_rules dst \
612
"pass"
613
614
atf_check -s exit:0 -o ignore \
615
ping6 -c 1 64:ff9b::192.0.2.254
616
atf_check -s exit:0 -o ignore \
617
ping6 -c 1 64:ff9b::192.0.2.254
618
619
# Verify on dst that we saw different source addresses
620
atf_check -s exit:0 -o match:".*192.0.2.2.*" \
621
jexec dst pfctl -ss
622
atf_check -s exit:0 -o match:".*192.0.2.3.*" \
623
jexec dst pfctl -ss
624
}
625
626
range_cleanup()
627
{
628
pft_cleanup
629
}
630
631
atf_test_case "pool" "cleanup"
632
pool_head()
633
{
634
atf_set descr 'Use a pool of IPv4 addresses'
635
atf_set require.user root
636
}
637
638
pool_body()
639
{
640
pft_init
641
642
epair_link=$(vnet_mkepair)
643
epair=$(vnet_mkepair)
644
645
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
646
route -6 add default 2001:db8::1
647
648
vnet_mkjail rtr ${epair}b ${epair_link}a
649
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
650
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
651
jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.3/24 up
652
jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.4/24 up
653
654
vnet_mkjail dst ${epair_link}b
655
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
656
jexec dst route add default 192.0.2.1
657
658
# Sanity checks
659
atf_check -s exit:0 -o ignore \
660
ping6 -c 1 2001:db8::1
661
atf_check -s exit:0 -o ignore \
662
jexec dst ping -c 1 192.0.2.1
663
664
jexec rtr pfctl -e
665
pft_set_rules rtr \
666
"set reassemble yes" \
667
"set state-policy if-bound" \
668
"block" \
669
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
670
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from { 192.0.2.1, 192.0.2.3, 192.0.2.4 } round-robin"
671
672
# Use pf to count sources
673
jexec dst pfctl -e
674
pft_set_rules dst \
675
"pass"
676
677
atf_check -s exit:0 -o ignore \
678
ping6 -c 1 64:ff9b::192.0.2.2
679
atf_check -s exit:0 -o ignore \
680
ping6 -c 1 64:ff9b::192.0.2.2
681
atf_check -s exit:0 -o ignore \
682
ping6 -c 1 64:ff9b::192.0.2.2
683
684
# Verify on dst that we saw different source addresses
685
atf_check -s exit:0 -o match:".*192.0.2.1.*" \
686
jexec dst pfctl -ss
687
atf_check -s exit:0 -o match:".*192.0.2.3.*" \
688
jexec dst pfctl -ss
689
atf_check -s exit:0 -o match:".*192.0.2.4.*" \
690
jexec dst pfctl -ss
691
}
692
693
pool_cleanup()
694
{
695
pft_cleanup
696
}
697
698
699
atf_test_case "table"
700
table_head()
701
{
702
atf_set descr 'Check table restrictions'
703
atf_set require.user root
704
}
705
706
table_body()
707
{
708
pft_init
709
710
# Round-robin and random are allowed
711
echo "pass in on epair inet6 from any to 64:ff9b::/96 af-to inet from <wanaddr> round-robin" | \
712
atf_check -s exit:0 \
713
pfctl -f -
714
echo "pass in on epair inet6 from any to 64:ff9b::/96 af-to inet from <wanaddr> random" | \
715
atf_check -s exit:0 \
716
pfctl -f -
717
718
# bitmask is not
719
echo "pass in on epair inet6 from any to 64:ff9b::/96 af-to inet from <wanaddr> bitmask" | \
720
atf_check -s exit:1 \
721
-e match:"tables are not supported by pool type" \
722
pfctl -f -
723
}
724
725
table_cleanup()
726
{
727
pft_cleanup
728
}
729
730
atf_test_case "table_range" "cleanup"
731
table_range_head()
732
{
733
atf_set descr 'Test using an address range within a table for the IPv4 side'
734
atf_set require.user root
735
}
736
737
table_range_body()
738
{
739
pft_init
740
741
epair_link=$(vnet_mkepair)
742
epair=$(vnet_mkepair)
743
744
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
745
route -6 add default 2001:db8::1
746
747
vnet_mkjail rtr ${epair}b ${epair_link}a
748
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
749
jexec rtr ifconfig ${epair_link}a 192.0.2.2/24 up
750
jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.3/24 up
751
752
vnet_mkjail dst ${epair_link}b
753
jexec dst ifconfig ${epair_link}b 192.0.2.254/24 up
754
jexec dst route add default 192.0.2.2
755
756
# Sanity checks
757
atf_check -s exit:0 -o ignore \
758
ping6 -c 1 2001:db8::1
759
atf_check -s exit:0 -o ignore \
760
jexec dst ping -c 1 192.0.2.2
761
762
jexec rtr pfctl -e
763
pft_set_rules rtr \
764
"set reassemble yes" \
765
"set state-policy if-bound" \
766
"table <wanaddrs> { 192.0.2.2/31 }" \
767
"block" \
768
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
769
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from <wanaddrs> round-robin"
770
771
# Use pf to count sources
772
jexec dst pfctl -e
773
pft_set_rules dst \
774
"pass"
775
776
atf_check -s exit:0 -o ignore \
777
ping6 -c 1 64:ff9b::192.0.2.254
778
atf_check -s exit:0 -o ignore \
779
ping6 -c 1 64:ff9b::192.0.2.254
780
781
# Verify on dst that we saw different source addresses
782
atf_check -s exit:0 -o match:".*192.0.2.2.*" \
783
jexec dst pfctl -ss
784
atf_check -s exit:0 -o match:".*192.0.2.3.*" \
785
jexec dst pfctl -ss
786
}
787
788
table_range_cleanup()
789
{
790
pft_cleanup
791
}
792
793
table_common_body()
794
{
795
pool_type=$1
796
797
pft_init
798
799
epair_link=$(vnet_mkepair)
800
epair=$(vnet_mkepair)
801
802
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
803
route -6 add default 2001:db8::1
804
805
vnet_mkjail rtr ${epair}b ${epair_link}a
806
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
807
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
808
jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.3/24 up
809
jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.4/24 up
810
811
vnet_mkjail dst ${epair_link}b
812
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
813
jexec dst route add default 192.0.2.1
814
815
# Sanity checks
816
atf_check -s exit:0 -o ignore \
817
ping6 -c 1 2001:db8::1
818
atf_check -s exit:0 -o ignore \
819
jexec dst ping -c 1 192.0.2.1
820
821
jexec rtr pfctl -e
822
pft_set_rules rtr \
823
"set reassemble yes" \
824
"set state-policy if-bound" \
825
"table <wanaddrs> { 192.0.2.1, 192.0.2.3, 192.0.2.4 }" \
826
"block" \
827
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
828
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from <wanaddrs> ${pool_type}"
829
830
# Use pf to count sources
831
jexec dst pfctl -e
832
pft_set_rules dst \
833
"pass"
834
835
atf_check -s exit:0 -o ignore \
836
ping6 -c 1 64:ff9b::192.0.2.2
837
atf_check -s exit:0 -o ignore \
838
ping6 -c 1 64:ff9b::192.0.2.2
839
atf_check -s exit:0 -o ignore \
840
ping6 -c 1 64:ff9b::192.0.2.2
841
842
# XXX We can't reasonably check pool type random because it's random. It may end
843
# up choosing the same source IP for all three connections.
844
if [ "${pool_type}" == "round-robin" ];
845
then
846
# Verify on dst that we saw different source addresses
847
atf_check -s exit:0 -o match:".*192.0.2.1.*" \
848
jexec dst pfctl -ss
849
atf_check -s exit:0 -o match:".*192.0.2.3.*" \
850
jexec dst pfctl -ss
851
atf_check -s exit:0 -o match:".*192.0.2.4.*" \
852
jexec dst pfctl -ss
853
fi
854
}
855
856
atf_test_case "table_round_robin" "cleanup"
857
table_round_robin_head()
858
{
859
atf_set descr 'Use a table of IPv4 addresses in round-robin mode'
860
atf_set require.user root
861
}
862
863
table_round_robin_body()
864
{
865
table_common_body round-robin
866
}
867
868
table_round_robin_cleanup()
869
{
870
pft_cleanup
871
}
872
873
atf_test_case "table_random" "cleanup"
874
table_random_head()
875
{
876
atf_set descr 'Use a table of IPv4 addresses in random mode'
877
atf_set require.user root
878
}
879
880
table_random_body()
881
{
882
table_common_body random
883
}
884
885
table_random_cleanup()
886
{
887
pft_cleanup
888
}
889
890
atf_test_case "dummynet" "cleanup"
891
dummynet_head()
892
{
893
atf_set descr 'Test dummynet on af-to rules'
894
atf_set require.user root
895
}
896
897
dummynet_body()
898
{
899
pft_init
900
dummynet_init
901
902
epair_link=$(vnet_mkepair)
903
epair=$(vnet_mkepair)
904
905
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
906
route -6 add default 2001:db8::1
907
908
vnet_mkjail rtr ${epair}b ${epair_link}a
909
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
910
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
911
912
vnet_mkjail dst ${epair_link}b
913
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
914
jexec dst route add default 192.0.2.1
915
916
# Sanity checks
917
atf_check -s exit:0 -o ignore \
918
ping6 -c 1 2001:db8::1
919
atf_check -s exit:0 -o ignore \
920
jexec dst ping -c 1 192.0.2.1
921
922
jexec rtr pfctl -e
923
jexec rtr dnctl pipe 1 config delay 600
924
pft_set_rules rtr \
925
"set reassemble yes" \
926
"set state-policy if-bound" \
927
"block" \
928
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
929
"pass in on ${epair}b inet6 from any to 64:ff9b::/96 dnpipe 1 af-to inet from (${epair_link}a)"
930
931
# The ping request will pass, but take 1.2 seconds (.6 in, .6 out)
932
# So this works:
933
atf_check -s exit:0 -o ignore \
934
ping6 -c 1 -t 2 64:ff9b::192.0.2.2
935
936
# But this times out:
937
atf_check -s exit:2 -o ignore \
938
ping6 -c 1 -t 1 64:ff9b::192.0.2.2
939
}
940
941
dummynet_cleanup()
942
{
943
pft_cleanup
944
}
945
946
atf_test_case "gateway6" "cleanup"
947
gateway6_head()
948
{
949
atf_set descr 'NAT64 with a routing hop on the v6 side'
950
atf_set require.user root
951
}
952
953
gateway6_body()
954
{
955
pft_init
956
957
epair_lan_link=$(vnet_mkepair)
958
epair_link=$(vnet_mkepair)
959
epair=$(vnet_mkepair)
960
961
ifconfig ${epair}a inet6 2001:db8:1::2/64 up no_dad
962
route -6 add default 2001:db8:1::1
963
964
vnet_mkjail lan_rtr ${epair}b ${epair_lan_link}a
965
jexec lan_rtr ifconfig ${epair}b inet6 2001:db8:1::1/64 up no_dad
966
jexec lan_rtr ifconfig ${epair_lan_link}a inet6 2001:db8::2/64 up no_dad
967
jexec lan_rtr route -6 add default 2001:db8::1
968
jexec lan_rtr sysctl net.inet6.ip6.forwarding=1
969
970
vnet_mkjail rtr ${epair_lan_link}b ${epair_link}a
971
jexec rtr ifconfig ${epair_lan_link}b inet6 2001:db8::1/64 up no_dad
972
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
973
jexec rtr route -6 add default 2001:db8::2
974
975
vnet_mkjail dst ${epair_link}b
976
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
977
jexec dst route add default 192.0.2.1
978
979
# Sanity checks
980
atf_check -s exit:0 -o ignore \
981
ping6 -c 1 2001:db8:1::1
982
atf_check -s exit:0 -o ignore \
983
ping6 -c 1 2001:db8::1
984
atf_check -s exit:0 -o ignore \
985
jexec dst ping -c 1 192.0.2.1
986
987
jexec rtr pfctl -e
988
pft_set_rules rtr \
989
"set reassemble yes" \
990
"set state-policy if-bound" \
991
"block" \
992
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
993
"pass in on ${epair_lan_link}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_link}a)"
994
995
# One ping
996
atf_check -s exit:0 -o ignore \
997
ping6 -c 1 64:ff9b::192.0.2.2
998
999
# Make sure packets make it even when state is established
1000
atf_check -s exit:0 \
1001
-o match:'5 packets transmitted, 5 packets received, 0.0% packet loss' \
1002
ping6 -c 5 64:ff9b::192.0.2.2
1003
}
1004
1005
gateway6_cleanup()
1006
{
1007
pft_cleanup
1008
}
1009
1010
atf_test_case "route_to" "cleanup"
1011
route_to_head()
1012
{
1013
atf_set descr 'Test route-to on af-to rules'
1014
atf_set require.user root
1015
}
1016
1017
route_to_body()
1018
{
1019
pft_init
1020
1021
epair_link=$(vnet_mkepair)
1022
epair=$(vnet_mkepair)
1023
1024
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
1025
route -6 add default 2001:db8::1
1026
1027
vnet_mkjail rtr ${epair}b ${epair_link}a
1028
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
1029
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
1030
1031
vnet_mkjail dst ${epair_link}b
1032
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
1033
jexec dst ifconfig lo0 203.0.113.1/32 alias
1034
jexec dst route add default 192.0.2.2
1035
1036
# Sanity checks
1037
atf_check -s exit:0 -o ignore \
1038
ping6 -c 1 2001:db8::1
1039
1040
jexec rtr pfctl -e
1041
pft_set_rules rtr \
1042
"set reassemble yes" \
1043
"set debug loud" \
1044
"set state-policy if-bound" \
1045
"block log (all)" \
1046
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
1047
"pass in on ${epair}b route-to (${epair_link}a 192.0.2.2) inet6 from any to 64:ff9b::/96 af-to inet from (${epair_link}a)"
1048
1049
atf_check -s exit:0 -o ignore \
1050
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
1051
ping6 -c 3 64:ff9b::192.0.2.2
1052
1053
states=$(mktemp) || exit 1
1054
jexec rtr pfctl -qvvss | normalize_pfctl_s > $states
1055
cat $states
1056
1057
# Interfaces of the state are reversed when doing inbound NAT64!
1058
for state_regexp in \
1059
"${epair_link}a ipv6-icmp 192.0.2.1:.* \(2001:db8::2\[[0-9]+\]\) -> 192.0.2.2:8 \(64:ff9b::c000:202\[[0-9]+\]\).* 3:3 pkts.*route-to: 192.0.2.2@${epair_link}a origif: ${epair}b" \
1060
; do
1061
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
1062
done
1063
}
1064
1065
route_to_cleanup()
1066
{
1067
pft_cleanup
1068
}
1069
1070
atf_test_case "reply_to" "cleanup"
1071
reply_to_head()
1072
{
1073
atf_set descr 'Test reply-to on af-to rules'
1074
atf_set require.user root
1075
}
1076
1077
reply_to_body()
1078
{
1079
pft_init
1080
1081
epair_link=$(vnet_mkepair)
1082
epair=$(vnet_mkepair)
1083
1084
ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
1085
route -6 add default 2001:db8::1
1086
1087
vnet_mkjail rtr ${epair}b ${epair_link}a
1088
jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
1089
jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
1090
1091
vnet_mkjail dst ${epair_link}b
1092
jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
1093
jexec dst route add default 192.0.2.1
1094
1095
# Sanity checks
1096
atf_check -s exit:0 -o ignore \
1097
ping6 -c 1 2001:db8::1
1098
1099
jexec rtr pfctl -e
1100
pft_set_rules rtr \
1101
"set reassemble yes" \
1102
"set state-policy if-bound" \
1103
"block" \
1104
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
1105
"pass in on ${epair}b reply-to (${epair}b 2001:db8::2) inet6 from any to 64:ff9b::/96 af-to inet from 192.0.2.1"
1106
1107
atf_check -s exit:0 -o ignore \
1108
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
1109
ping6 -c 3 64:ff9b::192.0.2.2
1110
}
1111
1112
reply_to_cleanup()
1113
{
1114
pft_cleanup
1115
}
1116
1117
atf_test_case "v6_gateway" "cleanup"
1118
v6_gateway_head()
1119
{
1120
atf_set descr 'nat64 when the IPv4 gateway is given by an IPv6 address'
1121
atf_set require.user root
1122
}
1123
1124
v6_gateway_body()
1125
{
1126
pft_init
1127
1128
epair_wan_two=$(vnet_mkepair)
1129
epair_wan_one=$(vnet_mkepair)
1130
epair_lan=$(vnet_mkepair)
1131
1132
ifconfig ${epair_lan}a inet6 2001:db8::2/64 up no_dad
1133
route -6 add default 2001:db8::1
1134
1135
vnet_mkjail rtr ${epair_lan}b ${epair_wan_one}a
1136
jexec rtr ifconfig ${epair_lan}b inet6 2001:db8::1/64 up no_dad
1137
jexec rtr ifconfig ${epair_wan_one}a 192.0.2.1/24 up
1138
jexec rtr ifconfig ${epair_wan_one}a inet6 -ifdisabled
1139
jexec rtr route add default -inet6 fe80::1%${epair_wan_one}a
1140
#jexec rtr route add default 192.0.2.2
1141
1142
vnet_mkjail wan_one ${epair_wan_one}b ${epair_wan_two}a
1143
jexec wan_one ifconfig ${epair_wan_one}b 192.0.2.2/24 up
1144
jexec wan_one ifconfig ${epair_wan_one}b inet6 fe80::1/64
1145
jexec wan_one ifconfig ${epair_wan_two}a 198.51.100.2/24 up
1146
jexec wan_one route add default 192.0.2.1
1147
jexec wan_one sysctl net.inet.ip.forwarding=1
1148
1149
vnet_mkjail wan_two ${epair_wan_two}b
1150
jexec wan_two ifconfig ${epair_wan_two}b 198.51.100.1/24 up
1151
jexec wan_two route add default 198.51.100.2
1152
1153
# Sanity checks
1154
atf_check -s exit:0 -o ignore \
1155
ping6 -c 1 2001:db8::1
1156
atf_check -s exit:0 -o ignore \
1157
jexec rtr ping -c 1 192.0.2.2
1158
atf_check -s exit:0 -o ignore \
1159
jexec rtr ping -c 1 198.51.100.1
1160
1161
jexec rtr pfctl -e
1162
pft_set_rules rtr \
1163
"set reassemble yes" \
1164
"set state-policy if-bound" \
1165
"block" \
1166
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
1167
"pass in on ${epair_lan}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_wan_one}a)"
1168
1169
atf_check -s exit:0 -o ignore \
1170
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
1171
ping6 -c 3 64:ff9b::192.0.2.2
1172
atf_check -s exit:0 -o ignore \
1173
-o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \
1174
ping6 -c 3 64:ff9b::198.51.100.1
1175
}
1176
1177
v6_gateway_cleanup()
1178
{
1179
pft_cleanup
1180
}
1181
1182
atf_init_test_cases()
1183
{
1184
atf_add_test_case "icmp_echo_in"
1185
atf_add_test_case "icmp_echo_out"
1186
atf_add_test_case "fragmentation_in"
1187
atf_add_test_case "fragmentation_out"
1188
atf_add_test_case "tcp_in_if_bound"
1189
atf_add_test_case "tcp_out_if_bound"
1190
atf_add_test_case "tcp_in_floating"
1191
atf_add_test_case "tcp_out_floating"
1192
atf_add_test_case "udp_in"
1193
atf_add_test_case "udp_out"
1194
atf_add_test_case "sctp_in"
1195
atf_add_test_case "sctp_out"
1196
atf_add_test_case "tos"
1197
atf_add_test_case "no_v4"
1198
atf_add_test_case "range"
1199
atf_add_test_case "pool"
1200
atf_add_test_case "table"
1201
atf_add_test_case "table_range"
1202
atf_add_test_case "table_round_robin"
1203
atf_add_test_case "table_random"
1204
atf_add_test_case "dummynet"
1205
atf_add_test_case "gateway6"
1206
atf_add_test_case "route_to"
1207
atf_add_test_case "reply_to"
1208
atf_add_test_case "v6_gateway"
1209
}
1210
1211