mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
netfilter: nf_conntrack_helper: dynamically allocate struct nf_conntrack_helper
Adapt all existing helpers to use a modified version of nf_ct_helper_init(), to dynamically allocate struct nf_conntrack_helper. Allocate expect_policy[] built-in into the helper to ensure this area is reachable after helper removal since a follow up patch adds refcount to track use of the nf_conntrack_helper structure from packet path so it remains around until last reference from ct helper extension is dropped. Export __nf_conntrack_helper_register() which allows to register nfnetlink_cthelper dynamically allocated helper. Adapt nfnetlink_cthelper to use the built-in expect_policy[]. This is a preparation patch to add packet path refcounting to helpers. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
@@ -29,13 +29,16 @@ enum nf_ct_helper_flags {
|
||||
|
||||
#define NF_CT_HELPER_NAME_LEN 16
|
||||
|
||||
/* Must be kept in sync with the classes defined by helpers */
|
||||
#define NF_CT_MAX_EXPECT_CLASSES 4
|
||||
|
||||
struct nf_conntrack_helper {
|
||||
struct hlist_node hnode; /* Internal use. */
|
||||
|
||||
char name[NF_CT_HELPER_NAME_LEN]; /* name of the module */
|
||||
refcount_t refcnt;
|
||||
struct module *me; /* pointer to self */
|
||||
const struct nf_conntrack_expect_policy *expect_policy;
|
||||
struct nf_conntrack_expect_policy expect_policy[NF_CT_MAX_EXPECT_CLASSES];
|
||||
|
||||
/* Tuple of things we will help (compared against server response) */
|
||||
struct nf_conntrack_tuple tuple;
|
||||
@@ -63,9 +66,6 @@ struct nf_conntrack_helper {
|
||||
char nat_mod_name[NF_CT_HELPER_NAME_LEN];
|
||||
};
|
||||
|
||||
/* Must be kept in sync with the classes defined by helpers */
|
||||
#define NF_CT_MAX_EXPECT_CLASSES 4
|
||||
|
||||
/* nf_conn feature for connections that have a helper */
|
||||
struct nf_conn_help {
|
||||
/* Helper. if any */
|
||||
@@ -103,11 +103,13 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
|
||||
struct nf_conn *ct),
|
||||
struct module *module);
|
||||
|
||||
int nf_conntrack_helper_register(struct nf_conntrack_helper *);
|
||||
int nf_conntrack_helper_register(struct nf_conntrack_helper *, struct nf_conntrack_helper **);
|
||||
int __nf_conntrack_helper_register(struct nf_conntrack_helper *);
|
||||
void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
|
||||
|
||||
int nf_conntrack_helpers_register(struct nf_conntrack_helper *, unsigned int);
|
||||
void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *,
|
||||
int nf_conntrack_helpers_register(struct nf_conntrack_helper *, unsigned int,
|
||||
struct nf_conntrack_helper **);
|
||||
void nf_conntrack_helpers_unregister(struct nf_conntrack_helper **,
|
||||
unsigned int);
|
||||
|
||||
struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
|
||||
|
||||
@@ -202,29 +202,34 @@ static const struct nf_conntrack_expect_policy snmp_exp_policy = {
|
||||
.timeout = 180,
|
||||
};
|
||||
|
||||
static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {
|
||||
.me = THIS_MODULE,
|
||||
.help = help,
|
||||
.expect_policy = &snmp_exp_policy,
|
||||
.name = "snmp_trap",
|
||||
.tuple.src.l3num = AF_INET,
|
||||
.tuple.src.u.udp.port = cpu_to_be16(SNMP_TRAP_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_UDP,
|
||||
};
|
||||
static struct nf_conntrack_helper snmp_trap_helper __read_mostly;
|
||||
static struct nf_conntrack_helper *snmp_trap_helper_ptr __read_mostly;
|
||||
|
||||
static int __init nf_nat_snmp_basic_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
BUG_ON(nf_nat_snmp_hook != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_snmp_hook, help);
|
||||
|
||||
return nf_conntrack_helper_register(&snmp_trap_helper);
|
||||
nf_ct_helper_init(&snmp_trap_helper, AF_INET, IPPROTO_UDP,
|
||||
"snmp_trap", SNMP_TRAP_PORT, SNMP_TRAP_PORT, SNMP_TRAP_PORT,
|
||||
&snmp_exp_policy, 0, help, NULL, THIS_MODULE);
|
||||
|
||||
err = nf_conntrack_helper_register(&snmp_trap_helper, &snmp_trap_helper_ptr);
|
||||
if (err < 0) {
|
||||
RCU_INIT_POINTER(nf_nat_snmp_hook, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_nat_snmp_basic_fini(void)
|
||||
{
|
||||
RCU_INIT_POINTER(nf_nat_snmp_hook, NULL);
|
||||
synchronize_rcu();
|
||||
nf_conntrack_helper_unregister(&snmp_trap_helper);
|
||||
nf_conntrack_helper_unregister(snmp_trap_helper_ptr);
|
||||
}
|
||||
|
||||
module_init(nf_nat_snmp_basic_init);
|
||||
|
||||
@@ -169,35 +169,15 @@ static const struct nf_conntrack_expect_policy amanda_exp_policy = {
|
||||
.timeout = 180,
|
||||
};
|
||||
|
||||
static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
|
||||
{
|
||||
.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",
|
||||
.me = THIS_MODULE,
|
||||
.help = amanda_help,
|
||||
.tuple.src.l3num = AF_INET6,
|
||||
.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),
|
||||
},
|
||||
};
|
||||
static struct nf_conntrack_helper amanda_helper[2] __read_mostly;
|
||||
static struct nf_conntrack_helper *amanda_helper_ptr[2] __read_mostly;
|
||||
|
||||
static void __exit nf_conntrack_amanda_fini(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
nf_conntrack_helpers_unregister(amanda_helper,
|
||||
ARRAY_SIZE(amanda_helper));
|
||||
nf_conntrack_helpers_unregister(amanda_helper_ptr,
|
||||
ARRAY_SIZE(amanda_helper_ptr));
|
||||
for (i = 0; i < ARRAY_SIZE(search); i++)
|
||||
textsearch_destroy(search[i].ts);
|
||||
}
|
||||
@@ -217,8 +197,17 @@ static int __init nf_conntrack_amanda_init(void)
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
nf_ct_helper_init(&amanda_helper[0], AF_INET, IPPROTO_UDP,
|
||||
HELPER_NAME, 10080, 10080, 10080,
|
||||
&amanda_exp_policy, 0, amanda_help, NULL, THIS_MODULE);
|
||||
nf_ct_helper_init(&amanda_helper[1], AF_INET6, IPPROTO_UDP,
|
||||
HELPER_NAME, 10080, 10080, 10080,
|
||||
&amanda_exp_policy, 0, amanda_help, NULL, THIS_MODULE);
|
||||
|
||||
ret = nf_conntrack_helpers_register(amanda_helper,
|
||||
ARRAY_SIZE(amanda_helper));
|
||||
ARRAY_SIZE(amanda_helper),
|
||||
amanda_helper_ptr);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
return 0;
|
||||
|
||||
@@ -555,6 +555,7 @@ static int nf_ct_ftp_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper ftp[MAX_PORTS * 2] __read_mostly;
|
||||
static struct nf_conntrack_helper *ftp_ptr[MAX_PORTS * 2] __read_mostly;
|
||||
|
||||
static const struct nf_conntrack_expect_policy ftp_exp_policy = {
|
||||
.max_expected = 1,
|
||||
@@ -563,7 +564,7 @@ static const struct nf_conntrack_expect_policy ftp_exp_policy = {
|
||||
|
||||
static void __exit nf_conntrack_ftp_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(ftp, ports_c * 2);
|
||||
nf_conntrack_helpers_unregister(ftp_ptr, ports_c * 2);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_ftp_init(void)
|
||||
@@ -588,7 +589,7 @@ static int __init nf_conntrack_ftp_init(void)
|
||||
nf_ct_ftp_from_nlattr, THIS_MODULE);
|
||||
}
|
||||
|
||||
ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
|
||||
ret = nf_conntrack_helpers_register(ftp, ports_c * 2, ftp_ptr);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to register helpers\n");
|
||||
return ret;
|
||||
|
||||
@@ -577,14 +577,8 @@ static const struct nf_conntrack_expect_policy h245_exp_policy = {
|
||||
.timeout = 240,
|
||||
};
|
||||
|
||||
static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
|
||||
.name = "H.245",
|
||||
.me = THIS_MODULE,
|
||||
.tuple.src.l3num = AF_UNSPEC,
|
||||
.tuple.dst.protonum = IPPROTO_UDP,
|
||||
.help = h245_help,
|
||||
.expect_policy = &h245_exp_policy,
|
||||
};
|
||||
static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly;
|
||||
static struct nf_conntrack_helper *nf_conntrack_helper_h245_ptr __read_mostly;
|
||||
|
||||
int get_h225_addr(struct nf_conn *ct, unsigned char *data,
|
||||
TransportAddress *taddr,
|
||||
@@ -643,7 +637,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
|
||||
&ct->tuplehash[!dir].tuple.src.u3,
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
IPPROTO_TCP, NULL, &port);
|
||||
rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_h245_ptr);
|
||||
|
||||
nathook = rcu_dereference(nfct_h323_nat_hook);
|
||||
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
|
||||
@@ -732,6 +726,9 @@ static int callforward_do_filter(struct net *net,
|
||||
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper nf_conntrack_helper_q931[2] __read_mostly;
|
||||
static struct nf_conntrack_helper *nf_conntrack_helper_q931_ptr[2] __read_mostly;
|
||||
|
||||
static int expect_callforwarding(struct sk_buff *skb,
|
||||
struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
@@ -767,7 +764,7 @@ static int expect_callforwarding(struct sk_buff *skb,
|
||||
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
|
||||
&ct->tuplehash[!dir].tuple.src.u3, &addr,
|
||||
IPPROTO_TCP, NULL, &port);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931_ptr[0]);
|
||||
|
||||
nathook = rcu_dereference(nfct_h323_nat_hook);
|
||||
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
|
||||
@@ -1140,27 +1137,6 @@ static const struct nf_conntrack_expect_policy q931_exp_policy = {
|
||||
.timeout = 240,
|
||||
};
|
||||
|
||||
static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
|
||||
{
|
||||
.name = "Q.931",
|
||||
.me = THIS_MODULE,
|
||||
.tuple.src.l3num = AF_INET,
|
||||
.tuple.src.u.tcp.port = cpu_to_be16(Q931_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_TCP,
|
||||
.help = q931_help,
|
||||
.expect_policy = &q931_exp_policy,
|
||||
},
|
||||
{
|
||||
.name = "Q.931",
|
||||
.me = THIS_MODULE,
|
||||
.tuple.src.l3num = AF_INET6,
|
||||
.tuple.src.u.tcp.port = cpu_to_be16(Q931_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_TCP,
|
||||
.help = q931_help,
|
||||
.expect_policy = &q931_exp_policy,
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
|
||||
int *datalen)
|
||||
{
|
||||
@@ -1234,7 +1210,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
|
||||
&ct->tuplehash[!dir].tuple.src.u3 : NULL,
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
IPPROTO_TCP, NULL, &port);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931_ptr[0]);
|
||||
exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
|
||||
|
||||
nathook = rcu_dereference(nfct_h323_nat_hook);
|
||||
@@ -1275,6 +1251,9 @@ static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper nf_conntrack_helper_ras[2] __read_mostly;
|
||||
static struct nf_conntrack_helper *nf_conntrack_helper_ras_ptr[2] __read_mostly;
|
||||
|
||||
static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff,
|
||||
@@ -1306,7 +1285,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
|
||||
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
|
||||
&ct->tuplehash[!dir].tuple.src.u3, &addr,
|
||||
IPPROTO_UDP, NULL, &port);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras_ptr[0]);
|
||||
|
||||
if (nf_ct_expect_related(exp, 0) == 0) {
|
||||
pr_debug("nf_ct_ras: expect RAS ");
|
||||
@@ -1523,7 +1502,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
|
||||
&ct->tuplehash[!dir].tuple.src.u3, &addr,
|
||||
IPPROTO_TCP, NULL, &port);
|
||||
exp->flags = NF_CT_EXPECT_PERMANENT;
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931_ptr[0]);
|
||||
|
||||
if (nf_ct_expect_related(exp, 0) == 0) {
|
||||
pr_debug("nf_ct_ras: expect Q.931 ");
|
||||
@@ -1577,7 +1556,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
|
||||
&ct->tuplehash[!dir].tuple.src.u3, &addr,
|
||||
IPPROTO_TCP, NULL, &port);
|
||||
exp->flags = NF_CT_EXPECT_PERMANENT;
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931);
|
||||
rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931_ptr[0]);
|
||||
|
||||
if (nf_ct_expect_related(exp, 0) == 0) {
|
||||
pr_debug("nf_ct_ras: expect Q.931 ");
|
||||
@@ -1711,59 +1690,57 @@ static const struct nf_conntrack_expect_policy ras_exp_policy = {
|
||||
.timeout = 240,
|
||||
};
|
||||
|
||||
static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
|
||||
{
|
||||
.name = "RAS",
|
||||
.me = THIS_MODULE,
|
||||
.tuple.src.l3num = AF_INET,
|
||||
.tuple.src.u.udp.port = cpu_to_be16(RAS_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_UDP,
|
||||
.help = ras_help,
|
||||
.expect_policy = &ras_exp_policy,
|
||||
},
|
||||
{
|
||||
.name = "RAS",
|
||||
.me = THIS_MODULE,
|
||||
.tuple.src.l3num = AF_INET6,
|
||||
.tuple.src.u.udp.port = cpu_to_be16(RAS_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_UDP,
|
||||
.help = ras_help,
|
||||
.expect_policy = &ras_exp_policy,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init h323_helper_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nf_conntrack_helper_register(&nf_conntrack_helper_h245);
|
||||
nf_ct_helper_init(&nf_conntrack_helper_ras[0], AF_INET, IPPROTO_UDP,
|
||||
"RAS", RAS_PORT, RAS_PORT, RAS_PORT,
|
||||
&ras_exp_policy, 0, ras_help, NULL, THIS_MODULE);
|
||||
nf_ct_helper_init(&nf_conntrack_helper_ras[1], AF_INET6, IPPROTO_UDP,
|
||||
"RAS", RAS_PORT, RAS_PORT, RAS_PORT,
|
||||
&ras_exp_policy, 0, ras_help, NULL, THIS_MODULE);
|
||||
nf_ct_helper_init(&nf_conntrack_helper_h245, AF_UNSPEC, IPPROTO_UDP,
|
||||
"H.245", 0, 0, 0,
|
||||
&h245_exp_policy, 0, h245_help, NULL, THIS_MODULE);
|
||||
nf_ct_helper_init(&nf_conntrack_helper_q931[0], AF_INET, IPPROTO_TCP,
|
||||
"Q.931", Q931_PORT, Q931_PORT, Q931_PORT,
|
||||
&q931_exp_policy, 0, q931_help, NULL, THIS_MODULE);
|
||||
nf_ct_helper_init(&nf_conntrack_helper_q931[1], AF_INET6, IPPROTO_TCP,
|
||||
"Q.931", Q931_PORT, Q931_PORT, Q931_PORT,
|
||||
&q931_exp_policy, 0, q931_help, NULL, THIS_MODULE);
|
||||
|
||||
ret = nf_conntrack_helper_register(&nf_conntrack_helper_h245,
|
||||
&nf_conntrack_helper_h245_ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = nf_conntrack_helpers_register(nf_conntrack_helper_q931,
|
||||
ARRAY_SIZE(nf_conntrack_helper_q931));
|
||||
ARRAY_SIZE(nf_conntrack_helper_q931),
|
||||
nf_conntrack_helper_q931_ptr);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
ret = nf_conntrack_helpers_register(nf_conntrack_helper_ras,
|
||||
ARRAY_SIZE(nf_conntrack_helper_ras));
|
||||
ARRAY_SIZE(nf_conntrack_helper_ras),
|
||||
nf_conntrack_helper_ras_ptr);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
nf_conntrack_helpers_unregister(nf_conntrack_helper_q931,
|
||||
ARRAY_SIZE(nf_conntrack_helper_q931));
|
||||
nf_conntrack_helpers_unregister(nf_conntrack_helper_q931_ptr,
|
||||
ARRAY_SIZE(nf_conntrack_helper_q931_ptr));
|
||||
err1:
|
||||
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
|
||||
nf_conntrack_helper_unregister(nf_conntrack_helper_h245_ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit h323_helper_exit(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(nf_conntrack_helper_ras,
|
||||
nf_conntrack_helpers_unregister(nf_conntrack_helper_ras_ptr,
|
||||
ARRAY_SIZE(nf_conntrack_helper_ras));
|
||||
nf_conntrack_helpers_unregister(nf_conntrack_helper_q931,
|
||||
nf_conntrack_helpers_unregister(nf_conntrack_helper_q931_ptr,
|
||||
ARRAY_SIZE(nf_conntrack_helper_q931));
|
||||
nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
|
||||
nf_conntrack_helper_unregister(nf_conntrack_helper_h245_ptr);
|
||||
}
|
||||
|
||||
static void __exit nf_conntrack_h323_fini(void)
|
||||
|
||||
@@ -347,14 +347,13 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_helper_log);
|
||||
|
||||
int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
|
||||
int __nf_conntrack_helper_register(struct nf_conntrack_helper *me)
|
||||
{
|
||||
struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
|
||||
unsigned int h = helper_hash(&me->tuple);
|
||||
struct nf_conntrack_helper *cur;
|
||||
int ret = 0, i;
|
||||
|
||||
BUG_ON(me->expect_policy == NULL);
|
||||
BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
|
||||
BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
|
||||
|
||||
@@ -394,6 +393,33 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
|
||||
mutex_unlock(&nf_ct_helper_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__nf_conntrack_helper_register);
|
||||
|
||||
int nf_conntrack_helper_register(struct nf_conntrack_helper *me,
|
||||
struct nf_conntrack_helper **helper_ptr)
|
||||
{
|
||||
struct nf_conntrack_helper *new_helper;
|
||||
int err;
|
||||
|
||||
new_helper = kzalloc_obj(*new_helper, GFP_KERNEL_ACCOUNT);
|
||||
if (!new_helper)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(new_helper, me, sizeof(*new_helper));
|
||||
*helper_ptr = new_helper;
|
||||
|
||||
err = __nf_conntrack_helper_register(new_helper);
|
||||
if (err < 0)
|
||||
goto err_helper;
|
||||
|
||||
return 0;
|
||||
|
||||
err_helper:
|
||||
*helper_ptr = NULL;
|
||||
kfree(new_helper);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
|
||||
|
||||
static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
|
||||
@@ -430,6 +456,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
|
||||
* last step, this ensures rcu readers of exp->helper are done.
|
||||
* No need for another synchronize_rcu() here.
|
||||
*/
|
||||
kfree(me);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
|
||||
|
||||
@@ -445,11 +472,12 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
|
||||
struct nf_conn *ct),
|
||||
struct module *module)
|
||||
{
|
||||
memset(helper, 0, sizeof(*helper));
|
||||
|
||||
helper->tuple.src.l3num = l3num;
|
||||
helper->tuple.dst.protonum = protonum;
|
||||
helper->tuple.src.u.all = htons(spec_port);
|
||||
helper->expect_policy = exp_pol;
|
||||
helper->expect_class_max = expect_class_max;
|
||||
|
||||
helper->help = help;
|
||||
helper->from_nlattr = from_nlattr;
|
||||
helper->me = module;
|
||||
@@ -460,34 +488,57 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
|
||||
snprintf(helper->name, sizeof(helper->name), "%s", name);
|
||||
else
|
||||
snprintf(helper->name, sizeof(helper->name), "%s-%u", name, id);
|
||||
|
||||
if (WARN_ON_ONCE(expect_class_max >= NF_CT_MAX_EXPECT_CLASSES))
|
||||
return;
|
||||
|
||||
memcpy(helper->expect_policy, exp_pol,
|
||||
(expect_class_max + 1) * sizeof(*exp_pol));
|
||||
helper->expect_class_max = expect_class_max;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_helper_init);
|
||||
|
||||
int nf_conntrack_helpers_register(struct nf_conntrack_helper *helper,
|
||||
unsigned int n)
|
||||
unsigned int n, struct nf_conntrack_helper **helper_ptr)
|
||||
{
|
||||
struct nf_conntrack_helper *new_helper;
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
err = nf_conntrack_helper_register(&helper[i]);
|
||||
if (err < 0)
|
||||
new_helper = kzalloc_obj(*new_helper, GFP_KERNEL_ACCOUNT);
|
||||
if (!new_helper) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(new_helper, &helper[i], sizeof(*new_helper));
|
||||
helper_ptr[i] = new_helper;
|
||||
|
||||
err = __nf_conntrack_helper_register(new_helper);
|
||||
if (err < 0) {
|
||||
helper_ptr[i] = NULL;
|
||||
goto err_helper;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
err_helper:
|
||||
kfree(new_helper);
|
||||
err:
|
||||
if (i > 0)
|
||||
nf_conntrack_helpers_unregister(helper, i);
|
||||
nf_conntrack_helpers_unregister(helper_ptr, i);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_helpers_register);
|
||||
|
||||
void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *helper,
|
||||
unsigned int n)
|
||||
void nf_conntrack_helpers_unregister(struct nf_conntrack_helper **helper,
|
||||
unsigned int n)
|
||||
{
|
||||
while (n-- > 0)
|
||||
nf_conntrack_helper_unregister(&helper[n]);
|
||||
while (n-- > 0) {
|
||||
nf_conntrack_helper_unregister(helper[n]);
|
||||
helper[n] = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
|
||||
|
||||
|
||||
@@ -255,6 +255,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly;
|
||||
static struct nf_conntrack_helper *irc_ptr[MAX_PORTS] __read_mostly;
|
||||
static struct nf_conntrack_expect_policy irc_exp_policy;
|
||||
|
||||
static int __init nf_conntrack_irc_init(void)
|
||||
@@ -289,7 +290,7 @@ static int __init nf_conntrack_irc_init(void)
|
||||
0, help, NULL, THIS_MODULE);
|
||||
}
|
||||
|
||||
ret = nf_conntrack_helpers_register(&irc[0], ports_c);
|
||||
ret = nf_conntrack_helpers_register(&irc[0], ports_c, irc_ptr);
|
||||
if (ret) {
|
||||
pr_err("failed to register helpers\n");
|
||||
kfree(irc_buffer);
|
||||
@@ -301,7 +302,7 @@ static int __init nf_conntrack_irc_init(void)
|
||||
|
||||
static void __exit nf_conntrack_irc_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(irc, ports_c);
|
||||
nf_conntrack_helpers_unregister(irc_ptr, ports_c);
|
||||
kfree(irc_buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,27 +44,25 @@ static int netbios_ns_help(struct sk_buff *skb, unsigned int protoff,
|
||||
return nf_conntrack_broadcast_help(skb, ct, ctinfo, timeout);
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper helper __read_mostly = {
|
||||
.name = HELPER_NAME,
|
||||
.tuple.src.l3num = NFPROTO_IPV4,
|
||||
.tuple.src.u.udp.port = cpu_to_be16(NMBD_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_UDP,
|
||||
.me = THIS_MODULE,
|
||||
.help = netbios_ns_help,
|
||||
.expect_policy = &exp_policy,
|
||||
};
|
||||
static struct nf_conntrack_helper helper __read_mostly;
|
||||
static struct nf_conntrack_helper *helper_ptr __read_mostly;
|
||||
|
||||
static int __init nf_conntrack_netbios_ns_init(void)
|
||||
{
|
||||
NF_CT_HELPER_BUILD_BUG_ON(0);
|
||||
|
||||
exp_policy.timeout = timeout;
|
||||
return nf_conntrack_helper_register(&helper);
|
||||
|
||||
nf_ct_helper_init(&helper, AF_INET, IPPROTO_UDP, HELPER_NAME,
|
||||
NMBD_PORT, NMBD_PORT, NMBD_PORT,
|
||||
&exp_policy, 0, netbios_ns_help, NULL, THIS_MODULE);
|
||||
|
||||
return nf_conntrack_helper_register(&helper, &helper_ptr);
|
||||
}
|
||||
|
||||
static void __exit nf_conntrack_netbios_ns_fini(void)
|
||||
{
|
||||
nf_conntrack_helper_unregister(&helper);
|
||||
nf_conntrack_helper_unregister(helper_ptr);
|
||||
}
|
||||
|
||||
module_init(nf_conntrack_netbios_ns_init);
|
||||
|
||||
@@ -582,27 +582,25 @@ static const struct nf_conntrack_expect_policy pptp_exp_policy = {
|
||||
};
|
||||
|
||||
/* control protocol helper */
|
||||
static struct nf_conntrack_helper pptp __read_mostly = {
|
||||
.name = "pptp",
|
||||
.me = THIS_MODULE,
|
||||
.tuple.src.l3num = AF_INET,
|
||||
.tuple.src.u.tcp.port = cpu_to_be16(PPTP_CONTROL_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_TCP,
|
||||
.help = conntrack_pptp_help,
|
||||
.destroy = pptp_destroy_siblings,
|
||||
.expect_policy = &pptp_exp_policy,
|
||||
};
|
||||
static struct nf_conntrack_helper pptp __read_mostly;
|
||||
static struct nf_conntrack_helper *pptp_ptr __read_mostly;
|
||||
|
||||
static int __init nf_conntrack_pptp_init(void)
|
||||
{
|
||||
NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_pptp_master));
|
||||
|
||||
return nf_conntrack_helper_register(&pptp);
|
||||
nf_ct_helper_init(&pptp, AF_INET, IPPROTO_TCP,
|
||||
"pptp", PPTP_CONTROL_PORT, PPTP_CONTROL_PORT, PPTP_CONTROL_PORT,
|
||||
&pptp_exp_policy, 0, conntrack_pptp_help, NULL, THIS_MODULE);
|
||||
|
||||
pptp.destroy = pptp_destroy_siblings;
|
||||
|
||||
return nf_conntrack_helper_register(&pptp, &pptp_ptr);
|
||||
}
|
||||
|
||||
static void __exit nf_conntrack_pptp_fini(void)
|
||||
{
|
||||
nf_conntrack_helper_unregister(&pptp);
|
||||
nf_conntrack_helper_unregister(pptp_ptr);
|
||||
}
|
||||
|
||||
module_init(nf_conntrack_pptp_init);
|
||||
|
||||
@@ -167,6 +167,7 @@ static int help(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper sane[MAX_PORTS * 2] __read_mostly;
|
||||
static struct nf_conntrack_helper *sane_ptr[MAX_PORTS * 2] __read_mostly;
|
||||
|
||||
static const struct nf_conntrack_expect_policy sane_exp_policy = {
|
||||
.max_expected = 1,
|
||||
@@ -175,7 +176,7 @@ static const struct nf_conntrack_expect_policy sane_exp_policy = {
|
||||
|
||||
static void __exit nf_conntrack_sane_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(sane, ports_c * 2);
|
||||
nf_conntrack_helpers_unregister(sane_ptr, ports_c * 2);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_sane_init(void)
|
||||
@@ -200,7 +201,7 @@ static int __init nf_conntrack_sane_init(void)
|
||||
THIS_MODULE);
|
||||
}
|
||||
|
||||
ret = nf_conntrack_helpers_register(sane, ports_c * 2);
|
||||
ret = nf_conntrack_helpers_register(sane, ports_c * 2, sane_ptr);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to register helpers\n");
|
||||
return ret;
|
||||
|
||||
@@ -1731,6 +1731,7 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff,
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper sip[MAX_PORTS * 4] __read_mostly;
|
||||
static struct nf_conntrack_helper *sip_ptr[MAX_PORTS * 4] __read_mostly;
|
||||
|
||||
static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
|
||||
[SIP_EXPECT_SIGNALLING] = {
|
||||
@@ -1757,7 +1758,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1
|
||||
|
||||
static void __exit nf_conntrack_sip_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(sip, ports_c * 4);
|
||||
nf_conntrack_helpers_unregister(sip_ptr, ports_c * 4);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_sip_init(void)
|
||||
@@ -1788,7 +1789,7 @@ static int __init nf_conntrack_sip_init(void)
|
||||
NULL, THIS_MODULE);
|
||||
}
|
||||
|
||||
ret = nf_conntrack_helpers_register(sip, ports_c * 4);
|
||||
ret = nf_conntrack_helpers_register(sip, ports_c * 4, sip_ptr);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to register helpers\n");
|
||||
return ret;
|
||||
|
||||
@@ -47,25 +47,24 @@ static struct nf_conntrack_expect_policy exp_policy = {
|
||||
.max_expected = 1,
|
||||
};
|
||||
|
||||
static struct nf_conntrack_helper helper __read_mostly = {
|
||||
.name = "snmp",
|
||||
.tuple.src.l3num = NFPROTO_IPV4,
|
||||
.tuple.src.u.udp.port = cpu_to_be16(SNMP_PORT),
|
||||
.tuple.dst.protonum = IPPROTO_UDP,
|
||||
.me = THIS_MODULE,
|
||||
.help = snmp_conntrack_help,
|
||||
.expect_policy = &exp_policy,
|
||||
};
|
||||
static struct nf_conntrack_helper helper __read_mostly;
|
||||
static struct nf_conntrack_helper *helper_ptr __read_mostly;
|
||||
|
||||
static int __init nf_conntrack_snmp_init(void)
|
||||
{
|
||||
exp_policy.timeout = timeout;
|
||||
return nf_conntrack_helper_register(&helper);
|
||||
|
||||
nf_ct_helper_init(&helper, AF_INET, IPPROTO_UDP,
|
||||
"snmp", SNMP_PORT, SNMP_PORT, SNMP_PORT,
|
||||
&exp_policy, 0, snmp_conntrack_help, NULL,
|
||||
THIS_MODULE);
|
||||
|
||||
return nf_conntrack_helper_register(&helper, &helper_ptr);
|
||||
}
|
||||
|
||||
static void __exit nf_conntrack_snmp_fini(void)
|
||||
{
|
||||
nf_conntrack_helper_unregister(&helper);
|
||||
nf_conntrack_helper_unregister(helper_ptr);
|
||||
}
|
||||
|
||||
module_init(nf_conntrack_snmp_init);
|
||||
|
||||
@@ -96,6 +96,7 @@ static int tftp_help(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
static struct nf_conntrack_helper tftp[MAX_PORTS * 2] __read_mostly;
|
||||
static struct nf_conntrack_helper *tftp_ptr[MAX_PORTS * 2] __read_mostly;
|
||||
|
||||
static const struct nf_conntrack_expect_policy tftp_exp_policy = {
|
||||
.max_expected = 1,
|
||||
@@ -104,7 +105,7 @@ static const struct nf_conntrack_expect_policy tftp_exp_policy = {
|
||||
|
||||
static void __exit nf_conntrack_tftp_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(tftp, ports_c * 2);
|
||||
nf_conntrack_helpers_unregister(tftp_ptr, ports_c * 2);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_tftp_init(void)
|
||||
@@ -127,7 +128,7 @@ static int __init nf_conntrack_tftp_init(void)
|
||||
THIS_MODULE);
|
||||
}
|
||||
|
||||
ret = nf_conntrack_helpers_register(tftp, ports_c * 2);
|
||||
ret = nf_conntrack_helpers_register(tftp, ports_c * 2, tftp_ptr);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to register helpers\n");
|
||||
return ret;
|
||||
|
||||
@@ -32,7 +32,7 @@ MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
|
||||
|
||||
struct nfnl_cthelper {
|
||||
struct list_head list;
|
||||
struct nf_conntrack_helper helper;
|
||||
struct nf_conntrack_helper *helper;
|
||||
};
|
||||
|
||||
static LIST_HEAD(nfnl_cthelper_list);
|
||||
@@ -176,7 +176,6 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
|
||||
const struct nlattr *attr)
|
||||
{
|
||||
int i, ret;
|
||||
struct nf_conntrack_expect_policy *expect_policy;
|
||||
struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
|
||||
unsigned int class_max;
|
||||
|
||||
@@ -195,26 +194,19 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
|
||||
if (class_max > NF_CT_MAX_EXPECT_CLASSES)
|
||||
return -EOVERFLOW;
|
||||
|
||||
expect_policy = kzalloc_objs(struct nf_conntrack_expect_policy,
|
||||
class_max);
|
||||
if (expect_policy == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < class_max; i++) {
|
||||
if (!tb[NFCTH_POLICY_SET+i])
|
||||
goto err;
|
||||
|
||||
ret = nfnl_cthelper_expect_policy(&expect_policy[i],
|
||||
ret = nfnl_cthelper_expect_policy(&helper->expect_policy[i],
|
||||
tb[NFCTH_POLICY_SET+i]);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
helper->expect_class_max = class_max - 1;
|
||||
helper->expect_policy = expect_policy;
|
||||
return 0;
|
||||
err:
|
||||
kfree(expect_policy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -230,21 +222,28 @@ nfnl_cthelper_create(const struct nlattr * const tb[],
|
||||
if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
|
||||
return -EINVAL;
|
||||
|
||||
nfcth = kzalloc_obj(*nfcth);
|
||||
nfcth = kzalloc_obj(*nfcth, GFP_KERNEL_ACCOUNT);
|
||||
if (nfcth == NULL)
|
||||
return -ENOMEM;
|
||||
helper = &nfcth->helper;
|
||||
|
||||
helper = kzalloc_obj(*helper, GFP_KERNEL_ACCOUNT);
|
||||
if (!helper) {
|
||||
ret = -ENOMEM;
|
||||
goto err_cth;
|
||||
}
|
||||
|
||||
nfcth->helper = helper;
|
||||
|
||||
ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
goto err_helper;
|
||||
|
||||
nla_strscpy(helper->name,
|
||||
tb[NFCTH_NAME], NF_CT_HELPER_NAME_LEN);
|
||||
size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
|
||||
if (size > sizeof_field(struct nf_conn_help, data)) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
goto err_helper;
|
||||
}
|
||||
helper->data_len = size;
|
||||
|
||||
@@ -273,15 +272,15 @@ nfnl_cthelper_create(const struct nlattr * const tb[],
|
||||
}
|
||||
}
|
||||
|
||||
ret = nf_conntrack_helper_register(helper);
|
||||
ret = __nf_conntrack_helper_register(helper);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
goto err_helper;
|
||||
|
||||
list_add_tail(&nfcth->list, &nfnl_cthelper_list);
|
||||
return 0;
|
||||
err2:
|
||||
kfree(helper->expect_policy);
|
||||
err1:
|
||||
err_helper:
|
||||
kfree(helper);
|
||||
err_cth:
|
||||
kfree(nfcth);
|
||||
return ret;
|
||||
}
|
||||
@@ -439,7 +438,7 @@ static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
|
||||
cur = &nlcth->helper;
|
||||
cur = nlcth->helper;
|
||||
|
||||
if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
|
||||
continue;
|
||||
@@ -650,7 +649,7 @@ static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
}
|
||||
|
||||
list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
|
||||
cur = &nlcth->helper;
|
||||
cur = nlcth->helper;
|
||||
if (helper_name &&
|
||||
strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
|
||||
continue;
|
||||
@@ -708,7 +707,7 @@ static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
|
||||
ret = -ENOENT;
|
||||
list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
|
||||
cur = &nlcth->helper;
|
||||
cur = nlcth->helper;
|
||||
j++;
|
||||
|
||||
if (helper_name &&
|
||||
@@ -723,7 +722,6 @@ static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
if (refcount_dec_if_one(&cur->refcnt)) {
|
||||
found = true;
|
||||
nf_conntrack_helper_unregister(cur);
|
||||
kfree(cur->expect_policy);
|
||||
|
||||
list_del(&nlcth->list);
|
||||
kfree(nlcth);
|
||||
@@ -796,10 +794,9 @@ static void __exit nfnl_cthelper_exit(void)
|
||||
nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
|
||||
|
||||
list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
|
||||
cur = &nlcth->helper;
|
||||
cur = nlcth->helper;
|
||||
|
||||
nf_conntrack_helper_unregister(cur);
|
||||
kfree(cur->expect_policy);
|
||||
kfree(nlcth);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user