diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile index 83f0d94e952e..7256602a55a9 100644 --- a/tests/sys/netpfil/pf/Makefile +++ b/tests/sys/netpfil/pf/Makefile @@ -1,60 +1,62 @@ # $FreeBSD$ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/netpfil/pf TESTS_SUBDIRS+= ioctl ATF_TESTS_SH+= altq \ anchor \ - checksum \ dup \ ether \ forward \ fragmentation \ get_state \ icmp \ killstate \ macro \ map_e \ match \ + modulate \ names \ nat \ pass_block \ pfsync \ prio \ proxy \ rdr \ ridentifier \ route_to \ + rtable \ rules_counter \ + scrub \ set_skip \ set_tos \ src_track \ syncookie \ synproxy \ table \ tos ${PACKAGE}FILES+= CVE-2019-5597.py \ CVE-2019-5598.py \ daytime_inetd.conf \ echo_inetd.conf \ fragcommon.py \ frag-overindex.py \ frag-overlimit.py \ frag-overreplace.py \ pfsync_defer.py \ pft_ether.py \ utils.subr ${PACKAGE}FILESMODE_CVE-2019-5597.py= 0555 ${PACKAGE}FILESMODE_CVE-2019-5598.py= 0555 ${PACKAGE}FILESMODE_fragcommon.py= 0555 ${PACKAGE}FILESMODE_frag-overindex.py= 0555 ${PACKAGE}FILESMODE_frag-overlimit.py= 0555 ${PACKAGE}FILESMODE_frag-overreplace.py= 0555 ${PACKAGE}FILESMODE_pfsync_defer.py= 0555 ${PACKAGE}FILESMODE_pft_ether.py= 0555 .include diff --git a/tests/sys/netpfil/pf/fragmentation.sh b/tests/sys/netpfil/pf/fragmentation.sh index fb57cc62d54b..03ba5030d8aa 100644 --- a/tests/sys/netpfil/pf/fragmentation.sh +++ b/tests/sys/netpfil/pf/fragmentation.sh @@ -1,339 +1,377 @@ # $FreeBSD$ # # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2017 Kristof Provost # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. . $(atf_get_srcdir)/utils.subr atf_test_case "too_many_fragments" "cleanup" too_many_fragments_head() { atf_set descr 'IPv4 fragment limitation test' atf_set require.user root } too_many_fragments_body() { pft_init epair=$(vnet_mkepair) vnet_mkjail alcatraz ${epair}a ifconfig ${epair}b inet 192.0.2.1/24 up jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up ifconfig ${epair}b mtu 200 jexec alcatraz ifconfig ${epair}a mtu 200 jexec alcatraz pfctl -e pft_set_rules alcatraz \ "scrub all fragment reassemble" # So we know pf is limiting things jexec alcatraz sysctl net.inet.ip.maxfragsperpacket=1024 # Sanity check atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 # We can ping with < 64 fragments atf_check -s exit:0 -o ignore ping -c 1 -s 800 192.0.2.2 # Too many fragments should fail atf_check -s exit:2 -o ignore ping -c 1 -s 20000 192.0.2.2 } too_many_fragments_cleanup() { pft_cleanup } atf_test_case "v6" "cleanup" v6_head() { atf_set descr 'IPv6 fragmentation test' atf_set require.user root atf_set require.progs scapy } v6_body() { pft_init epair_send=$(vnet_mkepair) epair_link=$(vnet_mkepair) vnet_mkjail alcatraz ${epair_send}b ${epair_link}a vnet_mkjail singsing ${epair_link}b ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up jexec alcatraz sysctl net.inet6.ip6.forwarding=1 jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2 route add -6 2001:db8:43::/64 2001:db8:42::2 jexec alcatraz ifconfig ${epair_send}b inet6 -ifdisabled jexec alcatraz ifconfig ${epair_link}a inet6 -ifdisabled jexec singsing ifconfig ${epair_link}b inet6 -ifdisabled ifconfig ${epair_send}a inet6 -ifdisabled jexec alcatraz pfctl -e pft_set_rules alcatraz \ "scrub fragment reassemble" \ "block in" \ "pass in inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ "pass in inet6 proto icmp6 icmp6-type { echoreq, echorep }" # Host test atf_check -s exit:0 -o ignore \ ping -6 -c 1 2001:db8:42::2 atf_check -s exit:0 -o ignore \ ping -6 -c 1 -s 4500 2001:db8:42::2 atf_check -s exit:0 -o ignore\ ping -6 -c 1 -b 70000 -s 65000 2001:db8:42::2 # Forwarding test atf_check -s exit:0 -o ignore \ ping -6 -c 1 2001:db8:43::3 atf_check -s exit:0 -o ignore \ ping -6 -c 1 -s 4500 2001:db8:43::3 atf_check -s exit:0 -o ignore\ ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 $(atf_get_srcdir)/CVE-2019-5597.py \ ${epair_send}a \ 2001:db8:42::1 \ 2001:db8:43::3 } v6_cleanup() { pft_cleanup } atf_test_case "mtu_diff" "cleanup" mtu_diff_head() { atf_set descr 'Test reassembly across different MTUs, PR #255432' atf_set require.user root } mtu_diff_body() { pft_init epair_small=$(vnet_mkepair) epair_large=$(vnet_mkepair) vnet_mkjail first ${epair_small}b ${epair_large}a vnet_mkjail second ${epair_large}b ifconfig ${epair_small}a 192.0.2.1/25 up jexec first ifconfig ${epair_small}b 192.0.2.2/25 up jexec first sysctl net.inet.ip.forwarding=1 jexec first ifconfig ${epair_large}a 192.0.2.130/25 up jexec first ifconfig ${epair_large}a mtu 9000 jexec second ifconfig ${epair_large}b 192.0.2.131/25 up jexec second ifconfig ${epair_large}b mtu 9000 jexec second route add default 192.0.2.130 route add 192.0.2.128/25 192.0.2.2 jexec first pfctl -e pft_set_rules first \ "scrub all fragment reassemble" # Sanity checks atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.130 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.131 # Large packet that'll get reassembled and sent out in one on the large # epair atf_check -s exit:0 -o ignore ping -c 1 -s 8000 192.0.2.131 } mtu_diff_cleanup() { pft_cleanup } frag_common() { name=$1 pft_init epair=$(vnet_mkepair) vnet_mkjail alcatraz ${epair}a ifconfig ${epair}b inet 192.0.2.1/24 up jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up jexec alcatraz pfctl -e pft_set_rules alcatraz \ "scrub all fragment reassemble" # Sanity check atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 atf_check -s exit:0 -o ignore $(atf_get_srcdir)/frag-${1}.py \ --to 192.0.2.2 \ --fromaddr 192.0.2.1 \ --sendif ${epair}b \ --recvif ${epair}b } atf_test_case "overreplace" "cleanup" overreplace_head() { atf_set descr 'ping fragment that overlaps fragment at index boundary and replace it' atf_set require.user root atf_set require.progs scapy } overreplace_body() { frag_common overreplace } overreplace_cleanup() { pft_cleanup } atf_test_case "overindex" "cleanup" overindex_head() { atf_set descr 'ping fragment that overlaps the first fragment at index boundary' atf_set require.user root atf_set require.progs scapy } overindex_body() { frag_common overindex } overindex_cleanup() { pft_cleanup } atf_test_case "overlimit" "cleanup" overlimit_head() { atf_set descr 'ping fragment at index boundary that cannot be requeued' atf_set require.user root atf_set require.progs scapy } overlimit_body() { frag_common overlimit } overlimit_cleanup() { pft_cleanup } atf_test_case "reassemble" "cleanup" reassemble_head() { atf_set descr 'Test reassembly' atf_set require.user root } reassemble_body() { pft_init epair=$(vnet_mkepair) vnet_mkjail alcatraz ${epair}a ifconfig ${epair}b inet 192.0.2.1/24 up jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up # Sanity check atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 jexec alcatraz pfctl -e pft_set_rules alcatraz \ "pass out" \ "block in" \ "pass in inet proto icmp all icmp-type echoreq" # Single fragment passes atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 # But a fragmented ping does not atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 pft_set_rules alcatraz \ "scrub in" \ "pass out" \ "block in" \ "pass in inet proto icmp all icmp-type echoreq" # Both single packet & fragmented pass when we scrub atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 192.0.2.2 pft_set_rules alcatraz \ "scrub in fragment no reassemble" \ "pass out" \ "block in" \ "pass in inet proto icmp all icmp-type echoreq" # And the fragmented ping doesn't pass if we do not reassemble atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 } reassemble_cleanup() { pft_cleanup } +atf_test_case "no_df" "cleanup" +no_df_head() +{ + atf_set descr 'Test removing of DF flag' + atf_set require.user root +} + +no_df_body() +{ + setup_router_server_ipv4 + + # Tester can send long packets which will get fragmented by the router. + # Replies from server will come in fragments which might get + # reassembled resulting in a long reply packet sent back to tester. + ifconfig ${epair_tester}a mtu 9000 + jexec router ifconfig ${epair_tester}b mtu 9000 + jexec router ifconfig ${epair_server}a mtu 1500 + jexec server ifconfig ${epair_server}b mtu 1500 + + # Sanity check. + ping_server_check_reply exit:0 --ping-type=icmp + + # Enable packet reassembly with clearing of the no-df flag. + pft_set_rules router \ + "scrub all fragment reassemble no-df" \ + "block" \ + "pass inet proto icmp all icmp-type echoreq" + # Ping with non-fragmentable packets. + # pf will strip the DF flag resulting in fragmentation and packets + # getting properly forwarded. + ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF +} +no_df_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "too_many_fragments" atf_add_test_case "v6" atf_add_test_case "mtu_diff" atf_add_test_case "overreplace" atf_add_test_case "overindex" atf_add_test_case "overlimit" atf_add_test_case "reassemble" + atf_add_test_case "no_df" } diff --git a/tests/sys/netpfil/pf/checksum.sh b/tests/sys/netpfil/pf/modulate.sh similarity index 55% rename from tests/sys/netpfil/pf/checksum.sh rename to tests/sys/netpfil/pf/modulate.sh index 9060e763d18d..ea0aa596f959 100644 --- a/tests/sys/netpfil/pf/checksum.sh +++ b/tests/sys/netpfil/pf/modulate.sh @@ -1,86 +1,80 @@ +# $FreeBSD$ +# # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # -# Copyright (c) 2020 Kristof Provost +# Copyright (c) 2023 Kajetan Staszkiewicz # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. . $(atf_get_srcdir)/utils.subr -common_dir=$(atf_get_srcdir)/../common - -atf_test_case "unaligned" "cleanup" -unaligned_head() +atf_test_case "modulate_v4" "cleanup" +modulate_v4_head() { - atf_set descr 'Test unaligned checksum updates' + atf_set descr 'IPv4 TCP sequence number modulation' atf_set require.user root atf_set require.progs scapy } -unaligned_body() +modulate_v4_body() { - pft_init - - epair_in=$(vnet_mkepair) - epair_out=$(vnet_mkepair) - - vnet_mkjail alcatraz ${epair_in}b ${epair_out}a + setup_router_dummy_ipv4 - ifconfig ${epair_in}a 192.0.2.2/24 up - route add -net 198.51.100.0/24 192.0.2.1 - - jexec alcatraz ifconfig ${epair_in}b 192.0.2.1/24 up - jexec alcatraz sysctl net.inet.ip.forwarding=1 - - jexec alcatraz ifconfig ${epair_out}a 198.51.100.1/24 up - jexec alcatraz arp -s 198.51.100.2 00:01:02:03:04:05 + pft_set_rules router \ + "pass in on ${epair_tester}b modulate state" + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-seq 42 # Sanity check + ping_dummy_check_request exit:1 --ping-type=tcpsyn --send-seq 42 --expect-seq 42 +} - ifconfig ${epair_out}b up +modulate_v4_cleanup() +{ + pft_cleanup +} - jexec alcatraz pfctl -e - pft_set_rules alcatraz \ - "scrub on ${epair_in}b reassemble tcp max-mss 1200" +atf_test_case "modulate_v6" "cleanup" +modulate_v6_head() +{ + atf_set descr 'IPv6 TCP sequence number modulation' + atf_set require.user root + atf_set require.progs scapy +} - # Check aligned - atf_check -s exit:0 ${common_dir}/pft_ping.py \ - --sendif ${epair_in}a \ - --to 198.51.100.2 \ - --recvif ${epair_out}b \ - --ping-type tcpsyn +modulate_v6_body() +{ + setup_router_dummy_ipv6 - # And unaligned - atf_check -s exit:0 ${common_dir}/pft_ping.py \ - --sendif ${epair_in}a \ - --to 198.51.100.2 \ - --recvif ${epair_out}b \ - --ping-type tcpsyn \ - --send-tcpopt-unaligned + pft_set_rules router \ + "pass in on ${epair_tester}b modulate state" + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-seq 42 # Sanity check + ping_dummy_check_request exit:1 --ping-type=tcpsyn --send-seq 42 --expect-seq 42 } -unaligned_cleanup() +modulate_v6_cleanup() { pft_cleanup } atf_init_test_cases() { - atf_add_test_case "unaligned" + atf_add_test_case "modulate_v4" + atf_add_test_case "modulate_v6" } diff --git a/tests/sys/netpfil/pf/rtable.sh b/tests/sys/netpfil/pf/rtable.sh new file mode 100644 index 000000000000..2362176636ac --- /dev/null +++ b/tests/sys/netpfil/pf/rtable.sh @@ -0,0 +1,131 @@ +# $FreeBSD$ +# +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2023 Kajetan Staszkiewicz +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +. $(atf_get_srcdir)/utils.subr + +atf_test_case "forward_v4" "cleanup" +forward_v4_head() +{ + atf_set descr 'Test IPv4 forwarding with rtable' + atf_set require.user root + atf_set require.progs scapy +} + +forward_v4_body() +{ + setup_router_server_ipv4 + + # Sanity check + ping_server_check_reply exit:0 + + jexec router sysctl net.fibs=2 + jexec router ifconfig ${epair_server}a fib 1 + jexec router route del -net ${net_server} + jexec router route add -fib 1 -net ${net_server} -iface ${epair_server}a + + # Sanity check + ping_server_check_reply exit:1 + + # This rule is not enough. + # Echo requests will be properly forwarded but replies can't be routed back. + pft_set_rules router \ + "pass in on ${epair_tester}b inet proto icmp all icmp-type echoreq rtable 1" + ping_server_check_reply exit:1 + + # Allow replies coming back to the tester properly via stateful filtering post-routing. + pft_set_rules router \ + "pass in on ${epair_tester}b inet proto icmp all icmp-type echoreq rtable 1" \ + "pass out on ${epair_server}a inet proto icmp all icmp-type echoreq rtable 0" + ping_server_check_reply exit:0 + + # Allow replies coming back to the tester properly via provding extra routes in rtable 1 + pft_set_rules router \ + "pass in on ${epair_tester}b inet proto icmp all icmp-type echoreq rtable 1" + jexec router route add -fib 1 -net ${net_tester} -iface ${epair_tester}b + ping_server_check_reply exit:0 +} + +forward_v4_cleanup() +{ + pft_cleanup +} + +atf_test_case "forward_v6" "cleanup" +forward_v6_head() +{ + atf_set descr 'Test IPv6 forwarding with rtable' + atf_set require.user root + atf_set require.progs scapy +} + +forward_v6_body() +{ + setup_router_server_ipv6 + + # Sanity check + ping_server_check_reply exit:0 + + jexec router sysctl net.fibs=2 + jexec router ifconfig ${epair_server}a fib 1 + jexec router route del -6 ${net_server} + jexec router route add -fib 1 -6 ${net_server} -iface ${epair_server}a + + # Sanity check + ping_server_check_reply exit:1 + + # This rule is not enough. + # Echo requests will be properly forwarded but replies can't be routed back. + pft_set_rules router \ + "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ + "pass in on ${epair_tester}b inet6 proto icmp6 icmp6-type echoreq" + ping_server_check_reply exit:1 + + # Allow replies coming back to the tester properly via stateful filtering post-routing. + pft_set_rules router \ + "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ + "pass in on ${epair_tester}b inet6 proto icmp6 icmp6-type echoreq rtable 1" \ + "pass out on ${epair_server}a inet6 proto icmp6 icmp6-type echoreq rtable 0" + ping_server_check_reply exit:0 + + # Allow replies coming back to the tester properly via provding extra routes in rtable 1 + pft_set_rules router \ + "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ + "pass in on ${epair_tester}b inet6 proto icmp6 icmp6-type echoreq rtable 1" + jexec router route add -fib 1 -6 ${net_tester} -iface ${epair_tester}b + ping_server_check_reply exit:0 +} + +forward_v6_cleanup() +{ + pft_cleanup +} + +atf_init_test_cases() +{ + atf_add_test_case "forward_v4" + atf_add_test_case "forward_v6" +} diff --git a/tests/sys/netpfil/pf/scrub.sh b/tests/sys/netpfil/pf/scrub.sh new file mode 100644 index 000000000000..ccc991ac1929 --- /dev/null +++ b/tests/sys/netpfil/pf/scrub.sh @@ -0,0 +1,221 @@ +# $FreeBSD$ +# +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2020 Kristof Provost +# Copyright (c) 2023 Kajetan Staszkiewicz +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +. $(atf_get_srcdir)/utils.subr + +atf_test_case "max_mss_v4" "cleanup" +max_mss_v4_head() +{ + atf_set descr 'Test IPv4 scrub "mss" rule' + atf_set require.user root + atf_set require.progs scapy +} + +max_mss_v4_body() +{ + setup_router_dummy_ipv4 + pft_set_rules router "scrub on ${epair_tester}b max-mss 1300" + # Check aligned + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-mss=1400 --expect-mss=1300 + # And unaligned + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-mss=1400 --expect-mss=1300 \ + --send-tcpopt-unaligned +} + +max_mss_v4_cleanup() +{ + pft_cleanup +} + + +atf_test_case "max_mss_v6" "cleanup" +max_mss_v6_head() +{ + atf_set descr 'Test IPv6 scrub "mss" rule' + atf_set require.user root + atf_set require.progs scapy +} + +max_mss_v6_body() +{ + setup_router_dummy_ipv6 + pft_set_rules router "scrub on ${epair_tester}b max-mss 1300" + # Check aligned + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-mss=1400 --expect-mss=1300 + # And unaligned + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-mss=1400 --expect-mss=1300 \ + --send-tcpopt-unaligned +} + +max_mss_v6_cleanup() +{ + pft_cleanup +} + + +atf_test_case "set_tos_v4" "cleanup" +set_tos_v4_head() +{ + atf_set descr 'Test IPv4 scub "set-tos" rule' + atf_set require.user root + atf_set require.progs scapy +} + +set_tos_v4_body() +{ + setup_router_dummy_ipv4 + pft_set_rules router "scrub on ${epair_tester}b set-tos 0x42" + ping_dummy_check_request exit:0 --send-tc=0 --expect-tc=66 +} + +set_tos_v4_cleanup() +{ + pft_cleanup +} + + +atf_test_case "set_tos_v6" "cleanup" +set_tos_v6_head() +{ + atf_set descr 'Test IPv6 scub "set-tos" rule' + atf_set require.user root + atf_set require.progs scapy +} + +set_tos_v6_body() +{ + setup_router_dummy_ipv6 + pft_set_rules router "scrub on ${epair_tester}b set-tos 0x42" + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-tc=0 --expect-tc=66 +} + +set_tos_v6_cleanup() +{ + pft_cleanup +} + + +atf_test_case "min_ttl_v4" "cleanup" +min_ttl_v4_head() +{ + atf_set descr 'Test IPv4 scub "min-ttl" rule' + atf_set require.user root + atf_set require.progs scapy +} + +min_ttl_v4_body() +{ + setup_router_dummy_ipv4 + pft_set_rules router "scrub on ${epair_tester}b min-ttl 50" + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-hlim=40 --expect-hlim=49 +} + +min_ttl_v4_cleanup() +{ + pft_cleanup +} + + +atf_test_case "min_ttl_v6" "cleanup" +min_ttl_v6_head() +{ + atf_set descr 'Test IPv6 scub "min-ttl" rule' + atf_set require.user root + atf_set require.progs scapy +} + +min_ttl_v6_body() +{ + setup_router_dummy_ipv6 + pft_set_rules router "scrub on ${epair_tester}b min-ttl 50" + ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-hlim=40 --expect-hlim=49 +} + +min_ttl_v6_cleanup() +{ + pft_cleanup +} + + +atf_test_case "no_scrub_v4" "cleanup" +no_scrub_v4_head() +{ + atf_set descr 'Test IPv4 "no scrub" rule' + atf_set require.user root + atf_set require.progs scapy +} + +no_scrub_v4_body() +{ + setup_router_dummy_ipv4 + pft_set_rules router\ + "no scrub on ${epair_tester}b to ${net_server_host_server}" + "scrub on ${epair_tester}b set-tos 0x42" + ping_dummy_check_request exit:0 --send-tc=0 --expect-tc=0 +} + +no_scrub_v4_cleanup() +{ + pft_cleanup +} + + +atf_test_case "no_scrub_v6" "cleanup" +no_scrub_v6_head() +{ + atf_set descr 'Test IPv6 "no scrub" rule' + atf_set require.user root + atf_set require.progs scapy +} + +no_scrub_v6_body() +{ + setup_router_dummy_ipv6 + pft_set_rules router \ + "no scrub on ${epair_tester}b to ${net_server_host_server}" + "scrub on ${epair_tester}b set-tos 0x42" + ping_dummy_check_request exit:0 --send-tc=0 --expect-tc=0 +} + +no_scrub_v6_cleanup() +{ + pft_cleanup +} + + +atf_init_test_cases() +{ + atf_add_test_case "max_mss_v4" + atf_add_test_case "max_mss_v6" + atf_add_test_case "set_tos_v4" + atf_add_test_case "set_tos_v6" + atf_add_test_case "min_ttl_v4" + atf_add_test_case "min_ttl_v6" + atf_add_test_case "no_scrub_v4" + atf_add_test_case "no_scrub_v6" +} diff --git a/tests/sys/netpfil/pf/utils.subr b/tests/sys/netpfil/pf/utils.subr index f4f7f4fe4d83..d8696b988098 100644 --- a/tests/sys/netpfil/pf/utils.subr +++ b/tests/sys/netpfil/pf/utils.subr @@ -1,155 +1,291 @@ # $FreeBSD$ # Utility functions ## # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2017 Kristof Provost +# Copyright (c) 2023 Kajetan Staszkiewicz # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. . $(atf_get_srcdir)/../../common/vnet.subr +common_dir=$(atf_get_srcdir)/../common pft_onerror() { status=$? echo "Debug log." echo "==========" echo "Test exit status: $?" echo if [ -f created_jails.lst ]; then for jailname in `cat created_jails.lst` do echo "Jail ${jailname}" echo "----------------" jexec ${jailname} ifconfig jexec ${jailname} netstat -rn jexec ${jailname} pfctl -sa -v done fi echo "Created interfaces:" echo "-------------------" cat created_interfaces.lst echo "Host interfaces:" echo "----------------" ifconfig } pft_init() { if [ "$1" == "debug" ] then trap pft_onerror EXIT fi vnet_init if [ ! -c /dev/pf ]; then atf_skip "This test requires pf" fi } pfsynct_init() { pft_init if ! kldstat -q -m pfsync; then atf_skip "This test requires pfsync" fi } pflog_init() { if ! kldstat -q -m pflog; then atf_skip "This test requires pflog" fi } dummynet_init() { pft_init if ! kldstat -q -m dummynet; then atf_skip "This test requires dummynet" fi } pft_set_rules() { jname=$1 shift if [ $jname == "noflush" ]; then jname=$1 shift else # Flush all states, rules, fragments, ... jexec ${jname} pfctl -F all fi while [ $# -gt 0 ]; do printf "$1\n" shift done | jexec ${jname} pfctl -f - if [ $? -ne 0 ]; then atf_fail "Failed to set PF rules in ${jname}" fi } pft_cleanup() { vnet_cleanup } pfsynct_cleanup() { pft_cleanup } is_altq_supported() { sysctl -q kern.features.altq >/dev/null || \ atf_skip "Test requires ALTQ" while [ -n "$1" ] do sysctl -q kern.features.altq.${1} >/dev/null || \ atf_skip "Test required ALTQ_${1}" shift done } altq_init() { pft_init is_altq_supported } altq_cleanup() { pft_cleanup } + +# Create a bare router jail. +# This function lacks target configuration. +setup_router_ipv4() +{ + pft_init + + epair_tester=$(vnet_mkepair) + epair_server=$(vnet_mkepair) + + net_tester=192.0.2.0/24 + net_tester_mask=24 + net_tester_host_router=192.0.2.1 + net_tester_host_tester=192.0.2.2 + + net_server=198.51.100.0/24 + net_server_mask=24 + net_server_host_router=198.51.100.1 + net_server_host_server=198.51.100.2 + + vnet_mkjail router ${epair_tester}b ${epair_server}a + + ifconfig ${epair_tester}a ${net_tester_host_tester}/${net_tester_mask} up + route add -net ${net_server} ${net_tester_host_router} + + jexec router ifconfig ${epair_tester}b ${net_tester_host_router}/${net_tester_mask} up + jexec router sysctl net.inet.ip.forwarding=1 + jexec router ifconfig ${epair_server}a ${net_server_host_router}/${net_server_mask} up + + jexec router pfctl -e +} + +# Create a router jail. +# The target for tests does not exist but a static ARP entry does +# so packets to it can be properly routed. +setup_router_dummy_ipv4() +{ + setup_router_ipv4 + jexec router arp -s ${net_server_host_server} 00:01:02:03:04:05 + ifconfig ${epair_server}b up +} + +# Create a router and a server jail. +# The server is capable of responding to pings from the tester. +setup_router_server_ipv4() +{ + setup_router_ipv4 + vnet_mkjail server ${epair_server}b + jexec server ifconfig ${epair_server}b ${net_server_host_server}/${net_server_mask} up + jexec server route add -net ${net_tester} ${net_server_host_router} + jexec server nc -4l 666 & + sleep 1 # Give nc time to start and listen +} + +# Create a bare router jail. +# This function lacks target configuration. +setup_router_ipv6() +{ + pft_init + + epair_tester=$(vnet_mkepair) + epair_server=$(vnet_mkepair) + + net_tester=2001:db8:42::/64 + net_tester_mask=64 + net_tester_host_router=2001:db8:42::1 + net_tester_host_tester=2001:db8:42::2 + + net_server=2001:db8:43::/64 + net_server_mask=64 + net_server_host_router=2001:db8:43::1 + net_server_host_server=2001:db8:43::2 + + vnet_mkjail router ${epair_tester}b ${epair_server}a + + ifconfig ${epair_tester}a inet6 ${net_tester_host_tester}/${net_tester_mask}up no_dad + route add -6 ${net_server} ${net_tester_host_router} + + jexec router ifconfig ${epair_tester}b inet6 ${net_tester_host_router}/${net_tester_mask} up no_dad + jexec router sysctl net.inet6.ip6.forwarding=1 + jexec router ifconfig ${epair_server}a inet6 ${net_server_host_router}/${net_server_mask} up no_dad + + jexec router pfctl -e +} + +# Create a router jail. +# The target for tests does not exist but a static NDP entry does +# so packets to it can be properly routed. +setup_router_dummy_ipv6() +{ + setup_router_ipv6 + jexec router ndp -s ${net_server_host_server} 00:01:02:03:04:05 + ifconfig ${epair_server}b up +} + +# Create a router and a server jail. +# The server is capable of responding to pings from tester. +setup_router_server_ipv6() +{ + setup_router_ipv6 + vnet_mkjail server ${epair_server}b + jexec server ifconfig ${epair_server}b inet6 ${net_server_host_server}/${net_server_mask} up no_dad + jexec server route add -6 ${net_tester} ${net_server_host_router} + jexec server nc -6l 666 & + sleep 1 # Give nc time to start and listen +} + +# Ping the dummy static NDP target. +# Check for pings being forwarded through the router towards the target. +ping_dummy_check_request() +{ + exit_condition=$1 + shift + params=$@ + atf_check -s ${exit_condition} ${common_dir}/pft_ping.py \ + --sendif ${epair_tester}a \ + --to ${net_server_host_server} \ + --recvif ${epair_server}b \ + $params +} + +# Ping the server jail. +# Check for responses coming back throught the router back to the tester. +ping_server_check_reply() +{ + exit_condition=$1 + shift + params=$@ + atf_check -s ${exit_condition} ${common_dir}/pft_ping.py \ + --sendif ${epair_tester}a \ + --to ${net_server_host_server} \ + --replyif ${epair_tester}a \ + $params +}