Skip to content

Commit e84945b

Browse files
author
Florian Westphal
committed
selftests: netfilter: query conntrack state to check for port clash resolution
Jakub reported this self test flaking occasionally (fails, but passes on re-run) on debug kernels. This is because the test checks for elapsed time to determine if both connections were established in parallel. Rework this to no longer depend on timing. Use busywait helper to check that both sockets have moved to established state and then query the conntrack engine for the two entries. Reported-by: Jakub Kicinski <kuba@kernel.org> Closes: https://lore.kernel.org/netfilter-devel/20250926163318.40d1a502@kernel.org/ Fixes: 117e149 ("selftests: netfilter: test nat source port clash resolution interaction with tcp early demux") Signed-off-by: Florian Westphal <fw@strlen.de>
1 parent a126ab6 commit e84945b

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

tools/testing/selftests/net/netfilter/nf_nat_edemux.sh

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,31 @@ cleanup()
1717

1818
checktool "socat -h" "run test without socat"
1919
checktool "iptables --version" "run test without iptables"
20+
checktool "conntrack --version" "run test without conntrack"
2021

2122
trap cleanup EXIT
2223

24+
connect_done()
25+
{
26+
local ns="$1"
27+
local port="$2"
28+
29+
ip netns exec "$ns" ss -nt -o state established "dport = :$port" | grep -q "$port"
30+
}
31+
32+
check_ctstate()
33+
{
34+
local ns="$1"
35+
local dp="$2"
36+
37+
if ! ip netns exec "$ns" conntrack --get -s 192.168.1.2 -d 192.168.1.1 -p tcp \
38+
--sport 10000 --dport "$dp" --state ESTABLISHED > /dev/null 2>&1;then
39+
echo "FAIL: Did not find expected state for dport $2"
40+
ip netns exec "$ns" bash -c 'conntrack -L; conntrack -S; ss -nt'
41+
ret=1
42+
fi
43+
}
44+
2345
setup_ns ns1 ns2
2446

2547
# Connect the namespaces using a veth pair
@@ -44,15 +66,18 @@ socatpid=$!
4466
ip netns exec "$ns2" sysctl -q net.ipv4.ip_local_port_range="10000 10000"
4567

4668
# add a virtual IP using DNAT
47-
ip netns exec "$ns2" iptables -t nat -A OUTPUT -d 10.96.0.1/32 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.1:5201
69+
ip netns exec "$ns2" iptables -t nat -A OUTPUT -d 10.96.0.1/32 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.1:5201 || exit 1
4870

4971
# ... and route it to the other namespace
5072
ip netns exec "$ns2" ip route add 10.96.0.1 via 192.168.1.1
5173

52-
# add a persistent connection from the other namespace
53-
ip netns exec "$ns2" socat -t 10 - TCP:192.168.1.1:5201 > /dev/null &
74+
# listener should be up by now, wait if it isn't yet.
75+
wait_local_port_listen "$ns1" 5201 tcp
5476

55-
sleep 1
77+
# add a persistent connection from the other namespace
78+
sleep 10 | ip netns exec "$ns2" socat -t 10 - TCP:192.168.1.1:5201 > /dev/null &
79+
cpid0=$!
80+
busywait "$BUSYWAIT_TIMEOUT" connect_done "$ns2" "5201"
5681

5782
# ip daddr:dport will be rewritten to 192.168.1.1 5201
5883
# NAT must reallocate source port 10000 because
@@ -71,26 +96,25 @@ fi
7196
ip netns exec "$ns1" iptables -t nat -A PREROUTING -p tcp --dport 5202 -j REDIRECT --to-ports 5201
7297
ip netns exec "$ns1" iptables -t nat -A PREROUTING -p tcp --dport 5203 -j REDIRECT --to-ports 5201
7398

74-
sleep 5 | ip netns exec "$ns2" socat -t 5 -u STDIN TCP:192.168.1.1:5202,connect-timeout=5 >/dev/null &
99+
sleep 5 | ip netns exec "$ns2" socat -T 5 -u STDIN TCP:192.168.1.1:5202,connect-timeout=5 >/dev/null &
100+
cpid1=$!
75101

76-
# if connect succeeds, client closes instantly due to EOF on stdin.
77-
# if connect hangs, it will time out after 5s.
78-
echo | ip netns exec "$ns2" socat -t 3 -u STDIN TCP:192.168.1.1:5203,connect-timeout=5 >/dev/null &
102+
sleep 5 | ip netns exec "$ns2" socat -T 5 -u STDIN TCP:192.168.1.1:5203,connect-timeout=5 >/dev/null &
79103
cpid2=$!
80104

81-
time_then=$(date +%s)
82-
wait $cpid2
83-
rv=$?
84-
time_now=$(date +%s)
105+
busywait "$BUSYWAIT_TIMEOUT" connect_done "$ns2" 5202
106+
busywait "$BUSYWAIT_TIMEOUT" connect_done "$ns2" 5203
85107

86-
# Check how much time has elapsed, expectation is for
87-
# 'cpid2' to connect and then exit (and no connect delay).
88-
delta=$((time_now - time_then))
108+
check_ctstate "$ns1" 5202
109+
check_ctstate "$ns1" 5203
89110

90-
if [ $delta -lt 2 ] && [ $rv -eq 0 ]; then
111+
kill $socatpid $cpid0 $cpid1 $cpid2
112+
socatpid=0
113+
114+
if [ $ret -eq 0 ]; then
91115
echo "PASS: could connect to service via redirected ports"
92116
else
93-
echo "FAIL: socat cannot connect to service via redirect ($delta seconds elapsed, returned $rv)"
117+
echo "FAIL: socat cannot connect to service via redirect"
94118
ret=1
95119
fi
96120

0 commit comments

Comments
 (0)