aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/net/unicast_extensions.sh
blob: f52aa5f7da524098b3314a38b1a9b48117f5cd83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# By Seth Schoen (c) 2021, for the IPv4 Unicast Extensions Project
# Thanks to David Ahern for help and advice on nettest modifications.
#
# Self-tests for IPv4 address extensions: the kernel's ability to accept
# certain traditionally unused or unallocated IPv4 addresses. For each kind
# of address, we test for interface assignment, ping, TCP, and forwarding.
# Must be run as root (to manipulate network namespaces and virtual
# interfaces).
#
# Things we test for here:
#
# * Currently the kernel accepts addresses in 0/8 and 240/4 as valid.
#
# * Notwithstanding that, 0.0.0.0 and 255.255.255.255 cannot be assigned.
#
# * Currently the kernel DOES NOT accept unicast use of the lowest
#   address in an IPv4 subnet (e.g. 192.168.100.0/32 in 192.168.100.0/24).
#   This is treated as a second broadcast address, for compatibility
#   with 4.2BSD (!).
#
# * Currently the kernel DOES NOT accept unicast use of any of 127/8.
#
# * Currently the kernel DOES NOT accept unicast use of any of 224/4.
#
# These tests provide an easy way to flip the expected result of any
# of these behaviors for testing kernel patches that change them.

source lib.sh

# nettest can be run from PATH or from same directory as this selftest
if ! which nettest >/dev/null; then
	PATH=$PWD:$PATH
	if ! which nettest >/dev/null; then
		echo "'nettest' command not found; skipping tests"
		exit $ksft_skip
	fi
fi

result=0

hide_output(){ exec 3>&1 4>&2 >/dev/null 2>/dev/null; }
show_output(){ exec >&3 2>&4; }

show_result(){
	if [ $1 -eq 0 ]; then
		printf "TEST: %-60s  [ OK ]\n" "${2}"
	else
		printf "TEST: %-60s  [FAIL]\n" "${2}"
		result=1
	fi
}

_do_segmenttest(){
	# Perform a simple set of link tests between a pair of
	# IP addresses on a shared (virtual) segment, using
	# ping and nettest.
	# foo --- bar
	# Arguments: ip_a ip_b prefix_length test_description
	#
	# Caller must set up $foo_ns and $bar_ns namespaces
	# containing linked veth devices foo and bar,
	# respectively.

	ip -n $foo_ns address add $1/$3 dev foo || return 1
	ip -n $foo_ns link set foo up || return 1
	ip -n $bar_ns address add $2/$3 dev bar || return 1
	ip -n $bar_ns link set bar up || return 1

	ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1
	ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1

	nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1
	nettest -B -N $foo_ns -O $bar_ns -r $2 || return 1

	return 0
}

_do_route_test(){
	# Perform a simple set of gateway tests.
	#
	# [foo] <---> [foo1]-[bar1] <---> [bar]   /prefix
	#  host          gateway          host
	#
	# Arguments: foo_ip foo1_ip bar1_ip bar_ip prefix_len test_description
	# Displays test result and returns success or failure.

	# Caller must set up $foo_ns, $bar_ns, and $router_ns
	# containing linked veth devices foo-foo1, bar1-bar
	# (foo in $foo_ns, foo1 and bar1 in $router_ns, and
	# bar in $bar_ns).

	ip -n $foo_ns address add $1/$5 dev foo || return 1
	ip -n $foo_ns link set foo up || return 1
	ip -n $foo_ns route add default via $2 || return 1
	ip -n $bar_ns address add $4/$5 dev bar || return 1
	ip -n $bar_ns link set bar up || return 1
	ip -n $bar_ns route add default via $3 || return 1
	ip -n $router_ns address add $2/$5 dev foo1 || return 1
	ip -n $router_ns link set foo1 up || return 1
	ip -n $router_ns address add $3/$5 dev bar1 || return 1
	ip -n $router_ns link set bar1 up || return 1

	echo 1 | ip netns exec $router_ns tee /proc/sys/net/ipv4/ip_forward

	ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1
	ip netns exec $foo_ns timeout 2 ping -c 1 $4 || return 1
	ip netns exec $bar_ns timeout 2 ping -c 1 $3 || return 1
	ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1

	nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1
	nettest -B -N $foo_ns -O $bar_ns -r $4 || return 1

	return 0
}

