Skip to content

Commit e306e37

Browse files
Florian Westphalummakynes
authored andcommitted
kselftest: add test for nfqueue induced conntrack race
The netfilter race happens when two packets with the same tuple are DNATed and enqueued with nfqueue in the postrouting hook. Once one of the packet is reinjected it may be DNATed again to a different destination, but the conntrack entry remains the same and the return packet was dropped. Based on earlier patch from Antonio Ojea. Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1766 Co-developed-by: Antonio Ojea <aojea@google.com> Signed-off-by: Antonio Ojea <aojea@google.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 8af79d3 commit e306e37

File tree

1 file changed

+91
-1
lines changed

1 file changed

+91
-1
lines changed

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

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ modprobe -q sctp
3131

3232
trap cleanup EXIT
3333

34-
setup_ns ns1 ns2 nsrouter
34+
setup_ns ns1 ns2 ns3 nsrouter
3535

3636
TMPFILE0=$(mktemp)
3737
TMPFILE1=$(mktemp)
@@ -48,6 +48,7 @@ if ! ip link add veth0 netns "$nsrouter" type veth peer name eth0 netns "$ns1" >
4848
exit $ksft_skip
4949
fi
5050
ip link add veth1 netns "$nsrouter" type veth peer name eth0 netns "$ns2"
51+
ip link add veth2 netns "$nsrouter" type veth peer name eth0 netns "$ns3"
5152

5253
ip -net "$nsrouter" link set veth0 up
5354
ip -net "$nsrouter" addr add 10.0.1.1/24 dev veth0
@@ -57,8 +58,13 @@ ip -net "$nsrouter" link set veth1 up
5758
ip -net "$nsrouter" addr add 10.0.2.1/24 dev veth1
5859
ip -net "$nsrouter" addr add dead:2::1/64 dev veth1 nodad
5960

61+
ip -net "$nsrouter" link set veth2 up
62+
ip -net "$nsrouter" addr add 10.0.3.1/24 dev veth2
63+
ip -net "$nsrouter" addr add dead:3::1/64 dev veth2 nodad
64+
6065
ip -net "$ns1" link set eth0 up
6166
ip -net "$ns2" link set eth0 up
67+
ip -net "$ns3" link set eth0 up
6268

6369
ip -net "$ns1" addr add 10.0.1.99/24 dev eth0
6470
ip -net "$ns1" addr add dead:1::99/64 dev eth0 nodad
@@ -70,6 +76,11 @@ ip -net "$ns2" addr add dead:2::99/64 dev eth0 nodad
7076
ip -net "$ns2" route add default via 10.0.2.1
7177
ip -net "$ns2" route add default via dead:2::1
7278

79+
ip -net "$ns3" addr add 10.0.3.99/24 dev eth0
80+
ip -net "$ns3" addr add dead:3::99/64 dev eth0 nodad
81+
ip -net "$ns3" route add default via 10.0.3.1
82+
ip -net "$ns3" route add default via dead:3::1
83+
7384
load_ruleset() {
7485
local name=$1
7586
local prio=$2
@@ -473,6 +484,83 @@ EOF
473484
check_output_files "$TMPINPUT" "$TMPFILE1" "sctp output"
474485
}
475486

487+
udp_listener_ready()
488+
{
489+
ss -S -N "$1" -uln -o "sport = :12345" | grep -q 12345
490+
}
491+
492+
output_files_written()
493+
{
494+
test -s "$1" && test -s "$2"
495+
}
496+
497+
test_udp_ct_race()
498+
{
499+
ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
500+
flush ruleset
501+
table inet udpq {
502+
chain prerouting {
503+
type nat hook prerouting priority dstnat - 5; policy accept;
504+
ip daddr 10.6.6.6 udp dport 12345 counter dnat to numgen inc mod 2 map { 0 : 10.0.2.99, 1 : 10.0.3.99 }
505+
}
506+
chain postrouting {
507+
type filter hook postrouting priority srcnat - 5; policy accept;
508+
udp dport 12345 counter queue num 12
509+
}
510+
}
511+
EOF
512+
:> "$TMPFILE1"
513+
:> "$TMPFILE2"
514+
515+
timeout 10 ip netns exec "$ns2" socat UDP-LISTEN:12345,fork OPEN:"$TMPFILE1",trunc &
516+
local rpid1=$!
517+
518+
timeout 10 ip netns exec "$ns3" socat UDP-LISTEN:12345,fork OPEN:"$TMPFILE2",trunc &
519+
local rpid2=$!
520+
521+
ip netns exec "$nsrouter" ./nf_queue -q 12 -d 1000 &
522+
local nfqpid=$!
523+
524+
busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns2"
525+
busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns3"
526+
busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 12
527+
528+
# Send two packets, one should end up in ns1, other in ns2.
529+
# This is because nfqueue will delay packet for long enough so that
530+
# second packet will not find existing conntrack entry.
531+
echo "Packet 1" | ip netns exec "$ns1" socat STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221
532+
echo "Packet 2" | ip netns exec "$ns1" socat STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221
533+
534+
busywait 10000 output_files_written "$TMPFILE1" "$TMPFILE2"
535+
536+
kill "$nfqpid"
537+
538+
if ! ip netns exec "$nsrouter" bash -c 'conntrack -L -p udp --dport 12345 2>/dev/null | wc -l | grep -q "^1"'; then
539+
echo "FAIL: Expected One udp conntrack entry"
540+
ip netns exec "$nsrouter" conntrack -L -p udp --dport 12345
541+
ret=1
542+
fi
543+
544+
if ! ip netns exec "$nsrouter" nft delete table inet udpq; then
545+
echo "FAIL: Could not delete udpq table"
546+
ret=1
547+
return
548+
fi
549+
550+
NUMLINES1=$(wc -l < "$TMPFILE1")
551+
NUMLINES2=$(wc -l < "$TMPFILE2")
552+
553+
if [ "$NUMLINES1" -ne 1 ] || [ "$NUMLINES2" -ne 1 ]; then
554+
ret=1
555+
echo "FAIL: uneven udp packet distribution: $NUMLINES1 $NUMLINES2"
556+
echo -n "$TMPFILE1: ";cat "$TMPFILE1"
557+
echo -n "$TMPFILE2: ";cat "$TMPFILE2"
558+
return
559+
fi
560+
561+
echo "PASS: both udp receivers got one packet each"
562+
}
563+
476564
test_queue_removal()
477565
{
478566
read tainted_then < /proc/sys/kernel/tainted
@@ -512,6 +600,7 @@ EOF
512600
ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
513601
ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
514602
ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
603+
ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth2.forwarding=1 > /dev/null
515604

516605
load_ruleset "filter" 0
517606

@@ -549,6 +638,7 @@ test_tcp_localhost_connectclose
549638
test_tcp_localhost_requeue
550639
test_sctp_forward
551640
test_sctp_output
641+
test_udp_ct_race
552642

553643
# should be last, adds vrf device in ns1 and changes routes
554644
test_icmp_vrf

0 commit comments

Comments
 (0)