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 206queue_head() 207{ 208 atf_set descr 'Basic queue test' 209 atf_set require.user root 210} 211 212queue_body() 213{ 214 fw=$1 215 216 if [ $fw = "ipfw" ] && [ "$(atf_config_get ci false)" = "true" ]; then 217 atf_skip "https://bugs.freebsd.org/264805" 218 fi 219 220 firewall_init $fw 221 dummynet_init $fw 222 223 epair=$(vnet_mkepair) 224 vnet_mkjail alcatraz ${epair}b 225 226 ifconfig ${epair}a 192.0.2.1/24 up 227 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 228 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 229 $(atf_get_srcdir)/../pf/echo_inetd.conf 230 231 # Sanity check 232 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 233 reply=$(echo "foo" | nc -N 192.0.2.2 7) 234 if [ "$reply" != "foo" ]; 235 then 236 atf_fail "Echo sanity check failed" 237 fi 238 239 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 240 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 241 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 242 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 243 244 firewall_config alcatraz ${fw} \ 245 "ipfw" \ 246 "ipfw add 1000 queue 100 tcp from 192.0.2.2 to any out" \ 247 "ipfw add 1001 queue 200 icmp from 192.0.2.2 to any out" \ 248 "ipfw add 1002 allow ip from any to any" \ 249 "pf" \ 250 "pass in proto tcp dnqueue (0, 100)" \ 251 "pass in proto icmp dnqueue (0, 200)" 252 253 # Single ping succeeds 254 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 255 256 # Unsaturated TCP succeeds 257 reply=$(echo "foo" | nc -w 5 -N 192.0.2.2 7) 258 if [ "$reply" != "foo" ]; 259 then 260 atf_fail "Unsaturated echo failed" 261 fi 262 263 # Saturate the link 264 ping -f -s 1300 192.0.2.2 & 265 266 # Allow this to fill the queue 267 sleep 1 268 269 # TCP should still just pass 270 fails=0 271 for i in `seq 1 3` 272 do 273 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 274 if [ $result -ne 2048000 ]; 275 then 276 echo "Failed to prioritise TCP traffic. Got only $result bytes" 277 fails=$(( ${fails} + 1 )) 278 fi 279 done 280 if [ ${fails} -gt 0 ]; 281 then 282 atf_fail "We failed prioritisation ${fails} times" 283 fi 284 285 # This will fail if we reverse the pola^W priority 286 firewall_config alcatraz ${fw} \ 287 "ipfw" \ 288 "ipfw add 1000 queue 200 tcp from 192.0.2.2 to any out" \ 289 "ipfw add 1001 queue 100 icmp from 192.0.2.2 to any out" \ 290 "ipfw add 1002 allow ip from any to any" \ 291 "pf" \ 292 "pass in proto tcp dnqueue (0, 200)" \ 293 "pass in proto icmp dnqueue (0, 100)" 294 295 jexec alcatraz ping -f -s 1300 192.0.2.1 & 296 sleep 1 297 298 fails=0 299 for i in `seq 1 3` 300 do 301 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 302 if [ $result -ne 2048000 ]; 303 then 304 echo "Failed to prioritise TCP traffic. Got only $result bytes" 305 fails=$(( ${fails} + 1 )) 306 fi 307 done 308 if [ ${fails} -lt 3 ]; 309 then 310 atf_fail "We failed reversed prioritisation only ${fails} times." 311 fi 312} 313 314queue_cleanup() 315{ 316 firewall_cleanup $1 317} 318 319queue_v6_head() 320{ 321 atf_set descr 'Basic queue test' 322 atf_set require.user root 323} 324 325queue_v6_body() 326{ 327 fw=$1 328 firewall_init $fw 329 dummynet_init $fw 330 331 epair=$(vnet_mkepair) 332 vnet_mkjail alcatraz ${epair}b 333 334 ifconfig ${epair}a inet6 2001:db8:42::1/64 no_dad up 335 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2 no_dad up 336 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 337 $(atf_get_srcdir)/../pf/echo_inetd.conf 338 339 # Sanity check 340 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 341 reply=$(echo "foo" | nc -N 2001:db8:42::2 7) 342 if [ "$reply" != "foo" ]; 343 then 344 atf_fail "Echo sanity check failed" 345 fi 346 347 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 348 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 349 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 350 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 351 352 firewall_config alcatraz ${fw} \ 353 "ipfw" \ 354 "ipfw add 1001 queue 100 tcp from 2001:db8:42::2 to any out" \ 355 "ipfw add 1000 queue 200 ipv6-icmp from 2001:db8:42::2 to any out" \ 356 "ipfw add 1002 allow ip6 from any to any" \ 357 "pf" \ 358 "pass in proto tcp dnqueue (0, 100)" \ 359 "pass in proto icmp6 dnqueue (0, 200)" 360 361 # Single ping succeeds 362 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 363 364 # Unsaturated TCP succeeds 365 reply=$(echo "foo" | nc -w 5 -N 2001:db8:42::2 7) 366 if [ "$reply" != "foo" ]; 367 then 368 atf_fail "Unsaturated echo failed" 369 fi 370 371 # Saturate the link 372 ping6 -f -s 1200 2001:db8:42::2 & 373 374 # Allow this to fill the queue 375 sleep 1 376 377 # TCP should still just pass 378 fails=0 379 for i in `seq 1 3` 380 do 381 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 382 if [ $result -ne 1024000 ]; 383 then 384 echo "Failed to prioritise TCP traffic. Got only $result bytes" 385 fails=$(( ${fails} + 1 )) 386 fi 387 done 388 if [ ${fails} -gt 0 ]; 389 then 390 atf_fail "We failed prioritisation ${fails} times" 391 fi 392 393 # What happens if we prioritise ICMP over TCP? 394 firewall_config alcatraz ${fw} \ 395 "ipfw" \ 396 "ipfw add 1001 queue 200 tcp from 2001:db8:42::2 to any out" \ 397 "ipfw add 1000 queue 100 ipv6-icmp from 2001:db8:42::2 to any out" \ 398 "ipfw add 1002 allow ip6 from any to any" \ 399 "pf" \ 400 "pass in proto tcp dnqueue (0, 200)" \ 401 "pass in proto icmp6 dnqueue (0, 100)" 402 403 fails=0 404 for i in `seq 1 3` 405 do 406 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 407 if [ $result -ne 1024000 ]; 408 then 409 echo "Failed to prioritise TCP traffic. Got only $result bytes" 410 fails=$(( ${fails} + 1 )) 411 fi 412 done 413 if [ ${fails} -lt 3 ]; 414 then 415 atf_fail "We failed reversed prioritisation only ${fails} times." 416 fi 417} 418 419queue_v6_cleanup() 420{ 421 firewall_cleanup $1 422} 423 424nat_head() 425{ 426 atf_set descr 'Basic dummynet + NAT test' 427 atf_set require.user root 428} 429 430nat_body() 431{ 432 fw=$1 433 firewall_init $fw 434 dummynet_init $fw 435 nat_init $fw 436 437 epair=$(vnet_mkepair) 438 epair_two=$(vnet_mkepair) 439 440 ifconfig ${epair}a 192.0.2.2/24 up 441 route add -net 198.51.100.0/24 192.0.2.1 442 443 vnet_mkjail gw ${epair}b ${epair_two}a 444 jexec gw ifconfig ${epair}b 192.0.2.1/24 up 445 jexec gw ifconfig ${epair_two}a 198.51.100.1/24 up 446 jexec gw sysctl net.inet.ip.forwarding=1 447 448 vnet_mkjail srv ${epair_two}b 449 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 450 451 jexec gw dnctl pipe 1 config bw 300Byte/s 452 453 firewall_config gw $fw \ 454 "pf" \ 455 "nat on ${epair_two}a inet from 192.0.2.0/24 to any -> (${epair_two}a)" \ 456 "pass dnpipe 1" 457 458 # We've deliberately not set a route to 192.0.2.0/24 on srv, so the 459 # only way it can respond to this is if NAT is applied correctly. 460 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 461} 462 463nat_cleanup() 464{ 465 firewall_cleanup $1 466} 467 468setup_tests \ 469 interface_removal \ 470 ipfw \ 471 pf \ 472 pipe \ 473 ipfw \ 474 pf \ 475 pipe_v6 \ 476 ipfw \ 477 pf \ 478 codel \ 479 ipfw \ 480 pf \ 481 queue \ 482 ipfw \ 483 pf \ 484 queue_v6 \ 485 ipfw \ 486 pf \ 487 nat \ 488 pf 489