aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2006-12-03 01:07:44 -0500
committerDavid S. Miller <davem@davemloft.net>2006-12-03 01:07:44 -0500
commit55a733247d6d2883d9bb77825fafac3dfca13fc2 (patch)
treee16357243c80ca11fe84639fc84f92e653eb3079 /net
parent5b1158e909ecbe1a052203e0d8df15633f829930 (diff)
[NETFILTER]: nf_nat: add FTP NAT helper port
Add FTP NAT helper. Split out from Jozsef's big nf_nat patch with a few small fixes by myself. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/Kconfig25
-rw-r--r--net/ipv4/netfilter/Makefile5
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c179
-rw-r--r--net/netfilter/nf_conntrack_ftp.c20
4 files changed, 210 insertions, 19 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 01789aeaeb5f..52f876db68f4 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -477,20 +477,29 @@ config IP_NF_NAT_SNMP_BASIC
477 477
478 To compile it as a module, choose M here. If unsure, say N. 478 To compile it as a module, choose M here. If unsure, say N.
479 479
480# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
481# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker.
482# From kconfig-language.txt:
483#
484# <expr> '&&' <expr> (6)
485#
486# (6) Returns the result of min(/expr/, /expr/).
487config IP_NF_NAT_FTP
488 tristate
489 depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT
490 default IP_NF_NAT && IP_NF_FTP
491
492config NF_NAT_FTP
493 tristate
494 depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
495 default NF_NAT && NF_CONNTRACK_FTP
496
480config IP_NF_NAT_IRC 497config IP_NF_NAT_IRC
481 tristate 498 tristate
482 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n 499 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
483 default IP_NF_NAT if IP_NF_IRC=y 500 default IP_NF_NAT if IP_NF_IRC=y
484 default m if IP_NF_IRC=m 501 default m if IP_NF_IRC=m
485 502
486# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
487# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh.
488config IP_NF_NAT_FTP
489 tristate
490 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
491 default IP_NF_NAT if IP_NF_FTP=y
492 default m if IP_NF_FTP=m
493
494config IP_NF_NAT_TFTP 503config IP_NF_NAT_TFTP
495 tristate 504 tristate
496 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n 505 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index ec31690764ac..c0c6194bb275 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -40,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
40obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o 40obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
41obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o 41obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
42 42
43# NAT helpers 43# NAT helpers (ip_conntrack)
44obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o 44obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
45obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o 45obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
46obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o 46obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
@@ -49,6 +49,9 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
49obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o 49obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
50obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o 50obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
51 51
52# NAT helpers (nf_conntrack)
53obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
54
52# generic IP tables 55# generic IP tables
53obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o 56obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
54 57
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
new file mode 100644
index 000000000000..751b59801755
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -0,0 +1,179 @@
1/* FTP extension for TCP NAT alteration. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/ip.h>
14#include <linux/tcp.h>
15#include <linux/netfilter_ipv4.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_conntrack_helper.h>
20#include <net/netfilter/nf_conntrack_expect.h>
21#include <linux/netfilter/nf_conntrack_ftp.h>
22
23MODULE_LICENSE("GPL");
24MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
25MODULE_DESCRIPTION("ftp NAT helper");
26MODULE_ALIAS("ip_nat_ftp");
27
28#if 0
29#define DEBUGP printk
30#else
31#define DEBUGP(format, args...)
32#endif
33
34/* FIXME: Time out? --RR */
35
36static int
37mangle_rfc959_packet(struct sk_buff **pskb,
38 __be32 newip,
39 u_int16_t port,
40 unsigned int matchoff,
41 unsigned int matchlen,
42 struct nf_conn *ct,
43 enum ip_conntrack_info ctinfo,
44 u32 *seq)
45{
46 char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
47
48 sprintf(buffer, "%u,%u,%u,%u,%u,%u",
49 NIPQUAD(newip), port>>8, port&0xFF);
50
51 DEBUGP("calling nf_nat_mangle_tcp_packet\n");
52
53 *seq += strlen(buffer) - matchlen;
54 return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
55 matchlen, buffer, strlen(buffer));
56}
57
58/* |1|132.235.1.2|6275| */
59static int
60mangle_eprt_packet(struct sk_buff **pskb,
61 __be32 newip,
62 u_int16_t port,
63 unsigned int matchoff,
64 unsigned int matchlen,
65 struct nf_conn *ct,
66 enum ip_conntrack_info ctinfo,
67 u32 *seq)
68{
69 char buffer[sizeof("|1|255.255.255.255|65535|")];
70
71 sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
72
73 DEBUGP("calling nf_nat_mangle_tcp_packet\n");
74
75 *seq += strlen(buffer) - matchlen;
76 return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
77 matchlen, buffer, strlen(buffer));
78}
79
80/* |1|132.235.1.2|6275| */
81static int
82mangle_epsv_packet(struct sk_buff **pskb,
83 __be32 newip,
84 u_int16_t port,
85 unsigned int matchoff,
86 unsigned int matchlen,
87 struct nf_conn *ct,
88 enum ip_conntrack_info ctinfo,
89 u32 *seq)
90{
91 char buffer[sizeof("|||65535|")];
92
93 sprintf(buffer, "|||%u|", port);
94
95 DEBUGP("calling nf_nat_mangle_tcp_packet\n");
96
97 *seq += strlen(buffer) - matchlen;
98 return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
99 matchlen, buffer, strlen(buffer));
100}
101
102static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
103 unsigned int, unsigned int, struct nf_conn *,
104 enum ip_conntrack_info, u32 *seq)
105= {
106 [NF_CT_FTP_PORT] = mangle_rfc959_packet,
107 [NF_CT_FTP_PASV] = mangle_rfc959_packet,
108 [NF_CT_FTP_EPRT] = mangle_eprt_packet,
109 [NF_CT_FTP_EPSV] = mangle_epsv_packet
110};
111
112/* So, this packet has hit the connection tracking matching code.
113 Mangle it, and change the expectation to match the new version. */
114static unsigned int nf_nat_ftp(struct sk_buff **pskb,
115 enum ip_conntrack_info ctinfo,
116 enum nf_ct_ftp_type type,
117 unsigned int matchoff,
118 unsigned int matchlen,
119 struct nf_conntrack_expect *exp,
120 u32 *seq)
121{
122 __be32 newip;
123 u_int16_t port;
124 int dir = CTINFO2DIR(ctinfo);
125 struct nf_conn *ct = exp->master;
126
127 DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
128
129 /* Connection will come from wherever this packet goes, hence !dir */
130 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
131 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
132 exp->dir = !dir;
133
134 /* When you see the packet, we need to NAT it the same as the
135 * this one. */
136 exp->expectfn = nf_nat_follow_master;
137
138 /* Try to get same port: if not, try to change it. */
139 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
140 exp->tuple.dst.u.tcp.port = htons(port);
141 if (nf_conntrack_expect_related(exp) == 0)
142 break;
143 }
144
145 if (port == 0)
146 return NF_DROP;
147
148 if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
149 seq)) {
150 nf_conntrack_unexpect_related(exp);
151 return NF_DROP;
152 }
153 return NF_ACCEPT;
154}
155
156static void __exit nf_nat_ftp_fini(void)
157{
158 rcu_assign_pointer(nf_nat_ftp_hook, NULL);
159 synchronize_rcu();
160}
161
162static int __init nf_nat_ftp_init(void)
163{
164 BUG_ON(rcu_dereference(nf_nat_ftp_hook));
165 rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp);
166 return 0;
167}
168
169/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
170static int warn_set(const char *val, struct kernel_param *kp)
171{
172 printk(KERN_INFO KBUILD_MODNAME
173 ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
174 return 0;
175}
176module_param_call(ports, warn_set, NULL, NULL, 0);
177
178module_init(nf_nat_ftp_init);
179module_exit(nf_nat_ftp_fini);
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index e299d657e4fc..92a947168761 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -51,7 +51,7 @@ module_param(loose, bool, 0600);
51 51
52unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, 52unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
53 enum ip_conntrack_info ctinfo, 53 enum ip_conntrack_info ctinfo,
54 enum ip_ct_ftp_type type, 54 enum nf_ct_ftp_type type,
55 unsigned int matchoff, 55 unsigned int matchoff,
56 unsigned int matchlen, 56 unsigned int matchlen,
57 struct nf_conntrack_expect *exp, 57 struct nf_conntrack_expect *exp,
@@ -74,7 +74,7 @@ static struct ftp_search {
74 size_t plen; 74 size_t plen;
75 char skip; 75 char skip;
76 char term; 76 char term;
77 enum ip_ct_ftp_type ftptype; 77 enum nf_ct_ftp_type ftptype;
78 int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char); 78 int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char);
79} search[IP_CT_DIR_MAX][2] = { 79} search[IP_CT_DIR_MAX][2] = {
80 [IP_CT_DIR_ORIGINAL] = { 80 [IP_CT_DIR_ORIGINAL] = {
@@ -83,7 +83,7 @@ static struct ftp_search {
83 .plen = sizeof("PORT") - 1, 83 .plen = sizeof("PORT") - 1,
84 .skip = ' ', 84 .skip = ' ',
85 .term = '\r', 85 .term = '\r',
86 .ftptype = IP_CT_FTP_PORT, 86 .ftptype = NF_CT_FTP_PORT,
87 .getnum = try_rfc959, 87 .getnum = try_rfc959,
88 }, 88 },
89 { 89 {
@@ -91,7 +91,7 @@ static struct ftp_search {
91 .plen = sizeof("EPRT") - 1, 91 .plen = sizeof("EPRT") - 1,
92 .skip = ' ', 92 .skip = ' ',
93 .term = '\r', 93 .term = '\r',
94 .ftptype = IP_CT_FTP_EPRT, 94 .ftptype = NF_CT_FTP_EPRT,
95 .getnum = try_eprt, 95 .getnum = try_eprt,
96 }, 96 },
97 }, 97 },
@@ -101,7 +101,7 @@ static struct ftp_search {
101 .plen = sizeof("227 ") - 1, 101 .plen = sizeof("227 ") - 1,
102 .skip = '(', 102 .skip = '(',
103 .term = ')', 103 .term = ')',
104 .ftptype = IP_CT_FTP_PASV, 104 .ftptype = NF_CT_FTP_PASV,
105 .getnum = try_rfc959, 105 .getnum = try_rfc959,
106 }, 106 },
107 { 107 {
@@ -109,7 +109,7 @@ static struct ftp_search {
109 .plen = sizeof("229 ") - 1, 109 .plen = sizeof("229 ") - 1,
110 .skip = '(', 110 .skip = '(',
111 .term = ')', 111 .term = ')',
112 .ftptype = IP_CT_FTP_EPSV, 112 .ftptype = NF_CT_FTP_EPSV,
113 .getnum = try_epsv_response, 113 .getnum = try_epsv_response,
114 }, 114 },
115 }, 115 },
@@ -320,7 +320,7 @@ static int find_pattern(const char *data, size_t dlen,
320} 320}
321 321
322/* Look up to see if we're just after a \n. */ 322/* Look up to see if we're just after a \n. */
323static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) 323static int find_nl_seq(u32 seq, const struct nf_ct_ftp_master *info, int dir)
324{ 324{
325 unsigned int i; 325 unsigned int i;
326 326
@@ -331,7 +331,7 @@ static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
331} 331}
332 332
333/* We don't update if it's older than what we have. */ 333/* We don't update if it's older than what we have. */
334static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir, 334static void update_nl_seq(u32 nl_seq, struct nf_ct_ftp_master *info, int dir,
335 struct sk_buff *skb) 335 struct sk_buff *skb)
336{ 336{
337 unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; 337 unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
@@ -367,7 +367,7 @@ static int help(struct sk_buff **pskb,
367 u32 seq; 367 u32 seq;
368 int dir = CTINFO2DIR(ctinfo); 368 int dir = CTINFO2DIR(ctinfo);
369 unsigned int matchlen, matchoff; 369 unsigned int matchlen, matchoff;
370 struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; 370 struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
371 struct nf_conntrack_expect *exp; 371 struct nf_conntrack_expect *exp;
372 struct nf_conntrack_man cmd = {}; 372 struct nf_conntrack_man cmd = {};
373 unsigned int i; 373 unsigned int i;
@@ -523,7 +523,7 @@ static int help(struct sk_buff **pskb,
523 /* Now, NAT might want to mangle the packet, and register the 523 /* Now, NAT might want to mangle the packet, and register the
524 * (possibly changed) expectation itself. */ 524 * (possibly changed) expectation itself. */
525 nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook); 525 nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook);
526 if (nf_nat_ftp) 526 if (nf_nat_ftp && ct->status & IPS_NAT_MASK)
527 ret = nf_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, 527 ret = nf_nat_ftp(pskb, ctinfo, search[dir][i].ftptype,
528 matchoff, matchlen, exp, &seq); 528 matchoff, matchlen, exp, &seq);
529 else { 529 else {