mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
netfilter pull request 26-09-28
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEjF9xRqF1emXiQiqU1w0aZmrPKyEFAmq5lC0ACgkQ1w0aZmrP
KyH/+A//XlfAsuJFsBE0sGf4zSuPw96RvjG9hjlbCahoMHSwwON46bl3frT+W9Zr
YNEIJMdEqqGEQ+bGQcafLlX3ayknzhN7cTe+VoBOR12/6WeewSG/1l3JusWgb91b
snDGU/tWaXn0ZmumpziiDWlgNapRkLlxCr7ZzqBNJowNZU/RNd/dtqiMdBz8osX7
eOtL947O2EIjNZ0+Y5AI6uHwQimEIdzPYIi50WpyxcLYLC/AEEJFhDTafwq5NTP/
tCzYODr2ybWXeC90yxFsLNQai+1Tyo7tq0BP1dcMg80i/kgOnVtAQqRt0E6BYaEP
Rwbfhh+onCbdRV0DpsuyL6uy3pnJ21uj48hWuquHgGnuP6yrc2EMTreLmt0szorH
nngUoqBNKheTqC8L+VSfjV6/+tDhwLTaH4knlasbZizWC//GjlBfK7c7499ApHrS
Icm9pVwKYtFFRARe8wT2H3AKO3u3DaVNXBDypviCnEuvAXRuIi4nwu/aMVVeD9cs
04uTCFqMvUv+rX3oJN13hhC88fyH4R25sMt/XIZQxel/ZwjZrcZYz8FoFi5ePdfF
X/tBDloygOt2tB3YRnHdPxm/SYOZTQoUlD9SmtwvSYnGD0V3TFmCFILAeNPc4SrZ
rR/H5yDV47JxXGst9xd5AJlMNhr6ZrbCqbqC6GhWPnXFXC01lvg=
=RZ9z
-----END PGP SIGNATURE-----
Merge tag 'nf-next-26-09-28' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
Pablo Neira Ayuso says:
====================
Netfilter updates for net-next
The following patchset contains Netfilter updates for net-next. The
fixes included in this batch are deemed to handle correctness issues
present in the Netfilter tree:
1) TCP sequence tracking is not reset inconditionally by synproxy when
recycling an entry, sashiko reports the zero offset case skips it.
Add a new function to inconditionally reset TCP sequence tracking.
From Fernando F. Mancera.
2) Update documentation to reflect that the default maximum number of
expectations (nf_conntrack_expect_max) is nf_conntrack_buckets / 64.
From Shaojie Sun.
3) Remove useless break; after return in nft_osf, from Linkui Xiao.
4) Fix typos in comments in the netfilter tree, from Hemanth Selam.
5) Remove a few conntrack error stats duplicated updates,
from Phil Sutter.
6) Do not bump invalid and drop conntrack error stats when packet is
dropped, this is another duplicate. also From Phil.
7) Set on netns pointer before registering the flowtable, this is
a requirement by the next patch, not fixing an existing issue.
From Qingfang Deng.
8) Remove unnecessary workqueue work flush for all of the existing
netns when device is gone. Also from Qingfang Deng.
9) Rework-fix nfnetlink_hook to correctly deal with large netlink
dumps. Use sequence numbers to detect interference with hook
updates while netlink dump is ongoing. From Phil Sutter.
10) Fix ctnetlink dump filtering by the IPv6 address, this has
only work correctly for IPv4 this far, from Piotr Kubik.
11) ctnetlink filtering by zone is supported, but the ctnetlink
dump filtering infrastructure was never updated to include a
flag from userspace, update it to fill this gap.
From Ilya Maximets.
* tag 'nf-next-26-09-28' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next:
netfilter: conntrack: make filtering by zone discoverable
netfilter: ctnetlink: fix inverted IPv6 address match in dump filter
netfilter: nfnetlink: Fix for interrupted hook dumps
netfilter: flowtable: check namespace before iterating flows
net/sched: act_ct: set net pointer before publishing flowtable
netfilter: conntrack: Untangle drop and invalid counters
netfilter: conntrack: Untangle insert_failed counter from others
netfilter: fix several typos in comments
netfilter: osf: remove unreachable break in nf_osf_ttl()
netfilter: conntrack: fix nf_conntrack_expect_max default value in documentation
netfilter: synproxy: fix reset of ct seqadj when reopening a connection
====================
Link: https://patch.msgid.link/20260927223436.269024-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
0a1a3898ab
|
|
@ -393,6 +393,12 @@ attribute-sets:
|
|||
name: reply-flags
|
||||
type: u32
|
||||
doc: bitmask of tuple fields to filter on, reply direction
|
||||
-
|
||||
name: zone
|
||||
type: flag
|
||||
doc: >-
|
||||
Filter on conntrack zone id; requires the top-level zone
|
||||
(``CTA_ZONE``) attribute.
|
||||
-
|
||||
name: conntrack-attrs
|
||||
attributes:
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ nf_conntrack_events - BOOLEAN
|
|||
|
||||
nf_conntrack_expect_max - INTEGER
|
||||
Maximum size of expectation table. Default value is
|
||||
nf_conntrack_buckets / 256. Minimum is 1.
|
||||
nf_conntrack_buckets / 64. Minimum is 1.
|
||||
|
||||
nf_conntrack_frag6_high_thresh - INTEGER
|
||||
default 262144
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ static inline struct nf_conn_seqadj *nfct_seqadj_ext_add(struct nf_conn *ct)
|
|||
|
||||
int nf_ct_seqadj_init(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
s32 off);
|
||||
void nf_ct_seqadj_reset(struct nf_conn *ct, enum ip_conntrack_info ctinfo);
|
||||
int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
__be32 seq, s32 off);
|
||||
void nf_ct_tcp_seqadj_set(struct sk_buff *skb, struct nf_conn *ct,
|
||||
|
|
|
|||
|
|
@ -33,5 +33,7 @@ struct netns_nf {
|
|||
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
|
||||
unsigned int defrag_ipv6_users;
|
||||
#endif
|
||||
unsigned int hook_base_seq;
|
||||
unsigned int nat_hook_base_seq;
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ enum ctattr_filter {
|
|||
CTA_FILTER_UNSPEC,
|
||||
CTA_FILTER_ORIG_FLAGS,
|
||||
CTA_FILTER_REPLY_FLAGS,
|
||||
CTA_FILTER_ZONE,
|
||||
__CTA_FILTER_MAX
|
||||
};
|
||||
#define CTA_FILTER_MAX (__CTA_FILTER_MAX - 1)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
|
|||
/*
|
||||
* Unfortunately, _b and _mask are not aligned to an int (or long int)
|
||||
* Some arches dont care, unrolling the loop is a win on them.
|
||||
* For other arches, we only have a 16bit alignement.
|
||||
* For other arches, we only have a 16bit alignment.
|
||||
*/
|
||||
static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -386,6 +386,15 @@ static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void bump_hook_base_seq(struct net *net)
|
||||
{
|
||||
unsigned int base_seq = READ_ONCE(net->nf.hook_base_seq);
|
||||
|
||||
while (++base_seq == 0)
|
||||
;
|
||||
smp_store_release(&net->nf.hook_base_seq, base_seq);
|
||||
}
|
||||
|
||||
static int __nf_register_net_hook(struct net *net, int pf,
|
||||
const struct nf_hook_ops *reg)
|
||||
{
|
||||
|
|
@ -430,6 +439,7 @@ static int __nf_register_net_hook(struct net *net, int pf,
|
|||
if (!IS_ERR(new_hooks)) {
|
||||
hooks_validate(new_hooks);
|
||||
rcu_assign_pointer(*pp, new_hooks);
|
||||
bump_hook_base_seq(net);
|
||||
}
|
||||
|
||||
mutex_unlock(&nf_hook_mutex);
|
||||
|
|
@ -483,6 +493,7 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
|
|||
{
|
||||
struct nf_hook_entries __rcu **pp;
|
||||
struct nf_hook_entries *p;
|
||||
bool found;
|
||||
|
||||
pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
|
||||
if (!pp)
|
||||
|
|
@ -496,7 +507,8 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
|
|||
return;
|
||||
}
|
||||
|
||||
if (nf_remove_net_hook(p, reg)) {
|
||||
found = nf_remove_net_hook(p, reg);
|
||||
if (found) {
|
||||
#ifdef CONFIG_NETFILTER_INGRESS
|
||||
if (nf_ingress_hook(reg, pf))
|
||||
net_dec_ingress_queue();
|
||||
|
|
@ -511,6 +523,8 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
|
|||
}
|
||||
|
||||
p = __nf_hook_entries_try_shrink(p, pp);
|
||||
if (found)
|
||||
bump_hook_base_seq(net);
|
||||
mutex_unlock(&nf_hook_mutex);
|
||||
if (!p)
|
||||
return;
|
||||
|
|
@ -784,6 +798,8 @@ static int __net_init netfilter_net_init(struct net *net)
|
|||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
net->nf.hook_base_seq = 1;
|
||||
net->nf.nat_hook_base_seq = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1426,7 +1426,7 @@ static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
return -IPSET_ERR_EXIST_SETNAME2;
|
||||
|
||||
/* Features must not change.
|
||||
* Not an artifical restriction anymore, as we must prevent
|
||||
* Not an artificial restriction anymore, as we must prevent
|
||||
* possible loops created by swapping in setlist type of sets.
|
||||
*/
|
||||
if (!(from->type->features == to->type->features &&
|
||||
|
|
|
|||
|
|
@ -1344,7 +1344,7 @@ static void set_mcast_pmtudisc(struct sock *sk, int val)
|
|||
}
|
||||
|
||||
/*
|
||||
* Specifiy default interface for outgoing multicasts
|
||||
* Specify default interface for outgoing multicasts
|
||||
*/
|
||||
static int set_mcast_if(struct sock *sk, struct net_device *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1169,7 +1169,6 @@ nf_ct_resolve_clash(struct sk_buff *skb, struct nf_conntrack_tuple_hash *h,
|
|||
return ret;
|
||||
|
||||
drop:
|
||||
NF_CT_STAT_INC(net, drop);
|
||||
NF_CT_STAT_INC(net, insert_failed);
|
||||
return NF_DROP;
|
||||
}
|
||||
|
|
@ -1259,7 +1258,6 @@ __nf_conntrack_confirm(struct sk_buff *skb)
|
|||
if (chainlen++ > max_chainlen) {
|
||||
chaintoolong:
|
||||
NF_CT_STAT_INC(net, chaintoolong);
|
||||
NF_CT_STAT_INC(net, insert_failed);
|
||||
ret = NF_DROP;
|
||||
goto dying;
|
||||
}
|
||||
|
|
@ -2067,9 +2065,10 @@ nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state)
|
|||
if (ret == -NF_REPEAT)
|
||||
goto repeat;
|
||||
|
||||
NF_CT_STAT_INC_ATOMIC(state->net, invalid);
|
||||
if (ret == NF_DROP)
|
||||
NF_CT_STAT_INC_ATOMIC(state->net, drop);
|
||||
else
|
||||
NF_CT_STAT_INC_ATOMIC(state->net, invalid);
|
||||
|
||||
ret = -ret;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -911,6 +911,7 @@ struct ctnetlink_filter {
|
|||
static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {
|
||||
[CTA_FILTER_ORIG_FLAGS] = NLA_POLICY_MASK(NLA_U32, CTA_FILTER_F_ALL),
|
||||
[CTA_FILTER_REPLY_FLAGS] = NLA_POLICY_MASK(NLA_U32, CTA_FILTER_F_ALL),
|
||||
[CTA_FILTER_ZONE] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static int ctnetlink_parse_filter(const struct nlattr *attr,
|
||||
|
|
@ -930,6 +931,9 @@ static int ctnetlink_parse_filter(const struct nlattr *attr,
|
|||
if (tb[CTA_FILTER_REPLY_FLAGS])
|
||||
filter->reply_flags = nla_get_u32(tb[CTA_FILTER_REPLY_FLAGS]);
|
||||
|
||||
if (tb[CTA_FILTER_ZONE])
|
||||
filter->zone_filter = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1006,6 +1010,7 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
|
|||
if (err)
|
||||
goto err_filter;
|
||||
|
||||
/* CTA_ZONE is allowed without CTA_FILTER_ZONE. */
|
||||
if (cda[CTA_ZONE]) {
|
||||
err = ctnetlink_parse_zone(cda[CTA_ZONE], &filter->zone);
|
||||
if (err < 0)
|
||||
|
|
@ -1020,6 +1025,12 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
|
|||
if (err < 0)
|
||||
goto err_filter;
|
||||
|
||||
/* CTA_FILTER_ZONE cannot be set without CTA_ZONE. */
|
||||
if (filter->zone_filter && !cda[CTA_ZONE]) {
|
||||
err = -EINVAL;
|
||||
goto err_filter;
|
||||
}
|
||||
|
||||
if (filter->orig_flags) {
|
||||
if (!cda[CTA_TUPLE_ORIG]) {
|
||||
err = -EINVAL;
|
||||
|
|
@ -1098,13 +1109,13 @@ static int ctnetlink_filter_match_tuple(struct nf_conntrack_tuple *filter_tuple,
|
|||
break;
|
||||
case NFPROTO_IPV6:
|
||||
if ((flags & CTA_FILTER_FLAG(CTA_IP_SRC)) &&
|
||||
!ipv6_addr_cmp(&filter_tuple->src.u3.in6,
|
||||
&ct_tuple->src.u3.in6))
|
||||
!ipv6_addr_equal(&filter_tuple->src.u3.in6,
|
||||
&ct_tuple->src.u3.in6))
|
||||
return 0;
|
||||
|
||||
if ((flags & CTA_FILTER_FLAG(CTA_IP_DST)) &&
|
||||
!ipv6_addr_cmp(&filter_tuple->dst.u3.in6,
|
||||
&ct_tuple->dst.u3.in6))
|
||||
!ipv6_addr_equal(&filter_tuple->dst.u3.in6,
|
||||
&ct_tuple->dst.u3.in6))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,23 @@ int nf_ct_seqadj_init(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_seqadj_init);
|
||||
|
||||
void nf_ct_seqadj_reset(struct nf_conn *ct, enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
struct nf_ct_seqadj *this_way;
|
||||
|
||||
if (unlikely(!seqadj))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&ct->lock);
|
||||
this_way = &seqadj->seq[dir];
|
||||
this_way->offset_before = 0;
|
||||
this_way->offset_after = 0;
|
||||
spin_unlock_bh(&ct->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_seqadj_reset);
|
||||
|
||||
int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
__be32 seq, s32 off)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -737,14 +737,9 @@ static void nf_flow_table_do_cleanup(struct nf_flowtable *flow_table,
|
|||
{
|
||||
struct net_device *dev = data;
|
||||
|
||||
if (!dev) {
|
||||
flow_offload_teardown(flow);
|
||||
return;
|
||||
}
|
||||
|
||||
if (net_eq(nf_ct_net(flow->ct), dev_net(dev)) &&
|
||||
(flow->tuplehash[0].tuple.iifidx == dev->ifindex ||
|
||||
flow->tuplehash[1].tuple.iifidx == dev->ifindex))
|
||||
if (!dev ||
|
||||
flow->tuplehash[0].tuple.iifidx == dev->ifindex ||
|
||||
flow->tuplehash[1].tuple.iifidx == dev->ifindex)
|
||||
flow_offload_teardown(flow);
|
||||
}
|
||||
|
||||
|
|
@ -761,8 +756,10 @@ void nf_flow_table_cleanup(struct net_device *dev)
|
|||
struct nf_flowtable *flowtable;
|
||||
|
||||
mutex_lock(&flowtable_lock);
|
||||
list_for_each_entry(flowtable, &flowtables, list)
|
||||
nf_flow_table_gc_cleanup(flowtable, dev);
|
||||
list_for_each_entry(flowtable, &flowtables, list) {
|
||||
if (net_eq(read_pnet(&flowtable->net), dev_net(dev)))
|
||||
nf_flow_table_gc_cleanup(flowtable, dev);
|
||||
}
|
||||
mutex_unlock(&flowtable_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
|
||||
|
|
|
|||
|
|
@ -1160,6 +1160,15 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct,
|
|||
}
|
||||
#endif
|
||||
|
||||
static void bump_nat_hook_base_seq(struct net *net)
|
||||
{
|
||||
unsigned int base_seq = READ_ONCE(net->nf.nat_hook_base_seq);
|
||||
|
||||
while (++base_seq == 0)
|
||||
;
|
||||
smp_store_release(&net->nf.nat_hook_base_seq, base_seq);
|
||||
}
|
||||
|
||||
static struct nf_ct_helper_expectfn follow_master_nat = {
|
||||
.name = "nat-follow-master",
|
||||
.expectfn = nf_nat_follow_master,
|
||||
|
|
@ -1245,6 +1254,7 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
|||
nat_proto_net->nat_hook_ops = nat_ops;
|
||||
|
||||
nat_proto_net->users++;
|
||||
bump_nat_hook_base_seq(net);
|
||||
|
||||
mutex_unlock(&nf_nat_proto_mutex);
|
||||
|
||||
|
|
@ -1299,6 +1309,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
|||
goto unlock;
|
||||
priv = nat_ops[hooknum].priv;
|
||||
nf_hook_entries_delete_raw(&priv->entries, ops);
|
||||
bump_nat_hook_base_seq(net);
|
||||
|
||||
if (nat_proto_net->users == 0) {
|
||||
nf_unregister_net_hooks(net, nat_ops, ops_count);
|
||||
|
|
|
|||
|
|
@ -686,7 +686,7 @@ ipv4_synproxy_hook(void *priv, struct sk_buff *skb,
|
|||
* adjustments, they will get initialized once the connection is
|
||||
* reestablished.
|
||||
*/
|
||||
nf_ct_seqadj_init(ct, ctinfo, 0);
|
||||
nf_ct_seqadj_reset(ct, ctinfo);
|
||||
synproxy->tsoff = 0;
|
||||
this_cpu_inc(snet->stats->conn_reopened);
|
||||
fallthrough;
|
||||
|
|
@ -1116,7 +1116,7 @@ ipv6_synproxy_hook(void *priv, struct sk_buff *skb,
|
|||
* adjustments, they will get initialized once the connection is
|
||||
* reestablished.
|
||||
*/
|
||||
nf_ct_seqadj_init(ct, ctinfo, 0);
|
||||
nf_ct_seqadj_reset(ct, ctinfo);
|
||||
synproxy->tsoff = 0;
|
||||
this_cpu_inc(snet->stats->conn_reopened);
|
||||
fallthrough;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ static int nf_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb,
|
|||
|
||||
struct nfnl_dump_hook_data {
|
||||
char devname[IFNAMSIZ];
|
||||
unsigned long headv;
|
||||
u8 hook;
|
||||
};
|
||||
|
||||
|
|
@ -338,27 +337,47 @@ nfnl_hook_entries_head(u8 pf, unsigned int hook, struct net *net, const char *de
|
|||
}
|
||||
|
||||
static int nfnl_hook_dump_nat(struct sk_buff *nlskb,
|
||||
const struct nfnl_dump_hook_data *ctx,
|
||||
const struct nf_hook_ops *ops,
|
||||
int family, unsigned int seq)
|
||||
struct netlink_callback *cb,
|
||||
const struct nf_hook_ops *ops, int family)
|
||||
{
|
||||
struct nf_nat_lookup_hook_priv *priv = ops->priv;
|
||||
struct nf_hook_entries *e = rcu_dereference(priv->entries);
|
||||
struct nfnl_dump_hook_data *ctx = cb->data;
|
||||
struct net *net = sock_net(nlskb->sk);
|
||||
struct nf_hook_ops **nat_ops;
|
||||
int i, err;
|
||||
unsigned int i = cb->args[1];
|
||||
struct nf_hook_entries *e;
|
||||
unsigned int base_seq;
|
||||
int err = 0;
|
||||
|
||||
base_seq = smp_load_acquire(&net->nf.nat_hook_base_seq);
|
||||
|
||||
e = rcu_dereference(priv->entries);
|
||||
if (!e)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
nat_ops = nf_hook_entries_get_hook_ops(e);
|
||||
|
||||
for (i = 0; i < e->num_hook_entries; i++) {
|
||||
err = nfnl_hook_dump_one(nlskb, ctx, nat_ops[i],
|
||||
ops->priority, family, seq);
|
||||
for (; i < e->num_hook_entries; i++) {
|
||||
err = nfnl_hook_dump_one(nlskb, ctx,
|
||||
READ_ONCE(nat_ops[i]),
|
||||
ops->priority, family,
|
||||
cb->nlh->nlmsg_seq);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
if (!err)
|
||||
i = 0;
|
||||
cb->args[1] = i;
|
||||
|
||||
if (cb->args[2] && base_seq != cb->args[2]) {
|
||||
cb->seq++;
|
||||
err = -EINTR;
|
||||
}
|
||||
cb->args[2] = base_seq;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nfnl_hook_dump(struct sk_buff *nlskb,
|
||||
|
|
@ -373,35 +392,31 @@ static int nfnl_hook_dump(struct sk_buff *nlskb,
|
|||
unsigned int i = cb->args[0];
|
||||
|
||||
rcu_read_lock();
|
||||
cb->seq = smp_load_acquire(&net->nf.hook_base_seq);
|
||||
|
||||
e = nfnl_hook_entries_head(family, ctx->hook, net, ctx->devname);
|
||||
if (!e)
|
||||
if (!e || IS_ERR(e))
|
||||
goto done;
|
||||
|
||||
if (IS_ERR(e)) {
|
||||
cb->seq++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((unsigned long)e != ctx->headv || i >= e->num_hook_entries)
|
||||
cb->seq++;
|
||||
|
||||
ops = nf_hook_entries_get_hook_ops(e);
|
||||
|
||||
for (; i < e->num_hook_entries; i++) {
|
||||
if (ops[i]->hook_ops_type == NF_HOOK_OP_NAT)
|
||||
err = nfnl_hook_dump_nat(nlskb, ctx, ops[i], family,
|
||||
cb->nlh->nlmsg_seq);
|
||||
else
|
||||
err = nfnl_hook_dump_one(nlskb, ctx, ops[i],
|
||||
ops[i]->priority, family,
|
||||
const struct nf_hook_ops *cur = READ_ONCE(ops[i]);
|
||||
|
||||
if (cur->hook_ops_type == NF_HOOK_OP_NAT) {
|
||||
err = nfnl_hook_dump_nat(nlskb, cb, cur, family);
|
||||
} else {
|
||||
err = nfnl_hook_dump_one(nlskb, ctx, cur,
|
||||
cur->priority, family,
|
||||
cb->nlh->nlmsg_seq);
|
||||
}
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
nl_dump_check_consistent(cb, nlmsg_hdr(nlskb));
|
||||
if (nlskb->len > 0)
|
||||
nl_dump_check_consistent(cb, nlmsg_hdr(nlskb));
|
||||
rcu_read_unlock();
|
||||
cb->args[0] = i;
|
||||
return nlskb->len;
|
||||
|
|
@ -442,10 +457,7 @@ static int nfnl_hook_dump_start(struct netlink_callback *cb)
|
|||
return -ENOMEM;
|
||||
|
||||
strscpy(ctx->devname, name, sizeof(ctx->devname));
|
||||
ctx->headv = (unsigned long)head;
|
||||
ctx->hook = hooknum;
|
||||
|
||||
cb->seq = 1;
|
||||
cb->data = ctx;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ static inline int nf_osf_ttl(const struct sk_buff *skb,
|
|||
switch (ttl_check) {
|
||||
case NF_OSF_TTL_TRUE:
|
||||
return ip->ttl == f_ttl;
|
||||
break;
|
||||
case NF_OSF_TTL_NOCHECK:
|
||||
return 1;
|
||||
case NF_OSF_TTL_LESS:
|
||||
|
|
|
|||
|
|
@ -349,10 +349,10 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params)
|
|||
ct_ft->nf_ft.type = &flowtable_ct;
|
||||
ct_ft->nf_ft.flags |= NF_FLOWTABLE_HW_OFFLOAD |
|
||||
NF_FLOWTABLE_COUNTER;
|
||||
write_pnet(&ct_ft->nf_ft.net, net);
|
||||
err = nf_flow_table_init(&ct_ft->nf_ft);
|
||||
if (err)
|
||||
goto err_init;
|
||||
write_pnet(&ct_ft->nf_ft.net, net);
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
out_unlock:
|
||||
|
|
|
|||
|
|
@ -215,7 +215,22 @@ static int count_entries(const struct nlmsghdr *nlh, void *data)
|
|||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone)
|
||||
static void put_zone_attr(struct nlmsghdr *nlh, uint16_t zone,
|
||||
bool use_cta_filter)
|
||||
{
|
||||
struct nlattr *nest;
|
||||
|
||||
mnl_attr_put_u16(nlh, CTA_ZONE, htons(zone));
|
||||
|
||||
if (use_cta_filter) {
|
||||
nest = mnl_attr_nest_start(nlh, CTA_FILTER);
|
||||
mnl_attr_put(nlh, CTA_FILTER_ZONE, 0, NULL);
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
}
|
||||
}
|
||||
|
||||
static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone,
|
||||
bool use_cta_filter)
|
||||
{
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlmsghdr *nlh;
|
||||
|
|
@ -235,7 +250,7 @@ static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone)
|
|||
nfh->version = NFNETLINK_V0;
|
||||
nfh->res_id = 0;
|
||||
|
||||
mnl_attr_put_u16(nlh, CTA_ZONE, htons(zone));
|
||||
put_zone_attr(nlh, zone, use_cta_filter);
|
||||
|
||||
ret = mnl_socket_sendto(sock, nlh, nlh->nlmsg_len);
|
||||
if (ret < 0) {
|
||||
|
|
@ -261,7 +276,8 @@ static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone)
|
|||
return reply_counter;
|
||||
}
|
||||
|
||||
static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
|
||||
static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone,
|
||||
bool use_cta_filter)
|
||||
{
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlmsghdr *nlh;
|
||||
|
|
@ -281,7 +297,7 @@ static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
|
|||
nfh->version = NFNETLINK_V0;
|
||||
nfh->res_id = 0;
|
||||
|
||||
mnl_attr_put_u16(nlh, CTA_ZONE, htons(zone));
|
||||
put_zone_attr(nlh, zone, use_cta_filter);
|
||||
|
||||
ret = mnl_socket_sendto(sock, nlh, nlh->nlmsg_len);
|
||||
if (ret < 0) {
|
||||
|
|
@ -304,43 +320,40 @@ static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
|
|||
return 0;
|
||||
}
|
||||
|
||||
FIXTURE(conntrack_dump_flush)
|
||||
{
|
||||
struct mnl_socket *sock;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(conntrack_dump_flush)
|
||||
static int conntrack_zone_setup(struct __test_metadata *_metadata,
|
||||
struct mnl_socket **sock)
|
||||
{
|
||||
struct in6_addr src, dst;
|
||||
int ret;
|
||||
|
||||
self->sock = mnl_socket_open(NETLINK_NETFILTER);
|
||||
if (!self->sock) {
|
||||
*sock = mnl_socket_open(NETLINK_NETFILTER);
|
||||
if (!*sock) {
|
||||
perror("mnl_socket_open");
|
||||
SKIP(return, "cannot open netlink_netfilter socket");
|
||||
SKIP(return -1, "cannot open netlink_netfilter socket");
|
||||
}
|
||||
|
||||
ret = mnl_socket_bind(self->sock, 0, MNL_SOCKET_AUTOPID);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = mnl_socket_bind(*sock, 0, MNL_SOCKET_AUTOPID);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
|
||||
ret = conntrack_count_zone(*sock, TEST_ZONE_ID, false);
|
||||
if (ret < 0 && errno == EPERM)
|
||||
SKIP(return, "Needs to be run as root");
|
||||
SKIP(return -1, "Needs to be run as root");
|
||||
else if (ret < 0 && errno == EOPNOTSUPP)
|
||||
SKIP(return, "Kernel does not seem to support conntrack zones");
|
||||
SKIP(return -1,
|
||||
"Kernel does not seem to support conntrack zones");
|
||||
|
||||
ret = conntrack_data_generate_v4(self->sock, 0xf0f0f0f0, 0xf1f1f1f1,
|
||||
ret = conntrack_data_generate_v4(*sock, 0xf0f0f0f0, 0xf1f1f1f1,
|
||||
TEST_ZONE_ID);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = conntrack_data_generate_v4(self->sock, 0xf2f2f2f2, 0xf3f3f3f3,
|
||||
ASSERT_EQ(ret, 0);
|
||||
ret = conntrack_data_generate_v4(*sock, 0xf2f2f2f2, 0xf3f3f3f3,
|
||||
TEST_ZONE_ID + 1);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = conntrack_data_generate_v4(self->sock, 0xf4f4f4f4, 0xf5f5f5f5,
|
||||
ASSERT_EQ(ret, 0);
|
||||
ret = conntrack_data_generate_v4(*sock, 0xf4f4f4f4, 0xf5f5f5f5,
|
||||
TEST_ZONE_ID + 2);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = conntrack_data_generate_v4(self->sock, 0xf6f6f6f6, 0xf7f7f7f7,
|
||||
ASSERT_EQ(ret, 0);
|
||||
ret = conntrack_data_generate_v4(*sock, 0xf6f6f6f6, 0xf7f7f7f7,
|
||||
NF_CT_DEFAULT_ZONE_ID);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
src = (struct in6_addr) {{
|
||||
.__u6_addr32 = {
|
||||
|
|
@ -358,9 +371,9 @@ FIXTURE_SETUP(conntrack_dump_flush)
|
|||
0x02000000
|
||||
}
|
||||
}};
|
||||
ret = conntrack_data_generate_v6(self->sock, src, dst,
|
||||
ret = conntrack_data_generate_v6(*sock, src, dst,
|
||||
TEST_ZONE_ID);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
src = (struct in6_addr) {{
|
||||
.__u6_addr32 = {
|
||||
0xb80d0120,
|
||||
|
|
@ -377,9 +390,9 @@ FIXTURE_SETUP(conntrack_dump_flush)
|
|||
0x04000000
|
||||
}
|
||||
}};
|
||||
ret = conntrack_data_generate_v6(self->sock, src, dst,
|
||||
ret = conntrack_data_generate_v6(*sock, src, dst,
|
||||
TEST_ZONE_ID + 1);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
src = (struct in6_addr) {{
|
||||
.__u6_addr32 = {
|
||||
0xb80d0120,
|
||||
|
|
@ -396,9 +409,9 @@ FIXTURE_SETUP(conntrack_dump_flush)
|
|||
0x06000000
|
||||
}
|
||||
}};
|
||||
ret = conntrack_data_generate_v6(self->sock, src, dst,
|
||||
ret = conntrack_data_generate_v6(*sock, src, dst,
|
||||
TEST_ZONE_ID + 2);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
src = (struct in6_addr) {{
|
||||
.__u6_addr32 = {
|
||||
|
|
@ -416,14 +429,51 @@ FIXTURE_SETUP(conntrack_dump_flush)
|
|||
0x08000000
|
||||
}
|
||||
}};
|
||||
ret = conntrack_data_generate_v6(self->sock, src, dst,
|
||||
ret = conntrack_data_generate_v6(*sock, src, dst,
|
||||
NF_CT_DEFAULT_ZONE_ID);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FIXTURE(conntrack_dump_flush)
|
||||
{
|
||||
struct mnl_socket *sock;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT(conntrack_dump_flush)
|
||||
{
|
||||
bool use_cta_filter;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(conntrack_dump_flush, cta_zone)
|
||||
{
|
||||
.use_cta_filter = false,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(conntrack_dump_flush, cta_filter)
|
||||
{
|
||||
.use_cta_filter = true,
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(conntrack_dump_flush)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (conntrack_zone_setup(_metadata, &self->sock))
|
||||
return;
|
||||
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, false);
|
||||
EXPECT_GE(ret, 2);
|
||||
if (ret > 2)
|
||||
SKIP(return, "kernel does not support filtering by zone");
|
||||
|
||||
if (variant->use_cta_filter) {
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, true);
|
||||
if (ret < 0 && errno == EINVAL)
|
||||
SKIP(return, "kernel does not support CTA_FILTER_ZONE");
|
||||
ASSERT_GE(ret, 0);
|
||||
}
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(conntrack_dump_flush)
|
||||
|
|
@ -434,39 +484,42 @@ TEST_F(conntrack_dump_flush, test_dump_by_zone)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID,
|
||||
variant->use_cta_filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
}
|
||||
|
||||
TEST_F(conntrack_dump_flush, test_flush_by_zone)
|
||||
{
|
||||
bool filter = variant->use_cta_filter;
|
||||
int ret;
|
||||
|
||||
ret = conntrack_flush_zone(self->sock, TEST_ZONE_ID);
|
||||
ret = conntrack_flush_zone(self->sock, TEST_ZONE_ID, filter);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, filter);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1, filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2, filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID);
|
||||
ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID, filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
}
|
||||
|
||||
TEST_F(conntrack_dump_flush, test_flush_by_zone_default)
|
||||
{
|
||||
bool filter = variant->use_cta_filter;
|
||||
int ret;
|
||||
|
||||
ret = conntrack_flush_zone(self->sock, NF_CT_DEFAULT_ZONE_ID);
|
||||
ret = conntrack_flush_zone(self->sock, NF_CT_DEFAULT_ZONE_ID, filter);
|
||||
EXPECT_EQ(ret, 0);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1, filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2);
|
||||
ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2, filter);
|
||||
EXPECT_EQ(ret, 2);
|
||||
ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID);
|
||||
ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID, filter);
|
||||
EXPECT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ table inet filter {
|
|||
}
|
||||
EOF
|
||||
|
||||
# make sure NAT core rewrites adress of icmp error if nat is used according to
|
||||
# make sure NAT core rewrites address of icmp error if nat is used according to
|
||||
# conntrack nat information (icmp error will be directed at nsrouter1 address,
|
||||
# but it needs to be routed to nsclient1 address).
|
||||
ip netns exec "$nsrouter1" nft -f - <<EOF
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user