1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2021 Rubicon Communications, LLC (Netgate) 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. $(atf_get_srcdir)/runner.subr 29 30interface_removal_head() 31{ 32 atf_set descr 'Test removing interfaces with dummynet delayed traffic' 33 atf_set require.user root 34} 35 36interface_removal_body() 37{ 38 fw=$1 39 firewall_init $fw 40 dummynet_init $fw 41 42 epair=$(vnet_mkepair) 43 vnet_mkjail alcatraz ${epair}b 44 45 ifconfig ${epair}a 192.0.2.1/24 up 46 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 47 48 # Sanity check 49 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 50 51 jexec alcatraz dnctl pipe 1 config delay 1500 52 53 firewall_config alcatraz ${fw} \ 54 "ipfw" \ 55 "ipfw add 1000 pipe 1 ip from any to any" \ 56 "pf" \ 57 "pass on ${epair}b dnpipe 1" 58 59 # single ping succeeds just fine 60 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 61 62 # Send traffic that'll still be pending when we remove the interface 63 ping -c 5 -s 1200 192.0.2.2 & 64 sleep 1 # Give ping the chance to start. 65 66 # Remove the interface, but keep the jail around for a bit 67 ifconfig ${epair}a destroy 68 69 sleep 3 70} 71 72interface_removal_cleanup() 73{ 74 firewall_cleanup $1 75} 76 77pipe_head() 78{ 79 atf_set descr 'Basic pipe test' 80 atf_set require.user root 81} 82 83pipe_body() 84{ 85 fw=$1 86 firewall_init $fw 87 dummynet_init $fw 88 89 epair=$(vnet_mkepair) 90 vnet_mkjail alcatraz ${epair}b 91 92 ifconfig ${epair}a 192.0.2.1/24 up 93 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 94 95 # Sanity check 96 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 97 98 jexec alcatraz dnctl pipe 1 config bw 30Byte/s 99 100 firewall_config alcatraz ${fw} \ 101 "ipfw" \ 102 "ipfw add 1000 pipe 1 ip from any to any" \ 103 "pf" \ 104 "pass on ${epair}b dnpipe 1" 105 106 # single ping succeeds just fine 107 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 108 109 # Saturate the link 110 ping -i .1 -c 5 -s 1200 192.0.2.2 111 112 # We should now be hitting the limits and get this packet dropped. 113 atf_check -s exit:2 -o ignore ping -c 1 -s 1200 192.0.2.2 114} 115 116pipe_cleanup() 117{ 118 firewall_cleanup $1 119} 120 121pipe_v6_head() 122{ 123 atf_set descr 'Basic IPv6 pipe test' 124 atf_set require.user root 125} 126 127pipe_v6_body() 128{ 129 fw=$1 130 firewall_init $fw 131 dummynet_init $fw 132 133 epair=$(vnet_mkepair) 134 vnet_mkjail alcatraz ${epair}b 135 136 ifconfig ${epair}a inet6 2001:db8:42::1/64 up no_dad 137 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2/64 up no_dad 138 139 # Sanity check 140 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 141 142 jexec alcatraz dnctl pipe 1 config bw 100Byte/s 143 144 firewall_config alcatraz ${fw} \ 145 "ipfw" \ 146 "ipfw add 1000 pipe 1 ip6 from any to any" \ 147 "pf" \ 148 "pass on ${epair}b dnpipe 1" 149 150 # Single ping succeeds 151 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 152 153 # Saturate the link 154 ping6 -i .1 -c 5 -s 1200 2001:db8:42::2 155 156 # We should now be hitting the limit and get this packet dropped. 157 atf_check -s exit:2 -o ignore ping6 -c 1 -s 1200 2001:db8:42::2 158} 159 160pipe_v6_cleanup() 161{ 162 firewall_cleanup $1 163} 164 165codel_head() 166{ 167 atf_set descr 'FQ_CODEL basic test' 168 atf_set require.user root 169} 170 171codel_body() 172{ 173 fw=$1 174 firewall_init $fw 175 dummynet_init $fw 176 177 epair=$(vnet_mkepair) 178 vnet_mkjail alcatraz ${epair}b 179 180 ifconfig ${epair}a 192.0.2.1/24 up 181 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 182 183 # Sanity check 184 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 185 186 jexec alcatraz dnctl pipe 1 config bw 10Mb queue 100 droptail 187 jexec alcatraz dnctl sched 1 config pipe 1 type fq_codel target 0ms interval 0ms quantum 1514 limit 10240 flows 1024 ecn 188 jexec alcatraz dnctl queue 1 config pipe 1 droptail 189 190 firewall_config alcatraz ${fw} \ 191 "ipfw" \ 192 "ipfw add 1000 queue 1 ip from any to any" \ 193 "pf" \ 194 "pass dnqueue 1" 195 196 # single ping succeeds just fine 197 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 198} 199 200codel_cleanup() 201{ 202 firewall_cleanup $1 203} 204 205wf2q_heap_head() 206{ 207 atf_set descr 'Test WF2Q+, attempting to provoke use-after-free' 208 atf_set require.user root 209} 210 211wf2q_heap_body() 212{ 213 fw=$1 214 firewall_init $fw 215 dummynet_init $fw 216 217 j=dummynet_wf2q_heap_${fw}_ 218 219 epair=$(vnet_mkepair) 220 epair_other=$(vnet_mkepair) 221 vnet_mkjail ${j}a ${epair}a 222 vnet_mkjail ${j}b ${epair}b ${epair_other}b 223 224 jexec ${j}a ifconfig ${epair}a up mtu 9000 225 va=$(jexec ${j}a ifconfig vlan create vlan 42 vlandev ${epair}a) 226 jexec ${j}a ifconfig ${va} 192.0.2.1/24 up #mtu 8000 227 228 jexec ${j}b ifconfig ${epair}b up mtu 9000 229 vb=$(jexec ${j}b ifconfig vlan create vlan 42 vlandev ${epair}b) 230 jexec ${j}b ifconfig ${vb} 192.0.2.2/24 up #mtu 8000 231 jexec ${j}b ifconfig ${epair_other}b up 232 233 # Sanity check 234 atf_check -s exit:0 -o ignore \ 235 jexec ${j}b ping -c 1 192.0.2.1 236 237 jexec ${j}b dnctl pipe 1 config bw 10Mb queue 100 delay 500 droptail 238 jexec ${j}b dnctl sched 1 config pipe 1 type wf2q+ 239 jexec ${j}b dnctl queue 1 config pipe 1 droptail 240 241 firewall_config ${j}b ${fw} \ 242 "pf" \ 243 "pass dnqueue 1" 244 245 jexec ${j}a ping -f 192.0.2.2 & 246 sleep 1 247 248 jexec ${j}b ifconfig ${vb} destroy 249 250 sleep 2 251} 252 253wf2q_heap_cleanup() 254{ 255 firewall_cleanup $1 256} 257 258queue_head() 259{ 260 atf_set descr 'Basic queue test' 261 atf_set require.user root 262} 263 264queue_body() 265{ 266 fw=$1 267 268 if [ $fw = "ipfw" ] && [ "$(atf_config_get ci false)" = "true" ]; then 269 atf_skip "https://bugs.freebsd.org/264805" 270 fi 271 272 firewall_init $fw 273 dummynet_init $fw 274 275 epair=$(vnet_mkepair) 276 vnet_mkjail alcatraz ${epair}b 277 278 ifconfig ${epair}a 192.0.2.1/24 up 279 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 280 jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-alcatraz.pid \ 281 $(atf_get_srcdir)/../pf/echo_inetd.conf 282 283 # Sanity check 284 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 285 reply=$(echo "foo" | nc -N 192.0.2.2 7) 286 if [ "$reply" != "foo" ]; 287 then 288 atf_fail "Echo sanity check failed" 289 fi 290 291 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 292 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 293 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 294 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 295 296 firewall_config alcatraz ${fw} \ 297 "ipfw" \ 298 "ipfw add 1000 queue 100 tcp from 192.0.2.2 to any out" \ 299 "ipfw add 1001 queue 200 icmp from 192.0.2.2 to any out" \ 300 "ipfw add 1002 allow ip from any to any" \ 301 "pf" \ 302 "pass in proto tcp dnqueue (0, 100)" \ 303 "pass in proto icmp dnqueue (0, 200)" 304 305 # Single ping succeeds 306 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 307 308 # Unsaturated TCP succeeds 309 reply=$(echo "foo" | nc -w 5 -N 192.0.2.2 7) 310 if [ "$reply" != "foo" ]; 311 then 312 atf_fail "Unsaturated echo failed" 313 fi 314 315 # Saturate the link 316 ping -f -s 1300 192.0.2.2 & 317 318 # Allow this to fill the queue 319 sleep 1 320 321 # TCP should still just pass 322 fails=0 323 for i in `seq 1 5` 324 do 325 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 326 if [ $result -ne 2048000 ]; 327 then 328 echo "Failed to prioritise TCP traffic. Got only $result bytes" 329 fails=$(( ${fails} + 1 )) 330 fi 331 done 332 if [ ${fails} -gt 2 ]; 333 then 334 atf_fail "We failed prioritisation ${fails} times" 335 fi 336 337 # This will fail if we reverse the pola^W priority 338 firewall_config alcatraz ${fw} \ 339 "ipfw" \ 340 "ipfw add 1000 queue 200 tcp from 192.0.2.2 to any out" \ 341 "ipfw add 1001 queue 100 icmp from 192.0.2.2 to any out" \ 342 "ipfw add 1002 allow ip from any to any" \ 343 "pf" \ 344 "pass in proto tcp dnqueue (0, 200)" \ 345 "pass in proto icmp dnqueue (0, 100)" 346 347 jexec alcatraz ping -f -s 1300 192.0.2.1 & 348 sleep 1 349 350 fails=0 351 for i in `seq 1 5` 352 do 353 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 354 if [ $result -ne 2048000 ]; 355 then 356 echo "Failed to prioritise TCP traffic. Got only $result bytes" 357 fails=$(( ${fails} + 1 )) 358 fi 359 done 360 if [ ${fails} -lt 3 ]; 361 then 362 atf_fail "We failed reversed prioritisation only ${fails} times." 363 fi 364} 365 366queue_cleanup() 367{ 368 firewall_cleanup $1 369} 370 371queue_v6_head() 372{ 373 atf_set descr 'Basic queue test' 374 atf_set require.user root 375} 376 377queue_v6_body() 378{ 379 fw=$1 380 firewall_init $fw 381 dummynet_init $fw 382 383 epair=$(vnet_mkepair) 384 vnet_mkjail alcatraz ${epair}b 385 386 ifconfig ${epair}a inet6 2001:db8:42::1/64 no_dad up 387 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2 no_dad up 388 jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-alcatraz.pid \ 389 $(atf_get_srcdir)/../pf/echo_inetd.conf 390 jexec alcatraz sysctl net.inet6.icmp6.errppslimit=0 391 392 # Sanity check 393 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 394 reply=$(echo "foo" | nc -N 2001:db8:42::2 7) 395 if [ "$reply" != "foo" ]; 396 then 397 atf_fail "Echo sanity check failed" 398 fi 399 400 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 401 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 402 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 403 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 404 405 firewall_config alcatraz ${fw} \ 406 "ipfw" \ 407 "ipfw add 1001 queue 100 tcp from 2001:db8:42::2 to any out" \ 408 "ipfw add 1000 queue 200 ipv6-icmp from 2001:db8:42::2 to any out" \ 409 "ipfw add 1002 allow ip6 from any to any" \ 410 "pf" \ 411 "pass in proto tcp dnqueue (0, 100)" \ 412 "pass in proto icmp6 dnqueue (0, 200)" 413 414 # Single ping succeeds 415 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 416 417 # Unsaturated TCP succeeds 418 reply=$(echo "foo" | nc -w 5 -N 2001:db8:42::2 7) 419 if [ "$reply" != "foo" ]; 420 then 421 atf_fail "Unsaturated echo failed" 422 fi 423 424 # Saturate the link 425 ping6 -f -s 1200 2001:db8:42::2 & 426 427 # Allow this to fill the queue 428 sleep 1 429 430 # TCP should still just pass 431 fails=0 432 for i in `seq 1 5` 433 do 434 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 435 if [ $result -ne 1024000 ]; 436 then 437 echo "Failed to prioritise TCP traffic. Got only $result bytes" 438 fails=$(( ${fails} + 1 )) 439 fi 440 done 441 if [ ${fails} -gt 2 ]; 442 then 443 atf_fail "We failed prioritisation ${fails} times" 444 fi 445 446 # What happens if we prioritise ICMP over TCP? 447 firewall_config alcatraz ${fw} \ 448 "ipfw" \ 449 "ipfw add 1001 queue 200 tcp from 2001:db8:42::2 to any out" \ 450 "ipfw add 1000 queue 100 ipv6-icmp from 2001:db8:42::2 to any out" \ 451 "ipfw add 1002 allow ip6 from any to any" \ 452 "pf" \ 453 "pass in proto tcp dnqueue (0, 200)" \ 454 "pass in proto icmp6 dnqueue (0, 100)" 455 456 fails=0 457 for i in `seq 1 5` 458 do 459 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 460 if [ $result -ne 1024000 ]; 461 then 462 echo "Failed to prioritise TCP traffic. Got only $result bytes" 463 fails=$(( ${fails} + 1 )) 464 fi 465 done 466 if [ ${fails} -lt 3 ]; 467 then 468 atf_fail "We failed reversed prioritisation only ${fails} times." 469 fi 470} 471 472queue_v6_cleanup() 473{ 474 firewall_cleanup $1 475} 476 477nat_head() 478{ 479 atf_set descr 'Basic dummynet + NAT test' 480 atf_set require.user root 481} 482 483nat_body() 484{ 485 fw=$1 486 firewall_init $fw 487 dummynet_init $fw 488 nat_init $fw 489 490 epair=$(vnet_mkepair) 491 epair_two=$(vnet_mkepair) 492 493 ifconfig ${epair}a 192.0.2.2/24 up 494 route add -net 198.51.100.0/24 192.0.2.1 495 496 vnet_mkjail gw ${epair}b ${epair_two}a 497 jexec gw ifconfig ${epair}b 192.0.2.1/24 up 498 jexec gw ifconfig ${epair_two}a 198.51.100.1/24 up 499 jexec gw sysctl net.inet.ip.forwarding=1 500 501 vnet_mkjail srv ${epair_two}b 502 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 503 504 jexec gw dnctl pipe 1 config bw 300Byte/s 505 506 firewall_config gw $fw \ 507 "pf" \ 508 "nat on ${epair_two}a inet from 192.0.2.0/24 to any -> (${epair_two}a)" \ 509 "pass dnpipe 1" 510 511 # We've deliberately not set a route to 192.0.2.0/24 on srv, so the 512 # only way it can respond to this is if NAT is applied correctly. 513 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 514} 515 516nat_cleanup() 517{ 518 firewall_cleanup $1 519} 520 521pls_basic_head() 522{ 523 atf_set descr 'Basic dummynet packet loss rate test' 524 atf_set require.user root 525} 526 527pls_basic_body() 528{ 529 fw=$1 530 firewall_init $fw 531 dummynet_init $fw 532 533 epair=$(vnet_mkepair) 534 vnet_mkjail alcatraz ${epair}b 535 536 ifconfig ${epair}a 192.0.2.1/24 up 537 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 538 539 firewall_config alcatraz ${fw} \ 540 "ipfw" \ 541 "ipfw add 65432 ip from any to any" \ 542 "pf" \ 543 "pass on ${epair}b" 544 545 # Sanity check 546 atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2 547 548 jexec alcatraz dnctl pipe 1 config plr 0.1 549 550 firewall_config alcatraz ${fw} \ 551 "ipfw" \ 552 "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \ 553 "pf" \ 554 "pass on ${epair}b dnpipe 1" 555 556 # check if the expected number of pings 557 # are dropped (84 - 96 responses). 558 # repeat up to 6 times if the initial 559 # checks fail 560 atf_check -s exit:0 -o match:'100 packets transmitted, (8[4-9]|9[0-6]) packets received' -r 20:10 ping -i 0.010 -c 100 192.0.2.2 561} 562 563pls_basic_cleanup() 564{ 565 firewall_cleanup $1 566} 567 568pls_gilbert_head() 569{ 570 atf_set descr 'dummynet Gilbert-Elliott packet loss model test' 571 atf_set require.user root 572} 573 574pls_gilbert_body() 575{ 576 fw=$1 577 firewall_init $fw 578 dummynet_init $fw 579 580 epair=$(vnet_mkepair) 581 vnet_mkjail alcatraz ${epair}b 582 583 ifconfig ${epair}a 192.0.2.1/24 up 584 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 585 586 firewall_config alcatraz ${fw} \ 587 "ipfw" \ 588 "ipfw add 65432 ip from any to any" \ 589 "pf" \ 590 "pass on ${epair}b" 591 592 # Sanity check 593 atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2 594 595 jexec alcatraz dnctl pipe 1 config plr 0.01,0.1,0.8,0.2 596 597 firewall_config alcatraz ${fw} \ 598 "ipfw" \ 599 "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \ 600 "pf" \ 601 "pass on ${epair}b dnpipe 1" 602 603 # check if the expected number of pings 604 # are dropped (70 - 85 responses). 605 # repeat up to 6 times if the initial 606 # checks fail 607 atf_check -s exit:0 -o match:'100 packets transmitted, (7[0-9]|8[0-5]) packets received' -r 20:10 ping -i 0.010 -c 100 192.0.2.2 608} 609 610pls_gilbert_cleanup() 611{ 612 firewall_cleanup $1 613} 614 615 616 617setup_tests \ 618 interface_removal \ 619 ipfw \ 620 pf \ 621 pipe \ 622 ipfw \ 623 pf \ 624 pipe_v6 \ 625 ipfw \ 626 pf \ 627 codel \ 628 ipfw \ 629 pf \ 630 wf2q_heap \ 631 pf \ 632 queue \ 633 ipfw \ 634 pf \ 635 queue_v6 \ 636 ipfw \ 637 pf \ 638 nat \ 639 pf \ 640 pls_basic \ 641 ipfw \ 642 pf \ 643 pls_gilbert \ 644 ipfw \ 645 pf 646