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 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
|
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Check xfrm policy resolution. Topology:
#
# 1.2 1.1 3.1 3.10 2.1 2.2
# eth1 eth1 veth0 veth0 eth1 eth1
# ns1 ---- ns3 ----- ns4 ---- ns2
#
# ns3 and ns4 are connected via ipsec tunnel.
# pings from ns1 to ns2 (and vice versa) are supposed to work like this:
# ns1: ping 10.0.2.2: passes via ipsec tunnel.
# ns2: ping 10.0.1.2: passes via ipsec tunnel.
# ns1: ping 10.0.1.253: passes via ipsec tunnel (direct policy)
# ns2: ping 10.0.2.253: passes via ipsec tunnel (direct policy)
#
# ns1: ping 10.0.2.254: does NOT pass via ipsec tunnel (exception)
# ns2: ping 10.0.1.254: does NOT pass via ipsec tunnel (exception)
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
ret=0
policy_checks_ok=1
KEY_SHA=0xdeadbeef1234567890abcdefabcdefabcdefabcd
KEY_AES=0x0123456789abcdef0123456789012345
SPI1=0x1
SPI2=0x2
do_esp_policy() {
local ns=$1
local me=$2
local remote=$3
local lnet=$4
local rnet=$5
# to encrypt packets as they go out (includes forwarded packets that need encapsulation)
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
# to fwd decrypted packets after esp processing:
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
}
do_esp() {
local ns=$1
local me=$2
local remote=$3
local lnet=$4
local rnet=$5
local spi_out=$6
local spi_in=$7
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
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
do_esp_policy $ns $me $remote $lnet $rnet
}
# add policies with different netmasks, to make sure kernel carries
# the policies contained within new netmask over when search tree is
# re-built.
# peer netns that are supposed to be encapsulated via esp have addresses
# in the 10.0.1.0/24 and 10.0.2.0/24 subnets, respectively.
#
# Adding a policy for '10.0.1.0/23' will make it necessary to
# alter the prefix of 10.0.1.0 subnet.
# In case new prefix overlaps with existing node, the node and all
# policies it carries need to be merged with the existing one(s).
#
# Do that here.
do_overlap()
{
local ns=$1
# adds new nodes to tree (neither network exists yet in policy database).
ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block
# adds a new node in the 10.0.0.0/24 tree (dst node exists).
ip -net $ns xfrm policy add src 10.2.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block
# adds a 10.2.0.0/23 node, but for different dst.
ip -net $ns xfrm policy add src 10.2.0.0/23 dst 10.0.1.0/24 dir fwd priority 200 action block
# dst now overlaps with the 10.0.1.0/24 ESP policy in fwd.
# kernel must 'promote' existing one (10.0.0.0/24) to 10.0.0.0/23.
# But 10.0.0.0/23 also includes existing 10.0.1.0/24, so that node
# also has to be merged too, including source-sorted subtrees.
# old:
# 10.0.0.0/24 (node 1 in dst tree of the bin)
# 10.1.0.0/24 (node in src tree of dst node 1)
# 10.2.0.0/24 (node in src tree of dst node 1)
# 10.0.1.0/24 (node 2 in dst tree of the bin)
# 10.0.2.0/24 (node in src tree of dst node 2)
# 10.2.0.0/24 (node in src tree of dst node 2)
#
# The next 'policy add' adds dst '10.0.0.0/23', which means
# that dst node 1 and dst node 2 have to be merged including
# the sub-tree. As no duplicates are allowed, policies in
# the two '10.0.2.0/24' are also merged.
#
# after the 'add', internal search tree should look like this:
# 10.0.0.0/23 (node in dst tree of bin)
# 10.0.2.0/24 (node in src tree of dst node)
# 10.1.0.0/24 (node in src tree of dst node)
# 10.2.0.0/24 (node in src tree of dst node)
#
# 10.0.0.0/24 and 10.0.1.0/24 nodes have been merged as 10.0.0.0/23.
ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/23 dir fwd priority 200 action block
# similar to above: add policies (with partially random address), with shrinking prefixes.
for p in 29 28 27;do
for k in $(seq 1 32); do
ip -net $ns xfrm policy add src 10.253.1.$((RANDOM%255))/$p dst 10.254.1.$((RANDOM%255))/$p dir fwd priority $((200+k)) action block 2>/dev/null
done
done
}
do_esp_policy_get_check() {
local ns=$1
local lnet=$2
local rnet=$3
ip -net $ns xfrm policy get src $lnet dst $rnet dir out > /dev/null
if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then
policy_checks_ok=0
echo "FAIL: ip -net $ns xfrm policy get src $lnet dst $rnet dir out"
ret=1
fi
ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd > /dev/null
if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then
policy_checks_ok=0
echo "FAIL: ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd"
ret=1
fi
}
do_exception() {
local ns=$1
local me=$2
local remote=$3
local encryptip=$4
local plain=$5
# network $plain passes without tunnel
ip -net $ns xfrm policy add dst $plain dir out priority 10 action allow
# direct policy for $encryptip, use tunnel, higher prio takes precedence
ip -net $ns xfrm policy add dst $encryptip dir out tmpl src $me dst $remote proto esp mode tunnel priority 1 action allow
}
# policies that are not supposed to match any packets generated in this test.
do_dummies4() {
local ns=$1
for i in $(seq 10 16);do
# dummy policy with wildcard src/dst.
echo netns exec $ns ip xfrm policy add src 0.0.0.0/0 dst 10.$i.99.0/30 dir out action block
echo netns exec $ns ip xfrm policy add src 10.$i.99.0/30 dst 0.0.0.0/0 dir out action block
for j in $(seq 32 64);do
echo netns exec $ns ip xfrm policy add src 10.$i.1.0/30 dst 10.$i.$j.0/30 dir out action block
# silly, as it encompasses the one above too, but its allowed:
echo netns exec $ns ip xfrm policy add src 10.$i.1.0/29 dst 10.$i.$j.0/29 dir out action block
# and yet again, even more broad one.
echo netns exec $ns ip xfrm policy add src 10.$i.1.0/24 dst 10.$i.$j.0/24 dir out action block
echo netns exec $ns ip xfrm policy add src 10.$i.$j.0/24 dst 10.$i.1.0/24 dir fwd action block
done
done | ip -batch /dev/stdin
}
do_dummies6() {
local ns=$1
for i in $(seq 10 16);do
for j in $(seq 32 64);do
echo netns exec $ns ip xfrm policy add src dead:$i::/64 dst dead:$i:$j::/64 dir out action block
echo netns exec $ns ip xfrm policy add src dead:$i:$j::/64 dst dead:$i::/24 dir fwd action block
done
done | ip -batch /dev/stdin
}
check_ipt_policy_count()
{
ns=$1
ip netns exec $ns iptables-save -c |grep policy | ( read c rest
ip netns exec $ns iptables -Z
if [ x"$c" = x'[0:0]' ]; then
exit 0
elif [ x"$c" = x ]; then
echo "ERROR: No counters"
ret=1
exit 111
else
exit 1
fi
)
}
check_xfrm() {
# 0: iptables -m policy rule count == 0
# 1: iptables -m policy rule count != 0
rval=$1
ip=$2
local lret=0
ip netns exec ns1 ping -q -c 1 10.0.2.$ip > /dev/null
check_ipt_policy_count ns3
if [ $? -ne $rval ] ; then
lret=1
fi
check_ipt_policy_count ns4
if [ $? -ne $rval ] ; then
lret=1
fi
ip netns exec ns2 ping -q -c 1 10.0.1.$ip > /dev/null
check_ipt_policy_count ns3
if [ $? -ne $rval ] ; then
lret=1
fi
check_ipt_policy_count ns4
if [ $? -ne $rval ] ; then
lret=1
fi
return $lret
}
check_exceptions()
{
logpostfix="$1"
local lret=0
# ping to .254 should be excluded from the tunnel (exception is in place).
check_xfrm 0 254
if [ $? -ne 0 ]; then
echo "FAIL: expected ping to .254 to fail ($logpostfix)"
lret=1
else
echo "PASS: ping to .254 bypassed ipsec tunnel ($logpostfix)"
fi
# ping to .253 should use use ipsec due to direct policy exception.
check_xfrm 1 253
if [ $? -ne 0 ]; then
echo "FAIL: expected ping to .253 to use ipsec tunnel ($logpostfix)"
lret=1
else
echo "PASS: direct policy matches ($logpostfix)"
fi
# ping to .2 should use ipsec.
check_xfrm 1 2
if [ $? -ne 0 ]; then
echo "FAIL: expected ping to .2 to use ipsec tunnel ($logpostfix)"
lret=1
else
echo "PASS: policy matches ($logpostfix)"
fi
return $lret
}
check_hthresh_repeat()
{
local log=$1
i=0
for i in $(seq 1 10);do
ip -net ns1 xfrm policy update src e000:0001::0000 dst ff01::0014:0000:0001 dir in tmpl src :: dst :: proto esp mode tunnel priority 100 action allow || break
ip -net ns1 xfrm policy set hthresh6 0 28 || break
ip -net ns1 xfrm policy update src e000:0001::0000 dst ff01::01 dir in tmpl src :: dst :: proto esp mode tunnel priority 100 action allow || break
ip -net ns1 xfrm policy set hthresh6 0 28 || break
done
if [ $i -ne 10 ] ;then
echo "FAIL: $log" 1>&2
ret=1
return 1
fi
echo "PASS: $log"
return 0
}
# insert non-overlapping policies in a random order and check that
# all of them can be fetched using the traffic selectors.
check_random_order()
{
local ns=$1
local log=$2
for i in $(seq 100); do
ip -net $ns xfrm policy flush
for j in $(seq 0 16 255 | sort -R); do
ip -net $ns xfrm policy add dst $j.0.0.0/24 dir out priority 10 action allow
done
for j in $(seq 0 16 255); do
if ! ip -net $ns xfrm policy get dst $j.0.0.0/24 dir out > /dev/null; then
echo "FAIL: $log" 1>&2
return 1
fi
done
done
for i in $(seq 100); do
ip -net $ns xfrm policy flush
for j in $(seq 0 16 255 | sort -R); do
local addr=$(printf "e000:0000:%02x00::/56" $j)
ip -net $ns xfrm policy add dst $addr dir out priority 10 action allow
done
for j in $(seq 0 16 255); do
local addr=$(printf "e000:0000:%02x00::/56" $j)
if ! ip -net $ns xfrm policy get dst $addr dir out > /dev/null; then
echo "FAIL: $log" 1>&2
return 1
fi
done
done
ip -net $ns xfrm policy flush
echo "PASS: $log"
return 0
}
#check for needed privileges
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
exit $ksft_skip
fi
ip -Version 2>/dev/null >/dev/null
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without the ip tool"
exit $ksft_skip
fi
# needed to check if policy lookup got valid ipsec result
iptables --version 2>/dev/null >/dev/null
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without iptables tool"
exit $ksft_skip
fi
for i in 1 2 3 4; do
ip netns add ns$i
ip -net ns$i link set lo up
done
DEV=veth0
ip link add $DEV netns ns1 type veth peer name eth1 netns ns3
ip link add $DEV netns ns2 type veth peer name eth1 netns ns4
ip link add $DEV netns ns3 type veth peer name veth0 netns ns4
DEV=veth0
for i in 1 2; do
ip -net ns$i link set $DEV up
ip -net ns$i addr add 10.0.$i.2/24 dev $DEV
ip -net ns$i addr add dead:$i::2/64 dev $DEV
ip -net ns$i addr add 10.0.$i.253 dev $DEV
ip -net ns$i addr add 10.0.$i.254 dev $DEV
ip -net ns$i addr add dead:$i::fd dev $DEV
ip -net ns$i addr add dead:$i::fe dev $DEV
done
for i in 3 4; do
ip -net ns$i link set eth1 up
ip -net ns$i link set veth0 up
done
ip -net ns1 route add default via 10.0.1.1
ip -net ns2 route add default via 10.0.2.1
ip -net ns3 addr add 10.0.1.1/24 dev eth1
ip -net ns3 addr add 10.0.3.1/24 dev veth0
ip -net ns3 addr add 2001:1::1/64 dev eth1
ip -net ns3 addr add 2001:3::1/64 dev veth0
ip -net ns3 route add default via 10.0.3.10
ip -net ns4 addr add 10.0.2.1/24 dev eth1
ip -net ns4 addr add 10.0.3.10/24 dev veth0
ip -net ns4 addr add 2001:2::1/64 dev eth1
ip -net ns4 addr add 2001:3::10/64 dev veth0
ip -net ns4 route add default via 10.0.3.1
for j in 4 6; do
for i in 3 4;do
ip netns exec ns$i sysctl net.ipv$j.conf.eth1.forwarding=1 > /dev/null
ip netns exec ns$i sysctl net.ipv$j.conf.veth0.forwarding=1 > /dev/null
done
done
# abuse iptables rule counter to check if ping matches a policy
ip netns exec ns3 iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec
ip netns exec ns4 iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec
if [ $? -ne 0 ];then
echo "SKIP: Could not insert iptables rule"
for i in 1 2 3 4;do ip netns del ns$i;done
exit $ksft_skip
fi
# localip remoteip localnet remotenet
do_esp ns3 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
do_esp ns3 dead:3::1 dead:3::10 dead:1::/64 dead:2::/64 $SPI1 $SPI2
do_esp ns4 10.0.3.10 10.0.3.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
do_esp ns4 dead:3::10 dead:3::1 dead:2::/64 dead:1::/64 $SPI2 $SPI1
do_dummies4 ns3
do_dummies6 ns4
do_esp_policy_get_check ns3 10.0.1.0/24 10.0.2.0/24
do_esp_policy_get_check ns4 10.0.2.0/24 10.0.1.0/24
do_esp_policy_get_check ns3 dead:1::/64 dead:2::/64
do_esp_policy_get_check ns4 dead:2::/64 dead:1::/64
# ping to .254 should use ipsec, exception is not installed.
check_xfrm 1 254
if [ $? -ne 0 ]; then
echo "FAIL: expected ping to .254 to use ipsec tunnel"
ret=1
else
echo "PASS: policy before exception matches"
fi
# installs exceptions
# localip remoteip encryptdst plaindst
do_exception ns3 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28
do_exception ns4 10.0.3.10 10.0.3.1 10.0.1.253 10.0.1.240/28
do_exception ns3 dead:3::1 dead:3::10 dead:2::fd dead:2:f0::/96
do_exception ns4 dead:3::10 dead:3::1 dead:1::fd dead:1:f0::/96
check_exceptions "exceptions"
if [ $? -ne 0 ]; then
ret=1
fi
# insert block policies with adjacent/overlapping netmasks
do_overlap ns3
check_exceptions "exceptions and block policies"
if [ $? -ne 0 ]; then
ret=1
fi
for n in ns3 ns4;do
ip -net $n xfrm policy set hthresh4 28 24 hthresh6 126 125
sleep $((RANDOM%5))
done
check_exceptions "exceptions and block policies after hresh changes"
# full flush of policy db, check everything gets freed incl. internal meta data
ip -net ns3 xfrm policy flush
do_esp_policy ns3 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24
do_exception ns3 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28
# move inexact policies to hash table
ip -net ns3 xfrm policy set hthresh4 16 16
sleep $((RANDOM%5))
check_exceptions "exceptions and block policies after hthresh change in ns3"
# restore original hthresh settings -- move policies back to tables
for n in ns3 ns4;do
ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128
sleep $((RANDOM%5))
done
check_exceptions "exceptions and block policies after htresh change to normal"
check_hthresh_repeat "policies with repeated htresh change"
check_random_order ns3 "policies inserted in random order"
for i in 1 2 3 4;do ip netns del ns$i;done
exit $ret
|