fibs_test.sh revision 265586
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: stable/10/tests/sys/netinet/fibs_test.sh 265586 2014-05-07 18:49:25Z asomers $
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	atf_expect_fail "kern/167947 arpresolve checks only the default FIB for the interface route"
59	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
60	# and a non-default fib
61	ADDR0="192.0.2.2"
62	ADDR1="192.0.2.3"
63	SUBNET="192.0.2.0"
64	# Due to bug TBD (regressed by multiple_fibs_on_same_subnet) we need
65	# diffferent subnet masks, or FIB1 won't have a subnet route.
66	MASK0="24"
67	MASK1="25"
68	# Spoof a MAC that is reserved per RFC7042
69	SPOOF_ADDR="192.0.2.4"
70	SPOOF_MAC="00:00:5E:00:53:00"
71
72	# Check system configuration
73	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
74		atf_skip "This test requires net.add_addr_allfibs=0"
75	fi
76	get_fibs 2
77
78	# Configure TAP interfaces
79	setup_tap "$FIB0" ${ADDR0} ${MASK0}
80	TAP0=$TAP
81	setup_tap "$FIB1" ${ADDR1} ${MASK1}
82	TAP1=$TAP
83
84	# Simulate a crossover cable
85	socat /dev/${TAP0} /dev/${TAP1} &
86	SOCAT_PID=$!
87	echo ${SOCAT_PID} >> "processes_to_kill"
88
89	# Send an ICMP echo request with a spoofed source IP
90	setfib 2 nping -c 1 -e ${TAP0} -S ${SPOOF_ADDR} \
91		--source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \
92		--icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \
93		${ADDR1}
94	# For informational and debugging purposes only, look for the
95	# characteristic error message
96	dmesg | grep "llinfo.*${SPOOF_ADDR}"
97	# Check that the ARP entry exists
98	atf_check -o match:"${SPOOF_ADDR}.*expires" setfib 3 arp ${SPOOF_ADDR}
99}
100arpresolve_checks_interface_fib_cleanup()
101{
102	for PID in `cat "processes_to_kill"`; do
103		kill $PID
104	done
105	cleanup_tap
106}
107
108
109# Regression test for kern/187549
110atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
111loopback_and_network_routes_on_nondefault_fib_head()
112{
113	atf_set "descr" "When creating and deleting loopback routes, use the interface's fib"
114	atf_set "require.user" "root"
115	atf_set "require.config" "fibs"
116}
117
118loopback_and_network_routes_on_nondefault_fib_body()
119{
120	atf_expect_fail "kern/187549 Host and network routes for a new interface appear in the wrong FIB"
121	# Configure the TAP interface to use an RFC5737 nonrouteable address
122	# and a non-default fib
123	ADDR="192.0.2.2"
124	SUBNET="192.0.2.0"
125	MASK="24"
126
127	# Check system configuration
128	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
129		atf_skip "This test requires net.add_addr_allfibs=0"
130	fi
131	get_fibs 1
132
133	# Configure a TAP interface
134	setup_tap ${FIB0} ${ADDR} ${MASK}
135
136	# Check whether the host route exists in only the correct FIB
137	setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
138	if [ 0 -ne $? ]; then
139		setfib ${FIB0} netstat -rn -f inet
140		atf_fail "Host route did not appear in the correct FIB"
141	fi
142	setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
143	if [ 0 -eq $? ]; then
144		setfib 0 netstat -rn -f inet
145		atf_fail "Host route appeared in the wrong FIB"
146	fi
147
148	# Check whether the network route exists in only the correct FIB
149	setfib ${FIB0} netstat -rn -f inet | \
150		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
151	if [ 0 -ne $? ]; then
152		setfib ${FIB0} netstat -rn -f inet
153		atf_fail "Network route did not appear in the correct FIB"
154	fi
155	setfib 0 netstat -rn -f inet | \
156		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
157	if [ 0 -eq $? ]; then
158		setfib ${FIB0} netstat -rn -f inet
159		atf_fail "Network route appeared in the wrong FIB"
160	fi
161}
162
163loopback_and_network_routes_on_nondefault_fib_cleanup()
164{
165	cleanup_tap
166}
167
168
169# Regression test for kern/187552
170atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
171default_route_with_multiple_fibs_on_same_subnet_head()
172{
173	atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default routes"
174	atf_set "require.user" "root"
175	atf_set "require.config" "fibs"
176}
177
178default_route_with_multiple_fibs_on_same_subnet_body()
179{
180	atf_expect_fail "kern/187552 default route uses the wrong interface when multiple interfaces have the same subnet but different fibs"
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 kern/187550
220atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
221subnet_route_with_multiple_fibs_on_same_subnet_head()
222{
223	atf_set "descr" "Multiple FIBs can have subnet routes for the same subnet"
224	atf_set "require.user" "root"
225	atf_set "require.config" "fibs"
226}
227
228subnet_route_with_multiple_fibs_on_same_subnet_body()
229{
230	atf_expect_fail "kern/187550 Multiple interfaces on different FIBs but the same subnet don't all have a subnet route"
231	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
232	# and a non-default fib
233	ADDR0="192.0.2.2"
234	ADDR1="192.0.2.3"
235	SUBNET="192.0.2.0"
236	MASK="24"
237
238	# Check system configuration
239	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
240		atf_skip "This test requires net.add_addr_allfibs=0"
241	fi
242	get_fibs 2
243
244	# Configure TAP interfaces
245	setup_tap "$FIB0" ${ADDR0} ${MASK}
246	setup_tap "$FIB1" ${ADDR1} ${MASK}
247
248	# Check that a subnet route exists on both fibs
249	atf_check -o ignore setfib "$FIB0" route get $ADDR1
250	atf_check -o ignore setfib "$FIB1" route get $ADDR0
251}
252
253subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
254{
255	cleanup_tap
256}
257
258# Test that source address selection works correctly for UDP packets with
259# SO_DONTROUTE set that are sent on non-default FIBs.
260# This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
261# Regression test for kern/187553
262atf_test_case udp_dontroute cleanup
263udp_dontroute_head()
264{
265	atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
266	atf_set "require.user" "root"
267	atf_set "require.config" "fibs"
268}
269
270udp_dontroute_body()
271{
272	atf_expect_fail "kern/187553 Source address selection for UDP packets with SO_DONTROUTE uses the default FIB"
273	# Configure the TAP interface to use an RFC5737 nonrouteable address
274	# and a non-default fib
275	ADDR="192.0.2.2"
276	SUBNET="192.0.2.0"
277	MASK="24"
278	# Use a different IP on the same subnet as the target
279	TARGET="192.0.2.100"
280
281	# Check system configuration
282	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
283		atf_skip "This test requires net.add_addr_allfibs=0"
284	fi
285	get_fibs 1
286
287	# Configure a TAP interface
288	setup_tap ${FIB0} ${ADDR} ${MASK}
289
290	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
291	# return ENETUNREACH
292	SRCDIR=`atf_get_srcdir`
293	atf_check -o ignore setfib ${FIB0} ${SRCDIR}/udp_dontroute ${TARGET}
294}
295
296udp_dontroute_cleanup()
297{
298	cleanup_tap
299}
300
301
302atf_init_test_cases()
303{
304	atf_add_test_case arpresolve_checks_interface_fib
305	atf_add_test_case loopback_and_network_routes_on_nondefault_fib
306	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
307	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
308	atf_add_test_case udp_dontroute
309}
310
311# Looks up one or more fibs from the configuration data and validates them.
312# Returns the results in the env varilables FIB0, FIB1, etc.
313
314# parameter numfibs	The number of fibs to lookup
315get_fibs()
316{
317	NUMFIBS=$1
318	net_fibs=`sysctl -n net.fibs`
319	i=0
320	while [ $i -lt "$NUMFIBS" ]; do
321		fib=`atf_config_get "fibs" | \
322			awk -v i=$(( i + 1 )) '{print $i}'`
323		echo "fib is ${fib}"
324		eval FIB${i}=${fib}
325		if [ "$fib" -ge "$net_fibs" ]; then
326			atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
327		fi
328		i=$(( $i + 1 ))
329	done
330}
331
332# Creates a new tap(4) interface, registers it for cleanup, and returns the
333# name via the environment variable TAP
334get_tap()
335{
336	local TAPN=0
337	while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do
338		if [ "$TAPN" -ge 8 ]; then
339			atf_skip "Could not create a tap(4) interface"
340		else
341			TAPN=$(($TAPN + 1))
342		fi
343	done
344	local TAPD=tap${TAPN}
345	# Record the TAP device so we can clean it up later
346	echo ${TAPD} >> "tap_devices_to_cleanup"
347	TAP=${TAPD}
348}
349
350# Create a tap(4) interface, configure it, and register it for cleanup.
351# parameters:
352# fib
353# IP address
354# Netmask in number of bits (eg 24 or 8)
355# Return: the tap interface name as the env variable TAP
356setup_tap()
357{
358	local FIB=$1
359	local ADDR=$2
360	local MASK=$3
361	get_tap
362	echo setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
363	setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
364}
365
366cleanup_tap()
367{
368	for TAPD in `cat "tap_devices_to_cleanup"`; do
369		ifconfig ${TAPD} destroy
370	done
371}
372