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