Commit 5b1158e9 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by David S. Miller
Browse files

[NETFILTER]: Add NAT support for nf_conntrack



Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik,
Yasuyuki Kozakai, Martin Josefsson and myself.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d2483dde
......@@ -357,7 +357,7 @@ extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
static inline void
nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family)
{
#ifdef CONFIG_IP_NF_NAT_NEEDED
#if defined(CONFIG_IP_NF_NAT_NEEDED) || defined(CONFIG_NF_NAT_NEEDED)
void (*decodefn)(struct sk_buff *, struct flowi *);
if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL)
......
......@@ -9,29 +9,23 @@
#ifndef _NF_CONNTRACK_IPV4_H
#define _NF_CONNTRACK_IPV4_H
#ifdef CONFIG_IP_NF_NAT_NEEDED
#include <linux/netfilter_ipv4/ip_nat.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat.h>
/* per conntrack: nat application helper private data */
union ip_conntrack_nat_help {
union nf_conntrack_nat_help {
/* insert nat helper private data here */
};
struct nf_conntrack_ipv4_nat {
struct ip_nat_info info;
union ip_conntrack_nat_help help;
struct nf_conn_nat {
struct nf_nat_info info;
union nf_conntrack_nat_help help;
#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
int masq_index;
#endif
};
#endif /* CONFIG_IP_NF_NAT_NEEDED */
struct nf_conntrack_ipv4 {
#ifdef CONFIG_IP_NF_NAT_NEEDED
struct nf_conntrack_ipv4_nat *nat;
#endif
};
#endif /* CONFIG_NF_NAT_NEEDED */
/* Returns new sk_buff, or NULL */
struct sk_buff *
......
......@@ -264,18 +264,45 @@ nf_conntrack_unregister_cache(u_int32_t features);
/* valid combinations:
* basic: nf_conn, nf_conn .. nf_conn_help
* nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help
* nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help
*/
#ifdef CONFIG_NF_NAT_NEEDED
static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct)
{
unsigned int offset = sizeof(struct nf_conn);
if (!(ct->features & NF_CT_F_NAT))
return NULL;
offset = ALIGN(offset, __alignof__(struct nf_conn_nat));
return (struct nf_conn_nat *) ((void *)ct + offset);
}
static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
{
unsigned int offset = sizeof(struct nf_conn);
if (!(ct->features & NF_CT_F_HELP))
return NULL;
if (ct->features & NF_CT_F_NAT) {
offset = ALIGN(offset, __alignof__(struct nf_conn_nat));
offset += sizeof(struct nf_conn_nat);
}
offset = ALIGN(offset, __alignof__(struct nf_conn_help));
return (struct nf_conn_help *) ((void *)ct + offset);
}
#else /* No NAT */
static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
{
unsigned int offset = sizeof(struct nf_conn);
if (!(ct->features & NF_CT_F_HELP))
return NULL;
offset = ALIGN(offset, __alignof__(struct nf_conn_help));
return (struct nf_conn_help *) ((void *)ct + offset);
}
#endif /* CONFIG_NF_NAT_NEEDED */
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_H */
......@@ -43,7 +43,7 @@ struct nf_conntrack_expect
#ifdef CONFIG_NF_NAT_NEEDED
/* This is the original per-proto part, used to map the
* expected connection the way the recipient expects. */
union nf_conntrack_manip_proto saved_proto;
union nf_conntrack_man_proto saved_proto;
/* Direction relative to the master connection. */
enum ip_conntrack_dir dir;
#endif
......
#ifndef _NF_NAT_H
#define _NF_NAT_H
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16
enum nf_nat_manip_type
{
IP_NAT_MANIP_SRC,
IP_NAT_MANIP_DST
};
/* SRC manip occurs POST_ROUTING or LOCAL_IN */
#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN)
#define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2
/* NAT sequence number modifications */
struct nf_nat_seq {
/* position of the last TCP sequence number modification (if any) */
u_int32_t correction_pos;
/* sequence number offset before and after last modification */
int16_t offset_before, offset_after;
};
/* Single range specification. */
struct nf_nat_range
{
/* Set to OR of flags above. */
unsigned int flags;
/* Inclusive: network order. */
__be32 min_ip, max_ip;
/* Inclusive: network order */
union nf_conntrack_man_proto min, max;
};
/* For backwards compat: don't use in modern code. */
struct nf_nat_multi_range_compat
{
unsigned int rangesize; /* Must be 1. */
/* hangs off end. */
struct nf_nat_range range[1];
};
#ifdef __KERNEL__
#include <linux/list.h>
/* The structure embedded in the conntrack structure. */
struct nf_nat_info
{
struct list_head bysource;
struct nf_nat_seq seq[IP_CT_DIR_MAX];
};
struct nf_conn;
/* Set up the info structure to map into this range. */
extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
const struct nf_nat_range *range,
unsigned int hooknum);
/* Is this tuple already taken? (not by us)*/
extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack);
extern int nf_nat_module_is_loaded;
#else /* !__KERNEL__: iptables wants this to compile. */
#define nf_nat_multi_range nf_nat_multi_range_compat
#endif /*__KERNEL__*/
#endif
#ifndef _NF_NAT_CORE_H
#define _NF_NAT_CORE_H
#include <linux/list.h>
#include <net/netfilter/nf_conntrack.h>
/* This header used to share core functionality between the standalone
NAT module, and the compatibility layer's use of NAT for masquerading. */
extern unsigned int nf_nat_packet(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb);
extern int nf_nat_icmp_reply_translation(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb);
static inline int nf_nat_initialized(struct nf_conn *ct,
enum nf_nat_manip_type manip)
{
if (manip == IP_NAT_MANIP_SRC)
return test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status);
else
return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
}
#endif /* _NF_NAT_CORE_H */
#ifndef _NF_NAT_HELPER_H
#define _NF_NAT_HELPER_H
/* NAT protocol helper routines. */
#include <net/netfilter/nf_conntrack.h>
struct sk_buff;
/* These return true or false. */
extern int nf_nat_mangle_tcp_packet(struct sk_buff **skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len);
extern int nf_nat_mangle_udp_packet(struct sk_buff **skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len);
extern int nf_nat_seq_adjust(struct sk_buff **pskb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo);
/* Setup NAT on this expected conntrack so it follows master, but goes
* to port ct->master->saved_proto. */
extern void nf_nat_follow_master(struct nf_conn *ct,
struct nf_conntrack_expect *this);
#endif
/* Header for use in defining a given protocol. */
#ifndef _NF_NAT_PROTOCOL_H
#define _NF_NAT_PROTOCOL_H
#include <net/netfilter/nf_nat.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
struct nf_nat_range;
struct nf_nat_protocol
{
/* Protocol name */
const char *name;
/* Protocol number. */
unsigned int protonum;
struct module *me;
/* Translate a packet to the target according to manip type.
Return true if succeeded. */
int (*manip_pkt)(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype);
/* Is the manipable part of the tuple between min and max incl? */
int (*in_range)(const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_proto *max);
/* Alter the per-proto part of the tuple (depending on
maniptype), to give a unique tuple in the given range if
possible; return false if not. Per-protocol part of tuple
is initialized to the incoming packet. */
int (*unique_tuple)(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct);
int (*range_to_nfattr)(struct sk_buff *skb,
const struct nf_nat_range *range);
int (*nfattr_to_range)(struct nfattr *tb[],
struct nf_nat_range *range);
};
/* Protocol registration. */
extern int nf_nat_protocol_register(struct nf_nat_protocol *proto);
extern void nf_nat_protocol_unregister(struct nf_nat_protocol *proto);
extern struct nf_nat_protocol *nf_nat_proto_find_get(u_int8_t protocol);
extern void nf_nat_proto_put(struct nf_nat_protocol *proto);
/* Built-in protocols. */
extern struct nf_nat_protocol nf_nat_protocol_tcp;
extern struct nf_nat_protocol nf_nat_protocol_udp;
extern struct nf_nat_protocol nf_nat_protocol_icmp;
extern struct nf_nat_protocol nf_nat_unknown_protocol;
extern int init_protocols(void) __init;
extern void cleanup_protocols(void);
extern struct nf_nat_protocol *find_nat_proto(u_int16_t protonum);
extern int nf_nat_port_range_to_nfattr(struct sk_buff *skb,
const struct nf_nat_range *range);
extern int nf_nat_port_nfattr_to_range(struct nfattr *tb[],
struct nf_nat_range *range);
#endif /*_NF_NAT_PROTO_H*/
#ifndef _NF_NAT_RULE_H
#define _NF_NAT_RULE_H
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_nat.h>
#include <linux/netfilter_ipv4/ip_tables.h>
/* Compatibility definitions for ipt_FOO modules */
#define ip_nat_range nf_nat_range
#define ip_conntrack_tuple nf_conntrack_tuple
#define ip_conntrack_get nf_ct_get
#define ip_conntrack nf_conn
#define ip_nat_setup_info nf_nat_setup_info
#define ip_nat_multi_range_compat nf_nat_multi_range_compat
#define ip_ct_iterate_cleanup nf_ct_iterate_cleanup
#define IP_NF_ASSERT NF_CT_ASSERT
extern int nf_nat_rule_init(void) __init;
extern void nf_nat_rule_cleanup(void);
extern int nf_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
struct nf_conn *ct,
struct nf_nat_info *info);
extern unsigned int
alloc_null_binding(struct nf_conn *ct,
struct nf_nat_info *info,
unsigned int hooknum);
extern unsigned int
alloc_null_binding_confirmed(struct nf_conn *ct,
struct nf_nat_info *info,
unsigned int hooknum);
#endif /* _NF_NAT_RULE_H */
......@@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration"
depends on INET && NETFILTER
config NF_CONNTRACK_IPV4
tristate "IPv4 support for new connection tracking (EXPERIMENTAL)"
tristate "IPv4 support for new connection tracking (required for NAT) (EXPERIMENTAL)"
depends on EXPERIMENTAL && NF_CONNTRACK
---help---
Connection tracking keeps a record of what packets have passed
......@@ -387,7 +387,7 @@ config IP_NF_TARGET_TCPMSS
To compile it as a module, choose M here. If unsure, say N.
# NAT + specific targets
# NAT + specific targets: ip_conntrack
config IP_NF_NAT
tristate "Full NAT"
depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
......@@ -398,14 +398,30 @@ config IP_NF_NAT
To compile it as a module, choose M here. If unsure, say N.
# NAT + specific targets: nf_conntrack
config NF_NAT
tristate "Full NAT"
depends on IP_NF_IPTABLES && NF_CONNTRACK
help
The Full NAT option allows masquerading, port forwarding and other
forms of full Network Address Port Translation. It is controlled by
the `nat' table in iptables: see the man page for iptables(8).
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_NAT_NEEDED
bool
depends on IP_NF_NAT != n
depends on IP_NF_NAT
default y
config NF_NAT_NEEDED
bool
depends on NF_NAT
default y
config IP_NF_TARGET_MASQUERADE
tristate "MASQUERADE target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_NF_NAT)
help
Masquerading is a special case of NAT: all outgoing connections are
changed to seem to come from a particular interface's address, and
......@@ -417,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE
config IP_NF_TARGET_REDIRECT
tristate "REDIRECT target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_NF_NAT)
help
REDIRECT is a special case of NAT: all incoming connections are
mapped onto the incoming interface's address, causing the packets to
......@@ -428,7 +444,7 @@ config IP_NF_TARGET_REDIRECT
config IP_NF_TARGET_NETMAP
tristate "NETMAP target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_NF_NAT)
help
NETMAP is an implementation of static 1:1 NAT mapping of network
addresses. It maps the network address part, while keeping the host
......@@ -439,7 +455,7 @@ config IP_NF_TARGET_NETMAP
config IP_NF_TARGET_SAME
tristate "SAME target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_NF_NAT)
help
This option adds a `SAME' target, which works like the standard SNAT
target, but attempts to give clients the same IP for all connections.
......
......@@ -5,7 +5,12 @@
# objects for the standalone - connection tracking / NAT
ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
ifneq ($(CONFIG_NF_NAT),)
iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o
else
iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o
endif
ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o
ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o
......@@ -16,6 +21,7 @@ ip_nat_h323-objs := ip_nat_helper_h323.o
# connection tracking
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
obj-$(CONFIG_IP_NF_NAT) += ip_nat.o
obj-$(CONFIG_NF_NAT) += nf_nat.o
# conntrack netlink interface
obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
......@@ -50,6 +56,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
obj-$(CONFIG_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
# matches
......
......@@ -44,12 +44,6 @@
#define DEBUGP(format, args...)
#endif
#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \
: ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \
: ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \
: ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
: "*ERROR*")))
#ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
......
......@@ -2,7 +2,7 @@
(depending on route). */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
* (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
......@@ -20,7 +20,11 @@
#include <net/checksum.h>
#include <net/route.h>
#include <linux/netfilter_ipv4.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
#include <linux/netfilter_ipv4/ip_tables.h>
MODULE_LICENSE("GPL");
......@@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb,
const struct xt_target *target,
const void *targinfo)
{
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat;
#endif
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
const struct ip_nat_multi_range_compat *mr;
struct ip_nat_range newrange;
const struct ip_nat_multi_range_compat *mr;
struct rtable *rt;
__be32 newsrc;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
ct = ip_conntrack_get(*pskb, &ctinfo);
#ifdef CONFIG_NF_NAT_NEEDED
nat = nfct_nat(ct);
#endif
IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
|| ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
/* Source address is 0.0.0.0 - locally generated packet that is
* probably not supposed to be masqueraded.
*/
#ifdef CONFIG_NF_NAT_NEEDED
if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
#else
if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0)
#endif
return NF_ACCEPT;
mr = targinfo;
......@@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb,
}
write_lock_bh(&masq_lock);
#ifdef CONFIG_NF_NAT_NEEDED
nat->masq_index = out->ifindex;
#else
ct->nat.masq_index = out->ifindex;
#endif
write_unlock_bh(&masq_lock);
/* Transfer from original range. */
......@@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb,
static inline int
device_cmp(struct ip_conntrack *i, void *ifindex)
{
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat = nfct_nat(i);
#endif
int ret;
read_lock_bh(&masq_lock);
#ifdef CONFIG_NF_NAT_NEEDED
ret = (nat->masq_index == (int)(long)ifindex);
#else
ret = (i->nat.masq_index == (int)(long)ifindex);
#endif
read_unlock_bh(&masq_lock);
return ret;
......
......@@ -15,7 +15,11 @@
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
#define MODULENAME "NETMAP"
MODULE_LICENSE("GPL");
......
/* Redirect. Simple mapping which alters dst to a local IP address. */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
* (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
......@@ -18,7 +18,11 @@
#include <net/protocol.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
......
......@@ -34,7 +34,11 @@
#include <net/protocol.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
#include <linux/netfilter_ipv4/ipt_SAME.h>
MODULE_LICENSE("GPL");
......@@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb,
Here we calculate the index in same->iparray which
holds the ipaddress we should use */
#ifdef CONFIG_NF_NAT_NEEDED
tmpip = ntohl(t->src.u3.ip);
if (!(same->info & IPT_SAME_NODST))
tmpip += ntohl(t->dst.u3.ip);
#else
tmpip = ntohl(t->src.ip);
if (!(same->info & IPT_SAME_NODST))
tmpip += ntohl(t->dst.ip);
#endif
aindex = tmpip % same->ipnum;