1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# return code to signal skipped test 5ksft_skip=4 6 7# search for legacy iptables (it uses the xtables extensions 8if iptables-legacy --version >/dev/null 2>&1; then 9 iptables='iptables-legacy' 10elif iptables --version >/dev/null 2>&1; then 11 iptables='iptables' 12else 13 iptables='' 14fi 15 16if ip6tables-legacy --version >/dev/null 2>&1; then 17 ip6tables='ip6tables-legacy' 18elif ip6tables --version >/dev/null 2>&1; then 19 ip6tables='ip6tables' 20else 21 ip6tables='' 22fi 23 24if nft --version >/dev/null 2>&1; then 25 nft='nft' 26else 27 nft='' 28fi 29 30if [ -z "$iptables$ip6tables$nft" ]; then 31 echo "SKIP: Test needs iptables, ip6tables or nft" 32 exit $ksft_skip 33fi 34 35sfx=$(mktemp -u "XXXXXXXX") 36ns1="ns1-$sfx" 37ns2="ns2-$sfx" 38trap "ip netns del $ns1; ip netns del $ns2" EXIT 39 40# create two netns, disable rp_filter in ns2 and 41# keep IPv6 address when moving into VRF 42ip netns add "$ns1" 43ip netns add "$ns2" 44ip netns exec "$ns2" sysctl -q net.ipv4.conf.all.rp_filter=0 45ip netns exec "$ns2" sysctl -q net.ipv4.conf.default.rp_filter=0 46ip netns exec "$ns2" sysctl -q net.ipv6.conf.all.keep_addr_on_down=1 47 48# a standard connection between the netns, should not trigger rp filter 49ip -net "$ns1" link add v0 type veth peer name v0 netns "$ns2" 50ip -net "$ns1" link set v0 up; ip -net "$ns2" link set v0 up 51ip -net "$ns1" a a 192.168.23.2/24 dev v0 52ip -net "$ns2" a a 192.168.23.1/24 dev v0 53ip -net "$ns1" a a fec0:23::2/64 dev v0 nodad 54ip -net "$ns2" a a fec0:23::1/64 dev v0 nodad 55 56# rp filter testing: ns1 sends packets via v0 which ns2 would route back via d0 57ip -net "$ns2" link add d0 type dummy 58ip -net "$ns2" link set d0 up 59ip -net "$ns1" a a 192.168.42.2/24 dev v0 60ip -net "$ns2" a a 192.168.42.1/24 dev d0 61ip -net "$ns1" a a fec0:42::2/64 dev v0 nodad 62ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad 63 64# firewall matches to test 65[ -n "$iptables" ] && ip netns exec "$ns2" \ 66 "$iptables" -t raw -A PREROUTING -s 192.168.0.0/16 -m rpfilter 67[ -n "$ip6tables" ] && ip netns exec "$ns2" \ 68 "$ip6tables" -t raw -A PREROUTING -s fec0::/16 -m rpfilter 69[ -n "$nft" ] && ip netns exec "$ns2" $nft -f - <<EOF 70table inet t { 71 chain c { 72 type filter hook prerouting priority raw; 73 ip saddr 192.168.0.0/16 fib saddr . iif oif exists counter 74 ip6 saddr fec0::/16 fib saddr . iif oif exists counter 75 } 76} 77EOF 78 79die() { 80 echo "FAIL: $*" 81 #ip netns exec "$ns2" "$iptables" -t raw -vS 82 #ip netns exec "$ns2" "$ip6tables" -t raw -vS 83 #ip netns exec "$ns2" nft list ruleset 84 exit 1 85} 86 87# check rule counters, return true if rule did not match 88ipt_zero_rule() { # (command) 89 [ -n "$1" ] || return 0 90 ip netns exec "$ns2" "$1" -t raw -vS | grep -q -- "-m rpfilter -c 0 0" 91} 92nft_zero_rule() { # (family) 93 [ -n "$nft" ] || return 0 94 ip netns exec "$ns2" "$nft" list chain inet t c | \ 95 grep -q "$1 saddr .* counter packets 0 bytes 0" 96} 97 98netns_ping() { # (netns, args...) 99 local netns="$1" 100 shift 101 ip netns exec "$netns" ping -q -c 1 -W 1 "$@" >/dev/null 102} 103 104testrun() { 105 # clear counters first 106 [ -n "$iptables" ] && ip netns exec "$ns2" "$iptables" -t raw -Z 107 [ -n "$ip6tables" ] && ip netns exec "$ns2" "$ip6tables" -t raw -Z 108 if [ -n "$nft" ]; then 109 ( 110 echo "delete table inet t"; 111 ip netns exec "$ns2" $nft -s list table inet t; 112 ) | ip netns exec "$ns2" $nft -f - 113 fi 114 115 # test 1: martian traffic should fail rpfilter matches 116 netns_ping "$ns1" -I v0 192.168.42.1 && \ 117 die "martian ping 192.168.42.1 succeeded" 118 netns_ping "$ns1" -I v0 fec0:42::1 && \ 119 die "martian ping fec0:42::1 succeeded" 120 121 ipt_zero_rule "$iptables" || die "iptables matched martian" 122 ipt_zero_rule "$ip6tables" || die "ip6tables matched martian" 123 nft_zero_rule ip || die "nft IPv4 matched martian" 124 nft_zero_rule ip6 || die "nft IPv6 matched martian" 125 126 # test 2: rpfilter match should pass for regular traffic 127 netns_ping "$ns1" 192.168.23.1 || \ 128 die "regular ping 192.168.23.1 failed" 129 netns_ping "$ns1" fec0:23::1 || \ 130 die "regular ping fec0:23::1 failed" 131 132 ipt_zero_rule "$iptables" && die "iptables match not effective" 133 ipt_zero_rule "$ip6tables" && die "ip6tables match not effective" 134 nft_zero_rule ip && die "nft IPv4 match not effective" 135 nft_zero_rule ip6 && die "nft IPv6 match not effective" 136 137} 138 139testrun 140 141# repeat test with vrf device in $ns2 142ip -net "$ns2" link add vrf0 type vrf table 10 143ip -net "$ns2" link set vrf0 up 144ip -net "$ns2" link set v0 master vrf0 145 146testrun 147 148echo "PASS: netfilter reverse path match works as intended" 149exit 0 150