mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 13:06:59 +02:00
netfilter pull request 25-06-05
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEjF9xRqF1emXiQiqU1w0aZmrPKyEFAmhBWmkACgkQ1w0aZmrP KyFWpxAAqMGJCK2pp09/3lUJNaPfGR0HJGTk9LAhWpMWoTvwJfnJYZ5PQzMcOpbZ d4lZoYiJph3eo0FofJXR1wzNvj2WeBStJCpiInd618QoxZkEVG2UN+5K4h64UVKo Hq/Zc8wjGfQ48KMP5AlliM0W/ES9c0R+5E34mn6Arid9Yoj1cnFTVEl1M1bvQ+lK wb91JtYbeXbUxMogRQ05fpSSK+lqthwHx4BlzX39eRrywHWIvVHaJaJZrbfjnR6K 9uSW6ff1t5ONuHDfv+jHJyOMgfSMoy2z219sMxnu4JA8JEJhqDLL6coCHLmG1tRH we5cUtK8g6vkC0k2w13N93s2B9RVZkBC8LnK0Hqijznhgqwn+2iHGBLnsYoyT0kp YtZw6uZXlPZBFM2rtdefznV4KhGGvWzURUQPd+XHKYMasnl4SWrVG8HXPlrbSJKH jpAY1ED3d7ehezzRvIIJq14CixrqMN+72AwmsXkQm/H4qO58/5RpV/keGDbIOMjK YtyITxDqLxS8iRKn7yqmhP9XOl8ys91oH4qt0Ro5yqMnQgjZ7/102vkGnF4BUA/i VpEVxtQ24w0DiKe4Slviw97JopDtlgb4EsfZ70VbbJ3HUndM2eXYbjO13byngvCv yRimI3KzCXnLkPbUKyi6uy4ooTClYN4bvizfQQGFjKb16hj3dkY= =CFYz -----END PGP SIGNATURE----- Merge tag 'nf-25-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Zero out the remainder in nft_pipapo AVX2 implementation, otherwise next lookup could bogusly report a mismatch. This is followed by two patches to update nft_pipapo selftests to cover for the previous bug. From Florian Westphal. 2) Check for reverse tuple too in case of esoteric NAT collisions for UDP traffic and extend selftest coverage. Also from Florian. netfilter pull request 25-06-05 * tag 'nf-25-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: selftests: netfilter: nft_nat.sh: add test for reverse clash with nat netfilter: nf_nat: also check reverse tuple to obtain clashing entry selftests: netfilter: nft_concat_range.sh: add datapath check for map fill bug selftests: netfilter: nft_concat_range.sh: prefer per element counters for testing netfilter: nf_set_pipapo_avx2: fix initial map fill ==================== Link: https://patch.msgid.link/20250605085735.52205-1-pablo@netfilter.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
edafd348a0
|
|
@ -248,7 +248,7 @@ static noinline bool
|
|||
nf_nat_used_tuple_new(const struct nf_conntrack_tuple *tuple,
|
||||
const struct nf_conn *ignored_ct)
|
||||
{
|
||||
static const unsigned long uses_nat = IPS_NAT_MASK | IPS_SEQ_ADJUST_BIT;
|
||||
static const unsigned long uses_nat = IPS_NAT_MASK | IPS_SEQ_ADJUST;
|
||||
const struct nf_conntrack_tuple_hash *thash;
|
||||
const struct nf_conntrack_zone *zone;
|
||||
struct nf_conn *ct;
|
||||
|
|
@ -287,8 +287,14 @@ nf_nat_used_tuple_new(const struct nf_conntrack_tuple *tuple,
|
|||
zone = nf_ct_zone(ignored_ct);
|
||||
|
||||
thash = nf_conntrack_find_get(net, zone, tuple);
|
||||
if (unlikely(!thash)) /* clashing entry went away */
|
||||
return false;
|
||||
if (unlikely(!thash)) {
|
||||
struct nf_conntrack_tuple reply;
|
||||
|
||||
nf_ct_invert_tuple(&reply, tuple);
|
||||
thash = nf_conntrack_find_get(net, zone, &reply);
|
||||
if (!thash) /* clashing entry went away */
|
||||
return false;
|
||||
}
|
||||
|
||||
ct = nf_ct_tuplehash_to_ctrack(thash);
|
||||
|
||||
|
|
|
|||
|
|
@ -1113,6 +1113,25 @@ bool nft_pipapo_avx2_estimate(const struct nft_set_desc *desc, u32 features,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* pipapo_resmap_init_avx2() - Initialise result map before first use
|
||||
* @m: Matching data, including mapping table
|
||||
* @res_map: Result map
|
||||
*
|
||||
* Like pipapo_resmap_init() but do not set start map bits covered by the first field.
|
||||
*/
|
||||
static inline void pipapo_resmap_init_avx2(const struct nft_pipapo_match *m, unsigned long *res_map)
|
||||
{
|
||||
const struct nft_pipapo_field *f = m->f;
|
||||
int i;
|
||||
|
||||
/* Starting map doesn't need to be set to all-ones for this implementation,
|
||||
* but we do need to zero the remaining bits, if any.
|
||||
*/
|
||||
for (i = f->bsize; i < m->bsize_max; i++)
|
||||
res_map[i] = 0ul;
|
||||
}
|
||||
|
||||
/**
|
||||
* nft_pipapo_avx2_lookup() - Lookup function for AVX2 implementation
|
||||
* @net: Network namespace
|
||||
|
|
@ -1171,7 +1190,7 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
|
|||
res = scratch->map + (map_index ? m->bsize_max : 0);
|
||||
fill = scratch->map + (map_index ? 0 : m->bsize_max);
|
||||
|
||||
/* Starting map doesn't need to be set for this implementation */
|
||||
pipapo_resmap_init_avx2(m, res);
|
||||
|
||||
nft_pipapo_avx2_prepare();
|
||||
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ display net,port,proto
|
|||
type_spec ipv4_addr . inet_service . inet_proto
|
||||
chain_spec ip daddr . udp dport . meta l4proto
|
||||
dst addr4 port proto
|
||||
src
|
||||
src
|
||||
start 1
|
||||
count 9
|
||||
src_delta 9
|
||||
|
|
@ -419,6 +419,7 @@ table inet filter {
|
|||
|
||||
set test {
|
||||
type ${type_spec}
|
||||
counter
|
||||
flags interval,timeout
|
||||
}
|
||||
|
||||
|
|
@ -1158,8 +1159,17 @@ del() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Return packet count from 'test' counter in 'inet filter' table
|
||||
# Return packet count for elem $1 from 'test' counter in 'inet filter' table
|
||||
count_packets() {
|
||||
found=0
|
||||
for token in $(nft reset element inet filter test "${1}" ); do
|
||||
[ ${found} -eq 1 ] && echo "${token}" && return
|
||||
[ "${token}" = "packets" ] && found=1
|
||||
done
|
||||
}
|
||||
|
||||
# Return packet count from 'test' counter in 'inet filter' table
|
||||
count_packets_nomatch() {
|
||||
found=0
|
||||
for token in $(nft list counter inet filter test); do
|
||||
[ ${found} -eq 1 ] && echo "${token}" && return
|
||||
|
|
@ -1206,6 +1216,10 @@ perf() {
|
|||
|
||||
# Set MAC addresses, send single packet, check that it matches, reset counter
|
||||
send_match() {
|
||||
local elem="$1"
|
||||
|
||||
shift
|
||||
|
||||
ip link set veth_a address "$(format_mac "${1}")"
|
||||
ip -n B link set veth_b address "$(format_mac "${2}")"
|
||||
|
||||
|
|
@ -1216,7 +1230,7 @@ send_match() {
|
|||
eval src_"$f"=\$\(format_\$f "${2}"\)
|
||||
done
|
||||
eval send_\$proto
|
||||
if [ "$(count_packets)" != "1" ]; then
|
||||
if [ "$(count_packets "$elem")" != "1" ]; then
|
||||
err "${proto} packet to:"
|
||||
err " $(for f in ${dst}; do
|
||||
eval format_\$f "${1}"; printf ' '; done)"
|
||||
|
|
@ -1242,7 +1256,7 @@ send_nomatch() {
|
|||
eval src_"$f"=\$\(format_\$f "${2}"\)
|
||||
done
|
||||
eval send_\$proto
|
||||
if [ "$(count_packets)" != "0" ]; then
|
||||
if [ "$(count_packets_nomatch)" != "0" ]; then
|
||||
err "${proto} packet to:"
|
||||
err " $(for f in ${dst}; do
|
||||
eval format_\$f "${1}"; printf ' '; done)"
|
||||
|
|
@ -1255,6 +1269,42 @@ send_nomatch() {
|
|||
fi
|
||||
}
|
||||
|
||||
maybe_send_nomatch() {
|
||||
local elem="$1"
|
||||
local what="$4"
|
||||
|
||||
[ $((RANDOM%20)) -gt 0 ] && return
|
||||
|
||||
dst_addr4="$2"
|
||||
dst_port="$3"
|
||||
send_udp
|
||||
|
||||
if [ "$(count_packets_nomatch)" != "0" ]; then
|
||||
err "Packet to $dst_addr4:$dst_port did match $what"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
maybe_send_match() {
|
||||
local elem="$1"
|
||||
local what="$4"
|
||||
|
||||
[ $((RANDOM%20)) -gt 0 ] && return
|
||||
|
||||
dst_addr4="$2"
|
||||
dst_port="$3"
|
||||
send_udp
|
||||
|
||||
if [ "$(count_packets "{ $elem }")" != "1" ]; then
|
||||
err "Packet to $dst_addr4:$dst_port did not match $what"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
nft reset counter inet filter test >/dev/null
|
||||
nft reset element inet filter test "{ $elem }" >/dev/null
|
||||
}
|
||||
|
||||
# Correctness test template:
|
||||
# - add ranged element, check that packets match it
|
||||
# - check that packets outside range don't match it
|
||||
|
|
@ -1262,6 +1312,8 @@ send_nomatch() {
|
|||
test_correctness_main() {
|
||||
range_size=1
|
||||
for i in $(seq "${start}" $((start + count))); do
|
||||
local elem=""
|
||||
|
||||
end=$((start + range_size))
|
||||
|
||||
# Avoid negative or zero-sized port ranges
|
||||
|
|
@ -1272,15 +1324,16 @@ test_correctness_main() {
|
|||
srcstart=$((start + src_delta))
|
||||
srcend=$((end + src_delta))
|
||||
|
||||
add "$(format)" || return 1
|
||||
elem="$(format)"
|
||||
add "$elem" || return 1
|
||||
for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do
|
||||
send_match "${j}" $((j + src_delta)) || return 1
|
||||
send_match "$elem" "${j}" $((j + src_delta)) || return 1
|
||||
done
|
||||
send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1
|
||||
|
||||
# Delete elements now and then
|
||||
if [ $((i % 3)) -eq 0 ]; then
|
||||
del "$(format)" || return 1
|
||||
del "$elem" || return 1
|
||||
for j in $(seq "$start" \
|
||||
$((range_size / 2 + 1)) ${end}); do
|
||||
send_nomatch "${j}" $((j + src_delta)) \
|
||||
|
|
@ -1572,14 +1625,17 @@ test_timeout() {
|
|||
|
||||
range_size=1
|
||||
for i in $(seq "$start" $((start + count))); do
|
||||
local elem=""
|
||||
|
||||
end=$((start + range_size))
|
||||
srcstart=$((start + src_delta))
|
||||
srcend=$((end + src_delta))
|
||||
|
||||
add "$(format)" || return 1
|
||||
elem="$(format)"
|
||||
add "$elem" || return 1
|
||||
|
||||
for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do
|
||||
send_match "${j}" $((j + src_delta)) || return 1
|
||||
send_match "$elem" "${j}" $((j + src_delta)) || return 1
|
||||
done
|
||||
|
||||
range_size=$((range_size + 1))
|
||||
|
|
@ -1737,7 +1793,7 @@ test_bug_reload() {
|
|||
srcend=$((end + src_delta))
|
||||
|
||||
for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do
|
||||
send_match "${j}" $((j + src_delta)) || return 1
|
||||
send_match "$(format)" "${j}" $((j + src_delta)) || return 1
|
||||
done
|
||||
|
||||
range_size=$((range_size + 1))
|
||||
|
|
@ -1756,22 +1812,34 @@ test_bug_net_port_proto_match() {
|
|||
range_size=1
|
||||
for i in $(seq 1 10); do
|
||||
for j in $(seq 1 20) ; do
|
||||
elem=$(printf "10.%d.%d.0/24 . %d1-%d0 . 6-17 " ${i} ${j} ${i} "$((i+1))")
|
||||
local dport=$j
|
||||
|
||||
elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))")
|
||||
|
||||
# too slow, do not test all addresses
|
||||
maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "before add" || return 1
|
||||
|
||||
nft "add element inet filter test { $elem }" || return 1
|
||||
|
||||
maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "after add" || return 1
|
||||
|
||||
nft "get element inet filter test { $elem }" | grep -q "$elem"
|
||||
if [ $? -ne 0 ];then
|
||||
local got=$(nft "get element inet filter test { $elem }")
|
||||
err "post-add: should have returned $elem but got $got"
|
||||
return 1
|
||||
fi
|
||||
|
||||
maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "out-of-range" || return 1
|
||||
done
|
||||
done
|
||||
|
||||
# recheck after set was filled
|
||||
for i in $(seq 1 10); do
|
||||
for j in $(seq 1 20) ; do
|
||||
elem=$(printf "10.%d.%d.0/24 . %d1-%d0 . 6-17 " ${i} ${j} ${i} "$((i+1))")
|
||||
local dport=$j
|
||||
|
||||
elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))")
|
||||
|
||||
nft "get element inet filter test { $elem }" | grep -q "$elem"
|
||||
if [ $? -ne 0 ];then
|
||||
|
|
@ -1779,6 +1847,9 @@ test_bug_net_port_proto_match() {
|
|||
err "post-fill: should have returned $elem but got $got"
|
||||
return 1
|
||||
fi
|
||||
|
||||
maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "recheck" || return 1
|
||||
maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "recheck out-of-range" || return 1
|
||||
done
|
||||
done
|
||||
|
||||
|
|
@ -1786,9 +1857,10 @@ test_bug_net_port_proto_match() {
|
|||
for i in $(seq 1 10); do
|
||||
for j in $(seq 1 20) ; do
|
||||
local rnd=$((RANDOM%10))
|
||||
local dport=$j
|
||||
local got=""
|
||||
|
||||
elem=$(printf "10.%d.%d.0/24 . %d1-%d0 . 6-17 " ${i} ${j} ${i} "$((i+1))")
|
||||
elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))")
|
||||
if [ $rnd -gt 0 ];then
|
||||
continue
|
||||
fi
|
||||
|
|
@ -1799,6 +1871,8 @@ test_bug_net_port_proto_match() {
|
|||
err "post-delete: query for $elem returned $got instead of error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "match after deletion" || return 1
|
||||
done
|
||||
done
|
||||
|
||||
|
|
@ -1817,7 +1891,7 @@ test_bug_avx2_mismatch()
|
|||
dst_addr6="$a2"
|
||||
send_icmp6
|
||||
|
||||
if [ "$(count_packets)" -gt "0" ]; then
|
||||
if [ "$(count_packets "{ icmpv6 . $a1 }")" -gt "0" ]; then
|
||||
err "False match for $a2"
|
||||
return 1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -866,6 +866,24 @@ EOF
|
|||
ip netns exec "$ns0" nft delete table $family nat
|
||||
}
|
||||
|
||||
file_cmp()
|
||||
{
|
||||
local infile="$1"
|
||||
local outfile="$2"
|
||||
|
||||
if ! cmp "$infile" "$outfile";then
|
||||
echo -n "Infile "
|
||||
ls -l "$infile"
|
||||
echo -n "Outfile "
|
||||
ls -l "$outfile"
|
||||
echo "ERROR: in and output file mismatch when checking $msg" 1>&1
|
||||
ret=1
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
test_stateless_nat_ip()
|
||||
{
|
||||
local lret=0
|
||||
|
|
@ -966,11 +984,7 @@ EOF
|
|||
|
||||
wait
|
||||
|
||||
if ! cmp "$INFILE" "$OUTFILE";then
|
||||
ls -l "$INFILE" "$OUTFILE"
|
||||
echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
file_cmp "$INFILE" "$OUTFILE" "udp with stateless nat" || lret=1
|
||||
|
||||
:> "$OUTFILE"
|
||||
|
||||
|
|
@ -991,6 +1005,62 @@ EOF
|
|||
return $lret
|
||||
}
|
||||
|
||||
test_dnat_clash()
|
||||
{
|
||||
local lret=0
|
||||
|
||||
if ! socat -h > /dev/null 2>&1;then
|
||||
echo "SKIP: Could not run dnat clash test without socat tool"
|
||||
[ $ret -eq 0 ] && ret=$ksft_skip
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns exec "$ns0" nft -f /dev/stdin <<EOF
|
||||
flush ruleset
|
||||
table ip dnat-test {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
ip daddr 10.0.2.1 udp dport 1234 counter dnat to 10.0.1.1:1234
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add dnat rules"
|
||||
[ $ret -eq 0 ] && ret=$ksft_skip
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
local udpdaddr="10.0.2.1"
|
||||
for i in 1 2;do
|
||||
echo "PING $udpdaddr" > "$INFILE"
|
||||
echo "PONG 10.0.1.1 step $i" | ip netns exec "$ns0" timeout 3 socat STDIO UDP4-LISTEN:1234,bind=10.0.1.1 > "$OUTFILE" 2>/dev/null &
|
||||
local lpid=$!
|
||||
|
||||
busywait $BUSYWAIT_TIMEOUT listener_ready "$ns0" 1234 "-u"
|
||||
|
||||
result=$(ip netns exec "$ns1" timeout 3 socat STDIO UDP4-SENDTO:"$udpdaddr:1234,sourceport=4321" < "$INFILE")
|
||||
udpdaddr="10.0.1.1"
|
||||
|
||||
if [ "$result" != "PONG 10.0.1.1 step $i" ] ; then
|
||||
echo "ERROR: failed to test udp $ns1 to $ns2 with dnat rule step $i, result: \"$result\"" 1>&2
|
||||
lret=1
|
||||
ret=1
|
||||
fi
|
||||
|
||||
wait
|
||||
|
||||
file_cmp "$INFILE" "$OUTFILE" "udp dnat step $i" || lret=1
|
||||
|
||||
:> "$OUTFILE"
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IP dnat clash $ns1:$ns2"
|
||||
|
||||
ip netns exec "$ns0" nft flush ruleset
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
# ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99
|
||||
for i in "$ns0" "$ns1" "$ns2" ;do
|
||||
ip netns exec "$i" nft -f /dev/stdin <<EOF
|
||||
|
|
@ -1147,6 +1217,7 @@ $test_inet_nat && test_redirect6 inet
|
|||
|
||||
test_port_shadowing
|
||||
test_stateless_nat_ip
|
||||
test_dnat_clash
|
||||
|
||||
if [ $ret -ne 0 ];then
|
||||
echo -n "FAIL: "
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user