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 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 3` 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 0 ]; 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 3` 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 inetd-alcatraz.pid \ 389 $(atf_get_srcdir)/../pf/echo_inetd.conf 390 391 # Sanity check 392 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 393 reply=$(echo "foo" | nc -N 2001:db8:42::2 7) 394 if [ "$reply" != "foo" ]; 395 then 396 atf_fail "Echo sanity check failed" 397 fi 398 399 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 400 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 401 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 402 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 403 404 firewall_config alcatraz ${fw} \ 405 "ipfw" \ 406 "ipfw add 1001 queue 100 tcp from 2001:db8:42::2 to any out" \ 407 "ipfw add 1000 queue 200 ipv6-icmp from 2001:db8:42::2 to any out" \ 408 "ipfw add 1002 allow ip6 from any to any" \ 409 "pf" \ 410 "pass in proto tcp dnqueue (0, 100)" \ 411 "pass in proto icmp6 dnqueue (0, 200)" 412 413 # Single ping succeeds 414 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 415 416 # Unsaturated TCP succeeds 417 reply=$(echo "foo" | nc -w 5 -N 2001:db8:42::2 7) 418 if [ "$reply" != "foo" ]; 419 then 420 atf_fail "Unsaturated echo failed" 421 fi 422 423 # Saturate the link 424 ping6 -f -s 1200 2001:db8:42::2 & 425 426 # Allow this to fill the queue 427 sleep 1 428 429 # TCP should still just pass 430 fails=0 431 for i in `seq 1 3` 432 do 433 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 434 if [ $result -ne 1024000 ]; 435 then 436 echo "Failed to prioritise TCP traffic. Got only $result bytes" 437 fails=$(( ${fails} + 1 )) 438 fi 439 done 440 if [ ${fails} -gt 0 ]; 441 then 442 atf_fail "We failed prioritisation ${fails} times" 443 fi 444 445 # What happens if we prioritise ICMP over TCP? 446 firewall_config alcatraz ${fw} \ 447 "ipfw" \ 448 "ipfw add 1001 queue 200 tcp from 2001:db8:42::2 to any out" \ 449 "ipfw add 1000 queue 100 ipv6-icmp from 2001:db8:42::2 to any out" \ 450 "ipfw add 1002 allow ip6 from any to any" \ 451 "pf" \ 452 "pass in proto tcp dnqueue (0, 200)" \ 453 "pass in proto icmp6 dnqueue (0, 100)" 454 455 fails=0 456 for i in `seq 1 3` 457 do 458 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 459 if [ $result -ne 1024000 ]; 460 then 461 echo "Failed to prioritise TCP traffic. Got only $result bytes" 462 fails=$(( ${fails} + 1 )) 463 fi 464 done 465 if [ ${fails} -lt 3 ]; 466 then 467 atf_fail "We failed reversed prioritisation only ${fails} times." 468 fi 469} 470 471queue_v6_cleanup() 472{ 473 firewall_cleanup $1 474} 475 476nat_head() 477{ 478 atf_set descr 'Basic dummynet + NAT test' 479 atf_set require.user root 480} 481 482nat_body() 483{ 484 fw=$1 485 firewall_init $fw 486 dummynet_init $fw 487 nat_init $fw 488 489 epair=$(vnet_mkepair) 490 epair_two=$(vnet_mkepair) 491 492 ifconfig ${epair}a 192.0.2.2/24 up 493 route add -net 198.51.100.0/24 192.0.2.1 494 495 vnet_mkjail gw ${epair}b ${epair_two}a 496 jexec gw ifconfig ${epair}b 192.0.2.1/24 up 497 jexec gw ifconfig ${epair_two}a 198.51.100.1/24 up 498 jexec gw sysctl net.inet.ip.forwarding=1 499 500 vnet_mkjail srv ${epair_two}b 501 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 502 503 jexec gw dnctl pipe 1 config bw 300Byte/s 504 505 firewall_config gw $fw \ 506 "pf" \ 507 "nat on ${epair_two}a inet from 192.0.2.0/24 to any -> (${epair_two}a)" \ 508 "pass dnpipe 1" 509 510 # We've deliberately not set a route to 192.0.2.0/24 on srv, so the 511 # only way it can respond to this is if NAT is applied correctly. 512 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 513} 514 515nat_cleanup() 516{ 517 firewall_cleanup $1 518} 519 520pls_basic_head() 521{ 522 atf_set descr 'Basic dummynet packet loss rate test' 523 atf_set require.user root 524} 525 526pls_basic_body() 527{ 528 fw=$1 529 firewall_init $fw 530 dummynet_init $fw 531 532 epair=$(vnet_mkepair) 533 vnet_mkjail alcatraz ${epair}b 534 535 ifconfig ${epair}a 192.0.2.1/24 up 536 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 537 538 firewall_config alcatraz ${fw} \ 539 "ipfw" \ 540 "ipfw add 65432 ip from any to any" \ 541 "pf" \ 542 "pass on ${epair}b" 543 544 # Sanity check 545 atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2 546 547 jexec alcatraz dnctl pipe 1 config plr 0.1 548 549 firewall_config alcatraz ${fw} \ 550 "ipfw" \ 551 "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \ 552 "pf" \ 553 "pass on ${epair}b dnpipe 1" 554 555 # check if the expected number of pings 556 # are dropped (84 - 96 responses). 557 # repeat up to 6 times if the initial 558 # checks fail 559 atf_check -s exit:0 -o match:'100 packets transmitted, (8[4-9]|9[0-6]) packets received' -r 6:10 ping -i 0.010 -c 100 192.0.2.2 560} 561 562pls_basic_cleanup() 563{ 564 firewall_cleanup $1 565} 566 567pls_gilbert_head() 568{ 569 atf_set descr 'dummynet Gilbert-Elliott packet loss model test' 570 atf_set require.user root 571} 572 573pls_gilbert_body() 574{ 575 fw=$1 576 firewall_init $fw 577 dummynet_init $fw 578 579 epair=$(vnet_mkepair) 580 vnet_mkjail alcatraz ${epair}b 581 582 ifconfig ${epair}a 192.0.2.1/24 up 583 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 584 585 firewall_config alcatraz ${fw} \ 586 "ipfw" \ 587 "ipfw add 65432 ip from any to any" \ 588 "pf" \ 589 "pass on ${epair}b" 590 591 # Sanity check 592 atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2 593 594 jexec alcatraz dnctl pipe 1 config plr 0.01,0.1,0.8,0.2 595 596 firewall_config alcatraz ${fw} \ 597 "ipfw" \ 598 "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \ 599 "pf" \ 600 "pass on ${epair}b dnpipe 1" 601 602 # check if the expected number of pings 603 # are dropped (70 - 85 responses). 604 # repeat up to 6 times if the initial 605 # checks fail 606 atf_check -s exit:0 -o match:'100 packets transmitted, (7[0-9]|8[0-5]) packets received' -r 6:10 ping -i 0.010 -c 100 192.0.2.2 607} 608 609pls_gilbert_cleanup() 610{ 611 firewall_cleanup $1 612} 613 614 615 616setup_tests \ 617 interface_removal \ 618 ipfw \ 619 pf \ 620 pipe \ 621 ipfw \ 622 pf \ 623 pipe_v6 \ 624 ipfw \ 625 pf \ 626 codel \ 627 ipfw \ 628 pf \ 629 wf2q_heap \ 630 pf \ 631 queue \ 632 ipfw \ 633 pf \ 634 queue_v6 \ 635 ipfw \ 636 pf \ 637 nat \ 638 pf \ 639 pls_basic \ 640 ipfw \ 641 pf \ 642 pls_gilbert \ 643 ipfw \ 644 pf 645