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