segmenttest(){
	# Sets up veth link and tries to connect over it.
	# Arguments: ip_a ip_b prefix_len test_description
	hide_output
	setup_ns foo_ns bar_ns
	ip link add foo netns $foo_ns type veth peer name bar netns $bar_ns

	test_result=0
	_do_segmenttest "$@" || test_result=1

	ip netns pids $foo_ns | xargs -r kill -9
	ip netns pids $bar_ns | xargs -r kill -9
	cleanup_ns $foo_ns $bar_ns
	show_output

	# inverted tests will expect failure instead of success
	[ -n "$expect_failure" ] && test_result=`expr 1 - $test_result`

	show_result $test_result "$4"
}

route_test(){
	# Sets up a simple gateway and tries to connect through it.
	# [foo] <---> [foo1]-[bar1] <---> [bar]   /prefix
	# Arguments: foo_ip foo1_ip bar1_ip bar_ip prefix_len test_description
	# Returns success or failure.

	hide_output
	setup_ns foo_ns bar_ns router_ns
	ip link add foo netns $foo_ns type veth peer name foo1 netns $router_ns
	ip link add bar netns $bar_ns type veth peer name bar1 netns $router_ns

	test_result=0
	_do_route_test "$@" || test_result=1

	ip netns pids $foo_ns | xargs -r kill -9
	ip netns pids $bar_ns | xargs -r kill -9
	ip netns pids $router_ns | xargs -r kill -9
	cleanup_ns $foo_ns $bar_ns $router_ns

	show_output

	# inverted tests will expect failure instead of success
	[ -n "$expect_failure" ] && test_result=`expr 1 - $test_result`
	show_result $test_result "$6"
}

echo "###########################################################################"
echo "Unicast address extensions tests (behavior of reserved IPv4 addresses)"
echo "###########################################################################"
#
# Test support for 240/4
segmenttest 240.1.2.1   240.1.2.4    24 "assign and ping within 240/4 (1 of 2) (is allowed)"
segmenttest 250.100.2.1 250.100.30.4 16 "assign and ping within 240/4 (2 of 2) (is allowed)"
#
# Test support for 0/8
segmenttest 0.1.2.17    0.1.2.23  24 "assign and ping within 0/8 (1 of 2) (is allowed)"
segmenttest 0.77.240.17 0.77.2.23 16 "assign and ping within 0/8 (2 of 2) (is allowed)"
#
# Even 255.255/16 is OK!
segmenttest 255.255.3.1 255.255.50.77 16 "assign and ping inside 255.255/16 (is allowed)"
#
# Or 255.255.255/24
segmenttest 255.255.255.1 255.255.255.254 24 "assign and ping inside 255.255.255/24 (is allowed)"
#
# Routing between different networks
route_test 240.5.6.7 240.5.6.1  255.1.2.1    255.1.2.3      24 "route between 240.5.6/24 and 255.1.2/24 (is allowed)"
route_test 0.200.6.7 0.200.38.1 245.99.101.1 245.99.200.111 16 "route between 0.200/16 and 245.99/16 (is allowed)"
#
# Test support for lowest address ending in .0
segmenttest 5.10.15.20 5.10.15.0 24 "assign and ping lowest address (/24)"
#
# Test support for lowest address not ending in .0
segmenttest 192.168.101.192 192.168.101.193 26 "assign and ping lowest address (/26)"
#
# Routing using lowest address as a gateway/endpoint
route_test 192.168.42.1 192.168.42.0 9.8.7.6 9.8.7.0 24 "routing using lowest address"
#
# ==============================================
# ==== TESTS THAT CURRENTLY EXPECT FAILURE =====
# ==============================================
expect_failure=true
# It should still not be possible to use 0.0.0.0 or 255.255.255.255
# as a unicast address.  Thus, these tests expect failure.
segmenttest 0.0.1.5       0.0.0.0         16 "assigning 0.0.0.0 (is forbidden)"
segmenttest 255.255.255.1 255.255.255.255 16 "assigning 255.255.255.255 (is forbidden)"
#
# Test support for not having all of 127 be loopback
# Currently Linux does not allow this, so this should fail too
segmenttest 127.99.4.5 127.99.4.6 16 "assign and ping inside 127/8 (is forbidden)"
#
# Test support for unicast use of class D
# Currently Linux does not allow this, so this should fail too
segmenttest 225.1.2.3 225.1.2.200 24 "assign and ping class D address (is forbidden)"
#
# Routing using class D as a gateway
route_test 225.1.42.1 225.1.42.2 9.8.7.6 9.8.7.1 24 "routing using class D (is forbidden)"
#
# Routing using 127/8
# Currently Linux does not allow this, so this should fail too
route_test 127.99.2.3 127.99.2.4 200.1.2.3 200.1.2.4 24 "routing using 127/8 (is forbidden)"
#
unset expect_failure
# =====================================================
# ==== END OF TESTS THAT CURRENTLY EXPECT FAILURE =====
# =====================================================
exit ${result}