mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Fix a crash when stateful expression with its own gc callback is used in a set definition. 2) Skip IPv6 packets from any link-local address in IPv6 fib expression. Add a selftest for this scenario, from Florian Westphal. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
22488e4550
4 changed files with 291 additions and 55 deletions
|
@ -135,6 +135,17 @@ void nft_fib6_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_fib6_eval_type);
|
EXPORT_SYMBOL_GPL(nft_fib6_eval_type);
|
||||||
|
|
||||||
|
static bool nft_fib_v6_skip_icmpv6(const struct sk_buff *skb, u8 next, const struct ipv6hdr *iph)
|
||||||
|
{
|
||||||
|
if (likely(next != IPPROTO_ICMPV6))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ipv6_addr_type(&iph->saddr) != IPV6_ADDR_ANY)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ipv6_addr_type(&iph->daddr) & IPV6_ADDR_LINKLOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
const struct nft_pktinfo *pkt)
|
||||||
{
|
{
|
||||||
|
@ -163,11 +174,14 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
||||||
|
|
||||||
lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph);
|
lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph);
|
||||||
|
|
||||||
if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
|
if (nft_hook(pkt) == NF_INET_PRE_ROUTING ||
|
||||||
nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
|
nft_hook(pkt) == NF_INET_INGRESS) {
|
||||||
|
if (nft_fib_is_loopback(pkt->skb, nft_in(pkt)) ||
|
||||||
|
nft_fib_v6_skip_icmpv6(pkt->skb, pkt->tprot, iph)) {
|
||||||
nft_fib_store_result(dest, priv, nft_in(pkt));
|
nft_fib_store_result(dest, priv, nft_in(pkt));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*dest = 0;
|
*dest = 0;
|
||||||
rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb,
|
rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb,
|
||||||
|
|
|
@ -4364,44 +4364,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
err = nf_tables_set_alloc_name(&ctx, set, name);
|
err = nf_tables_set_alloc_name(&ctx, set, name);
|
||||||
kfree(name);
|
kfree(name);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_set_alloc_name;
|
goto err_set_name;
|
||||||
|
|
||||||
if (nla[NFTA_SET_EXPR]) {
|
|
||||||
expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
|
|
||||||
if (IS_ERR(expr)) {
|
|
||||||
err = PTR_ERR(expr);
|
|
||||||
goto err_set_alloc_name;
|
|
||||||
}
|
|
||||||
set->exprs[0] = expr;
|
|
||||||
set->num_exprs++;
|
|
||||||
} else if (nla[NFTA_SET_EXPRESSIONS]) {
|
|
||||||
struct nft_expr *expr;
|
|
||||||
struct nlattr *tmp;
|
|
||||||
int left;
|
|
||||||
|
|
||||||
if (!(flags & NFT_SET_EXPR)) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err_set_alloc_name;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
|
|
||||||
if (i == NFT_SET_EXPR_MAX) {
|
|
||||||
err = -E2BIG;
|
|
||||||
goto err_set_init;
|
|
||||||
}
|
|
||||||
if (nla_type(tmp) != NFTA_LIST_ELEM) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err_set_init;
|
|
||||||
}
|
|
||||||
expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
|
|
||||||
if (IS_ERR(expr)) {
|
|
||||||
err = PTR_ERR(expr);
|
|
||||||
goto err_set_init;
|
|
||||||
}
|
|
||||||
set->exprs[i++] = expr;
|
|
||||||
set->num_exprs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
udata = NULL;
|
udata = NULL;
|
||||||
if (udlen) {
|
if (udlen) {
|
||||||
|
@ -4426,7 +4389,6 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
set->udata = udata;
|
set->udata = udata;
|
||||||
set->timeout = timeout;
|
set->timeout = timeout;
|
||||||
set->gc_int = gc_int;
|
set->gc_int = gc_int;
|
||||||
set->handle = nf_tables_alloc_handle(table);
|
|
||||||
|
|
||||||
set->field_count = desc.field_count;
|
set->field_count = desc.field_count;
|
||||||
for (i = 0; i < desc.field_count; i++)
|
for (i = 0; i < desc.field_count; i++)
|
||||||
|
@ -4436,20 +4398,59 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_set_init;
|
goto err_set_init;
|
||||||
|
|
||||||
|
if (nla[NFTA_SET_EXPR]) {
|
||||||
|
expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
|
||||||
|
if (IS_ERR(expr)) {
|
||||||
|
err = PTR_ERR(expr);
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
set->exprs[0] = expr;
|
||||||
|
set->num_exprs++;
|
||||||
|
} else if (nla[NFTA_SET_EXPRESSIONS]) {
|
||||||
|
struct nft_expr *expr;
|
||||||
|
struct nlattr *tmp;
|
||||||
|
int left;
|
||||||
|
|
||||||
|
if (!(flags & NFT_SET_EXPR)) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
|
||||||
|
if (i == NFT_SET_EXPR_MAX) {
|
||||||
|
err = -E2BIG;
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
if (nla_type(tmp) != NFTA_LIST_ELEM) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
|
||||||
|
if (IS_ERR(expr)) {
|
||||||
|
err = PTR_ERR(expr);
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
set->exprs[i++] = expr;
|
||||||
|
set->num_exprs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set->handle = nf_tables_alloc_handle(table);
|
||||||
|
|
||||||
err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
|
err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_set_trans;
|
goto err_set_expr_alloc;
|
||||||
|
|
||||||
list_add_tail_rcu(&set->list, &table->sets);
|
list_add_tail_rcu(&set->list, &table->sets);
|
||||||
table->use++;
|
table->use++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_set_trans:
|
err_set_expr_alloc:
|
||||||
ops->destroy(set);
|
|
||||||
err_set_init:
|
|
||||||
for (i = 0; i < set->num_exprs; i++)
|
for (i = 0; i < set->num_exprs; i++)
|
||||||
nft_expr_destroy(&ctx, set->exprs[i]);
|
nft_expr_destroy(&ctx, set->exprs[i]);
|
||||||
err_set_alloc_name:
|
|
||||||
|
ops->destroy(set);
|
||||||
|
err_set_init:
|
||||||
kfree(set->name);
|
kfree(set->name);
|
||||||
err_set_name:
|
err_set_name:
|
||||||
kvfree(set);
|
kvfree(set);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
# Makefile for netfilter selftests
|
# Makefile for netfilter selftests
|
||||||
|
|
||||||
TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
|
TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
|
||||||
conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
|
conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
|
||||||
nft_concat_range.sh nft_conntrack_helper.sh \
|
nft_concat_range.sh nft_conntrack_helper.sh \
|
||||||
nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
|
nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
|
||||||
|
|
221
tools/testing/selftests/netfilter/nft_fib.sh
Executable file
221
tools/testing/selftests/netfilter/nft_fib.sh
Executable file
|
@ -0,0 +1,221 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# This tests the fib expression.
|
||||||
|
#
|
||||||
|
# Kselftest framework requirement - SKIP code is 4.
|
||||||
|
ksft_skip=4
|
||||||
|
ret=0
|
||||||
|
|
||||||
|
sfx=$(mktemp -u "XXXXXXXX")
|
||||||
|
ns1="ns1-$sfx"
|
||||||
|
ns2="ns2-$sfx"
|
||||||
|
nsrouter="nsrouter-$sfx"
|
||||||
|
timeout=4
|
||||||
|
|
||||||
|
log_netns=$(sysctl -n net.netfilter.nf_log_all_netns)
|
||||||
|
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
ip netns del ${ns1}
|
||||||
|
ip netns del ${ns2}
|
||||||
|
ip netns del ${nsrouter}
|
||||||
|
|
||||||
|
[ $log_netns -eq 0 ] && sysctl -q net.netfilter.nf_log_all_netns=$log_netns
|
||||||
|
}
|
||||||
|
|
||||||
|
nft --version > /dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ];then
|
||||||
|
echo "SKIP: Could not run test without nft tool"
|
||||||
|
exit $ksft_skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip -Version > /dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ];then
|
||||||
|
echo "SKIP: Could not run test without ip tool"
|
||||||
|
exit $ksft_skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip netns add ${nsrouter}
|
||||||
|
if [ $? -ne 0 ];then
|
||||||
|
echo "SKIP: Could not create net namespace"
|
||||||
|
exit $ksft_skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
dmesg | grep -q ' nft_rpfilter: '
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
dmesg -c | grep ' nft_rpfilter: '
|
||||||
|
echo "WARN: a previous test run has failed" 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
sysctl -q net.netfilter.nf_log_all_netns=1
|
||||||
|
ip netns add ${ns1}
|
||||||
|
ip netns add ${ns2}
|
||||||
|
|
||||||
|
load_ruleset() {
|
||||||
|
local netns=$1
|
||||||
|
|
||||||
|
ip netns exec ${netns} nft -f /dev/stdin <<EOF
|
||||||
|
table inet filter {
|
||||||
|
chain prerouting {
|
||||||
|
type filter hook prerouting priority 0; policy accept;
|
||||||
|
fib saddr . iif oif missing counter log prefix "$netns nft_rpfilter: " drop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
load_ruleset_count() {
|
||||||
|
local netns=$1
|
||||||
|
|
||||||
|
ip netns exec ${netns} nft -f /dev/stdin <<EOF
|
||||||
|
table inet filter {
|
||||||
|
chain prerouting {
|
||||||
|
type filter hook prerouting priority 0; policy accept;
|
||||||
|
ip daddr 1.1.1.1 fib saddr . iif oif missing counter drop
|
||||||
|
ip6 daddr 1c3::c01d fib saddr . iif oif missing counter drop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
check_drops() {
|
||||||
|
dmesg | grep -q ' nft_rpfilter: '
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
dmesg | grep ' nft_rpfilter: '
|
||||||
|
echo "FAIL: rpfilter did drop packets"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_fib_counter() {
|
||||||
|
local want=$1
|
||||||
|
local ns=$2
|
||||||
|
local address=$3
|
||||||
|
|
||||||
|
line=$(ip netns exec ${ns} nft list table inet filter | grep 'fib saddr . iif' | grep $address | grep "packets $want" )
|
||||||
|
ret=$?
|
||||||
|
|
||||||
|
if [ $ret -ne 0 ];then
|
||||||
|
echo "Netns $ns fib counter doesn't match expected packet count of $want for $address" 1>&2
|
||||||
|
ip netns exec ${ns} nft list table inet filter
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $want -gt 0 ]; then
|
||||||
|
echo "PASS: fib expression did drop packets for $address"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
load_ruleset ${nsrouter}
|
||||||
|
load_ruleset ${ns1}
|
||||||
|
load_ruleset ${ns2}
|
||||||
|
|
||||||
|
ip link add veth0 netns ${nsrouter} type veth peer name eth0 netns ${ns1} > /dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ];then
|
||||||
|
echo "SKIP: No virtual ethernet pair device support in kernel"
|
||||||
|
exit $ksft_skip
|
||||||
|
fi
|
||||||
|
ip link add veth1 netns ${nsrouter} type veth peer name eth0 netns ${ns2}
|
||||||
|
|
||||||
|
ip -net ${nsrouter} link set lo up
|
||||||
|
ip -net ${nsrouter} link set veth0 up
|
||||||
|
ip -net ${nsrouter} addr add 10.0.1.1/24 dev veth0
|
||||||
|
ip -net ${nsrouter} addr add dead:1::1/64 dev veth0
|
||||||
|
|
||||||
|
ip -net ${nsrouter} link set veth1 up
|
||||||
|
ip -net ${nsrouter} addr add 10.0.2.1/24 dev veth1
|
||||||
|
ip -net ${nsrouter} addr add dead:2::1/64 dev veth1
|
||||||
|
|
||||||
|
ip -net ${ns1} link set lo up
|
||||||
|
ip -net ${ns1} link set eth0 up
|
||||||
|
|
||||||
|
ip -net ${ns2} link set lo up
|
||||||
|
ip -net ${ns2} link set eth0 up
|
||||||
|
|
||||||
|
ip -net ${ns1} addr add 10.0.1.99/24 dev eth0
|
||||||
|
ip -net ${ns1} addr add dead:1::99/64 dev eth0
|
||||||
|
ip -net ${ns1} route add default via 10.0.1.1
|
||||||
|
ip -net ${ns1} route add default via dead:1::1
|
||||||
|
|
||||||
|
ip -net ${ns2} addr add 10.0.2.99/24 dev eth0
|
||||||
|
ip -net ${ns2} addr add dead:2::99/64 dev eth0
|
||||||
|
ip -net ${ns2} route add default via 10.0.2.1
|
||||||
|
ip -net ${ns2} route add default via dead:2::1
|
||||||
|
|
||||||
|
test_ping() {
|
||||||
|
local daddr4=$1
|
||||||
|
local daddr6=$2
|
||||||
|
|
||||||
|
ip netns exec ${ns1} ping -c 1 -q $daddr4 > /dev/null
|
||||||
|
ret=$?
|
||||||
|
if [ $ret -ne 0 ];then
|
||||||
|
check_drops
|
||||||
|
echo "FAIL: ${ns1} cannot reach $daddr4, ret $ret" 1>&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip netns exec ${ns1} ping -c 3 -q $daddr6 > /dev/null
|
||||||
|
ret=$?
|
||||||
|
if [ $ret -ne 0 ];then
|
||||||
|
check_drops
|
||||||
|
echo "FAIL: ${ns1} cannot reach $daddr6, ret $ret" 1>&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||||
|
ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
|
||||||
|
ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
|
||||||
|
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
test_ping 10.0.2.1 dead:2::1 || exit 1
|
||||||
|
check_drops || exit 1
|
||||||
|
|
||||||
|
test_ping 10.0.2.99 dead:2::99 || exit 1
|
||||||
|
check_drops || exit 1
|
||||||
|
|
||||||
|
echo "PASS: fib expression did not cause unwanted packet drops"
|
||||||
|
|
||||||
|
ip netns exec ${nsrouter} nft flush table inet filter
|
||||||
|
|
||||||
|
ip -net ${ns1} route del default
|
||||||
|
ip -net ${ns1} -6 route del default
|
||||||
|
|
||||||
|
ip -net ${ns1} addr del 10.0.1.99/24 dev eth0
|
||||||
|
ip -net ${ns1} addr del dead:1::99/64 dev eth0
|
||||||
|
|
||||||
|
ip -net ${ns1} addr add 10.0.2.99/24 dev eth0
|
||||||
|
ip -net ${ns1} addr add dead:2::99/64 dev eth0
|
||||||
|
|
||||||
|
ip -net ${ns1} route add default via 10.0.2.1
|
||||||
|
ip -net ${ns1} -6 route add default via dead:2::1
|
||||||
|
|
||||||
|
ip -net ${nsrouter} addr add dead:2::1/64 dev veth0
|
||||||
|
|
||||||
|
# switch to ruleset that doesn't log, this time
|
||||||
|
# its expected that this does drop the packets.
|
||||||
|
load_ruleset_count ${nsrouter}
|
||||||
|
|
||||||
|
# ns1 has a default route, but nsrouter does not.
|
||||||
|
# must not check return value, ping to 1.1.1.1 will
|
||||||
|
# fail.
|
||||||
|
check_fib_counter 0 ${nsrouter} 1.1.1.1 || exit 1
|
||||||
|
check_fib_counter 0 ${nsrouter} 1c3::c01d || exit 1
|
||||||
|
|
||||||
|
ip netns exec ${ns1} ping -c 1 -W 1 -q 1.1.1.1 > /dev/null
|
||||||
|
check_fib_counter 1 ${nsrouter} 1.1.1.1 || exit 1
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
ip netns exec ${ns1} ping -c 3 -q 1c3::c01d > /dev/null
|
||||||
|
check_fib_counter 3 ${nsrouter} 1c3::c01d || exit 1
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in a new issue