Skip to content

Commit

Permalink
netfilter: nfnetlink: allow to detect if ctnetlink listeners exist
Browse files Browse the repository at this point in the history
At this time, every new conntrack gets the 'event cache extension'
enabled for it.

This is because the 'net.netfilter.nf_conntrack_events' sysctl defaults
to 1.

Changing the default to 0 means that commands that rely on the event
notification extension, e.g. 'conntrack -E' or conntrackd, stop working.

We COULD detect if there is a listener by means of
'nfnetlink_has_listeners()' and only add the extension if this is true.

The downside is a dependency from conntrack module to nfnetlink module.

This adds a different way: inc/dec a counter whenever a ctnetlink group
is being (un)subscribed and toggle a flag in struct net.

Next patches will take advantage of this and will only add the event
extension if the flag is set.

Signed-off-by: Florian Westphal <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
Florian Westphal authored and ummakynes committed May 13, 2022
1 parent 8169ff5 commit 2794cdb
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
1 change: 1 addition & 0 deletions include/net/netns/conntrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ struct nf_ip_net {

struct netns_ct {
#ifdef CONFIG_NF_CONNTRACK_EVENTS
bool ctnetlink_has_listener;
bool ecache_dwork_pending;
#endif
u8 sysctl_log_invalid; /* Log invalid packets */
Expand Down
40 changes: 37 additions & 3 deletions net/netfilter/nfnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ MODULE_DESCRIPTION("Netfilter messages via netlink socket");
static unsigned int nfnetlink_pernet_id __read_mostly;

struct nfnl_net {
unsigned int ctnetlink_listeners;
struct sock *nfnl;
};

Expand Down Expand Up @@ -654,7 +655,6 @@ static void nfnetlink_rcv(struct sk_buff *skb)
netlink_rcv_skb(skb, nfnetlink_rcv_msg);
}

#ifdef CONFIG_MODULES
static int nfnetlink_bind(struct net *net, int group)
{
const struct nfnetlink_subsystem *ss;
Expand All @@ -670,19 +670,53 @@ static int nfnetlink_bind(struct net *net, int group)
rcu_read_unlock();
if (!ss)
request_module_nowait("nfnetlink-subsys-%d", type);

#ifdef CONFIG_NF_CONNTRACK_EVENTS
if (type == NFNL_SUBSYS_CTNETLINK) {
struct nfnl_net *nfnlnet = nfnl_pernet(net);

nfnl_lock(NFNL_SUBSYS_CTNETLINK);

if (WARN_ON_ONCE(nfnlnet->ctnetlink_listeners == UINT_MAX)) {
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
return -EOVERFLOW;
}

nfnlnet->ctnetlink_listeners++;
if (nfnlnet->ctnetlink_listeners == 1)
WRITE_ONCE(net->ct.ctnetlink_has_listener, true);
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
}
#endif
return 0;
}

static void nfnetlink_unbind(struct net *net, int group)
{
#ifdef CONFIG_NF_CONNTRACK_EVENTS
int type = nfnl_group2type[group];

if (type == NFNL_SUBSYS_CTNETLINK) {
struct nfnl_net *nfnlnet = nfnl_pernet(net);

nfnl_lock(NFNL_SUBSYS_CTNETLINK);
WARN_ON_ONCE(nfnlnet->ctnetlink_listeners == 0);
nfnlnet->ctnetlink_listeners--;
if (nfnlnet->ctnetlink_listeners == 0)
WRITE_ONCE(net->ct.ctnetlink_has_listener, false);
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
}
#endif
}

static int __net_init nfnetlink_net_init(struct net *net)
{
struct nfnl_net *nfnlnet = nfnl_pernet(net);
struct netlink_kernel_cfg cfg = {
.groups = NFNLGRP_MAX,
.input = nfnetlink_rcv,
#ifdef CONFIG_MODULES
.bind = nfnetlink_bind,
#endif
.unbind = nfnetlink_unbind,
};

nfnlnet->nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, &cfg);
Expand Down

0 comments on commit 2794cdb

Please sign in to comment.