Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 834184b1 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso
Browse files

netfilter: defrag: only register defrag functionality if needed



nf_defrag modules for ipv4 and ipv6 export an empty stub function.
Any module that needs the defragmentation hooks registered simply 'calls'
this empty function to create a phony module dependency -- modprobe will
then load the defrag module too.

This extends netfilter ipv4/ipv6 defragmentation modules to delay the hook
registration until the functionality is requested within a network namespace
instead of module load time for all namespaces.

Hooks are only un-registered on module unload or when a namespace that used
such defrag functionality exits.

We have to use struct net for this as the register hooks can be called
before netns initialization here from the ipv4/ipv6 conntrack module
init path.

There is no unregister functionality support, defrag will always be
active once it was requested inside a net namespace.

The reason is that defrag has impact on nft and iptables rulesets
(without defrag we might see framents).

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 481fa373
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
#ifndef _NF_DEFRAG_IPV4_H
#define _NF_DEFRAG_IPV4_H

void nf_defrag_ipv4_enable(void);
struct net;
int nf_defrag_ipv4_enable(struct net *);

#endif /* _NF_DEFRAG_IPV4_H */
+2 −1
Original line number Diff line number Diff line
#ifndef _NF_DEFRAG_IPV6_H
#define _NF_DEFRAG_IPV6_H

void nf_defrag_ipv6_enable(void);
struct net;
int nf_defrag_ipv6_enable(struct net *);

int nf_ct_frag6_init(void);
void nf_ct_frag6_cleanup(void);
+6 −0
Original line number Diff line number Diff line
@@ -17,5 +17,11 @@ struct netns_nf {
	struct ctl_table_header *nf_log_dir_header;
#endif
	struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
	bool			defrag_ipv4;
#endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
	bool			defrag_ipv6;
#endif
};
#endif
+6 −1
Original line number Diff line number Diff line
@@ -325,6 +325,12 @@ static int ipv4_hooks_register(struct net *net)
	if (cnet->users > 1)
		goto out_unlock;

	err = nf_defrag_ipv4_enable(net);
	if (err) {
		cnet->users = 0;
		goto out_unlock;
	}

	err = nf_register_net_hooks(net, ipv4_conntrack_ops,
				    ARRAY_SIZE(ipv4_conntrack_ops));

@@ -422,7 +428,6 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
	int ret = 0;

	need_conntrack();
	nf_defrag_ipv4_enable();

	ret = nf_register_sockopt(&so_getorigdst);
	if (ret < 0) {
+38 −3
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <net/netns/generic.h>
#include <net/route.h>
#include <net/ip.h>

@@ -22,6 +23,8 @@
#endif
#include <net/netfilter/nf_conntrack_zones.h>

static DEFINE_MUTEX(defrag4_mutex);

static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
				   u_int32_t user)
{
@@ -102,18 +105,50 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
	},
};

static void __net_exit defrag4_net_exit(struct net *net)
{
	if (net->nf.defrag_ipv4) {
		nf_unregister_net_hooks(net, ipv4_defrag_ops,
					ARRAY_SIZE(ipv4_defrag_ops));
		net->nf.defrag_ipv4 = false;
	}
}

static struct pernet_operations defrag4_net_ops = {
	.exit = defrag4_net_exit,
};

static int __init nf_defrag_init(void)
{
	return nf_register_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
	return register_pernet_subsys(&defrag4_net_ops);
}

static void __exit nf_defrag_fini(void)
{
	nf_unregister_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
	unregister_pernet_subsys(&defrag4_net_ops);
}

void nf_defrag_ipv4_enable(void)
int nf_defrag_ipv4_enable(struct net *net)
{
	int err = 0;

	might_sleep();

	if (net->nf.defrag_ipv4)
		return 0;

	mutex_lock(&defrag4_mutex);
	if (net->nf.defrag_ipv4)
		goto out_unlock;

	err = nf_register_net_hooks(net, ipv4_defrag_ops,
				    ARRAY_SIZE(ipv4_defrag_ops));
	if (err == 0)
		net->nf.defrag_ipv4 = true;

 out_unlock:
	mutex_unlock(&defrag4_mutex);
	return err;
}
EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);

Loading