1# $FreeBSD$ 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2021 Rubicon Communications, LLC (Netgate) 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27 28. $(atf_get_srcdir)/utils.subr 29. $(atf_get_srcdir)/runner.subr 30 31interface_removal_head() 32{ 33 atf_set descr 'Test removing interfaces with dummynet delayed traffic' 34 atf_set require.user root 35} 36 37interface_removal_body() 38{ 39 fw=$1 40 firewall_init $fw 41 dummynet_init $fw 42 43 epair=$(vnet_mkepair) 44 vnet_mkjail alcatraz ${epair}b 45 46 ifconfig ${epair}a 192.0.2.1/24 up 47 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 48 49 # Sanity check 50 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 51 52 jexec alcatraz dnctl pipe 1 config delay 1500 53 54 firewall_config alcatraz ${fw} \ 55 "ipfw" \ 56 "ipfw add 1000 pipe 1 ip from any to any" \ 57 "pf" \ 58 "pass on ${epair}b dnpipe 1" 59 60 # single ping succeeds just fine 61 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 62 63 # Send traffic that'll still be pending when we remove the interface 64 ping -c 5 -s 1200 192.0.2.2 & 65 sleep 1 # Give ping the chance to start. 66 67 # Remove the interface, but keep the jail around for a bit 68 ifconfig ${epair}a destroy 69 70 sleep 3 71} 72 73interface_removal_cleanup() 74{ 75 firewall_cleanup $1 76} 77 78pipe_head() 79{ 80 atf_set descr 'Basic pipe test' 81 atf_set require.user root 82} 83 84pipe_body() 85{ 86 fw=$1 87 firewall_init $fw 88 dummynet_init $fw 89 90 epair=$(vnet_mkepair) 91 vnet_mkjail alcatraz ${epair}b 92 93 ifconfig ${epair}a 192.0.2.1/24 up 94 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 95 96 # Sanity check 97 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 98 99 jexec alcatraz dnctl pipe 1 config bw 30Byte/s 100 101 firewall_config alcatraz ${fw} \ 102 "ipfw" \ 103 "ipfw add 1000 pipe 1 ip from any to any" \ 104 "pf" \ 105 "pass on ${epair}b dnpipe 1" 106 107 # single ping succeeds just fine 108 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 109 110 # Saturate the link 111 ping -i .1 -c 5 -s 1200 192.0.2.2 112 113 # We should now be hitting the limits and get this packet dropped. 114 atf_check -s exit:2 -o ignore ping -c 1 -s 1200 192.0.2.2 115} 116 117pipe_cleanup() 118{ 119 firewall_cleanup $1 120} 121 122pipe_v6_head() 123{ 124 atf_set descr 'Basic IPv6 pipe test' 125 atf_set require.user root 126} 127 128pipe_v6_body() 129{ 130 fw=$1 131 firewall_init $fw 132 dummynet_init $fw 133 134 epair=$(vnet_mkepair) 135 vnet_mkjail alcatraz ${epair}b 136 137 ifconfig ${epair}a inet6 2001:db8:42::1/64 up no_dad 138 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2/64 up no_dad 139 140 # Sanity check 141 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 142 143 jexec alcatraz dnctl pipe 1 config bw 100Byte/s 144 145 firewall_config alcatraz ${fw} \ 146 "ipfw" \ 147 "ipfw add 1000 pipe 1 ip6 from any to any" \ 148 "pf" \ 149 "pass on ${epair}b dnpipe 1" 150 151 # Single ping succeeds 152 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 153 154 # Saturate the link 155 ping6 -i .1 -c 5 -s 1200 2001:db8:42::2 156 157 # We should now be hitting the limit and get this packet dropped. 158 atf_check -s exit:2 -o ignore ping6 -c 1 -s 1200 2001:db8:42::2 159} 160 161pipe_v6_cleanup() 162{ 163 firewall_cleanup $1 164} 165 166codel_head() 167{ 168 atf_set descr 'FQ_CODEL basic test' 169 atf_set require.user root 170} 171 172codel_body() 173{ 174 fw=$1 175 firewall_init $fw 176 dummynet_init $fw 177 178 epair=$(vnet_mkepair) 179 vnet_mkjail alcatraz ${epair}b 180 181 ifconfig ${epair}a 192.0.2.1/24 up 182 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 183 184 # Sanity check 185 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 186 187 jexec alcatraz dnctl pipe 1 config bw 10Mb queue 100 droptail 188 jexec alcatraz dnctl sched 1 config pipe 1 type fq_codel target 0ms interval 0ms quantum 1514 limit 10240 flows 1024 ecn 189 jexec alcatraz dnctl queue 1 config pipe 1 droptail 190 191 firewall_config alcatraz ${fw} \ 192 "ipfw" \ 193 "ipfw add 1000 queue 1 ip from any to any" \ 194 "pf" \ 195 "pass dnqueue 1" 196 197 # single ping succeeds just fine 198 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 199} 200 201codel_cleanup() 202{ 203 firewall_cleanup $1 204} 205 206wf2q_heap_head() 207{ 208 atf_set descr 'Test WF2Q+, attempting to provoke use-after-free' 209 atf_set require.user root 210} 211 212wf2q_heap_body() 213{ 214 fw=$1 215 firewall_init $fw 216 dummynet_init $fw 217 218 j=dummynet_wf2q_heap_${fw}_ 219 220 epair=$(vnet_mkepair) 221 epair_other=$(vnet_mkepair) 222 vnet_mkjail ${j}a ${epair}a 223 vnet_mkjail ${j}b ${epair}b ${epair_other}b 224 225 jexec ${j}a ifconfig ${epair}a up mtu 9000 226 va=$(jexec ${j}a ifconfig vlan create vlan 42 vlandev ${epair}a) 227 jexec ${j}a ifconfig ${va} 192.0.2.1/24 up #mtu 8000 228 229 jexec ${j}b ifconfig ${epair}b up mtu 9000 230 vb=$(jexec ${j}b ifconfig vlan create vlan 42 vlandev ${epair}b) 231 jexec ${j}b ifconfig ${vb} 192.0.2.2/24 up #mtu 8000 232 jexec ${j}b ifconfig ${epair_other}b up 233 234 # Sanity check 235 atf_check -s exit:0 -o ignore \ 236 jexec ${j}b ping -c 1 192.0.2.1 237 238 jexec ${j}b dnctl pipe 1 config bw 10Mb queue 100 delay 500 droptail 239 jexec ${j}b dnctl sched 1 config pipe 1 type wf2q+ 240 jexec ${j}b dnctl queue 1 config pipe 1 droptail 241 242 firewall_config ${j}b ${fw} \ 243 "pf" \ 244 "pass dnqueue 1" 245 246 jexec ${j}a ping -f 192.0.2.2 & 247 sleep 1 248 249 jexec ${j}b ifconfig ${vb} destroy 250 251 sleep 2 252} 253 254wf2q_heap_cleanup() 255{ 256 firewall_cleanup $1 257} 258 259queue_head() 260{ 261 atf_set descr 'Basic queue test' 262 atf_set require.user root 263} 264 265queue_body() 266{ 267 fw=$1 268 269 if [ $fw = "ipfw" ] && [ "$(atf_config_get ci false)" = "true" ]; then 270 atf_skip "https://bugs.freebsd.org/264805" 271 fi 272 273 firewall_init $fw 274 dummynet_init $fw 275 276 epair=$(vnet_mkepair) 277 vnet_mkjail alcatraz ${epair}b 278 279 ifconfig ${epair}a 192.0.2.1/24 up 280 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 281 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 282 $(atf_get_srcdir)/../pf/echo_inetd.conf 283 284 # Sanity check 285 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 286 reply=$(echo "foo" | nc -N 192.0.2.2 7) 287 if [ "$reply" != "foo" ]; 288 then 289 atf_fail "Echo sanity check failed" 290 fi 291 292 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 293 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 294 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 295 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 296 297 firewall_config alcatraz ${fw} \ 298 "ipfw" \ 299 "ipfw add 1000 queue 100 tcp from 192.0.2.2 to any out" \ 300 "ipfw add 1001 queue 200 icmp from 192.0.2.2 to any out" \ 301 "ipfw add 1002 allow ip from any to any" \ 302 "pf" \ 303 "pass in proto tcp dnqueue (0, 100)" \ 304 "pass in proto icmp dnqueue (0, 200)" 305 306 # Single ping succeeds 307 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 308 309 # Unsaturated TCP succeeds 310 reply=$(echo "foo" | nc -w 5 -N 192.0.2.2 7) 311 if [ "$reply" != "foo" ]; 312 then 313 atf_fail "Unsaturated echo failed" 314 fi 315 316 # Saturate the link 317 ping -f -s 1300 192.0.2.2 & 318 319 # Allow this to fill the queue 320 sleep 1 321 322 # TCP should still just pass 323 fails=0 324 for i in `seq 1 3` 325 do 326 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 327 if [ $result -ne 2048000 ]; 328 then 329 echo "Failed to prioritise TCP traffic. Got only $result bytes" 330 fails=$(( ${fails} + 1 )) 331 fi 332 done 333 if [ ${fails} -gt 0 ]; 334 then 335 atf_fail "We failed prioritisation ${fails} times" 336 fi 337 338 # This will fail if we reverse the pola^W priority 339 firewall_config alcatraz ${fw} \ 340 "ipfw" \ 341 "ipfw add 1000 queue 200 tcp from 192.0.2.2 to any out" \ 342 "ipfw add 1001 queue 100 icmp from 192.0.2.2 to any out" \ 343 "ipfw add 1002 allow ip from any to any" \ 344 "pf" \ 345 "pass in proto tcp dnqueue (0, 200)" \ 346 "pass in proto icmp dnqueue (0, 100)" 347 348 jexec alcatraz ping -f -s 1300 192.0.2.1 & 349 sleep 1 350 351 fails=0 352 for i in `seq 1 3` 353 do 354 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 355 if [ $result -ne 2048000 ]; 356 then 357 echo "Failed to prioritise TCP traffic. Got only $result bytes" 358 fails=$(( ${fails} + 1 )) 359 fi 360 done 361 if [ ${fails} -lt 3 ]; 362 then 363 atf_fail "We failed reversed prioritisation only ${fails} times." 364 fi 365} 366 367queue_cleanup() 368{ 369 firewall_cleanup $1 370} 371 372queue_v6_head() 373{ 374 atf_set descr 'Basic queue test' 375 atf_set require.user root 376} 377 378queue_v6_body() 379{ 380 fw=$1 381 firewall_init $fw 382 dummynet_init $fw 383 384 epair=$(vnet_mkepair) 385 vnet_mkjail alcatraz ${epair}b 386 387 ifconfig ${epair}a inet6 2001:db8:42::1/64 no_dad up 388 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2 no_dad up 389 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 390 $(atf_get_srcdir)/../pf/echo_inetd.conf 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 3` 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 0 ]; 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 3` 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 521setup_tests \ 522 interface_removal \ 523 ipfw \ 524 pf \ 525 pipe \ 526 ipfw \ 527 pf \ 528 pipe_v6 \ 529 ipfw \ 530 pf \ 531 codel \ 532 ipfw \ 533 pf \ 534 wf2q_heap \ 535 pf \ 536 queue \ 537 ipfw \ 538 pf \ 539 queue_v6 \ 540 ipfw \ 541 pf \ 542 nat \ 543 pf 544