1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Check xfrm policy resolution.  Topology:
5#
6# 1.2   1.1   3.1  3.10    2.1   2.2
7# eth1  eth1 veth0 veth0 eth1   eth1
8# ns1 ---- ns3 ----- ns4 ---- ns2
9#
10# ns3 and ns4 are connected via ipsec tunnel.
11# pings from ns1 to ns2 (and vice versa) are supposed to work like this:
12# ns1: ping 10.0.2.2: passes via ipsec tunnel.
13# ns2: ping 10.0.1.2: passes via ipsec tunnel.
14
15# ns1: ping 10.0.1.253: passes via ipsec tunnel (direct policy)
16# ns2: ping 10.0.2.253: passes via ipsec tunnel (direct policy)
17#
18# ns1: ping 10.0.2.254: does NOT pass via ipsec tunnel (exception)
19# ns2: ping 10.0.1.254: does NOT pass via ipsec tunnel (exception)
20
21# Kselftest framework requirement - SKIP code is 4.
22ksft_skip=4
23ret=0
24policy_checks_ok=1
25
26KEY_SHA=0xdeadbeef1234567890abcdefabcdefabcdefabcd
27KEY_AES=0x0123456789abcdef0123456789012345
28SPI1=0x1
29SPI2=0x2
30
31do_esp() {
32    local ns=$1
33    local me=$2
34    local remote=$3
35    local lnet=$4
36    local rnet=$5
37    local spi_out=$6
38    local spi_in=$7
39
40    ip -net $ns xfrm state add src $remote dst $me proto esp spi $spi_in  enc aes $KEY_AES  auth sha1 $KEY_SHA  mode tunnel sel src $rnet dst $lnet
41    ip -net $ns xfrm state add src $me  dst $remote proto esp spi $spi_out enc aes $KEY_AES auth sha1 $KEY_SHA mode tunnel sel src $lnet dst $rnet
42
43    # to encrypt packets as they go out (includes forwarded packets that need encapsulation)
44    ip -net $ns xfrm policy add src $lnet dst $rnet dir out tmpl src $me dst $remote proto esp mode tunnel priority 100 action allow
45    # to fwd decrypted packets after esp processing:
46    ip -net $ns xfrm policy add src $rnet dst $lnet dir fwd tmpl src $remote dst $me proto esp mode tunnel priority 100 action allow
47}
48
49do_esp_policy_get_check() {
50    local ns=$1
51    local lnet=$2
52    local rnet=$3
53
54    ip -net $ns xfrm policy get src $lnet dst $rnet dir out > /dev/null
55    if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then
56        policy_checks_ok=0
57        echo "FAIL: ip -net $ns xfrm policy get src $lnet dst $rnet dir out"
58        ret=1
59    fi
60
61    ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd > /dev/null
62    if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then
63        policy_checks_ok=0
64        echo "FAIL: ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd"
65        ret=1
66    fi
67}
68
69do_exception() {
70    local ns=$1
71    local me=$2
72    local remote=$3
73    local encryptip=$4
74    local plain=$5
75
76    # network $plain passes without tunnel
77    ip -net $ns xfrm policy add dst $plain dir out priority 10 action allow
78
79    # direct policy for $encryptip, use tunnel, higher prio takes precedence
80    ip -net $ns xfrm policy add dst $encryptip dir out tmpl src $me dst $remote proto esp mode tunnel priority 1 action allow
81}
82
83# policies that are not supposed to match any packets generated in this test.
84do_dummies4() {
85    local ns=$1
86
87    for i in $(seq 10 16);do
88      # dummy policy with wildcard src/dst.
89      echo netns exec $ns ip xfrm policy add src 0.0.0.0/0 dst 10.$i.99.0/30 dir out action block
90      echo netns exec $ns ip xfrm policy add src 10.$i.99.0/30 dst 0.0.0.0/0 dir out action block
91      for j in $(seq 32 64);do
92        echo netns exec $ns ip xfrm policy add src 10.$i.1.0/30 dst 10.$i.$j.0/30 dir out action block
93        # silly, as it encompasses the one above too, but its allowed:
94        echo netns exec $ns ip xfrm policy add src 10.$i.1.0/29 dst 10.$i.$j.0/29 dir out action block
95        # and yet again, even more broad one.
96        echo netns exec $ns ip xfrm policy add src 10.$i.1.0/24 dst 10.$i.$j.0/24 dir out action block
97        echo netns exec $ns ip xfrm policy add src 10.$i.$j.0/24 dst 10.$i.1.0/24 dir fwd action block
98      done
99    done | ip -batch /dev/stdin
100}
101
102do_dummies6() {
103    local ns=$1
104
105    for i in $(seq 10 16);do
106      for j in $(seq 32 64);do
107       echo netns exec $ns ip xfrm policy add src dead:$i::/64 dst dead:$i:$j::/64 dir out action block
108       echo netns exec $ns ip xfrm policy add src dead:$i:$j::/64 dst dead:$i::/24 dir fwd action block
109      done
110    done | ip -batch /dev/stdin
111}
112
113check_ipt_policy_count()
114{
115	ns=$1
116
117	ip netns exec $ns iptables-save -c |grep policy | ( read c rest
118		ip netns exec $ns iptables -Z
119		if [ x"$c" = x'[0:0]' ]; then
120			exit 0
121		elif [ x"$c" = x ]; then
122			echo "ERROR: No counters"
123			ret=1
124			exit 111
125		else
126			exit 1
127		fi
128	)
129}
130
131check_xfrm() {
132	# 0: iptables -m policy rule count == 0
133	# 1: iptables -m policy rule count != 0
134	rval=$1
135	ip=$2
136	lret=0
137
138	ip netns exec ns1 ping -q -c 1 10.0.2.$ip > /dev/null
139
140	check_ipt_policy_count ns3
141	if [ $? -ne $rval ] ; then
142		lret=1
143	fi
144	check_ipt_policy_count ns4
145	if [ $? -ne $rval ] ; then
146		lret=1
147	fi
148
149	ip netns exec ns2 ping -q -c 1 10.0.1.$ip > /dev/null
150
151	check_ipt_policy_count ns3
152	if [ $? -ne $rval ] ; then
153		lret=1
154	fi
155	check_ipt_policy_count ns4
156	if [ $? -ne $rval ] ; then
157		lret=1
158	fi
159
160	return $lret
161}
162
163#check for needed privileges
164if [ "$(id -u)" -ne 0 ];then
165	echo "SKIP: Need root privileges"
166	exit $ksft_skip
167fi
168
169ip -Version 2>/dev/null >/dev/null
170if [ $? -ne 0 ];then
171	echo "SKIP: Could not run test without the ip tool"
172	exit $ksft_skip
173fi
174
175# needed to check if policy lookup got valid ipsec result
176iptables --version 2>/dev/null >/dev/null
177if [ $? -ne 0 ];then
178	echo "SKIP: Could not run test without iptables tool"
179	exit $ksft_skip
180fi
181
182for i in 1 2 3 4; do
183    ip netns add ns$i
184    ip -net ns$i link set lo up
185done
186
187DEV=veth0
188ip link add $DEV netns ns1 type veth peer name eth1 netns ns3
189ip link add $DEV netns ns2 type veth peer name eth1 netns ns4
190
191ip link add $DEV netns ns3 type veth peer name veth0 netns ns4
192
193DEV=veth0
194for i in 1 2; do
195    ip -net ns$i link set $DEV up
196    ip -net ns$i addr add 10.0.$i.2/24 dev $DEV
197    ip -net ns$i addr add dead:$i::2/64 dev $DEV
198
199    ip -net ns$i addr add 10.0.$i.253 dev $DEV
200    ip -net ns$i addr add 10.0.$i.254 dev $DEV
201    ip -net ns$i addr add dead:$i::fd dev $DEV
202    ip -net ns$i addr add dead:$i::fe dev $DEV
203done
204
205for i in 3 4; do
206ip -net ns$i link set eth1 up
207ip -net ns$i link set veth0 up
208done
209
210ip -net ns1 route add default via 10.0.1.1
211ip -net ns2 route add default via 10.0.2.1
212
213ip -net ns3 addr add 10.0.1.1/24 dev eth1
214ip -net ns3 addr add 10.0.3.1/24 dev veth0
215ip -net ns3 addr add 2001:1::1/64 dev eth1
216ip -net ns3 addr add 2001:3::1/64 dev veth0
217
218ip -net ns3 route add default via 10.0.3.10
219
220ip -net ns4 addr add 10.0.2.1/24 dev eth1
221ip -net ns4 addr add 10.0.3.10/24 dev veth0
222ip -net ns4 addr add 2001:2::1/64 dev eth1
223ip -net ns4 addr add 2001:3::10/64 dev veth0
224ip -net ns4 route add default via 10.0.3.1
225
226for j in 4 6; do
227	for i in 3 4;do
228		ip netns exec ns$i sysctl net.ipv$j.conf.eth1.forwarding=1 > /dev/null
229		ip netns exec ns$i sysctl net.ipv$j.conf.veth0.forwarding=1 > /dev/null
230	done
231done
232
233# abuse iptables rule counter to check if ping matches a policy
234ip netns exec ns3 iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec
235ip netns exec ns4 iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec
236if [ $? -ne 0 ];then
237	echo "SKIP: Could not insert iptables rule"
238	for i in 1 2 3 4;do ip netns del ns$i;done
239	exit $ksft_skip
240fi
241
242#          localip  remoteip  localnet    remotenet
243do_esp ns3 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
244do_esp ns3 dead:3::1 dead:3::10 dead:1::/64 dead:2::/64 $SPI1 $SPI2
245do_esp ns4 10.0.3.10 10.0.3.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
246do_esp ns4 dead:3::10 dead:3::1 dead:2::/64 dead:1::/64 $SPI2 $SPI1
247
248do_dummies4 ns3
249do_dummies6 ns4
250
251do_esp_policy_get_check ns3 10.0.1.0/24 10.0.2.0/24
252do_esp_policy_get_check ns4 10.0.2.0/24 10.0.1.0/24
253do_esp_policy_get_check ns3 dead:1::/64 dead:2::/64
254do_esp_policy_get_check ns4 dead:2::/64 dead:1::/64
255
256# ping to .254 should use ipsec, exception is not installed.
257check_xfrm 1 254
258if [ $? -ne 0 ]; then
259	echo "FAIL: expected ping to .254 to use ipsec tunnel"
260	ret=1
261else
262	echo "PASS: policy before exception matches"
263fi
264
265# installs exceptions
266#                localip  remoteip   encryptdst  plaindst
267do_exception ns3 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28
268do_exception ns4 10.0.3.10 10.0.3.1 10.0.1.253 10.0.1.240/28
269
270do_exception ns3 dead:3::1 dead:3::10 dead:2::fd  dead:2:f0::/96
271do_exception ns4 dead:3::10 dead:3::1 dead:1::fd  dead:1:f0::/96
272
273# ping to .254 should now be excluded from the tunnel
274check_xfrm 0 254
275if [ $? -ne 0 ]; then
276	echo "FAIL: expected ping to .254 to fail"
277	ret=1
278else
279	echo "PASS: ping to .254 bypassed ipsec tunnel"
280fi
281
282# ping to .253 should use use ipsec due to direct policy exception.
283check_xfrm 1 253
284if [ $? -ne 0 ]; then
285	echo "FAIL: expected ping to .253 to use ipsec tunnel"
286	ret=1
287else
288	echo "PASS: direct policy matches"
289fi
290
291# ping to .2 should use ipsec.
292check_xfrm 1 2
293if [ $? -ne 0 ]; then
294	echo "FAIL: expected ping to .2 to use ipsec tunnel"
295	ret=1
296else
297	echo "PASS: policy matches"
298fi
299
300for i in 1 2 3 4;do ip netns del ns$i;done
301
302exit $ret
303