2 # SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 # Copyright © 2023 Orange Business Services
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
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.
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
27 . $(atf_get_srcdir)/utils.subr
32 if ! kldstat -q -m sctp; then
33 atf_skip "This test requires SCTP"
37 atf_test_case "basic_v4" "cleanup"
40 atf_set descr 'Basic SCTP connection over IPv4 passthrough'
41 atf_set require.user root
51 vnet_mkjail ${j}a ${epair}a
52 vnet_mkjail ${j}b ${epair}b
54 jexec ${j}a ifconfig ${epair}a 192.0.2.1/24 up
55 jexec ${j}b ifconfig ${epair}b 192.0.2.2/24 up
57 atf_check -s exit:0 -o ignore \
58 jexec ${j}a ping -c 1 192.0.2.2
63 "pass in proto sctp to port 1234"
65 echo "foo" | jexec ${j}a nc --sctp -N -l 1234 &
67 # Wait for the server to start
70 out=$(jexec ${j}b nc --sctp -N -w 3 192.0.2.1 1234)
71 if [ "$out" != "foo" ]; then
72 atf_fail "SCTP connection failed"
75 # Now with scrub rules present, so normalization is done
79 "pass in proto sctp to port 1234"
81 echo "foo" | jexec ${j}a nc --sctp -N -l 1234 &
84 out=$(jexec ${j}b nc --sctp -N -w 3 192.0.2.1 1234)
85 if [ "$out" != "foo" ]; then
86 atf_fail "SCTP connection failed"
89 # Now fail with a blocked port
90 echo "foo" | jexec ${j}a nc --sctp -N -l 1235 &
93 out=$(jexec ${j}b nc --sctp -N -w 3 192.0.2.1 1235)
94 if [ "$out" == "foo" ]; then
95 atf_fail "SCTP port block failed"
98 # Now fail with a blocked port but passing source port
99 out=$(jexec ${j}b nc --sctp -N -w 3 -p 1234 192.0.2.1 1235)
100 if [ "$out" == "foo" ]; then
101 atf_fail "SCTP port block failed"
110 atf_test_case "basic_v6" "cleanup"
113 atf_set descr 'Basic SCTP connection over IPv6'
114 atf_set require.user root
122 epair=$(vnet_mkepair)
124 vnet_mkjail ${j}a ${epair}a
125 vnet_mkjail ${j}b ${epair}b
127 jexec ${j}a ifconfig ${epair}a inet6 2001:db8::a/64 up no_dad
128 jexec ${j}b ifconfig ${epair}b inet6 2001:db8::b/64 up no_dad
131 atf_check -s exit:0 -o ignore \
132 jexec ${j}a ping -6 -c 1 2001:db8::b
135 pft_set_rules ${j}a \
137 "pass in proto sctp to port 1234"
139 echo "foo" | jexec ${j}a nc -6 --sctp -N -l 1234 &
141 # Wait for the server to start
144 out=$(jexec ${j}b nc --sctp -N -w 3 2001:db8::a 1234)
145 if [ "$out" != "foo" ]; then
146 atf_fail "SCTP connection failed"
149 # Now with scrub rules present, so normalization is done
150 pft_set_rules ${j}a \
153 "pass in proto sctp to port 1234"
155 echo "foo" | jexec ${j}a nc -6 --sctp -N -l 1234 &
158 out=$(jexec ${j}b nc --sctp -N -w 3 2001:db8::a 1234)
159 if [ "$out" != "foo" ]; then
160 atf_fail "SCTP connection failed"
163 # Now fail with a blocked port
164 echo "foo" | jexec ${j}a nc -6 --sctp -N -l 1235 &
167 out=$(jexec ${j}b nc --sctp -N -w 3 2001:db8::a 1235)
168 if [ "$out" == "foo" ]; then
169 atf_fail "SCTP port block failed"
172 # Now fail with a blocked port but passing source port
173 out=$(jexec ${j}b nc --sctp -N -w 3 -p 1234 2001:db8::a 1235)
174 if [ "$out" == "foo" ]; then
175 atf_fail "SCTP port block failed"
184 atf_test_case "abort_v4" "cleanup"
187 atf_set descr 'Test sending ABORT messages'
188 atf_set require.user root
196 epair=$(vnet_mkepair)
198 vnet_mkjail ${j}a ${epair}a
199 vnet_mkjail ${j}b ${epair}b
201 jexec ${j}a ifconfig ${epair}a 192.0.2.1/24 up
202 jexec ${j}b ifconfig ${epair}b 192.0.2.2/24 up
205 atf_check -s exit:0 -o ignore \
206 jexec ${j}a ping -c 1 192.0.2.2
209 pft_set_rules ${j}a \
210 "block return in proto sctp to port 1234"
212 echo "foo" | jexec ${j}a nc --sctp -N -l 1234 &
214 # Wait for the server to start
217 # If we get the abort we'll exit immediately, if we don't timeout will
219 out=$(jexec ${j}b timeout 3 nc --sctp -N 192.0.2.1 1234)
220 if [ $? -eq 124 ]; then
221 atf_fail 'Abort not received'
223 if [ "$out" == "foo" ]; then
224 atf_fail "block failed entirely"
227 # Without 'return' we will time out.
228 pft_set_rules ${j}a \
229 "block in proto sctp to port 1234"
231 out=$(jexec ${j}b timeout 3 nc --sctp -N 192.0.2.1 1234)
232 if [ $? -ne 124 ]; then
233 atf_fail 'Abort sent anyway?'
242 atf_test_case "abort_v6" "cleanup"
245 atf_set descr 'Test sending ABORT messages over IPv6'
246 atf_set require.user root
254 epair=$(vnet_mkepair)
256 vnet_mkjail ${j}a ${epair}a
257 vnet_mkjail ${j}b ${epair}b
259 jexec ${j}a ifconfig ${epair}a inet6 2001:db8::a/64 no_dad
260 jexec ${j}b ifconfig ${epair}b inet6 2001:db8::b/64 no_dad
263 atf_check -s exit:0 -o ignore \
264 jexec ${j}a ping -6 -c 1 2001:db8::b
267 pft_set_rules ${j}a \
268 "block return in proto sctp to port 1234"
270 echo "foo" | jexec ${j}a nc -6 --sctp -N -l 1234 &
272 # Wait for the server to start
275 # If we get the abort we'll exit immediately, if we don't timeout will
277 out=$(jexec ${j}b timeout 3 nc --sctp -N 2001:db8::a 1234)
278 if [ $? -eq 124 ]; then
279 atf_fail 'Abort not received'
281 if [ "$out" == "foo" ]; then
282 atf_fail "block failed entirely"
285 # Without 'return' we will time out.
286 pft_set_rules ${j}a \
287 "block in proto sctp to port 1234"
289 out=$(jexec ${j}b timeout 3 nc --sctp -N 2001:db8::a 1234)
290 if [ $? -ne 124 ]; then
291 atf_fail 'Abort sent anyway?'
300 atf_test_case "nat_v4" "cleanup"
303 atf_set descr 'Test NAT-ing SCTP over IPv4'
304 atf_set require.user root
312 epair_c=$(vnet_mkepair)
313 epair_srv=$(vnet_mkepair)
315 vnet_mkjail ${j}srv ${epair_srv}a
316 vnet_mkjail ${j}gw ${epair_srv}b ${epair_c}a
317 vnet_mkjail ${j}c ${epair_c}b
319 jexec ${j}srv ifconfig ${epair_srv}a 198.51.100.1/24 up
320 # No default route in srv jail, to ensure we're NAT-ing
321 jexec ${j}gw ifconfig ${epair_srv}b 198.51.100.2/24 up
322 jexec ${j}gw ifconfig ${epair_c}a 192.0.2.1/24 up
323 jexec ${j}gw sysctl net.inet.ip.forwarding=1
324 jexec ${j}c ifconfig ${epair_c}b 192.0.2.2/24 up
325 jexec ${j}c route add default 192.0.2.1
327 jexec ${j}gw pfctl -e
328 pft_set_rules ${j}gw \
329 "nat on ${epair_srv}b from 192.0.2.0/24 -> (${epair_srv}b)" \
333 atf_check -s exit:0 -o ignore \
334 jexec ${j}c ping -c 1 198.51.100.1
336 echo "foo" | jexec ${j}srv nc --sctp -N -l 1234 &
338 # Wait for the server to start
341 out=$(jexec ${j}c nc --sctp -N -w 3 198.51.100.1 1234)
342 if [ "$out" != "foo" ]; then
343 atf_fail "SCTP connection failed"
352 atf_test_case "nat_v6" "cleanup"
355 atf_set descr 'Test NAT-ing SCTP over IPv6'
356 atf_set require.user root
364 epair_c=$(vnet_mkepair)
365 epair_srv=$(vnet_mkepair)
367 vnet_mkjail ${j}srv ${epair_srv}a
368 vnet_mkjail ${j}gw ${epair_srv}b ${epair_c}a
369 vnet_mkjail ${j}c ${epair_c}b
371 jexec ${j}srv ifconfig ${epair_srv}a inet6 2001:db8::1/64 up no_dad
372 # No default route in srv jail, to ensure we're NAT-ing
373 jexec ${j}gw ifconfig ${epair_srv}b inet6 2001:db8::2/64 up no_dad
374 jexec ${j}gw ifconfig ${epair_c}a inet6 2001:db8:1::1/64 up no_dad
375 jexec ${j}gw sysctl net.inet6.ip6.forwarding=1
376 jexec ${j}c ifconfig ${epair_c}b inet6 2001:db8:1::2/64 up no_dad
377 jexec ${j}c route add -6 default 2001:db8:1::1
379 jexec ${j}gw pfctl -e
380 pft_set_rules ${j}gw \
381 "nat on ${epair_srv}b from 2001:db8:1::/64 -> (${epair_srv}b)" \
385 atf_check -s exit:0 -o ignore \
386 jexec ${j}c ping -6 -c 1 2001:db8::1
388 echo "foo" | jexec ${j}srv nc -6 --sctp -N -l 1234 &
390 # Wait for the server to start
393 out=$(jexec ${j}c nc --sctp -N -w 3 2001:db8::1 1234)
394 if [ "$out" != "foo" ]; then
395 atf_fail "SCTP connection failed"
404 atf_test_case "rdr_v4" "cleanup"
407 atf_set descr 'Test rdr SCTP over IPv4'
408 atf_set require.user root
416 epair_c=$(vnet_mkepair)
417 epair_srv=$(vnet_mkepair)
419 vnet_mkjail ${j}srv ${epair_srv}a
420 vnet_mkjail ${j}gw ${epair_srv}b ${epair_c}a
421 vnet_mkjail ${j}c ${epair_c}b
423 jexec ${j}srv ifconfig ${epair_srv}a 198.51.100.1/24 up
424 # No default route in srv jail, to ensure we're NAT-ing
425 jexec ${j}gw ifconfig ${epair_srv}b 198.51.100.2/24 up
426 jexec ${j}gw ifconfig ${epair_c}a 192.0.2.1/24 up
427 jexec ${j}gw sysctl net.inet.ip.forwarding=1
428 jexec ${j}c ifconfig ${epair_c}b 192.0.2.2/24 up
429 jexec ${j}c route add default 192.0.2.1
431 jexec ${j}gw pfctl -e
432 pft_set_rules ${j}gw \
433 "rdr pass on ${epair_srv}b proto sctp from 198.51.100.0/24 to any port 1234 -> 192.0.2.2 port 1234" \
436 echo "foo" | jexec ${j}c nc --sctp -N -l 1234 &
438 # Wait for the server to start
441 out=$(jexec ${j}srv nc --sctp -N -w 3 198.51.100.2 1234)
442 if [ "$out" != "foo" ]; then
443 atf_fail "SCTP connection failed"
446 # Despite configuring port changes pf will not do so.
447 echo "bar" | jexec ${j}c nc --sctp -N -l 1234 &
449 pft_set_rules ${j}gw \
450 "rdr pass on ${epair_srv}b proto sctp from 198.51.100.0/24 to any port 1234 -> 192.0.2.2 port 4321" \
454 out=$(jexec ${j}srv nc --sctp -N -w 3 198.51.100.2 4321)
455 if [ "$out" == "bar" ]; then
456 atf_fail "Port was unexpectedly changed."
460 out=$(jexec ${j}srv nc --sctp -N -w 3 198.51.100.2 1234)
461 if [ "$out" != "bar" ]; then
462 atf_fail "Port was unexpectedly changed."
471 atf_test_case "pfsync" "cleanup"
474 atf_set descr 'Test pfsync-ing SCTP connections'
475 atf_set require.user root
480 # + Builds bellow topology and initiate an SCTP connection
481 # from client to server.
482 # + Tests that the connection remains open when we fail over from
483 # router one to router two.
493 # ┌────────────────┴─┐ ┌─┴────────────────┐
495 # └────────────────┬─┘ └─┬────────────────┘
507 if ! kldstat -q -m carp
509 atf_skip "This test requires carp"
516 bridge0=$(vnet_mkbridge)
517 bridge1=$(vnet_mkbridge)
519 epair_c=$(vnet_mkepair)
520 epair_one0=$(vnet_mkepair)
521 epair_two0=$(vnet_mkepair)
522 epair_sync=$(vnet_mkepair)
523 epair_one1=$(vnet_mkepair)
524 epair_two1=$(vnet_mkepair)
525 epair_srv=$(vnet_mkepair)
527 ifconfig ${bridge0} addm ${epair_c}a addm ${epair_one0}a addm ${epair_two0}a
528 ifconfig ${epair_one0}a up
529 ifconfig ${epair_two0}a up
530 ifconfig ${epair_c}a up
531 ifconfig ${bridge0} up
533 ifconfig ${bridge1} addm ${epair_srv}a addm ${epair_one1}a addm ${epair_two1}a
534 ifconfig ${epair_one1}a up
535 ifconfig ${epair_two1}a up
536 ifconfig ${epair_srv}a up
537 ifconfig ${bridge1} up
539 vnet_mkjail ${j}c ${epair_c}b
540 jexec ${j}c ifconfig ${epair_c}b 192.0.2.2/24 up
541 jexec ${j}c route add default 192.0.2.1
543 vnet_mkjail ${j}one ${epair_one0}b ${epair_one1}b ${epair_sync}a
544 jexec ${j}one ifconfig ${epair_one0}b 192.0.2.3/24 up
545 jexec ${j}one ifconfig ${epair_one0}b \
546 alias 192.0.2.1/32 vhid 1 pass 1234
547 jexec ${j}one ifconfig ${epair_one1}b 198.51.100.3/24 up
548 jexec ${j}one ifconfig ${epair_one1}b \
549 alias 198.51.100.2/32 vhid 2 pass 4321
550 jexec ${j}one ifconfig ${epair_sync}a 203.0.113.1/24 up
551 jexec ${j}one ifconfig pfsync0 \
552 syncdev ${epair_sync}a \
555 jexec ${j}one sysctl net.inet.ip.forwarding=1
557 vnet_mkjail ${j}two ${epair_two0}b ${epair_two1}b ${epair_sync}b
558 jexec ${j}two ifconfig ${epair_two0}b 192.0.2.4/24 up
559 jexec ${j}two ifconfig ${epair_two0}b \
560 alias 192.0.2.1/32 vhid 1 pass 1234
561 jexec ${j}two ifconfig ${epair_two1}b 198.51.100.4/24 up
562 jexec ${j}two ifconfig ${epair_two1}b \
563 alias 198.51.100.2/32 vhid 2 pass 4321
564 jexec ${j}two ifconfig ${epair_sync}b 203.0.113.2/24 up
565 jexec ${j}two ifconfig pfsync0 \
566 syncdev ${epair_sync}b \
569 jexec ${j}two sysctl net.inet.ip.forwarding=1
571 vnet_mkjail ${j}srv ${epair_srv}b
572 jexec ${j}srv ifconfig ${epair_srv}b 198.51.100.1/24 up
573 jexec ${j}srv route add default 198.51.100.2
575 # Demote two, to avoid dealing with asymmetric routing
576 jexec ${j}two sysctl net.inet.carp.demotion=50
578 jexec ${j}one pfctl -e
579 pft_set_rules ${j}one \
581 "pass proto { icmp, pfsync, carp }" \
582 "pass proto sctp to port 1234" \
583 "pass proto tcp to port 1234"
585 jexec ${j}two pfctl -e
586 pft_set_rules ${j}two \
588 "pass proto { icmp, pfsync, carp }" \
589 "pass proto sctp to port 1234" \
590 "pass proto tcp to port 1234"
592 # Give carp time to get set up
596 atf_check -s exit:0 -o ignore \
597 jexec ${j}c ping -c 1 198.51.100.1
599 # Now start up an SCTP connection
601 tail -F ${tmp}/input | jexec ${j}srv nc --sctp -l 1234 &
604 jexec ${j}c nc --sctp 198.51.100.1 1234 > ${tmp}/output &
605 echo "1" >> ${tmp}/input
607 # Give time for the traffic to arrive
609 line=$(tail -n -1 ${tmp}/output)
610 if [ "${line}" != "1" ];
614 atf_fail "Initial SCTP connection failed"
617 # Verify that two has the connection too
618 state=$(jexec ${j}two pfctl -ss | grep sctp)
619 if [ -z "${state}" ];
621 jexec ${j}two pfctl -ss
622 atf_fail "Failed to find SCTP state on secondary pfsync host"
625 # Now fail over (both carp IPs should switch here)
626 jexec ${j}one sysctl net.inet.carp.demotion=100
628 while ! jexec ${j}one ifconfig ${epair_one0}b | grep MASTER;
632 while ! jexec ${j}one ifconfig ${epair_one1}b | grep MASTER;
638 atf_check -s exit:0 -o ignore \
639 jexec ${j}c ping -c 1 198.51.100.1
641 # And check that the connection is still live
642 echo "2" >> ${tmp}/input
644 line=$(tail -n -1 ${tmp}/output)
645 if [ "${line}" != "2" ];
649 atf_fail "SCTP failover failed"
658 atf_init_test_cases()
660 atf_add_test_case "basic_v4"
661 atf_add_test_case "basic_v6"
662 atf_add_test_case "abort_v4"
663 atf_add_test_case "abort_v6"
664 atf_add_test_case "nat_v4"
665 atf_add_test_case "nat_v6"
666 atf_add_test_case "rdr_v4"
667 atf_add_test_case "pfsync"