Skip to content

Commit

Permalink
[NETFILTER]: nf_nat: add FTP NAT helper port
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jozsef Kadlecsik authored and David S. Miller committed Dec 3, 2006
1 parent 5b1158e commit 55a7332
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 31 deletions.
20 changes: 10 additions & 10 deletions include/linux/netfilter/nf_conntrack_ftp.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
/* FTP tracking. */

/* This enum is exposed to userspace */
enum ip_ct_ftp_type
enum nf_ct_ftp_type
{
/* PORT command from client */
IP_CT_FTP_PORT,
NF_CT_FTP_PORT,
/* PASV response from server */
IP_CT_FTP_PASV,
NF_CT_FTP_PASV,
/* EPRT command from client */
IP_CT_FTP_EPRT,
NF_CT_FTP_EPRT,
/* EPSV response from server */
IP_CT_FTP_EPSV,
NF_CT_FTP_EPSV,
};

#ifdef __KERNEL__
Expand All @@ -21,23 +21,23 @@ enum ip_ct_ftp_type

#define NUM_SEQ_TO_REMEMBER 2
/* This structure exists only once per master */
struct ip_ct_ftp_master {
struct nf_ct_ftp_master {
/* Valid seq positions for cmd matching after newline */
u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
/* 0 means seq_match_aft_nl not set */
int seq_aft_nl_num[IP_CT_DIR_MAX];
};

struct ip_conntrack_expect;
struct nf_conntrack_expect;

/* For NAT to hook in when we find a packet which describes what other
* connection we should expect. */
extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
enum ip_ct_ftp_type type,
enum nf_ct_ftp_type type,
unsigned int matchoff,
unsigned int matchlen,
struct ip_conntrack_expect *exp,
struct nf_conntrack_expect *exp,
u32 *seq);
#endif /* __KERNEL__ */

Expand Down
40 changes: 39 additions & 1 deletion include/linux/netfilter_ipv4/ip_conntrack_ftp.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
#ifndef _IP_CONNTRACK_FTP_H
#define _IP_CONNTRACK_FTP_H
/* FTP tracking. */

#include <linux/netfilter/nf_conntrack_ftp.h>
/* This enum is exposed to userspace */
enum ip_ct_ftp_type
{
/* PORT command from client */
IP_CT_FTP_PORT,
/* PASV response from server */
IP_CT_FTP_PASV,
/* EPRT command from client */
IP_CT_FTP_EPRT,
/* EPSV response from server */
IP_CT_FTP_EPSV,
};

#ifdef __KERNEL__

#define FTP_PORT 21

#define NUM_SEQ_TO_REMEMBER 2
/* This structure exists only once per master */
struct ip_ct_ftp_master {
/* Valid seq positions for cmd matching after newline */
u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
/* 0 means seq_match_aft_nl not set */
int seq_aft_nl_num[IP_CT_DIR_MAX];
};

struct ip_conntrack_expect;

/* For NAT to hook in when we find a packet which describes what other
* connection we should expect. */
extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
enum ip_ct_ftp_type type,
unsigned int matchoff,
unsigned int matchlen,
struct ip_conntrack_expect *exp,
u32 *seq);
#endif /* __KERNEL__ */

