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