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

[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 *); ...@@ -357,7 +357,7 @@ extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
static inline void static inline void
nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) 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 *); void (*decodefn)(struct sk_buff *, struct flowi *);
if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL) if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL)
......
...@@ -9,29 +9,23 @@ ...@@ -9,29 +9,23 @@
#ifndef _NF_CONNTRACK_IPV4_H #ifndef _NF_CONNTRACK_IPV4_H
#define _NF_CONNTRACK_IPV4_H #define _NF_CONNTRACK_IPV4_H
#ifdef CONFIG_IP_NF_NAT_NEEDED #ifdef CONFIG_NF_NAT_NEEDED
#include <linux/netfilter_ipv4/ip_nat.h> #include <net/netfilter/nf_nat.h>
/* per conntrack: nat application helper private data */ /* per conntrack: nat application helper private data */
union ip_conntrack_nat_help { union nf_conntrack_nat_help {
/* insert nat helper private data here */ /* insert nat helper private data here */
}; };
struct nf_conntrack_ipv4_nat { struct nf_conn_nat {
struct ip_nat_info info; struct nf_nat_info info;
union ip_conntrack_nat_help help; union nf_conntrack_nat_help help;
#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
int masq_index; int masq_index;
#endif #endif
}; };
#endif /* CONFIG_IP_NF_NAT_NEEDED */ #endif /* CONFIG_NF_NAT_NEEDED */
struct nf_conntrack_ipv4 {
#ifdef CONFIG_IP_NF_NAT_NEEDED
struct nf_conntrack_ipv4_nat *nat;
#endif
};
/* Returns new sk_buff, or NULL */ /* Returns new sk_buff, or NULL */
struct sk_buff * struct sk_buff *
......
...@@ -264,18 +264,45 @@ nf_conntrack_unregister_cache(u_int32_t features); ...@@ -264,18 +264,45 @@ nf_conntrack_unregister_cache(u_int32_t features);
/* valid combinations: /* valid combinations:
* basic: nf_conn, nf_conn .. nf_conn_help * 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) static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
{ {
unsigned int offset = sizeof(struct nf_conn); unsigned int offset = sizeof(struct nf_conn);
if (!(ct->features & NF_CT_F_HELP)) if (!(ct->features & NF_CT_F_HELP))
return NULL; 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)); offset = ALIGN(offset, __alignof__(struct nf_conn_help));
return (struct nf_conn_help *) ((void *)ct + offset); 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 /* __KERNEL__ */
#endif /* _NF_CONNTRACK_H */ #endif /* _NF_CONNTRACK_H */
...@@ -43,7 +43,7 @@ struct nf_conntrack_expect ...@@ -43,7 +43,7 @@ struct nf_conntrack_expect
#ifdef CONFIG_NF_NAT_NEEDED #ifdef CONFIG_NF_NAT_NEEDED
/* This is the original per-proto part, used to map the /* This is the original per-proto part, used to map the
* expected connection the way the recipient expects. */ * 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. */ /* Direction relative to the master connection. */
enum ip_conntrack_dir dir; enum ip_conntrack_dir dir;
#endif #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" ...@@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration"
depends on INET && NETFILTER depends on INET && NETFILTER
config NF_CONNTRACK_IPV4 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 depends on EXPERIMENTAL && NF_CONNTRACK
---help--- ---help---
Connection tracking keeps a record of what packets have passed Connection tracking keeps a record of what packets have passed
...@@ -387,7 +387,7 @@ config IP_NF_TARGET_TCPMSS ...@@ -387,7 +387,7 @@ config IP_NF_TARGET_TCPMSS
To compile it as a module, choose M here. If unsure, say N. 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 config IP_NF_NAT
tristate "Full NAT" tristate "Full NAT"
depends on IP_NF_IPTABLES && IP_NF_CONNTRACK depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
...@@ -398,14 +398,30 @@ config IP_NF_NAT ...@@ -398,14 +398,30 @@ config IP_NF_NAT
To compile it as a module, choose M here. If unsure, say N. 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 config IP_NF_NAT_NEEDED
bool 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 default y
config IP_NF_TARGET_MASQUERADE config IP_NF_TARGET_MASQUERADE
tristate "MASQUERADE target support" tristate "MASQUERADE target support"
depends on IP_NF_NAT depends on (NF_NAT || IP_NF_NAT)
help help
Masquerading is a special case of NAT: all outgoing connections are Masquerading is a special case of NAT: all outgoing connections are
changed to seem to come from a particular interface's address, and changed to seem to come from a particular interface's address, and
...@@ -417,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE ...@@ -417,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE
config IP_NF_TARGET_REDIRECT config IP_NF_TARGET_REDIRECT
tristate "REDIRECT target support" tristate "REDIRECT target support"
depends on IP_NF_NAT depends on (NF_NAT || IP_NF_NAT)
help help
REDIRECT is a special case of NAT: all incoming connections are REDIRECT is a special case of NAT: all incoming connections are
mapped onto the incoming interface's address, causing the packets to mapped onto the incoming interface's address, causing the packets to
...@@ -428,7 +444,7 @@ config IP_NF_TARGET_REDIRECT ...@@ -428,7 +444,7 @@ config IP_NF_TARGET_REDIRECT
config IP_NF_TARGET_NETMAP config IP_NF_TARGET_NETMAP
tristate "NETMAP target support" tristate "NETMAP target support"
depends on IP_NF_NAT depends on (NF_NAT || IP_NF_NAT)
help help
NETMAP is an implementation of static 1:1 NAT mapping of network NETMAP is an implementation of static 1:1 NAT mapping of network
addresses. It maps the network address part, while keeping the host addresses. It maps the network address part, while keeping the host
...@@ -439,7 +455,7 @@ config IP_NF_TARGET_NETMAP ...@@ -439,7 +455,7 @@ config IP_NF_TARGET_NETMAP
config IP_NF_TARGET_SAME config IP_NF_TARGET_SAME
tristate "SAME target support" tristate "SAME target support"
depends on IP_NF_NAT depends on (NF_NAT || IP_NF_NAT)
help help
This option adds a `SAME' target, which works like the standard SNAT This option adds a `SAME' target, which works like the standard SNAT
target, but attempts to give clients the same IP for all connections. target, but attempts to give clients the same IP for all connections.
......
...@@ -5,7 +5,12 @@ ...@@ -5,7 +5,12 @@
# objects for the standalone - connection tracking / NAT # 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_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 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 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_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 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 ...@@ -16,6 +21,7 @@ ip_nat_h323-objs := ip_nat_helper_h323.o
# connection tracking # connection tracking
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
obj-$(CONFIG_IP_NF_NAT) += ip_nat.o obj-$(CONFIG_IP_NF_NAT) += ip_nat.o
obj-$(CONFIG_NF_NAT) += nf_nat.o
# conntrack netlink interface # conntrack netlink interface
obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
...@@ -50,6 +56,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.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_FILTER) += iptable_filter.o
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
obj-$(CONFIG_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
# matches # matches
......
...@@ -44,12 +44,6 @@ ...@@ -44,12 +44,6 @@
#define DEBUGP(format, args...) #define DEBUGP(format, args...)
#endif #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 #ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
(depending on route). */ (depending on route). */
/* (C) 1999-2001 Paul `Rusty' Russell /* (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 * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -20,7 +20,11 @@ ...@@ -20,7 +20,11 @@
#include <net/checksum.h> #include <net/checksum.h>
#include <net/route.h> #include <net/route.h>
#include <linux/netfilter_ipv4.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> #include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb, ...@@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb,
const struct xt_target *target, const struct xt_target *target,
const void *targinfo) const void *targinfo)
{ {
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat;
#endif
struct ip_conntrack *ct; struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
const struct ip_nat_multi_range_compat *mr;
struct ip_nat_range newrange; struct ip_nat_range newrange;
const struct ip_nat_multi_range_compat *mr;
struct rtable *rt; struct rtable *rt;
__be32 newsrc; __be32 newsrc;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
ct = ip_conntrack_get(*pskb, &ctinfo); 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 IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
|| ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
/* Source address is 0.0.0.0 - locally generated packet that is /* Source address is 0.0.0.0 - locally generated packet that is
* probably not supposed to be masqueraded. * 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) if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0)
#endif
return NF_ACCEPT; return NF_ACCEPT;
mr = targinfo; mr = targinfo;
...@@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb, ...@@ -93,7 +107,11 @@ masquerade_target(struct sk_buff **pskb,
} }
write_lock_bh(&masq_lock); write_lock_bh(&masq_lock);
#ifdef CONFIG_NF_NAT_NEEDED
nat->masq_index = out->ifindex;
#else
ct->nat.masq_index = out->ifindex; ct->nat.masq_index = out->ifindex;
#endif
write_unlock_bh(&masq_lock); write_unlock_bh(&masq_lock);
/* Transfer from original range. */ /* Transfer from original range. */
...@@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb, ...@@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb,
static inline int static inline int
device_cmp(struct ip_conntrack *i, void *ifindex) device_cmp(struct ip_conntrack *i, void *ifindex)
{ {
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat = nfct_nat(i);
#endif
int ret; int ret;
read_lock_bh(&masq_lock); 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); ret = (i->nat.masq_index == (int)(long)ifindex);
#endif
read_unlock_bh(&masq_lock); read_unlock_bh(&masq_lock);
return ret; return ret;
......
...@@ -15,7 +15,11 @@ ...@@ -15,7 +15,11 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4.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> #include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
#define MODULENAME "NETMAP" #define MODULENAME "NETMAP"
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
/* Redirect. Simple mapping which alters dst to a local IP address. */ /* Redirect. Simple mapping which alters dst to a local IP address. */
/* (C) 1999-2001 Paul `Rusty' Russell /* (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 * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -18,7 +18,11 @@ ...@@ -18,7 +18,11 @@
#include <net/protocol.h> #include <net/protocol.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <linux/netfilter_ipv4.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> #include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
......
...@@ -34,7 +34,11 @@ ...@@ -34,7 +34,11 @@
#include <net/protocol.h> #include <net/protocol.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <linux/netfilter_ipv4.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> #include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
#include <linux/netfilter_ipv4/ipt_SAME.h> #include <linux/netfilter_ipv4/ipt_SAME.h>
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb, ...@@ -152,11 +156,17 @@ same_target(struct sk_buff **pskb,
Here we calculate the index in same->iparray which Here we calculate the index in same->iparray which
holds the ipaddress we should use */ 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); tmpip = ntohl(t->src.ip);
if (!(same->info & IPT_SAME_NODST)) if (!(same->info & IPT_SAME_NODST))
tmpip += ntohl(t->dst.ip); tmpip += ntohl(t->dst.ip);
#endif
aindex = tmpip % same->ipnum; aindex = tmpip % same->ipnum;
new_ip = htonl(same->iparray[aindex]); new_ip = htonl(same->iparray[aindex]);
......
...@@ -111,10 +111,10 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, ...@@ -111,10 +111,10 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
return NF_ACCEPT; return NF_ACCEPT;
} }
int nat_module_is_loaded = 0; int nf_nat_module_is_loaded = 0;
static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple)
{ {
if (nat_module_is_loaded) if (nf_nat_module_is_loaded)
return NF_CT_F_NAT; return NF_CT_F_NAT;
return NF_CT_F_BASIC; return NF_CT_F_BASIC;
...@@ -532,3 +532,6 @@ module_init(nf_conntrack_l3proto_ipv4_init); ...@@ -532,3 +532,6 @@ module_init(nf_conntrack_l3proto_ipv4_init);
module_exit(nf_conntrack_l3proto_ipv4_fini); module_exit(nf_conntrack_l3proto_ipv4_fini);
EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
#ifdef CONFIG_NF_NAT_NEEDED
EXPORT_SYMBOL(nf_nat_module_is_loaded);
#endif
This diff is collapsed.
This diff is collapsed.
/* (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/types.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
static int
icmp_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)
{
return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) &&
ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
}
static int
icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
static u_int16_t id;
unsigned int range_size;
unsigned int i;
range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1;
/* If no range specified... */
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED))
range_size = 0xFFFF;
for (i = 0; i < range_size; i++, id++) {
tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
(id % range_size));
if (!nf_nat_used_tuple(tuple, ct))
return 1;
}
return 0;
}
static int
icmp_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct icmphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
return 0;
hdr = (struct icmphdr *)((*pskb)->data + hdroff);
nf_proto_csum_replace2(&hdr->checksum, *pskb,
hdr->un.echo.id, tuple->src.u.icmp.id, 0);
hdr->un.echo.id = tuple->src.u.icmp.id;
return 1;
}
struct nf_nat_protocol nf_nat_protocol_icmp = {
.name = "ICMP",
.protonum = IPPROTO_ICMP,
.me = THIS_MODULE,
.manip_pkt = icmp_manip_pkt,
.in_range = icmp_in_range,
.unique_tuple = icmp_unique_tuple,
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
.range_to_nfattr = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};
/* (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/types.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
#include <net/netfilter/nf_nat_core.h>
static int
tcp_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)
{
__be16 port;
if (maniptype == IP_NAT_MANIP_SRC)
port = tuple->src.u.tcp.port;
else
port = tuple->dst.u.tcp.port;
return ntohs(port) >= ntohs(min->tcp.port) &&
ntohs(port) <= ntohs(max->tcp.port);
}
static int
tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
static u_int16_t port;
__be16 *portptr;
unsigned int range_size, min, i;
if (maniptype == IP_NAT_MANIP_SRC)
portptr = &tuple->src.u.tcp.port;
else
portptr = &tuple->dst.u.tcp.port;
/* If no range specified... */
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
/* If it's dst rewrite, can't change port */
if (maniptype == IP_NAT_MANIP_DST)
return 0;
/* Map privileged onto privileged. */
if (ntohs(*portptr) < 1024) {
/* Loose convention: >> 512 is credential passing */
if (ntohs(*portptr)<512) {
min = 1;
range_size = 511 - min + 1;
} else {
min = 600;
range_size = 1023 - min + 1;
}
} else {
min = 1024;
range_size = 65535 - 1024 + 1;
}
} else {
min = ntohs(range->min.tcp.port);
range_size = ntohs(range->max.tcp.port) - min + 1;
}
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct))
return 1;
}
return 0;
}
static int
tcp_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct tcphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
__be32 oldip, newip;
__be16 *portptr, newport, oldport;
int hdrsize = 8; /* TCP connection tracking guarantees this much */
/* this could be a inner header returned in icmp packet; in such
cases we cannot update the checksum field since it is outside of
the 8 bytes of transport layer headers we are guaranteed */
if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
hdrsize = sizeof(struct tcphdr);
if (!skb_make_writable(pskb, hdroff + hdrsize))
return 0;
iph = (struct iphdr *)((*pskb)->data + iphdroff);
hdr = (struct tcphdr *)((*pskb)->data + hdroff);
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
oldip = iph->saddr;
newip = tuple->src.u3.ip;
newport = tuple->src.u.tcp.port;
portptr = &hdr->source;
} else {
/* Get rid of dst ip and dst pt */
oldip = iph->daddr;
newip = tuple->dst.u3.ip;
newport = tuple->dst.u.tcp.port;
portptr = &hdr->dest;
}
oldport = *portptr;
*portptr = newport;
if (hdrsize < sizeof(*hdr))
return 1;
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
return 1;
}
struct nf_nat_protocol nf_nat_protocol_tcp = {
.name = "TCP",
.protonum = IPPROTO_TCP,
.me = THIS_MODULE,
.manip_pkt = tcp_manip_pkt,
.in_range = tcp_in_range,
.unique_tuple = tcp_unique_tuple,
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
.range_to_nfattr = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};
/* (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/types.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
static int
udp_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)
{
__be16 port;
if (maniptype == IP_NAT_MANIP_SRC)
port = tuple->src.u.udp.port;
else
port = tuple->dst.u.udp.port;
return ntohs(port) >= ntohs(min->udp.port) &&
ntohs(port) <= ntohs(max->udp.port);
}
static int
udp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
static u_int16_t port;
__be16 *portptr;
unsigned int range_size, min, i;
if (maniptype == IP_NAT_MANIP_SRC)
portptr = &tuple->src.u.udp.port;
else
portptr = &tuple->dst.u.udp.port;
/* If no range specified... */
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
/* If it's dst rewrite, can't change port */
if (maniptype == IP_NAT_MANIP_DST)
return 0;
if (ntohs(*portptr) < 1024) {
/* Loose convention: >> 512 is credential passing */
if (ntohs(*portptr)<512) {
min = 1;
range_size = 511 - min + 1;
} else {
min = 600;
range_size = 1023 - min + 1;
}
} else {
min = 1024;
range_size = 65535 - 1024 + 1;
}
} else {
min = ntohs(range->min.udp.port);
range_size = ntohs(range->max.udp.port) - min + 1;
}
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct))
return 1;
}
return 0;
}
static int
udp_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct udphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
__be32 oldip, newip;
__be16 *portptr, newport;
if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
return 0;
iph = (struct iphdr *)((*pskb)->data + iphdroff);
hdr = (struct udphdr *)((*pskb)->data + hdroff);
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
oldip = iph->saddr;
newip = tuple->src.u3.ip;
newport = tuple->src.u.udp.port;
portptr = &hdr->source;
} else {
/* Get rid of dst ip and dst pt */
oldip = iph->daddr;
newip = tuple->dst.u3.ip;
newport = tuple->dst.u.udp.port;
portptr = &hdr->dest;
}
if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport,
0);
if (!hdr->check)
hdr->check = CSUM_MANGLED_0;
}
*portptr = newport;
return 1;
}
struct nf_nat_protocol nf_nat_protocol_udp = {
.name = "UDP",
.protonum = IPPROTO_UDP,
.me = THIS_MODULE,
.manip_pkt = udp_manip_pkt,
.in_range = udp_in_range,
.unique_tuple = udp_unique_tuple,
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
.range_to_nfattr = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};
/* The "unknown" protocol. This is what is used for protocols we
* don't understand. It's returned by ip_ct_find_proto().
*/
/* (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/types.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
static int unknown_in_range(const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type manip_type,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_proto *max)
{
return 1;
}
static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
/* Sorry: we can't help you; if it's not unique, we can't frob
anything. */
return 0;
}
static int
unknown_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
return 1;
}
struct nf_nat_protocol nf_nat_unknown_protocol = {
.name = "unknown",
/* .me isn't set: getting a ref to this cannot fail. */
.manip_pkt = unknown_manip_pkt,
.in_range = unknown_in_range,
.unique_tuple = unknown_unique_tuple,
};
/* (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.
*/
/* Everything about the rules for NAT. */
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <net/checksum.h>
#include <net/route.h>
#include <linux/bitops.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
#define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT))
static struct
{
struct ipt_replace repl;
struct ipt_standard entries[3];
struct ipt_error term;
} nat_initial_table __initdata = {
.repl = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
.underflow = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
},
.entries = {
/* PRE_ROUTING */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* POST_ROUTING */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* LOCAL_OUT */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
},
/* ERROR */
.term = {
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_error),
},
.target = {
.target = {
.u = {
.user = {
.target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
.name = IPT_ERROR_TARGET,
},
},
},
.errorname = "ERROR",
},
}
};
static struct ipt_table nat_table = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
.me = THIS_MODULE,
.af = AF_INET,
};
/* Source NAT */
static unsigned int ipt_snat_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_nat_multi_range_compat *mr = targinfo;
NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
ct = nf_ct_get(*pskb, &ctinfo);
/* Connection must be valid and new. */
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
NF_CT_ASSERT(out);
return nf_nat_setup_info(ct, &mr->range[0], hooknum);
}
/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
{
static int warned = 0;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
struct rtable *rt;
if (ip_route_output_key(&rt, &fl) != 0)
return;
if (rt->rt_src != srcip && !warned) {
printk("NAT: no longer support implicit source local NAT\n");
printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n",
NIPQUAD(srcip), NIPQUAD(dstip));
warned = 1;
}
ip_rt_put(rt);
}
static unsigned int ipt_dnat_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_nat_multi_range_compat *mr = targinfo;
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
hooknum == NF_IP_LOCAL_OUT);
ct = nf_ct_get(*pskb, &ctinfo);
/* Connection must be valid and new. */
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
if (hooknum == NF_IP_LOCAL_OUT &&
mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
warn_if_extra_mangle((*pskb)->nh.iph->daddr,
mr->range[0].min_ip);
return nf_nat_setup_info(ct, &mr->range[0], hooknum);
}
static int ipt_snat_checkentry(const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
struct nf_nat_multi_range_compat *mr = targinfo;
/* Must be a valid range */
if (mr->rangesize != 1) {
printk("SNAT: multiple ranges no longer supported\n");
return 0;
}
return 1;
}
static int ipt_dnat_checkentry(const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
struct nf_nat_multi_range_compat *mr = targinfo;
/* Must be a valid range */
if (mr->rangesize != 1) {
printk("DNAT: multiple ranges no longer supported\n");
return 0;
}
return 1;
}
inline unsigned int
alloc_null_binding(struct nf_conn *ct,
struct nf_nat_info *info,
unsigned int hooknum)
{
/* Force range to this IP; let proto decide mapping for
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
Use reply in case it's already been mangled (eg local packet).
*/
__be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
struct nf_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n",
ct, NIPQUAD(ip));
return nf_nat_setup_info(ct, &range, hooknum);
}
unsigned int
alloc_null_binding_confirmed(struct nf_conn *ct,
struct nf_nat_info *info,
unsigned int hooknum)
{
__be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
u_int16_t all
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
struct nf_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
ct, NIPQUAD(ip));
return nf_nat_setup_info(ct, &range, hooknum);
}
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)
{
int ret;
ret = ipt_do_table(pskb, hooknum, in, out, &nat_table);
if (ret == NF_ACCEPT) {
if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
/* NUL mapping */
ret = alloc_null_binding(ct, info, hooknum);
}
return ret;
}
static struct ipt_target ipt_snat_reg = {
.name = "SNAT",
.target = ipt_snat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
.table = "nat",
.hooks = 1 << NF_IP_POST_ROUTING,
.checkentry = ipt_snat_checkentry,
.family = AF_INET,
};
static struct xt_target ipt_dnat_reg = {
.name = "DNAT",
.target = ipt_dnat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
.table = "nat",
.hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
.checkentry = ipt_dnat_checkentry,
.family = AF_INET,
};
int __init nf_nat_rule_init(void)
{
int ret;
ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
if (ret != 0)
return ret;
ret = xt_register_target(&ipt_snat_reg);
if (ret != 0)
goto unregister_table;
ret = xt_register_target(&ipt_dnat_reg);
if (ret != 0)
goto unregister_snat;
return ret;
unregister_snat:
xt_unregister_target(&ipt_snat_reg);
unregister_table:
ipt_unregister_table(&nat_table);
return ret;
}
void nf_nat_rule_cleanup(void)
{
xt_unregister_target(&ipt_dnat_reg);
xt_unregister_target(&ipt_snat_reg);
ipt_unregister_table(&nat_table);
}
This diff is collapsed.
...@@ -579,7 +579,8 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, ...@@ -579,7 +579,8 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
/* FIXME: protect helper list per RCU */ /* FIXME: protect helper list per RCU */
read_lock_bh(&nf_conntrack_lock); read_lock_bh(&nf_conntrack_lock);
helper = __nf_ct_helper_find(repl); helper = __nf_ct_helper_find(repl);
if (helper) /* NAT might want to assign a helper later */
if (helper || features & NF_CT_F_NAT)
features |= NF_CT_F_HELP; features |= NF_CT_F_HELP;
read_unlock_bh(&nf_conntrack_lock); read_unlock_bh(&nf_conntrack_lock);
...@@ -850,6 +851,26 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, ...@@ -850,6 +851,26 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
orig->dst.protonum)); orig->dst.protonum));
} }
/* Alter reply tuple (maybe alter helper). This is for NAT, and is
implicitly racy: see __nf_conntrack_confirm */
void nf_conntrack_alter_reply(struct nf_conn *ct,
const struct nf_conntrack_tuple *newreply)
{
struct nf_conn_help *help = nfct_help(ct);
write_lock_bh(&nf_conntrack_lock);
/* Should be unconfirmed, so not in hash table yet */
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
DEBUGP("Altering reply tuple of %p to ", ct);
NF_CT_DUMP_TUPLE(newreply);
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
if (!ct->master && help && help->expecting == 0)
help->helper = __nf_ct_helper_find(newreply);
write_unlock_bh(&nf_conntrack_lock);
}
/* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */
void __nf_ct_refresh_acct(struct nf_conn *ct, void __nf_ct_refresh_acct(struct nf_conn *ct,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
......
...@@ -39,7 +39,11 @@ ...@@ -39,7 +39,11 @@
#include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l3proto.h> #include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_l4proto.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h> #include <net/netfilter/nf_conntrack_tuple.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_protocol.h>
#endif
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h> #include <linux/netfilter/nfnetlink_conntrack.h>
...@@ -430,7 +434,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -430,7 +434,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
restart: restart:
list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
h = (struct nf_conntrack_tuple_hash *) i; h = (struct nf_conntrack_tuple_hash *) i;
if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
continue; continue;
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
/* Dump entries of a given L3 protocol number. /* Dump entries of a given L3 protocol number.
...@@ -556,28 +560,28 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, ...@@ -556,28 +560,28 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
return 0; return 0;
} }
#ifdef CONFIG_IP_NF_NAT_NEEDED #ifdef CONFIG_NF_NAT_NEEDED
static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
[CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t),
[CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),
}; };
static int ctnetlink_parse_nat_proto(struct nfattr *attr, static int nfnetlink_parse_nat_proto(struct nfattr *attr,
const struct nf_conn *ct, const struct nf_conn *ct,
struct ip_nat_range *range) struct nf_nat_range *range)
{ {
struct nfattr *tb[CTA_PROTONAT_MAX]; struct nfattr *tb[CTA_PROTONAT_MAX];
struct ip_nat_protocol *npt; struct nf_nat_protocol *npt;
nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
return -EINVAL; return -EINVAL;
npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
if (!npt->nfattr_to_range) { if (!npt->nfattr_to_range) {
ip_nat_proto_put(npt); nf_nat_proto_put(npt);
return 0; return 0;
} }
...@@ -585,7 +589,7 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr, ...@@ -585,7 +589,7 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
if (npt->nfattr_to_range(tb, range) > 0) if (npt->nfattr_to_range(tb, range) > 0)
range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
ip_nat_proto_put(npt); nf_nat_proto_put(npt);
return 0; return 0;
} }
...@@ -596,8 +600,8 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = { ...@@ -596,8 +600,8 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = {
}; };
static inline int static inline int
ctnetlink_parse_nat(struct nfattr *nat, nfnetlink_parse_nat(struct nfattr *nat,
const struct nf_conn *ct, struct ip_nat_range *range) const struct nf_conn *ct, struct nf_nat_range *range)
{ {
struct nfattr *tb[CTA_NAT_MAX]; struct nfattr *tb[CTA_NAT_MAX];
int err; int err;
...@@ -623,7 +627,7 @@ ctnetlink_parse_nat(struct nfattr *nat, ...@@ -623,7 +627,7 @@ ctnetlink_parse_nat(struct nfattr *nat,
if (!tb[CTA_NAT_PROTO-1]) if (!tb[CTA_NAT_PROTO-1])
return 0; return 0;
err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
if (err < 0) if (err < 0)
return err; return err;
...@@ -798,35 +802,35 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) ...@@ -798,35 +802,35 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[])
return -EINVAL; return -EINVAL;
if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
#ifndef CONFIG_IP_NF_NAT_NEEDED #ifndef CONFIG_NF_NAT_NEEDED
return -EINVAL; return -EINVAL;
#else #else
struct ip_nat_range range; struct nf_nat_range range;
if (cda[CTA_NAT_DST-1]) { if (cda[CTA_NAT_DST-1]) {
if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, if (nfnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
&range) < 0) &range) < 0)
return -EINVAL; return -EINVAL;
if (ip_nat_initialized(ct, if (nf_nat_initialized(ct,
HOOK2MANIP(NF_IP_PRE_ROUTING))) HOOK2MANIP(NF_IP_PRE_ROUTING)))
return -EEXIST; return -EEXIST;
ip_nat_setup_info(ct, &range, hooknum); nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
} }
if (cda[CTA_NAT_SRC-1]) { if (cda[CTA_NAT_SRC-1]) {
if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, if (nfnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
&range) < 0) &range) < 0)
return -EINVAL; return -EINVAL;
if (ip_nat_initialized(ct, if (nf_nat_initialized(ct,
HOOK2MANIP(NF_IP_POST_ROUTING))) HOOK2MANIP(NF_IP_POST_ROUTING)))
return -EEXIST; return -EEXIST;
ip_nat_setup_info(ct, &range, hooknum); nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
} }
#endif #endif
} }
/* Be careful here, modifying NAT bits can screw up things, /* Be careful here, modifying NAT bits can screw up things,
* so don't let users modify them directly if they don't pass * so don't let users modify them directly if they don't pass
* ip_nat_range. */ * nf_nat_range. */
ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
return 0; return 0;
} }
......
...@@ -730,7 +730,7 @@ static int tcp_in_window(struct ip_ct_tcp *state, ...@@ -730,7 +730,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
return res; return res;
} }
#ifdef CONFIG_IP_NF_NAT_NEEDED #ifdef CONFIG_NF_NAT_NEEDED
/* Update sender->td_end after NAT successfully mangled the packet */ /* Update sender->td_end after NAT successfully mangled the packet */
/* Caller must linearize skb at tcp header. */ /* Caller must linearize skb at tcp header. */
void nf_conntrack_tcp_update(struct sk_buff *skb, void nf_conntrack_tcp_update(struct sk_buff *skb,
......
...@@ -530,8 +530,11 @@ EXPORT_SYMBOL(nf_conntrack_lock); ...@@ -530,8 +530,11 @@ EXPORT_SYMBOL(nf_conntrack_lock);
EXPORT_SYMBOL(nf_conntrack_hash); EXPORT_SYMBOL(nf_conntrack_hash);
EXPORT_SYMBOL(nf_conntrack_untracked); EXPORT_SYMBOL(nf_conntrack_untracked);
EXPORT_SYMBOL_GPL(nf_conntrack_find_get); EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
#ifdef CONFIG_IP_NF_NAT_NEEDED #ifdef CONFIG_NF_NAT_NEEDED
EXPORT_SYMBOL(nf_conntrack_tcp_update); EXPORT_SYMBOL(nf_conntrack_tcp_update);
EXPORT_SYMBOL(nf_conntrack_register_cache);
EXPORT_SYMBOL(nf_conntrack_unregister_cache);
EXPORT_SYMBOL(nf_conntrack_alter_reply);
#endif #endif
EXPORT_SYMBOL(__nf_conntrack_confirm); EXPORT_SYMBOL(__nf_conntrack_confirm);
EXPORT_SYMBOL(nf_ct_get_tuple); EXPORT_SYMBOL(nf_ct_get_tuple);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment