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

Commit 08010a21 authored by Flavio Leitner's avatar Flavio Leitner Committed by Pablo Neira Ayuso
Browse files

netfilter: add API to manage NAT helpers.



The API allows a conntrack helper to indicate its corresponding
NAT helper which then can be loaded and reference counted.

Signed-off-by: default avatarFlavio Leitner <fbl@redhat.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent e1f172e1
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -15,7 +15,8 @@
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_conntrack_expect.h>

#define NF_NAT_HELPER_NAME(name)	"ip_nat_" name
#define NF_NAT_HELPER_PREFIX		"ip_nat_"
#define NF_NAT_HELPER_NAME(name)	NF_NAT_HELPER_PREFIX name
#define MODULE_ALIAS_NF_NAT_HELPER(name) \
	MODULE_ALIAS(NF_NAT_HELPER_NAME(name))

@@ -58,6 +59,8 @@ struct nf_conntrack_helper {
	unsigned int queue_num;
	/* length of userspace private data stored in nf_conn_help->data */
	u16 data_len;
	/* name of NAT helper module */
	char nat_mod_name[NF_CT_HELPER_NAME_LEN];
};

/* Must be kept in sync with the classes defined by helpers */
@@ -157,4 +160,21 @@ nf_ct_helper_expectfn_find_by_symbol(const void *symbol);
extern struct hlist_head *nf_ct_helper_hash;
extern unsigned int nf_ct_helper_hsize;

struct nf_conntrack_nat_helper {
	struct list_head list;
	char mod_name[NF_CT_HELPER_NAME_LEN];	/* module name */
	struct module *module;			/* pointer to self */
};

#define NF_CT_NAT_HELPER_INIT(name) \
	{ \
	.mod_name = NF_NAT_HELPER_NAME(name), \
	.module = THIS_MODULE \
	}

void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat);
void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat);
int nf_nat_helper_try_module_get(const char *name, u16 l3num,
				 u8 protonum);
void nf_nat_helper_put(struct nf_conntrack_helper *helper);
#endif /*_NF_CONNTRACK_HELPER_H*/
+6 −2
Original line number Diff line number Diff line
@@ -28,11 +28,13 @@
static unsigned int master_timeout __read_mostly = 300;
static char *ts_algo = "kmp";

#define HELPER_NAME "amanda"

MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
MODULE_DESCRIPTION("Amanda connection tracking module");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_conntrack_amanda");
MODULE_ALIAS_NFCT_HELPER("amanda");
MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);

module_param(master_timeout, uint, 0600);
MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
@@ -179,13 +181,14 @@ static const struct nf_conntrack_expect_policy amanda_exp_policy = {

static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
	{
		.name			= "amanda",
		.name			= HELPER_NAME,
		.me			= THIS_MODULE,
		.help			= amanda_help,
		.tuple.src.l3num	= AF_INET,
		.tuple.src.u.udp.port	= cpu_to_be16(10080),
		.tuple.dst.protonum	= IPPROTO_UDP,
		.expect_policy		= &amanda_exp_policy,
		.nat_mod_name		= NF_NAT_HELPER_NAME(HELPER_NAME),
	},
	{
		.name			= "amanda",
@@ -195,6 +198,7 @@ static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
		.tuple.src.u.udp.port	= cpu_to_be16(10080),
		.tuple.dst.protonum	= IPPROTO_UDP,
		.expect_policy		= &amanda_exp_policy,
		.nat_mod_name		= NF_NAT_HELPER_NAME(HELPER_NAME),
	},
};

+11 −7
Original line number Diff line number Diff line
@@ -29,11 +29,13 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <linux/netfilter/nf_conntrack_ftp.h>

#define HELPER_NAME "ftp"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
MODULE_DESCRIPTION("ftp connection tracking helper");
MODULE_ALIAS("ip_conntrack_ftp");
MODULE_ALIAS_NFCT_HELPER("ftp");
MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);

/* This is slow, but it's simple. --RR */
static char *ftp_buffer;
@@ -588,12 +590,14 @@ static int __init nf_conntrack_ftp_init(void)
	/* FIXME should be configurable whether IPv4 and IPv6 FTP connections
		 are tracked or not - YK */
	for (i = 0; i < ports_c; i++) {
		nf_ct_helper_init(&ftp[2 * i], AF_INET, IPPROTO_TCP, "ftp",
				  FTP_PORT, ports[i], ports[i], &ftp_exp_policy,
				  0, help, nf_ct_ftp_from_nlattr, THIS_MODULE);
		nf_ct_helper_init(&ftp[2 * i + 1], AF_INET6, IPPROTO_TCP, "ftp",
				  FTP_PORT, ports[i], ports[i], &ftp_exp_policy,
				  0, help, nf_ct_ftp_from_nlattr, THIS_MODULE);
		nf_ct_helper_init(&ftp[2 * i], AF_INET, IPPROTO_TCP,
				  HELPER_NAME, FTP_PORT, ports[i], ports[i],
				  &ftp_exp_policy, 0, help,
				  nf_ct_ftp_from_nlattr, THIS_MODULE);
		nf_ct_helper_init(&ftp[2 * i + 1], AF_INET6, IPPROTO_TCP,
				  HELPER_NAME, FTP_PORT, ports[i], ports[i],
				  &ftp_exp_policy, 0, help,
				  nf_ct_ftp_from_nlattr, THIS_MODULE);
	}

	ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
