Path: blob/main/tests/sys/netpfil/pf/divert-to.sh
108778 views
#1# SPDX-License-Identifier: BSD-2-Clause2#3# Copyright (c) 2023 Igor Ostapenko <[email protected]>4#5# Redistribution and use in source and binary forms, with or without6# modification, are permitted provided that the following conditions7# are met:8# 1. Redistributions of source code must retain the above copyright9# notice, this list of conditions and the following disclaimer.10# 2. Redistributions in binary form must reproduce the above copyright11# notice, this list of conditions and the following disclaimer in the12# documentation and/or other materials provided with the distribution.13#14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24# SUCH DAMAGE.2526#27# pf divert-to action test cases28#29# -----------| |-- |----| ----| |-----------30# ( ) inbound |pf_check_in| ) -> |host| -> ( ) |pf_check_out| outbound )31# -----------| | |-- |----| ----| | |-----------32# | |33# \|/ \|/34# |------| |------|35# |divapp| |divapp|36# |------| |------|37#38# The basic cases:39# - inbound > diverted | divapp terminated40# - inbound > diverted > inbound | host terminated41# - inbound > diverted > outbound | network terminated42# - outbound > diverted | divapp terminated43# - outbound > diverted > outbound | network terminated44# - outbound > diverted > inbound | e.g. host terminated45#46# When a packet is diverted, forwarded, and possibly diverted again:47# - inbound > diverted > inbound > forwarded48# > outbound | network terminated49# - inbound > diverted > inbound > forwarded50# > outbound > diverted > outbound | network terminated51#52# Test case naming legend:53# in - inbound54# div - diverted55# out - outbound56# fwd - forwarded57# dn - delayed by dummynet58#5960. $(atf_get_srcdir)/utils.subr6162atf_test_case "in_div" "cleanup"63in_div_head()64{65atf_set descr 'Test inbound > diverted | divapp terminated'66atf_set require.user root67atf_set require.kmods ipdivert68}69in_div_body()70{71pft_init7273epair=$(vnet_mkepair)74vnet_mkjail div ${epair}b75atf_check ifconfig ${epair}a 192.0.2.1/24 up76atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad77atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up78atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad7980# Sanity check81atf_check -o ignore ping -c3 192.0.2.282atf_check -o ignore ping -c3 2001:db8::28384jexec div pfctl -e85pft_set_rules div \86"pass all" \87"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000" \88"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2000"8990jexec div $(atf_get_srcdir)/../common/divapp 2000 &91divapp_pid=$!92# Wait for the divapp to be ready93sleep 19495# divapp is expected to "eat" the packet96atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.29798wait $divapp_pid99100jexec div $(atf_get_srcdir)/../common/divapp 2000 &101divapp_pid=$!102# Wait for the divapp to be ready103sleep 1104105# divapp is expected to "eat" the packet106atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2107108wait $divapp_pid109}110in_div_cleanup()111{112pft_cleanup113}114115atf_test_case "in_div_in" "cleanup"116in_div_in_head()117{118atf_set descr 'Test inbound > diverted > inbound | host terminated'119atf_set require.user root120atf_set require.kmods ipdivert121}122in_div_in_body()123{124pft_init125126epair=$(vnet_mkepair)127vnet_mkjail div ${epair}b128atf_check ifconfig ${epair}a 192.0.2.1/24 up129atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad130atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up131atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad132133# Sanity check134atf_check -o ignore ping -c3 192.0.2.2135atf_check -o ignore ping -c3 2001:db8::2136137jexec div pfctl -e138pft_set_rules div \139"pass all" \140"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000 no state" \141"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2000 no state"142143jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &144divapp_pid=$!145# Wait for the divapp to be ready146sleep 1147148# divapp is NOT expected to "eat" the packet149atf_check -s exit:0 -o ignore ping -c1 192.0.2.2150151wait $divapp_pid152153jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &154divapp_pid=$!155# Wait for the divapp to be ready156sleep 1157158# divapp is expected to "eat" the packet159atf_check -s exit:0 -o ignore ping -c1 -t1 2001:db8::2160161wait $divapp_pid162}163in_div_in_cleanup()164{165pft_cleanup166}167168atf_test_case "out_div" "cleanup"169out_div_head()170{171atf_set descr 'Test outbound > diverted | divapp terminated'172atf_set require.user root173atf_set require.kmods ipdivert174}175out_div_body()176{177pft_init178179epair=$(vnet_mkepair)180vnet_mkjail div ${epair}b181atf_check ifconfig ${epair}a 192.0.2.1/24 up182atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad183atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up184atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad185186# Sanity check187atf_check -o ignore ping -c3 192.0.2.2188atf_check -o ignore ping -c3 2001:db8::2189190jexec div pfctl -e191pft_set_rules div \192"pass all" \193"pass in inet proto icmp icmp-type echoreq no state" \194"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state" \195"pass in inet6 proto icmp6 icmp6-type echoreq no state" \196"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 2000 no state"197198jexec div $(atf_get_srcdir)/../common/divapp 2000 &199divapp_pid=$!200# Wait for the divapp to be ready201sleep 1202203# divapp is expected to "eat" the packet204atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2205206wait $divapp_pid207208jexec div $(atf_get_srcdir)/../common/divapp 2000 &209divapp_pid=$!210# Wait for the divapp to be ready211sleep 1212213# divapp is expected to "eat" the packet214atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2215216wait $divapp_pid217}218out_div_cleanup()219{220pft_cleanup221}222223atf_test_case "out_div_out" "cleanup"224out_div_out_head()225{226atf_set descr 'Test outbound > diverted > outbound | network terminated'227atf_set require.user root228atf_set require.kmods ipdivert229}230out_div_out_body()231{232pft_init233234epair=$(vnet_mkepair)235vnet_mkjail div ${epair}b236atf_check ifconfig ${epair}a 192.0.2.1/24 up237atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad238atf_check jexec div ifconfig ${epair}b 192.0.2.2/24 up239atf_check jexec div ifconfig ${epair}b inet6 2001:db8::2/64 no_dad240241# Sanity check242atf_check -o ignore ping -c3 192.0.2.2243atf_check -o ignore ping -c3 2001:db8::2244245jexec div pfctl -e246pft_set_rules div \247"pass all" \248"pass in inet proto icmp icmp-type echoreq no state" \249"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state" \250"pass in inet6 proto icmp6 icmp6-type echoreq no state" \251"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 2000 no state"252253jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &254divapp_pid=$!255# Wait for the divapp to be ready256sleep 1257258# divapp is NOT expected to "eat" the packet259atf_check -s exit:0 -o ignore ping -c1 192.0.2.2260261wait $divapp_pid262263jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back &264divapp_pid=$!265# Wait for the divapp to be ready266sleep 1267268# divapp is NOT expected to "eat" the packet269atf_check -s exit:0 -o ignore ping -c1 2001:db8::2270271wait $divapp_pid272}273out_div_out_cleanup()274{275pft_cleanup276}277278atf_test_case "in_div_in_fwd_out_div_out" "cleanup"279in_div_in_fwd_out_div_out_head()280{281atf_set descr 'Test inbound > diverted > inbound > forwarded > outbound > diverted > outbound | network terminated'282atf_set require.user root283atf_set require.kmods ipdivert284}285in_div_in_fwd_out_div_out_body()286{287pft_init288289# host <a--epair0--b> router <a--epair1--b> site290epair0=$(vnet_mkepair)291epair1=$(vnet_mkepair)292293vnet_mkjail router ${epair0}b ${epair1}a294atf_check ifconfig ${epair0}a 192.0.2.1/24 up295atf_check ifconfig ${epair0}a inet6 2001:db8::1/64 no_dad296atf_check -o ignore jexec router sysctl net.inet.ip.forwarding=1297atf_check -o ignore jexec router sysctl net.inet6.ip6.forwarding=1298atf_check jexec router ifconfig ${epair0}b 192.0.2.2/24 up299atf_check jexec router ifconfig ${epair0}b inet6 2001:db8::2/64 no_dad300atf_check jexec router ifconfig ${epair1}a 198.51.100.1/24 up301atf_check jexec router ifconfig ${epair1}a inet6 2001:db9::1/64 no_dad302303vnet_mkjail site ${epair1}b304jexec site ifconfig ${epair1}b 198.51.100.2/24 up305jexec site ifconfig ${epair1}b inet6 2001:db9::2/64 no_dad306jexec site route add default 198.51.100.1307jexec site route -6 add default 2001:db9::1308309atf_check -o ignore route add -net 198.51.100.0/24 192.0.2.2310atf_check -o ignore route -6 add -net 2001:db9::/64 2001:db8::2311312# Sanity check313atf_check -o ignore ping -c3 192.0.2.2314atf_check -o ignore ping -c3 2001:db8::2315316# Should be routed without pf317atf_check -o ignore ping -c3 198.51.100.2318atf_check -o ignore ping -c3 2001:db9::2319320jexec router pfctl -e321pft_set_rules router \322"pass all" \323"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \324"pass out inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2002 no state" \325"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2001 no state" \326"pass out inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2002 no state"327328jexec router $(atf_get_srcdir)/../common/divapp 2001 divert-back &329indivapp_pid=$!330jexec router $(atf_get_srcdir)/../common/divapp 2002 divert-back &331outdivapp_pid=$!332# Wait for the divapps to be ready333sleep 1334335# Both divapps are NOT expected to "eat" the packet336atf_check -s exit:0 -o ignore ping -c1 198.51.100.2337338wait $indivapp_pid && wait $outdivapp_pid339340jexec router $(atf_get_srcdir)/../common/divapp 2001 divert-back &341indivapp_pid=$!342jexec router $(atf_get_srcdir)/../common/divapp 2002 divert-back &343outdivapp_pid=$!344# Wait for the divapps to be ready345sleep 1346347# Both divapps are NOT expected to "eat" the packet348atf_check -o ignore ping -c1 2001:db9::2349350wait $indivapp_pid && wait $outdivapp_pid351}352in_div_in_fwd_out_div_out_cleanup()353{354pft_cleanup355}356357atf_test_case "in_dn_in_div_in_out_div_out_dn_out" "cleanup"358in_dn_in_div_in_out_div_out_dn_out_head()359{360atf_set descr 'Test inbound > delayed+diverted > outbound > diverted+delayed > outbound | network terminated'361atf_set require.user root362atf_set require.kmods dummynet ipdivert363}364in_dn_in_div_in_out_div_out_dn_out_body()365{366pft_init367368epair=$(vnet_mkepair)369vnet_mkjail alcatraz ${epair}b370atf_check ifconfig ${epair}a 192.0.2.1/24 up371atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad372atf_check ifconfig ${epair}a ether 02:00:00:00:00:01373atf_check jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up374atf_check jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 no_dad375376# Sanity check377atf_check -o ignore ping -c3 192.0.2.2378atf_check -o ignore ping -c3 2001:db8::2379380# a) ping should time out due to very narrow dummynet pipes {381382jexec alcatraz dnctl pipe 1001 config bw 1Byte/s383jexec alcatraz dnctl pipe 1002 config bw 1Byte/s384385jexec alcatraz pfctl -e386pft_set_rules alcatraz \387"ether pass in from 02:00:00:00:00:01 l3 all dnpipe 1001" \388"ether pass out to 02:00:00:00:00:01 l3 all dnpipe 1002 " \389"pass all" \390"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 1001 no state" \391"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 1002 no state" \392"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 1001 no state" \393"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 1002 no state"394395jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &396indivapp_pid=$!397jexec alcatraz $(atf_get_srcdir)/../common/divapp 1002 divert-back &398outdivapp_pid=$!399# Wait for the divapps to be ready400sleep 1401402atf_check -s not-exit:0 -o ignore ping -c1 -s56 -t1 192.0.2.2403404wait $indivapp_pid405atf_check_not_equal 0 $?406wait $outdivapp_pid407atf_check_not_equal 0 $?408409jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &410indivapp_pid=$!411jexec alcatraz $(atf_get_srcdir)/../common/divapp 1002 divert-back &412outdivapp_pid=$!413# Wait for the divapps to be ready414sleep 1415416atf_check -s not-exit:0 -o ignore ping -c1 -s56 -t1 2001:db8::2417418wait $indivapp_pid419atf_check_not_equal 0 $?420wait $outdivapp_pid421atf_check_not_equal 0 $?422423# }424425# b) ping should NOT time out due to wide enough dummynet pipes {426427jexec alcatraz dnctl pipe 2001 config bw 100KByte/s428jexec alcatraz dnctl pipe 2002 config bw 100KByte/s429430jexec alcatraz pfctl -e431pft_set_rules alcatraz \432"ether pass in from 02:00:00:00:00:01 l3 all dnpipe 2001" \433"ether pass out to 02:00:00:00:00:01 l3 all dnpipe 2002 " \434"pass all" \435"pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \436"pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2002 no state" \437"pass in inet6 proto icmp6 icmp6-type echoreq divert-to ::1 port 2001 no state" \438"pass out inet6 proto icmp6 icmp6-type echorep divert-to ::1 port 2002 no state"439440jexec alcatraz $(atf_get_srcdir)/../common/divapp 2001 divert-back &441indivapp_pid=$!442jexec alcatraz $(atf_get_srcdir)/../common/divapp 2002 divert-back &443outdivapp_pid=$!444# Wait for the divapps to be ready445sleep 1446447atf_check -o ignore ping -c1 -s56 -t1 192.0.2.2448449wait $indivapp_pid450atf_check_equal 0 $?451wait $outdivapp_pid452atf_check_equal 0 $?453454jexec alcatraz $(atf_get_srcdir)/../common/divapp 2001 divert-back &455indivapp_pid=$!456jexec alcatraz $(atf_get_srcdir)/../common/divapp 2002 divert-back &457outdivapp_pid=$!458# Wait for the divapps to be ready459sleep 1460461atf_check -o ignore ping -c1 -s56 -t1 2001:db8::2462463wait $indivapp_pid464atf_check_equal 0 $?465wait $outdivapp_pid466atf_check_equal 0 $?467468# }469}470in_dn_in_div_in_out_div_out_dn_out_cleanup()471{472pft_cleanup473}474475atf_test_case "pr260867" "cleanup"476pr260867_head()477{478atf_set descr 'Test for the loop reported in PR260867'479atf_set require.user root480atf_set require.kmods ipdivert481}482pr260867_body()483{484pft_init485486epair=$(vnet_mkepair)487488atf_check ifconfig ${epair}a 192.0.2.1/24 up489atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad490491vnet_mkjail alcatraz ${epair}b492atf_check jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up493atf_check jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 no_dad494495# Sanity check496atf_check -o ignore ping -c3 192.0.2.2497atf_check -o ignore ping -c3 2001:db8::2498499jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf500jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &501502jexec alcatraz pfctl -e503pft_set_rules alcatraz \504"pass in on ${epair}b proto tcp from any to port 7 divert-to 0.0.0.0 port 1001"505506reply=$(echo "foo" | nc -N 192.0.2.2 7)507if [ "${reply}" != "foo" ]; then508atf_fail "Did not receive v4 echo reply"509fi510511reply=$(echo "foo" | nc -N -6 2001:db8::2 7)512if [ "${reply}" != "foo" ]; then513atf_fail "Did not receive v6 echo reply"514fi515}516pr260867_cleanup()517{518pft_cleanup519}520521atf_test_case "pr260867_icmp" "cleanup"522pr260867_icmp_head()523{524atf_set descr 'Variant of the PR260867 test'525atf_set require.user root526atf_set require.kmods ipdivert527}528pr260867_icmp_body()529{530pft_init531532epair=$(vnet_mkepair)533534atf_check ifconfig ${epair}a 192.0.2.1/24 up535atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad536537vnet_mkjail alcatraz ${epair}b538atf_check jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up539atf_check jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 no_dad540541# Sanity check542atf_check -o ignore ping -c3 192.0.2.2543atf_check -o ignore ping -c3 2001:db8::2544545jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &546547jexec alcatraz pfctl -e548pft_set_rules alcatraz \549"pass in on ${epair}b proto icmp from any to any divert-to 0.0.0.0 port 1001" \550"pass in on ${epair}b proto icmp6 from any to any divert-to :: port 1001"551552atf_check -o ignore ping -c 3 192.0.2.2553atf_check -o ignore ping -c 3 2001:db8::2554}555pr260867_icmp_cleanup()556{557pft_cleanup558}559560atf_init_test_cases()561{562atf_add_test_case "in_div"563atf_add_test_case "in_div_in"564565atf_add_test_case "out_div"566atf_add_test_case "out_div_out"567568atf_add_test_case "in_div_in_fwd_out_div_out"569570atf_add_test_case "in_dn_in_div_in_out_div_out_dn_out"571572atf_add_test_case "pr260867"573atf_add_test_case "pr260867_icmp"574}575576577