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 source lib.sh 22 ret=0 23 policy_checks_ok=1 24 25 KEY_SHA=0xdeadbeef1234567890abcdefabcdefabcdefabcd 26 KEY_AES=0x0123456789abcdef0123456789012345 27 SPI1=0x1 28 SPI2=0x2 29 30 do_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 43 do_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. 70 do_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 117 do_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 137 do_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. 152 do_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 170 do_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 181 check_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 199 check_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 231 check_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 266 check_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. 291 check_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 331 if [ "$(id -u)" -ne 0 ];then 332 echo "SKIP: Need root privileges" 333 exit $ksft_skip 334 fi 335 336 ip -Version 2>/dev/null >/dev/null 337 if [ $? -ne 0 ];then 338 echo "SKIP: Could not run test without the ip tool" 339 exit $ksft_skip 340 fi 341 342 # needed to check if policy lookup got valid ipsec result 343 iptables --version 2>/dev/null >/dev/null 344 if [ $? -ne 0 ];then 345 echo "SKIP: Could not run test without iptables tool" 346 exit $ksft_skip 347 fi 348 349 setup_ns ns1 ns2 ns3 ns4 350 ns[1]=$ns1 351 ns[2]=$ns2 352 ns[3]=$ns3 353 ns[4]=$ns4 354 355 DEV=veth0 356 ip link add $DEV netns ${ns[1]} type veth peer name eth1 netns ${ns[3]} 357 ip link add $DEV netns ${ns[2]} type veth peer name eth1 netns ${ns[4]} 358 359 ip link add $DEV netns ${ns[3]} type veth peer name veth0 netns ${ns[4]} 360 361 DEV=veth0 362 for 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 371 done 372 373 for i in 3 4; do 374 ip -net ${ns[$i]} link set eth1 up 375 ip -net ${ns[$i]} link set veth0 up 376 done 377 378 ip -net ${ns[1]} route add default via 10.0.1.1 379 ip -net ${ns[2]} route add default via 10.0.2.1 380 381 ip -net ${ns[3]} addr add 10.0.1.1/24 dev eth1 382 ip -net ${ns[3]} addr add 10.0.3.1/24 dev veth0 383 ip -net ${ns[3]} addr add 2001:1::1/64 dev eth1 384 ip -net ${ns[3]} addr add 2001:3::1/64 dev veth0 385 386 ip -net ${ns[3]} route add default via 10.0.3.10 387 388 ip -net ${ns[4]} addr add 10.0.2.1/24 dev eth1 389 ip -net ${ns[4]} addr add 10.0.3.10/24 dev veth0 390 ip -net ${ns[4]} addr add 2001:2::1/64 dev eth1 391 ip -net ${ns[4]} addr add 2001:3::10/64 dev veth0 392 ip -net ${ns[4]} route add default via 10.0.3.1 393 394 for 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 399 done 400 401 # abuse iptables rule counter to check if ping matches a policy 402 ip netns exec ${ns[3]} iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec 403 ip netns exec ${ns[4]} iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec 404 if [ $? -ne 0 ];then 405 echo "SKIP: Could not insert iptables rule" 406 cleanup_ns $ns1 $ns2 $ns3 $ns4 407 exit $ksft_skip 408 fi 409 410 # localip remoteip localnet remotenet 411 do_esp ${ns[3]} 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2 412 do_esp ${ns[3]} dead:3::1 dead:3::10 dead:1::/64 dead:2::/64 $SPI1 $SPI2 413 do_esp ${ns[4]} 10.0.3.10 10.0.3.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1 414 do_esp ${ns[4]} dead:3::10 dead:3::1 dead:2::/64 dead:1::/64 $SPI2 $SPI1 415 416 do_dummies4 ${ns[3]} 417 do_dummies6 ${ns[4]} 418 419 do_esp_policy_get_check ${ns[3]} 10.0.1.0/24 10.0.2.0/24 420 do_esp_policy_get_check ${ns[4]} 10.0.2.0/24 10.0.1.0/24 421 do_esp_policy_get_check ${ns[3]} dead:1::/64 dead:2::/64 422 do_esp_policy_get_check ${ns[4]} dead:2::/64 dead:1::/64 423 424 # ping to .254 should use ipsec, exception is not installed. 425 check_xfrm 1 254 426 if [ $? -ne 0 ]; then 427 echo "FAIL: expected ping to .254 to use ipsec tunnel" 428 ret=1 429 else 430 echo "PASS: policy before exception matches" 431 fi 432 433 # installs exceptions 434 # localip remoteip encryptdst plaindst 435 do_exception ${ns[3]} 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28 436 do_exception ${ns[4]} 10.0.3.10 10.0.3.1 10.0.1.253 10.0.1.240/28 437 438 do_exception ${ns[3]} dead:3::1 dead:3::10 dead:2::fd dead:2:f0::/96 439 do_exception ${ns[4]} dead:3::10 dead:3::1 dead:1::fd dead:1:f0::/96 440 441 check_exceptions "exceptions" 442 if [ $? -ne 0 ]; then 443 ret=1 444 fi 445 446 # insert block policies with adjacent/overlapping netmasks 447 do_overlap ${ns[3]} 448 449 check_exceptions "exceptions and block policies" 450 if [ $? -ne 0 ]; then 451 ret=1 452 fi 453 454 for n in ${ns[3]} ${ns[4]};do 455 ip -net $n xfrm policy set hthresh4 28 24 hthresh6 126 125 456 sleep $((RANDOM%5)) 457 done 458 459 check_exceptions "exceptions and block policies after hresh changes" 460 461 # full flush of policy db, check everything gets freed incl. internal meta data 462 ip -net ${ns[3]} xfrm policy flush 463 464 do_esp_policy ${ns[3]} 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 465 do_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 468 ip -net ${ns[3]} xfrm policy set hthresh4 16 16 469 470 sleep $((RANDOM%5)) 471 check_exceptions "exceptions and block policies after hthresh change in ns3" 472 473 # restore original hthresh settings -- move policies back to tables 474 for n in ${ns[3]} ${ns[4]};do 475 ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128 476 sleep $((RANDOM%5)) 477 done 478 check_exceptions "exceptions and block policies after htresh change to normal" 479 480 check_hthresh_repeat "policies with repeated htresh change" 481 482 check_random_order ${ns[3]} "policies inserted in random order" 483 484 cleanup_ns $ns1 $ns2 $ns3 $ns4 485 486 exit $ret
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.