Skip to content

Commit 55a7332

Browse files
Jozsef Kadlecsikdavem330
authored andcommitted
[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 <[email protected]> Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5b1158e commit 55a7332

File tree

7 files changed

+260
-31
lines changed

7 files changed

+260
-31
lines changed

include/linux/netfilter/nf_conntrack_ftp.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
/* FTP tracking. */
44

55
/* This enum is exposed to userspace */
6-
enum ip_ct_ftp_type
6+
enum nf_ct_ftp_type
77
{
88
/* PORT command from client */
9-
IP_CT_FTP_PORT,
9+
NF_CT_FTP_PORT,
1010
/* PASV response from server */
11-
IP_CT_FTP_PASV,
11+
NF_CT_FTP_PASV,
1212
/* EPRT command from client */
13-
IP_CT_FTP_EPRT,
13+
NF_CT_FTP_EPRT,
1414
/* EPSV response from server */
15-
IP_CT_FTP_EPSV,
15+
NF_CT_FTP_EPSV,
1616
};
1717

1818
#ifdef __KERNEL__
@@ -21,23 +21,23 @@ enum ip_ct_ftp_type
2121

2222
#define NUM_SEQ_TO_REMEMBER 2
2323
/* This structure exists only once per master */
24-
struct ip_ct_ftp_master {
24+
struct nf_ct_ftp_master {
2525
/* Valid seq positions for cmd matching after newline */
2626
u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
2727
/* 0 means seq_match_aft_nl not set */
2828
int seq_aft_nl_num[IP_CT_DIR_MAX];
2929
};
3030

31-
struct ip_conntrack_expect;
31+
struct nf_conntrack_expect;
3232

3333
/* For NAT to hook in when we find a packet which describes what other
3434
* connection we should expect. */
35-
extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
35+
extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
3636
enum ip_conntrack_info ctinfo,
37-
enum ip_ct_ftp_type type,
37+
enum nf_ct_ftp_type type,
3838
unsigned int matchoff,
3939
unsigned int matchlen,
40-
struct ip_conntrack_expect *exp,
40+
struct nf_conntrack_expect *exp,
4141
u32 *seq);
4242
#endif /* __KERNEL__ */
4343

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,44 @@
11
#ifndef _IP_CONNTRACK_FTP_H
22
#define _IP_CONNTRACK_FTP_H
3+
/* FTP tracking. */
34

4-
#include <linux/netfilter/nf_conntrack_ftp.h>
5+
/* This enum is exposed to userspace */
6+
enum ip_ct_ftp_type
7+
{
8+
/* PORT command from client */
9+
IP_CT_FTP_PORT,
10+
/* PASV response from server */
11+
IP_CT_FTP_PASV,
12+
/* EPRT command from client */
13+
IP_CT_FTP_EPRT,
14+
/* EPSV response from server */
15+
IP_CT_FTP_EPSV,
16+
};
17+
18+
#ifdef __KERNEL__
19+
20+
#define FTP_PORT 21
21+
22+
#define NUM_SEQ_TO_REMEMBER 2
23+
/* This structure exists only once per master */
24+
struct ip_ct_ftp_master {
25+
/* Valid seq positions for cmd matching after newline */
26+
u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
27+
/* 0 means seq_match_aft_nl not set */
28+
int seq_aft_nl_num[IP_CT_DIR_MAX];
29+
};
30+
31+
struct ip_conntrack_expect;
32+
33+
/* For NAT to hook in when we find a packet which describes what other
34+
* connection we should expect. */
35+
extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
36+
enum ip_conntrack_info ctinfo,
37+
enum ip_ct_ftp_type type,
38+
unsigned int matchoff,
39+
unsigned int matchlen,
40+
struct ip_conntrack_expect *exp,
41+
u32 *seq);
42+
#endif /* __KERNEL__ */
543

644
#endif /* _IP_CONNTRACK_FTP_H */

include/net/netfilter/nf_conntrack.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ union nf_conntrack_expect_proto {
4545
/* per conntrack: application helper private data */
4646
union nf_conntrack_help {
4747
/* insert conntrack helper private data (master) here */
48-
struct ip_ct_ftp_master ct_ftp_info;
48+
struct nf_ct_ftp_master ct_ftp_info;
4949
};
5050

5151
#include <linux/types.h>

net/ipv4/netfilter/Kconfig

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -477,20 +477,29 @@ config IP_NF_NAT_SNMP_BASIC
477477

478478
To compile it as a module, choose M here. If unsure, say N.
479479

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/).
487+
config 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+
492+
config NF_NAT_FTP
493+
tristate
494+
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
495+
default NF_NAT && NF_CONNTRACK_FTP
496+
480497
config IP_NF_NAT_IRC
481498
tristate
482499
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
483500
default IP_NF_NAT if IP_NF_IRC=y
484501
default m if IP_NF_IRC=m
485502

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.
488-
config 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-
494503
config IP_NF_NAT_TFTP
495504
tristate
496505
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n

net/ipv4/netfilter/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
4040
obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
4141
obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
4242

43-
# NAT helpers
43+
# NAT helpers (ip_conntrack)
4444
obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
4545
obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
4646
obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
@@ -49,6 +49,9 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
4949
obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
5050
obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
5151

52+
# NAT helpers (nf_conntrack)
53+
obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
54+
5255
# generic IP tables
5356
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
5457

net/ipv4/netfilter/nf_nat_ftp.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 <[email protected]>
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+
23+
MODULE_LICENSE("GPL");
24+
MODULE_AUTHOR("Rusty Russell <[email protected]>");
25+
MODULE_DESCRIPTION("ftp NAT helper");
26+
MODULE_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+
36+
static int
37+
mangle_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| */
59+
static int
60+
mangle_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| */
81+
static int
82+
mangle_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+
102+
static 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. */
114+
static 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+
156+
static void __exit nf_nat_ftp_fini(void)
157+
{
158+
rcu_assign_pointer(nf_nat_ftp_hook, NULL);
159+
synchronize_rcu();
160+
}
161+
162+
static 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. */
170+
static 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+
}
176+
module_param_call(ports, warn_set, NULL, NULL, 0);
177+
178+
module_init(nf_nat_ftp_init);
179+
module_exit(nf_nat_ftp_fini);

0 commit comments

Comments
 (0)