1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2018 Kristof Provost <kp@FreeBSD.org> 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 29common_dir=$(atf_get_srcdir)/../common 30 31# We need to somehow test if the random algorithm of pf_map_addr() is working. 32# The table or prefix contains multiple IP next-hop addresses, for each one try 33# to establish up to 10 connections. Fail the test if with this many attempts 34# the "good" target has not been chosen. However this choice is random, 35# the check might still ocasionally fail. 36check_random() { 37 if [ "$1" = "IPv4" ]; then 38 ping_from="${net_clients_4}.1" 39 ping_to="${host_server_4}" 40 else 41 ping_from="${net_clients_6}::1" 42 ping_to="${host_server_6}" 43 fi 44 good_targets="$2" 45 bad_targets="$3" 46 47 port=42000 48 states=$(mktemp) || exit 1 49 for good_target in $good_targets; do 50 found="no" 51 for attempt in $(seq 1 10); do 52 port=$(( port + 1 )) 53 jexec router pfctl -Fs 54 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 55 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 56 --fromaddr ${ping_from} --to ${ping_to} \ 57 --ping-type=tcp3way --send-sport=${port} 58 jexec router pfctl -qvvss | normalize_pfctl_s > $states 59 cat $states 60 if [ -n "${bad_targets}" ]; then 61 for bad_target in $bad_targets; do 62 if grep -qE "route-to: ${bad_target}@" $states; then 63 atf_fail "Bad target ${bad_target} selected!" 64 fi 65 done 66 fi; 67 if grep -qE "route-to: ${good_target}@" $states; then 68 found=yes 69 break 70 fi 71 done 72 if [ "${found}" = "no" ]; then 73 atf_fail "Target ${good_target} not selected after ${attempt} attempts!" 74 fi 75 done 76} 77 78pf_map_addr_common() 79{ 80 setup_router_server_nat64 81 82 # Clients will connect from another network behind the router. 83 # This allows for using multiple source addresses. 84 jexec router route add -6 ${net_clients_6}::/${net_clients_6_mask} ${net_tester_6_host_tester} 85 jexec router route add ${net_clients_4}.0/${net_clients_4_mask} ${net_tester_4_host_tester} 86 87 # The servers are reachable over additional IP addresses for 88 # testing of tables and subnets. The addresses are noncontinougnus 89 # for pf_map_addr() counter tests. 90 for i in 0 1 4 5; do 91 a1=$((24 + i)) 92 jexec server1 ifconfig ${epair_server1}b inet ${net_server1_4}.${a1}/32 alias 93 jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6}::42:${i}/128 alias 94 a2=$((40 + i)) 95 jexec server2 ifconfig ${epair_server2}b inet ${net_server2_4}.${a2}/32 alias 96 jexec server2 ifconfig ${epair_server2}b inet6 ${net_server2_6}::42:${i}/128 alias 97 done 98} 99 100atf_test_case "v4" "cleanup" 101v4_head() 102{ 103 atf_set descr 'Basic route-to test' 104 atf_set require.user root 105} 106 107v4_body() 108{ 109 pft_init 110 111 epair_send=$(vnet_mkepair) 112 ifconfig ${epair_send}a 192.0.2.1/24 up 113 epair_route=$(vnet_mkepair) 114 ifconfig ${epair_route}a 203.0.113.1/24 up 115 116 vnet_mkjail alcatraz ${epair_send}b ${epair_route}b 117 jexec alcatraz ifconfig ${epair_send}b 192.0.2.2/24 up 118 jexec alcatraz ifconfig ${epair_route}b 203.0.113.2/24 up 119 jexec alcatraz route add -net 198.51.100.0/24 192.0.2.1 120 jexec alcatraz pfctl -e 121 122 # Attempt to provoke PR 228782 123 pft_set_rules alcatraz "block all" "pass user 2" \ 124 "pass out route-to (${epair_route}b 203.0.113.1) from 192.0.2.2 to 198.51.100.1 no state" 125 jexec alcatraz nc -w 3 -s 192.0.2.2 198.51.100.1 22 126 127 # atf wants us to not return an error, but our netcat will fail 128 true 129} 130 131v4_cleanup() 132{ 133 pft_cleanup 134} 135 136atf_test_case "v6" "cleanup" 137v6_head() 138{ 139 atf_set descr 'Basic route-to test (IPv6)' 140 atf_set require.user root 141} 142 143v6_body() 144{ 145 pft_init 146 147 epair_send=$(vnet_mkepair) 148 ifconfig ${epair_send}a inet6 2001:db8:42::1/64 up no_dad -ifdisabled 149 epair_route=$(vnet_mkepair) 150 ifconfig ${epair_route}a inet6 2001:db8:43::1/64 up no_dad -ifdisabled 151 152 vnet_mkjail alcatraz ${epair_send}b ${epair_route}b 153 jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 up no_dad 154 jexec alcatraz ifconfig ${epair_route}b inet6 2001:db8:43::2/64 up no_dad 155 jexec alcatraz route add -6 2001:db8:666::/64 2001:db8:42::2 156 jexec alcatraz pfctl -e 157 158 # Attempt to provoke PR 228782 159 pft_set_rules alcatraz "block all" "pass user 2" \ 160 "pass out route-to (${epair_route}b 2001:db8:43::1) from 2001:db8:42::2 to 2001:db8:666::1 no state" 161 jexec alcatraz nc -6 -w 3 -s 2001:db8:42::2 2001:db8:666::1 22 162 163 # atf wants us to not return an error, but our netcat will fail 164 true 165} 166 167v6_cleanup() 168{ 169 pft_cleanup 170} 171 172atf_test_case "multiwan" "cleanup" 173multiwan_head() 174{ 175 atf_set descr 'Multi-WAN redirection / reply-to test' 176 atf_set require.user root 177} 178 179multiwan_body() 180{ 181 pft_init 182 183 epair_one=$(vnet_mkepair) 184 epair_two=$(vnet_mkepair) 185 epair_cl_one=$(vnet_mkepair) 186 epair_cl_two=$(vnet_mkepair) 187 188 vnet_mkjail srv ${epair_one}b ${epair_two}b 189 vnet_mkjail wan_one ${epair_one}a ${epair_cl_one}b 190 vnet_mkjail wan_two ${epair_two}a ${epair_cl_two}b 191 vnet_mkjail client ${epair_cl_one}a ${epair_cl_two}a 192 193 jexec client ifconfig ${epair_cl_one}a 203.0.113.1/25 194 jexec wan_one ifconfig ${epair_cl_one}b 203.0.113.2/25 195 jexec wan_one ifconfig ${epair_one}a 192.0.2.1/24 up 196 jexec wan_one sysctl net.inet.ip.forwarding=1 197 jexec srv ifconfig ${epair_one}b 192.0.2.2/24 up 198 jexec client route add 192.0.2.0/24 203.0.113.2 199 200 jexec client ifconfig ${epair_cl_two}a 203.0.113.128/25 201 jexec wan_two ifconfig ${epair_cl_two}b 203.0.113.129/25 202 jexec wan_two ifconfig ${epair_two}a 198.51.100.1/24 up 203 jexec wan_two sysctl net.inet.ip.forwarding=1 204 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 205 jexec client route add 198.51.100.0/24 203.0.113.129 206 207 jexec srv ifconfig lo0 127.0.0.1/8 up 208 jexec srv route add default 192.0.2.1 209 jexec srv sysctl net.inet.ip.forwarding=1 210 211 # Run echo server in srv jail 212 jexec srv /usr/sbin/inetd -p ${PWD}/multiwan.pid $(atf_get_srcdir)/echo_inetd.conf 213 214 jexec srv pfctl -e 215 pft_set_rules srv \ 216 "nat on ${epair_one}b inet from 127.0.0.0/8 to any -> (${epair_one}b)" \ 217 "nat on ${epair_two}b inet from 127.0.0.0/8 to any -> (${epair_two}b)" \ 218 "rdr on ${epair_one}b inet proto tcp from any to 192.0.2.2 port 7 -> 127.0.0.1 port 7" \ 219 "rdr on ${epair_two}b inet proto tcp from any to 198.51.100.2 port 7 -> 127.0.0.1 port 7" \ 220 "block in" \ 221 "block out" \ 222 "pass in quick on ${epair_one}b reply-to (${epair_one}b 192.0.2.1) inet proto tcp from any to 127.0.0.1 port 7" \ 223 "pass in quick on ${epair_two}b reply-to (${epair_two}b 198.51.100.1) inet proto tcp from any to 127.0.0.1 port 7" 224 225 # These will always succeed, because we don't change interface to route 226 # correctly here. 227 result=$(echo "one" | jexec wan_one nc -N -w 3 192.0.2.2 7) 228 if [ "${result}" != "one" ]; then 229 atf_fail "Redirect on one failed" 230 fi 231 result=$(echo "two" | jexec wan_two nc -N -w 3 198.51.100.2 7) 232 if [ "${result}" != "two" ]; then 233 atf_fail "Redirect on two failed" 234 fi 235 236 result=$(echo "one" | jexec client nc -N -w 3 192.0.2.2 7) 237 if [ "${result}" != "one" ]; then 238 atf_fail "Redirect from client on one failed" 239 fi 240 241 # This should trigger the issue fixed in 829a69db855b48ff7e8242b95e193a0783c489d9 242 result=$(echo "two" | jexec client nc -N -w 3 198.51.100.2 7) 243 if [ "${result}" != "two" ]; then 244 atf_fail "Redirect from client on two failed" 245 fi 246} 247 248multiwan_cleanup() 249{ 250 pft_cleanup 251} 252 253atf_test_case "multiwanlocal" "cleanup" 254multiwanlocal_head() 255{ 256 atf_set descr 'Multi-WAN local origin source-based redirection / route-to test' 257 atf_set require.user root 258} 259 260multiwanlocal_body() 261{ 262 pft_init 263 264 epair_one=$(vnet_mkepair) 265 epair_two=$(vnet_mkepair) 266 epair_cl_one=$(vnet_mkepair) 267 epair_cl_two=$(vnet_mkepair) 268 269 vnet_mkjail srv1 ${epair_one}b 270 vnet_mkjail srv2 ${epair_two}b 271 vnet_mkjail wan_one ${epair_one}a ${epair_cl_one}b 272 vnet_mkjail wan_two ${epair_two}a ${epair_cl_two}b 273 vnet_mkjail client ${epair_cl_one}a ${epair_cl_two}a 274 275 jexec client ifconfig ${epair_cl_one}a 203.0.113.1/25 276 jexec wan_one ifconfig ${epair_cl_one}b 203.0.113.2/25 277 jexec wan_one ifconfig ${epair_one}a 192.0.2.1/24 up 278 jexec wan_one sysctl net.inet.ip.forwarding=1 279 jexec srv1 ifconfig ${epair_one}b 192.0.2.2/24 up 280 281 jexec client ifconfig ${epair_cl_two}a 203.0.113.128/25 282 jexec wan_two ifconfig ${epair_cl_two}b 203.0.113.129/25 283 jexec wan_two ifconfig ${epair_two}a 198.51.100.1/24 up 284 jexec wan_two sysctl net.inet.ip.forwarding=1 285 jexec srv2 ifconfig ${epair_two}b 198.51.100.2/24 up 286 287 jexec client route add default 203.0.113.2 288 jexec srv1 route add default 192.0.2.1 289 jexec srv2 route add default 198.51.100.1 290 291 # Run data source in srv1 and srv2 292 jexec srv1 sh -c 'dd if=/dev/zero bs=1024 count=100 | nc -l 7 -w 2 -N &' 293 jexec srv2 sh -c 'dd if=/dev/zero bs=1024 count=100 | nc -l 7 -w 2 -N &' 294 295 jexec client pfctl -e 296 pft_set_rules client \ 297 "block in" \ 298 "block out" \ 299 "pass out quick route-to (${epair_cl_two}a 203.0.113.129) inet proto tcp from 203.0.113.128 to any port 7" \ 300 "pass out on ${epair_cl_one}a inet proto tcp from any to any port 7" \ 301 "set skip on lo" 302 303 # This should work 304 result=$(jexec client nc -N -w 1 192.0.2.2 7 | wc -c) 305 if [ ${result} -ne 102400 ]; then 306 jexec client pfctl -ss 307 atf_fail "Redirect from client on one failed: ${result}" 308 fi 309 310 # This should trigger the issue 311 result=$(jexec client nc -N -w 1 -s 203.0.113.128 198.51.100.2 7 | wc -c) 312 jexec client pfctl -ss 313 if [ ${result} -ne 102400 ]; then 314 atf_fail "Redirect from client on two failed: ${result}" 315 fi 316} 317 318multiwanlocal_cleanup() 319{ 320 pft_cleanup 321} 322 323atf_test_case "icmp_nat" "cleanup" 324icmp_nat_head() 325{ 326 atf_set descr 'Test that ICMP packets are correct for route-to + NAT' 327 atf_set require.user root 328 atf_set require.progs python3 scapy 329} 330 331icmp_nat_body() 332{ 333 pft_init 334 335 epair_one=$(vnet_mkepair) 336 epair_two=$(vnet_mkepair) 337 epair_three=$(vnet_mkepair) 338 339 vnet_mkjail gw ${epair_one}b ${epair_two}a ${epair_three}a 340 vnet_mkjail srv ${epair_two}b 341 vnet_mkjail srv2 ${epair_three}b 342 343 ifconfig ${epair_one}a 192.0.2.2/24 up 344 route add -net 198.51.100.0/24 192.0.2.1 345 jexec gw sysctl net.inet.ip.forwarding=1 346 jexec gw ifconfig ${epair_one}b 192.0.2.1/24 up 347 jexec gw ifconfig ${epair_two}a 198.51.100.1/24 up 348 jexec gw ifconfig ${epair_three}a 203.0.113.1/24 up mtu 500 349 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 350 jexec srv route add default 198.51.100.1 351 jexec srv2 ifconfig ${epair_three}b 203.0.113.2/24 up mtu 500 352 jexec srv2 route add default 203.0.113.1 353 354 # Sanity check 355 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 356 357 jexec gw pfctl -e 358 pft_set_rules gw \ 359 "nat on ${epair_two}a inet from 192.0.2.0/24 to any -> (${epair_two}a)" \ 360 "nat on ${epair_three}a inet from 192.0.2.0/24 to any -> (${epair_three}a)" \ 361 "pass out route-to (${epair_three}a 203.0.113.2) proto icmp icmp-type echoreq" 362 363 # Now ensure that we get an ICMP error with the correct IP addresses in it. 364 atf_check -s exit:0 ${common_dir}/pft_icmp_check.py \ 365 --to 198.51.100.2 \ 366 --fromaddr 192.0.2.2 \ 367 --recvif ${epair_one}a \ 368 --sendif ${epair_one}a 369 370 # ping reports the ICMP error, so check of that too. 371 atf_check -s exit:2 -o match:'frag needed and DF set' \ 372 ping -D -c 1 -s 1000 198.51.100.2 373} 374 375icmp_nat_cleanup() 376{ 377 pft_cleanup 378} 379 380atf_test_case "dummynet" "cleanup" 381dummynet_head() 382{ 383 atf_set descr 'Test that dummynet applies to route-to packets' 384 atf_set require.user root 385} 386 387dummynet_body() 388{ 389 dummynet_init 390 391 epair_srv=$(vnet_mkepair) 392 epair_gw=$(vnet_mkepair) 393 394 vnet_mkjail srv ${epair_srv}a 395 jexec srv ifconfig ${epair_srv}a 192.0.2.1/24 up 396 jexec srv route add default 192.0.2.2 397 398 vnet_mkjail gw ${epair_srv}b ${epair_gw}a 399 jexec gw ifconfig ${epair_srv}b 192.0.2.2/24 up 400 jexec gw ifconfig ${epair_gw}a 198.51.100.1/24 up 401 jexec gw sysctl net.inet.ip.forwarding=1 402 403 ifconfig ${epair_gw}b 198.51.100.2/24 up 404 route add -net 192.0.2.0/24 198.51.100.1 405 406 # Sanity check 407 atf_check -s exit:0 -o ignore ping -c 1 -t 1 192.0.2.1 408 409 jexec gw dnctl pipe 1 config delay 1200 410 pft_set_rules gw \ 411 "pass out route-to (${epair_srv}b 192.0.2.1) to 192.0.2.1 dnpipe 1" 412 jexec gw pfctl -e 413 414 # The ping request will pass, but take 1.2 seconds 415 # So this works: 416 atf_check -s exit:0 -o ignore ping -c 1 -t 2 192.0.2.1 417 # But this times out: 418 atf_check -s exit:2 -o ignore ping -c 1 -t 1 192.0.2.1 419 420 # return path dummynet 421 pft_set_rules gw \ 422 "pass out route-to (${epair_srv}b 192.0.2.1) to 192.0.2.1 dnpipe (0, 1)" 423 424 # The ping request will pass, but take 1.2 seconds 425 # So this works: 426 atf_check -s exit:0 -o ignore ping -c 1 -t 2 192.0.2.1 427 # But this times out: 428 atf_check -s exit:2 -o ignore ping -c 1 -t 1 192.0.2.1 429} 430 431dummynet_cleanup() 432{ 433 pft_cleanup 434} 435 436atf_test_case "dummynet_in" "cleanup" 437dummynet_in_head() 438{ 439 atf_set descr 'Thest that dummynet works as expected on pass in route-to packets' 440 atf_set require.user root 441} 442 443dummynet_in_body() 444{ 445 dummynet_init 446 447 epair_srv=$(vnet_mkepair) 448 epair_gw=$(vnet_mkepair) 449 450 vnet_mkjail srv ${epair_srv}a 451 jexec srv ifconfig ${epair_srv}a 192.0.2.1/24 up 452 jexec srv route add default 192.0.2.2 453 454 vnet_mkjail gw ${epair_srv}b ${epair_gw}a 455 jexec gw ifconfig ${epair_srv}b 192.0.2.2/24 up 456 jexec gw ifconfig ${epair_gw}a 198.51.100.1/24 up 457 jexec gw sysctl net.inet.ip.forwarding=1 458 459 ifconfig ${epair_gw}b 198.51.100.2/24 up 460 route add -net 192.0.2.0/24 198.51.100.1 461 462 # Sanity check 463 atf_check -s exit:0 -o ignore ping -c 1 -t 1 192.0.2.1 464 465 jexec gw dnctl pipe 1 config delay 1200 466 pft_set_rules gw \ 467 "pass in route-to (${epair_srv}b 192.0.2.1) to 192.0.2.1 dnpipe 1" 468 jexec gw pfctl -e 469 470 # The ping request will pass, but take 1.2 seconds 471 # So this works: 472 echo "Expect 1.2 s" 473 ping -c 1 192.0.2.1 474 atf_check -s exit:0 -o ignore ping -c 1 -t 2 192.0.2.1 475 # But this times out: 476 atf_check -s exit:2 -o ignore ping -c 1 -t 1 192.0.2.1 477 478 # return path dummynet 479 pft_set_rules gw \ 480 "pass in route-to (${epair_srv}b 192.0.2.1) to 192.0.2.1 dnpipe (0, 1)" 481 482 # The ping request will pass, but take 1.2 seconds 483 # So this works: 484 echo "Expect 1.2 s" 485 ping -c 1 192.0.2.1 486 atf_check -s exit:0 -o ignore ping -c 1 -t 2 192.0.2.1 487 # But this times out: 488 atf_check -s exit:2 -o ignore ping -c 1 -t 1 192.0.2.1 489} 490 491dummynet_in_cleanup() 492{ 493 pft_cleanup 494} 495 496atf_test_case "ifbound" "cleanup" 497ifbound_head() 498{ 499 atf_set descr 'Test that route-to states bind the expected interface' 500 atf_set require.user root 501} 502 503ifbound_body() 504{ 505 pft_init 506 507 j="route_to:ifbound" 508 509 epair_one=$(vnet_mkepair) 510 epair_two=$(vnet_mkepair) 511 ifconfig ${epair_one}b up 512 513 vnet_mkjail ${j}2 ${epair_two}b 514 jexec ${j}2 ifconfig ${epair_two}b inet 198.51.100.2/24 up 515 jexec ${j}2 ifconfig ${epair_two}b inet alias 203.0.113.1/24 516 jexec ${j}2 route add default 198.51.100.1 517 518 vnet_mkjail $j ${epair_one}a ${epair_two}a 519 jexec $j ifconfig ${epair_one}a 192.0.2.1/24 up 520 jexec $j ifconfig ${epair_two}a 198.51.100.1/24 up 521 jexec $j route add default 192.0.2.2 522 523 jexec $j pfctl -e 524 pft_set_rules $j \ 525 "set state-policy if-bound" \ 526 "block" \ 527 "pass out route-to (${epair_two}a 198.51.100.2)" 528 529 atf_check -s exit:0 -o ignore \ 530 jexec $j ping -c 3 203.0.113.1 531} 532 533ifbound_cleanup() 534{ 535 pft_cleanup 536} 537 538atf_test_case "ifbound_v6" "cleanup" 539ifbound_v6_head() 540{ 541 atf_set descr 'Test that route-to states for IPv6 bind the expected interface' 542 atf_set require.user root 543} 544 545ifbound_v6_body() 546{ 547 pft_init 548 549 j="route_to:ifbound_v6" 550 551 epair_one=$(vnet_mkepair) 552 epair_two=$(vnet_mkepair) 553 ifconfig ${epair_one}b up 554 555 vnet_mkjail ${j}2 ${epair_two}b 556 jexec ${j}2 ifconfig ${epair_two}b inet6 2001:db8:1::2/64 up no_dad 557 jexec ${j}2 ifconfig ${epair_two}b inet6 alias 2001:db8:2::1/64 no_dad 558 jexec ${j}2 route -6 add default 2001:db8:1::1 559 560 vnet_mkjail $j ${epair_one}a ${epair_two}a 561 jexec $j ifconfig ${epair_one}a inet6 2001:db8::1/64 up no_dad 562 jexec $j ifconfig ${epair_two}a inet6 2001:db8:1::1/64 up no_dad 563 jexec $j route -6 add default 2001:db8::2 564 565 jexec $j ping6 -c 3 2001:db8:1::2 566 567 jexec $j pfctl -e 568 pft_set_rules $j \ 569 "set state-policy if-bound" \ 570 "block" \ 571 "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 572 "pass out route-to (${epair_two}a 2001:db8:1::2)" 573 574 atf_check -s exit:0 -o ignore \ 575 jexec $j ping6 -c 3 2001:db8:2::1 576} 577 578ifbound_v6_cleanup() 579{ 580 pft_cleanup 581} 582 583atf_test_case "ifbound_reply_to" "cleanup" 584ifbound_reply_to_head() 585{ 586 atf_set descr 'Test that reply-to states bind to the expected interface' 587 atf_set require.user root 588 atf_set require.progs python3 scapy 589} 590 591ifbound_reply_to_body() 592{ 593 pft_init 594 595 j="route_to:ifbound_reply_to" 596 597 epair_one=$(vnet_mkepair) 598 epair_two=$(vnet_mkepair) 599 ifconfig ${epair_one}b inet 192.0.2.2/24 up 600 ifconfig ${epair_two}b up 601 602 vnet_mkjail $j ${epair_one}a ${epair_two}a 603 jexec $j ifconfig ${epair_one}a 192.0.2.1/24 up 604 jexec $j ifconfig ${epair_two}a 198.51.100.1/24 up 605 jexec $j route add default 198.51.100.254 606 607 jexec $j pfctl -e 608 pft_set_rules $j \ 609 "set state-policy if-bound" \ 610 "block" \ 611 "pass in on ${epair_one}a reply-to (${epair_one}a 192.0.2.2) inet from any to 192.0.2.0/24 keep state" 612 613 atf_check -s exit:0 -o ignore \ 614 ping -c 3 192.0.2.1 615 616 atf_check -s exit:0 \ 617 ${common_dir}/pft_ping.py \ 618 --to 192.0.2.1 \ 619 --from 203.0.113.2 \ 620 --sendif ${epair_one}b \ 621 --replyif ${epair_one}b 622 623 # pft_ping uses the same ID every time, so this will look like more traffic in the same state 624 atf_check -s exit:0 \ 625 ${common_dir}/pft_ping.py \ 626 --to 192.0.2.1 \ 627 --from 203.0.113.2 \ 628 --sendif ${epair_one}b \ 629 --replyif ${epair_one}b 630 631 jexec $j pfctl -ss -vv 632} 633 634ifbound_reply_to_cleanup() 635{ 636 pft_cleanup 637} 638 639atf_test_case "ifbound_reply_to_v6" "cleanup" 640ifbound_reply_to_v6_head() 641{ 642 atf_set descr 'Test that reply-to states bind to the expected interface for IPv6' 643 atf_set require.user root 644 atf_set require.progs python3 scapy 645} 646 647ifbound_reply_to_v6_body() 648{ 649 pft_init 650 651 j="route_to:ifbound_reply_to_v6" 652 653 epair_one=$(vnet_mkepair) 654 epair_two=$(vnet_mkepair) 655 656 vnet_mkjail ${j}s ${epair_one}b ${epair_two}b 657 jexec ${j}s ifconfig ${epair_one}b inet6 2001:db8::2/64 up no_dad 658 jexec ${j}s ifconfig ${epair_two}b up 659 #jexec ${j}s route -6 add default 2001:db8::1 660 661 vnet_mkjail $j ${epair_one}a ${epair_two}a 662 jexec $j ifconfig ${epair_one}a inet6 2001:db8::1/64 up no_dad 663 jexec $j ifconfig ${epair_two}a inet6 2001:db8:1::1/64 up no_dad 664 jexec $j route -6 add default 2001:db8:1::254 665 666 jexec $j pfctl -e 667 pft_set_rules $j \ 668 "set state-policy if-bound" \ 669 "block" \ 670 "pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 671 "pass in on ${epair_one}a reply-to (${epair_one}a 2001:db8::2) inet6 from any to 2001:db8::/64 keep state" 672 673 atf_check -s exit:0 -o ignore \ 674 jexec ${j}s ping6 -c 3 2001:db8::1 675 676 atf_check -s exit:0 \ 677 jexec ${j}s ${common_dir}/pft_ping.py \ 678 --to 2001:db8::1 \ 679 --from 2001:db8:2::2 \ 680 --sendif ${epair_one}b \ 681 --replyif ${epair_one}b 682 683 # pft_ping uses the same ID every time, so this will look like more traffic in the same state 684 atf_check -s exit:0 \ 685 jexec ${j}s ${common_dir}/pft_ping.py \ 686 --to 2001:db8::1 \ 687 --from 2001:db8:2::2 \ 688 --sendif ${epair_one}b \ 689 --replyif ${epair_one}b 690 691 jexec $j pfctl -ss -vv 692} 693 694ifbound_reply_to_v6_cleanup() 695{ 696 pft_cleanup 697} 698 699atf_test_case "ifbound_reply_to_rdr_dummynet" "cleanup" 700ifbound_reply_to_rdr_dummynet_head() 701{ 702 atf_set descr 'Test that reply-to states bind to the expected non-default-route interface after rdr and dummynet' 703 atf_set require.user root 704 atf_set require.progs python3 scapy 705} 706 707ifbound_reply_to_rdr_dummynet_body() 708{ 709 dummynet_init 710 711 j="route_to:ifbound_reply_to_rdr_dummynet" 712 713 epair_one=$(vnet_mkepair) 714 epair_two=$(vnet_mkepair) 715 ifconfig ${epair_one}b inet 192.0.2.2/24 up 716 ifconfig ${epair_two}b up 717 718 vnet_mkjail $j ${epair_one}a ${epair_two}a 719 jexec $j ifconfig lo0 inet 127.0.0.1/8 up 720 jexec $j ifconfig ${epair_one}a 192.0.2.1/24 up 721 jexec $j ifconfig ${epair_two}a 198.51.100.1/24 up 722 jexec $j route add default 198.51.100.254 723 724 jexec $j pfctl -e 725 jexec $j dnctl pipe 1 config delay 1 726 pft_set_rules $j \ 727 "set state-policy if-bound" \ 728 "rdr on ${epair_one}a proto icmp from any to 192.0.2.1 -> 127.0.0.1" \ 729 "rdr on ${epair_two}a proto icmp from any to 198.51.100.1 -> 127.0.0.1" \ 730 "match in on ${epair_one}a inet all dnpipe (1, 1)" \ 731 "pass in on ${epair_one}a reply-to (${epair_one}a 192.0.2.2) inet from any to 127.0.0.1 keep state" 732 733 atf_check -s exit:0 -o ignore \ 734 ping -c 3 192.0.2.1 735 736 atf_check -s exit:0 \ 737 ${common_dir}/pft_ping.py \ 738 --to 192.0.2.1 \ 739 --from 203.0.113.2 \ 740 --sendif ${epair_one}b \ 741 --replyif ${epair_one}b 742 743 # pft_ping uses the same ID every time, so this will look like more traffic in the same state 744 atf_check -s exit:0 \ 745 ${common_dir}/pft_ping.py \ 746 --to 192.0.2.1 \ 747 --from 203.0.113.2 \ 748 --sendif ${epair_one}b \ 749 --replyif ${epair_one}b 750 751 jexec $j pfctl -sr -vv 752 jexec $j pfctl -ss -vv 753} 754 755ifbound_reply_to_rdr_dummynet_cleanup() 756{ 757 pft_cleanup 758} 759 760atf_test_case "dummynet_frag" "cleanup" 761dummynet_frag_head() 762{ 763 atf_set descr 'Test fragmentation with route-to and dummynet' 764 atf_set require.user root 765} 766 767dummynet_frag_body() 768{ 769 pft_init 770 dummynet_init 771 772 epair_one=$(vnet_mkepair) 773 epair_two=$(vnet_mkepair) 774 775 ifconfig ${epair_one}a 192.0.2.1/24 up 776 777 vnet_mkjail alcatraz ${epair_one}b ${epair_two}a 778 jexec alcatraz ifconfig ${epair_one}b 192.0.2.2/24 up 779 jexec alcatraz ifconfig ${epair_two}a 198.51.100.1/24 up 780 jexec alcatraz sysctl net.inet.ip.forwarding=1 781 782 vnet_mkjail singsing ${epair_two}b 783 jexec singsing ifconfig ${epair_two}b 198.51.100.2/24 up 784 jexec singsing route add default 198.51.100.1 785 786 route add 198.51.100.0/24 192.0.2.2 787 788 jexec alcatraz dnctl pipe 1 config bw 1000Byte/s burst 4500 789 jexec alcatraz dnctl pipe 2 config 790 # This second pipe ensures that the pf_test(PF_OUT) call in pf_route() doesn't 791 # delay packets in dummynet (by inheriting pipe 1 from the input rule). 792 793 jexec alcatraz pfctl -e 794 pft_set_rules alcatraz \ 795 "set reassemble yes" \ 796 "pass in route-to (${epair_two}a 198.51.100.2) inet proto icmp all icmp-type echoreq dnpipe 1" \ 797 "pass out dnpipe 2" 798 799 800 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 801 atf_check -s exit:0 -o ignore ping -c 1 -s 4000 198.51.100.2 802} 803 804dummynet_frag_cleanup() 805{ 806 pft_cleanup 807} 808 809atf_test_case "dummynet_double" "cleanup" 810dummynet_double_head() 811{ 812 atf_set descr 'Ensure dummynet is not applied multiple times' 813 atf_set require.user root 814} 815 816dummynet_double_body() 817{ 818 pft_init 819 dummynet_init 820 821 epair_one=$(vnet_mkepair) 822 epair_two=$(vnet_mkepair) 823 824 ifconfig ${epair_one}a 192.0.2.1/24 up 825 826 vnet_mkjail alcatraz ${epair_one}b ${epair_two}a 827 jexec alcatraz ifconfig ${epair_one}b 192.0.2.2/24 up 828 jexec alcatraz ifconfig ${epair_two}a 198.51.100.1/24 up 829 jexec alcatraz sysctl net.inet.ip.forwarding=1 830 831 vnet_mkjail singsing ${epair_two}b 832 jexec singsing ifconfig ${epair_two}b 198.51.100.2/24 up 833 jexec singsing route add default 198.51.100.1 834 835 route add 198.51.100.0/24 192.0.2.2 836 837 jexec alcatraz dnctl pipe 1 config delay 800 838 839 jexec alcatraz pfctl -e 840 pft_set_rules alcatraz \ 841 "set reassemble yes" \ 842 "nat on ${epair_two}a from 192.0.2.0/24 -> (${epair_two}a)" \ 843 "pass in route-to (${epair_two}a 198.51.100.2) inet proto icmp all icmp-type echoreq dnpipe (1, 1)" \ 844 "pass out route-to (${epair_two}a 198.51.100.2) inet proto icmp all icmp-type echoreq" 845 846 ping -c 1 198.51.100.2 847 jexec alcatraz pfctl -sr -vv 848 jexec alcatraz pfctl -ss -vv 849 850 # We expect to be delayed 1.6 seconds, so timeout of two seconds passes, but 851 # timeout of 1 does not. 852 atf_check -s exit:0 -o ignore ping -t 2 -c 1 198.51.100.2 853 atf_check -s exit:2 -o ignore ping -t 1 -c 1 198.51.100.2 854} 855 856dummynet_double_cleanup() 857{ 858 pft_cleanup 859} 860 861atf_test_case "sticky" "cleanup" 862sticky_head() 863{ 864 atf_set descr 'Set and retrieve a rule with sticky-address' 865 atf_set require.user root 866} 867 868sticky_body() 869{ 870 pft_init 871 872 vnet_mkjail alcatraz 873 874 pft_set_rules alcatraz \ 875 "pass in quick log on n_test_h_rtr route-to (n_srv_h_rtr <change_dst>) sticky-address from any to <dst> keep state" 876 877 jexec alcatraz pfctl -qvvsr 878} 879 880sticky_cleanup() 881{ 882 pft_cleanup 883} 884 885atf_test_case "ttl" "cleanup" 886ttl_head() 887{ 888 atf_set descr 'Ensure we decrement TTL on route-to' 889 atf_set require.user root 890} 891 892ttl_body() 893{ 894 pft_init 895 896 epair_one=$(vnet_mkepair) 897 epair_two=$(vnet_mkepair) 898 ifconfig ${epair_one}b 192.0.2.2/24 up 899 route add default 192.0.2.1 900 901 vnet_mkjail alcatraz ${epair_one}a ${epair_two}a 902 jexec alcatraz ifconfig ${epair_one}a 192.0.2.1/24 up 903 jexec alcatraz ifconfig ${epair_two}a 198.51.100.1/24 up 904 jexec alcatraz sysctl net.inet.ip.forwarding=1 905 906 vnet_mkjail singsing ${epair_two}b 907 jexec singsing ifconfig ${epair_two}b 198.51.100.2/24 up 908 jexec singsing route add default 198.51.100.1 909 910 # Sanity check 911 atf_check -s exit:0 -o ignore \ 912 ping -c 3 198.51.100.2 913 914 jexec alcatraz pfctl -e 915 pft_set_rules alcatraz \ 916 "pass out" \ 917 "pass in route-to (${epair_two}a 198.51.100.2)" 918 919 atf_check -s exit:0 -o ignore \ 920 ping -c 3 198.51.100.2 921 922 atf_check -s exit:2 -o ignore \ 923 ping -m 1 -c 3 198.51.100.2 924} 925 926ttl_cleanup() 927{ 928 pft_cleanup 929} 930 931 932atf_test_case "empty_pool" "cleanup" 933empty_pool_head() 934{ 935 atf_set descr 'Route-to with empty pool' 936 atf_set require.user root 937 atf_set require.progs python3 scapy 938} 939 940empty_pool_body() 941{ 942 pft_init 943 setup_router_server_ipv6 944 945 946 pft_set_rules router \ 947 "block" \ 948 "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 949 "pass in on ${epair_tester}b route-to (${epair_server}a <nonexistent>) inet6 from any to ${net_server_host_server}" \ 950 "pass out on ${epair_server}a" 951 952 # pf_map_addr_sn() won't be able to pick a target address, because 953 # the table used in redireciton pool is empty. Packet will not be 954 # forwarded, error counter will be increased. 955 ping_server_check_reply exit:1 956 # Ignore warnings about not-loaded ALTQ 957 atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null" 958} 959 960empty_pool_cleanup() 961{ 962 pft_cleanup 963} 964 965atf_test_case "table_loop" "cleanup" 966 967table_loop_head() 968{ 969 atf_set descr 'Check that iterating over tables poperly loops' 970 atf_set require.user root 971} 972 973table_loop_body() 974{ 975 pf_map_addr_common 976 977 jexec router pfctl -e 978 pft_set_rules router \ 979 "set debug loud" \ 980 "set reassemble yes" \ 981 "set state-policy if-bound" \ 982 "table <rt_targets_1> { ${net_server1_6}::42:4/127 ${net_server1_6}::42:0/127 }" \ 983 "table <rt_targets_2> { ${net_server2_6}::42:4/127 }" \ 984 "pass in on ${epair_tester}b \ 985 route-to { \ 986 (${epair_server1}a <rt_targets_1>) \ 987 (${epair_server2}a <rt_targets_2_empty>) \ 988 (${epair_server2}a <rt_targets_2>) \ 989 } \ 990 inet6 proto tcp \ 991 keep state" 992 993 # Both hosts of the pool are tables. Each table gets iterated over once, 994 # then the pool iterates to the next host, which is also iterated, 995 # then the pool loops back to the 1st host. If an empty table is found, 996 # it is skipped. Unless that's the only table, that is tested by 997 # the "empty_pool" test. 998 for port in $(seq 1 7); do 999 port=$((4200 + port)) 1000 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1001 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1002 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1003 --ping-type=tcp3way --send-sport=${port} 1004 done 1005 1006 states=$(mktemp) || exit 1 1007 jexec router pfctl -qvvss | normalize_pfctl_s > $states 1008 cat $states 1009 1010 for state_regexp in \ 1011 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4201\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1012 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \ 1013 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4203\] .* route-to: ${net_server1_6}::42:4@${epair_server1}a" \ 1014 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4204\] .* route-to: ${net_server1_6}::42:5@${epair_server1}a" \ 1015 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4205\] .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \ 1016 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4206\] .* route-to: ${net_server2_6}::42:5@${epair_server2}a" \ 1017 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4207\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1018 ; do 1019 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 1020 done 1021} 1022 1023table_loop_cleanup() 1024{ 1025 pft_cleanup 1026} 1027 1028 1029atf_test_case "roundrobin" "cleanup" 1030 1031roundrobin_head() 1032{ 1033 atf_set descr 'multiple gateways of mixed AF, including prefixes and tables, for IPv6 packets' 1034 atf_set require.user root 1035} 1036 1037roundrobin_body() 1038{ 1039 pf_map_addr_common 1040 1041 # The rule is defined as "inet6 proto tcp" so directly given IPv4 hosts 1042 # will be removed from the pool by pfctl. Tables will still be loaded 1043 # and pf_map_addr() will only use IPv6 addresses from them. It will 1044 # iterate over members of the pool and inside of tables and prefixes. 1045 1046 jexec router pfctl -e 1047 pft_set_rules router \ 1048 "set debug loud" \ 1049 "set reassemble yes" \ 1050 "set state-policy if-bound" \ 1051 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:0/127 ${net_server2_6}::42:4 }" \ 1052 "pass in on ${epair_tester}b \ 1053 route-to { \ 1054 (${epair_server1}a ${net_server1_4_host_server}) \ 1055 (${epair_server2}a <rt_targets_empty>) \ 1056 (${epair_server1}a ${net_server1_6}::42:0/127) \ 1057 (${epair_server2}a <rt_targets_empty>) \ 1058 (${epair_server2}a <rt_targets>) \ 1059 } \ 1060 inet6 proto tcp \ 1061 keep state" 1062 1063 for port in $(seq 1 6); do 1064 port=$((4200 + port)) 1065 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1066 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1067 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1068 --ping-type=tcp3way --send-sport=${port} 1069 done 1070 1071 states=$(mktemp) || exit 1 1072 jexec router pfctl -qvvss | normalize_pfctl_s > $states 1073 1074 for state_regexp in \ 1075 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4201\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1076 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \ 1077 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4203\] .* route-to: ${net_server2_6}::42:0@${epair_server2}a" \ 1078 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4204\] .* route-to: ${net_server2_6}::42:1@${epair_server2}a" \ 1079 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4205\] .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \ 1080 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4206\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1081 ; do 1082 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 1083 done 1084} 1085 1086roundrobin_cleanup() 1087{ 1088 pft_cleanup 1089} 1090 1091atf_test_case "random_table" "cleanup" 1092 1093random_table_head() 1094{ 1095 atf_set descr 'Pool with random flag and a table for IPv6' 1096 atf_set require.user root 1097} 1098 1099random_table_body() 1100{ 1101 pf_map_addr_common 1102 1103 # The "random" flag will pick random hosts from the table but will 1104 # not dive into prefixes, always choosing the 0th address. 1105 # Proper address family will be choosen. 1106 1107 jexec router pfctl -e 1108 pft_set_rules router \ 1109 "set debug loud" \ 1110 "set reassemble yes" \ 1111 "set state-policy if-bound" \ 1112 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:0/127 ${net_server2_6}::42:4 }" \ 1113 "pass in on ${epair_tester}b \ 1114 route-to { (${epair_server2}a <rt_targets>) } random \ 1115 inet6 proto tcp \ 1116 keep state" 1117 1118 good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:4" 1119 bad_targets="${net_server2_6}::42:1" 1120 check_random IPv6 "${good_targets}" "${bad_targets}" 1121} 1122 1123random_table_cleanup() 1124{ 1125 pft_cleanup 1126} 1127 1128atf_test_case "random_prefix" "cleanup" 1129 1130random_prefix_head() 1131{ 1132 atf_set descr 'Pool with random flag and a table for IPv4' 1133 atf_set require.user root 1134} 1135 1136random_prefix_body() 1137{ 1138 pf_map_addr_common 1139 1140 # The "random" flag will pick random hosts from given prefix. 1141 # The choice being random makes testing it non-trivial. We do 10 1142 # attempts to have each target chosen. Hopefully this is enough to have 1143 # this test pass often enough. 1144 1145 jexec router pfctl -e 1146 pft_set_rules router \ 1147 "set debug loud" \ 1148 "set reassemble yes" \ 1149 "set state-policy if-bound" \ 1150 "pass in on ${epair_tester}b \ 1151 route-to { (${epair_server2}a ${net_server2_6}::42:0/127) } random \ 1152 inet6 proto tcp \ 1153 keep state" 1154 1155 good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:1" 1156 check_random IPv6 "${good_targets}" 1157} 1158 1159random_prefix_cleanup() 1160{ 1161 pft_cleanup 1162} 1163 1164atf_test_case "prefer_ipv6_nexthop_single_ipv4" "cleanup" 1165 1166prefer_ipv6_nexthop_single_ipv4_head() 1167{ 1168 atf_set descr 'prefer-ipv6-nexthop option for a single IPv4 gateway' 1169 atf_set require.user root 1170} 1171 1172prefer_ipv6_nexthop_single_ipv4_body() 1173{ 1174 pf_map_addr_common 1175 1176 # Basic forwarding test for prefer-ipv6-nexthop pool option. 1177 # A single IPv4 gateway will work only for IPv4 traffic. 1178 1179 jexec router pfctl -e 1180 pft_set_rules router \ 1181 "set reassemble yes" \ 1182 "set state-policy if-bound" \ 1183 "pass in on ${epair_tester}b \ 1184 route-to (${epair_server1}a ${net_server1_4_host_server}) prefer-ipv6-nexthop \ 1185 proto tcp \ 1186 keep state" 1187 1188 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1189 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1190 --fromaddr ${net_clients_4}.1 --to ${host_server_4} \ 1191 --ping-type=tcp3way --send-sport=4201 \ 1192 1193 atf_check -s exit:1 ${common_dir}/pft_ping.py \ 1194 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1195 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1196 --ping-type=tcp3way --send-sport=4202 1197 1198 states=$(mktemp) || exit 1 1199 jexec router pfctl -qvvss | normalize_pfctl_s > $states 1200 1201 for state_regexp in \ 1202 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4201 .* route-to: ${net_server1_4_host_server}@${epair_server1}a" \ 1203 ; do 1204 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 1205 done 1206 1207 # The IPv6 packet could not have been routed over IPv4 gateway. 1208 atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null" 1209} 1210 1211prefer_ipv6_nexthop_single_ipv4_cleanup() 1212{ 1213 pft_cleanup 1214} 1215 1216atf_test_case "prefer_ipv6_nexthop_single_ipv6" "cleanup" 1217 1218prefer_ipv6_nexthop_single_ipv6_head() 1219{ 1220 atf_set descr 'prefer-ipv6-nexthop option for a single IPv6 gateway' 1221 atf_set require.user root 1222} 1223 1224prefer_ipv6_nexthop_single_ipv6_body() 1225{ 1226 pf_map_addr_common 1227 1228 # Basic forwarding test for prefer-ipv6-nexthop pool option. 1229 # A single IPve gateway will work both for IPv4 and IPv6 traffic. 1230 1231 jexec router pfctl -e 1232 pft_set_rules router \ 1233 "set reassemble yes" \ 1234 "set state-policy if-bound" \ 1235 "pass in on ${epair_tester}b \ 1236 route-to (${epair_server1}a ${net_server1_6_host_server}) prefer-ipv6-nexthop \ 1237 proto tcp \ 1238 keep state" 1239 1240 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1241 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1242 --fromaddr ${net_clients_4}.1 --to ${host_server_4} \ 1243 --ping-type=tcp3way --send-sport=4201 \ 1244 1245 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1246 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1247 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1248 --ping-type=tcp3way --send-sport=4202 1249 1250 states=$(mktemp) || exit 1 1251 jexec router pfctl -qvvss | normalize_pfctl_s > $states 1252 1253 for state_regexp in \ 1254 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4201 .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \ 1255 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \ 1256 ; do 1257 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 1258 done 1259} 1260 1261prefer_ipv6_nexthop_single_ipv6_cleanup() 1262{ 1263 pft_cleanup 1264} 1265 1266atf_test_case "prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4" "cleanup" 1267 1268prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4_head() 1269{ 1270 atf_set descr 'prefer-ipv6-nexthop option for multiple gateways of mixed AF with prefixes and tables, round robin selection, for IPv4 packets' 1271 atf_set require.user root 1272} 1273 1274prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4_body() 1275{ 1276 pf_map_addr_common 1277 1278 # pf_map_addr() starts iterating over hosts of the pool from the 2nd 1279 # host. This behaviour was here before adding prefer-ipv6-nexthop 1280 # support, we test for it. Some targets are hosts and some are tables. 1281 # Those are iterated too. Finally the iteration loops back 1282 # to the beginning of the pool. Send out IPv4 probes. They will use all 1283 # IPv4 and IPv6 addresses from the pool. 1284 1285 jexec router pfctl -e 1286 pft_set_rules router \ 1287 "set reassemble yes" \ 1288 "set state-policy if-bound" \ 1289 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:4/127 }" \ 1290 "pass in on ${epair_tester}b \ 1291 route-to { \ 1292 (${epair_server1}a ${net_server1_6_host_server}) \ 1293 (${epair_server1}a ${net_server1_6}::42:0/127) \ 1294 (${epair_server2}a ${net_server2_4_host_server}) \ 1295 (${epair_server2}a <rt_targets_empty>) \ 1296 (${epair_server1}a ${net_server1_4}.24/31) \ 1297 (${epair_server2}a <rt_targets>) \ 1298 } prefer-ipv6-nexthop \ 1299 proto tcp \ 1300 keep state" 1301 1302 for port in $(seq 1 12); do 1303 port=$((4200 + port)) 1304 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1305 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1306 --fromaddr ${net_clients_4}.1 --to ${host_server_4} \ 1307 --ping-type=tcp3way --send-sport=${port} 1308 done 1309 1310 states=$(mktemp) || exit 1 1311 jexec router pfctl -qvvss | normalize_pfctl_s > $states 1312 1313 for state_regexp in \ 1314 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4201 .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1315 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4202 .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \ 1316 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4203 .* route-to: ${net_server2_4_host_server}@${epair_server2}a" \ 1317 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4204 .* route-to: ${net_server1_4}.24@${epair_server1}a" \ 1318 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4205 .* route-to: ${net_server1_4}.25@${epair_server1}a" \ 1319 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4206 .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \ 1320 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4207 .* route-to: ${net_server2_6}::42:5@${epair_server2}a" \ 1321 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4208 .* route-to: ${net_server2_4}.40@${epair_server2}a" \ 1322 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4209 .* route-to: ${net_server2_4}.41@${epair_server2}a" \ 1323 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4210 .* route-to: ${net_server2_4}.44@${epair_server2}a" \ 1324 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4211 .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \ 1325 "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4212 .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1326 ; do 1327 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 1328 done 1329} 1330 1331prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4_cleanup() 1332{ 1333 pft_cleanup 1334} 1335 1336prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6_head() 1337{ 1338 atf_set descr 'prefer-ipv6-nexthop option for multiple gateways of mixed AF with prefixes and tables, round-robin selection, for IPv6 packets' 1339 atf_set require.user root 1340} 1341 1342prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6_body() 1343{ 1344 pf_map_addr_common 1345 1346 # The "random" flag will pick random hosts from the table but will 1347 # not dive into prefixes, always choosing the 0th address. 1348 # Proper address family will be choosen. The choice being random makes 1349 # testing it non-trivial. We do 10 attempts to have each target chosen. 1350 # Hopefully this is enough to have this test pass often enough. 1351 1352 # pf_map_addr() starts iterating over hosts of the pool from the 2nd 1353 # host. This behaviour was here before adding prefer-ipv6-nexthop 1354 # support, we test for it. Some targets are hosts and some are tables. 1355 # Those are iterated too. Finally the iteration loops back 1356 # to the beginning of the pool. Send out IPv6 probes. They will use only 1357 # IPv6 addresses from the pool. 1358 1359 jexec router pfctl -e 1360 pft_set_rules router \ 1361 "set reassemble yes" \ 1362 "set state-policy if-bound" \ 1363 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:4/127 }" \ 1364 "pass in on ${epair_tester}b \ 1365 route-to { \ 1366 (${epair_server1}a ${net_server1_6_host_server}) \ 1367 (${epair_server1}a ${net_server1_6}::42:0/127) \ 1368 (${epair_server2}a ${net_server2_4_host_server}) \ 1369 (${epair_server2}a <rt_targets_empty>) \ 1370 (${epair_server1}a ${net_server1_4}.24/31) \ 1371 (${epair_server2}a <rt_targets>) \ 1372 } prefer-ipv6-nexthop \ 1373 proto tcp \ 1374 keep state" 1375 1376 for port in $(seq 1 6); do 1377 port=$((4200 + port)) 1378 atf_check -s exit:0 ${common_dir}/pft_ping.py \ 1379 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1380 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1381 --ping-type=tcp3way --send-sport=${port} 1382 done 1383 1384 states=$(mktemp) || exit 1 1385 jexec router pfctl -qvvss | normalize_pfctl_s > $states 1386 1387 for state_regexp in \ 1388 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4201\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1389 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \ 1390 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4203\] .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \ 1391 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4204\] .* route-to: ${net_server2_6}::42:5@${epair_server2}a" \ 1392 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4205\] .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \ 1393 "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4206\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \ 1394 ; do 1395 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 1396 done 1397} 1398 1399prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6_cleanup() 1400{ 1401 pft_cleanup 1402} 1403 1404atf_test_case "prefer_ipv6_nexthop_mixed_af_random_ipv4" "cleanup" 1405 1406prefer_ipv6_nexthop_mixed_af_random_table_ipv4_head() 1407{ 1408 atf_set descr 'prefer-ipv6-nexthop option for a mixed-af table with random selection for IPv4 packets' 1409 atf_set require.user root 1410} 1411 1412prefer_ipv6_nexthop_mixed_af_random_table_ipv4_body() 1413{ 1414 pf_map_addr_common 1415 1416 # Similarly to the test "random_table" the algorithm will choose 1417 # IP addresses from the table not diving into prefixes. 1418 # *prefer*-ipv6-nexthop means that IPv6 nexthops are preferred, 1419 # so IPv4 ones will not be chosen as long as there are IPv6 ones 1420 # available. With this tested there is no need for a test for IPv6-only 1421 # next-hops table. 1422 1423 jexec router pfctl -e 1424 pft_set_rules router \ 1425 "set reassemble yes" \ 1426 "set state-policy if-bound" \ 1427 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:0/127 ${net_server2_6}::42:4 }" \ 1428 "pass in on ${epair_tester}b \ 1429 route-to { (${epair_server2}a <rt_targets>) } random prefer-ipv6-nexthop \ 1430 proto tcp \ 1431 keep state" 1432 1433 good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:4" 1434 bad_targets="${net_server2_4}.40 ${net_server2_4}.41 ${net_server2_4}.44 ${net_server2_6}::42:1" 1435 check_random IPv4 "${good_targets}" "${bad_targets}" 1436} 1437 1438prefer_ipv6_nexthop_mixed_af_random_table_ipv4_cleanup() 1439{ 1440 pft_cleanup 1441} 1442 1443prefer_ipv6_nexthop_ipv4_random_table_ipv4_head() 1444{ 1445 atf_set descr 'prefer-ipv6-nexthop option for an IPv4-only table with random selection for IPv4 packets' 1446 atf_set require.user root 1447} 1448 1449prefer_ipv6_nexthop_ipv4_random_table_ipv4_body() 1450{ 1451 pf_map_addr_common 1452 1453 # Similarly to the test pf_map_addr:random_table the algorithm will 1454 # choose IP addresses from the table not diving into prefixes. 1455 # There are no IPv6 nexthops in the table, so the algorithm will 1456 # fall back to IPv4. 1457 1458 jexec router pfctl -e 1459 pft_set_rules router \ 1460 "set reassemble yes" \ 1461 "set state-policy if-bound" \ 1462 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 }" \ 1463 "pass in on ${epair_tester}b \ 1464 route-to { (${epair_server2}a <rt_targets>) } random prefer-ipv6-nexthop \ 1465 proto tcp \ 1466 keep state" 1467 1468 good_targets="${net_server2_4}.40 ${net_server2_4}.44" 1469 bad_targets="${net_server2_4}.41" 1470 check_random IPv4 "${good_targets}" "${bad_targets}" 1471} 1472 1473prefer_ipv6_nexthop_ipv4_random_table_ipv4_cleanup() 1474{ 1475 pft_cleanup 1476} 1477 1478prefer_ipv6_nexthop_ipv4_random_table_ipv6_head() 1479{ 1480 atf_set descr 'prefer-ipv6-nexthop option for an IPv4-only table with random selection for IPv6 packets' 1481 atf_set require.user root 1482} 1483 1484prefer_ipv6_nexthop_ipv4_random_table_ipv6_body() 1485{ 1486 pf_map_addr_common 1487 1488 # IPv6 packets can't be forwarded over IPv4 next-hops. 1489 # The failure happens in pf_map_addr() and increases the respective 1490 # error counter. 1491 1492 jexec router pfctl -e 1493 pft_set_rules router \ 1494 "set reassemble yes" \ 1495 "set state-policy if-bound" \ 1496 "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 }" \ 1497 "pass in on ${epair_tester}b \ 1498 route-to { (${epair_server2}a <rt_targets>) } random prefer-ipv6-nexthop \ 1499 proto tcp \ 1500 keep state" 1501 1502 atf_check -s exit:1 ${common_dir}/pft_ping.py \ 1503 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1504 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1505 --ping-type=tcp3way --send-sport=4201 1506 1507 atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null" 1508} 1509 1510prefer_ipv6_nexthop_ipv4_random_table_ipv6_cleanup() 1511{ 1512 pft_cleanup 1513} 1514 1515prefer_ipv6_nexthop_ipv6_random_prefix_ipv4_head() 1516{ 1517 atf_set descr 'prefer-ipv6-nexthop option for an IPv6 prefix with random selection for IPv4 packets' 1518 atf_set require.user root 1519} 1520 1521prefer_ipv6_nexthop_ipv6_random_prefix_ipv4_body() 1522{ 1523 pf_map_addr_common 1524 1525 jexec router pfctl -e 1526 pft_set_rules router \ 1527 "set reassemble yes" \ 1528 "set state-policy if-bound" \ 1529 "pass in on ${epair_tester}b \ 1530 route-to { (${epair_server2}a ${net_server2_6}::42:0/127) } random prefer-ipv6-nexthop \ 1531 proto tcp \ 1532 keep state" 1533 1534 good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:1" 1535 check_random IPv4 "${good_targets}" 1536} 1537 1538prefer_ipv6_nexthop_ipv6_random_prefix_ipv4_cleanup() 1539{ 1540 pft_cleanup 1541} 1542 1543prefer_ipv6_nexthop_ipv6_random_prefix_ipv6_head() 1544{ 1545 atf_set descr 'prefer-ipv6-nexthop option for an IPv6 prefix with random selection for IPv6 packets' 1546 atf_set require.user root 1547} 1548 1549prefer_ipv6_nexthop_ipv6_random_prefix_ipv6_body() 1550{ 1551 pf_map_addr_common 1552 1553 jexec router pfctl -e 1554 pft_set_rules router \ 1555 "set reassemble yes" \ 1556 "set state-policy if-bound" \ 1557 "pass in on ${epair_tester}b \ 1558 route-to { (${epair_server2}a ${net_server2_6}::42:0/127) } random prefer-ipv6-nexthop \ 1559 proto tcp \ 1560 keep state" 1561 1562 good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:1" 1563 check_random IPv6 "${good_targets}" 1564} 1565 1566prefer_ipv6_nexthop_ipv6_random_prefix_ipv6_cleanup() 1567{ 1568 pft_cleanup 1569} 1570 1571prefer_ipv6_nexthop_ipv4_random_prefix_ipv4_head() 1572{ 1573 atf_set descr 'prefer-ipv6-nexthop option for an IPv4 prefix with random selection for IPv4 packets' 1574 atf_set require.user root 1575} 1576 1577prefer_ipv6_nexthop_ipv4_random_prefix_ipv4_body() 1578{ 1579 pf_map_addr_common 1580 1581 jexec router pfctl -e 1582 pft_set_rules router \ 1583 "set reassemble yes" \ 1584 "set state-policy if-bound" \ 1585 "pass in on ${epair_tester}b \ 1586 route-to { (${epair_server2}a ${net_server2_4}.40/31) } random prefer-ipv6-nexthop \ 1587 proto tcp \ 1588 keep state" 1589 1590 good_targets="${net_server2_4}.40 ${net_server2_4}.41" 1591 check_random IPv4 "${good_targets}" 1592} 1593 1594prefer_ipv6_nexthop_ipv4_random_prefix_ipv4_cleanup() 1595{ 1596 pft_cleanup 1597} 1598 1599prefer_ipv6_nexthop_ipv4_random_prefix_ipv6_head() 1600{ 1601 atf_set descr 'prefer-ipv6-nexthop option for an IPv4 prefix with random selection for IPv6 packets' 1602 atf_set require.user root 1603} 1604 1605prefer_ipv6_nexthop_ipv4_random_prefix_ipv6_body() 1606{ 1607 pf_map_addr_common 1608 1609 # IPv6 packets can't be forwarded over IPv4 next-hops. 1610 # The failure happens in pf_map_addr() and increases the respective 1611 # error counter. 1612 1613 jexec router pfctl -e 1614 pft_set_rules router \ 1615 "set reassemble yes" \ 1616 "set state-policy if-bound" \ 1617 "pass in on ${epair_tester}b \ 1618 route-to { (${epair_server2}a ${net_server2_4}.40/31) } random prefer-ipv6-nexthop \ 1619 proto tcp \ 1620 keep state" 1621 1622 atf_check -s exit:1 ${common_dir}/pft_ping.py \ 1623 --sendif ${epair_tester}a --replyif ${epair_tester}a \ 1624 --fromaddr ${net_clients_6}::1 --to ${host_server_6} \ 1625 --ping-type=tcp3way --send-sport=4201 1626 1627 atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null" 1628} 1629 1630prefer_ipv6_nexthop_ipv4_random_prefix_ipv6_cleanup() 1631{ 1632 pft_cleanup 1633} 1634 1635atf_init_test_cases() 1636{ 1637 atf_add_test_case "v4" 1638 atf_add_test_case "v6" 1639 atf_add_test_case "multiwan" 1640 atf_add_test_case "multiwanlocal" 1641 atf_add_test_case "icmp_nat" 1642 atf_add_test_case "dummynet" 1643 atf_add_test_case "dummynet_in" 1644 atf_add_test_case "ifbound" 1645 atf_add_test_case "ifbound_v6" 1646 atf_add_test_case "ifbound_reply_to" 1647 atf_add_test_case "ifbound_reply_to_v6" 1648 atf_add_test_case "ifbound_reply_to_rdr_dummynet" 1649 atf_add_test_case "dummynet_frag" 1650 atf_add_test_case "dummynet_double" 1651 atf_add_test_case "sticky" 1652 atf_add_test_case "ttl" 1653 atf_add_test_case "empty_pool" 1654 # Tests for pf_map_addr() without prefer-ipv6-nexthop 1655 atf_add_test_case "table_loop" 1656 atf_add_test_case "roundrobin" 1657 atf_add_test_case "random_table" 1658 atf_add_test_case "random_prefix" 1659 # Tests for pf_map_addr() without prefer-ipv6-nexthop 1660 # Next hop is a Single IP address 1661 atf_add_test_case "prefer_ipv6_nexthop_single_ipv4" 1662 atf_add_test_case "prefer_ipv6_nexthop_single_ipv6" 1663 # Next hop is tables and prefixes, accessed by the round-robin algorithm 1664 atf_add_test_case "prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4" 1665 atf_add_test_case "prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6" 1666 # Next hop is a table, accessed by the random algorithm 1667 atf_add_test_case "prefer_ipv6_nexthop_mixed_af_random_table_ipv4" 1668 atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_table_ipv4" 1669 atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_table_ipv6" 1670 # Next hop is a prefix, accessed by the random algorithm 1671 atf_add_test_case "prefer_ipv6_nexthop_ipv6_random_prefix_ipv4" 1672 atf_add_test_case "prefer_ipv6_nexthop_ipv6_random_prefix_ipv6" 1673 atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_prefix_ipv4" 1674 atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_prefix_ipv6" 1675} 1676