Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # Check xfrm policy resolution.  Topology:
0005 #
0006 # 1.2   1.1   3.1  3.10    2.1   2.2
0007 # eth1  eth1 veth0 veth0 eth1   eth1
0008 # ns1 ---- ns3 ----- ns4 ---- ns2
0009 #
0010 # ns3 and ns4 are connected via ipsec tunnel.
0011 # pings from ns1 to ns2 (and vice versa) are supposed to work like this:
0012 # ns1: ping 10.0.2.2: passes via ipsec tunnel.
0013 # ns2: ping 10.0.1.2: passes via ipsec tunnel.
0014 
0015 # ns1: ping 10.0.1.253: passes via ipsec tunnel (direct policy)
0016 # ns2: ping 10.0.2.253: passes via ipsec tunnel (direct policy)
0017 #
0018 # ns1: ping 10.0.2.254: does NOT pass via ipsec tunnel (exception)
0019 # ns2: ping 10.0.1.254: does NOT pass via ipsec tunnel (exception)
0020 
0021 # Kselftest framework requirement - SKIP code is 4.
0022 ksft_skip=4
0023 ret=0
0024 policy_checks_ok=1
0025 
0026 KEY_SHA=0xdeadbeef1234567890abcdefabcdefabcdefabcd
0027 KEY_AES=0x0123456789abcdef0123456789012345
0028 SPI1=0x1
0029 SPI2=0x2
0030 
0031 do_esp_policy() {
0032     local ns=$1
0033     local me=$2
0034     local remote=$3
0035     local lnet=$4
0036     local rnet=$5
0037 
0038     # to encrypt packets as they go out (includes forwarded packets that need encapsulation)
0039     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
0040     # to fwd decrypted packets after esp processing:
0041     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
0042 }
0043 
0044 do_esp() {
0045     local ns=$1
0046     local me=$2
0047     local remote=$3
0048     local lnet=$4
0049     local rnet=$5
0050     local spi_out=$6
0051     local spi_in=$7
0052 
0053     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
0054     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
0055 
0056     do_esp_policy $ns $me $remote $lnet $rnet
0057 }
0058 
0059 # add policies with different netmasks, to make sure kernel carries
0060 # the policies contained within new netmask over when search tree is
0061 # re-built.
0062 # peer netns that are supposed to be encapsulated via esp have addresses
0063 # in the 10.0.1.0/24 and 10.0.2.0/24 subnets, respectively.
0064 #
0065 # Adding a policy for '10.0.1.0/23' will make it necessary to
0066 # alter the prefix of 10.0.1.0 subnet.
0067 # In case new prefix overlaps with existing node, the node and all
0068 # policies it carries need to be merged with the existing one(s).
0069 #
0070 # Do that here.
0071 do_overlap()
0072 {
0073     local ns=$1
0074 
0075     # adds new nodes to tree (neither network exists yet in policy database).
0076     ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block
0077 
0078     # adds a new node in the 10.0.0.0/24 tree (dst node exists).
0079     ip -net $ns xfrm policy add src 10.2.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block
0080 
0081     # adds a 10.2.0.0/23 node, but for different dst.
0082     ip -net $ns xfrm policy add src 10.2.0.0/23 dst 10.0.1.0/24 dir fwd priority 200 action block
0083 
0084     # dst now overlaps with the 10.0.1.0/24 ESP policy in fwd.
0085     # kernel must 'promote' existing one (10.0.0.0/24) to 10.0.0.0/23.
0086     # But 10.0.0.0/23 also includes existing 10.0.1.0/24, so that node
0087     # also has to be merged too, including source-sorted subtrees.
0088     # old:
0089     # 10.0.0.0/24 (node 1 in dst tree of the bin)
0090     #    10.1.0.0/24 (node in src tree of dst node 1)
0091     #    10.2.0.0/24 (node in src tree of dst node 1)
0092     # 10.0.1.0/24 (node 2 in dst tree of the bin)
0093     #    10.0.2.0/24 (node in src tree of dst node 2)
0094     #    10.2.0.0/24 (node in src tree of dst node 2)
0095     #
0096     # The next 'policy add' adds dst '10.0.0.0/23', which means
0097     # that dst node 1 and dst node 2 have to be merged including
0098     # the sub-tree.  As no duplicates are allowed, policies in
0099     # the two '10.0.2.0/24' are also merged.
0100     #
0101     # after the 'add', internal search tree should look like this:
0102     # 10.0.0.0/23 (node in dst tree of bin)
0103     #     10.0.2.0/24 (node in src tree of dst node)
0104     #     10.1.0.0/24 (node in src tree of dst node)
0105     #     10.2.0.0/24 (node in src tree of dst node)
0106     #
0107     # 10.0.0.0/24 and 10.0.1.0/24 nodes have been merged as 10.0.0.0/23.
0108     ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/23 dir fwd priority 200 action block
0109 
0110     # similar to above: add policies (with partially random address), with shrinking prefixes.
0111     for p in 29 28 27;do
0112       for k in $(seq 1 32); do
0113        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
0114       done
0115     done
0116 }
0117 
0118 do_esp_policy_get_check() {
0119     local ns=$1
0120     local lnet=$2
0121     local rnet=$3
0122 
0123     ip -net $ns xfrm policy get src $lnet dst $rnet dir out > /dev/null
0124     if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then
0125         policy_checks_ok=0
0126         echo "FAIL: ip -net $ns xfrm policy get src $lnet dst $rnet dir out"
0127         ret=1
0128     fi
0129 
0130     ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd > /dev/null
0131     if [ $? -ne 0 ] && [ $policy_checks_ok -eq 1 ] ;then
0132         policy_checks_ok=0
0133         echo "FAIL: ip -net $ns xfrm policy get src $rnet dst $lnet dir fwd"
0134         ret=1
0135     fi
0136 }
0137 
0138 do_exception() {
0139     local ns=$1
0140     local me=$2
0141     local remote=$3
0142     local encryptip=$4
0143     local plain=$5
0144 
0145     # network $plain passes without tunnel
0146     ip -net $ns xfrm policy add dst $plain dir out priority 10 action allow
0147 
0148     # direct policy for $encryptip, use tunnel, higher prio takes precedence
0149     ip -net $ns xfrm policy add dst $encryptip dir out tmpl src $me dst $remote proto esp mode tunnel priority 1 action allow
0150 }
0151 
0152 # policies that are not supposed to match any packets generated in this test.
0153 do_dummies4() {
0154     local ns=$1
0155 
0156     for i in $(seq 10 16);do
0157       # dummy policy with wildcard src/dst.
0158       echo netns exec $ns ip xfrm policy add src 0.0.0.0/0 dst 10.$i.99.0/30 dir out action block
0159       echo netns exec $ns ip xfrm policy add src 10.$i.99.0/30 dst 0.0.0.0/0 dir out action block
0160       for j in $(seq 32 64);do
0161         echo netns exec $ns ip xfrm policy add src 10.$i.1.0/30 dst 10.$i.$j.0/30 dir out action block
0162         # silly, as it encompasses the one above too, but its allowed:
0163         echo netns exec $ns ip xfrm policy add src 10.$i.1.0/29 dst 10.$i.$j.0/29 dir out action block
0164         # and yet again, even more broad one.
0165         echo netns exec $ns ip xfrm policy add src 10.$i.1.0/24 dst 10.$i.$j.0/24 dir out action block
0166         echo netns exec $ns ip xfrm policy add src 10.$i.$j.0/24 dst 10.$i.1.0/24 dir fwd action block
0167       done
0168     done | ip -batch /dev/stdin
0169 }
0170 
0171 do_dummies6() {
0172     local ns=$1
0173 
0174     for i in $(seq 10 16);do
0175       for j in $(seq 32 64);do
0176        echo netns exec $ns ip xfrm policy add src dead:$i::/64 dst dead:$i:$j::/64 dir out action block
0177        echo netns exec $ns ip xfrm policy add src dead:$i:$j::/64 dst dead:$i::/24 dir fwd action block
0178       done
0179     done | ip -batch /dev/stdin
0180 }
0181 
0182 check_ipt_policy_count()
0183 {
0184         ns=$1
0185 
0186         ip netns exec $ns iptables-save -c |grep policy | ( read c rest
0187                 ip netns exec $ns iptables -Z
0188                 if [ x"$c" = x'[0:0]' ]; then
0189                         exit 0
0190                 elif [ x"$c" = x ]; then
0191                         echo "ERROR: No counters"
0192                         ret=1
0193                         exit 111
0194                 else
0195                         exit 1
0196                 fi
0197         )
0198 }
0199 
0200 check_xfrm() {
0201         # 0: iptables -m policy rule count == 0
0202         # 1: iptables -m policy rule count != 0
0203         rval=$1
0204         ip=$2
0205         local lret=0
0206 
0207         ip netns exec ns1 ping -q -c 1 10.0.2.$ip > /dev/null
0208 
0209         check_ipt_policy_count ns3
0210         if [ $? -ne $rval ] ; then
0211                 lret=1
0212         fi
0213         check_ipt_policy_count ns4
0214         if [ $? -ne $rval ] ; then
0215                 lret=1
0216         fi
0217 
0218         ip netns exec ns2 ping -q -c 1 10.0.1.$ip > /dev/null
0219 
0220         check_ipt_policy_count ns3
0221         if [ $? -ne $rval ] ; then
0222                 lret=1
0223         fi
0224         check_ipt_policy_count ns4
0225         if [ $? -ne $rval ] ; then
0226                 lret=1
0227         fi
0228 
0229         return $lret
0230 }
0231 
0232 check_exceptions()
0233 {
0234         logpostfix="$1"
0235         local lret=0
0236 
0237         # ping to .254 should be excluded from the tunnel (exception is in place).
0238         check_xfrm 0 254
0239         if [ $? -ne 0 ]; then
0240                 echo "FAIL: expected ping to .254 to fail ($logpostfix)"
0241                 lret=1
0242         else
0243                 echo "PASS: ping to .254 bypassed ipsec tunnel ($logpostfix)"
0244         fi
0245 
0246         # ping to .253 should use use ipsec due to direct policy exception.
0247         check_xfrm 1 253
0248         if [ $? -ne 0 ]; then
0249                 echo "FAIL: expected ping to .253 to use ipsec tunnel ($logpostfix)"
0250                 lret=1
0251         else
0252                 echo "PASS: direct policy matches ($logpostfix)"
0253         fi
0254 
0255         # ping to .2 should use ipsec.
0256         check_xfrm 1 2
0257         if [ $? -ne 0 ]; then
0258                 echo "FAIL: expected ping to .2 to use ipsec tunnel ($logpostfix)"
0259                 lret=1
0260         else
0261                 echo "PASS: policy matches ($logpostfix)"
0262         fi
0263 
0264         return $lret
0265 }
0266 
0267 check_hthresh_repeat()
0268 {
0269         local log=$1
0270         i=0
0271 
0272         for i in $(seq 1 10);do
0273                 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
0274                 ip -net ns1 xfrm policy set hthresh6 0 28 || break
0275 
0276                 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
0277                 ip -net ns1 xfrm policy set hthresh6 0 28 || break
0278         done
0279 
0280         if [ $i -ne 10 ] ;then
0281                 echo "FAIL: $log" 1>&2
0282                 ret=1
0283                 return 1
0284         fi
0285 
0286         echo "PASS: $log"
0287         return 0
0288 }
0289 
0290 # insert non-overlapping policies in a random order and check that
0291 # all of them can be fetched using the traffic selectors.
0292 check_random_order()
0293 {
0294         local ns=$1
0295         local log=$2
0296 
0297         for i in $(seq 100); do
0298                 ip -net $ns xfrm policy flush
0299                 for j in $(seq 0 16 255 | sort -R); do
0300                         ip -net $ns xfrm policy add dst $j.0.0.0/24 dir out priority 10 action allow
0301                 done
0302                 for j in $(seq 0 16 255); do
0303                         if ! ip -net $ns xfrm policy get dst $j.0.0.0/24 dir out > /dev/null; then
0304                                 echo "FAIL: $log" 1>&2
0305                                 return 1
0306                         fi
0307                 done
0308         done
0309 
0310         for i in $(seq 100); do
0311                 ip -net $ns xfrm policy flush
0312                 for j in $(seq 0 16 255 | sort -R); do
0313                         local addr=$(printf "e000:0000:%02x00::/56" $j)
0314                         ip -net $ns xfrm policy add dst $addr dir out priority 10 action allow
0315                 done
0316                 for j in $(seq 0 16 255); do
0317                         local addr=$(printf "e000:0000:%02x00::/56" $j)
0318                         if ! ip -net $ns xfrm policy get dst $addr dir out > /dev/null; then
0319                                 echo "FAIL: $log" 1>&2
0320                                 return 1
0321                         fi
0322                 done
0323         done
0324 
0325         ip -net $ns xfrm policy flush
0326 
0327         echo "PASS: $log"
0328         return 0
0329 }
0330 
0331 #check for needed privileges
0332 if [ "$(id -u)" -ne 0 ];then
0333         echo "SKIP: Need root privileges"
0334         exit $ksft_skip
0335 fi
0336 
0337 ip -Version 2>/dev/null >/dev/null
0338 if [ $? -ne 0 ];then
0339         echo "SKIP: Could not run test without the ip tool"
0340         exit $ksft_skip
0341 fi
0342 
0343 # needed to check if policy lookup got valid ipsec result
0344 iptables --version 2>/dev/null >/dev/null
0345 if [ $? -ne 0 ];then
0346         echo "SKIP: Could not run test without iptables tool"
0347         exit $ksft_skip
0348 fi
0349 
0350 for i in 1 2 3 4; do
0351     ip netns add ns$i
0352     ip -net ns$i link set lo up
0353 done
0354 
0355 DEV=veth0
0356 ip link add $DEV netns ns1 type veth peer name eth1 netns ns3
0357 ip link add $DEV netns ns2 type veth peer name eth1 netns ns4
0358 
0359 ip link add $DEV netns ns3 type veth peer name veth0 netns ns4
0360 
0361 DEV=veth0
0362 for i in 1 2; do
0363     ip -net ns$i link set $DEV up
0364     ip -net ns$i addr add 10.0.$i.2/24 dev $DEV
0365     ip -net ns$i addr add dead:$i::2/64 dev $DEV
0366 
0367     ip -net ns$i addr add 10.0.$i.253 dev $DEV
0368     ip -net ns$i addr add 10.0.$i.254 dev $DEV
0369     ip -net ns$i addr add dead:$i::fd dev $DEV
0370     ip -net ns$i addr add dead:$i::fe dev $DEV
0371 done
0372 
0373 for i in 3 4; do
0374 ip -net ns$i link set eth1 up
0375 ip -net ns$i link set veth0 up
0376 done
0377 
0378 ip -net ns1 route add default via 10.0.1.1
0379 ip -net ns2 route add default via 10.0.2.1
0380 
0381 ip -net ns3 addr add 10.0.1.1/24 dev eth1
0382 ip -net ns3 addr add 10.0.3.1/24 dev veth0
0383 ip -net ns3 addr add 2001:1::1/64 dev eth1
0384 ip -net ns3 addr add 2001:3::1/64 dev veth0
0385 
0386 ip -net ns3 route add default via 10.0.3.10
0387 
0388 ip -net ns4 addr add 10.0.2.1/24 dev eth1
0389 ip -net ns4 addr add 10.0.3.10/24 dev veth0
0390 ip -net ns4 addr add 2001:2::1/64 dev eth1
0391 ip -net ns4 addr add 2001:3::10/64 dev veth0
0392 ip -net ns4 route add default via 10.0.3.1
0393 
0394 for j in 4 6; do
0395         for i in 3 4;do
0396                 ip netns exec ns$i sysctl net.ipv$j.conf.eth1.forwarding=1 > /dev/null
0397                 ip netns exec ns$i sysctl net.ipv$j.conf.veth0.forwarding=1 > /dev/null
0398         done
0399 done
0400 
0401 # abuse iptables rule counter to check if ping matches a policy
0402 ip netns exec ns3 iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec
0403 ip netns exec ns4 iptables -p icmp -A FORWARD -m policy --dir out --pol ipsec
0404 if [ $? -ne 0 ];then
0405         echo "SKIP: Could not insert iptables rule"
0406         for i in 1 2 3 4;do ip netns del ns$i;done
0407         exit $ksft_skip
0408 fi
0409 
0410 #          localip  remoteip  localnet    remotenet
0411 do_esp ns3 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
0412 do_esp ns3 dead:3::1 dead:3::10 dead:1::/64 dead:2::/64 $SPI1 $SPI2
0413 do_esp ns4 10.0.3.10 10.0.3.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
0414 do_esp ns4 dead:3::10 dead:3::1 dead:2::/64 dead:1::/64 $SPI2 $SPI1
0415 
0416 do_dummies4 ns3
0417 do_dummies6 ns4
0418 
0419 do_esp_policy_get_check ns3 10.0.1.0/24 10.0.2.0/24
0420 do_esp_policy_get_check ns4 10.0.2.0/24 10.0.1.0/24
0421 do_esp_policy_get_check ns3 dead:1::/64 dead:2::/64
0422 do_esp_policy_get_check ns4 dead:2::/64 dead:1::/64
0423 
0424 # ping to .254 should use ipsec, exception is not installed.
0425 check_xfrm 1 254
0426 if [ $? -ne 0 ]; then
0427         echo "FAIL: expected ping to .254 to use ipsec tunnel"
0428         ret=1
0429 else
0430         echo "PASS: policy before exception matches"
0431 fi
0432 
0433 # installs exceptions
0434 #                localip  remoteip   encryptdst  plaindst
0435 do_exception ns3 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28
0436 do_exception ns4 10.0.3.10 10.0.3.1 10.0.1.253 10.0.1.240/28
0437 
0438 do_exception ns3 dead:3::1 dead:3::10 dead:2::fd  dead:2:f0::/96
0439 do_exception ns4 dead:3::10 dead:3::1 dead:1::fd  dead:1:f0::/96
0440 
0441 check_exceptions "exceptions"
0442 if [ $? -ne 0 ]; then
0443         ret=1
0444 fi
0445 
0446 # insert block policies with adjacent/overlapping netmasks
0447 do_overlap ns3
0448 
0449 check_exceptions "exceptions and block policies"
0450 if [ $? -ne 0 ]; then
0451         ret=1
0452 fi
0453 
0454 for n in ns3 ns4;do
0455         ip -net $n xfrm policy set hthresh4 28 24 hthresh6 126 125
0456         sleep $((RANDOM%5))
0457 done
0458 
0459 check_exceptions "exceptions and block policies after hresh changes"
0460 
0461 # full flush of policy db, check everything gets freed incl. internal meta data
0462 ip -net ns3 xfrm policy flush
0463 
0464 do_esp_policy ns3 10.0.3.1 10.0.3.10 10.0.1.0/24 10.0.2.0/24
0465 do_exception ns3 10.0.3.1 10.0.3.10 10.0.2.253 10.0.2.240/28
0466 
0467 # move inexact policies to hash table
0468 ip -net ns3 xfrm policy set hthresh4 16 16
0469 
0470 sleep $((RANDOM%5))
0471 check_exceptions "exceptions and block policies after hthresh change in ns3"
0472 
0473 # restore original hthresh settings -- move policies back to tables
0474 for n in ns3 ns4;do
0475         ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128
0476         sleep $((RANDOM%5))
0477 done
0478 check_exceptions "exceptions and block policies after htresh change to normal"
0479 
0480 check_hthresh_repeat "policies with repeated htresh change"
0481 
0482 check_random_order ns3 "policies inserted in random order"
0483 
0484 for i in 1 2 3 4;do ip netns del ns$i;done
0485 
0486 exit $ret