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

Signed-off-by: Flavio Leitner <f...@sysclose.org>
---
 include/net/netfilter/nf_conntrack_helper.h |  19 +++-
 net/netfilter/nf_conntrack_amanda.c         |   2 +
 net/netfilter/nf_conntrack_ftp.c            |   6 +-
 net/netfilter/nf_conntrack_helper.c         | 108 +++++++++++++++++++-
 net/netfilter/nf_conntrack_irc.c            |   3 +-
 net/netfilter/nf_conntrack_sane.c           |   4 +-
 net/netfilter/nf_conntrack_sip.c            |  12 ++-
 net/netfilter/nf_conntrack_tftp.c           |   6 +-
 8 files changed, 147 insertions(+), 13 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_helper.h 
b/include/net/netfilter/nf_conntrack_helper.h
index e86fadf7e7c5..0d36d6bfb522 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -58,6 +58,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 */
@@ -98,7 +100,8 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
                                   enum ip_conntrack_info ctinfo),
                       int (*from_nlattr)(struct nlattr *attr,
                                          struct nf_conn *ct),
-                      struct module *module);
+                      struct module *module,
+                      const char *nat_mod_name);
 
 int nf_conntrack_helper_register(struct nf_conntrack_helper *);
 void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
@@ -157,4 +160,18 @@ 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_helper_nat {
+       struct list_head list;
+       char name[NF_CT_HELPER_NAME_LEN];
+       struct module *module;          /* pointer to self */
+};
+
+void nf_ct_helper_nat_init(struct nf_conntrack_helper_nat *nat,
+                          const char *name, struct module *module);
+
+void nf_conntrack_helper_nat_register(struct nf_conntrack_helper_nat *nat);
+void nf_conntrack_helper_nat_unregister(struct nf_conntrack_helper_nat *nat);
+int nf_conntrack_helper_nat_try_module_get(const char *name, u16 l3num,
+                                          u8 protonum);
+void nf_conntrack_helper_nat_put(struct nf_conntrack_helper *helper);
 #endif /*_NF_CONNTRACK_HELPER_H*/
diff --git a/net/netfilter/nf_conntrack_amanda.c 
b/net/netfilter/nf_conntrack_amanda.c
index f2681ec5b5f6..b5d255897d9e 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -186,6 +186,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_CT_NAT_HELPER_MOD_NAME("amanda"),
        },
        {
                .name                   = "amanda",
@@ -195,6 +196,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_CT_NAT_HELPER_MOD_NAME("amanda"),
        },
 };
 
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index a11c304fb771..fec9bb462071 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -590,10 +590,12 @@ static int __init nf_conntrack_ftp_init(void)
        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);
+                                 0, help, nf_ct_ftp_from_nlattr, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("ftp"));
                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);
+                                 0, help, nf_ct_ftp_from_nlattr, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("ftp"));
        }
 
        ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
