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 firewall_init $fw 269 dummynet_init $fw 270 271 epair=$(vnet_mkepair) 272 vnet_mkjail alcatraz ${epair}b 273 274 ifconfig ${epair}a 192.0.2.1/24 up 275 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 276 jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-alcatraz.pid \ 277 $(atf_get_srcdir)/../pf/echo_inetd.conf 278 279 # Sanity check 280 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 281 reply=$(echo "foo" | nc -N 192.0.2.2 7) 282 if [ "$reply" != "foo" ]; 283 then 284 atf_fail "Echo sanity check failed" 285 fi 286 287 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 288 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 289 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 290 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 291 292 firewall_config alcatraz ${fw} \ 293 "ipfw" \ 294 "ipfw add 1000 queue 100 tcp from 192.0.2.2 to any out" \ 295 "ipfw add 1001 queue 200 icmp from 192.0.2.2 to any out" \ 296 "ipfw add 1002 allow ip from any to any" \ 297 "pf" \ 298 "pass in proto tcp dnqueue (0, 100)" \ 299 "pass in proto icmp dnqueue (0, 200)" 300 301 # Single ping succeeds 302 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 303 304 # Unsaturated TCP succeeds 305 reply=$(echo "foo" | nc -w 5 -N 192.0.2.2 7) 306 if [ "$reply" != "foo" ]; 307 then 308 atf_fail "Unsaturated echo failed" 309 fi 310 311 # Saturate the link 312 ping -f -s 1300 192.0.2.2 & 313 314 # Allow this to fill the queue 315 sleep 1 316 317 # TCP should still just pass 318 fails=0 319 for i in `seq 1 5` 320 do 321 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 322 if [ $result -ne 2048000 ]; 323 then 324 echo "Failed to prioritise TCP traffic. Got only $result bytes" 325 fails=$(( ${fails} + 1 )) 326 fi 327 done 328 if [ ${fails} -gt 2 ]; 329 then 330 atf_fail "We failed prioritisation ${fails} times" 331 fi 332 333 # This will fail if we reverse the pola^W priority 334 firewall_config alcatraz ${fw} \ 335 "ipfw" \ 336 "ipfw add 1000 queue 200 tcp from 192.0.2.2 to any out" \ 337 "ipfw add 1001 queue 100 icmp from 192.0.2.2 to any out" \ 338 "ipfw add 1002 allow ip from any to any" \ 339 "pf" \ 340 "pass in proto tcp dnqueue (0, 200)" \ 341 "pass in proto icmp dnqueue (0, 100)" 342 343 jexec alcatraz ping -f -s 1300 192.0.2.1 & 344 sleep 1 345 346 fails=0 347 for i in `seq 1 5` 348 do 349 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 350 if [ $result -ne 2048000 ]; 351 then 352 echo "Failed to prioritise TCP traffic. Got only $result bytes" 353 fails=$(( ${fails} + 1 )) 354 fi 355 done 356 if [ ${fails} -lt 3 ]; 357 then 358 atf_fail "We failed reversed prioritisation only ${fails} times." 359 fi 360} 361 362queue_cleanup() 363{ 364 firewall_cleanup $1 365} 366 367queue_v6_head() 368{ 369 atf_set descr 'Basic queue test' 370 atf_set require.user root 371} 372 373queue_v6_body() 374{ 375 fw=$1 376 firewall_init $fw 377 dummynet_init $fw 378 379 epair=$(vnet_mkepair) 380 vnet_mkjail alcatraz ${epair}b 381 382 ifconfig ${epair}a inet6 2001:db8:42::1/64 no_dad up 383 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2 no_dad up 384 jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-alcatraz.pid \ 385 $(atf_get_srcdir)/../pf/echo_inetd.conf 386 jexec alcatraz sysctl net.inet6.icmp6.errppslimit=0 387 388 # Sanity check 389 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 390 reply=$(echo "foo" | nc -N 2001:db8:42::2 7) 391 if [ "$reply" != "foo" ]; 392 then 393 atf_fail "Echo sanity check failed" 394 fi 395 396 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 397 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 398 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 399 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 400 401 firewall_config alcatraz ${fw} \ 402 "ipfw" \ 403 "ipfw add 1001 queue 100 tcp from 2001:db8:42::2 to any out" \ 404 "ipfw add 1000 queue 200 ipv6-icmp from 2001:db8:42::2 to any out" \ 405 "ipfw add 1002 allow ip6 from any to any" \ 406 "pf" \ 407 "pass in proto tcp dnqueue (0, 100)" \ 408 "pass in proto icmp6 dnqueue (0, 200)" 409 410 # Single ping succeeds 411 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 412 413 # Unsaturated TCP succeeds 414 reply=$(echo "foo" | nc -w 5 -N 2001:db8:42::2 7) 415 if [ "$reply" != "foo" ]; 416 then 417 atf_fail "Unsaturated echo failed" 418 fi 419 420 # Saturate the link 421 ping6 -f -s 1200 2001:db8:42::2 & 422 423 # Allow this to fill the queue 424 sleep 1 425 426 # TCP should still just pass 427 fails=0 428 for i in `seq 1 5` 429 do 430 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 431 if [ $result -ne 1024000 ]; 432 then 433 echo "Failed to prioritise TCP traffic. Got only $result bytes" 434 fails=$(( ${fails} + 1 )) 435 fi 436 done 437 if [ ${fails} -gt 2 ]; 438 then 439 atf_fail "We failed prioritisation ${fails} times" 440 fi 441 442 # What happens if we prioritise ICMP over TCP? 443 firewall_config alcatraz ${fw} \ 444 "ipfw" \ 445 "ipfw add 1001 queue 200 tcp from 2001:db8:42::2 to any out" \ 446 "ipfw add 1000 queue 100 ipv6-icmp from 2001:db8:42::2 to any out" \ 447 "ipfw add 1002 allow ip6 from any to any" \ 448 "pf" \ 449 "pass in proto tcp dnqueue (0, 200)" \ 450 "pass in proto icmp6 dnqueue (0, 100)" 451 452 fails=0 453 for i in `seq 1 5` 454 do 455 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 456 if [ $result -ne 1024000 ]; 457 then 458 echo "Failed to prioritise TCP traffic. Got only $result bytes" 459 fails=$(( ${fails} + 1 )) 460 fi 461 done 462 if [ ${fails} -lt 3 ]; 463 then 464 atf_fail "We failed reversed prioritisation only ${fails} times." 465 fi 466} 467 468queue_v6_cleanup() 469{ 470 firewall_cleanup $1 471} 472 473nat_head() 474{ 475 atf_set descr 'Basic dummynet + NAT test' 476 atf_set require.user root 477} 478 479nat_body() 480{ 481 fw=$1 482 firewall_init $fw 483 dummynet_init $fw 484 nat_init $fw 485 486 epair=$(vnet_mkepair) 487 epair_two=$(vnet_mkepair) 488 489 ifconfig ${epair}a 192.0.2.2/24 up 490 route add -net 198.51.100.0/24 192.0.2.1 491 492 vnet_mkjail gw ${epair}b ${epair_two}a 493 jexec gw ifconfig ${epair}b 192.0.2.1/24 up 494 jexec gw ifconfig ${epair_two}a 198.51.100.1/24 up 495 jexec gw sysctl net.inet.ip.forwarding=1 496 497 vnet_mkjail srv ${epair_two}b 498 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 499 500 jexec gw dnctl pipe 1 config bw 300Byte/s 501 502 firewall_config gw $fw \ 503 "pf" \ 504 "nat on ${epair_two}a inet from 192.0.2.0/24 to any -> (${epair_two}a)" \ 505 "pass dnpipe 1" 506 507 # We've deliberately not set a route to 192.0.2.0/24 on srv, so the 508 # only way it can respond to this is if NAT is applied correctly. 509 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 510} 511 512nat_cleanup() 513{ 514 firewall_cleanup $1 515} 516 517pls_basic_head() 518{ 519 atf_set descr 'Basic dummynet packet loss rate test' 520 atf_set require.user root 521} 522 523pls_basic_body() 524{ 525 fw=$1 526 firewall_init $fw 527 dummynet_init $fw 528 529 epair=$(vnet_mkepair) 530 vnet_mkjail alcatraz ${epair}b 531 532 ifconfig ${epair}a 192.0.2.1/24 up 533 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 534 535 firewall_config alcatraz ${fw} \ 536 "ipfw" \ 537 "ipfw add 65432 ip from any to any" \ 538 "pf" \ 539 "pass on ${epair}b" 540 541 # Sanity check 542 atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2 543 544 jexec alcatraz dnctl pipe 1 config plr 0.1 545 546 firewall_config alcatraz ${fw} \ 547 "ipfw" \ 548 "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \ 549 "pf" \ 550 "pass on ${epair}b dnpipe 1" 551 552 # check if the expected number of pings 553 # are dropped (84 - 96 responses). 554 # repeat up to 6 times if the initial 555 # checks fail 556 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 557} 558 559pls_basic_cleanup() 560{ 561 firewall_cleanup $1 562} 563 564pls_gilbert_head() 565{ 566 atf_set descr 'dummynet Gilbert-Elliott packet loss model test' 567 atf_set require.user root 568} 569 570pls_gilbert_body() 571{ 572 fw=$1 573 firewall_init $fw 574 dummynet_init $fw 575 576 epair=$(vnet_mkepair) 577 vnet_mkjail alcatraz ${epair}b 578 579 ifconfig ${epair}a 192.0.2.1/24 up 580 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 581 582 firewall_config alcatraz ${fw} \ 583 "ipfw" \ 584 "ipfw add 65432 ip from any to any" \ 585 "pf" \ 586 "pass on ${epair}b" 587 588 # Sanity check 589 atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2 590 591 jexec alcatraz dnctl pipe 1 config plr 0.01,0.1,0.8,0.2 592 593 firewall_config alcatraz ${fw} \ 594 "ipfw" \ 595 "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \ 596 "pf" \ 597 "pass on ${epair}b dnpipe 1" 598 599 # check if the expected number of pings 600 # are dropped (70 - 85 responses). 601 # repeat up to 6 times if the initial 602 # checks fail 603 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 604} 605 606pls_gilbert_cleanup() 607{ 608 firewall_cleanup $1 609} 610 611 612 613setup_tests \ 614 interface_removal \ 615 ipfw \ 616 pf \ 617 pipe \ 618 ipfw \ 619 pf \ 620 pipe_v6 \ 621 ipfw \ 622 pf \ 623 codel \ 624 ipfw \ 625 pf \ 626 wf2q_heap \ 627 pf \ 628 queue \ 629 ipfw \ 630 pf \ 631 queue_v6 \ 632 ipfw \ 633 pf \ 634 nat \ 635 pf \ 636 pls_basic \ 637 ipfw \ 638 pf \ 639 pls_gilbert \ 640 ipfw \ 641 pf 642