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 21source lib.sh 22ret=0 23policy_checks_ok=1 24 25KEY_SHA=0xdeadbeef1234567890abcdefabcdefabcdefabcd 26KEY_AES=0x0123456789abcdef0123456789012345 27SPI1=0x1 28SPI2=0x2 29 30do_esp_policy() { 31 local ns=$1 32 local me=$2 33 local remote=$3 34 local lnet=$4 35 local rnet=$5 36 37 # to encrypt packets as they go out (includes forwarded packets that need encapsulation) 38 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 39 # to fwd decrypted packets after esp processing: 40 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 41} 42 43do_esp() { 44 local ns=$1 45 local me=$2 46 local remote=$3 47 local lnet=$4 48 local rnet=$5 49 local spi_out=$6 50 local spi_in=$7 51 52 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 53 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 54 55 do_esp_policy $ns $me $remote $lnet $rnet 56} 57 58# add policies with different netmasks, to make sure kernel carries 59# the policies contained within new netmask over when search tree is 60# re-built. 61# peer netns that are supposed to be encapsulated via esp have addresses 62# in the 10.0.1.0/24 and 10.0.2.0/24 subnets, respectively. 63# 64# Adding a policy for '10.0.1.0/23' will make it necessary to 65# alter the prefix of 10.0.1.0 subnet. 66# In case new prefix overlaps with existing node, the node and all 67# policies it carries need to be merged with the existing one(s). 68# 69# Do that here. 70do_overlap() 71{ 72 local ns=$1 73 74 # adds new nodes to tree (neither network exists yet in policy database). 75 ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block 76 77 # adds a new node in the 10.0.0.0/24 tree (dst node exists). 78 ip -net $ns xfrm policy add src 10.2.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block 79 80 # adds a 10.2.0.0/23 node, but for different dst. 81 ip -net $ns xfrm policy add src 10.2.0.0/23 dst 10.0.1.0/24 dir fwd priority 200 action block 82 83 # dst now overlaps with the 10.0.1.0/24 ESP policy in fwd. 84 # kernel must 'promote' existing one (10.0.0.0/24) to 10.0.0.0/23. 85 # But 10.0.0.0/23 also includes existing 10.0.1.0/24, so that node 86 # also has to be merged too, including source-sorted subtrees. 87 # old: 88 # 10.0.0.0/24 (node 1 in dst tree of the bin) 89 # 10.1.0.0/24 (node in src tree of dst node 1) 90 # 10.2.0.0/24 (node in src tree of dst node 1) 91 # 10.0.1.0/24 (node 2 in dst tree of the bin) 92 # 10.0.2.0/24 (node in src tree of dst node 2) 93 # 10.2.0.0/24 (node in src tree of dst node 2) 94 # 95 # The next 'policy add' adds dst '10.0.0.0/23', which means 96 # that dst node 1 and dst node 2 have to be merged including 97 # the sub-tree. As no duplicates are allowed, policies in 98 # the two '10.0.2.0/24' are also merged. 99 # 100 # after the 'add', internal search tree should look like this: 101 # 10.0.0.0/23 (node in dst tree of bin) 102 # 10.0.2.0/24 (node in src tree of dst node) 103 # 10.1.0.0/24 (node in src tree of dst node) 104 # 10.2.0.0/24 (node in src tree of dst node) 105 # 106 # 10.0.0.0/24 and 10.0.1.0/24 nodes have been merged as 10.0.0.0/23. 107 ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/23 dir fwd priority 200 action block 108 109 # similar to above: add policies (with partially random address), with shrinking prefixes. 110 for p in 29 28 27;do 111 for k in $(seq 1 32); do 112 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 113 done 114 done 115} 116 117do_esp_policy_get_check() { 118 local ns=$1 119 local lnet=$2 120 local rnet=$3 121 122 ip -net $ns xfrm policy get src $lnet dst $rnet dir out > /dev/null 123 if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then 124 policy_checks_ok=0 125 echo "FAIL: ip -net $ns xfrm policy get src $lnet dst $rnet dir out" 126 ret=1 127 fi 128 129 ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd > /dev/null 130 if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then 131 policy_checks_ok=0 132 echo "FAIL: ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd" 133 ret=1 134 fi 135} 136 137do_exception() { 138 local ns=$1 139 local me=$2 140 local remote=$3 141 local encryptip=$4 142 local plain=$5 143 144 # network $plain passes without tunnel 145 ip -net $ns xfrm policy add dst $plain dir out priority 10 action allow 146 147 # direct policy for $encryptip, use tunnel, higher prio takes precedence 148 ip -net $ns xfrm policy add dst $encryptip dir out tmpl src $me dst $remote proto esp mode tunnel priority 1 action allow 149} 150 151# policies that are not supposed to match any packets generated in this test. 152do_dummies4() { 153 local ns=$1 154 155 for i in $(seq 10 16);do 156 # dummy policy with wildcard src/dst. 157 echo netns exec $ns ip xfrm policy add src 0.0.0.0/0 dst 10.$i.99.0/30 dir out action block 158 echo netns exec $ns ip xfrm policy add src 10.$i.99.0/30 dst 0.0.0.0/0 dir out action block 159 for j in $(seq 32 64);do 160 echo netns exec $ns ip xfrm policy add src 10.$i.1.0/30 dst 10.$i.$j.0/30 dir out action block 161 # silly, as it encompasses the one above too, but its allowed: 162 echo netns exec $ns ip xfrm policy add src 10.$i.1.0/29 dst 10.$i.$j.0/29 dir out action block 163 # and yet again, even more broad one. 164 echo netns exec $ns ip xfrm policy add src 10.$i.1.0/24 dst 10.$i.$j.0/24 dir out action block 165 echo netns exec $ns ip xfrm policy add src 10.$i.$j.0/24 dst 10.$i.1.0/24 dir fwd action block 166 done 167 done | ip -batch /dev/stdin 168} 169 170do_dummies6() { 171 local ns=$1 172 173 for i in $(seq 10 16);do 174 for j in $(seq 32 64);do 175 echo netns exec $ns ip xfrm policy add src dead:$i::/64 dst dead:$i:$j::/64 dir out action block 176 echo netns exec $ns ip xfrm policy add src dead:$i:$j::/64 dst dead:$i::/24 dir fwd action block 177 done 178 done | ip -batch /dev/stdin 179} 180 181check_ipt_policy_count() 182{ 183 ns=$1 184 185 ip netns exec $ns iptables-save -c |grep policy | ( read c rest 186 ip netns exec $ns iptables -Z 187 if [ x"$c" = x'[0:0]' ]; then 188 exit 0 189 elif [ x"$c" = x ]; then 190 echo "ERROR: No counters" 191 ret=1 192 exit 111 193 else 194 exit 1 195 fi 196 ) 197} 198 199check_xfrm() { 200 # 0: iptables -m policy rule count == 0 201 # 1: iptables -m policy rule count != 0 202 rval=$1 203 ip=$2 204 local lret=0 205 206 ip netns exec ${ns[1]} ping -q -c 1 10.0.2.$ip > /dev/null 207 208 check_ipt_policy_count ${ns[3]} 209 if [ $? -ne $rval ] ; then 210 lret=1 211 fi 212 check_ipt_policy_count ${ns[4]} 213 if [ $? -ne $rval ] ; then 214 lret=1 215 fi 216 217 ip netns exec ${ns[2]} ping -q -c 1 10.0.1.$ip > /dev/null 218 219 check_ipt_policy_count ${ns[3]} 220 if [ $? -ne $rval ] ; then 221 lret=1 222 fi 223 check_ipt_policy_count ${ns[4]} 224 if [ $? -ne $rval ] ; then 225 lret=1 226 fi 227 228 return $lret 229} 230 231check_exceptions() 232{ 233 logpostfix="$1" 234 local lret=0 235 236 # ping to .254 should be excluded from the tunnel (exception is in place). 237 check_xfrm 0 254 238 if [ $? -ne 0 ]; then 239 echo "FAIL: expected ping to .254 to fail ($logpostfix)" 240 lret=1 241 else 242 echo "PASS: ping to .254 bypassed ipsec tunnel ($logpostfix)" 243 fi 244 245 # ping to .253 should use use ipsec due to direct policy exception. 246 check_xfrm 1 253 247 if [ $? -ne 0 ]; then 248 echo "FAIL: expected ping to .253 to use ipsec tunnel ($logpostfix)" 249 lret=1 250 else 251 echo "PASS: direct policy matches ($logpostfix)" 252 fi 253 254 # ping to .2 should use ipsec. 255 check_xfrm 1 2 256 if [ $? -ne 0 ]; then 257 echo "FAIL: expected ping to .2 to use ipsec tunnel ($logpostfix)" 258 lret=1 259 else 260 echo "PASS: policy matches ($logpostfix)" 261 fi 262 263 return $lret 264} 265 266check_hthresh_repeat() 267{ 268 local log=$1 269 i=0 270 271 for i in $(seq 1 10);do 272 ip -net ${ns[1]} 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 273 ip -net ${ns[1]} xfrm policy set hthresh6 0 28 || break 274 275 ip -net ${ns[1]} xfrm policy update src e000:0001::0000 dst ff01::01 dir in tmpl src :: dst :: proto esp mode tunnel priority 100 action allow || break 276 ip -net ${ns[1]} xfrm policy set hthresh6 0 28 || break 277 done 278 279 if [ $i -ne 10 ] ;then 280 echo "FAIL: $log" 1>&2 281 ret=1 282 return 1 283 fi 284 285 echo "PASS: $log" 286 return 0 287} 288 289# insert non-overlapping policies in a random order and check that 290# all of them can be fetched using the traffic selectors. 291check_random_order() 292{ 293 local ns=$1 294 local log=$2 295 296 for i in $(seq 50); do 297 ip -net $ns xfrm policy flush 298 for j in $(seq 0 16 255 | sort -R); do 299 ip -net $ns xfrm policy add dst $j.0.0.0/24 dir out priority 10 action allow 300 done 301 for j in $(seq 0 16 255); do 302 if ! ip -net $ns xfrm policy get dst $j.0.0.0/24 dir out > /dev/null; then 303 echo "FAIL: $log" 1>&2 304 return 1 305 fi 306 done 307 done 308 309 for i in $(seq 50); do 310 ip -net $ns xfrm policy flush 311 for j in $(seq 0 16 255 | sort -R); do 312 local addr=$(printf "e000:0000:%02x00::/56" $j) 313 ip -net $ns xfrm policy add dst $addr dir out priority 10 action allow 314 done 315 for j in $(seq 0 16 255); do 316 local addr=$(printf "e000:0000:%02x00::/56" $j) 317 if ! ip -net $ns xfrm policy get dst $addr dir out > /dev/null; then 318 echo "FAIL: $log" 1>&2 319 return 1 320 fi 321 done 322 done 323 324 ip -net $ns xfrm policy flush 325 326 echo "PASS: $log" 327 return 0 328} 329 330#check for needed privileges 331if [ "$(id -u)" -ne 0 ];then 332 echo "SKIP: Need root privileges" 333 exit $ksft_skip 334fi 335 336ip -Version 2>/dev/null >/dev/null 337if [ $? -ne 0 ];then 338 echo "SKIP: Could not run test without the ip tool" 339 exit $ksft_skip 340fi 341 342# needed to check if policy lookup got valid ipsec result 343iptables --version 2>/dev/null >/dev/null 344if [ $? -ne 0 ];then 345 echo "SKIP: Could not run test without iptables tool" 346 exit $ksft_skip 347fi 348 349setup_ns ns1 ns2 ns3 ns4 350ns[1]=$ns1 351ns[2]=$ns2 352ns[3]=$ns3 353ns[4]=$ns4 354 355DEV=veth0 356ip link add $DEV netns ${ns[1]} type veth peer name eth1 netns ${ns[3]} 357ip link add $DEV netns ${ns[2]} type veth peer name eth1 netns ${ns[4]} 358 359ip link add $DEV netns ${ns[3]} type veth peer name veth0 netns ${ns[4]} 360 361DEV=veth0 362for i in 1 2; do 363 ip -net ${ns[$i]} link set $DEV up 364 ip -net ${ns[$i]} addr add 10.0.$i.2/24 dev $DEV 365 ip -net ${ns[$i]} addr add dead:$i::2/64 dev $DEV 366 367 ip -net ${ns[$i]} addr add 10.0.$i.253 dev $DEV 368 ip -net ${ns[$i]} addr add 10.0.$i.254 dev $DEV 369 ip -net ${ns[$i]} addr add dead:$i::fd dev $DEV 370 ip -net ${ns[$i]} addr add dead:$i::fe dev $DEV 371done 372 373for i in 3 4; do 374 ip -net ${ns[$i]} link set eth1 up 375 ip -net ${ns[$i]} link set veth0 up 376done 377 378ip -net ${ns[1]} route add default via 10.0.1.1 379ip -net ${ns[2]} route add default via 10.0.2.1 380 381ip -net ${ns[3]} addr add 10.0.1.1/24 dev eth1 382ip -net ${ns[3]} addr add 10.0.3.1/24 dev veth0 383ip -net ${ns[3]} addr add 2001:1::1/64 dev eth1 384ip -net ${ns[3]} addr add 2001:3::1/64 dev veth0 385 386ip -net ${ns[3]} route add default via 10.0.3.10 387 388ip -net ${ns[4]} addr add 10.0.2.1/24 dev eth1 389ip -net ${ns[4]} addr add 10.0.3.10/24 dev veth0 390ip -net ${ns[4]} addr add 2001:2::1/64 dev eth1 391ip -net ${ns[4]} addr add 2001:3::10/64 dev veth0 392ip -net ${ns[4]} route add default via 10.0.3.1 393 394for j in 4 6; do 395 for i in 3 4;do 396 ip netns exec ${ns[$i]} sysctl net.ipv$j.conf.eth1.forwarding=1 > /dev/null 397 ip netns exec ${ns[$i]} sysctl net.ipv$j.conf.veth0.forwarding=1 > /dev/null 398 done 399done 400 401# abuse iptables rule counter to check if ping matches a policy 402ip netns exec ${ns[3]} iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec 403ip netns exec ${ns[4]} iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec 404if [ $? -ne 0 ];then 405 echo "SKIP: Could not insert iptables rule" 406 cleanup_ns $ns1 $ns2 $ns3 $ns4 407 exit $ksft_skip 408fi 409 410# localip remoteip localnet remotenet 411do_esp ${ns[3]} 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2 412do_esp ${ns[3]} dead:3::1 dead:3::10 dead:1::/64 dead:2::/64 $SPI1 $SPI2 413do_esp ${ns[4]} 10.0.3.10 10.0.3.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1 414do_esp ${ns[4]} dead:3::10 dead:3::1 dead:2::/64 dead:1::/64 $SPI2 $SPI1 415 416do_dummies4 ${ns[3]} 417do_dummies6 ${ns[4]} 418 419do_esp_policy_get_check ${ns[3]} 10.0.1.0/24 10.0.2.0/24 420do_esp_policy_get_check ${ns[4]} 10.0.2.0/24 10.0.1.0/24 421do_esp_policy_get_check ${ns[3]} dead:1::/64 dead:2::/64 422do_esp_policy_get_check ${ns[4]} dead:2::/64 dead:1::/64 423 424# ping to .254 should use ipsec, exception is not installed. 425check_xfrm 1 254 426if [ $? -ne 0 ]; then 427 echo "FAIL: expected ping to .254 to use ipsec tunnel" 428 ret=1 429else 430 echo "PASS: policy before exception matches" 431fi 432 433# installs exceptions 434# localip remoteip encryptdst plaindst 435do_exception ${ns[3]} 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28 436do_exception ${ns[4]} 10.0.3.10 10.0.3.1 10.0.1.253 10.0.1.240/28 437 438do_exception ${ns[3]} dead:3::1 dead:3::10 dead:2::fd dead:2:f0::/96 439do_exception ${ns[4]} dead:3::10 dead:3::1 dead:1::fd dead:1:f0::/96 440 441check_exceptions "exceptions" 442if [ $? -ne 0 ]; then 443 ret=1 444fi 445 446# insert block policies with adjacent/overlapping netmasks 447do_overlap ${ns[3]} 448 449check_exceptions "exceptions and block policies" 450if [ $? -ne 0 ]; then 451 ret=1 452fi 453 454for n in ${ns[3]} ${ns[4]};do 455 ip -net $n xfrm policy set hthresh4 28 24 hthresh6 126 125 456 sleep $((RANDOM%5)) 457done 458 459check_exceptions "exceptions and block policies after hresh changes" 460 461# full flush of policy db, check everything gets freed incl. internal meta data 462ip -net ${ns[3]} xfrm policy flush 463 464do_esp_policy ${ns[3]} 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 465do_exception ${ns[3]} 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28 466 467# move inexact policies to hash table 468ip -net ${ns[3]} xfrm policy set hthresh4 16 16 469 470sleep $((RANDOM%5)) 471check_exceptions "exceptions and block policies after hthresh change in ns3" 472 473# restore original hthresh settings -- move policies back to tables 474for n in ${ns[3]} ${ns[4]};do 475 ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128 476 sleep $((RANDOM%5)) 477done 478check_exceptions "exceptions and block policies after htresh change to normal" 479 480check_hthresh_repeat "policies with repeated htresh change" 481 482check_random_order ${ns[3]} "policies inserted in random order" 483 484cleanup_ns $ns1 $ns2 $ns3 $ns4 485 486exit $ret 487