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

selftests: netfilter: check icmp pkttoobig errors are set as related

When an icmp error such as pkttoobig is received, conntrack checks
if the "inner" header (header of packet that did not fit link mtu)
is matches an existing connection, and, if so, sets that packet as
being related to the conntrack entry it found.

It was recently reported that this "related" setting also works
if the inner header is from another, different connection (i.e.,
artificial/forged icmp error).

Add a test, followup patch will add additional "inner dst matches
outer dst in reverse direction" check before setting related state.

Link: https://www.synacktiv.com/posts/systems/icmp-reachable.html
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
becf2319 ed0de45a

+284 -1
+1 -1
tools/testing/selftests/netfilter/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 # Makefile for netfilter selftests 3 3 4 - TEST_PROGS := nft_trans_stress.sh nft_nat.sh 4 + TEST_PROGS := nft_trans_stress.sh nft_nat.sh conntrack_icmp_related.sh 5 5 6 6 include ../lib.mk
+283
tools/testing/selftests/netfilter/conntrack_icmp_related.sh
··· 1 + #!/bin/bash 2 + # 3 + # check that ICMP df-needed/pkttoobig icmp are set are set as related 4 + # state 5 + # 6 + # Setup is: 7 + # 8 + # nsclient1 -> nsrouter1 -> nsrouter2 -> nsclient2 9 + # MTU 1500, except for nsrouter2 <-> nsclient2 link (1280). 10 + # ping nsclient2 from nsclient1, checking that conntrack did set RELATED 11 + # 'fragmentation needed' icmp packet. 12 + # 13 + # In addition, nsrouter1 will perform IP masquerading, i.e. also 14 + # check the icmp errors are propagated to the correct host as per 15 + # nat of "established" icmp-echo "connection". 16 + 17 + # Kselftest framework requirement - SKIP code is 4. 18 + ksft_skip=4 19 + ret=0 20 + 21 + nft --version > /dev/null 2>&1 22 + if [ $? -ne 0 ];then 23 + echo "SKIP: Could not run test without nft tool" 24 + exit $ksft_skip 25 + fi 26 + 27 + ip -Version > /dev/null 2>&1 28 + if [ $? -ne 0 ];then 29 + echo "SKIP: Could not run test without ip tool" 30 + exit $ksft_skip 31 + fi 32 + 33 + cleanup() { 34 + for i in 1 2;do ip netns del nsclient$i;done 35 + for i in 1 2;do ip netns del nsrouter$i;done 36 + } 37 + 38 + ipv4() { 39 + echo -n 192.168.$1.2 40 + } 41 + 42 + ipv6 () { 43 + echo -n dead:$1::2 44 + } 45 + 46 + check_counter() 47 + { 48 + ns=$1 49 + name=$2 50 + expect=$3 51 + local lret=0 52 + 53 + cnt=$(ip netns exec $ns nft list counter inet filter "$name" | grep -q "$expect") 54 + if [ $? -ne 0 ]; then 55 + echo "ERROR: counter $name in $ns has unexpected value (expected $expect)" 1>&2 56 + ip netns exec $ns nft list counter inet filter "$name" 1>&2 57 + lret=1 58 + fi 59 + 60 + return $lret 61 + } 62 + 63 + check_unknown() 64 + { 65 + expect="packets 0 bytes 0" 66 + for n in nsclient1 nsclient2 nsrouter1 nsrouter2; do 67 + check_counter $n "unknown" "$expect" 68 + if [ $? -ne 0 ] ;then 69 + return 1 70 + fi 71 + done 72 + 73 + return 0 74 + } 75 + 76 + for n in nsclient1 nsclient2 nsrouter1 nsrouter2; do 77 + ip netns add $n 78 + ip -net $n link set lo up 79 + done 80 + 81 + DEV=veth0 82 + ip link add $DEV netns nsclient1 type veth peer name eth1 netns nsrouter1 83 + DEV=veth0 84 + ip link add $DEV netns nsclient2 type veth peer name eth1 netns nsrouter2 85 + 86 + DEV=veth0 87 + ip link add $DEV netns nsrouter1 type veth peer name eth2 netns nsrouter2 88 + 89 + DEV=veth0 90 + for i in 1 2; do 91 + ip -net nsclient$i link set $DEV up 92 + ip -net nsclient$i addr add $(ipv4 $i)/24 dev $DEV 93 + ip -net nsclient$i addr add $(ipv6 $i)/64 dev $DEV 94 + done 95 + 96 + ip -net nsrouter1 link set eth1 up 97 + ip -net nsrouter1 link set veth0 up 98 + 99 + ip -net nsrouter2 link set eth1 up 100 + ip -net nsrouter2 link set eth2 up 101 + 102 + ip -net nsclient1 route add default via 192.168.1.1 103 + ip -net nsclient1 -6 route add default via dead:1::1 104 + 105 + ip -net nsclient2 route add default via 192.168.2.1 106 + ip -net nsclient2 route add default via dead:2::1 107 + 108 + i=3 109 + ip -net nsrouter1 addr add 192.168.1.1/24 dev eth1 110 + ip -net nsrouter1 addr add 192.168.3.1/24 dev veth0 111 + ip -net nsrouter1 addr add dead:1::1/64 dev eth1 112 + ip -net nsrouter1 addr add dead:3::1/64 dev veth0 113 + ip -net nsrouter1 route add default via 192.168.3.10 114 + ip -net nsrouter1 -6 route add default via dead:3::10 115 + 116 + ip -net nsrouter2 addr add 192.168.2.1/24 dev eth1 117 + ip -net nsrouter2 addr add 192.168.3.10/24 dev eth2 118 + ip -net nsrouter2 addr add dead:2::1/64 dev eth1 119 + ip -net nsrouter2 addr add dead:3::10/64 dev eth2 120 + ip -net nsrouter2 route add default via 192.168.3.1 121 + ip -net nsrouter2 route add default via dead:3::1 122 + 123 + sleep 2 124 + for i in 4 6; do 125 + ip netns exec nsrouter1 sysctl -q net.ipv$i.conf.all.forwarding=1 126 + ip netns exec nsrouter2 sysctl -q net.ipv$i.conf.all.forwarding=1 127 + done 128 + 129 + for netns in nsrouter1 nsrouter2; do 130 + ip netns exec $netns nft -f - <<EOF 131 + table inet filter { 132 + counter unknown { } 133 + counter related { } 134 + chain forward { 135 + type filter hook forward priority 0; policy accept; 136 + meta l4proto icmpv6 icmpv6 type "packet-too-big" ct state "related" counter name "related" accept 137 + meta l4proto icmp icmp type "destination-unreachable" ct state "related" counter name "related" accept 138 + meta l4proto { icmp, icmpv6 } ct state new,established accept 139 + counter name "unknown" drop 140 + } 141 + } 142 + EOF 143 + done 144 + 145 + ip netns exec nsclient1 nft -f - <<EOF 146 + table inet filter { 147 + counter unknown { } 148 + counter related { } 149 + chain input { 150 + type filter hook input priority 0; policy accept; 151 + meta l4proto { icmp, icmpv6 } ct state established,untracked accept 152 + 153 + meta l4proto { icmp, icmpv6 } ct state "related" counter name "related" accept 154 + counter name "unknown" drop 155 + } 156 + } 157 + EOF 158 + 159 + ip netns exec nsclient2 nft -f - <<EOF 160 + table inet filter { 161 + counter unknown { } 162 + counter new { } 163 + counter established { } 164 + 165 + chain input { 166 + type filter hook input priority 0; policy accept; 167 + meta l4proto { icmp, icmpv6 } ct state established,untracked accept 168 + 169 + meta l4proto { icmp, icmpv6 } ct state "new" counter name "new" accept 170 + meta l4proto { icmp, icmpv6 } ct state "established" counter name "established" accept 171 + counter name "unknown" drop 172 + } 173 + chain output { 174 + type filter hook output priority 0; policy accept; 175 + meta l4proto { icmp, icmpv6 } ct state established,untracked accept 176 + 177 + meta l4proto { icmp, icmpv6 } ct state "new" counter name "new" 178 + meta l4proto { icmp, icmpv6 } ct state "established" counter name "established" 179 + counter name "unknown" drop 180 + } 181 + } 182 + EOF 183 + 184 + 185 + # make sure NAT core rewrites adress of icmp error if nat is used according to 186 + # conntrack nat information (icmp error will be directed at nsrouter1 address, 187 + # but it needs to be routed to nsclient1 address). 188 + ip netns exec nsrouter1 nft -f - <<EOF 189 + table ip nat { 190 + chain postrouting { 191 + type nat hook postrouting priority 0; policy accept; 192 + ip protocol icmp oifname "veth0" counter masquerade 193 + } 194 + } 195 + table ip6 nat { 196 + chain postrouting { 197 + type nat hook postrouting priority 0; policy accept; 198 + ip6 nexthdr icmpv6 oifname "veth0" counter masquerade 199 + } 200 + } 201 + EOF 202 + 203 + ip netns exec nsrouter2 ip link set eth1 mtu 1280 204 + ip netns exec nsclient2 ip link set veth0 mtu 1280 205 + sleep 1 206 + 207 + ip netns exec nsclient1 ping -c 1 -s 1000 -q -M do 192.168.2.2 >/dev/null 208 + if [ $? -ne 0 ]; then 209 + echo "ERROR: netns ip routing/connectivity broken" 1>&2 210 + cleanup 211 + exit 1 212 + fi 213 + ip netns exec nsclient1 ping6 -q -c 1 -s 1000 dead:2::2 >/dev/null 214 + if [ $? -ne 0 ]; then 215 + echo "ERROR: netns ipv6 routing/connectivity broken" 1>&2 216 + cleanup 217 + exit 1 218 + fi 219 + 220 + check_unknown 221 + if [ $? -ne 0 ]; then 222 + ret=1 223 + fi 224 + 225 + expect="packets 0 bytes 0" 226 + for netns in nsrouter1 nsrouter2 nsclient1;do 227 + check_counter "$netns" "related" "$expect" 228 + if [ $? -ne 0 ]; then 229 + ret=1 230 + fi 231 + done 232 + 233 + expect="packets 2 bytes 2076" 234 + check_counter nsclient2 "new" "$expect" 235 + if [ $? -ne 0 ]; then 236 + ret=1 237 + fi 238 + 239 + ip netns exec nsclient1 ping -q -c 1 -s 1300 -M do 192.168.2.2 > /dev/null 240 + if [ $? -eq 0 ]; then 241 + echo "ERROR: ping should have failed with PMTU too big error" 1>&2 242 + ret=1 243 + fi 244 + 245 + # nsrouter2 should have generated the icmp error, so 246 + # related counter should be 0 (its in forward). 247 + expect="packets 0 bytes 0" 248 + check_counter "nsrouter2" "related" "$expect" 249 + if [ $? -ne 0 ]; then 250 + ret=1 251 + fi 252 + 253 + # but nsrouter1 should have seen it, same for nsclient1. 254 + expect="packets 1 bytes 576" 255 + for netns in nsrouter1 nsclient1;do 256 + check_counter "$netns" "related" "$expect" 257 + if [ $? -ne 0 ]; then 258 + ret=1 259 + fi 260 + done 261 + 262 + ip netns exec nsclient1 ping6 -c 1 -s 1300 dead:2::2 > /dev/null 263 + if [ $? -eq 0 ]; then 264 + echo "ERROR: ping6 should have failed with PMTU too big error" 1>&2 265 + ret=1 266 + fi 267 + 268 + expect="packets 2 bytes 1856" 269 + for netns in nsrouter1 nsclient1;do 270 + check_counter "$netns" "related" "$expect" 271 + if [ $? -ne 0 ]; then 272 + ret=1 273 + fi 274 + done 275 + 276 + if [ $ret -eq 0 ];then 277 + echo "PASS: icmp mtu error had RELATED state" 278 + else 279 + echo "ERROR: icmp error RELATED state test has failed" 280 + fi 281 + 282 + cleanup 283 + exit $ret