#endif /* _IP_CONNTRACK_FTP_H */
2 changes: 1 addition & 1 deletion include/net/netfilter/nf_conntrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ union nf_conntrack_expect_proto {
/* per conntrack: application helper private data */
union nf_conntrack_help {
/* insert conntrack helper private data (master) here */
struct ip_ct_ftp_master ct_ftp_info;
struct nf_ct_ftp_master ct_ftp_info;
};

#include <linux/types.h>
Expand Down
25 changes: 17 additions & 8 deletions net/ipv4/netfilter/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -477,20 +477,29 @@ config IP_NF_NAT_SNMP_BASIC

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

# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker.
# From kconfig-language.txt:
#
# <expr> '&&' <expr> (6)
#
# (6) Returns the result of min(/expr/, /expr/).
config IP_NF_NAT_FTP
tristate
depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT
default IP_NF_NAT && IP_NF_FTP

config NF_NAT_FTP
tristate
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
default NF_NAT && NF_CONNTRACK_FTP

config IP_NF_NAT_IRC
tristate
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
default IP_NF_NAT if IP_NF_IRC=y
default m if IP_NF_IRC=m

# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh.
config IP_NF_NAT_FTP
tristate
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
default IP_NF_NAT if IP_NF_FTP=y
default m if IP_NF_FTP=m

config IP_NF_NAT_TFTP
tristate
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
Expand Down
5 changes: 4 additions & 1 deletion net/ipv4/netfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o

# NAT helpers
# NAT helpers (ip_conntrack)
obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
Expand All @@ -49,6 +49,9 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o

# NAT helpers (nf_conntrack)
obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o

# generic IP tables
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o

Expand Down
179 changes: 179 additions & 0 deletions net/ipv4/netfilter/nf_nat_ftp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* FTP extension for TCP NAT alteration. */

/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_ftp.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
MODULE_DESCRIPTION("ftp NAT helper");
MODULE_ALIAS("ip_nat_ftp");

#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif

/* FIXME: Time out? --RR */

static int
mangle_rfc959_packet(struct sk_buff **pskb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
u32 *seq)
{
char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];

sprintf(buffer, "%u,%u,%u,%u,%u,%u",
NIPQUAD(newip), port>>8, port&0xFF);

DEBUGP("calling nf_nat_mangle_tcp_packet\n");

*seq += strlen(buffer) - matchlen;
return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}

/* |1|132.235.1.2|6275| */
static int
mangle_eprt_packet(struct sk_buff **pskb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
u32 *seq)
{
char buffer[sizeof("|1|255.255.255.255|65535|")];

sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);

DEBUGP("calling nf_nat_mangle_tcp_packet\n");

*seq += strlen(buffer) - matchlen;
return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}

/* |1|132.235.1.2|6275| */
static int
mangle_epsv_packet(struct sk_buff **pskb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
u32 *seq)
{
char buffer[sizeof("|||65535|")];

sprintf(buffer, "|||%u|", port);

DEBUGP("calling nf_nat_mangle_tcp_packet\n");

*seq += strlen(buffer) - matchlen;
return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}

static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
unsigned int, unsigned int, struct nf_conn *,
enum ip_conntrack_info, u32 *seq)
= {
[NF_CT_FTP_PORT] = mangle_rfc959_packet,
[NF_CT_FTP_PASV] = mangle_rfc959_packet,
[NF_CT_FTP_EPRT] = mangle_eprt_packet,
[NF_CT_FTP_EPSV] = mangle_epsv_packet
};

/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int nf_nat_ftp(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
enum nf_ct_ftp_type type,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conntrack_expect *exp,
u32 *seq)
{
__be32 newip;
u_int16_t port;
int dir = CTINFO2DIR(ctinfo);
struct nf_conn *ct = exp->master;

DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);

/* Connection will come from wherever this packet goes, hence !dir */
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
exp->dir = !dir;

/* When you see the packet, we need to NAT it the same as the
* this one. */
exp->expectfn = nf_nat_follow_master;

/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
exp->tuple.dst.u.tcp.port = htons(port);
if (nf_conntrack_expect_related(exp) == 0)
break;
}

if (port == 0)
return NF_DROP;

if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
seq)) {
nf_conntrack_unexpect_related(exp);
return NF_DROP;
}
return NF_ACCEPT;
}

static void __exit nf_nat_ftp_fini(void)
{
rcu_assign_pointer(nf_nat_ftp_hook, NULL);
synchronize_rcu();
}

static int __init nf_nat_ftp_init(void)
{
BUG_ON(rcu_dereference(nf_nat_ftp_hook));
rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp);
return 0;
}

/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
static int warn_set(const char *val, struct kernel_param *kp)
{
printk(KERN_INFO KBUILD_MODNAME
": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
return 0;
}
module_param_call(ports, warn_set, NULL, NULL, 0);

module_init(nf_nat_ftp_init);
module_exit(nf_nat_ftp_fini);
Loading

0 comments on commit 55a7332

Please sign in to comment.