1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2018 Kristof Provost <kp@FreeBSD.org> 5# Copyright (c) 2025 Kajetan Staszkiewicz <ks@FreeBSD.org> 6# Copyright (c) 2021 KUROSAWA Takahiro <takahiro.kurosawa@gmail.com> 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27# SUCH DAMAGE. 28 29. $(atf_get_srcdir)/utils.subr 30 31atf_test_case "exhaust" "cleanup" 32exhaust_head() 33{ 34 atf_set descr 'Test exhausting the NAT pool' 35 atf_set require.user root 36} 37 38exhaust_body() 39{ 40 pft_init 41 42 epair_nat=$(vnet_mkepair) 43 epair_echo=$(vnet_mkepair) 44 45 vnet_mkjail nat ${epair_nat}b ${epair_echo}a 46 vnet_mkjail echo ${epair_echo}b 47 48 ifconfig ${epair_nat}a 192.0.2.2/24 up 49 route add -net 198.51.100.0/24 192.0.2.1 50 51 jexec nat ifconfig ${epair_nat}b 192.0.2.1/24 up 52 jexec nat ifconfig ${epair_echo}a 198.51.100.1/24 up 53 jexec nat sysctl net.inet.ip.forwarding=1 54 55 jexec echo ifconfig ${epair_echo}b 198.51.100.2/24 up 56 jexec echo /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf 57 58 # Enable pf! 59 jexec nat pfctl -e 60 pft_set_rules nat \ 61 "nat pass on ${epair_echo}a inet from 192.0.2.0/24 to any -> (${epair_echo}a) port 30000:30001 sticky-address" 62 63 # Sanity check 64 atf_check -s exit:0 -o ignore ping -c 3 198.51.100.2 65 66 atf_check -s exit:0 -o match:foo* echo "foo" | nc -N 198.51.100.2 7 67 atf_check -s exit:0 -o match:foo* echo "foo" | nc -N 198.51.100.2 7 68 69 # This one will fail, but that's expected 70 echo "foo" | nc -N 198.51.100.2 7 & 71 72 sleep 1 73 74 # If the kernel is stuck in pf_get_sport() this will not succeed either. 75 timeout 2 jexec nat pfctl -sa 76 if [ $? -eq 124 ]; then 77 # Timed out 78 atf_fail "pfctl timeout" 79 fi 80} 81 82exhaust_cleanup() 83{ 84 pft_cleanup 85} 86 87atf_test_case "nested_anchor" "cleanup" 88nested_anchor_head() 89{ 90 atf_set descr 'Test setting and retrieving nested nat anchors' 91 atf_set require.user root 92} 93 94nested_anchor_body() 95{ 96 pft_init 97 98 epair=$(vnet_mkepair) 99 100 vnet_mkjail nat ${epair}a 101 102 pft_set_rules nat \ 103 "nat-anchor \"foo\"" 104 105 echo "nat-anchor \"bar\"" | jexec nat pfctl -g -a foo -f - 106 echo "nat on ${epair}a from any to any -> (${epair}a)" | jexec nat pfctl -g -a "foo/bar" -f - 107 108 atf_check -s exit:0 -o inline:"nat-anchor \"foo\" all { 109 nat-anchor \"bar\" all { 110 nat on ${epair}a all -> (${epair}a) round-robin 111 } 112} 113" jexec nat pfctl -sn -a "*" 114 115} 116 117endpoint_independent_setup() 118{ 119 pft_init 120 filter="udp and dst port 1234" # only capture udp pings 121 122 epair_client=$(vnet_mkepair) 123 epair_nat=$(vnet_mkepair) 124 epair_server1=$(vnet_mkepair) 125 epair_server2=$(vnet_mkepair) 126 bridge=$(vnet_mkbridge) 127 128 vnet_mkjail nat ${epair_client}b ${epair_nat}a 129 vnet_mkjail client ${epair_client}a 130 vnet_mkjail server1 ${epair_server1}a 131 vnet_mkjail server2 ${epair_server2}a 132 133 ifconfig ${epair_server1}b up 134 ifconfig ${epair_server2}b up 135 ifconfig ${epair_nat}b up 136 ifconfig ${bridge} \ 137 addm ${epair_server1}b \ 138 addm ${epair_server2}b \ 139 addm ${epair_nat}b \ 140 up 141 142 jexec nat ifconfig ${epair_client}b 192.0.2.1/24 up 143 jexec nat ifconfig ${epair_nat}a 198.51.100.42/24 up 144 jexec nat sysctl net.inet.ip.forwarding=1 145 146 jexec client ifconfig ${epair_client}a 192.0.2.2/24 up 147 jexec client route add default 192.0.2.1 148 149 jexec server1 ifconfig ${epair_server1}a 198.51.100.32/24 up 150 jexec server2 ifconfig ${epair_server2}a 198.51.100.22/24 up 151} 152 153endpoint_independent_common() 154{ 155 # Enable pf! 156 jexec nat pfctl -e 157 158 # validate non-endpoint independent nat rule behaviour 159 pft_set_rules nat "${1}" 160 161 jexec server1 tcpdump -i ${epair_server1}a -w ${PWD}/server1.pcap \ 162 --immediate-mode $filter & 163 server1tcppid="$!" 164 jexec server2 tcpdump -i ${epair_server2}a -w ${PWD}/server2.pcap \ 165 --immediate-mode $filter & 166 server2tcppid="$!" 167 168 # send out multiple packets 169 for i in $(seq 1 10); do 170 echo "ping" | jexec client nc -u 198.51.100.32 1234 -p 4242 -w 0 171 echo "ping" | jexec client nc -u 198.51.100.22 1234 -p 4242 -w 0 172 done 173 174 kill $server1tcppid 175 kill $server2tcppid 176 177 tuple_server1=$(tcpdump -r ${PWD}/server1.pcap | awk '{addr=$3} END {print addr}') 178 tuple_server2=$(tcpdump -r ${PWD}/server2.pcap | awk '{addr=$3} END {print addr}') 179 180 if [ -z $tuple_server1 ] 181 then 182 atf_fail "server1 did not receive connection from client (default)" 183 fi 184 185 if [ -z $tuple_server2 ] 186 then 187 atf_fail "server2 did not receive connection from client (default)" 188 fi 189 190 if [ "$tuple_server1" = "$tuple_server2" ] 191 then 192 echo "server1 tcpdump: $tuple_server1" 193 echo "server2 tcpdump: $tuple_server2" 194 atf_fail "Received same IP:port on server1 and server2 (default)" 195 fi 196 197 # validate endpoint independent nat rule behaviour 198 pft_set_rules nat "${2}" 199 200 jexec server1 tcpdump -i ${epair_server1}a -w ${PWD}/server1.pcap \ 201 --immediate-mode $filter & 202 server1tcppid="$!" 203 jexec server2 tcpdump -i ${epair_server2}a -w ${PWD}/server2.pcap \ 204 --immediate-mode $filter & 205 server2tcppid="$!" 206 207 # send out multiple packets, sometimes one fails to go through 208 for i in $(seq 1 10); do 209 echo "ping" | jexec client nc -u 198.51.100.32 1234 -p 4242 -w 0 210 echo "ping" | jexec client nc -u 198.51.100.22 1234 -p 4242 -w 0 211 done 212 213 kill $server1tcppid 214 kill $server2tcppid 215 216 tuple_server1=$(tcpdump -r ${PWD}/server1.pcap | awk '{addr=$3} END {print addr}') 217 tuple_server2=$(tcpdump -r ${PWD}/server2.pcap | awk '{addr=$3} END {print addr}') 218 219 if [ -z $tuple_server1 ] 220 then 221 atf_fail "server1 did not receive connection from client (endpoint-independent)" 222 fi 223 224 if [ -z $tuple_server2 ] 225 then 226 atf_fail "server2 did not receive connection from client (endpoint-independent)" 227 fi 228 229 if [ ! "$tuple_server1" = "$tuple_server2" ] 230 then 231 echo "server1 tcpdump: $tuple_server1" 232 echo "server2 tcpdump: $tuple_server2" 233 atf_fail "Received different IP:port on server1 than server2 (endpoint-independent)" 234 fi 235} 236 237atf_test_case "endpoint_independent_compat" "cleanup" 238endpoint_independent_compat_head() 239{ 240 atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers' 241 atf_set require.user root 242} 243 244endpoint_independent_compat_body() 245{ 246 endpoint_independent_setup # Sets ${epair_…} variables 247 248 endpoint_independent_common \ 249 "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a)" \ 250 "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a) endpoint-independent" 251} 252 253endpoint_independent_compat_cleanup() 254{ 255 pft_cleanup 256 rm -f server1.out 257 rm -f server2.out 258} 259 260atf_test_case "endpoint_independent_pass" "cleanup" 261endpoint_independent_pass_head() 262{ 263 atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers' 264 atf_set require.user root 265} 266 267endpoint_independent_pass_body() 268{ 269 endpoint_independent_setup # Sets ${epair_…} variables 270 271 endpoint_independent_common \ 272 "pass out on ${epair_nat}a inet from ! (${epair_nat}a) to any nat-to (${epair_nat}a) keep state" \ 273 "pass out on ${epair_nat}a inet from ! (${epair_nat}a) to any nat-to (${epair_nat}a) endpoint-independent keep state" 274 275} 276 277endpoint_independent_pass_cleanup() 278{ 279 pft_cleanup 280 rm -f server1.out 281 rm -f server2.out 282} 283 284nested_anchor_cleanup() 285{ 286 pft_cleanup 287} 288 289atf_test_case "nat6_nolinklocal" "cleanup" 290nat6_nolinklocal_head() 291{ 292 atf_set descr 'Ensure we do not use link-local addresses' 293 atf_set require.user root 294} 295 296nat6_nolinklocal_body() 297{ 298 pft_init 299 300 epair_nat=$(vnet_mkepair) 301 epair_echo=$(vnet_mkepair) 302 303 vnet_mkjail nat ${epair_nat}b ${epair_echo}a 304 vnet_mkjail echo ${epair_echo}b 305 306 ifconfig ${epair_nat}a inet6 2001:db8::2/64 no_dad up 307 route add -6 -net 2001:db8:1::/64 2001:db8::1 308 309 jexec nat ifconfig ${epair_nat}b inet6 2001:db8::1/64 no_dad up 310 jexec nat ifconfig ${epair_echo}a inet6 2001:db8:1::1/64 no_dad up 311 jexec nat sysctl net.inet6.ip6.forwarding=1 312 313 jexec echo ifconfig ${epair_echo}b inet6 2001:db8:1::2/64 no_dad up 314 # Ensure we can't reply to link-local pings 315 jexec echo pfctl -e 316 pft_set_rules echo \ 317 "pass" \ 318 "block in inet6 proto icmp6 from fe80::/10 to any icmp6-type echoreq" 319 320 jexec nat pfctl -e 321 pft_set_rules nat \ 322 "nat pass on ${epair_echo}a inet6 from 2001:db8::/64 to any -> (${epair_echo}a)" \ 323 "pass" 324 325 # Sanity check 326 atf_check -s exit:0 -o ignore \ 327 ping -6 -c 1 2001:db8::1 328 for i in `seq 0 10` 329 do 330 atf_check -s exit:0 -o ignore \ 331 ping -6 -c 1 2001:db8:1::2 332 done 333} 334 335nat6_nolinklocal_cleanup() 336{ 337 pft_cleanup 338} 339 340empty_table_common() 341{ 342 option=$1 343 344 pft_init 345 346 epair_wan=$(vnet_mkepair) 347 epair_lan=$(vnet_mkepair) 348 349 vnet_mkjail srv ${epair_wan}a 350 jexec srv ifconfig ${epair_wan}a 192.0.2.2/24 up 351 352 vnet_mkjail rtr ${epair_wan}b ${epair_lan}a 353 jexec rtr ifconfig ${epair_wan}b 192.0.2.1/24 up 354 jexec rtr ifconfig ${epair_lan}a 198.51.100.1/24 up 355 jexec rtr sysctl net.inet.ip.forwarding=1 356 357 ifconfig ${epair_lan}b 198.51.100.2/24 up 358 route add default 198.51.100.1 359 360 jexec rtr pfctl -e 361 pft_set_rules rtr \ 362 "table <empty>" \ 363 "nat on ${epair_wan}b inet from 198.51.100.0/24 -> <empty> ${option}" \ 364 "pass" 365 366 # Sanity checks 367 atf_check -s exit:0 -o ignore \ 368 jexec rtr ping -c 1 192.0.2.2 369 atf_check -s exit:0 -o ignore \ 370 ping -c 1 198.51.100.1 371 atf_check -s exit:0 -o ignore \ 372 ping -c 1 192.0.2.1 373 374 # Provoke divide by zero 375 ping -c 1 192.0.2.2 376 true 377} 378 379atf_test_case "empty_table_source_hash" "cleanup" 380empty_table_source_hash_head() 381{ 382 atf_set descr 'Test source-hash on an emtpy table' 383 atf_set require.user root 384} 385 386empty_table_source_hash_body() 387{ 388 empty_table_common "source-hash" 389} 390 391empty_table_source_hash_cleanup() 392{ 393 pft_cleanup 394} 395 396atf_test_case "empty_table_random" "cleanup" 397empty_table_random_head() 398{ 399 atf_set descr 'Test random on an emtpy table' 400 atf_set require.user root 401} 402 403empty_table_random_body() 404{ 405 empty_table_common "random" 406} 407 408empty_table_random_cleanup() 409{ 410 pft_cleanup 411} 412 413no_addrs_common() 414{ 415 option=$1 416 417 pft_init 418 419 epair_wan=$(vnet_mkepair) 420 epair_lan=$(vnet_mkepair) 421 422 vnet_mkjail srv ${epair_wan}a 423 jexec srv ifconfig ${epair_wan}a 192.0.2.2/24 up 424 425 vnet_mkjail rtr ${epair_wan}b ${epair_lan}a 426 jexec rtr route add -net 192.0.2.0/24 -iface ${epair_wan}b 427 jexec rtr ifconfig ${epair_lan}a 198.51.100.1/24 up 428 jexec rtr sysctl net.inet.ip.forwarding=1 429 430 ifconfig ${epair_lan}b 198.51.100.2/24 up 431 route add default 198.51.100.1 432 433 jexec rtr pfctl -e 434 pft_set_rules rtr \ 435 "nat on ${epair_wan}b inet from 198.51.100.0/24 -> (${epair_wan}b) ${option}" \ 436 "pass" 437 438 # Provoke divide by zero 439 ping -c 1 192.0.2.2 440 true 441} 442 443atf_test_case "no_addrs_source_hash" "cleanup" 444no_addrs_source_hash_head() 445{ 446 atf_set descr 'Test source-hash on an interface with no addresses' 447 atf_set require.user root 448} 449 450no_addrs_source_hash_body() 451{ 452 no_addrs_common "source-hash" 453} 454 455no_addrs_source_hash_cleanup() 456{ 457 pft_cleanup 458} 459 460atf_test_case "no_addrs_random" "cleanup" 461no_addrs_random_head() 462{ 463 atf_set descr 'Test random on an interface with no addresses' 464 atf_set require.user root 465} 466 467no_addrs_random_body() 468{ 469 no_addrs_common "random" 470} 471 472no_addrs_random_cleanup() 473{ 474 pft_cleanup 475} 476 477nat_pass_head() 478{ 479 atf_set descr 'IPv4 NAT on pass rule' 480 atf_set require.user root 481 atf_set require.progs scapy 482} 483 484nat_pass_body() 485{ 486 setup_router_server_ipv4 487 # Delete the route back to make sure that the traffic has been NAT-ed 488 jexec server route del -net ${net_tester} ${net_server_host_router} 489 490 pft_set_rules router \ 491 "block" \ 492 "pass in on ${epair_tester}b inet proto tcp keep state" \ 493 "pass out on ${epair_server}a inet proto tcp nat-to ${epair_server}a keep state" 494 495 ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201 496 497 jexec router pfctl -qvvsr 498 jexec router pfctl -qvvss 499 jexec router ifconfig 500 jexec router netstat -rn 501} 502 503nat_pass_cleanup() 504{ 505 pft_cleanup 506} 507 508nat_match_head() 509{ 510 atf_set descr 'IPv4 NAT on match rule' 511 atf_set require.user root 512 atf_set require.progs scapy 513} 514 515nat_match_body() 516{ 517 setup_router_server_ipv4 518 # Delete the route back to make sure that the traffic has been NAT-ed 519 jexec server route del -net ${net_tester} ${net_server_host_router} 520 521 # NAT is applied during ruleset evaluation: 522 # rules after "match" match on NAT-ed address 523 pft_set_rules router \ 524 "block" \ 525 "pass in on ${epair_tester}b inet proto tcp keep state" \ 526 "match out on ${epair_server}a inet proto tcp nat-to ${epair_server}a" \ 527 "pass out on ${epair_server}a inet proto tcp from ${epair_server}a keep state" 528 529 ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201 530 531 jexec router pfctl -qvvsr 532 jexec router pfctl -qvvss 533 jexec router ifconfig 534 jexec router netstat -rn 535} 536 537nat_match_cleanup() 538{ 539 pft_cleanup 540} 541 542map_e_common() 543{ 544 NC_TRY_COUNT=12 545 546 pft_init 547 548 epair_map_e=$(vnet_mkepair) 549 epair_echo=$(vnet_mkepair) 550 551 vnet_mkjail map_e ${epair_map_e}b ${epair_echo}a 552 vnet_mkjail echo ${epair_echo}b 553 554 ifconfig ${epair_map_e}a 192.0.2.2/24 up 555 route add -net 198.51.100.0/24 192.0.2.1 556 557 jexec map_e ifconfig ${epair_map_e}b 192.0.2.1/24 up 558 jexec map_e ifconfig ${epair_echo}a 198.51.100.1/24 up 559 jexec map_e sysctl net.inet.ip.forwarding=1 560 561 jexec echo ifconfig ${epair_echo}b 198.51.100.2/24 up 562 jexec echo /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf 563 564 # Enable pf! 565 jexec map_e pfctl -e 566} 567 568atf_test_case "map_e_compat" "cleanup" 569map_e_compat_head() 570{ 571 atf_set descr 'map-e-portset test' 572 atf_set require.user root 573} 574 575map_e_compat_body() 576{ 577 map_e_common 578 579 pft_set_rules map_e \ 580 "nat pass on ${epair_echo}a inet from 192.0.2.0/24 to any -> (${epair_echo}a) map-e-portset 2/12/0x342" 581 582 # Only allow specified ports. 583 jexec echo pfctl -e 584 pft_set_rules echo "block return all" \ 585 "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 19720:19723 to (${epair_echo}b) port 7" \ 586 "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 36104:36107 to (${epair_echo}b) port 7" \ 587 "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 52488:52491 to (${epair_echo}b) port 7" \ 588 "set skip on lo" 589 590 i=0 591 while [ ${i} -lt ${NC_TRY_COUNT} ] 592 do 593 echo "foo ${i}" | timeout 2 nc -N 198.51.100.2 7 594 if [ $? -ne 0 ]; then 595 atf_fail "nc failed (${i})" 596 fi 597 i=$((${i}+1)) 598 done 599} 600 601map_e_compat_cleanup() 602{ 603 pft_cleanup 604} 605 606 607atf_test_case "map_e_pass" "cleanup" 608map_e_pass_head() 609{ 610 atf_set descr 'map-e-portset test' 611 atf_set require.user root 612} 613 614map_e_pass_body() 615{ 616 map_e_common 617 618 pft_set_rules map_e \ 619 "pass out on ${epair_echo}a inet from 192.0.2.0/24 to any nat-to (${epair_echo}a) map-e-portset 2/12/0x342 keep state" 620 621 jexec map_e pfctl -qvvsr 622 623 # Only allow specified ports. 624 jexec echo pfctl -e 625 pft_set_rules echo "block return all" \ 626 "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 19720:19723 to (${epair_echo}b) port 7" \ 627 "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 36104:36107 to (${epair_echo}b) port 7" \ 628 "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 52488:52491 to (${epair_echo}b) port 7" \ 629 "set skip on lo" 630 631 i=0 632 while [ ${i} -lt ${NC_TRY_COUNT} ] 633 do 634 echo "foo ${i}" | timeout 2 nc -N 198.51.100.2 7 635 if [ $? -ne 0 ]; then 636 atf_fail "nc failed (${i})" 637 fi 638 i=$((${i}+1)) 639 done 640} 641 642map_e_pass_cleanup() 643{ 644 pft_cleanup 645} 646 647binat_compat_head() 648{ 649 atf_set descr 'IPv4 BINAT with nat ruleset' 650 atf_set require.user root 651 atf_set require.progs scapy 652} 653 654binat_compat_body() 655{ 656 setup_router_server_ipv4 657 # Delete the route back to make sure that the traffic has been NAT-ed 658 jexec server route del -net ${net_tester} ${net_server_host_router} 659 660 pft_set_rules router \ 661 "set state-policy if-bound" \ 662 "set ruleset-optimization none" \ 663 "binat on ${epair_server}a inet proto tcp from ${net_tester_host_tester} to any tag sometag -> ${epair_server}a" \ 664 "block" \ 665 "pass in on ${epair_tester}b inet proto tcp !tagged sometag keep state" \ 666 "pass out on ${epair_server}a inet proto tcp tagged sometag keep state" \ 667 "pass in on ${epair_server}a inet proto tcp tagged sometag keep state" \ 668 "pass out on ${epair_tester}b inet proto tcp tagged sometag keep state" 669 670 # Test the outbound NAT part of BINAT. 671 ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201 672 673 states=$(mktemp) || exit 1 674 jexec router pfctl -qvss | normalize_pfctl_s > $states 675 676 for state_regexp in \ 677 "${epair_tester}b tcp ${net_server_host_server}:9 <- ${net_tester_host_tester}:4201 .* 3:2 pkts,.* rule 1" \ 678 "${epair_server}a tcp ${net_server_host_router}:4201 \(${net_tester_host_tester}:4201\) -> ${net_server_host_server}:9 .* 3:2 pkts,.* rule 2" \ 679 ; do 680 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 681 done 682 683 # Test the inbound RDR part of BINAT. 684 # The "tester" becomes "server" and vice versa. 685 inetd_conf=$(mktemp) 686 echo "discard stream tcp nowait root internal" > $inetd_conf 687 inetd -p ${PWD}/inetd_tester.pid $inetd_conf 688 689 atf_check -s exit:0 \ 690 jexec server ${common_dir}/pft_ping.py \ 691 --ping-type=tcp3way --send-sport=4202 \ 692 --sendif ${epair_server}b \ 693 --to ${net_server_host_router} \ 694 --replyif ${epair_server}b 695 696 states=$(mktemp) || exit 1 697 jexec router pfctl -qvss | normalize_pfctl_s > $states 698 699 for state_regexp in \ 700 "${epair_server}a tcp ${net_tester_host_tester}:9 \(${net_server_host_router}:9\) <- ${net_server_host_server}:4202 .* 3:2 pkts,.* rule 3" \ 701 "${epair_tester}b tcp ${net_server_host_server}:4202 -> ${net_tester_host_tester}:9 .* 3:2 pkts,.* rule 4" \ 702 ; do 703 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 704 done 705} 706 707binat_compat_cleanup() 708{ 709 pft_cleanup 710 kill $(cat ${PWD}/inetd_tester.pid) 711} 712 713binat_match_head() 714{ 715 atf_set descr 'IPv4 BINAT with nat ruleset' 716 atf_set require.user root 717 atf_set require.progs scapy 718} 719 720binat_match_body() 721{ 722 setup_router_server_ipv4 723 # Delete the route back to make sure that the traffic has been NAT-ed 724 jexec server route del -net ${net_tester} ${net_server_host_router} 725 726 # The "binat-to" rule expands to 2 rules so the ""pass" rules start at 3! 727 pft_set_rules router \ 728 "set state-policy if-bound" \ 729 "set ruleset-optimization none" \ 730 "block" \ 731 "match on ${epair_server}a inet proto tcp from ${net_tester_host_tester} to any tag sometag binat-to ${epair_server}a" \ 732 "pass in on ${epair_tester}b inet proto tcp !tagged sometag keep state" \ 733 "pass out on ${epair_server}a inet proto tcp tagged sometag keep state" \ 734 "pass in on ${epair_server}a inet proto tcp tagged sometag keep state" \ 735 "pass out on ${epair_tester}b inet proto tcp tagged sometag keep state" 736 737 # Test the outbound NAT part of BINAT. 738 ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201 739 740 states=$(mktemp) || exit 1 741 jexec router pfctl -qvss | normalize_pfctl_s > $states 742 743 for state_regexp in \ 744 "${epair_tester}b tcp ${net_server_host_server}:9 <- ${net_tester_host_tester}:4201 .* 3:2 pkts,.* rule 3" \ 745 "${epair_server}a tcp ${net_server_host_router}:4201 \(${net_tester_host_tester}:4201\) -> ${net_server_host_server}:9 .* 3:2 pkts,.* rule 4" \ 746 ; do 747 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 748 done 749 750 # Test the inbound RDR part of BINAT. 751 # The "tester" becomes "server" and vice versa. 752 inetd_conf=$(mktemp) 753 echo "discard stream tcp nowait root internal" > $inetd_conf 754 inetd -p ${PWD}/inetd_tester.pid $inetd_conf 755 756 atf_check -s exit:0 \ 757 jexec server ${common_dir}/pft_ping.py \ 758 --ping-type=tcp3way --send-sport=4202 \ 759 --sendif ${epair_server}b \ 760 --to ${net_server_host_router} \ 761 --replyif ${epair_server}b 762 763 states=$(mktemp) || exit 1 764 jexec router pfctl -qvss | normalize_pfctl_s > $states 765 766 for state_regexp in \ 767 "${epair_server}a tcp ${net_tester_host_tester}:9 \(${net_server_host_router}:9\) <- ${net_server_host_server}:4202 .* 3:2 pkts,.* rule 5" \ 768 "${epair_tester}b tcp ${net_server_host_server}:4202 -> ${net_tester_host_tester}:9 .* 3:2 pkts,.* rule 6" \ 769 ; do 770 grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" 771 done 772} 773 774binat_match_cleanup() 775{ 776 pft_cleanup 777 kill $(cat ${PWD}/inetd_tester.pid) 778} 779 780atf_init_test_cases() 781{ 782 atf_add_test_case "exhaust" 783 atf_add_test_case "nested_anchor" 784 atf_add_test_case "endpoint_independent_compat" 785 atf_add_test_case "endpoint_independent_pass" 786 atf_add_test_case "nat6_nolinklocal" 787 atf_add_test_case "empty_table_source_hash" 788 atf_add_test_case "no_addrs_source_hash" 789 atf_add_test_case "empty_table_random" 790 atf_add_test_case "no_addrs_random" 791 atf_add_test_case "map_e_compat" 792 atf_add_test_case "map_e_pass" 793 atf_add_test_case "nat_pass" 794 atf_add_test_case "nat_match" 795 atf_add_test_case "binat_compat" 796 atf_add_test_case "binat_match" 797} 798