+86 −0
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@ module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
MODULE_PARM_DESC(nf_conntrack_helper,
		 "Enable automatic conntrack helper assignment (default 0)");

static DEFINE_MUTEX(nf_ct_nat_helpers_mutex);
static struct list_head nf_ct_nat_helpers __read_mostly;

/* Stupid hash, but collision free for the default registrations of the
 * helpers currently in the kernel. */
static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
@@ -130,6 +133,70 @@ void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);

static struct nf_conntrack_nat_helper *
nf_conntrack_nat_helper_find(const char *mod_name)
{
	struct nf_conntrack_nat_helper *cur;
	bool found = false;

	list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) {
		if (!strcmp(cur->mod_name, mod_name)) {
			found = true;
			break;
		}
	}
	return found ? cur : NULL;
}

int
nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
{
	struct nf_conntrack_helper *h;
	struct nf_conntrack_nat_helper *nat;
	char mod_name[NF_CT_HELPER_NAME_LEN];
	int ret = 0;

	rcu_read_lock();
	h = __nf_conntrack_helper_find(name, l3num, protonum);
	if (!h) {
		rcu_read_unlock();
		return -ENOENT;
	}

	nat = nf_conntrack_nat_helper_find(h->nat_mod_name);
	if (!nat) {
		snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name);
		rcu_read_unlock();
		request_module(mod_name);

		rcu_read_lock();
		nat = nf_conntrack_nat_helper_find(mod_name);
		if (!nat) {
			rcu_read_unlock();
			return -ENOENT;
		}
	}

	if (!try_module_get(nat->module))
		ret = -ENOENT;

	rcu_read_unlock();
	return ret;
}
EXPORT_SYMBOL_GPL(nf_nat_helper_try_module_get);

void nf_nat_helper_put(struct nf_conntrack_helper *helper)
{
	struct nf_conntrack_nat_helper *nat;

	nat = nf_conntrack_nat_helper_find(helper->nat_mod_name);
	if (WARN_ON_ONCE(!nat))
		return;

	module_put(nat->module);
}
EXPORT_SYMBOL_GPL(nf_nat_helper_put);

struct nf_conn_help *
nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
{
@@ -430,6 +497,8 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
	helper->help = help;
	helper->from_nlattr = from_nlattr;
	helper->me = module;
	snprintf(helper->nat_mod_name, sizeof(helper->nat_mod_name),
		 NF_NAT_HELPER_PREFIX "%s", name);

	if (spec_port == default_port)
		snprintf(helper->name, sizeof(helper->name), "%s", name);
@@ -466,6 +535,22 @@ void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *helper,
}
EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);

void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat)
{
	mutex_lock(&nf_ct_nat_helpers_mutex);
	list_add_rcu(&nat->list, &nf_ct_nat_helpers);
	mutex_unlock(&nf_ct_nat_helpers_mutex);
}
EXPORT_SYMBOL_GPL(nf_nat_helper_register);

void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat)
{
	mutex_lock(&nf_ct_nat_helpers_mutex);
	list_del_rcu(&nat->list);
	mutex_unlock(&nf_ct_nat_helpers_mutex);
}
EXPORT_SYMBOL_GPL(nf_nat_helper_unregister);

static const struct nf_ct_ext_type helper_extend = {
	.len	= sizeof(struct nf_conn_help),
	.align	= __alignof__(struct nf_conn_help),
@@ -493,6 +578,7 @@ int nf_conntrack_helper_init(void)
		goto out_extend;
	}

	INIT_LIST_HEAD(&nf_ct_nat_helpers);
	return 0;
out_extend:
	kvfree(nf_ct_helper_hash);
+4 −2
Original line number Diff line number Diff line
@@ -42,11 +42,13 @@ unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
				struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_irc_hook);

#define HELPER_NAME "irc"

MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_conntrack_irc");
MODULE_ALIAS_NFCT_HELPER("irc");
MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);

module_param_array(ports, ushort, &ports_c, 0400);
MODULE_PARM_DESC(ports, "port numbers of IRC servers");
@@ -259,7 +261,7 @@ static int __init nf_conntrack_irc_init(void)
		ports[ports_c++] = IRC_PORT;

	for (i = 0; i < ports_c; i++) {
		nf_ct_helper_init(&irc[i], AF_INET, IPPROTO_TCP, "irc",
		nf_ct_helper_init(&irc[i], AF_INET, IPPROTO_TCP, HELPER_NAME,
				  IRC_PORT, ports[i], i, &irc_exp_policy,
				  0, help, NULL, THIS_MODULE);
	}
Loading