1# 2# Copyright (c) 2014 Spectra Logic Corporation 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions, and the following disclaimer, 10# without modification. 11# 2. Redistributions in binary form must reproduce at minimum a disclaimer 12# substantially similar to the "NO WARRANTY" disclaimer below 13# ("Disclaimer") and any redistribution must be conditioned upon 14# including a substantially similar Disclaimer requirement for further 15# binary redistribution. 16# 17# NO WARRANTY 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22# HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28# POSSIBILITY OF SUCH DAMAGES. 29# 30# Authors: Alan Somers (Spectra Logic Corporation) 31# 32# $FreeBSD$ 33 34# All of the tests in this file requires the test-suite config variable "fibs" 35# to be defined to a space-delimited list of FIBs that may be used for testing. 36 37# arpresolve should check the interface fib for routes to a target when 38# creating an ARP table entry. This is a regression for kern/167947, where 39# arpresolve only checked the default route. 40# 41# Outline: 42# Create two tap(4) interfaces 43# Simulate a crossover cable between them by using net/socat 44# Use nping (from security/nmap) to send an ICMP echo request from one 45# interface to the other, spoofing the source IP. The source IP must be 46# spoofed, or else it will already have an entry in the arp table. 47# Check whether an arp entry exists for the spoofed IP 48atf_test_case arpresolve_checks_interface_fib cleanup 49arpresolve_checks_interface_fib_head() 50{ 51 atf_set "descr" "arpresolve should check the interface fib, not the default fib, for routes" 52 atf_set "require.user" "root" 53 atf_set "require.config" "fibs" 54 atf_set "require.progs" "socat nping" 55} 56arpresolve_checks_interface_fib_body() 57{ 58 # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses 59 # and a non-default fib 60 ADDR0="192.0.2.2" 61 ADDR1="192.0.2.3" 62 SUBNET="192.0.2.0" 63 # Due to bug TBD (regressed by multiple_fibs_on_same_subnet) we need 64 # diffferent subnet masks, or FIB1 won't have a subnet route. 65 MASK0="24" 66 MASK1="25" 67 # Spoof a MAC that is reserved per RFC7042 68 SPOOF_ADDR="192.0.2.4" 69 SPOOF_MAC="00:00:5E:00:53:00" 70 71 # Check system configuration 72 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then 73 atf_skip "This test requires net.add_addr_allfibs=0" 74 fi 75 get_fibs 2 76 77 # Configure TAP interfaces 78 setup_tap "$FIB0" ${ADDR0} ${MASK0} 79 TAP0=$TAP 80 setup_tap "$FIB1" ${ADDR1} ${MASK1} 81 TAP1=$TAP 82 83 # Simulate a crossover cable 84 socat /dev/${TAP0} /dev/${TAP1} & 85 SOCAT_PID=$! 86 echo ${SOCAT_PID} >> "processes_to_kill" 87 88 # Send an ICMP echo request with a spoofed source IP 89 setfib 2 nping -c 1 -e ${TAP0} -S ${SPOOF_ADDR} \ 90 --source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \ 91 --icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \ 92 ${ADDR1} 93 # For informational and debugging purposes only, look for the 94 # characteristic error message 95 dmesg | grep "llinfo.*${SPOOF_ADDR}" 96 # Check that the ARP entry exists 97 atf_check -o match:"${SPOOF_ADDR}.*expires" setfib 3 arp ${SPOOF_ADDR} 98} 99arpresolve_checks_interface_fib_cleanup() 100{ 101 if [ -f processes_to_kill ]; then 102 for pid in $(cat processes_to_kill); do 103 kill "${pid}" 104 done 105 rm -f processes_to_kill 106 fi 107 cleanup_tap 108} 109 110 111# Regression test for kern/187549 112atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup 113loopback_and_network_routes_on_nondefault_fib_head() 114{ 115 atf_set "descr" "When creating and deleting loopback routes, use the interface's fib" 116 atf_set "require.user" "root" 117 atf_set "require.config" "fibs" 118} 119 120loopback_and_network_routes_on_nondefault_fib_body() 121{ 122 # Configure the TAP interface to use an RFC5737 nonrouteable address 123 # and a non-default fib 124 ADDR="192.0.2.2" 125 SUBNET="192.0.2.0" 126 MASK="24" 127 128 # Check system configuration 129 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then 130 atf_skip "This test requires net.add_addr_allfibs=0" 131 fi 132 get_fibs 1 133 134 # Configure a TAP interface 135 setup_tap ${FIB0} ${ADDR} ${MASK} 136 137 # Check whether the host route exists in only the correct FIB 138 setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0" 139 if [ 0 -ne $? ]; then 140 setfib ${FIB0} netstat -rn -f inet 141 atf_fail "Host route did not appear in the correct FIB" 142 fi 143 setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0" 144 if [ 0 -eq $? ]; then 145 setfib 0 netstat -rn -f inet 146 atf_fail "Host route appeared in the wrong FIB" 147 fi 148 149 # Check whether the network route exists in only the correct FIB 150 setfib ${FIB0} netstat -rn -f inet | \ 151 grep -q "^${SUBNET}/${MASK}.*${TAPD}" 152 if [ 0 -ne $? ]; then 153 setfib ${FIB0} netstat -rn -f inet 154 atf_fail "Network route did not appear in the correct FIB" 155 fi 156 setfib 0 netstat -rn -f inet | \ 157 grep -q "^${SUBNET}/${MASK}.*${TAPD}" 158 if [ 0 -eq $? ]; then 159 setfib ${FIB0} netstat -rn -f inet 160 atf_fail "Network route appeared in the wrong FIB" 161 fi 162} 163 164loopback_and_network_routes_on_nondefault_fib_cleanup() 165{ 166 cleanup_tap 167} 168 169 170# Regression test for kern/187552 171atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup 172default_route_with_multiple_fibs_on_same_subnet_head() 173{ 174 atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default routes" 175 atf_set "require.user" "root" 176 atf_set "require.config" "fibs" 177} 178 179default_route_with_multiple_fibs_on_same_subnet_body() 180{ 181 # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses 182 # and a non-default fib 183 ADDR0="192.0.2.2" 184 ADDR1="192.0.2.3" 185 GATEWAY="192.0.2.1" 186 SUBNET="192.0.2.0" 187 MASK="24" 188 189 # Check system configuration 190 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then 191 atf_skip "This test requires net.add_addr_allfibs=0" 192 fi 193 get_fibs 2 194 195 # Configure TAP interfaces 196 setup_tap "$FIB0" ${ADDR0} ${MASK} 197 TAP0=$TAP 198 setup_tap "$FIB1" ${ADDR1} ${MASK} 199 TAP1=$TAP 200 201 # Attempt to add default routes 202 setfib ${FIB0} route add default ${GATEWAY} 203 setfib ${FIB1} route add default ${GATEWAY} 204 205 # Verify that the default route exists for both fibs, with their 206 # respective interfaces. 207 atf_check -o match:"^default.*${TAP0}$" \ 208 setfib ${FIB0} netstat -rn -f inet 209 atf_check -o match:"^default.*${TAP1}$" \ 210 setfib ${FIB1} netstat -rn -f inet 211} 212 213default_route_with_multiple_fibs_on_same_subnet_cleanup() 214{ 215 cleanup_tap 216} 217 218 219# Regression test for PR kern/189089 220# Create two tap interfaces and assign them both the same IP address but with 221# different netmasks, and both on the default FIB. Then remove one's IP 222# address. Hopefully the machine won't panic. 223atf_test_case same_ip_multiple_ifaces_fib0 cleanup 224same_ip_multiple_ifaces_fib0_head() 225{ 226 atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface." 227 atf_set "require.user" "root" 228 atf_set "require.config" "fibs" 229} 230same_ip_multiple_ifaces_fib0_body() 231{ 232 ADDR="192.0.2.2" 233 MASK0="24" 234 MASK1="32" 235 236 # Unlike most of the tests in this file, this is applicable regardless 237 # of net.add_addr_allfibs 238 239 # Setup the interfaces, then remove one alias. It should not panic. 240 setup_tap 0 ${ADDR} ${MASK0} 241 TAP0=${TAP} 242 setup_tap 0 ${ADDR} ${MASK1} 243 TAP1=${TAP} 244 ifconfig ${TAP1} -alias ${ADDR} 245 246 # Do it again, in the opposite order. It should not panic. 247 setup_tap 0 ${ADDR} ${MASK0} 248 TAP0=${TAP} 249 setup_tap 0 ${ADDR} ${MASK1} 250 TAP1=${TAP} 251 ifconfig ${TAP0} -alias ${ADDR} 252} 253same_ip_multiple_ifaces_fib0_cleanup() 254{ 255 cleanup_tap 256} 257 258# Regression test for PR kern/189088 259# Test that removing an IP address works even if the same IP is assigned to a 260# different interface, on a different FIB. Tests the same code that whose 261# panic was regressed by same_ip_multiple_ifaces_fib0. 262# Create two tap interfaces and assign them both the same IP address but with 263# different netmasks, and on different FIBs. Then remove one's IP 264# address. Hopefully the machine won't panic. Also, the IP's hostroute should 265# dissappear from the correct fib. 266atf_test_case same_ip_multiple_ifaces cleanup 267same_ip_multiple_ifaces_head() 268{ 269 atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface, on non-default FIBs." 270 atf_set "require.user" "root" 271 atf_set "require.config" "fibs" 272} 273same_ip_multiple_ifaces_body() 274{ 275 atf_expect_fail "kern/189088 Assigning the same IP to multiple interfaces in different FIBs creates a host route for only one" 276 ADDR="192.0.2.2" 277 MASK0="24" 278 MASK1="32" 279 280 # Unlike most of the tests in this file, this is applicable regardless 281 # of net.add_addr_allfibs 282 get_fibs 2 283 284 # Setup the interfaces, then remove one alias. It should not panic. 285 setup_tap ${FIB0} ${ADDR} ${MASK0} 286 TAP0=${TAP} 287 setup_tap ${FIB1} ${ADDR} ${MASK1} 288 TAP1=${TAP} 289 ifconfig ${TAP1} -alias ${ADDR} 290 atf_check -o not-match:"^${ADDR}[[:space:]]" \ 291 setfib ${FIB1} netstat -rn -f inet 292 293 # Do it again, in the opposite order. It should not panic. 294 setup_tap ${FIB0} ${ADDR} ${MASK0} 295 TAP0=${TAP} 296 setup_tap ${FIB1} ${ADDR} ${MASK1} 297 TAP1=${TAP} 298 ifconfig ${TAP0} -alias ${ADDR} 299 atf_check -o not-match:"^${ADDR}[[:space:]]" \ 300 setfib ${FIB0} netstat -rn -f inet 301} 302same_ip_multiple_ifaces_cleanup() 303{ 304 # Due to PR kern/189088, we must destroy the interfaces in LIFO order 305 # in order for the routes to be correctly cleaned up. 306 for TAPD in `tail -r "tap_devices_to_cleanup"`; do 307 ifconfig ${TAPD} destroy 308 done 309} 310 311# Regression test for kern/187550 312atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup 313subnet_route_with_multiple_fibs_on_same_subnet_head() 314{ 315 atf_set "descr" "Multiple FIBs can have subnet routes for the same subnet" 316 atf_set "require.user" "root" 317 atf_set "require.config" "fibs" 318} 319 320subnet_route_with_multiple_fibs_on_same_subnet_body() 321{ 322 # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses 323 # and a non-default fib 324 ADDR0="192.0.2.2" 325 ADDR1="192.0.2.3" 326 SUBNET="192.0.2.0" 327 MASK="24" 328 329 # Check system configuration 330 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then 331 atf_skip "This test requires net.add_addr_allfibs=0" 332 fi 333 get_fibs 2 334 335 # Configure TAP interfaces 336 setup_tap "$FIB0" ${ADDR0} ${MASK} 337 setup_tap "$FIB1" ${ADDR1} ${MASK} 338 339 # Check that a subnet route exists on both fibs 340 atf_check -o ignore setfib "$FIB0" route get $ADDR1 341 atf_check -o ignore setfib "$FIB1" route get $ADDR0 342} 343 344subnet_route_with_multiple_fibs_on_same_subnet_cleanup() 345{ 346 cleanup_tap 347} 348 349# Test that source address selection works correctly for UDP packets with 350# SO_DONTROUTE set that are sent on non-default FIBs. 351# This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host" 352# Regression test for kern/187553 353# 354# The root cause was that ifa_ifwithnet() did not have a fib argument. It 355# would return an address from an interface on any FIB that had a subnet route 356# for the destination. If more than one were available, it would choose the 357# most specific. This is most easily tested by creating a FIB without a 358# default route, then trying to send a UDP packet with SO_DONTROUTE set to an 359# address which is not routable on that FIB. Absent the fix for this bug, 360# in_pcbladdr would choose an interface on any FIB with a default route. With 361# the fix, you will get EUNREACH or ENETUNREACH. 362atf_test_case udp_dontroute cleanup 363udp_dontroute_head() 364{ 365 atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works" 366 atf_set "require.user" "root" 367 atf_set "require.config" "fibs" 368} 369 370udp_dontroute_body() 371{ 372 # Configure the TAP interface to use an RFC5737 nonrouteable address 373 # and a non-default fib 374 ADDR0="192.0.2.2" 375 ADDR1="192.0.2.3" 376 SUBNET="192.0.2.0" 377 MASK="24" 378 # Use a different IP on the same subnet as the target 379 TARGET="192.0.2.100" 380 SRCDIR=`atf_get_srcdir` 381 382 # Check system configuration 383 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then 384 atf_skip "This test requires net.add_addr_allfibs=0" 385 fi 386 get_fibs 2 387 388 # Configure the TAP interfaces 389 setup_tap ${FIB0} ${ADDR0} ${MASK} 390 TARGET_TAP=${TAP} 391 setup_tap ${FIB1} ${ADDR1} ${MASK} 392 393 # Send a UDP packet with SO_DONTROUTE. In the failure case, it will 394 # return ENETUNREACH, or send the packet to the wrong tap 395 atf_check -o ignore setfib ${FIB0} \ 396 ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP} 397 cleanup_tap 398 399 # Repeat, but this time target the other tap 400 setup_tap ${FIB0} ${ADDR0} ${MASK} 401 setup_tap ${FIB1} ${ADDR1} ${MASK} 402 TARGET_TAP=${TAP} 403 404 atf_check -o ignore setfib ${FIB1} \ 405 ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP} 406} 407 408udp_dontroute_cleanup() 409{ 410 cleanup_tap 411} 412 413 414atf_init_test_cases() 415{ 416 atf_add_test_case arpresolve_checks_interface_fib 417 atf_add_test_case loopback_and_network_routes_on_nondefault_fib 418 atf_add_test_case default_route_with_multiple_fibs_on_same_subnet 419 atf_add_test_case same_ip_multiple_ifaces_fib0 420 atf_add_test_case same_ip_multiple_ifaces 421 atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet 422 atf_add_test_case udp_dontroute 423} 424 425# Looks up one or more fibs from the configuration data and validates them. 426# Returns the results in the env varilables FIB0, FIB1, etc. 427 428# parameter numfibs The number of fibs to lookup 429get_fibs() 430{ 431 NUMFIBS=$1 432 net_fibs=`sysctl -n net.fibs` 433 i=0 434 while [ $i -lt "$NUMFIBS" ]; do 435 fib=`atf_config_get "fibs" | \ 436 awk -v i=$(( i + 1 )) '{print $i}'` 437 echo "fib is ${fib}" 438 eval FIB${i}=${fib} 439 if [ "$fib" -ge "$net_fibs" ]; then 440 atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}" 441 fi 442 i=$(( $i + 1 )) 443 done 444} 445 446# Creates a new tap(4) interface, registers it for cleanup, and returns the 447# name via the environment variable TAP 448get_tap() 449{ 450 local TAPN=0 451 while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do 452 if [ "$TAPN" -ge 8 ]; then 453 atf_skip "Could not create a tap(4) interface" 454 else 455 TAPN=$(($TAPN + 1)) 456 fi 457 done 458 local TAPD=tap${TAPN} 459 # Record the TAP device so we can clean it up later 460 echo ${TAPD} >> "tap_devices_to_cleanup" 461 TAP=${TAPD} 462} 463 464# Create a tap(4) interface, configure it, and register it for cleanup. 465# parameters: 466# fib 467# IP address 468# Netmask in number of bits (eg 24 or 8) 469# Return: the tap interface name as the env variable TAP 470setup_tap() 471{ 472 local FIB=$1 473 local ADDR=$2 474 local MASK=$3 475 get_tap 476 echo setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB 477 setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB 478} 479 480cleanup_tap() 481{ 482 if [ -f tap_devices_to_cleanup ]; then 483 for tap_device in $(cat tap_devices_to_cleanup); do 484 ifconfig "${tap_device}" destroy 485 done 486 rm -f tap_devices_to_cleanup 487 fi 488} 489