From: Florian Westphal Date: Wed, 24 Jun 2026 20:49:28 +0000 (+0200) Subject: tests: shell: add packetpath test for nft ct expectation support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1c4f734eae7c03db45d76afa80f45d576734f7f;p=thirdparty%2Fnftables.git tests: shell: add packetpath test for nft ct expectation support This will fail on kernels that lack 6fb421bd07f1 ("netfilter: nft_ct: expectation timeouts are passed in milliseconds"). On kernels that lack NAT support the test will indicate SKIP. Signed-off-by: Florian Westphal --- diff --git a/tests/shell/testcases/packetpath/ct_expect b/tests/shell/testcases/packetpath/ct_expect new file mode 100755 index 00000000..cc8f5267 --- /dev/null +++ b/tests/shell/testcases/packetpath/ct_expect @@ -0,0 +1,262 @@ +#!/bin/bash + +# NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat) + +. $NFT_TEST_LIBRARY_FILE + +set -x + +rc=1 + +cleanup() +{ + set +e + for i in $R $C $S;do + kill $(ip netns pid $i) 2>/dev/null + ip netns del $i + done + + exit $rc +} +trap cleanup EXIT + +dump_expect_table() { + ip netns exec "$R" conntrack --family ipv6 -L expect + ip netns exec "$R" conntrack --family ipv4 -L expect +} + +assert_failout() +{ + ip netns exec $R $NFT list ruleset + ip netns exec $R conntrack -L + dump_expect_table +} + +do_connect() { + local ns="$1" + local addr="$2" + local port="$3" + + ip netns exec "$ns" socat -u STDIN TCP-CONNECT:$addr:$port,connect-timeout=1 < /dev/null +} + +connect_fail() { + local ns="$1" + local addr="$2" + local port="$3" + local msg="$4" + + do_connect "$ns" "$addr" "$port" + assert_fail "connect from $ns to $addr:$port $msg" +} + +connect_ok() { + local ns="$1" + local addr="$2" + local port="$3" + local msg="$4" + + do_connect "$ns" "$addr" "$port" + assert_pass "connect from $ns to $addr:$port $msg" +} + +test_expect() { + local ip_cr="$1" + local ip_sr="$2" + local msg="$3" + + echo check port is closed from outside. + connect_fail "$S" "$ip_cr" 1234 + + echo "Test: expectation via ruleset$msg" + + echo control port should be open. + connect_ok "$C" "$ip_sr" 2222 "$msg" + + dump_expect_table + + echo expected port. Should now pass. + connect_ok "$S" "$ip_cr" 1234 "$msg" + + echo one expectation max, expect fail. + connect_fail "$S" "$ip_cr" 1234 "$msg" +} + +test_timeout() { + echo "Test: expectation auto-timeout" + # control port - this should be open. + connect_ok "$C" "$ip4_sr" 2222 + connect_ok "$C" "[$ip6_sr]" 2222 + + dump_expect_table + + # timeout. We 'bundle' ipv4 and ipv6 test here. + sleep 6 + + dump_expect_table + + echo "expect failures" + connect_fail "$S" "$ip4_cr" 1234 + connect_fail "$S" "[$ip6_cr]" 1234 +} + +rnd=$(mktemp -u XXXXXXXX) +R="ns-router-$rnd" +C="ns-client-$rnd" +S="ns-server-$rnd" + +ip6_sr=dead:d8:ff:22::1 +ip6_cr=dead:d8:ff:21::2 +ip6_rs=dead:d8:ff:22::fffe +ip6_rc=dead:d8:ff:21::fffe + +ip4_sr=10.1.22.1 +ip4_cr=10.1.21.2 +ip4_rs=10.1.22.99 +ip4_rc=10.1.21.99 + +set -e +ip netns add $R +ip netns add $S +ip netns add $C +ip -net $S link set lo up +ip -net $R link set lo up +ip -net $C link set lo up +ip netns exec $R sysctl -wq net.ipv4.ip_forward=1 +ip netns exec $R sysctl -wq net.ipv6.conf.all.forwarding=1 + +ip link add s_r netns $S type veth peer name r_s netns $R +ip link add c_r netns $C type veth peer name r_c netns $R +ip -net $S link set s_r up +ip -net $R link set r_s up +ip -net $R link set r_c up +ip -net $C link set c_r up + +ip -net $S addr add ${ip6_sr}/64 dev s_r nodad +ip -net $C addr add ${ip6_cr}/64 dev c_r nodad +ip -net $R addr add ${ip6_rs}/64 dev r_s nodad +ip -net $R addr add ${ip6_rc}/64 dev r_c nodad +ip -net $C route add ${ip6_rs}/64 via ${ip6_rc} dev c_r +ip -net $S route add ${ip6_rc}/64 via ${ip6_rs} dev s_r +assert_pass "topo initialization" + +ip -net $S addr add ${ip4_sr}/24 dev s_r +ip -net $C addr add ${ip4_cr}/24 dev c_r +ip -net $R addr add ${ip4_rs}/24 dev r_s +ip -net $R addr add ${ip4_rc}/24 dev r_c + +ip -net $C route add 10.1.22.0/24 via ${ip4_rc} dev c_r +ip -net $S route add 10.1.21.0/24 via ${ip4_rs} dev s_r + +ip netns exec "$C" ping -q -c 1 "$ip4_sr" +ip netns exec "$C" ping -q -c 1 "$ip6_sr" + +timeout 20 ip netns exec "$S" socat TCP6-LISTEN:2222,ipv6only=1,fork,reuseaddr PIPE & +timeout 20 ip netns exec "$S" socat TCP4-LISTEN:2222,fork,reuseaddr PIPE & +timeout 20 ip netns exec "$C" socat TCP6-LISTEN:1234,ipv6only=1,fork,reuseaddr PIPE & +timeout 20 ip netns exec "$C" socat TCP4-LISTEN:1234,fork,reuseaddr PIPE & +wait_local_port_listen $S 2222 tcp +wait_local_port_listen $C 1234 tcp + +ip netns exec $R $NFT -f - <<-EOF +flush ruleset +table inet t { + ct expectation ctexpect4 { + protocol tcp + dport 1234 + timeout 5s + size 1 + l3proto ip + } + + ct expectation ctexpect6 { + protocol tcp + dport 1234 + timeout 5s + size 1 + l3proto ip6 + } + + chain c { + type filter hook forward priority filter; policy drop; + ct state established accept + meta l4proto tcp ct state related counter accept + meta iifname r_c ct state new jump { + tcp dport 2222 counter ct expectation set meta nfproto map { ipv4 : ctexpect4, ipv6 : ctexpect6 } counter accept + counter accept + } + meta l4proto tcp counter reject with tcp reset + meta l4proto { icmp, icmpv6 } accept + } +} +EOF + +ip netns exec "$C" ping -q -c 1 "$ip4_sr" +ip netns exec "$C" ping -q -c 1 "$ip6_sr" + +set +e +echo check port is closed from outside. +connect_fail "$S" "$ip4_cr" 1234 +connect_fail "$S" "[$ip6_cr]" 1234 + +test_expect "$ip4_cr" "$ip4_sr" "" +test_expect "[$ip6_cr]" "[$ip6_sr]" "" + +ip netns exec $R conntrack -F +test_timeout + +set -e +ip netns exec $R $NFT -f - <<-EOF +flush ruleset +table inet t { + ct expectation ctexpect4 { + protocol tcp + dport 1234 + timeout 5s + size 1 + l3proto ip + } + + ct expectation ctexpect6 { + protocol tcp + dport 1234 + timeout 5s + size 1 + l3proto ip6 + } + chain c { + type filter hook forward priority filter; policy drop; + ct state established accept + meta l4proto tcp ct state related counter accept + meta iifname r_c ct state new accept + meta l4proto tcp counter reject with tcp reset + meta l4proto { icmp, icmpv6 } accept + } + + chain masq { + type nat hook postrouting priority srcnat; policy accept; + meta oifname "r_s" counter masquerade + } + + chain e { + type filter hook postrouting priority 50000 ; policy accept; + meta iifname r_c ct state new jump { + tcp dport 2222 counter ct expectation set meta nfproto map { ipv4 : ctexpect4, ipv6 : ctexpect6 } counter accept + counter accept + } + } +} +EOF + +ip netns exec $R conntrack -F +echo "Test: conntrack expectation with masquerade" +set +e + +# Skip here, this is a kernel bug / missing feature we can't +# test for. +rc=77 +test_expect "$ip4_rs" "$ip4_sr" " with masquerade" +test_expect "[$ip6_rs]" "[$ip6_sr]" " with masquerade" + +ip netns exec "$R" conntrack -L +rc=0 diff --git a/tests/shell/testcases/packetpath/dumps/ct_expect.nodump b/tests/shell/testcases/packetpath/dumps/ct_expect.nodump new file mode 100644 index 00000000..e69de29b