| #!/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() { |
| 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 |
| |
| # 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_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 |
| 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 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 |
| |
| # ping to .254 should now be excluded from the tunnel |
| check_xfrm 0 254 |
| if [ $? -ne 0 ]; then |
| echo "FAIL: expected ping to .254 to fail" |
| ret=1 |
| else |
| echo "PASS: ping to .254 bypassed ipsec tunnel" |
| 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" |
| ret=1 |
| else |
| echo "PASS: direct policy matches" |
| 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" |
| ret=1 |
| else |
| echo "PASS: policy matches" |
| fi |
| |
| for i in 1 2 3 4;do ip netns del ns$i;done |
| |
| exit $ret |