1*cc7ec8feSIgor Ostapenko# 2*cc7ec8feSIgor Ostapenko# SPDX-License-Identifier: BSD-2-Clause 3*cc7ec8feSIgor Ostapenko# 4*cc7ec8feSIgor Ostapenko# Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro> 5*cc7ec8feSIgor Ostapenko# 6*cc7ec8feSIgor Ostapenko# Redistribution and use in source and binary forms, with or without 7*cc7ec8feSIgor Ostapenko# modification, are permitted provided that the following conditions 8*cc7ec8feSIgor Ostapenko# are met: 9*cc7ec8feSIgor Ostapenko# 1. Redistributions of source code must retain the above copyright 10*cc7ec8feSIgor Ostapenko# notice, this list of conditions and the following disclaimer. 11*cc7ec8feSIgor Ostapenko# 2. Redistributions in binary form must reproduce the above copyright 12*cc7ec8feSIgor Ostapenko# notice, this list of conditions and the following disclaimer in the 13*cc7ec8feSIgor Ostapenko# documentation and/or other materials provided with the distribution. 14*cc7ec8feSIgor Ostapenko# 15*cc7ec8feSIgor Ostapenko# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*cc7ec8feSIgor Ostapenko# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*cc7ec8feSIgor Ostapenko# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*cc7ec8feSIgor Ostapenko# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*cc7ec8feSIgor Ostapenko# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*cc7ec8feSIgor Ostapenko# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*cc7ec8feSIgor Ostapenko# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*cc7ec8feSIgor Ostapenko# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*cc7ec8feSIgor Ostapenko# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*cc7ec8feSIgor Ostapenko# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*cc7ec8feSIgor Ostapenko# SUCH DAMAGE. 26*cc7ec8feSIgor Ostapenko 27*cc7ec8feSIgor Ostapenko# 28*cc7ec8feSIgor Ostapenko# ipfw divert action test cases 29*cc7ec8feSIgor Ostapenko# 30*cc7ec8feSIgor Ostapenko# -----------| |-- |----| ----| |----------- 31*cc7ec8feSIgor Ostapenko# ( ) inbound |ipfw| ) -> |host| -> ( ) |ipfw| outbound ) 32*cc7ec8feSIgor Ostapenko# -----------| | |-- |----| ----| | |----------- 33*cc7ec8feSIgor Ostapenko# | | 34*cc7ec8feSIgor Ostapenko# \|/ \|/ 35*cc7ec8feSIgor Ostapenko# |------| |------| 36*cc7ec8feSIgor Ostapenko# |divapp| |divapp| 37*cc7ec8feSIgor Ostapenko# |------| |------| 38*cc7ec8feSIgor Ostapenko# 39*cc7ec8feSIgor Ostapenko# The basic cases: 40*cc7ec8feSIgor Ostapenko# - inbound > diverted | divapp terminated 41*cc7ec8feSIgor Ostapenko# - inbound > diverted > inbound | host terminated 42*cc7ec8feSIgor Ostapenko# - inbound > diverted > outbound | network terminated 43*cc7ec8feSIgor Ostapenko# - outbound > diverted | divapp terminated 44*cc7ec8feSIgor Ostapenko# - outbound > diverted > outbound | network terminated 45*cc7ec8feSIgor Ostapenko# - outbound > diverted > inbound | e.g. host terminated 46*cc7ec8feSIgor Ostapenko# 47*cc7ec8feSIgor Ostapenko# When a packet is diverted, forwarded, and possibly diverted again: 48*cc7ec8feSIgor Ostapenko# - inbound > diverted > inbound > forwarded 49*cc7ec8feSIgor Ostapenko# > outbound | network terminated 50*cc7ec8feSIgor Ostapenko# - inbound > diverted > inbound > forwarded 51*cc7ec8feSIgor Ostapenko# > outbound > diverted > outbound | network terminated 52*cc7ec8feSIgor Ostapenko# 53*cc7ec8feSIgor Ostapenko# Test case naming legend: 54*cc7ec8feSIgor Ostapenko# in - inbound 55*cc7ec8feSIgor Ostapenko# div - diverted 56*cc7ec8feSIgor Ostapenko# out - outbound 57*cc7ec8feSIgor Ostapenko# fwd - forwarded 58*cc7ec8feSIgor Ostapenko# 59*cc7ec8feSIgor Ostapenko 60*cc7ec8feSIgor Ostapenko. $(atf_get_srcdir)/../common/utils.subr 61*cc7ec8feSIgor Ostapenko 62*cc7ec8feSIgor Ostapenkodivert_init() 63*cc7ec8feSIgor Ostapenko{ 64*cc7ec8feSIgor Ostapenko if ! kldstat -q -m ipdivert; then 65*cc7ec8feSIgor Ostapenko atf_skip "This test requires ipdivert" 66*cc7ec8feSIgor Ostapenko fi 67*cc7ec8feSIgor Ostapenko} 68*cc7ec8feSIgor Ostapenko 69*cc7ec8feSIgor Ostapenkoatf_test_case "in_div" "cleanup" 70*cc7ec8feSIgor Ostapenkoin_div_head() 71*cc7ec8feSIgor Ostapenko{ 72*cc7ec8feSIgor Ostapenko atf_set descr 'Test inbound > diverted | divapp terminated' 73*cc7ec8feSIgor Ostapenko atf_set require.user root 74*cc7ec8feSIgor Ostapenko} 75*cc7ec8feSIgor Ostapenkoin_div_body() 76*cc7ec8feSIgor Ostapenko{ 77*cc7ec8feSIgor Ostapenko firewall_init "ipfw" 78*cc7ec8feSIgor Ostapenko divert_init 79*cc7ec8feSIgor Ostapenko 80*cc7ec8feSIgor Ostapenko epair=$(vnet_mkepair) 81*cc7ec8feSIgor Ostapenko vnet_mkjail div ${epair}b 82*cc7ec8feSIgor Ostapenko ifconfig ${epair}a 192.0.2.1/24 up 83*cc7ec8feSIgor Ostapenko jexec div ifconfig ${epair}b 192.0.2.2/24 up 84*cc7ec8feSIgor Ostapenko jexec div ipfw add 65534 allow all from any to any 85*cc7ec8feSIgor Ostapenko 86*cc7ec8feSIgor Ostapenko # Sanity check 87*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c3 192.0.2.2 88*cc7ec8feSIgor Ostapenko 89*cc7ec8feSIgor Ostapenko jexec div ipfw add 100 divert 2000 icmp from any to any in icmptypes 8 90*cc7ec8feSIgor Ostapenko 91*cc7ec8feSIgor Ostapenko jexec div $(atf_get_srcdir)/../common/divapp 2000 & 92*cc7ec8feSIgor Ostapenko divapp_pid=$! 93*cc7ec8feSIgor Ostapenko # Wait for the divapp to be ready 94*cc7ec8feSIgor Ostapenko sleep 1 95*cc7ec8feSIgor Ostapenko 96*cc7ec8feSIgor Ostapenko # divapp is expected to "eat" the packet 97*cc7ec8feSIgor Ostapenko atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2 98*cc7ec8feSIgor Ostapenko 99*cc7ec8feSIgor Ostapenko wait $divapp_pid 100*cc7ec8feSIgor Ostapenko} 101*cc7ec8feSIgor Ostapenkoin_div_cleanup() 102*cc7ec8feSIgor Ostapenko{ 103*cc7ec8feSIgor Ostapenko firewall_cleanup "ipfw" 104*cc7ec8feSIgor Ostapenko} 105*cc7ec8feSIgor Ostapenko 106*cc7ec8feSIgor Ostapenkoatf_test_case "in_div_in" "cleanup" 107*cc7ec8feSIgor Ostapenkoin_div_in_head() 108*cc7ec8feSIgor Ostapenko{ 109*cc7ec8feSIgor Ostapenko atf_set descr 'Test inbound > diverted > inbound | host terminated' 110*cc7ec8feSIgor Ostapenko atf_set require.user root 111*cc7ec8feSIgor Ostapenko} 112*cc7ec8feSIgor Ostapenkoin_div_in_body() 113*cc7ec8feSIgor Ostapenko{ 114*cc7ec8feSIgor Ostapenko firewall_init "ipfw" 115*cc7ec8feSIgor Ostapenko divert_init 116*cc7ec8feSIgor Ostapenko 117*cc7ec8feSIgor Ostapenko epair=$(vnet_mkepair) 118*cc7ec8feSIgor Ostapenko vnet_mkjail div ${epair}b 119*cc7ec8feSIgor Ostapenko ifconfig ${epair}a 192.0.2.1/24 up 120*cc7ec8feSIgor Ostapenko jexec div ifconfig ${epair}b 192.0.2.2/24 up 121*cc7ec8feSIgor Ostapenko jexec div ipfw add 65534 allow all from any to any 122*cc7ec8feSIgor Ostapenko 123*cc7ec8feSIgor Ostapenko # Sanity check 124*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c3 192.0.2.2 125*cc7ec8feSIgor Ostapenko 126*cc7ec8feSIgor Ostapenko jexec div ipfw add 100 divert 2000 icmp from any to any in icmptypes 8 127*cc7ec8feSIgor Ostapenko 128*cc7ec8feSIgor Ostapenko jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back & 129*cc7ec8feSIgor Ostapenko divapp_pid=$! 130*cc7ec8feSIgor Ostapenko # Wait for the divapp to be ready 131*cc7ec8feSIgor Ostapenko sleep 1 132*cc7ec8feSIgor Ostapenko 133*cc7ec8feSIgor Ostapenko # divapp is NOT expected to "eat" the packet 134*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c1 192.0.2.2 135*cc7ec8feSIgor Ostapenko 136*cc7ec8feSIgor Ostapenko wait $divapp_pid 137*cc7ec8feSIgor Ostapenko} 138*cc7ec8feSIgor Ostapenkoin_div_in_cleanup() 139*cc7ec8feSIgor Ostapenko{ 140*cc7ec8feSIgor Ostapenko firewall_cleanup "ipfw" 141*cc7ec8feSIgor Ostapenko} 142*cc7ec8feSIgor Ostapenko 143*cc7ec8feSIgor Ostapenkoatf_test_case "out_div" "cleanup" 144*cc7ec8feSIgor Ostapenkoout_div_head() 145*cc7ec8feSIgor Ostapenko{ 146*cc7ec8feSIgor Ostapenko atf_set descr 'Test outbound > diverted | divapp terminated' 147*cc7ec8feSIgor Ostapenko atf_set require.user root 148*cc7ec8feSIgor Ostapenko} 149*cc7ec8feSIgor Ostapenkoout_div_body() 150*cc7ec8feSIgor Ostapenko{ 151*cc7ec8feSIgor Ostapenko firewall_init "ipfw" 152*cc7ec8feSIgor Ostapenko divert_init 153*cc7ec8feSIgor Ostapenko 154*cc7ec8feSIgor Ostapenko epair=$(vnet_mkepair) 155*cc7ec8feSIgor Ostapenko vnet_mkjail div ${epair}b 156*cc7ec8feSIgor Ostapenko ifconfig ${epair}a 192.0.2.1/24 up 157*cc7ec8feSIgor Ostapenko jexec div ifconfig ${epair}b 192.0.2.2/24 up 158*cc7ec8feSIgor Ostapenko jexec div ipfw add 65534 allow all from any to any 159*cc7ec8feSIgor Ostapenko 160*cc7ec8feSIgor Ostapenko # Sanity check 161*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c3 192.0.2.2 162*cc7ec8feSIgor Ostapenko 163*cc7ec8feSIgor Ostapenko jexec div ipfw add 100 divert 2000 icmp from any to any out icmptypes 0 164*cc7ec8feSIgor Ostapenko 165*cc7ec8feSIgor Ostapenko jexec div $(atf_get_srcdir)/../common/divapp 2000 & 166*cc7ec8feSIgor Ostapenko divapp_pid=$! 167*cc7ec8feSIgor Ostapenko # Wait for the divapp to be ready 168*cc7ec8feSIgor Ostapenko sleep 1 169*cc7ec8feSIgor Ostapenko 170*cc7ec8feSIgor Ostapenko # divapp is expected to "eat" the packet 171*cc7ec8feSIgor Ostapenko atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2 172*cc7ec8feSIgor Ostapenko 173*cc7ec8feSIgor Ostapenko wait $divapp_pid 174*cc7ec8feSIgor Ostapenko} 175*cc7ec8feSIgor Ostapenkoout_div_cleanup() 176*cc7ec8feSIgor Ostapenko{ 177*cc7ec8feSIgor Ostapenko firewall_cleanup "ipfw" 178*cc7ec8feSIgor Ostapenko} 179*cc7ec8feSIgor Ostapenko 180*cc7ec8feSIgor Ostapenkoatf_test_case "out_div_out" "cleanup" 181*cc7ec8feSIgor Ostapenkoout_div_out_head() 182*cc7ec8feSIgor Ostapenko{ 183*cc7ec8feSIgor Ostapenko atf_set descr 'Test outbound > diverted > outbound | network terminated' 184*cc7ec8feSIgor Ostapenko atf_set require.user root 185*cc7ec8feSIgor Ostapenko} 186*cc7ec8feSIgor Ostapenkoout_div_out_body() 187*cc7ec8feSIgor Ostapenko{ 188*cc7ec8feSIgor Ostapenko firewall_init "ipfw" 189*cc7ec8feSIgor Ostapenko divert_init 190*cc7ec8feSIgor Ostapenko 191*cc7ec8feSIgor Ostapenko epair=$(vnet_mkepair) 192*cc7ec8feSIgor Ostapenko vnet_mkjail div ${epair}b 193*cc7ec8feSIgor Ostapenko ifconfig ${epair}a 192.0.2.1/24 up 194*cc7ec8feSIgor Ostapenko jexec div ifconfig ${epair}b 192.0.2.2/24 up 195*cc7ec8feSIgor Ostapenko jexec div ipfw add 65534 allow all from any to any 196*cc7ec8feSIgor Ostapenko 197*cc7ec8feSIgor Ostapenko # Sanity check 198*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c3 192.0.2.2 199*cc7ec8feSIgor Ostapenko 200*cc7ec8feSIgor Ostapenko jexec div ipfw add 100 divert 2000 icmp from any to any out icmptypes 0 201*cc7ec8feSIgor Ostapenko 202*cc7ec8feSIgor Ostapenko jexec div $(atf_get_srcdir)/../common/divapp 2000 divert-back & 203*cc7ec8feSIgor Ostapenko divapp_pid=$! 204*cc7ec8feSIgor Ostapenko # Wait for the divapp to be ready 205*cc7ec8feSIgor Ostapenko sleep 1 206*cc7ec8feSIgor Ostapenko 207*cc7ec8feSIgor Ostapenko # divapp is NOT expected to "eat" the packet 208*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c1 192.0.2.2 209*cc7ec8feSIgor Ostapenko 210*cc7ec8feSIgor Ostapenko wait $divapp_pid 211*cc7ec8feSIgor Ostapenko} 212*cc7ec8feSIgor Ostapenkoout_div_out_cleanup() 213*cc7ec8feSIgor Ostapenko{ 214*cc7ec8feSIgor Ostapenko firewall_cleanup "ipfw" 215*cc7ec8feSIgor Ostapenko} 216*cc7ec8feSIgor Ostapenko 217*cc7ec8feSIgor Ostapenkoatf_test_case "in_div_in_fwd_out_div_out" "cleanup" 218*cc7ec8feSIgor Ostapenkoin_div_in_fwd_out_div_out_head() 219*cc7ec8feSIgor Ostapenko{ 220*cc7ec8feSIgor Ostapenko atf_set descr 'Test inbound > diverted > inbound > forwarded > outbound > diverted > outbound | network terminated' 221*cc7ec8feSIgor Ostapenko atf_set require.user root 222*cc7ec8feSIgor Ostapenko} 223*cc7ec8feSIgor Ostapenkoin_div_in_fwd_out_div_out_body() 224*cc7ec8feSIgor Ostapenko{ 225*cc7ec8feSIgor Ostapenko firewall_init "ipfw" 226*cc7ec8feSIgor Ostapenko divert_init 227*cc7ec8feSIgor Ostapenko 228*cc7ec8feSIgor Ostapenko # host <a--epair0--b> router <a--epair1--b> site 229*cc7ec8feSIgor Ostapenko epair0=$(vnet_mkepair) 230*cc7ec8feSIgor Ostapenko epair1=$(vnet_mkepair) 231*cc7ec8feSIgor Ostapenko 232*cc7ec8feSIgor Ostapenko vnet_mkjail router ${epair0}b ${epair1}a 233*cc7ec8feSIgor Ostapenko ifconfig ${epair0}a 192.0.2.1/24 up 234*cc7ec8feSIgor Ostapenko jexec router sysctl net.inet.ip.forwarding=1 235*cc7ec8feSIgor Ostapenko jexec router ifconfig ${epair0}b 192.0.2.2/24 up 236*cc7ec8feSIgor Ostapenko jexec router ifconfig ${epair1}a 198.51.100.1/24 up 237*cc7ec8feSIgor Ostapenko jexec router ipfw add 65534 allow all from any to any 238*cc7ec8feSIgor Ostapenko 239*cc7ec8feSIgor Ostapenko vnet_mkjail site ${epair1}b 240*cc7ec8feSIgor Ostapenko jexec site ifconfig ${epair1}b 198.51.100.2/24 up 241*cc7ec8feSIgor Ostapenko jexec site ipfw add 65534 allow all from any to any 242*cc7ec8feSIgor Ostapenko jexec site route add default 198.51.100.1 243*cc7ec8feSIgor Ostapenko 244*cc7ec8feSIgor Ostapenko route add -net 198.51.100.0/24 192.0.2.2 245*cc7ec8feSIgor Ostapenko 246*cc7ec8feSIgor Ostapenko # Sanity check 247*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c3 192.0.2.2 248*cc7ec8feSIgor Ostapenko 249*cc7ec8feSIgor Ostapenko # Should be routed without diversion 250*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c3 198.51.100.2 251*cc7ec8feSIgor Ostapenko 252*cc7ec8feSIgor Ostapenko jexec router ipfw add 100 divert 2001 icmp from any to any in icmptypes 8 253*cc7ec8feSIgor Ostapenko jexec router ipfw add 200 divert 2002 icmp from any to any out icmptypes 8 254*cc7ec8feSIgor Ostapenko 255*cc7ec8feSIgor Ostapenko jexec router $(atf_get_srcdir)/../common/divapp 2001 divert-back & 256*cc7ec8feSIgor Ostapenko indivapp_pid=$! 257*cc7ec8feSIgor Ostapenko jexec router $(atf_get_srcdir)/../common/divapp 2002 divert-back & 258*cc7ec8feSIgor Ostapenko outdivapp_pid=$! 259*cc7ec8feSIgor Ostapenko # Wait for the divappS to be ready 260*cc7ec8feSIgor Ostapenko sleep 1 261*cc7ec8feSIgor Ostapenko 262*cc7ec8feSIgor Ostapenko # Both divappS are NOT expected to "eat" the packet 263*cc7ec8feSIgor Ostapenko atf_check -s exit:0 -o ignore ping -c1 198.51.100.2 264*cc7ec8feSIgor Ostapenko 265*cc7ec8feSIgor Ostapenko wait $indivapp_pid && wait $outdivapp_pid 266*cc7ec8feSIgor Ostapenko} 267*cc7ec8feSIgor Ostapenkoin_div_in_fwd_out_div_out_cleanup() 268*cc7ec8feSIgor Ostapenko{ 269*cc7ec8feSIgor Ostapenko firewall_cleanup "ipfw" 270*cc7ec8feSIgor Ostapenko} 271*cc7ec8feSIgor Ostapenko 272*cc7ec8feSIgor Ostapenkoatf_init_test_cases() 273*cc7ec8feSIgor Ostapenko{ 274*cc7ec8feSIgor Ostapenko atf_add_test_case "in_div" 275*cc7ec8feSIgor Ostapenko atf_add_test_case "in_div_in" 276*cc7ec8feSIgor Ostapenko 277*cc7ec8feSIgor Ostapenko atf_add_test_case "out_div" 278*cc7ec8feSIgor Ostapenko atf_add_test_case "out_div_out" 279*cc7ec8feSIgor Ostapenko 280*cc7ec8feSIgor Ostapenko atf_add_test_case "in_div_in_fwd_out_div_out" 281*cc7ec8feSIgor Ostapenko} 282