Commit 5bdac418 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: nat: fix icmp id randomization

Sven Auhagen reported that a 2nd ping request will fail if 'fully-random'
mode is used.

Reason is that if no proto information is given, min/max are both 0,
so we set the icmp id to 0 instead of chosing a random value between
0 and 65535.

Update test case as well to catch this, without fix this yields:
[..]
ERROR: cannot ping ns1 from ns2 with ip masquerade fully-random (attempt 2)
ERROR: cannot ping ns1 from ns2 with ipv6 masquerade fully-random (attempt 2)

... becaus 2nd ping clashes with existing 'id 0' icmp conntrack and gets
dropped.

Fixes: 203f2e78 ("netfilter: nat: remove l4proto->unique_tuple")
Reported-by: default avatarSven Auhagen <sven.auhagen@voleatech.de>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 33d1c018
...@@ -415,9 +415,14 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -415,9 +415,14 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple,
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
/* id is same for either direction... */ /* id is same for either direction... */
keyptr = &tuple->src.u.icmp.id; keyptr = &tuple->src.u.icmp.id;
min = range->min_proto.icmp.id; if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) {
range_size = ntohs(range->max_proto.icmp.id) - min = 0;
ntohs(range->min_proto.icmp.id) + 1; range_size = 65536;
} else {
min = ntohs(range->min_proto.icmp.id);
range_size = ntohs(range->max_proto.icmp.id) -
ntohs(range->min_proto.icmp.id) + 1;
}
goto find_free_id; goto find_free_id;
#if IS_ENABLED(CONFIG_NF_CT_PROTO_GRE) #if IS_ENABLED(CONFIG_NF_CT_PROTO_GRE)
case IPPROTO_GRE: case IPPROTO_GRE:
......
...@@ -321,6 +321,7 @@ EOF ...@@ -321,6 +321,7 @@ EOF
test_masquerade6() test_masquerade6()
{ {
local natflags=$1
local lret=0 local lret=0
ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
...@@ -354,13 +355,13 @@ ip netns exec ns0 nft -f - <<EOF ...@@ -354,13 +355,13 @@ ip netns exec ns0 nft -f - <<EOF
table ip6 nat { table ip6 nat {
chain postrouting { chain postrouting {
type nat hook postrouting priority 0; policy accept; type nat hook postrouting priority 0; policy accept;
meta oif veth0 masquerade meta oif veth0 masquerade $natflags
} }
} }
EOF EOF
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echo "ERROR: cannot ping ns1 from ns2 with active ipv6 masquerading" echo "ERROR: cannot ping ns1 from ns2 with active ipv6 masquerade $natflags"
lret=1 lret=1
fi fi
...@@ -397,19 +398,26 @@ EOF ...@@ -397,19 +398,26 @@ EOF
fi fi
done done
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
if [ $? -ne 0 ] ; then
echo "ERROR: cannot ping ns1 from ns2 with active ipv6 masquerade $natflags (attempt 2)"
lret=1
fi
ip netns exec ns0 nft flush chain ip6 nat postrouting ip netns exec ns0 nft flush chain ip6 nat postrouting
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "ERROR: Could not flush ip6 nat postrouting" 1>&2 echo "ERROR: Could not flush ip6 nat postrouting" 1>&2
lret=1 lret=1
fi fi
test $lret -eq 0 && echo "PASS: IPv6 masquerade for ns2" test $lret -eq 0 && echo "PASS: IPv6 masquerade $natflags for ns2"
return $lret return $lret
} }
test_masquerade() test_masquerade()
{ {
local natflags=$1
local lret=0 local lret=0
ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
...@@ -417,7 +425,7 @@ test_masquerade() ...@@ -417,7 +425,7 @@ test_masquerade()
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echo "ERROR: canot ping ns1 from ns2" echo "ERROR: cannot ping ns1 from ns2 $natflags"
lret=1 lret=1
fi fi
...@@ -443,13 +451,13 @@ ip netns exec ns0 nft -f - <<EOF ...@@ -443,13 +451,13 @@ ip netns exec ns0 nft -f - <<EOF
table ip nat { table ip nat {
chain postrouting { chain postrouting {
type nat hook postrouting priority 0; policy accept; type nat hook postrouting priority 0; policy accept;
meta oif veth0 masquerade meta oif veth0 masquerade $natflags
} }
} }
EOF EOF
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
echo "ERROR: cannot ping ns1 from ns2 with active ip masquerading" echo "ERROR: cannot ping ns1 from ns2 with active ip masquere $natflags"
lret=1 lret=1
fi fi
...@@ -485,13 +493,19 @@ EOF ...@@ -485,13 +493,19 @@ EOF
fi fi
done done
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
if [ $? -ne 0 ] ; then
echo "ERROR: cannot ping ns1 from ns2 with active ip masquerade $natflags (attempt 2)"
lret=1
fi
ip netns exec ns0 nft flush chain ip nat postrouting ip netns exec ns0 nft flush chain ip nat postrouting
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "ERROR: Could not flush nat postrouting" 1>&2 echo "ERROR: Could not flush nat postrouting" 1>&2
lret=1 lret=1
fi fi
test $lret -eq 0 && echo "PASS: IP masquerade for ns2" test $lret -eq 0 && echo "PASS: IP masquerade $natflags for ns2"
return $lret return $lret
} }
...@@ -750,8 +764,12 @@ test_local_dnat ...@@ -750,8 +764,12 @@ test_local_dnat
test_local_dnat6 test_local_dnat6
reset_counters reset_counters
test_masquerade test_masquerade ""
test_masquerade6 test_masquerade6 ""
reset_counters
test_masquerade "fully-random"
test_masquerade6 "fully-random"
reset_counters reset_counters
test_redirect test_redirect
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment