mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	netfilter: nfnetlink: allow to detect if ctnetlink listeners exist
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 <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
		
							parent
							
								
									8169ff5840
								
							
						
					
					
						commit
						2794cdb0b9
					
				
					 2 changed files with 38 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -670,9 +670,44 @@ 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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -680,9 +715,8 @@ static int __net_init nfnetlink_net_init(struct net *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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue