Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Flavio Leitner <fbl@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Flavio Leitner and committed by
Pablo Neira Ayuso
08010a21 e1f172e1

+161 -37
+21 -1
include/net/netfilter/nf_conntrack_helper.h
··· 15 15 #include <net/netfilter/nf_conntrack_extend.h> 16 16 #include <net/netfilter/nf_conntrack_expect.h> 17 17 18 - #define NF_NAT_HELPER_NAME(name) "ip_nat_" name 18 + #define NF_NAT_HELPER_PREFIX "ip_nat_" 19 + #define NF_NAT_HELPER_NAME(name) NF_NAT_HELPER_PREFIX name 19 20 #define MODULE_ALIAS_NF_NAT_HELPER(name) \ 20 21 MODULE_ALIAS(NF_NAT_HELPER_NAME(name)) 21 22 ··· 59 58 unsigned int queue_num; 60 59 /* length of userspace private data stored in nf_conn_help->data */ 61 60 u16 data_len; 61 + /* name of NAT helper module */ 62 + char nat_mod_name[NF_CT_HELPER_NAME_LEN]; 62 63 }; 63 64 64 65 /* Must be kept in sync with the classes defined by helpers */ ··· 160 157 extern struct hlist_head *nf_ct_helper_hash; 161 158 extern unsigned int nf_ct_helper_hsize; 162 159 160 + struct nf_conntrack_nat_helper { 161 + struct list_head list; 162 + char mod_name[NF_CT_HELPER_NAME_LEN]; /* module name */ 163 + struct module *module; /* pointer to self */ 164 + }; 165 + 166 + #define NF_CT_NAT_HELPER_INIT(name) \ 167 + { \ 168 + .mod_name = NF_NAT_HELPER_NAME(name), \ 169 + .module = THIS_MODULE \ 170 + } 171 + 172 + void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat); 173 + void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat); 174 + int nf_nat_helper_try_module_get(const char *name, u16 l3num, 175 + u8 protonum); 176 + void nf_nat_helper_put(struct nf_conntrack_helper *helper); 163 177 #endif /*_NF_CONNTRACK_HELPER_H*/
+6 -2
net/netfilter/nf_conntrack_amanda.c
··· 28 28 static unsigned int master_timeout __read_mostly = 300; 29 29 static char *ts_algo = "kmp"; 30 30 31 + #define HELPER_NAME "amanda" 32 + 31 33 MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); 32 34 MODULE_DESCRIPTION("Amanda connection tracking module"); 33 35 MODULE_LICENSE("GPL"); 34 36 MODULE_ALIAS("ip_conntrack_amanda"); 35 - MODULE_ALIAS_NFCT_HELPER("amanda"); 37 + MODULE_ALIAS_NFCT_HELPER(HELPER_NAME); 36 38 37 39 module_param(master_timeout, uint, 0600); 38 40 MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); ··· 181 179 182 180 static struct nf_conntrack_helper amanda_helper[2] __read_mostly = { 183 181 { 184 - .name = "amanda", 182 + .name = HELPER_NAME, 185 183 .me = THIS_MODULE, 186 184 .help = amanda_help, 187 185 .tuple.src.l3num = AF_INET, 188 186 .tuple.src.u.udp.port = cpu_to_be16(10080), 189 187 .tuple.dst.protonum = IPPROTO_UDP, 190 188 .expect_policy = &amanda_exp_policy, 189 + .nat_mod_name = NF_NAT_HELPER_NAME(HELPER_NAME), 191 190 }, 192 191 { 193 192 .name = "amanda", ··· 198 195 .tuple.src.u.udp.port = cpu_to_be16(10080), 199 196 .tuple.dst.protonum = IPPROTO_UDP, 200 197 .expect_policy = &amanda_exp_policy, 198 + .nat_mod_name = NF_NAT_HELPER_NAME(HELPER_NAME), 201 199 }, 202 200 }; 203 201
+11 -7
net/netfilter/nf_conntrack_ftp.c
··· 29 29 #include <net/netfilter/nf_conntrack_helper.h> 30 30 #include <linux/netfilter/nf_conntrack_ftp.h> 31 31 32 + #define HELPER_NAME "ftp" 33 + 32 34 MODULE_LICENSE("GPL"); 33 35 MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); 34 36 MODULE_DESCRIPTION("ftp connection tracking helper"); 35 37 MODULE_ALIAS("ip_conntrack_ftp"); 36 - MODULE_ALIAS_NFCT_HELPER("ftp"); 38 + MODULE_ALIAS_NFCT_HELPER(HELPER_NAME); 37 39 38 40 /* This is slow, but it's simple. --RR */ 39 41 static char *ftp_buffer; ··· 590 588 /* FIXME should be configurable whether IPv4 and IPv6 FTP connections 591 589 are tracked or not - YK */ 592 590 for (i = 0; i < ports_c; i++) { 593 - nf_ct_helper_init(&ftp[2 * i], AF_INET, IPPROTO_TCP, "ftp", 594 - FTP_PORT, ports[i], ports[i], &ftp_exp_policy, 595 - 0, help, nf_ct_ftp_from_nlattr, THIS_MODULE); 596 - nf_ct_helper_init(&ftp[2 * i + 1], AF_INET6, IPPROTO_TCP, "ftp", 597 - FTP_PORT, ports[i], ports[i], &ftp_exp_policy, 598 - 0, help, nf_ct_ftp_from_nlattr, THIS_MODULE); 591 + nf_ct_helper_init(&ftp[2 * i], AF_INET, IPPROTO_TCP, 592 + HELPER_NAME, FTP_PORT, ports[i], ports[i], 593 + &ftp_exp_policy, 0, help, 594 + nf_ct_ftp_from_nlattr, THIS_MODULE); 595 + nf_ct_helper_init(&ftp[2 * i + 1], AF_INET6, IPPROTO_TCP, 596 + HELPER_NAME, FTP_PORT, ports[i], ports[i], 597 + &ftp_exp_policy, 0, help, 598 + nf_ct_ftp_from_nlattr, THIS_MODULE); 599 599 } 600 600 601 601 ret = nf_conntrack_helpers_register(ftp, ports_c * 2);
+86
net/netfilter/nf_conntrack_helper.c
··· 42 42 MODULE_PARM_DESC(nf_conntrack_helper, 43 43 "Enable automatic conntrack helper assignment (default 0)"); 44 44 45 + static DEFINE_MUTEX(nf_ct_nat_helpers_mutex); 46 + static struct list_head nf_ct_nat_helpers __read_mostly; 47 + 45 48 /* Stupid hash, but collision free for the default registrations of the 46 49 * helpers currently in the kernel. */ 47 50 static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple) ··· 132 129 module_put(helper->me); 133 130 } 134 131 EXPORT_SYMBOL_GPL(nf_conntrack_helper_put); 132 + 133 + static struct nf_conntrack_nat_helper * 134 + nf_conntrack_nat_helper_find(const char *mod_name) 135 + { 136 + struct nf_conntrack_nat_helper *cur; 137 + bool found = false; 138 + 139 + list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) { 140 + if (!strcmp(cur->mod_name, mod_name)) { 141 + found = true; 142 + break; 143 + } 144 + } 145 + return found ? cur : NULL; 146 + } 147 + 148 + int 149 + nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum) 150 + { 151 + struct nf_conntrack_helper *h; 152 + struct nf_conntrack_nat_helper *nat; 153 + char mod_name[NF_CT_HELPER_NAME_LEN]; 154 + int ret = 0; 155 + 156 + rcu_read_lock(); 157 + h = __nf_conntrack_helper_find(name, l3num, protonum); 158 + if (!h) { 159 + rcu_read_unlock(); 160 + return -ENOENT; 161 + } 162 + 163 + nat = nf_conntrack_nat_helper_find(h->nat_mod_name); 164 + if (!nat) { 165 + snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name); 166 + rcu_read_unlock(); 167 + request_module(mod_name); 168 + 169 + rcu_read_lock(); 170 + nat = nf_conntrack_nat_helper_find(mod_name); 171 + if (!nat) { 172 + rcu_read_unlock(); 173 + return -ENOENT; 174 + } 175 + } 176 + 177 + if (!try_module_get(nat->module)) 178 + ret = -ENOENT; 179 + 180 + rcu_read_unlock(); 181 + return ret; 182 + } 183 + EXPORT_SYMBOL_GPL(nf_nat_helper_try_module_get); 184 + 185 + void nf_nat_helper_put(struct nf_conntrack_helper *helper) 186 + { 187 + struct nf_conntrack_nat_helper *nat; 188 + 189 + nat = nf_conntrack_nat_helper_find(helper->nat_mod_name); 190 + if (WARN_ON_ONCE(!nat)) 191 + return; 192 + 193 + module_put(nat->module); 194 + } 195 + EXPORT_SYMBOL_GPL(nf_nat_helper_put); 135 196 136 197 struct nf_conn_help * 137 198 nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) ··· 497 430 helper->help = help; 498 431 helper->from_nlattr = from_nlattr; 499 432 helper->me = module; 433 + snprintf(helper->nat_mod_name, sizeof(helper->nat_mod_name), 434 + NF_NAT_HELPER_PREFIX "%s", name); 500 435 501 436 if (spec_port == default_port) 502 437 snprintf(helper->name, sizeof(helper->name), "%s", name); ··· 535 466 } 536 467 EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister); 537 468 469 + void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat) 470 + { 471 + mutex_lock(&nf_ct_nat_helpers_mutex); 472 + list_add_rcu(&nat->list, &nf_ct_nat_helpers); 473 + mutex_unlock(&nf_ct_nat_helpers_mutex); 474 + } 475 + EXPORT_SYMBOL_GPL(nf_nat_helper_register); 476 + 477 + void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat) 478 + { 479 + mutex_lock(&nf_ct_nat_helpers_mutex); 480 + list_del_rcu(&nat->list); 481 + mutex_unlock(&nf_ct_nat_helpers_mutex); 482 + } 483 + EXPORT_SYMBOL_GPL(nf_nat_helper_unregister); 484 + 538 485 static const struct nf_ct_ext_type helper_extend = { 539 486 .len = sizeof(struct nf_conn_help), 540 487 .align = __alignof__(struct nf_conn_help), ··· 578 493 goto out_extend; 579 494 } 580 495 496 + INIT_LIST_HEAD(&nf_ct_nat_helpers); 581 497 return 0; 582 498 out_extend: 583 499 kvfree(nf_ct_helper_hash);
+4 -2
net/netfilter/nf_conntrack_irc.c
··· 42 42 struct nf_conntrack_expect *exp) __read_mostly; 43 43 EXPORT_SYMBOL_GPL(nf_nat_irc_hook); 44 44 45 + #define HELPER_NAME "irc" 46 + 45 47 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 46 48 MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); 47 49 MODULE_LICENSE("GPL"); 48 50 MODULE_ALIAS("ip_conntrack_irc"); 49 - MODULE_ALIAS_NFCT_HELPER("irc"); 51 + MODULE_ALIAS_NFCT_HELPER(HELPER_NAME); 50 52 51 53 module_param_array(ports, ushort, &ports_c, 0400); 52 54 MODULE_PARM_DESC(ports, "port numbers of IRC servers"); ··· 261 259 ports[ports_c++] = IRC_PORT; 262 260 263 261 for (i = 0; i < ports_c; i++) { 264 - nf_ct_helper_init(&irc[i], AF_INET, IPPROTO_TCP, "irc", 262 + nf_ct_helper_init(&irc[i], AF_INET, IPPROTO_TCP, HELPER_NAME, 265 263 IRC_PORT, ports[i], i, &irc_exp_policy, 266 264 0, help, NULL, THIS_MODULE); 267 265 }
+7 -5
net/netfilter/nf_conntrack_sane.c
··· 30 30 #include <net/netfilter/nf_conntrack_expect.h> 31 31 #include <linux/netfilter/nf_conntrack_sane.h> 32 32 33 + #define HELPER_NAME "sane" 34 + 33 35 MODULE_LICENSE("GPL"); 34 36 MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>"); 35 37 MODULE_DESCRIPTION("SANE connection tracking helper"); 36 - MODULE_ALIAS_NFCT_HELPER("sane"); 38 + MODULE_ALIAS_NFCT_HELPER(HELPER_NAME); 37 39 38 40 static char *sane_buffer; 39 41 ··· 197 195 /* FIXME should be configurable whether IPv4 and IPv6 connections 198 196 are tracked or not - YK */ 199 197 for (i = 0; i < ports_c; i++) { 200 - nf_ct_helper_init(&sane[2 * i], AF_INET, IPPROTO_TCP, "sane", 201 - SANE_PORT, ports[i], ports[i], 198 + nf_ct_helper_init(&sane[2 * i], AF_INET, IPPROTO_TCP, 199 + HELPER_NAME, SANE_PORT, ports[i], ports[i], 202 200 &sane_exp_policy, 0, help, NULL, 203 201 THIS_MODULE); 204 - nf_ct_helper_init(&sane[2 * i + 1], AF_INET6, IPPROTO_TCP, "sane", 205 - SANE_PORT, ports[i], ports[i], 202 + nf_ct_helper_init(&sane[2 * i + 1], AF_INET6, IPPROTO_TCP, 203 + HELPER_NAME, SANE_PORT, ports[i], ports[i], 206 204 &sane_exp_policy, 0, help, NULL, 207 205 THIS_MODULE); 208 206 }
+15 -13
net/netfilter/nf_conntrack_sip.c
··· 30 30 #include <net/netfilter/nf_conntrack_zones.h> 31 31 #include <linux/netfilter/nf_conntrack_sip.h> 32 32 33 + #define HELPER_NAME "sip" 34 + 33 35 MODULE_LICENSE("GPL"); 34 36 MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); 35 37 MODULE_DESCRIPTION("SIP connection tracking helper"); 36 38 MODULE_ALIAS("ip_conntrack_sip"); 37 - MODULE_ALIAS_NFCT_HELPER("sip"); 39 + MODULE_ALIAS_NFCT_HELPER(HELPER_NAME); 38 40 39 41 #define MAX_PORTS 8 40 42 static unsigned short ports[MAX_PORTS]; ··· 1671 1669 ports[ports_c++] = SIP_PORT; 1672 1670 1673 1671 for (i = 0; i < ports_c; i++) { 1674 - nf_ct_helper_init(&sip[4 * i], AF_INET, IPPROTO_UDP, "sip", 1675 - SIP_PORT, ports[i], i, sip_exp_policy, 1676 - SIP_EXPECT_MAX, sip_help_udp, 1672 + nf_ct_helper_init(&sip[4 * i], AF_INET, IPPROTO_UDP, 1673 + HELPER_NAME, SIP_PORT, ports[i], i, 1674 + sip_exp_policy, SIP_EXPECT_MAX, sip_help_udp, 1677 1675 NULL, THIS_MODULE); 1678 - nf_ct_helper_init(&sip[4 * i + 1], AF_INET, IPPROTO_TCP, "sip", 1679 - SIP_PORT, ports[i], i, sip_exp_policy, 1680 - SIP_EXPECT_MAX, sip_help_tcp, 1676 + nf_ct_helper_init(&sip[4 * i + 1], AF_INET, IPPROTO_TCP, 1677 + HELPER_NAME, SIP_PORT, ports[i], i, 1678 + sip_exp_policy, SIP_EXPECT_MAX, sip_help_tcp, 1681 1679 NULL, THIS_MODULE); 1682 - nf_ct_helper_init(&sip[4 * i + 2], AF_INET6, IPPROTO_UDP, "sip", 1683 - SIP_PORT, ports[i], i, sip_exp_policy, 1684 - SIP_EXPECT_MAX, sip_help_udp, 1680 + nf_ct_helper_init(&sip[4 * i + 2], AF_INET6, IPPROTO_UDP, 1681 + HELPER_NAME, SIP_PORT, ports[i], i, 1682 + sip_exp_policy, SIP_EXPECT_MAX, sip_help_udp, 1685 1683 NULL, THIS_MODULE); 1686 - nf_ct_helper_init(&sip[4 * i + 3], AF_INET6, IPPROTO_TCP, "sip", 1687 - SIP_PORT, ports[i], i, sip_exp_policy, 1688 - SIP_EXPECT_MAX, sip_help_tcp, 1684 + nf_ct_helper_init(&sip[4 * i + 3], AF_INET6, IPPROTO_TCP, 1685 + HELPER_NAME, SIP_PORT, ports[i], i, 1686 + sip_exp_policy, SIP_EXPECT_MAX, sip_help_tcp, 1689 1687 NULL, THIS_MODULE); 1690 1688 } 1691 1689
+11 -7
net/netfilter/nf_conntrack_tftp.c
··· 20 20 #include <net/netfilter/nf_conntrack_helper.h> 21 21 #include <linux/netfilter/nf_conntrack_tftp.h> 22 22 23 + #define HELPER_NAME "tftp" 24 + 23 25 MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); 24 26 MODULE_DESCRIPTION("TFTP connection tracking helper"); 25 27 MODULE_LICENSE("GPL"); 26 28 MODULE_ALIAS("ip_conntrack_tftp"); 27 - MODULE_ALIAS_NFCT_HELPER("tftp"); 29 + MODULE_ALIAS_NFCT_HELPER(HELPER_NAME); 28 30 29 31 #define MAX_PORTS 8 30 32 static unsigned short ports[MAX_PORTS]; ··· 121 119 ports[ports_c++] = TFTP_PORT; 122 120 123 121 for (i = 0; i < ports_c; i++) { 124 - nf_ct_helper_init(&tftp[2 * i], AF_INET, IPPROTO_UDP, "tftp", 125 - TFTP_PORT, ports[i], i, &tftp_exp_policy, 126 - 0, tftp_help, NULL, THIS_MODULE); 127 - nf_ct_helper_init(&tftp[2 * i + 1], AF_INET6, IPPROTO_UDP, "tftp", 128 - TFTP_PORT, ports[i], i, &tftp_exp_policy, 129 - 0, tftp_help, NULL, THIS_MODULE); 122 + nf_ct_helper_init(&tftp[2 * i], AF_INET, IPPROTO_UDP, 123 + HELPER_NAME, TFTP_PORT, ports[i], i, 124 + &tftp_exp_policy, 0, tftp_help, NULL, 125 + THIS_MODULE); 126 + nf_ct_helper_init(&tftp[2 * i + 1], AF_INET6, IPPROTO_UDP, 127 + HELPER_NAME, TFTP_PORT, ports[i], i, 128 + &tftp_exp_policy, 0, tftp_help, NULL, 129 + THIS_MODULE); 130 130 } 131 131 132 132 ret = nf_conntrack_helpers_register(tftp, ports_c * 2);