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 31pipe_head() 32{ 33 atf_set descr 'Basic pipe test' 34 atf_set require.user root 35} 36 37pipe_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 bw 30Byte/s 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 # Saturate the link 64 ping -i .1 -c 5 -s 1200 192.0.2.2 65 66 # We should now be hitting the limits and get this packet dropped. 67 atf_check -s exit:2 -o ignore ping -c 1 -s 1200 192.0.2.2 68} 69 70pipe_cleanup() 71{ 72 firewall_cleanup $1 73} 74 75pipe_v6_head() 76{ 77 atf_set descr 'Basic IPv6 pipe test' 78 atf_set require.user root 79} 80 81pipe_v6_body() 82{ 83 fw=$1 84 firewall_init $fw 85 dummynet_init $fw 86 87 epair=$(vnet_mkepair) 88 vnet_mkjail alcatraz ${epair}b 89 90 ifconfig ${epair}a inet6 2001:db8:42::1/64 up no_dad 91 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2/64 up no_dad 92 93 # Sanity check 94 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 95 96 jexec alcatraz dnctl pipe 1 config bw 100Byte/s 97 98 firewall_config alcatraz ${fw} \ 99 "ipfw" \ 100 "ipfw add 1000 pipe 1 ip6 from any to any" \ 101 "pf" \ 102 "pass dnpipe 1" 103 104 # Single ping succeeds 105 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 106 107 # Saturate the link 108 ping6 -i .1 -c 5 -s 1200 2001:db8:42::2 109 110 # We should now be hitting the limit and get this packet dropped. 111 atf_check -s exit:2 -o ignore ping6 -c 1 -s 1200 2001:db8:42::2 112} 113 114pipe_v6_cleanup() 115{ 116 firewall_cleanup $1 117} 118 119queue_head() 120{ 121 atf_set descr 'Basic queue test' 122 atf_set require.user root 123} 124 125queue_body() 126{ 127 fw=$1 128 firewall_init $fw 129 dummynet_init $fw 130 131 epair=$(vnet_mkepair) 132 vnet_mkjail alcatraz ${epair}b 133 134 ifconfig ${epair}a 192.0.2.1/24 up 135 jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up 136 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 137 $(atf_get_srcdir)/../pf/echo_inetd.conf 138 139 # Sanity check 140 atf_check -s exit:0 -o ignore ping -i .1 -c 3 -s 1200 192.0.2.2 141 reply=$(echo "foo" | nc -N 192.0.2.2 7) 142 if [ "$reply" != "foo" ]; 143 then 144 atf_fail "Echo sanity check failed" 145 fi 146 147 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 148 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 149 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 150 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 151 152 firewall_config alcatraz ${fw} \ 153 "ipfw" \ 154 "ipfw add 1000 queue 100 tcp from 192.0.2.2 to any out" \ 155 "ipfw add 1001 queue 200 icmp from 192.0.2.2 to any out" \ 156 "ipfw add 1002 allow ip from any to any" \ 157 "pf" \ 158 "pass in proto tcp dnqueue (0, 100)" \ 159 "pass in proto icmp dnqueue (0, 200)" 160 161 # Single ping succeeds 162 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 163 164 # Unsaturated TCP succeeds 165 reply=$(echo "foo" | nc -w 5 -N 192.0.2.2 7) 166 if [ "$reply" != "foo" ]; 167 then 168 atf_fail "Unsaturated echo failed" 169 fi 170 171 # Saturate the link 172 ping -f -s 1300 192.0.2.2 & 173 174 # Allow this to fill the queue 175 sleep 1 176 177 # TCP should still just pass 178 fails=0 179 for i in `seq 1 3` 180 do 181 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 182 if [ $result -ne 2048000 ]; 183 then 184 echo "Failed to prioritise TCP traffic. Got only $result bytes" 185 fails=$(( ${fails} + 1 )) 186 fi 187 done 188 if [ ${fails} -gt 0 ]; 189 then 190 atf_fail "We failed prioritisation ${fails} times" 191 fi 192 193 # This will fail if we reverse the pola^W priority 194 firewall_config alcatraz ${fw} \ 195 "ipfw" \ 196 "ipfw add 1000 queue 200 tcp from 192.0.2.2 to any out" \ 197 "ipfw add 1001 queue 100 icmp from 192.0.2.2 to any out" \ 198 "ipfw add 1002 allow ip from any to any" \ 199 "pf" \ 200 "pass in proto tcp dnqueue (0, 200)" \ 201 "pass in proto icmp dnqueue (0, 100)" 202 203 jexec alcatraz ping -f -s 1300 192.0.2.1 & 204 sleep 1 205 206 fails=0 207 for i in `seq 1 3` 208 do 209 result=$(dd if=/dev/zero bs=1024 count=2000 | timeout 3 nc -w 5 -N 192.0.2.2 7 | wc -c) 210 if [ $result -ne 2048000 ]; 211 then 212 echo "Failed to prioritise TCP traffic. Got only $result bytes" 213 fails=$(( ${fails} + 1 )) 214 fi 215 done 216 if [ ${fails} -lt 3 ]; 217 then 218 atf_fail "We failed reversed prioritisation only ${fails} times." 219 fi 220} 221 222queue_cleanup() 223{ 224 firewall_cleanup $1 225} 226 227queue_v6_head() 228{ 229 atf_set descr 'Basic queue test' 230 atf_set require.user root 231} 232 233queue_v6_body() 234{ 235 fw=$1 236 firewall_init $fw 237 dummynet_init $fw 238 239 epair=$(vnet_mkepair) 240 vnet_mkjail alcatraz ${epair}b 241 242 ifconfig ${epair}a inet6 2001:db8:42::1/64 no_dad up 243 jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2 no_dad up 244 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 245 $(atf_get_srcdir)/../pf/echo_inetd.conf 246 247 # Sanity check 248 atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2 249 reply=$(echo "foo" | nc -N 2001:db8:42::2 7) 250 if [ "$reply" != "foo" ]; 251 then 252 atf_fail "Echo sanity check failed" 253 fi 254 255 jexec alcatraz dnctl pipe 1 config bw 1MByte/s 256 jexec alcatraz dnctl sched 1 config pipe 1 type wf2q+ 257 jexec alcatraz dnctl queue 100 config sched 1 weight 99 mask all 258 jexec alcatraz dnctl queue 200 config sched 1 weight 1 mask all 259 260 firewall_config alcatraz ${fw} \ 261 "ipfw" \ 262 "ipfw add 1001 queue 100 tcp from 2001:db8:42::2 to any out" \ 263 "ipfw add 1000 queue 200 ipv6-icmp from 2001:db8:42::2 to any out" \ 264 "ipfw add 1002 allow ip6 from any to any" \ 265 "pf" \ 266 "pass in proto tcp dnqueue (0, 100)" \ 267 "pass in proto icmp6 dnqueue (0, 200)" 268 269 # Single ping succeeds 270 atf_check -s exit:0 -o ignore ping6 -c 1 2001:db8:42::2 271 272 # Unsaturated TCP succeeds 273 reply=$(echo "foo" | nc -w 5 -N 2001:db8:42::2 7) 274 if [ "$reply" != "foo" ]; 275 then 276 atf_fail "Unsaturated echo failed" 277 fi 278 279 # Saturate the link 280 ping6 -f -s 1200 2001:db8:42::2 & 281 282 # Allow this to fill the queue 283 sleep 1 284 285 # TCP should still just pass 286 fails=0 287 for i in `seq 1 3` 288 do 289 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 290 if [ $result -ne 1024000 ]; 291 then 292 echo "Failed to prioritise TCP traffic. Got only $result bytes" 293 fails=$(( ${fails} + 1 )) 294 fi 295 done 296 if [ ${fails} -gt 0 ]; 297 then 298 atf_fail "We failed prioritisation ${fails} times" 299 fi 300 301 # What happens if we prioritise ICMP over TCP? 302 firewall_config alcatraz ${fw} \ 303 "ipfw" \ 304 "ipfw add 1001 queue 200 tcp from 2001:db8:42::2 to any out" \ 305 "ipfw add 1000 queue 100 ipv6-icmp from 2001:db8:42::2 to any out" \ 306 "ipfw add 1002 allow ip6 from any to any" \ 307 "pf" \ 308 "pass in proto tcp dnqueue (0, 200)" \ 309 "pass in proto icmp6 dnqueue (0, 100)" 310 311 fails=0 312 for i in `seq 1 3` 313 do 314 result=$(dd if=/dev/zero bs=1024 count=1000 | timeout 3 nc -w 5 -N 2001:db8:42::2 7 | wc -c) 315 if [ $result -ne 1024000 ]; 316 then 317 echo "Failed to prioritise TCP traffic. Got only $result bytes" 318 fails=$(( ${fails} + 1 )) 319 fi 320 done 321 if [ ${fails} -lt 3 ]; 322 then 323 atf_fail "We failed reversed prioritisation only ${fails} times." 324 fi 325} 326 327queue_v6_cleanup() 328{ 329 firewall_cleanup $1 330} 331 332nat_head() 333{ 334 atf_set descr 'Basic dummynet + NAT test' 335 atf_set require.user root 336} 337 338nat_body() 339{ 340 fw=$1 341 firewall_init $fw 342 dummynet_init $fw 343 nat_init $fw 344 345 epair=$(vnet_mkepair) 346 epair_two=$(vnet_mkepair) 347 348 ifconfig ${epair}a 192.0.2.2/24 up 349 route add -net 198.51.100.0/24 192.0.2.1 350 351 vnet_mkjail gw ${epair}b ${epair_two}a 352 jexec gw ifconfig ${epair}b 192.0.2.1/24 up 353 jexec gw ifconfig ${epair_two}a 198.51.100.1/24 up 354 jexec gw sysctl net.inet.ip.forwarding=1 355 356 vnet_mkjail srv ${epair_two}b 357 jexec srv ifconfig ${epair_two}b 198.51.100.2/24 up 358 359 jexec gw dnctl pipe 1 config bw 300Byte/s 360 361 firewall_config gw $fw \ 362 "pf" \ 363 "nat on ${epair_two}a inet from 192.0.2.0/24 to any -> (${epair_two}a)" \ 364 "pass dnpipe 1" 365 366 # We've deliberately not set a route to 192.0.2.0/24 on srv, so the 367 # only way it can respond to this is if NAT is applied correctly. 368 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 369} 370 371nat_cleanup() 372{ 373 firewall_cleanup $1 374} 375 376setup_tests \ 377 pipe \ 378 ipfw \ 379 pf \ 380 pipe_v6 \ 381 ipfw \ 382 pf \ 383 queue \ 384 ipfw \ 385 pf \ 386 queue_v6 \ 387 ipfw \ 388 pf \ 389 nat \ 390 pf 391