Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: netfilter: add a vrf+conntrack testcase

Rework the reproducer for the vrf+conntrack regression reported
by Eugene into a selftest and also add a test for ip masquerading
that Lahav fixed recently.

With net or net-next tree, the first test fails and the latter
two pass.

With 09e856d54bda5f28 ("vrf: Reset skb conntrack connection on VRF rcv")
reverted first test passes but the last two fail.

A proper fix needs more work, for time being a revert seems to be
the best choice, snat/masquerade did not work before the fix.

Link: https://lore.kernel.org/netdev/378ca299-4474-7e9a-3d36-2350c8c98995@gmail.com/T/#m95358a31810df7392f541f99d187227bc75c9963
Reported-by: Eugene Crosser <crosser@average.org>
Cc: Lahav Schlesinger <lschlesinger@drivenets.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
33b8aad2 c45231a7

+221 -1
+2 -1
tools/testing/selftests/netfilter/Makefile
··· 5 5 conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \ 6 6 nft_concat_range.sh nft_conntrack_helper.sh \ 7 7 nft_queue.sh nft_meta.sh nf_nat_edemux.sh \ 8 - ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh 8 + ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \ 9 + conntrack_vrf.sh 9 10 10 11 LDLIBS = -lmnl 11 12 TEST_GEN_FILES = nf-queue
+219
tools/testing/selftests/netfilter/conntrack_vrf.sh
··· 1 + #!/bin/sh 2 + 3 + # This script demonstrates interaction of conntrack and vrf. 4 + # The vrf driver calls the netfilter hooks again, with oif/iif 5 + # pointing at the VRF device. 6 + # 7 + # For ingress, this means first iteration has iifname of lower/real 8 + # device. In this script, thats veth0. 9 + # Second iteration is iifname set to vrf device, tvrf in this script. 10 + # 11 + # For egress, this is reversed: first iteration has the vrf device, 12 + # second iteration is done with the lower/real/veth0 device. 13 + # 14 + # test_ct_zone_in demonstrates unexpected change of nftables 15 + # behavior # caused by commit 09e856d54bda5f28 "vrf: Reset skb conntrack 16 + # connection on VRF rcv" 17 + # 18 + # It was possible to assign conntrack zone to a packet (or mark it for 19 + # `notracking`) in the prerouting chain before conntrack, based on real iif. 20 + # 21 + # After the change, the zone assignment is lost and the zone is assigned based 22 + # on the VRF master interface (in case such a rule exists). 23 + # assignment is lost. Instead, assignment based on the `iif` matching 24 + # Thus it is impossible to distinguish packets based on the original 25 + # interface. 26 + # 27 + # test_masquerade_vrf and test_masquerade_veth0 demonstrate the problem 28 + # that was supposed to be fixed by the commit mentioned above to make sure 29 + # that any fix to test case 1 won't break masquerade again. 30 + 31 + ksft_skip=4 32 + 33 + IP0=172.30.30.1 34 + IP1=172.30.30.2 35 + PFXL=30 36 + ret=0 37 + 38 + sfx=$(mktemp -u "XXXXXXXX") 39 + ns0="ns0-$sfx" 40 + ns1="ns1-$sfx" 41 + 42 + cleanup() 43 + { 44 + ip netns pids $ns0 | xargs kill 2>/dev/null 45 + ip netns pids $ns1 | xargs kill 2>/dev/null 46 + 47 + ip netns del $ns0 $ns1 48 + } 49 + 50 + nft --version > /dev/null 2>&1 51 + if [ $? -ne 0 ];then 52 + echo "SKIP: Could not run test without nft tool" 53 + exit $ksft_skip 54 + fi 55 + 56 + ip -Version > /dev/null 2>&1 57 + if [ $? -ne 0 ];then 58 + echo "SKIP: Could not run test without ip tool" 59 + exit $ksft_skip 60 + fi 61 + 62 + ip netns add "$ns0" 63 + if [ $? -ne 0 ];then 64 + echo "SKIP: Could not create net namespace $ns0" 65 + exit $ksft_skip 66 + fi 67 + ip netns add "$ns1" 68 + 69 + trap cleanup EXIT 70 + 71 + ip netns exec $ns0 sysctl -q -w net.ipv4.conf.default.rp_filter=0 72 + ip netns exec $ns0 sysctl -q -w net.ipv4.conf.all.rp_filter=0 73 + ip netns exec $ns0 sysctl -q -w net.ipv4.conf.all.rp_filter=0 74 + 75 + ip link add veth0 netns "$ns0" type veth peer name veth0 netns "$ns1" > /dev/null 2>&1 76 + if [ $? -ne 0 ];then 77 + echo "SKIP: Could not add veth device" 78 + exit $ksft_skip 79 + fi 80 + 81 + ip -net $ns0 li add tvrf type vrf table 9876 82 + if [ $? -ne 0 ];then 83 + echo "SKIP: Could not add vrf device" 84 + exit $ksft_skip 85 + fi 86 + 87 + ip -net $ns0 li set lo up 88 + 89 + ip -net $ns0 li set veth0 master tvrf 90 + ip -net $ns0 li set tvrf up 91 + ip -net $ns0 li set veth0 up 92 + ip -net $ns1 li set veth0 up 93 + 94 + ip -net $ns0 addr add $IP0/$PFXL dev veth0 95 + ip -net $ns1 addr add $IP1/$PFXL dev veth0 96 + 97 + ip netns exec $ns1 iperf3 -s > /dev/null 2>&1& 98 + if [ $? -ne 0 ];then 99 + echo "SKIP: Could not start iperf3" 100 + exit $ksft_skip 101 + fi 102 + 103 + # test vrf ingress handling. 104 + # The incoming connection should be placed in conntrack zone 1, 105 + # as decided by the first iteration of the ruleset. 106 + test_ct_zone_in() 107 + { 108 + ip netns exec $ns0 nft -f - <<EOF 109 + table testct { 110 + chain rawpre { 111 + type filter hook prerouting priority raw; 112 + 113 + iif { veth0, tvrf } counter meta nftrace set 1 114 + iif veth0 counter ct zone set 1 counter return 115 + iif tvrf counter ct zone set 2 counter return 116 + ip protocol icmp counter 117 + notrack counter 118 + } 119 + 120 + chain rawout { 121 + type filter hook output priority raw; 122 + 123 + oif veth0 counter ct zone set 1 counter return 124 + oif tvrf counter ct zone set 2 counter return 125 + notrack counter 126 + } 127 + } 128 + EOF 129 + ip netns exec $ns1 ping -W 1 -c 1 -I veth0 $IP0 > /dev/null 130 + 131 + # should be in zone 1, not zone 2 132 + count=$(ip netns exec $ns0 conntrack -L -s $IP1 -d $IP0 -p icmp --zone 1 2>/dev/null | wc -l) 133 + if [ $count -eq 1 ]; then 134 + echo "PASS: entry found in conntrack zone 1" 135 + else 136 + echo "FAIL: entry not found in conntrack zone 1" 137 + count=$(ip netns exec $ns0 conntrack -L -s $IP1 -d $IP0 -p icmp --zone 2 2> /dev/null | wc -l) 138 + if [ $count -eq 1 ]; then 139 + echo "FAIL: entry found in zone 2 instead" 140 + else 141 + echo "FAIL: entry not in zone 1 or 2, dumping table" 142 + ip netns exec $ns0 conntrack -L 143 + ip netns exec $ns0 nft list ruleset 144 + fi 145 + fi 146 + } 147 + 148 + # add masq rule that gets evaluated w. outif set to vrf device. 149 + # This tests the first iteration of the packet through conntrack, 150 + # oifname is the vrf device. 151 + test_masquerade_vrf() 152 + { 153 + ip netns exec $ns0 conntrack -F 2>/dev/null 154 + 155 + ip netns exec $ns0 nft -f - <<EOF 156 + flush ruleset 157 + table ip nat { 158 + chain postrouting { 159 + type nat hook postrouting priority 0; 160 + # NB: masquerade should always be combined with 'oif(name) bla', 161 + # lack of this is intentional here, we want to exercise double-snat. 162 + ip saddr 172.30.30.0/30 counter masquerade random 163 + } 164 + } 165 + EOF 166 + ip netns exec $ns0 ip vrf exec tvrf iperf3 -t 1 -c $IP1 >/dev/null 167 + if [ $? -ne 0 ]; then 168 + echo "FAIL: iperf3 connect failure with masquerade + sport rewrite on vrf device" 169 + ret=1 170 + return 171 + fi 172 + 173 + # must also check that nat table was evaluated on second (lower device) iteration. 174 + ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2' 175 + if [ $? -eq 0 ]; then 176 + echo "PASS: iperf3 connect with masquerade + sport rewrite on vrf device" 177 + else 178 + echo "FAIL: vrf masq rule has unexpected counter value" 179 + ret=1 180 + fi 181 + } 182 + 183 + # add masq rule that gets evaluated w. outif set to veth device. 184 + # This tests the 2nd iteration of the packet through conntrack, 185 + # oifname is the lower device (veth0 in this case). 186 + test_masquerade_veth() 187 + { 188 + ip netns exec $ns0 conntrack -F 2>/dev/null 189 + ip netns exec $ns0 nft -f - <<EOF 190 + flush ruleset 191 + table ip nat { 192 + chain postrouting { 193 + type nat hook postrouting priority 0; 194 + meta oif veth0 ip saddr 172.30.30.0/30 counter masquerade random 195 + } 196 + } 197 + EOF 198 + ip netns exec $ns0 ip vrf exec tvrf iperf3 -t 1 -c $IP1 > /dev/null 199 + if [ $? -ne 0 ]; then 200 + echo "FAIL: iperf3 connect failure with masquerade + sport rewrite on veth device" 201 + ret=1 202 + return 203 + fi 204 + 205 + # must also check that nat table was evaluated on second (lower device) iteration. 206 + ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2' 207 + if [ $? -eq 0 ]; then 208 + echo "PASS: iperf3 connect with masquerade + sport rewrite on veth device" 209 + else 210 + echo "FAIL: vrf masq rule has unexpected counter value" 211 + ret=1 212 + fi 213 + } 214 + 215 + test_ct_zone_in 216 + test_masquerade_vrf 217 + test_masquerade_veth 218 + 219 + exit $ret