diff --git a/net/netfilter/nf_conntrack_helper.c 
b/net/netfilter/nf_conntrack_helper.c
index 274baf1dab87..883a8d438503 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -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 struct list_head nf_ct_nat_helpers __read_mostly;
+static DEFINE_SPINLOCK(nf_ct_nat_helpers_lock);
+
 /* 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,75 @@ void nf_conntrack_helper_put(struct nf_conntrack_helper 
*helper)
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);
 
+static struct nf_conntrack_helper_nat *
+nf_conntrack_helper_nat_find(const char *name)
+{
+       struct nf_conntrack_helper_nat *cur;
+       bool found = false;
+
+       list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) {
+               if (!strcmp(cur->name, name)) {
+                       found = true;
+                       break;
+               }
+       }
+       return found ? cur : NULL;
+}
+
+int
+nf_conntrack_helper_nat_try_module_get(const char *name, u16 l3num, u8 
protonum)
+{
+       struct nf_conntrack_helper *h;
+       struct nf_conntrack_helper_nat *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 == NULL) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+
+       if (!strlen(h->nat_mod_name)) {
+               rcu_read_unlock();
+               return -EOPNOTSUPP;
+       }
+
+       nat = nf_conntrack_helper_nat_find(h->nat_mod_name);
+       if (nat == NULL) {
+               snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name);
+               rcu_read_unlock();
+               ret = request_module(mod_name);
+               if (ret != 0)
+                       return ret;
+
+               rcu_read_lock();
+               nat = nf_conntrack_helper_nat_find(mod_name);
+               if (nat == NULL) {
+                       rcu_read_unlock();
+                       return -EINVAL;
+               }
+       }
+
+       if (!try_module_get(nat->module))
+               ret = -EINVAL;
+
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_helper_nat_try_module_get);
+
+void nf_conntrack_helper_nat_put(struct nf_conntrack_helper *helper)
+{
+       struct nf_conntrack_helper_nat *nat;
+
+       nat = nf_conntrack_helper_nat_find(helper->nat_mod_name);
+       BUG_ON(nat == NULL);
+       module_put(nat->module);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_helper_nat_put);
+
 struct nf_conn_help *
 nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
 {
@@ -420,7 +492,8 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
                                   enum ip_conntrack_info ctinfo),
                       int (*from_nlattr)(struct nlattr *attr,
                                          struct nf_conn *ct),
-                      struct module *module)
+                      struct module *module,
+                      const char *nat_mod_name)
 {
        helper->tuple.src.l3num = l3num;
        helper->tuple.dst.protonum = protonum;
@@ -430,6 +503,10 @@ void nf_ct_helper_init(struct nf_conntrack_helper *helper,
        helper->help = help;
        helper->from_nlattr = from_nlattr;
        helper->me = module;
+       helper->nat_mod_name[0] = '\0';
+       if (nat_mod_name)
+               snprintf(helper->nat_mod_name, sizeof(helper->nat_mod_name),
+                        "%s", nat_mod_name);
 
        if (spec_port == default_port)
                snprintf(helper->name, sizeof(helper->name), "%s", name);
@@ -466,6 +543,34 @@ void nf_conntrack_helpers_unregister(struct 
nf_conntrack_helper *helper,
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
 
+void nf_conntrack_helper_nat_register(struct nf_conntrack_helper_nat *nat)
+{
+       BUG_ON(nat->module == NULL);
+
+       spin_lock(&nf_ct_nat_helpers_lock);
+       list_add_rcu(&nat->list, &nf_ct_nat_helpers);
+       spin_unlock(&nf_ct_nat_helpers_lock);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_helper_nat_register);
+
+void nf_conntrack_helper_nat_unregister(struct nf_conntrack_helper_nat *nat)
+{
+       BUG_ON(nat->module == NULL);
+
+       spin_lock(&nf_ct_nat_helpers_lock);
+       list_del_rcu(&nat->list);
+       spin_unlock(&nf_ct_nat_helpers_lock);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_helper_nat_unregister);
+
+void nf_ct_helper_nat_init(struct nf_conntrack_helper_nat *nat,
+                          const char *name, struct module *module)
+{
+       nat->module = module;
+       snprintf(nat->name, sizeof(nat->name), "%s", name);
+}
+EXPORT_SYMBOL_GPL(nf_ct_helper_nat_init);
+
 static const struct nf_ct_ext_type helper_extend = {
        .len    = sizeof(struct nf_conn_help),
        .align  = __alignof__(struct nf_conn_help),
@@ -493,6 +598,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);
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 4099f4d79bae..659aa2cb5493 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -261,7 +261,8 @@ static int __init nf_conntrack_irc_init(void)
        for (i = 0; i < ports_c; i++) {
                nf_ct_helper_init(&irc[i], AF_INET, IPPROTO_TCP, "irc",
                                  IRC_PORT, ports[i], i, &irc_exp_policy,
-                                 0, help, NULL, THIS_MODULE);
+                                 0, help, NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("irc"));
        }
 
        ret = nf_conntrack_helpers_register(&irc[0], ports_c);
diff --git a/net/netfilter/nf_conntrack_sane.c 
b/net/netfilter/nf_conntrack_sane.c
index 5072ff96ab33..b08724b8754c 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -198,11 +198,11 @@ static int __init nf_conntrack_sane_init(void)
                nf_ct_helper_init(&sane[2 * i], AF_INET, IPPROTO_TCP, "sane",
                                  SANE_PORT, ports[i], ports[i],
                                  &sane_exp_policy, 0, help, NULL,
-                                 THIS_MODULE);
+                                 THIS_MODULE, NULL);
                nf_ct_helper_init(&sane[2 * i + 1], AF_INET6, IPPROTO_TCP, 
"sane",
                                  SANE_PORT, ports[i], ports[i],
                                  &sane_exp_policy, 0, help, NULL,
-                                 THIS_MODULE);
+                                 THIS_MODULE, NULL);
        }
 
        ret = nf_conntrack_helpers_register(sane, ports_c * 2);
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f067c6b50857..0d4fca4a329f 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1677,19 +1677,23 @@ static int __init nf_conntrack_sip_init(void)
                nf_ct_helper_init(&sip[4 * i], AF_INET, IPPROTO_UDP, "sip",
                                  SIP_PORT, ports[i], i, sip_exp_policy,
                                  SIP_EXPECT_MAX, sip_help_udp,
-                                 NULL, THIS_MODULE);
+                                 NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("sip"));
                nf_ct_helper_init(&sip[4 * i + 1], AF_INET, IPPROTO_TCP, "sip",
                                  SIP_PORT, ports[i], i, sip_exp_policy,
                                  SIP_EXPECT_MAX, sip_help_tcp,
-                                 NULL, THIS_MODULE);
+                                 NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("sip"));
                nf_ct_helper_init(&sip[4 * i + 2], AF_INET6, IPPROTO_UDP, "sip",
                                  SIP_PORT, ports[i], i, sip_exp_policy,
                                  SIP_EXPECT_MAX, sip_help_udp,
-                                 NULL, THIS_MODULE);
+                                 NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("sip"));
                nf_ct_helper_init(&sip[4 * i + 3], AF_INET6, IPPROTO_TCP, "sip",
                                  SIP_PORT, ports[i], i, sip_exp_policy,
                                  SIP_EXPECT_MAX, sip_help_tcp,
-                                 NULL, THIS_MODULE);
+                                 NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("sip"));
        }
 
        ret = nf_conntrack_helpers_register(sip, ports_c * 4);
diff --git a/net/netfilter/nf_conntrack_tftp.c 
b/net/netfilter/nf_conntrack_tftp.c
index 548b673b3625..e1fbf892db70 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -121,10 +121,12 @@ static int __init nf_conntrack_tftp_init(void)
        for (i = 0; i < ports_c; i++) {
                nf_ct_helper_init(&tftp[2 * i], AF_INET, IPPROTO_UDP, "tftp",
                                  TFTP_PORT, ports[i], i, &tftp_exp_policy,
-                                 0, tftp_help, NULL, THIS_MODULE);
+                                 0, tftp_help, NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("tftp"));
                nf_ct_helper_init(&tftp[2 * i + 1], AF_INET6, IPPROTO_UDP, 
"tftp",
                                  TFTP_PORT, ports[i], i, &tftp_exp_policy,
-                                 0, tftp_help, NULL, THIS_MODULE);
+                                 0, tftp_help, NULL, THIS_MODULE,
+                                 NF_CT_NAT_HELPER_MOD_NAME("tftp"));
        }
 
        ret = nf_conntrack_helpers_register(tftp, ports_c * 2);
-- 
2.20.1



_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to