#!/bin/bash # # This test is for basic NAT functionality: snat, dnat, redirect, masquerade. # # Kselftest framework requirement - SKIP code is 4. ksft_skip=4 ret=0 nft --version > /dev/null 2>&1 if [ $? -ne 0 ];then echo "SKIP: Could not run test without nft tool" exit $ksft_skip fi ip -Version > /dev/null 2>&1 if [ $? -ne 0 ];then echo "SKIP: Could not run test without ip tool" exit $ksft_skip fi ip netns add ns0 ip netns add ns1 ip netns add ns2 ip link add veth0 netns ns0 type veth peer name eth0 netns ns1 > /dev/null 2>&1 if [ $? -ne 0 ];then echo "SKIP: No virtual ethernet pair device support in kernel" exit $ksft_skip fi ip link add veth1 netns ns0 type veth peer name eth0 netns ns2 ip -net ns0 link set lo up ip -net ns0 link set veth0 up ip -net ns0 addr add 10.0.1.1/24 dev veth0 ip -net ns0 addr add dead:1::1/64 dev veth0 ip -net ns0 link set veth1 up ip -net ns0 addr add 10.0.2.1/24 dev veth1 ip -net ns0 addr add dead:2::1/64 dev veth1 for i in 1 2; do ip -net ns$i link set lo up ip -net ns$i link set eth0 up ip -net ns$i addr add 10.0.$i.99/24 dev eth0 ip -net ns$i route add default via 10.0.$i.1 ip -net ns$i addr add dead:$i::99/64 dev eth0 ip -net ns$i route add default via dead:$i::1 done bad_counter() { local ns=$1 local counter=$2 local expect=$3 echo "ERROR: $counter counter in $ns has unexpected value (expected $expect)" 1>&2 ip netns exec $ns nft list counter inet filter $counter 1>&2 } check_counters() { ns=$1 local lret=0 cnt=$(ip netns exec $ns nft list counter inet filter ns0in | grep -q "packets 1 bytes 84") if [ $? -ne 0 ]; then bad_counter $ns ns0in "packets 1 bytes 84" lret=1 fi cnt=$(ip netns exec $ns nft list counter inet filter ns0out | grep -q "packets 1 bytes 84") if [ $? -ne 0 ]; then bad_counter $ns ns0out "packets 1 bytes 84" lret=1 fi expect="packets 1 bytes 104" cnt=$(ip netns exec $ns nft list counter inet filter ns0in6 | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter $ns ns0in6 "$expect" lret=1 fi cnt=$(ip netns exec $ns nft list counter inet filter ns0out6 | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter $ns ns0out6 "$expect" lret=1 fi return $lret } check_ns0_counters() { local ns=$1 local lret=0 cnt=$(ip netns exec ns0 nft list counter inet filter ns0in | grep -q "packets 0 bytes 0") if [ $? -ne 0 ]; then bad_counter ns0 ns0in "packets 0 bytes 0" lret=1 fi cnt=$(ip netns exec ns0 nft list counter inet filter ns0in6 | grep -q "packets 0 bytes 0") if [ $? -ne 0 ]; then bad_counter ns0 ns0in6 "packets 0 bytes 0" lret=1 fi cnt=$(ip netns exec ns0 nft list counter inet filter ns0out | grep -q "packets 0 bytes 0") if [ $? -ne 0 ]; then bad_counter ns0 ns0out "packets 0 bytes 0" lret=1 fi cnt=$(ip netns exec ns0 nft list counter inet filter ns0out6 | grep -q "packets 0 bytes 0") if [ $? -ne 0 ]; then bad_counter ns0 ns0out6 "packets 0 bytes 0" lret=1 fi for dir in "in" "out" ; do expect="packets 1 bytes 84" cnt=$(ip netns exec ns0 nft list counter inet filter ${ns}${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 $ns$dir "$expect" lret=1 fi expect="packets 1 bytes 104" cnt=$(ip netns exec ns0 nft list counter inet filter ${ns}${dir}6 | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 $ns$dir6 "$expect" lret=1 fi done return $lret } reset_counters() { for i in 0 1 2;do ip netns exec ns$i nft reset counters inet > /dev/null done } test_local_dnat6() { local lret=0 ip netns exec ns0 nft -f - < /dev/null if [ $? -ne 0 ]; then lret=1 echo "ERROR: ping6 failed" return $lret fi expect="packets 0 bytes 0" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 ns1$dir "$expect" lret=1 fi done expect="packets 1 bytes 104" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 ns2$dir "$expect" lret=1 fi done # expect 0 count in ns1 expect="packets 0 bytes 0" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi done # expect 1 packet in ns2 expect="packets 1 bytes 104" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns2 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns0$dir "$expect" lret=1 fi done test $lret -eq 0 && echo "PASS: ipv6 ping to ns1 was NATted to ns2" ip netns exec ns0 nft flush chain ip6 nat output return $lret } test_local_dnat() { local lret=0 ip netns exec ns0 nft -f - < /dev/null if [ $? -ne 0 ]; then lret=1 echo "ERROR: ping failed" return $lret fi expect="packets 0 bytes 0" for dir in "in" "out" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 ns1$dir "$expect" lret=1 fi done expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 ns2$dir "$expect" lret=1 fi done # expect 0 count in ns1 expect="packets 0 bytes 0" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi done # expect 1 packet in ns2 expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns2 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns0$dir "$expect" lret=1 fi done test $lret -eq 0 && echo "PASS: ping to ns1 was NATted to ns2" ip netns exec ns0 nft flush chain ip nat output reset_counters ip netns exec ns0 ping -q -c 1 10.0.1.99 > /dev/null if [ $? -ne 0 ]; then lret=1 echo "ERROR: ping failed" return $lret fi expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns1$dir "$expect" lret=1 fi done expect="packets 0 bytes 0" for dir in "in" "out" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 ns2$dir "$expect" lret=1 fi done # expect 1 count in ns1 expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns0 ns0$dir "$expect" lret=1 fi done # expect 0 packet in ns2 expect="packets 0 bytes 0" for dir in "in" "out" ; do cnt=$(ip netns exec ns2 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns2$dir "$expect" lret=1 fi done test $lret -eq 0 && echo "PASS: ping to ns1 OK after nat output chain flush" return $lret } test_masquerade6() { local lret=0 ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannot ping ns1 from ns2 via ipv6" return 1 lret=1 fi expect="packets 1 bytes 104" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns2$dir "$expect" lret=1 fi cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done reset_counters # add masquerading rule ip netns exec ns0 nft -f - < /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannot ping ns1 from ns2 with active ipv6 masquerading" lret=1 fi # ns1 should have seen packets from ns0, due to masquerade expect="packets 1 bytes 104" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done # ns1 should not have seen packets from ns2, due to masquerade expect="packets 0 bytes 0" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done ip netns exec ns0 nft flush chain ip6 nat postrouting if [ $? -ne 0 ]; then echo "ERROR: Could not flush ip6 nat postrouting" 1>&2 lret=1 fi test $lret -eq 0 && echo "PASS: IPv6 masquerade for ns2" return $lret } test_masquerade() { local lret=0 ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null ip netns exec ns0 sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: canot ping ns1 from ns2" lret=1 fi expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns2$dir "$expect" lret=1 fi cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done reset_counters # add masquerading rule ip netns exec ns0 nft -f - < /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannot ping ns1 from ns2 with active ip masquerading" lret=1 fi # ns1 should have seen packets from ns0, due to masquerade expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns0${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done # ns1 should not have seen packets from ns2, due to masquerade expect="packets 0 bytes 0" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done ip netns exec ns0 nft flush chain ip nat postrouting if [ $? -ne 0 ]; then echo "ERROR: Could not flush nat postrouting" 1>&2 lret=1 fi test $lret -eq 0 && echo "PASS: IP masquerade for ns2" return $lret } test_redirect6() { local lret=0 ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannnot ping ns1 from ns2 via ipv6" lret=1 fi expect="packets 1 bytes 104" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns2$dir "$expect" lret=1 fi cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done reset_counters # add redirect rule ip netns exec ns0 nft -f - < /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannot ping ns1 from ns2 with active ip6 redirect" lret=1 fi # ns1 should have seen no packets from ns2, due to redirection expect="packets 0 bytes 0" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi done # ns0 should have seen packets from ns2, due to masquerade expect="packets 1 bytes 104" for dir in "in6" "out6" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi done ip netns exec ns0 nft delete table ip6 nat if [ $? -ne 0 ]; then echo "ERROR: Could not delete ip6 nat table" 1>&2 lret=1 fi test $lret -eq 0 && echo "PASS: IPv6 redirection for ns2" return $lret } test_redirect() { local lret=0 ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null ip netns exec ns0 sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannot ping ns1 from ns2" lret=1 fi expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns2$dir "$expect" lret=1 fi cnt=$(ip netns exec ns2 nft list counter inet filter ns1${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns2 ns1$dir "$expect" lret=1 fi done reset_counters # add redirect rule ip netns exec ns0 nft -f - < /dev/null # ping ns2->ns1 if [ $? -ne 0 ] ; then echo "ERROR: cannot ping ns1 from ns2 with active ip redirect" lret=1 fi # ns1 should have seen no packets from ns2, due to redirection expect="packets 0 bytes 0" for dir in "in" "out" ; do cnt=$(ip netns exec ns1 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi done # ns0 should have seen packets from ns2, due to masquerade expect="packets 1 bytes 84" for dir in "in" "out" ; do cnt=$(ip netns exec ns0 nft list counter inet filter ns2${dir} | grep -q "$expect") if [ $? -ne 0 ]; then bad_counter ns1 ns0$dir "$expect" lret=1 fi done ip netns exec ns0 nft delete table ip nat if [ $? -ne 0 ]; then echo "ERROR: Could not delete nat table" 1>&2 lret=1 fi test $lret -eq 0 && echo "PASS: IP redirection for ns2" return $lret } # ip netns exec ns0 ping -c 1 -q 10.0.$i.99 for i in 0 1 2; do ip netns exec ns$i nft -f - < /dev/null if [ $? -ne 0 ];then echo "ERROR: Could not reach other namespace(s)" 1>&2 ret=1 fi ip netns exec ns0 ping -c 1 -q dead:$i::99 > /dev/null if [ $? -ne 0 ];then echo "ERROR: Could not reach other namespace(s) via ipv6" 1>&2 ret=1 fi check_counters ns$i if [ $? -ne 0 ]; then ret=1 fi check_ns0_counters ns$i if [ $? -ne 0 ]; then ret=1 fi reset_counters done if [ $ret -eq 0 ];then echo "PASS: netns routing/connectivity: ns0 can reach ns1 and ns2" fi reset_counters test_local_dnat test_local_dnat6 reset_counters test_masquerade test_masquerade6 reset_counters test_redirect test_redirect6 for i in 0 1 2; do ip netns del ns$i;done exit $ret