From patchwork Tue Mar 26 20:57:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flavio Leitner X-Patchwork-Id: 1066076 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=sysclose.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=sysclose.org header.i=fbl@sysclose.org header.b="doUPSJr8"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44TNkP4cchz9sV0 for ; Wed, 27 Mar 2019 07:57:49 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732803AbfCZU5s (ORCPT ); Tue, 26 Mar 2019 16:57:48 -0400 Received: from sender-of-o51.zoho.com ([135.84.80.216]:21044 "EHLO sender-of-o51.zoho.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732716AbfCZU5s (ORCPT ); Tue, 26 Mar 2019 16:57:48 -0400 ARC-Seal: i=1; a=rsa-sha256; t=1553633857; cv=none; d=zoho.com; s=zohoarc; b=E9Qz1e5pApwzLbjD/7B0cxDWxPHUXxXqmQqn82aaOgHSSPfYa/BwAUR0MLsWstUMthiaD//3s5BZC6u5EuIJJtgAZZwTpnv0luLmqw27oPHu5DPXA9r1tnIBKcEyCgK66qnrHOk6kdTI/qDfNnPzfQG42PGUmpSMnAljK8wQLN0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1553633857; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To:ARC-Authentication-Results; bh=sVTUDP1D/Xg9En8NKjz9zg6WRIOmBBfHMtuk9ue6A3I=; b=QbpnTq2ok+rtWZFm3wDES/pUsjaEX9EU3gtGY7CyJrWFFLZQ3DPamryXqWxhZj0vMlt1Tiqj7b0zXB8b6LzAgHsb/oAx3uOFVyJO3RCbTo97fITyBYTPD5GAaaB5/FAibhXU9xsOnyVJb94LbgP1zxQf+WXSdgAUZEVDWCRxpxo= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass header.i=sysclose.org; spf=pass smtp.mailfrom=fbl@sysclose.org; dmarc=pass header.from= header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1553633857; s=zoho; d=sysclose.org; i=fbl@sysclose.org; h=From:To:Cc:Message-ID:Subject:Date:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Content-Type; l=13391; bh=sVTUDP1D/Xg9En8NKjz9zg6WRIOmBBfHMtuk9ue6A3I=; b=doUPSJr8hKliL+0YQpEGIGg1XLdvlaHt1t0D3GBV1xy2TTd2Chss5WlOnewQhr41 DzNSoj0hJW37R946teBfK5WxzLnyvZJOkEUVAZ27O+WB98b8tRPi/S5l8J6rist/4qT 1ox/z0e4aayHUKz27RXbT+8u3aIuU3y2ARXHCxOY= Received: from localhost (177.183.215.126 [177.183.215.126]) by mx.zohomail.com with SMTPS id 1553633856195782.1851203181355; Tue, 26 Mar 2019 13:57:36 -0700 (PDT) From: Flavio Leitner To: netdev@vger.kernel.org Cc: Joe Stringer , Pravin B Shelar , dev@openvswitch.org, netfilter-devel@vger.kernel.org Message-ID: <20190326205715.22288-3-fbl@sysclose.org> Subject: [PATCH net-next 2/8] netfilter: add API to manage NAT helpers. Date: Tue, 26 Mar 2019 17:57:09 -0300 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190326205715.22288-1-fbl@sysclose.org> References: <20190326205715.22288-1-fbl@sysclose.org> MIME-Version: 1.0 X-ZohoMailClient: External Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- 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);