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

selftests: netfilter: Test reverse path filtering

Test reverse path (filter) matches in iptables, ip6tables and nftables.
Both with a regular interface and a VRF.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>

authored by

Phil Sutter and committed by
Florian Westphal
6e31ce83 739cfa34

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