aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2012-08-26 13:14:06 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-08-29 21:00:14 -0400
commitc7232c9979cba684c50b64c513c4a83c9aa70563 (patch)
treedbe0fdac62191d85935f5a3dfe815c1b1add60f9
parent051966c0c644a1c96092d4206e00704ade813c9a (diff)
netfilter: add protocol independent NAT core
Convert the IPv4 NAT implementation to a protocol independent core and address family specific modules. Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/linux/netfilter.h14
-rw-r--r--include/linux/netfilter/nf_nat.h8
-rw-r--r--include/linux/netfilter/nfnetlink_conntrack.h6
-rw-r--r--include/linux/netfilter_ipv4.h1
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h2
-rw-r--r--include/net/netfilter/nf_nat.h2
-rw-r--r--include/net/netfilter/nf_nat_core.h5
-rw-r--r--include/net/netfilter/nf_nat_l3proto.h47
-rw-r--r--include/net/netfilter/nf_nat_l4proto.h71
-rw-r--r--include/net/netfilter/nf_nat_protocol.h67
-rw-r--r--include/net/netfilter/nf_nat_rule.h15
-rw-r--r--include/net/netns/conntrack.h4
-rw-r--r--include/net/netns/ipv4.h2
-rw-r--r--net/ipv4/netfilter.c37
-rw-r--r--net/ipv4/netfilter/Kconfig64
-rw-r--r--net/ipv4/netfilter/Makefile11
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c15
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c15
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c15
-rw-r--r--net/ipv4/netfilter/iptable_nat.c (renamed from net/ipv4/netfilter/nf_nat_standalone.c)264
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c6
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c1
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c1
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c23
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c1
-rw-r--r--net/ipv4/netfilter/nf_nat_l3proto_ipv4.c281
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c15
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c30
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_icmp.c24
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c214
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c19
-rw-r--r--net/ipv4/netfilter/nf_nat_tftp.c1
-rw-r--r--net/netfilter/Kconfig24
-rw-r--r--net/netfilter/Makefile11
-rw-r--r--net/netfilter/core.c5
-rw-r--r--net/netfilter/nf_conntrack_core.c6
-rw-r--r--net/netfilter/nf_conntrack_netlink.c35
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c8
-rw-r--r--net/netfilter/nf_conntrack_sip.c6
-rw-r--r--net/netfilter/nf_nat_core.c (renamed from net/ipv4/netfilter/nf_nat_core.c)673
-rw-r--r--net/netfilter/nf_nat_helper.c (renamed from net/ipv4/netfilter/nf_nat_helper.c)100
-rw-r--r--net/netfilter/nf_nat_proto_common.c (renamed from net/ipv4/netfilter/nf_nat_proto_common.c)54
-rw-r--r--net/netfilter/nf_nat_proto_dccp.c (renamed from net/ipv4/netfilter/nf_nat_proto_dccp.c)56
-rw-r--r--net/netfilter/nf_nat_proto_sctp.c (renamed from net/ipv4/netfilter/nf_nat_proto_sctp.c)53
-rw-r--r--net/netfilter/nf_nat_proto_tcp.c (renamed from net/ipv4/netfilter/nf_nat_proto_tcp.c)40
-rw-r--r--net/netfilter/nf_nat_proto_udp.c (renamed from net/ipv4/netfilter/nf_nat_proto_udp.c)42
-rw-r--r--net/netfilter/nf_nat_proto_udplite.c (renamed from net/ipv4/netfilter/nf_nat_proto_udplite.c)58
-rw-r--r--net/netfilter/nf_nat_proto_unknown.c (renamed from net/ipv4/netfilter/nf_nat_proto_unknown.c)16
-rw-r--r--net/netfilter/xt_nat.c167
49 files changed, 1495 insertions, 1140 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index c613cf0d788..1dcf2a38e51 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -342,7 +342,7 @@ extern int nf_register_afinfo(const struct nf_afinfo *afinfo);
342extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo); 342extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo);
343 343
344#include <net/flow.h> 344#include <net/flow.h>
345extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); 345extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
346 346
347static inline void 347static inline void
348nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) 348nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
@@ -350,13 +350,11 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
350#ifdef CONFIG_NF_NAT_NEEDED 350#ifdef CONFIG_NF_NAT_NEEDED
351 void (*decodefn)(struct sk_buff *, struct flowi *); 351 void (*decodefn)(struct sk_buff *, struct flowi *);
352 352
353 if (family == AF_INET) { 353 rcu_read_lock();
354 rcu_read_lock(); 354 decodefn = rcu_dereference(nf_nat_decode_session_hook);
355 decodefn = rcu_dereference(ip_nat_decode_session); 355 if (decodefn)
356 if (decodefn) 356 decodefn(skb, fl);
357 decodefn(skb, fl); 357 rcu_read_unlock();
358 rcu_read_unlock();
359 }
360#endif 358#endif
361} 359}
362 360
diff --git a/include/linux/netfilter/nf_nat.h b/include/linux/netfilter/nf_nat.h
index 8df2d13730b..bf0cc373ffb 100644
--- a/include/linux/netfilter/nf_nat.h
+++ b/include/linux/netfilter/nf_nat.h
@@ -22,4 +22,12 @@ struct nf_nat_ipv4_multi_range_compat {
22 struct nf_nat_ipv4_range range[1]; 22 struct nf_nat_ipv4_range range[1];
23}; 23};
24 24
25struct nf_nat_range {
26 unsigned int flags;
27 union nf_inet_addr min_addr;
28 union nf_inet_addr max_addr;
29 union nf_conntrack_man_proto min_proto;
30 union nf_conntrack_man_proto max_proto;
31};
32
25#endif /* _NETFILTER_NF_NAT_H */ 33#endif /* _NETFILTER_NF_NAT_H */
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index f649f7423ca..68920eab287 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -142,8 +142,10 @@ enum ctattr_tstamp {
142 142
143enum ctattr_nat { 143enum ctattr_nat {
144 CTA_NAT_UNSPEC, 144 CTA_NAT_UNSPEC,
145 CTA_NAT_MINIP, 145 CTA_NAT_V4_MINIP,
146 CTA_NAT_MAXIP, 146#define CTA_NAT_MINIP CTA_NAT_V4_MINIP
147 CTA_NAT_V4_MAXIP,
148#define CTA_NAT_MAXIP CTA_NAT_V4_MAXIP
147 CTA_NAT_PROTO, 149 CTA_NAT_PROTO,
148 __CTA_NAT_MAX 150 __CTA_NAT_MAX
149}; 151};
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index e2b12801378..b962dfc695a 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -79,7 +79,6 @@ enum nf_ip_hook_priorities {
79 79
80#ifdef __KERNEL__ 80#ifdef __KERNEL__
81extern int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type); 81extern int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type);
82extern int ip_xfrm_me_harder(struct sk_buff *skb);
83extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, 82extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
84 unsigned int dataoff, u_int8_t protocol); 83 unsigned int dataoff, u_int8_t protocol);
85#endif /*__KERNEL__*/ 84#endif /*__KERNEL__*/
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 983f0026324..cc13f377a70 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -43,7 +43,7 @@ struct nf_conntrack_expect {
43 unsigned int class; 43 unsigned int class;
44 44
45#ifdef CONFIG_NF_NAT_NEEDED 45#ifdef CONFIG_NF_NAT_NEEDED
46 __be32 saved_ip; 46 union nf_inet_addr saved_addr;
47 /* This is the original per-proto part, used to map the 47 /* This is the original per-proto part, used to map the
48 * expected connection the way the recipient expects. */ 48 * expected connection the way the recipient expects. */
49 union nf_conntrack_man_proto saved_proto; 49 union nf_conntrack_man_proto saved_proto;
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
index b4de990b55f..1752f133905 100644
--- a/include/net/netfilter/nf_nat.h
+++ b/include/net/netfilter/nf_nat.h
@@ -50,7 +50,7 @@ struct nf_conn_nat {
50 50
51/* Set up the info structure to map into this range. */ 51/* Set up the info structure to map into this range. */
52extern unsigned int nf_nat_setup_info(struct nf_conn *ct, 52extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
53 const struct nf_nat_ipv4_range *range, 53 const struct nf_nat_range *range,
54 enum nf_nat_manip_type maniptype); 54 enum nf_nat_manip_type maniptype);
55 55
56/* Is this tuple already taken? (not by us)*/ 56/* Is this tuple already taken? (not by us)*/
diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h
index b13d8d18d59..972e1e47ec7 100644
--- a/include/net/netfilter/nf_nat_core.h
+++ b/include/net/netfilter/nf_nat_core.h
@@ -12,10 +12,7 @@ extern unsigned int nf_nat_packet(struct nf_conn *ct,
12 unsigned int hooknum, 12 unsigned int hooknum,
13 struct sk_buff *skb); 13 struct sk_buff *skb);
14 14
15extern int nf_nat_icmp_reply_translation(struct nf_conn *ct, 15extern int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family);
16 enum ip_conntrack_info ctinfo,
17 unsigned int hooknum,
18 struct sk_buff *skb);
19 16
20static inline int nf_nat_initialized(struct nf_conn *ct, 17static inline int nf_nat_initialized(struct nf_conn *ct,
21 enum nf_nat_manip_type manip) 18 enum nf_nat_manip_type manip)
diff --git a/include/net/netfilter/nf_nat_l3proto.h b/include/net/netfilter/nf_nat_l3proto.h
new file mode 100644
index 00000000000..beed96961fa
--- /dev/null
+++ b/include/net/netfilter/nf_nat_l3proto.h
@@ -0,0 +1,47 @@
1#ifndef _NF_NAT_L3PROTO_H
2#define _NF_NAT_L3PROTO_H
3
4struct nf_nat_l4proto;
5struct nf_nat_l3proto {
6 u8 l3proto;
7
8 bool (*in_range)(const struct nf_conntrack_tuple *t,
9 const struct nf_nat_range *range);
10
11 u32 (*secure_port)(const struct nf_conntrack_tuple *t, __be16);
12
13 bool (*manip_pkt)(struct sk_buff *skb,
14 unsigned int iphdroff,
15 const struct nf_nat_l4proto *l4proto,
16 const struct nf_conntrack_tuple *target,
17 enum nf_nat_manip_type maniptype);
18
19 void (*csum_update)(struct sk_buff *skb, unsigned int iphdroff,
20 __sum16 *check,
21 const struct nf_conntrack_tuple *t,
22 enum nf_nat_manip_type maniptype);
23
24 void (*csum_recalc)(struct sk_buff *skb, u8 proto,
25 void *data, __sum16 *check,
26 int datalen, int oldlen);
27
28 void (*decode_session)(struct sk_buff *skb,
29 const struct nf_conn *ct,
30 enum ip_conntrack_dir dir,
31 unsigned long statusbit,
32 struct flowi *fl);
33
34 int (*nlattr_to_range)(struct nlattr *tb[],
35 struct nf_nat_range *range);
36};
37
38extern int nf_nat_l3proto_register(const struct nf_nat_l3proto *);
39extern void nf_nat_l3proto_unregister(const struct nf_nat_l3proto *);
40extern const struct nf_nat_l3proto *__nf_nat_l3proto_find(u8 l3proto);
41
42extern int nf_nat_icmp_reply_translation(struct sk_buff *skb,
43 struct nf_conn *ct,
44 enum ip_conntrack_info ctinfo,
45 unsigned int hooknum);
46
47#endif /* _NF_NAT_L3PROTO_H */
diff --git a/include/net/netfilter/nf_nat_l4proto.h b/include/net/netfilter/nf_nat_l4proto.h
new file mode 100644
index 00000000000..1f0a4f018fc
--- /dev/null
+++ b/include/net/netfilter/nf_nat_l4proto.h
@@ -0,0 +1,71 @@
1/* Header for use in defining a given protocol. */
2#ifndef _NF_NAT_L4PROTO_H
3#define _NF_NAT_L4PROTO_H
4#include <net/netfilter/nf_nat.h>
5#include <linux/netfilter/nfnetlink_conntrack.h>
6
7struct nf_nat_range;
8struct nf_nat_l3proto;
9
10struct nf_nat_l4proto {
11 /* Protocol number. */
12 u8 l4proto;
13
14 /* Translate a packet to the target according to manip type.
15 * Return true if succeeded.
16 */
17 bool (*manip_pkt)(struct sk_buff *skb,
18 const struct nf_nat_l3proto *l3proto,
19 unsigned int iphdroff, unsigned int hdroff,
20 const struct nf_conntrack_tuple *tuple,
21 enum nf_nat_manip_type maniptype);
22
23 /* Is the manipable part of the tuple between min and max incl? */
24 bool (*in_range)(const struct nf_conntrack_tuple *tuple,
25 enum nf_nat_manip_type maniptype,
26 const union nf_conntrack_man_proto *min,
27 const union nf_conntrack_man_proto *max);
28
29 /* Alter the per-proto part of the tuple (depending on
30 * maniptype), to give a unique tuple in the given range if
31 * possible. Per-protocol part of tuple is initialized to the
32 * incoming packet.
33 */
34 void (*unique_tuple)(const struct nf_nat_l3proto *l3proto,
35 struct nf_conntrack_tuple *tuple,
36 const struct nf_nat_range *range,
37 enum nf_nat_manip_type maniptype,
38 const struct nf_conn *ct);
39
40 int (*nlattr_to_range)(struct nlattr *tb[],
41 struct nf_nat_range *range);
42};
43
44/* Protocol registration. */
45extern int nf_nat_l4proto_register(u8 l3proto, const struct nf_nat_l4proto *l4proto);
46extern void nf_nat_l4proto_unregister(u8 l3proto, const struct nf_nat_l4proto *l4proto);
47
48extern const struct nf_nat_l4proto *__nf_nat_l4proto_find(u8 l3proto, u8 l4proto);
49
50/* Built-in protocols. */
51extern const struct nf_nat_l4proto nf_nat_l4proto_tcp;
52extern const struct nf_nat_l4proto nf_nat_l4proto_udp;
53extern const struct nf_nat_l4proto nf_nat_l4proto_icmp;
54extern const struct nf_nat_l4proto nf_nat_l4proto_unknown;
55
56extern bool nf_nat_l4proto_in_range(const struct nf_conntrack_tuple *tuple,
57 enum nf_nat_manip_type maniptype,
58 const union nf_conntrack_man_proto *min,
59 const union nf_conntrack_man_proto *max);
60
61extern void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,
62 struct nf_conntrack_tuple *tuple,
63 const struct nf_nat_range *range,
64 enum nf_nat_manip_type maniptype,
65 const struct nf_conn *ct,
66 u16 *rover);
67
68extern int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[],
69 struct nf_nat_range *range);
70
71#endif /*_NF_NAT_L4PROTO_H*/
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
deleted file mode 100644
index 7b0b51165f7..00000000000
--- a/include/net/netfilter/nf_nat_protocol.h
+++ /dev/null
@@ -1,67 +0,0 @@
1/* Header for use in defining a given protocol. */
2#ifndef _NF_NAT_PROTOCOL_H
3#define _NF_NAT_PROTOCOL_H
4#include <net/netfilter/nf_nat.h>
5#include <linux/netfilter/nfnetlink_conntrack.h>
6
7struct nf_nat_ipv4_range;
8
9struct nf_nat_protocol {
10 /* Protocol number. */
11 unsigned int protonum;
12
13 /* Translate a packet to the target according to manip type.
14 Return true if succeeded. */
15 bool (*manip_pkt)(struct sk_buff *skb,
16 unsigned int iphdroff,
17 const struct nf_conntrack_tuple *tuple,
18 enum nf_nat_manip_type maniptype);
19
20 /* Is the manipable part of the tuple between min and max incl? */
21 bool (*in_range)(const struct nf_conntrack_tuple *tuple,
22 enum nf_nat_manip_type maniptype,
23 const union nf_conntrack_man_proto *min,
24 const union nf_conntrack_man_proto *max);
25
26 /* Alter the per-proto part of the tuple (depending on
27 maniptype), to give a unique tuple in the given range if
28 possible. Per-protocol part of tuple is initialized to the
29 incoming packet. */
30 void (*unique_tuple)(struct nf_conntrack_tuple *tuple,
31 const struct nf_nat_ipv4_range *range,
32 enum nf_nat_manip_type maniptype,
33 const struct nf_conn *ct);
34
35 int (*nlattr_to_range)(struct nlattr *tb[],
36 struct nf_nat_ipv4_range *range);
37};
38
39/* Protocol registration. */
40extern int nf_nat_protocol_register(const struct nf_nat_protocol *proto);
41extern void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto);
42
43/* Built-in protocols. */
44extern const struct nf_nat_protocol nf_nat_protocol_tcp;
45extern const struct nf_nat_protocol nf_nat_protocol_udp;
46extern const struct nf_nat_protocol nf_nat_protocol_icmp;
47extern const struct nf_nat_protocol nf_nat_unknown_protocol;
48
49extern int init_protocols(void) __init;
50extern void cleanup_protocols(void);
51extern const struct nf_nat_protocol *find_nat_proto(u_int16_t protonum);
52
53extern bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple,
54 enum nf_nat_manip_type maniptype,
55 const union nf_conntrack_man_proto *min,
56 const union nf_conntrack_man_proto *max);
57
58extern void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
59 const struct nf_nat_ipv4_range *range,
60 enum nf_nat_manip_type maniptype,
61 const struct nf_conn *ct,
62 u_int16_t *rover);
63
64extern int nf_nat_proto_nlattr_to_range(struct nlattr *tb[],
65 struct nf_nat_ipv4_range *range);
66
67#endif /*_NF_NAT_PROTO_H*/
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
deleted file mode 100644
index 2890bdc4cd9..00000000000
--- a/include/net/netfilter/nf_nat_rule.h
+++ /dev/null
@@ -1,15 +0,0 @@
1#ifndef _NF_NAT_RULE_H
2#define _NF_NAT_RULE_H
3#include <net/netfilter/nf_conntrack.h>
4#include <net/netfilter/nf_nat.h>
5#include <linux/netfilter_ipv4/ip_tables.h>
6
7extern int nf_nat_rule_init(void) __init;
8extern void nf_nat_rule_cleanup(void);
9extern int nf_nat_rule_find(struct sk_buff *skb,
10 unsigned int hooknum,
11 const struct net_device *in,
12 const struct net_device *out,
13 struct nf_conn *ct);
14
15#endif /* _NF_NAT_RULE_H */
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index 3aecdc7a84f..a1d83cc8bf8 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -83,6 +83,10 @@ struct netns_ct {
83 int sysctl_auto_assign_helper; 83 int sysctl_auto_assign_helper;
84 bool auto_assign_helper_warned; 84 bool auto_assign_helper_warned;
85 struct nf_ip_net nf_ct_proto; 85 struct nf_ip_net nf_ct_proto;
86#ifdef CONFIG_NF_NAT_NEEDED
87 struct hlist_head *nat_bysource;
88 unsigned int nat_htable_size;
89#endif
86#ifdef CONFIG_SYSCTL 90#ifdef CONFIG_SYSCTL
87 struct ctl_table_header *sysctl_header; 91 struct ctl_table_header *sysctl_header;
88 struct ctl_table_header *acct_sysctl_header; 92 struct ctl_table_header *acct_sysctl_header;
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 1474dd65c66..ace280d19a2 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -51,8 +51,6 @@ struct netns_ipv4 {
51 struct xt_table *iptable_security; 51 struct xt_table *iptable_security;
52#endif 52#endif
53 struct xt_table *nat_table; 53 struct xt_table *nat_table;
54 struct hlist_head *nat_bysource;
55 unsigned int nat_htable_size;
56#endif 54#endif
57 55
58 int sysctl_icmp_echo_ignore_all; 56 int sysctl_icmp_echo_ignore_all;
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index ed1b3678319..f1643c0c358 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -72,43 +72,6 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
72} 72}
73EXPORT_SYMBOL(ip_route_me_harder); 73EXPORT_SYMBOL(ip_route_me_harder);
74 74
75#ifdef CONFIG_XFRM
76int ip_xfrm_me_harder(struct sk_buff *skb)
77{
78 struct flowi fl;
79 unsigned int hh_len;
80 struct dst_entry *dst;
81
82 if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
83 return 0;
84 if (xfrm_decode_session(skb, &fl, AF_INET) < 0)
85 return -1;
86
87 dst = skb_dst(skb);
88 if (dst->xfrm)
89 dst = ((struct xfrm_dst *)dst)->route;
90 dst_hold(dst);
91
92 dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
93 if (IS_ERR(dst))
94 return -1;
95
96 skb_dst_drop(skb);
97 skb_dst_set(skb, dst);
98
99 /* Change in oif may mean change in hh_len. */
100 hh_len = skb_dst(skb)->dev->hard_header_len;
101 if (skb_headroom(skb) < hh_len &&
102 pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
103 return -1;
104 return 0;
105}
106EXPORT_SYMBOL(ip_xfrm_me_harder);
107#endif
108
109void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
110EXPORT_SYMBOL(ip_nat_decode_session);
111
112/* 75/*
113 * Extra routing may needed on local out, as the QUEUE target never 76 * Extra routing may needed on local out, as the QUEUE target never
114 * returns control to the table. 77 * returns control to the table.
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index fcc543cd987..b26629681bd 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -143,25 +143,22 @@ config IP_NF_TARGET_ULOG
143 To compile it as a module, choose M here. If unsure, say N. 143 To compile it as a module, choose M here. If unsure, say N.
144 144
145# NAT + specific targets: nf_conntrack 145# NAT + specific targets: nf_conntrack
146config NF_NAT 146config NF_NAT_IPV4
147 tristate "Full NAT" 147 tristate "IPv4 NAT"
148 depends on NF_CONNTRACK_IPV4 148 depends on NF_CONNTRACK_IPV4
149 default m if NETFILTER_ADVANCED=n 149 default m if NETFILTER_ADVANCED=n
150 select NF_NAT
150 help 151 help
151 The Full NAT option allows masquerading, port forwarding and other 152 The IPv4 NAT option allows masquerading, port forwarding and other
152 forms of full Network Address Port Translation. It is controlled by 153 forms of full Network Address Port Translation. It is controlled by
153 the `nat' table in iptables: see the man page for iptables(8). 154 the `nat' table in iptables: see the man page for iptables(8).
154 155
155 To compile it as a module, choose M here. If unsure, say N. 156 To compile it as a module, choose M here. If unsure, say N.
156 157
157config NF_NAT_NEEDED 158if NF_NAT_IPV4
158 bool
159 depends on NF_NAT
160 default y
161 159
162config IP_NF_TARGET_MASQUERADE 160config IP_NF_TARGET_MASQUERADE
163 tristate "MASQUERADE target support" 161 tristate "MASQUERADE target support"
164 depends on NF_NAT
165 default m if NETFILTER_ADVANCED=n 162 default m if NETFILTER_ADVANCED=n
166 help 163 help
167 Masquerading is a special case of NAT: all outgoing connections are 164 Masquerading is a special case of NAT: all outgoing connections are
@@ -174,7 +171,6 @@ config IP_NF_TARGET_MASQUERADE
174 171
175config IP_NF_TARGET_NETMAP 172config IP_NF_TARGET_NETMAP
176 tristate "NETMAP target support" 173 tristate "NETMAP target support"
177 depends on NF_NAT
178 depends on NETFILTER_ADVANCED 174 depends on NETFILTER_ADVANCED
179 help 175 help
180 NETMAP is an implementation of static 1:1 NAT mapping of network 176 NETMAP is an implementation of static 1:1 NAT mapping of network
@@ -185,7 +181,6 @@ config IP_NF_TARGET_NETMAP
185 181
186config IP_NF_TARGET_REDIRECT 182config IP_NF_TARGET_REDIRECT
187 tristate "REDIRECT target support" 183 tristate "REDIRECT target support"
188 depends on NF_NAT
189 depends on NETFILTER_ADVANCED 184 depends on NETFILTER_ADVANCED
190 help 185 help
191 REDIRECT is a special case of NAT: all incoming connections are 186 REDIRECT is a special case of NAT: all incoming connections are
@@ -195,9 +190,11 @@ config IP_NF_TARGET_REDIRECT
195 190
196 To compile it as a module, choose M here. If unsure, say N. 191 To compile it as a module, choose M here. If unsure, say N.
197 192
193endif
194
198config NF_NAT_SNMP_BASIC 195config NF_NAT_SNMP_BASIC
199 tristate "Basic SNMP-ALG support" 196 tristate "Basic SNMP-ALG support"
200 depends on NF_CONNTRACK_SNMP && NF_NAT 197 depends on NF_CONNTRACK_SNMP && NF_NAT_IPV4
201 depends on NETFILTER_ADVANCED 198 depends on NETFILTER_ADVANCED
202 default NF_NAT && NF_CONNTRACK_SNMP 199 default NF_NAT && NF_CONNTRACK_SNMP
203 ---help--- 200 ---help---
@@ -219,61 +216,46 @@ config NF_NAT_SNMP_BASIC
219# <expr> '&&' <expr> (6) 216# <expr> '&&' <expr> (6)
220# 217#
221# (6) Returns the result of min(/expr/, /expr/). 218# (6) Returns the result of min(/expr/, /expr/).
222config NF_NAT_PROTO_DCCP
223 tristate
224 depends on NF_NAT && NF_CT_PROTO_DCCP
225 default NF_NAT && NF_CT_PROTO_DCCP
226 219
227config NF_NAT_PROTO_GRE 220config NF_NAT_PROTO_GRE
228 tristate 221 tristate
229 depends on NF_NAT && NF_CT_PROTO_GRE 222 depends on NF_NAT_IPV4 && NF_CT_PROTO_GRE
230
231config NF_NAT_PROTO_UDPLITE
232 tristate
233 depends on NF_NAT && NF_CT_PROTO_UDPLITE
234 default NF_NAT && NF_CT_PROTO_UDPLITE
235
236config NF_NAT_PROTO_SCTP
237 tristate
238 default NF_NAT && NF_CT_PROTO_SCTP
239 depends on NF_NAT && NF_CT_PROTO_SCTP
240 select LIBCRC32C
241 223
242config NF_NAT_FTP 224config NF_NAT_FTP
243 tristate 225 tristate
244 depends on NF_CONNTRACK && NF_NAT 226 depends on NF_CONNTRACK && NF_NAT_IPV4
245 default NF_NAT && NF_CONNTRACK_FTP 227 default NF_NAT_IPV4 && NF_CONNTRACK_FTP
246 228
247config NF_NAT_IRC 229config NF_NAT_IRC
248 tristate 230 tristate
249 depends on NF_CONNTRACK && NF_NAT 231 depends on NF_CONNTRACK && NF_NAT_IPV4
250 default NF_NAT && NF_CONNTRACK_IRC 232 default NF_NAT_IPV4 && NF_CONNTRACK_IRC
251 233
252config NF_NAT_TFTP 234config NF_NAT_TFTP
253 tristate 235 tristate
254 depends on NF_CONNTRACK && NF_NAT 236 depends on NF_CONNTRACK && NF_NAT_IPV4
255 default NF_NAT && NF_CONNTRACK_TFTP 237 default NF_NAT_IPV4 && NF_CONNTRACK_TFTP
256 238
257config NF_NAT_AMANDA 239config NF_NAT_AMANDA
258 tristate 240 tristate
259 depends on NF_CONNTRACK && NF_NAT 241 depends on NF_CONNTRACK && NF_NAT_IPV4
260 default NF_NAT && NF_CONNTRACK_AMANDA 242 default NF_NAT_IPV4 && NF_CONNTRACK_AMANDA
261 243
262config NF_NAT_PPTP 244config NF_NAT_PPTP
263 tristate 245 tristate
264 depends on NF_CONNTRACK && NF_NAT 246 depends on NF_CONNTRACK && NF_NAT_IPV4
265 default NF_NAT && NF_CONNTRACK_PPTP 247 default NF_NAT_IPV4 && NF_CONNTRACK_PPTP
266 select NF_NAT_PROTO_GRE 248 select NF_NAT_PROTO_GRE
267 249
268config NF_NAT_H323 250config NF_NAT_H323
269 tristate 251 tristate
270 depends on NF_CONNTRACK && NF_NAT 252 depends on NF_CONNTRACK && NF_NAT_IPV4
271 default NF_NAT && NF_CONNTRACK_H323 253 default NF_NAT_IPV4 && NF_CONNTRACK_H323
272 254
273config NF_NAT_SIP 255config NF_NAT_SIP
274 tristate 256 tristate
275 depends on NF_CONNTRACK && NF_NAT 257 depends on NF_CONNTRACK && NF_NAT_IPV4
276 default NF_NAT && NF_CONNTRACK_SIP 258 default NF_NAT_IPV4 && NF_CONNTRACK_SIP
277 259
278# mangle + specific targets 260# mangle + specific targets
279config IP_NF_MANGLE 261config IP_NF_MANGLE
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index c20674dc945..0ea3acc510e 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -10,13 +10,11 @@ nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o
10endif 10endif
11endif 11endif
12 12
13nf_nat-y := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_common.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
14iptable_nat-y := nf_nat_rule.o nf_nat_standalone.o
15
16# connection tracking 13# connection tracking
17obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o 14obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
18 15
19obj-$(CONFIG_NF_NAT) += nf_nat.o 16nf_nat_ipv4-y := nf_nat_l3proto_ipv4.o nf_nat_proto_icmp.o
17obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o
20 18
21# defrag 19# defrag
22obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o 20obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
@@ -32,10 +30,7 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
32obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o 30obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
33 31
34# NAT protocols (nf_nat) 32# NAT protocols (nf_nat)
35obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
36obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 33obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
37obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
38obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
39 34
40# generic IP tables 35# generic IP tables
41obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o 36obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
@@ -43,7 +38,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
43# the three instances of ip_tables 38# the three instances of ip_tables
44obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o 39obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
45obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o 40obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
46obj-$(CONFIG_NF_NAT) += iptable_nat.o 41obj-$(CONFIG_NF_NAT_IPV4) += iptable_nat.o
47obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o 42obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
48obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o 43obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
49 44
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index cbb6a1a6f6f..1c3aa28b51a 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -19,9 +19,9 @@
19#include <net/ip.h> 19#include <net/ip.h>
20#include <net/checksum.h> 20#include <net/checksum.h>
21#include <net/route.h> 21#include <net/route.h>
22#include <net/netfilter/nf_nat_rule.h>
23#include <linux/netfilter_ipv4.h> 22#include <linux/netfilter_ipv4.h>
24#include <linux/netfilter/x_tables.h> 23#include <linux/netfilter/x_tables.h>
24#include <net/netfilter/nf_nat.h>
25 25
26MODULE_LICENSE("GPL"); 26MODULE_LICENSE("GPL");
27MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 27MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -49,7 +49,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
49 struct nf_conn *ct; 49 struct nf_conn *ct;
50 struct nf_conn_nat *nat; 50 struct nf_conn_nat *nat;
51 enum ip_conntrack_info ctinfo; 51 enum ip_conntrack_info ctinfo;
52 struct nf_nat_ipv4_range newrange; 52 struct nf_nat_range newrange;
53 const struct nf_nat_ipv4_multi_range_compat *mr; 53 const struct nf_nat_ipv4_multi_range_compat *mr;
54 const struct rtable *rt; 54 const struct rtable *rt;
55 __be32 newsrc, nh; 55 __be32 newsrc, nh;
@@ -80,10 +80,13 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
80 nat->masq_index = par->out->ifindex; 80 nat->masq_index = par->out->ifindex;
81 81
82 /* Transfer from original range. */ 82 /* Transfer from original range. */
83 newrange = ((struct nf_nat_ipv4_range) 83 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
84 { mr->range[0].flags | NF_NAT_RANGE_MAP_IPS, 84 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
85 newsrc, newsrc, 85 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
86 mr->range[0].min, mr->range[0].max }); 86 newrange.min_addr.ip = newsrc;
87 newrange.max_addr.ip = newsrc;
88 newrange.min_proto = mr->range[0].min;
89 newrange.max_proto = mr->range[0].max;
87 90
88 /* Hand modified range to generic setup. */ 91 /* Hand modified range to generic setup. */
89 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); 92 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index b5bfbbabf70..85028dc0425 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -16,7 +16,7 @@
16#include <linux/netfilter.h> 16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv4.h> 17#include <linux/netfilter_ipv4.h>
18#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter/x_tables.h>
19#include <net/netfilter/nf_nat_rule.h> 19#include <net/netfilter/nf_nat.h>
20 20
21MODULE_LICENSE("GPL"); 21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>"); 22MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
@@ -44,7 +44,7 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
44 enum ip_conntrack_info ctinfo; 44 enum ip_conntrack_info ctinfo;
45 __be32 new_ip, netmask; 45 __be32 new_ip, netmask;
46 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 46 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
47 struct nf_nat_ipv4_range newrange; 47 struct nf_nat_range newrange;
48 48
49 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 49 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
50 par->hooknum == NF_INET_POST_ROUTING || 50 par->hooknum == NF_INET_POST_ROUTING ||
@@ -61,10 +61,13 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
61 new_ip = ip_hdr(skb)->saddr & ~netmask; 61 new_ip = ip_hdr(skb)->saddr & ~netmask;
62 new_ip |= mr->range[0].min_ip & netmask; 62 new_ip |= mr->range[0].min_ip & netmask;
63 63
64 newrange = ((struct nf_nat_ipv4_range) 64 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
65 { mr->range[0].flags | NF_NAT_RANGE_MAP_IPS, 65 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
66 new_ip, new_ip, 66 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
67 mr->range[0].min, mr->range[0].max }); 67 newrange.min_addr.ip = new_ip;
68 newrange.max_addr.ip = new_ip;
69 newrange.min_proto = mr->range[0].min;
70 newrange.max_proto = mr->range[0].max;
68 71
69 /* Hand modified range to generic setup. */ 72 /* Hand modified range to generic setup. */
70 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); 73 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 7c0103a5203..11407d7d247 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -19,7 +19,7 @@
19#include <net/checksum.h> 19#include <net/checksum.h>
20#include <linux/netfilter_ipv4.h> 20#include <linux/netfilter_ipv4.h>
21#include <linux/netfilter/x_tables.h> 21#include <linux/netfilter/x_tables.h>
22#include <net/netfilter/nf_nat_rule.h> 22#include <net/netfilter/nf_nat.h>
23 23
24MODULE_LICENSE("GPL"); 24MODULE_LICENSE("GPL");
25MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 25MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -48,7 +48,7 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
48 enum ip_conntrack_info ctinfo; 48 enum ip_conntrack_info ctinfo;
49 __be32 newdst; 49 __be32 newdst;
50 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 50 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
51 struct nf_nat_ipv4_range newrange; 51 struct nf_nat_range newrange;
52 52
53 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 53 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
54 par->hooknum == NF_INET_LOCAL_OUT); 54 par->hooknum == NF_INET_LOCAL_OUT);
@@ -76,10 +76,13 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
76 } 76 }
77 77
78 /* Transfer from original range. */ 78 /* Transfer from original range. */
79 newrange = ((struct nf_nat_ipv4_range) 79 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
80 { mr->range[0].flags | NF_NAT_RANGE_MAP_IPS, 80 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
81 newdst, newdst, 81 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
82 mr->range[0].min, mr->range[0].max }); 82 newrange.min_addr.ip = newdst;
83 newrange.max_addr.ip = newdst;
84 newrange.min_proto = mr->range[0].min;
85 newrange.max_proto = mr->range[0].max;
83 86
84 /* Hand modified range to generic setup. */ 87 /* Hand modified range to generic setup. */
85 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); 88 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/iptable_nat.c
index 3828a422982..9e0ffaf1d94 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -1,84 +1,71 @@
1/* (C) 1999-2001 Paul `Rusty' Russell 1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2011 Patrick McHardy <kaber@trash.net>
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 6 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
7 */ 8 */
8#include <linux/types.h> 9
9#include <linux/icmp.h> 10#include <linux/module.h>
10#include <linux/gfp.h>
11#include <linux/ip.h>
12#include <linux/netfilter.h> 11#include <linux/netfilter.h>
13#include <linux/netfilter_ipv4.h> 12#include <linux/netfilter_ipv4.h>
14#include <linux/module.h> 13#include <linux/netfilter_ipv4/ip_tables.h>
15#include <linux/skbuff.h> 14#include <linux/ip.h>
16#include <linux/proc_fs.h>
17#include <net/ip.h> 15#include <net/ip.h>
18#include <net/checksum.h>
19#include <linux/spinlock.h>
20 16
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_conntrack_core.h>
23#include <net/netfilter/nf_conntrack_extend.h>
24#include <net/netfilter/nf_nat.h> 17#include <net/netfilter/nf_nat.h>
25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_nat_protocol.h>
27#include <net/netfilter/nf_nat_core.h> 18#include <net/netfilter/nf_nat_core.h>
28#include <net/netfilter/nf_nat_helper.h> 19#include <net/netfilter/nf_nat_l3proto.h>
29#include <linux/netfilter_ipv4/ip_tables.h> 20
21static const struct xt_table nf_nat_ipv4_table = {
22 .name = "nat",
23 .valid_hooks = (1 << NF_INET_PRE_ROUTING) |
24 (1 << NF_INET_POST_ROUTING) |
25 (1 << NF_INET_LOCAL_OUT) |
26 (1 << NF_INET_LOCAL_IN),
27 .me = THIS_MODULE,
28 .af = NFPROTO_IPV4,
29};
30 30
31#ifdef CONFIG_XFRM 31static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
32static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
33{ 32{
34 struct flowi4 *fl4 = &fl->u.ip4; 33 /* Force range to this IP; let proto decide mapping for
35 const struct nf_conn *ct; 34 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
36 const struct nf_conntrack_tuple *t; 35 */
37 enum ip_conntrack_info ctinfo; 36 struct nf_nat_range range;
38 enum ip_conntrack_dir dir; 37
39 unsigned long statusbit; 38 range.flags = 0;
40 39 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
41 ct = nf_ct_get(skb, &ctinfo); 40 HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
42 if (ct == NULL) 41 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
43 return; 42 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
44 dir = CTINFO2DIR(ctinfo); 43
45 t = &ct->tuplehash[dir].tuple; 44 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
46 45}
47 if (dir == IP_CT_DIR_ORIGINAL)
48 statusbit = IPS_DST_NAT;
49 else
50 statusbit = IPS_SRC_NAT;
51
52 if (ct->status & statusbit) {
53 fl4->daddr = t->dst.u3.ip;
54 if (t->dst.protonum == IPPROTO_TCP ||
55 t->dst.protonum == IPPROTO_UDP ||
56 t->dst.protonum == IPPROTO_UDPLITE ||
57 t->dst.protonum == IPPROTO_DCCP ||
58 t->dst.protonum == IPPROTO_SCTP)
59 fl4->fl4_dport = t->dst.u.tcp.port;
60 }
61 46
62 statusbit ^= IPS_NAT_MASK; 47static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
48 const struct net_device *in,
49 const struct net_device *out,
50 struct nf_conn *ct)
51{
52 struct net *net = nf_ct_net(ct);
53 unsigned int ret;
63 54
64 if (ct->status & statusbit) { 55 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
65 fl4->saddr = t->src.u3.ip; 56 if (ret == NF_ACCEPT) {
66 if (t->dst.protonum == IPPROTO_TCP || 57 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
67 t->dst.protonum == IPPROTO_UDP || 58 ret = alloc_null_binding(ct, hooknum);
68 t->dst.protonum == IPPROTO_UDPLITE ||
69 t->dst.protonum == IPPROTO_DCCP ||
70 t->dst.protonum == IPPROTO_SCTP)
71 fl4->fl4_sport = t->src.u.tcp.port;
72 } 59 }
60 return ret;
73} 61}
74#endif
75 62
76static unsigned int 63static unsigned int
77nf_nat_fn(unsigned int hooknum, 64nf_nat_ipv4_fn(unsigned int hooknum,
78 struct sk_buff *skb, 65 struct sk_buff *skb,
79 const struct net_device *in, 66 const struct net_device *in,
80 const struct net_device *out, 67 const struct net_device *out,
81 int (*okfn)(struct sk_buff *)) 68 int (*okfn)(struct sk_buff *))
82{ 69{
83 struct nf_conn *ct; 70 struct nf_conn *ct;
84 enum ip_conntrack_info ctinfo; 71 enum ip_conntrack_info ctinfo;
@@ -87,14 +74,16 @@ nf_nat_fn(unsigned int hooknum,
87 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 74 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
88 75
89 /* We never see fragments: conntrack defrags on pre-routing 76 /* We never see fragments: conntrack defrags on pre-routing
90 and local-out, and nf_nat_out protects post-routing. */ 77 * and local-out, and nf_nat_out protects post-routing.
78 */
91 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb))); 79 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb)));
92 80
93 ct = nf_ct_get(skb, &ctinfo); 81 ct = nf_ct_get(skb, &ctinfo);
94 /* Can't track? It's not due to stress, or conntrack would 82 /* Can't track? It's not due to stress, or conntrack would
95 have dropped it. Hence it's the user's responsibilty to 83 * have dropped it. Hence it's the user's responsibilty to
96 packet filter it out, or implement conntrack/NAT for that 84 * packet filter it out, or implement conntrack/NAT for that
97 protocol. 8) --RR */ 85 * protocol. 8) --RR
86 */
98 if (!ct) 87 if (!ct)
99 return NF_ACCEPT; 88 return NF_ACCEPT;
100 89
@@ -118,17 +107,17 @@ nf_nat_fn(unsigned int hooknum,
118 case IP_CT_RELATED: 107 case IP_CT_RELATED:
119 case IP_CT_RELATED_REPLY: 108 case IP_CT_RELATED_REPLY:
120 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 109 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
121 if (!nf_nat_icmp_reply_translation(ct, ctinfo, 110 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
122 hooknum, skb)) 111 hooknum))
123 return NF_DROP; 112 return NF_DROP;
124 else 113 else
125 return NF_ACCEPT; 114 return NF_ACCEPT;
126 } 115 }
127 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 116 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
128 case IP_CT_NEW: 117 case IP_CT_NEW:
129
130 /* Seen it before? This can happen for loopback, retrans, 118 /* Seen it before? This can happen for loopback, retrans,
131 or local packets.. */ 119 * or local packets.
120 */
132 if (!nf_nat_initialized(ct, maniptype)) { 121 if (!nf_nat_initialized(ct, maniptype)) {
133 unsigned int ret; 122 unsigned int ret;
134 123
@@ -151,16 +140,16 @@ nf_nat_fn(unsigned int hooknum,
151} 140}
152 141
153static unsigned int 142static unsigned int
154nf_nat_in(unsigned int hooknum, 143nf_nat_ipv4_in(unsigned int hooknum,
155 struct sk_buff *skb, 144 struct sk_buff *skb,
156 const struct net_device *in, 145 const struct net_device *in,
157 const struct net_device *out, 146 const struct net_device *out,
158 int (*okfn)(struct sk_buff *)) 147 int (*okfn)(struct sk_buff *))
159{ 148{
160 unsigned int ret; 149 unsigned int ret;
161 __be32 daddr = ip_hdr(skb)->daddr; 150 __be32 daddr = ip_hdr(skb)->daddr;
162 151
163 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 152 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn);
164 if (ret != NF_DROP && ret != NF_STOLEN && 153 if (ret != NF_DROP && ret != NF_STOLEN &&
165 daddr != ip_hdr(skb)->daddr) 154 daddr != ip_hdr(skb)->daddr)
166 skb_dst_drop(skb); 155 skb_dst_drop(skb);
@@ -169,11 +158,11 @@ nf_nat_in(unsigned int hooknum,
169} 158}
170 159
171static unsigned int 160static unsigned int
172nf_nat_out(unsigned int hooknum, 161nf_nat_ipv4_out(unsigned int hooknum,
173 struct sk_buff *skb, 162 struct sk_buff *skb,
174 const struct net_device *in, 163 const struct net_device *in,
175 const struct net_device *out, 164 const struct net_device *out,
176 int (*okfn)(struct sk_buff *)) 165 int (*okfn)(struct sk_buff *))
177{ 166{
178#ifdef CONFIG_XFRM 167#ifdef CONFIG_XFRM
179 const struct nf_conn *ct; 168 const struct nf_conn *ct;
@@ -186,29 +175,30 @@ nf_nat_out(unsigned int hooknum,
186 ip_hdrlen(skb) < sizeof(struct iphdr)) 175 ip_hdrlen(skb) < sizeof(struct iphdr))
187 return NF_ACCEPT; 176 return NF_ACCEPT;
188 177
189 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 178 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn);
190#ifdef CONFIG_XFRM 179#ifdef CONFIG_XFRM
191 if (ret != NF_DROP && ret != NF_STOLEN && 180 if (ret != NF_DROP && ret != NF_STOLEN &&
181 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
192 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 182 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
193 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 183 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
194 184
195 if ((ct->tuplehash[dir].tuple.src.u3.ip != 185 if ((ct->tuplehash[dir].tuple.src.u3.ip !=
196 ct->tuplehash[!dir].tuple.dst.u3.ip) || 186 ct->tuplehash[!dir].tuple.dst.u3.ip) ||
197 (ct->tuplehash[dir].tuple.src.u.all != 187 (ct->tuplehash[dir].tuple.src.u.all !=
198 ct->tuplehash[!dir].tuple.dst.u.all) 188 ct->tuplehash[!dir].tuple.dst.u.all))
199 ) 189 if (nf_xfrm_me_harder(skb, AF_INET) < 0)
200 return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP; 190 ret = NF_DROP;
201 } 191 }
202#endif 192#endif
203 return ret; 193 return ret;
204} 194}
205 195
206static unsigned int 196static unsigned int
207nf_nat_local_fn(unsigned int hooknum, 197nf_nat_ipv4_local_fn(unsigned int hooknum,
208 struct sk_buff *skb, 198 struct sk_buff *skb,
209 const struct net_device *in, 199 const struct net_device *in,
210 const struct net_device *out, 200 const struct net_device *out,
211 int (*okfn)(struct sk_buff *)) 201 int (*okfn)(struct sk_buff *))
212{ 202{
213 const struct nf_conn *ct; 203 const struct nf_conn *ct;
214 enum ip_conntrack_info ctinfo; 204 enum ip_conntrack_info ctinfo;
@@ -219,7 +209,7 @@ nf_nat_local_fn(unsigned int hooknum,
219 ip_hdrlen(skb) < sizeof(struct iphdr)) 209 ip_hdrlen(skb) < sizeof(struct iphdr))
220 return NF_ACCEPT; 210 return NF_ACCEPT;
221 211
222 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 212 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn);
223 if (ret != NF_DROP && ret != NF_STOLEN && 213 if (ret != NF_DROP && ret != NF_STOLEN &&
224 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 214 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
225 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 215 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -230,21 +220,20 @@ nf_nat_local_fn(unsigned int hooknum,
230 ret = NF_DROP; 220 ret = NF_DROP;
231 } 221 }
232#ifdef CONFIG_XFRM 222#ifdef CONFIG_XFRM
233 else if (ct->tuplehash[dir].tuple.dst.u.all != 223 else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
224 ct->tuplehash[dir].tuple.dst.u.all !=
234 ct->tuplehash[!dir].tuple.src.u.all) 225 ct->tuplehash[!dir].tuple.src.u.all)
235 if (ip_xfrm_me_harder(skb)) 226 if (nf_xfrm_me_harder(skb, AF_INET) < 0)
236 ret = NF_DROP; 227 ret = NF_DROP;
237#endif 228#endif
238 } 229 }
239 return ret; 230 return ret;
240} 231}
241 232
242/* We must be after connection tracking and before packet filtering. */ 233static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
243
244static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
245 /* Before packet filtering, change destination */ 234 /* Before packet filtering, change destination */
246 { 235 {
247 .hook = nf_nat_in, 236 .hook = nf_nat_ipv4_in,
248 .owner = THIS_MODULE, 237 .owner = THIS_MODULE,
249 .pf = NFPROTO_IPV4, 238 .pf = NFPROTO_IPV4,
250 .hooknum = NF_INET_PRE_ROUTING, 239 .hooknum = NF_INET_PRE_ROUTING,
@@ -252,7 +241,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
252 }, 241 },
253 /* After packet filtering, change source */ 242 /* After packet filtering, change source */
254 { 243 {
255 .hook = nf_nat_out, 244 .hook = nf_nat_ipv4_out,
256 .owner = THIS_MODULE, 245 .owner = THIS_MODULE,
257 .pf = NFPROTO_IPV4, 246 .pf = NFPROTO_IPV4,
258 .hooknum = NF_INET_POST_ROUTING, 247 .hooknum = NF_INET_POST_ROUTING,
@@ -260,7 +249,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
260 }, 249 },
261 /* Before packet filtering, change destination */ 250 /* Before packet filtering, change destination */
262 { 251 {
263 .hook = nf_nat_local_fn, 252 .hook = nf_nat_ipv4_local_fn,
264 .owner = THIS_MODULE, 253 .owner = THIS_MODULE,
265 .pf = NFPROTO_IPV4, 254 .pf = NFPROTO_IPV4,
266 .hooknum = NF_INET_LOCAL_OUT, 255 .hooknum = NF_INET_LOCAL_OUT,
@@ -268,7 +257,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
268 }, 257 },
269 /* After packet filtering, change source */ 258 /* After packet filtering, change source */
270 { 259 {
271 .hook = nf_nat_fn, 260 .hook = nf_nat_ipv4_fn,
272 .owner = THIS_MODULE, 261 .owner = THIS_MODULE,
273 .pf = NFPROTO_IPV4, 262 .pf = NFPROTO_IPV4,
274 .hooknum = NF_INET_LOCAL_IN, 263 .hooknum = NF_INET_LOCAL_IN,
@@ -276,51 +265,56 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
276 }, 265 },
277}; 266};
278 267
279static int __init nf_nat_standalone_init(void) 268static int __net_init iptable_nat_net_init(struct net *net)
280{ 269{
281 int ret = 0; 270 struct ipt_replace *repl;
271
272 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
273 if (repl == NULL)
274 return -ENOMEM;
275 net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
276 kfree(repl);
277 if (IS_ERR(net->ipv4.nat_table))
278 return PTR_ERR(net->ipv4.nat_table);
279 return 0;
280}
282 281
283 need_ipv4_conntrack(); 282static void __net_exit iptable_nat_net_exit(struct net *net)
283{
284 ipt_unregister_table(net, net->ipv4.nat_table);
285}
284 286
285#ifdef CONFIG_XFRM 287static struct pernet_operations iptable_nat_net_ops = {
286 BUG_ON(ip_nat_decode_session != NULL); 288 .init = iptable_nat_net_init,
287 RCU_INIT_POINTER(ip_nat_decode_session, nat_decode_session); 289 .exit = iptable_nat_net_exit,
288#endif 290};
289 ret = nf_nat_rule_init();
290 if (ret < 0) {
291 pr_err("nf_nat_init: can't setup rules.\n");
292 goto cleanup_decode_session;
293 }
294 ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
295 if (ret < 0) {
296 pr_err("nf_nat_init: can't register hooks.\n");
297 goto cleanup_rule_init;
298 }
299 return ret;
300 291
301 cleanup_rule_init: 292static int __init iptable_nat_init(void)
302 nf_nat_rule_cleanup(); 293{
303 cleanup_decode_session: 294 int err;
304#ifdef CONFIG_XFRM 295
305 RCU_INIT_POINTER(ip_nat_decode_session, NULL); 296 err = register_pernet_subsys(&iptable_nat_net_ops);
306 synchronize_net(); 297 if (err < 0)
307#endif 298 goto err1;
308 return ret; 299
300 err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
301 if (err < 0)
302 goto err2;
303 return 0;
304
305err2:
306 unregister_pernet_subsys(&iptable_nat_net_ops);
307err1:
308 return err;
309} 309}
310 310
311static void __exit nf_nat_standalone_fini(void) 311static void __exit iptable_nat_exit(void)
312{ 312{
313 nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); 313 nf_unregister_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
314 nf_nat_rule_cleanup(); 314 unregister_pernet_subsys(&iptable_nat_net_ops);
315#ifdef CONFIG_XFRM
316 RCU_INIT_POINTER(ip_nat_decode_session, NULL);
317 synchronize_net();
318#endif
319 /* Conntrack caches are unregistered in nf_conntrack_cleanup */
320} 315}
321 316
322module_init(nf_nat_standalone_init); 317module_init(iptable_nat_init);
323module_exit(nf_nat_standalone_fini); 318module_exit(iptable_nat_exit);
324 319
325MODULE_LICENSE("GPL"); 320MODULE_LICENSE("GPL");
326MODULE_ALIAS("ip_nat");
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 4ada3295d9a..fcdd0c2406e 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -29,12 +29,6 @@
29#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 29#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
30#include <net/netfilter/nf_log.h> 30#include <net/netfilter/nf_log.h>
31 31
32int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
33 struct nf_conn *ct,
34 enum ip_conntrack_info ctinfo,
35 unsigned int protoff);
36EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
37
38static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, 32static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
39 struct nf_conntrack_tuple *tuple) 33 struct nf_conntrack_tuple *tuple)
40{ 34{
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
index 75464b62f5f..42d33788117 100644
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -16,7 +16,6 @@
16#include <net/netfilter/nf_conntrack_helper.h> 16#include <net/netfilter/nf_conntrack_helper.h>
17#include <net/netfilter/nf_conntrack_expect.h> 17#include <net/netfilter/nf_conntrack_expect.h>
18#include <net/netfilter/nf_nat_helper.h> 18#include <net/netfilter/nf_nat_helper.h>
19#include <net/netfilter/nf_nat_rule.h>
20#include <linux/netfilter/nf_conntrack_amanda.h> 19#include <linux/netfilter/nf_conntrack_amanda.h>
21 20
22MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); 21MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
index 5589f3af4a8..dd5e387fc03 100644
--- a/net/ipv4/netfilter/nf_nat_ftp.c
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -15,7 +15,6 @@
15#include <linux/netfilter_ipv4.h> 15#include <linux/netfilter_ipv4.h>
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.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> 18#include <net/netfilter/nf_conntrack_helper.h>
20#include <net/netfilter/nf_conntrack_expect.h> 19#include <net/netfilter/nf_conntrack_expect.h>
21#include <linux/netfilter/nf_conntrack_ftp.h> 20#include <linux/netfilter/nf_conntrack_ftp.h>
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index d2c228db38b..9c3db10b22d 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -15,7 +15,6 @@
15 15
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.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> 18#include <net/netfilter/nf_conntrack_helper.h>
20#include <net/netfilter/nf_conntrack_expect.h> 19#include <net/netfilter/nf_conntrack_expect.h>
21#include <linux/netfilter/nf_conntrack_h323.h> 20#include <linux/netfilter/nf_conntrack_h323.h>
@@ -392,7 +391,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
392static void ip_nat_q931_expect(struct nf_conn *new, 391static void ip_nat_q931_expect(struct nf_conn *new,
393 struct nf_conntrack_expect *this) 392 struct nf_conntrack_expect *this)
394{ 393{
395 struct nf_nat_ipv4_range range; 394 struct nf_nat_range range;
396 395
397 if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ 396 if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */
398 nf_nat_follow_master(new, this); 397 nf_nat_follow_master(new, this);
@@ -404,14 +403,15 @@ static void ip_nat_q931_expect(struct nf_conn *new,
404 403
405 /* Change src to where master sends to */ 404 /* Change src to where master sends to */
406 range.flags = NF_NAT_RANGE_MAP_IPS; 405 range.flags = NF_NAT_RANGE_MAP_IPS;
407 range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; 406 range.min_addr = range.max_addr =
407 new->tuplehash[!this->dir].tuple.src.u3;
408 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC); 408 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
409 409
410 /* For DST manip, map port here to where it's expected. */ 410 /* For DST manip, map port here to where it's expected. */
411 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 411 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
412 range.min = range.max = this->saved_proto; 412 range.min_proto = range.max_proto = this->saved_proto;
413 range.min_ip = range.max_ip = 413 range.min_addr = range.max_addr =
414 new->master->tuplehash[!this->dir].tuple.src.u3.ip; 414 new->master->tuplehash[!this->dir].tuple.src.u3;
415 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST); 415 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
416} 416}
417 417
@@ -490,20 +490,21 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
490static void ip_nat_callforwarding_expect(struct nf_conn *new, 490static void ip_nat_callforwarding_expect(struct nf_conn *new,
491 struct nf_conntrack_expect *this) 491 struct nf_conntrack_expect *this)
492{ 492{
493 struct nf_nat_ipv4_range range; 493 struct nf_nat_range range;
494 494
495 /* This must be a fresh one. */ 495 /* This must be a fresh one. */
496 BUG_ON(new->status & IPS_NAT_DONE_MASK); 496 BUG_ON(new->status & IPS_NAT_DONE_MASK);
497 497
498 /* Change src to where master sends to */ 498 /* Change src to where master sends to */
499 range.flags = NF_NAT_RANGE_MAP_IPS; 499 range.flags = NF_NAT_RANGE_MAP_IPS;
500 range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; 500 range.min_addr = range.max_addr =
501 new->tuplehash[!this->dir].tuple.src.u3;
501 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC); 502 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
502 503
503 /* For DST manip, map port here to where it's expected. */ 504 /* For DST manip, map port here to where it's expected. */
504 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 505 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
505 range.min = range.max = this->saved_proto; 506 range.min_proto = range.max_proto = this->saved_proto;
506 range.min_ip = range.max_ip = this->saved_ip; 507 range.min_addr = range.max_addr = this->saved_addr;
507 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST); 508 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
508} 509}
509 510
@@ -519,7 +520,7 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
519 u_int16_t nated_port; 520 u_int16_t nated_port;
520 521
521 /* Set expectations for NAT */ 522 /* Set expectations for NAT */
522 exp->saved_ip = exp->tuple.dst.u3.ip; 523 exp->saved_addr = exp->tuple.dst.u3;
523 exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; 524 exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
524 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; 525 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
525 exp->expectfn = ip_nat_callforwarding_expect; 526 exp->expectfn = ip_nat_callforwarding_expect;
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
index 5b0c20a1f08..1ce37f89ec7 100644
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -17,7 +17,6 @@
17 17
18#include <net/netfilter/nf_nat.h> 18#include <net/netfilter/nf_nat.h>
19#include <net/netfilter/nf_nat_helper.h> 19#include <net/netfilter/nf_nat_helper.h>
20#include <net/netfilter/nf_nat_rule.h>
21#include <net/netfilter/nf_conntrack_helper.h> 20#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h> 21#include <net/netfilter/nf_conntrack_expect.h>
23#include <linux/netfilter/nf_conntrack_irc.h> 22#include <linux/netfilter/nf_conntrack_irc.h>
diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
new file mode 100644
index 00000000000..d8b2e14efdd
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
@@ -0,0 +1,281 @@
1/*
2 * (C) 1999-2001 Paul `Rusty' Russell
3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4 * (C) 2011 Patrick McHardy <kaber@trash.net>
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/types.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/ip.h>
15#include <linux/icmp.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv4.h>
18#include <net/secure_seq.h>
19#include <net/checksum.h>
20#include <net/route.h>
21#include <net/ip.h>
22
23#include <net/netfilter/nf_conntrack_core.h>
24#include <net/netfilter/nf_conntrack.h>
25#include <net/netfilter/nf_nat_core.h>
26#include <net/netfilter/nf_nat_l3proto.h>
27#include <net/netfilter/nf_nat_l4proto.h>
28
29static const struct nf_nat_l3proto nf_nat_l3proto_ipv4;
30
31#ifdef CONFIG_XFRM
32static void nf_nat_ipv4_decode_session(struct sk_buff *skb,
33 const struct nf_conn *ct,
34 enum ip_conntrack_dir dir,
35 unsigned long statusbit,
36 struct flowi *fl)
37{
38 const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
39 struct flowi4 *fl4 = &fl->u.ip4;
40
41 if (ct->status & statusbit) {
42 fl4->daddr = t->dst.u3.ip;
43 if (t->dst.protonum == IPPROTO_TCP ||
44 t->dst.protonum == IPPROTO_UDP ||
45 t->dst.protonum == IPPROTO_UDPLITE ||
46 t->dst.protonum == IPPROTO_DCCP ||
47 t->dst.protonum == IPPROTO_SCTP)
48 fl4->fl4_dport = t->dst.u.all;
49 }
50
51 statusbit ^= IPS_NAT_MASK;
52
53 if (ct->status & statusbit) {
54 fl4->saddr = t->src.u3.ip;
55 if (t->dst.protonum == IPPROTO_TCP ||
56 t->dst.protonum == IPPROTO_UDP ||
57 t->dst.protonum == IPPROTO_UDPLITE ||
58 t->dst.protonum == IPPROTO_DCCP ||
59 t->dst.protonum == IPPROTO_SCTP)
60 fl4->fl4_sport = t->src.u.all;
61 }
62}
63#endif /* CONFIG_XFRM */
64
65static bool nf_nat_ipv4_in_range(const struct nf_conntrack_tuple *t,
66 const struct nf_nat_range *range)
67{
68 return ntohl(t->src.u3.ip) >= ntohl(range->min_addr.ip) &&
69 ntohl(t->src.u3.ip) <= ntohl(range->max_addr.ip);
70}
71
72static u32 nf_nat_ipv4_secure_port(const struct nf_conntrack_tuple *t,
73 __be16 dport)
74{
75 return secure_ipv4_port_ephemeral(t->src.u3.ip, t->dst.u3.ip, dport);
76}
77
78static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
79 unsigned int iphdroff,
80 const struct nf_nat_l4proto *l4proto,
81 const struct nf_conntrack_tuple *target,
82 enum nf_nat_manip_type maniptype)
83{
84 struct iphdr *iph;
85 unsigned int hdroff;
86
87 if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
88 return false;
89
90 iph = (void *)skb->data + iphdroff;
91 hdroff = iphdroff + iph->ihl * 4;
92
93 if (!l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv4, iphdroff, hdroff,
94 target, maniptype))
95 return false;
96 iph = (void *)skb->data + iphdroff;
97
98 if (maniptype == NF_NAT_MANIP_SRC) {
99 csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
100 iph->saddr = target->src.u3.ip;
101 } else {
102 csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
103 iph->daddr = target->dst.u3.ip;
104 }
105 return true;
106}
107
108static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
109 unsigned int iphdroff, __sum16 *check,
110 const struct nf_conntrack_tuple *t,
111 enum nf_nat_manip_type maniptype)
112{
113 struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
114 __be32 oldip, newip;
115
116 if (maniptype == NF_NAT_MANIP_SRC) {
117 oldip = iph->saddr;
118 newip = t->src.u3.ip;
119 } else {
120 oldip = iph->daddr;
121 newip = t->dst.u3.ip;
122 }
123 inet_proto_csum_replace4(check, skb, oldip, newip, 1);
124}
125
126static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
127 u8 proto, void *data, __sum16 *check,
128 int datalen, int oldlen)
129{
130 const struct iphdr *iph = ip_hdr(skb);
131 struct rtable *rt = skb_rtable(skb);
132
133 if (skb->ip_summed != CHECKSUM_PARTIAL) {
134 if (!(rt->rt_flags & RTCF_LOCAL) &&
135 (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
136 skb->ip_summed = CHECKSUM_PARTIAL;
137 skb->csum_start = skb_headroom(skb) +
138 skb_network_offset(skb) +
139 ip_hdrlen(skb);
140 skb->csum_offset = (void *)check - data;
141 *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
142 datalen, proto, 0);
143 } else {
144 *check = 0;
145 *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
146 datalen, proto,
147 csum_partial(data, datalen,
148 0));
149 if (proto == IPPROTO_UDP && !*check)
150 *check = CSUM_MANGLED_0;
151 }
152 } else
153 inet_proto_csum_replace2(check, skb,
154 htons(oldlen), htons(datalen), 1);
155}
156
157static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[],
158 struct nf_nat_range *range)
159{
160 if (tb[CTA_NAT_V4_MINIP]) {
161 range->min_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MINIP]);
162 range->flags |= NF_NAT_RANGE_MAP_IPS;
163 }
164
165 if (tb[CTA_NAT_V4_MAXIP])
166 range->max_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MAXIP]);
167 else
168 range->max_addr.ip = range->min_addr.ip;
169
170 return 0;
171}
172
173static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = {
174 .l3proto = NFPROTO_IPV4,
175 .in_range = nf_nat_ipv4_in_range,
176 .secure_port = nf_nat_ipv4_secure_port,
177 .manip_pkt = nf_nat_ipv4_manip_pkt,
178 .csum_update = nf_nat_ipv4_csum_update,
179 .csum_recalc = nf_nat_ipv4_csum_recalc,
180 .nlattr_to_range = nf_nat_ipv4_nlattr_to_range,
181#ifdef CONFIG_XFRM
182 .decode_session = nf_nat_ipv4_decode_session,
183#endif
184};
185
186int nf_nat_icmp_reply_translation(struct sk_buff *skb,
187 struct nf_conn *ct,
188 enum ip_conntrack_info ctinfo,
189 unsigned int hooknum)
190{
191 struct {
192 struct icmphdr icmp;
193 struct iphdr ip;
194 } *inside;
195 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
196 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
197 unsigned int hdrlen = ip_hdrlen(skb);
198 const struct nf_nat_l4proto *l4proto;
199 struct nf_conntrack_tuple target;
200 unsigned long statusbit;
201
202 NF_CT_ASSERT(ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY);
203
204 if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
205 return 0;
206 if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
207 return 0;
208
209 inside = (void *)skb->data + hdrlen;
210 if (inside->icmp.type == ICMP_REDIRECT) {
211 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
212 return 0;
213 if (ct->status & IPS_NAT_MASK)
214 return 0;
215 }
216
217 if (manip == NF_NAT_MANIP_SRC)
218 statusbit = IPS_SRC_NAT;
219 else
220 statusbit = IPS_DST_NAT;
221
222 /* Invert if this is reply direction */
223 if (dir == IP_CT_DIR_REPLY)
224 statusbit ^= IPS_NAT_MASK;
225
226 if (!(ct->status & statusbit))
227 return 1;
228
229 l4proto = __nf_nat_l4proto_find(NFPROTO_IPV4, inside->ip.protocol);
230 if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
231 l4proto, &ct->tuplehash[!dir].tuple, !manip))
232 return 0;
233
234 if (skb->ip_summed != CHECKSUM_PARTIAL) {
235 /* Reloading "inside" here since manip_pkt may reallocate */
236 inside = (void *)skb->data + hdrlen;
237 inside->icmp.checksum = 0;
238 inside->icmp.checksum =
239 csum_fold(skb_checksum(skb, hdrlen,
240 skb->len - hdrlen, 0));
241 }
242
243 /* Change outer to look like the reply to an incoming packet */
244 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
245 l4proto = __nf_nat_l4proto_find(NFPROTO_IPV4, 0);
246 if (!nf_nat_ipv4_manip_pkt(skb, 0, l4proto, &target, manip))
247 return 0;
248
249 return 1;
250}
251EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
252
253static int __init nf_nat_l3proto_ipv4_init(void)
254{
255 int err;
256
257 err = nf_nat_l4proto_register(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
258 if (err < 0)
259 goto err1;
260 err = nf_nat_l3proto_register(&nf_nat_l3proto_ipv4);
261 if (err < 0)
262 goto err2;
263 return err;
264
265err2:
266 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
267err1:
268 return err;
269}
270
271static void __exit nf_nat_l3proto_ipv4_exit(void)
272{
273 nf_nat_l3proto_unregister(&nf_nat_l3proto_ipv4);
274 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
275}
276
277MODULE_LICENSE("GPL");
278MODULE_ALIAS("nf-nat-" __stringify(AF_INET));
279
280module_init(nf_nat_l3proto_ipv4_init);
281module_exit(nf_nat_l3proto_ipv4_exit);
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 31ef890d894..a06d7d74817 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -22,7 +22,6 @@
22 22
23#include <net/netfilter/nf_nat.h> 23#include <net/netfilter/nf_nat.h>
24#include <net/netfilter/nf_nat_helper.h> 24#include <net/netfilter/nf_nat_helper.h>
25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_conntrack_helper.h> 25#include <net/netfilter/nf_conntrack_helper.h>
27#include <net/netfilter/nf_conntrack_expect.h> 26#include <net/netfilter/nf_conntrack_expect.h>
28#include <net/netfilter/nf_conntrack_zones.h> 27#include <net/netfilter/nf_conntrack_zones.h>
@@ -47,7 +46,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
47 struct nf_conntrack_tuple t; 46 struct nf_conntrack_tuple t;
48 const struct nf_ct_pptp_master *ct_pptp_info; 47 const struct nf_ct_pptp_master *ct_pptp_info;
49 const struct nf_nat_pptp *nat_pptp_info; 48 const struct nf_nat_pptp *nat_pptp_info;
50 struct nf_nat_ipv4_range range; 49 struct nf_nat_range range;
51 50
52 ct_pptp_info = nfct_help_data(master); 51 ct_pptp_info = nfct_help_data(master);
53 nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; 52 nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
@@ -89,21 +88,21 @@ static void pptp_nat_expected(struct nf_conn *ct,
89 88
90 /* Change src to where master sends to */ 89 /* Change src to where master sends to */
91 range.flags = NF_NAT_RANGE_MAP_IPS; 90 range.flags = NF_NAT_RANGE_MAP_IPS;
92 range.min_ip = range.max_ip 91 range.min_addr = range.max_addr
93 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 92 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
94 if (exp->dir == IP_CT_DIR_ORIGINAL) { 93 if (exp->dir == IP_CT_DIR_ORIGINAL) {
95 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 94 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
96 range.min = range.max = exp->saved_proto; 95 range.min_proto = range.max_proto = exp->saved_proto;
97 } 96 }
98 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); 97 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
99 98
100 /* For DST manip, map port here to where it's expected. */ 99 /* For DST manip, map port here to where it's expected. */
101 range.flags = NF_NAT_RANGE_MAP_IPS; 100 range.flags = NF_NAT_RANGE_MAP_IPS;
102 range.min_ip = range.max_ip 101 range.min_addr = range.max_addr
103 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; 102 = ct->master->tuplehash[!exp->dir].tuple.src.u3;
104 if (exp->dir == IP_CT_DIR_REPLY) { 103 if (exp->dir == IP_CT_DIR_REPLY) {
105 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 104 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
106 range.min = range.max = exp->saved_proto; 105 range.min_proto = range.max_proto = exp->saved_proto;
107 } 106 }
108 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); 107 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
109} 108}
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index 46ba0b9ab98..ea44f02563b 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -28,8 +28,7 @@
28#include <linux/ip.h> 28#include <linux/ip.h>
29 29
30#include <net/netfilter/nf_nat.h> 30#include <net/netfilter/nf_nat.h>
31#include <net/netfilter/nf_nat_rule.h> 31#include <net/netfilter/nf_nat_l4proto.h>
32#include <net/netfilter/nf_nat_protocol.h>
33#include <linux/netfilter/nf_conntrack_proto_gre.h> 32#include <linux/netfilter/nf_conntrack_proto_gre.h>
34 33
35MODULE_LICENSE("GPL"); 34MODULE_LICENSE("GPL");
@@ -38,8 +37,9 @@ MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
38 37
39/* generate unique tuple ... */ 38/* generate unique tuple ... */
40static void 39static void
41gre_unique_tuple(struct nf_conntrack_tuple *tuple, 40gre_unique_tuple(const struct nf_nat_l3proto *l3proto,
42 const struct nf_nat_ipv4_range *range, 41 struct nf_conntrack_tuple *tuple,
42 const struct nf_nat_range *range,
43 enum nf_nat_manip_type maniptype, 43 enum nf_nat_manip_type maniptype,
44 const struct nf_conn *ct) 44 const struct nf_conn *ct)
45{ 45{
@@ -62,8 +62,8 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
62 min = 1; 62 min = 1;
63 range_size = 0xffff; 63 range_size = 0xffff;
64 } else { 64 } else {
65 min = ntohs(range->min.gre.key); 65 min = ntohs(range->min_proto.gre.key);
66 range_size = ntohs(range->max.gre.key) - min + 1; 66 range_size = ntohs(range->max_proto.gre.key) - min + 1;
67 } 67 }
68 68
69 pr_debug("min = %u, range_size = %u\n", min, range_size); 69 pr_debug("min = %u, range_size = %u\n", min, range_size);
@@ -80,14 +80,14 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
80 80
81/* manipulate a GRE packet according to maniptype */ 81/* manipulate a GRE packet according to maniptype */
82static bool 82static bool
83gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, 83gre_manip_pkt(struct sk_buff *skb,
84 const struct nf_nat_l3proto *l3proto,
85 unsigned int iphdroff, unsigned int hdroff,
84 const struct nf_conntrack_tuple *tuple, 86 const struct nf_conntrack_tuple *tuple,
85 enum nf_nat_manip_type maniptype) 87 enum nf_nat_manip_type maniptype)
86{ 88{
87 const struct gre_hdr *greh; 89 const struct gre_hdr *greh;
88 struct gre_hdr_pptp *pgreh; 90 struct gre_hdr_pptp *pgreh;
89 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
90 unsigned int hdroff = iphdroff + iph->ihl * 4;
91 91
92 /* pgreh includes two optional 32bit fields which are not required 92 /* pgreh includes two optional 32bit fields which are not required
93 * to be there. That's where the magic '8' comes from */ 93 * to be there. That's where the magic '8' comes from */
@@ -117,24 +117,24 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
117 return true; 117 return true;
118} 118}
119 119
120static const struct nf_nat_protocol gre = { 120static const struct nf_nat_l4proto gre = {
121 .protonum = IPPROTO_GRE, 121 .l4proto = IPPROTO_GRE,
122 .manip_pkt = gre_manip_pkt, 122 .manip_pkt = gre_manip_pkt,
123 .in_range = nf_nat_proto_in_range, 123 .in_range = nf_nat_l4proto_in_range,
124 .unique_tuple = gre_unique_tuple, 124 .unique_tuple = gre_unique_tuple,
125#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 125#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
126 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 126 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
127#endif 127#endif
128}; 128};
129 129
130static int __init nf_nat_proto_gre_init(void) 130static int __init nf_nat_proto_gre_init(void)
131{ 131{
132 return nf_nat_protocol_register(&gre); 132 return nf_nat_l4proto_register(NFPROTO_IPV4, &gre);
133} 133}
134 134
135static void __exit nf_nat_proto_gre_fini(void) 135static void __exit nf_nat_proto_gre_fini(void)
136{ 136{
137 nf_nat_protocol_unregister(&gre); 137 nf_nat_l4proto_unregister(NFPROTO_IPV4, &gre);
138} 138}
139 139
140module_init(nf_nat_proto_gre_init); 140module_init(nf_nat_proto_gre_init);
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index b35172851ba..eb303471bcf 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -15,8 +15,7 @@
15#include <linux/netfilter.h> 15#include <linux/netfilter.h>
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_core.h> 17#include <net/netfilter/nf_nat_core.h>
18#include <net/netfilter/nf_nat_rule.h> 18#include <net/netfilter/nf_nat_l4proto.h>
19#include <net/netfilter/nf_nat_protocol.h>
20 19
21static bool 20static bool
22icmp_in_range(const struct nf_conntrack_tuple *tuple, 21icmp_in_range(const struct nf_conntrack_tuple *tuple,
@@ -29,8 +28,9 @@ icmp_in_range(const struct nf_conntrack_tuple *tuple,
29} 28}
30 29
31static void 30static void
32icmp_unique_tuple(struct nf_conntrack_tuple *tuple, 31icmp_unique_tuple(const struct nf_nat_l3proto *l3proto,
33 const struct nf_nat_ipv4_range *range, 32 struct nf_conntrack_tuple *tuple,
33 const struct nf_nat_range *range,
34 enum nf_nat_manip_type maniptype, 34 enum nf_nat_manip_type maniptype,
35 const struct nf_conn *ct) 35 const struct nf_conn *ct)
36{ 36{
@@ -38,13 +38,14 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
38 unsigned int range_size; 38 unsigned int range_size;
39 unsigned int i; 39 unsigned int i;
40 40
41 range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; 41 range_size = ntohs(range->max_proto.icmp.id) -
42 ntohs(range->min_proto.icmp.id) + 1;
42 /* If no range specified... */ 43 /* If no range specified... */
43 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) 44 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED))
44 range_size = 0xFFFF; 45 range_size = 0xFFFF;
45 46
46 for (i = 0; ; ++id) { 47 for (i = 0; ; ++id) {
47 tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + 48 tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) +
48 (id % range_size)); 49 (id % range_size));
49 if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) 50 if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
50 return; 51 return;
@@ -54,13 +55,12 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
54 55
55static bool 56static bool
56icmp_manip_pkt(struct sk_buff *skb, 57icmp_manip_pkt(struct sk_buff *skb,
57 unsigned int iphdroff, 58 const struct nf_nat_l3proto *l3proto,
59 unsigned int iphdroff, unsigned int hdroff,
58 const struct nf_conntrack_tuple *tuple, 60 const struct nf_conntrack_tuple *tuple,
59 enum nf_nat_manip_type maniptype) 61 enum nf_nat_manip_type maniptype)
60{ 62{
61 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
62 struct icmphdr *hdr; 63 struct icmphdr *hdr;
63 unsigned int hdroff = iphdroff + iph->ihl*4;
64 64
65 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 65 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
66 return false; 66 return false;
@@ -72,12 +72,12 @@ icmp_manip_pkt(struct sk_buff *skb,
72 return true; 72 return true;
73} 73}
74 74
75const struct nf_nat_protocol nf_nat_protocol_icmp = { 75const struct nf_nat_l4proto nf_nat_l4proto_icmp = {
76 .protonum = IPPROTO_ICMP, 76 .l4proto = IPPROTO_ICMP,
77 .manip_pkt = icmp_manip_pkt, 77 .manip_pkt = icmp_manip_pkt,
78 .in_range = icmp_in_range, 78 .in_range = icmp_in_range,
79 .unique_tuple = icmp_unique_tuple, 79 .unique_tuple = icmp_unique_tuple,
80#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 80#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
81 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 81 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
82#endif 82#endif
83}; 83};
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
deleted file mode 100644
index d2a9dc314e0..00000000000
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ /dev/null
@@ -1,214 +0,0 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9/* Everything about the rules for NAT. */
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11#include <linux/types.h>
12#include <linux/ip.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter_ipv4.h>
15#include <linux/module.h>
16#include <linux/kmod.h>
17#include <linux/skbuff.h>
18#include <linux/proc_fs.h>
19#include <linux/slab.h>
20#include <net/checksum.h>
21#include <net/route.h>
22#include <linux/bitops.h>
23
24#include <linux/netfilter_ipv4/ip_tables.h>
25#include <net/netfilter/nf_nat.h>
26#include <net/netfilter/nf_nat_core.h>
27#include <net/netfilter/nf_nat_rule.h>
28
29#define NAT_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
30 (1 << NF_INET_POST_ROUTING) | \
31 (1 << NF_INET_LOCAL_OUT) | \
32 (1 << NF_INET_LOCAL_IN))
33
34static const struct xt_table nat_table = {
35 .name = "nat",
36 .valid_hooks = NAT_VALID_HOOKS,
37 .me = THIS_MODULE,
38 .af = NFPROTO_IPV4,
39};
40
41/* Source NAT */
42static unsigned int
43ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
44{
45 struct nf_conn *ct;
46 enum ip_conntrack_info ctinfo;
47 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
48
49 NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING ||
50 par->hooknum == NF_INET_LOCAL_IN);
51
52 ct = nf_ct_get(skb, &ctinfo);
53
54 /* Connection must be valid and new. */
55 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
56 ctinfo == IP_CT_RELATED_REPLY));
57 NF_CT_ASSERT(par->out != NULL);
58
59 return nf_nat_setup_info(ct, &mr->range[0], NF_NAT_MANIP_SRC);
60}
61
62static unsigned int
63ipt_dnat_target(struct sk_buff *skb, const struct xt_action_param *par)
64{
65 struct nf_conn *ct;
66 enum ip_conntrack_info ctinfo;
67 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
68
69 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
70 par->hooknum == NF_INET_LOCAL_OUT);
71
72 ct = nf_ct_get(skb, &ctinfo);
73
74 /* Connection must be valid and new. */
75 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
76
77 return nf_nat_setup_info(ct, &mr->range[0], NF_NAT_MANIP_DST);
78}
79
80static int ipt_snat_checkentry(const struct xt_tgchk_param *par)
81{
82 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
83
84 /* Must be a valid range */
85 if (mr->rangesize != 1) {
86 pr_info("SNAT: multiple ranges no longer supported\n");
87 return -EINVAL;
88 }
89 return 0;
90}
91
92static int ipt_dnat_checkentry(const struct xt_tgchk_param *par)
93{
94 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
95
96 /* Must be a valid range */
97 if (mr->rangesize != 1) {
98 pr_info("DNAT: multiple ranges no longer supported\n");
99 return -EINVAL;
100 }
101 return 0;
102}
103
104static unsigned int
105alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
106{
107 /* Force range to this IP; let proto decide mapping for
108 per-proto parts (hence not NF_NAT_RANGE_PROTO_SPECIFIED).
109 */
110 struct nf_nat_ipv4_range range;
111
112 range.flags = 0;
113 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
114 HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
115 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
116 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
117
118 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
119}
120
121int nf_nat_rule_find(struct sk_buff *skb,
122 unsigned int hooknum,
123 const struct net_device *in,
124 const struct net_device *out,
125 struct nf_conn *ct)
126{
127 struct net *net = nf_ct_net(ct);
128 int ret;
129
130 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
131
132 if (ret == NF_ACCEPT) {
133 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
134 /* NUL mapping */
135 ret = alloc_null_binding(ct, hooknum);
136 }
137 return ret;
138}
139
140static struct xt_target ipt_snat_reg __read_mostly = {
141 .name = "SNAT",
142 .target = ipt_snat_target,
143 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
144 .table = "nat",
145 .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN),
146 .checkentry = ipt_snat_checkentry,
147 .family = AF_INET,
148};
149
150static struct xt_target ipt_dnat_reg __read_mostly = {
151 .name = "DNAT",
152 .target = ipt_dnat_target,
153 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
154 .table = "nat",
155 .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
156 .checkentry = ipt_dnat_checkentry,
157 .family = AF_INET,
158};
159
160static int __net_init nf_nat_rule_net_init(struct net *net)
161{
162 struct ipt_replace *repl;
163
164 repl = ipt_alloc_initial_table(&nat_table);
165 if (repl == NULL)
166 return -ENOMEM;
167 net->ipv4.nat_table = ipt_register_table(net, &nat_table, repl);
168 kfree(repl);
169 if (IS_ERR(net->ipv4.nat_table))
170 return PTR_ERR(net->ipv4.nat_table);
171 return 0;
172}
173
174static void __net_exit nf_nat_rule_net_exit(struct net *net)
175{
176 ipt_unregister_table(net, net->ipv4.nat_table);
177}
178
179static struct pernet_operations nf_nat_rule_net_ops = {
180 .init = nf_nat_rule_net_init,
181 .exit = nf_nat_rule_net_exit,
182};
183
184int __init nf_nat_rule_init(void)
185{
186 int ret;
187
188 ret = register_pernet_subsys(&nf_nat_rule_net_ops);
189 if (ret != 0)
190 goto out;
191 ret = xt_register_target(&ipt_snat_reg);
192 if (ret != 0)
193 goto unregister_table;
194
195 ret = xt_register_target(&ipt_dnat_reg);
196 if (ret != 0)
197 goto unregister_snat;
198
199 return ret;
200
201 unregister_snat:
202 xt_unregister_target(&ipt_snat_reg);
203 unregister_table:
204 unregister_pernet_subsys(&nf_nat_rule_net_ops);
205 out:
206 return ret;
207}
208
209void nf_nat_rule_cleanup(void)
210{
211 xt_unregister_target(&ipt_dnat_reg);
212 xt_unregister_target(&ipt_snat_reg);
213 unregister_pernet_subsys(&nf_nat_rule_net_ops);
214}
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index df626af8413..47a47186a79 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -19,7 +19,6 @@
19 19
20#include <net/netfilter/nf_nat.h> 20#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_helper.h> 21#include <net/netfilter/nf_nat_helper.h>
22#include <net/netfilter/nf_nat_rule.h>
23#include <net/netfilter/nf_conntrack_helper.h> 22#include <net/netfilter/nf_conntrack_helper.h>
24#include <net/netfilter/nf_conntrack_expect.h> 23#include <net/netfilter/nf_conntrack_expect.h>
25#include <linux/netfilter/nf_conntrack_sip.h> 24#include <linux/netfilter/nf_conntrack_sip.h>
@@ -255,15 +254,15 @@ static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off)
255static void ip_nat_sip_expected(struct nf_conn *ct, 254static void ip_nat_sip_expected(struct nf_conn *ct,
256 struct nf_conntrack_expect *exp) 255 struct nf_conntrack_expect *exp)
257{ 256{
258 struct nf_nat_ipv4_range range; 257 struct nf_nat_range range;
259 258
260 /* This must be a fresh one. */ 259 /* This must be a fresh one. */
261 BUG_ON(ct->status & IPS_NAT_DONE_MASK); 260 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
262 261
263 /* For DST manip, map port here to where it's expected. */ 262 /* For DST manip, map port here to where it's expected. */
264 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 263 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
265 range.min = range.max = exp->saved_proto; 264 range.min_proto = range.max_proto = exp->saved_proto;
266 range.min_ip = range.max_ip = exp->saved_ip; 265 range.min_addr = range.max_addr = exp->saved_addr;
267 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); 266 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
268 267
269 /* Change src to where master sends to, but only if the connection 268 /* Change src to where master sends to, but only if the connection
@@ -271,8 +270,8 @@ static void ip_nat_sip_expected(struct nf_conn *ct,
271 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 270 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
272 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { 271 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
273 range.flags = NF_NAT_RANGE_MAP_IPS; 272 range.flags = NF_NAT_RANGE_MAP_IPS;
274 range.min_ip = range.max_ip 273 range.min_addr = range.max_addr
275 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 274 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
276 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); 275 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
277 } 276 }
278} 277}
@@ -307,7 +306,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
307 else 306 else
308 port = ntohs(exp->tuple.dst.u.udp.port); 307 port = ntohs(exp->tuple.dst.u.udp.port);
309 308
310 exp->saved_ip = exp->tuple.dst.u3.ip; 309 exp->saved_addr = exp->tuple.dst.u3;
311 exp->tuple.dst.u3.ip = newip; 310 exp->tuple.dst.u3.ip = newip;
312 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; 311 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
313 exp->dir = !dir; 312 exp->dir = !dir;
@@ -329,7 +328,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
329 if (port == 0) 328 if (port == 0)
330 return NF_DROP; 329 return NF_DROP;
331 330
332 if (exp->tuple.dst.u3.ip != exp->saved_ip || 331 if (exp->tuple.dst.u3.ip != exp->saved_addr.ip ||
333 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { 332 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
334 buflen = sprintf(buffer, "%pI4:%u", &newip, port); 333 buflen = sprintf(buffer, "%pI4:%u", &newip, port);
335 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, 334 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -485,13 +484,13 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
485 else 484 else
486 rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip; 485 rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
487 486
488 rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; 487 rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
489 rtp_exp->tuple.dst.u3.ip = rtp_addr->ip; 488 rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
490 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; 489 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
491 rtp_exp->dir = !dir; 490 rtp_exp->dir = !dir;
492 rtp_exp->expectfn = ip_nat_sip_expected; 491 rtp_exp->expectfn = ip_nat_sip_expected;
493 492
494 rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; 493 rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
495 rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip; 494 rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
496 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; 495 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
497 rtcp_exp->dir = !dir; 496 rtcp_exp->dir = !dir;
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
index 9dbb8d284f9..ccabbda71a3 100644
--- a/net/ipv4/netfilter/nf_nat_tftp.c
+++ b/net/ipv4/netfilter/nf_nat_tftp.c
@@ -11,7 +11,6 @@
11#include <net/netfilter/nf_conntrack_helper.h> 11#include <net/netfilter/nf_conntrack_helper.h>
12#include <net/netfilter/nf_conntrack_expect.h> 12#include <net/netfilter/nf_conntrack_expect.h>
13#include <net/netfilter/nf_nat_helper.h> 13#include <net/netfilter/nf_nat_helper.h>
14#include <net/netfilter/nf_nat_rule.h>
15#include <linux/netfilter/nf_conntrack_tftp.h> 14#include <linux/netfilter/nf_conntrack_tftp.h>
16 15
17MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); 16MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c19b214ffd5..91adddae20a 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -356,6 +356,30 @@ config NETFILTER_NETLINK_QUEUE_CT
356 If this option is enabled, NFQUEUE can include Connection Tracking 356 If this option is enabled, NFQUEUE can include Connection Tracking
357 information together with the packet is the enqueued via NFNETLINK. 357 information together with the packet is the enqueued via NFNETLINK.
358 358
359config NF_NAT
360 tristate
361
362config NF_NAT_NEEDED
363 bool
364 depends on NF_NAT
365 default y
366
367config NF_NAT_PROTO_DCCP
368 tristate
369 depends on NF_NAT && NF_CT_PROTO_DCCP
370 default NF_NAT && NF_CT_PROTO_DCCP
371
372config NF_NAT_PROTO_UDPLITE
373 tristate
374 depends on NF_NAT && NF_CT_PROTO_UDPLITE
375 default NF_NAT && NF_CT_PROTO_UDPLITE
376
377config NF_NAT_PROTO_SCTP
378 tristate
379 default NF_NAT && NF_CT_PROTO_SCTP
380 depends on NF_NAT && NF_CT_PROTO_SCTP
381 select LIBCRC32C
382
359endif # NF_CONNTRACK 383endif # NF_CONNTRACK
360 384
361# transparent proxy support 385# transparent proxy support
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 1c5160f2278..09c9451bc51 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -43,6 +43,17 @@ obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
43obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o 43obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
44obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o 44obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
45 45
46nf_nat-y := nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \
47 nf_nat_proto_udp.o nf_nat_proto_tcp.o nf_nat_helper.o
48
49obj-$(CONFIG_NF_NAT) += nf_nat.o
50obj-$(CONFIG_NF_NAT) += xt_nat.o
51
52# NAT protocols (nf_nat)
53obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
54obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
55obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
56
46# transparent proxy support 57# transparent proxy support
47obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o 58obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
48 59
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 8f4b0b2b6f8..e61b3ac9591 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -275,6 +275,11 @@ EXPORT_SYMBOL_GPL(nfq_ct_nat_hook);
275 275
276#endif /* CONFIG_NF_CONNTRACK */ 276#endif /* CONFIG_NF_CONNTRACK */
277 277
278#ifdef CONFIG_NF_NAT_NEEDED
279void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
280EXPORT_SYMBOL(nf_nat_decode_session_hook);
281#endif
282
278#ifdef CONFIG_PROC_FS 283#ifdef CONFIG_PROC_FS
279struct proc_dir_entry *proc_net_netfilter; 284struct proc_dir_entry *proc_net_netfilter;
280EXPORT_SYMBOL(proc_net_netfilter); 285EXPORT_SYMBOL(proc_net_netfilter);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index cf4875565d6..f83e79defed 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -55,6 +55,12 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
55 const struct nlattr *attr) __read_mostly; 55 const struct nlattr *attr) __read_mostly;
56EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); 56EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
57 57
58int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
59 struct nf_conn *ct,
60 enum ip_conntrack_info ctinfo,
61 unsigned int protoff);
62EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
63
58DEFINE_SPINLOCK(nf_conntrack_lock); 64DEFINE_SPINLOCK(nf_conntrack_lock);
59EXPORT_SYMBOL_GPL(nf_conntrack_lock); 65EXPORT_SYMBOL_GPL(nf_conntrack_lock);
60 66
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index da4fc37a857..966f5133a38 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -45,7 +45,7 @@
45#include <net/netfilter/nf_conntrack_timestamp.h> 45#include <net/netfilter/nf_conntrack_timestamp.h>
46#ifdef CONFIG_NF_NAT_NEEDED 46#ifdef CONFIG_NF_NAT_NEEDED
47#include <net/netfilter/nf_nat_core.h> 47#include <net/netfilter/nf_nat_core.h>
48#include <net/netfilter/nf_nat_protocol.h> 48#include <net/netfilter/nf_nat_l4proto.h>
49#include <net/netfilter/nf_nat_helper.h> 49#include <net/netfilter/nf_nat_helper.h>
50#endif 50#endif
51 51
@@ -1096,13 +1096,14 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
1096 const struct nlattr *attr) 1096 const struct nlattr *attr)
1097{ 1097{
1098 typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup; 1098 typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
1099 int err;
1099 1100
1100 parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook); 1101 parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
1101 if (!parse_nat_setup) { 1102 if (!parse_nat_setup) {
1102#ifdef CONFIG_MODULES 1103#ifdef CONFIG_MODULES
1103 rcu_read_unlock(); 1104 rcu_read_unlock();
1104 nfnl_unlock(); 1105 nfnl_unlock();
1105 if (request_module("nf-nat-ipv4") < 0) { 1106 if (request_module("nf-nat") < 0) {
1106 nfnl_lock(); 1107 nfnl_lock();
1107 rcu_read_lock(); 1108 rcu_read_lock();
1108 return -EOPNOTSUPP; 1109 return -EOPNOTSUPP;
@@ -1115,7 +1116,26 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
1115 return -EOPNOTSUPP; 1116 return -EOPNOTSUPP;
1116 } 1117 }
1117 1118
1118 return parse_nat_setup(ct, manip, attr); 1119 err = parse_nat_setup(ct, manip, attr);
1120 if (err == -EAGAIN) {
1121#ifdef CONFIG_MODULES
1122 rcu_read_unlock();
1123 spin_unlock_bh(&nf_conntrack_lock);
1124 nfnl_unlock();
1125 if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
1126 nfnl_lock();
1127 spin_lock_bh(&nf_conntrack_lock);
1128 rcu_read_lock();
1129 return -EOPNOTSUPP;
1130 }
1131 nfnl_lock();
1132 spin_lock_bh(&nf_conntrack_lock);
1133 rcu_read_lock();
1134#else
1135 err = -EOPNOTSUPP;
1136#endif
1137 }
1138 return err;
1119} 1139}
1120#endif 1140#endif
1121 1141
@@ -1979,6 +1999,8 @@ nla_put_failure:
1979 return -1; 1999 return -1;
1980} 2000}
1981 2001
2002static const union nf_inet_addr any_addr;
2003
1982static int 2004static int
1983ctnetlink_exp_dump_expect(struct sk_buff *skb, 2005ctnetlink_exp_dump_expect(struct sk_buff *skb,
1984 const struct nf_conntrack_expect *exp) 2006 const struct nf_conntrack_expect *exp)
@@ -2005,7 +2027,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
2005 goto nla_put_failure; 2027 goto nla_put_failure;
2006 2028
2007#ifdef CONFIG_NF_NAT_NEEDED 2029#ifdef CONFIG_NF_NAT_NEEDED
2008 if (exp->saved_ip || exp->saved_proto.all) { 2030 if (!nf_inet_addr_cmp(&exp->saved_addr, &any_addr) ||
2031 exp->saved_proto.all) {
2009 nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED); 2032 nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
2010 if (!nest_parms) 2033 if (!nest_parms)
2011 goto nla_put_failure; 2034 goto nla_put_failure;
@@ -2014,7 +2037,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
2014 goto nla_put_failure; 2037 goto nla_put_failure;
2015 2038
2016 nat_tuple.src.l3num = nf_ct_l3num(master); 2039 nat_tuple.src.l3num = nf_ct_l3num(master);
2017 nat_tuple.src.u3.ip = exp->saved_ip; 2040 nat_tuple.src.u3 = exp->saved_addr;
2018 nat_tuple.dst.protonum = nf_ct_protonum(master); 2041 nat_tuple.dst.protonum = nf_ct_protonum(master);
2019 nat_tuple.src.u = exp->saved_proto; 2042 nat_tuple.src.u = exp->saved_proto;
2020 2043
@@ -2410,7 +2433,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
2410 if (err < 0) 2433 if (err < 0)
2411 return err; 2434 return err;
2412 2435
2413 exp->saved_ip = nat_tuple.src.u3.ip; 2436 exp->saved_addr = nat_tuple.src.u3;
2414 exp->saved_proto = nat_tuple.src.u; 2437 exp->saved_proto = nat_tuple.src.u;
2415 exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR])); 2438 exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
2416 2439
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index a5ac11ebef3..9c2cc716f4a 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -505,10 +505,10 @@ static inline s16 nat_offset(const struct nf_conn *ct,
505 505
506 return get_offset != NULL ? get_offset(ct, dir, seq) : 0; 506 return get_offset != NULL ? get_offset(ct, dir, seq) : 0;
507} 507}
508#define NAT_OFFSET(pf, ct, dir, seq) \ 508#define NAT_OFFSET(ct, dir, seq) \
509 (pf == NFPROTO_IPV4 ? nat_offset(ct, dir, seq) : 0) 509 (nat_offset(ct, dir, seq))
510#else 510#else
511#define NAT_OFFSET(pf, ct, dir, seq) 0 511#define NAT_OFFSET(ct, dir, seq) 0
512#endif 512#endif
513 513
514static bool tcp_in_window(const struct nf_conn *ct, 514static bool tcp_in_window(const struct nf_conn *ct,
@@ -541,7 +541,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
541 tcp_sack(skb, dataoff, tcph, &sack); 541 tcp_sack(skb, dataoff, tcph, &sack);
542 542
543 /* Take into account NAT sequence number mangling */ 543 /* Take into account NAT sequence number mangling */
544 receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1); 544 receiver_offset = NAT_OFFSET(ct, !dir, ack - 1);
545 ack -= receiver_offset; 545 ack -= receiver_offset;
546 sack -= receiver_offset; 546 sack -= receiver_offset;
547 547
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 590f0abaab8..d5174902db3 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -946,11 +946,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
946 break; 946 break;
947#ifdef CONFIG_NF_NAT_NEEDED 947#ifdef CONFIG_NF_NAT_NEEDED
948 if (exp->tuple.src.l3num == AF_INET && !direct_rtp && 948 if (exp->tuple.src.l3num == AF_INET && !direct_rtp &&
949 (exp->saved_ip != exp->tuple.dst.u3.ip || 949 (exp->saved_addr.ip != exp->tuple.dst.u3.ip ||
950 exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) && 950 exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
951 ct->status & IPS_NAT_MASK) { 951 ct->status & IPS_NAT_MASK) {
952 daddr->ip = exp->saved_ip; 952 daddr->ip = exp->saved_addr.ip;
953 tuple.dst.u3.ip = exp->saved_ip; 953 tuple.dst.u3.ip = exp->saved_addr.ip;
954 tuple.dst.u.udp.port = exp->saved_proto.udp.port; 954 tuple.dst.u.udp.port = exp->saved_proto.udp.port;
955 direct_rtp = 1; 955 direct_rtp = 1;
956 } else 956 } else
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 44b082fd48a..c577b753fb9 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -1,7 +1,7 @@
1/* NAT for netfilter; shared with compatibility layer. */ 1/*
2 2 * (C) 1999-2001 Paul `Rusty' Russell
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4 * (C) 2011 Patrick McHardy <kaber@trash.net>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 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 7 * it under the terms of the GNU General Public License version 2 as
@@ -13,39 +13,106 @@
13#include <linux/timer.h> 13#include <linux/timer.h>
14#include <linux/skbuff.h> 14#include <linux/skbuff.h>
15#include <linux/gfp.h> 15#include <linux/gfp.h>
16#include <net/checksum.h> 16#include <net/xfrm.h>
17#include <net/icmp.h>
18#include <net/ip.h>
19#include <net/tcp.h> /* For tcp_prot in getorigdst */
20#include <linux/icmp.h>
21#include <linux/udp.h>
22#include <linux/jhash.h> 17#include <linux/jhash.h>
18#include <linux/rtnetlink.h>
23 19
24#include <linux/netfilter_ipv4.h>
25#include <net/netfilter/nf_conntrack.h> 20#include <net/netfilter/nf_conntrack.h>
26#include <net/netfilter/nf_conntrack_core.h> 21#include <net/netfilter/nf_conntrack_core.h>
27#include <net/netfilter/nf_nat.h> 22#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/nf_nat_protocol.h> 23#include <net/netfilter/nf_nat_l3proto.h>
24#include <net/netfilter/nf_nat_l4proto.h>
29#include <net/netfilter/nf_nat_core.h> 25#include <net/netfilter/nf_nat_core.h>
30#include <net/netfilter/nf_nat_helper.h> 26#include <net/netfilter/nf_nat_helper.h>
31#include <net/netfilter/nf_conntrack_helper.h> 27#include <net/netfilter/nf_conntrack_helper.h>
32#include <net/netfilter/nf_conntrack_l3proto.h> 28#include <net/netfilter/nf_conntrack_l3proto.h>
33#include <net/netfilter/nf_conntrack_zones.h> 29#include <net/netfilter/nf_conntrack_zones.h>
30#include <linux/netfilter/nf_nat.h>
34 31
35static DEFINE_SPINLOCK(nf_nat_lock); 32static DEFINE_SPINLOCK(nf_nat_lock);
36 33
37static struct nf_conntrack_l3proto *l3proto __read_mostly; 34static DEFINE_MUTEX(nf_nat_proto_mutex);
38 35static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO]
39#define MAX_IP_NAT_PROTO 256 36 __read_mostly;
40static const struct nf_nat_protocol __rcu *nf_nat_protos[MAX_IP_NAT_PROTO] 37static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO]
41 __read_mostly; 38 __read_mostly;
42 39
43static inline const struct nf_nat_protocol * 40
44__nf_nat_proto_find(u_int8_t protonum) 41inline const struct nf_nat_l3proto *
42__nf_nat_l3proto_find(u8 family)
45{ 43{
46 return rcu_dereference(nf_nat_protos[protonum]); 44 return rcu_dereference(nf_nat_l3protos[family]);
47} 45}
48 46
47inline const struct nf_nat_l4proto *
48__nf_nat_l4proto_find(u8 family, u8 protonum)
49{
50 return rcu_dereference(nf_nat_l4protos[family][protonum]);
51}
52EXPORT_SYMBOL_GPL(__nf_nat_l4proto_find);
53
54#ifdef CONFIG_XFRM
55static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
56{
57 const struct nf_nat_l3proto *l3proto;
58 const struct nf_conn *ct;
59 enum ip_conntrack_info ctinfo;
60 enum ip_conntrack_dir dir;
61 unsigned long statusbit;
62 u8 family;
63
64 ct = nf_ct_get(skb, &ctinfo);
65 if (ct == NULL)
66 return;
67
68 family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
69 rcu_read_lock();
70 l3proto = __nf_nat_l3proto_find(family);
71 if (l3proto == NULL)
72 goto out;
73
74 dir = CTINFO2DIR(ctinfo);
75 if (dir == IP_CT_DIR_ORIGINAL)
76 statusbit = IPS_DST_NAT;
77 else
78 statusbit = IPS_SRC_NAT;
79
80 l3proto->decode_session(skb, ct, dir, statusbit, fl);
81out:
82 rcu_read_unlock();
83}
84
85int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
86{
87 struct flowi fl;
88 unsigned int hh_len;
89 struct dst_entry *dst;
90
91 if (xfrm_decode_session(skb, &fl, family) < 0)
92 return -1;
93
94 dst = skb_dst(skb);
95 if (dst->xfrm)
96 dst = ((struct xfrm_dst *)dst)->route;
97 dst_hold(dst);
98
99 dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
100 if (IS_ERR(dst))
101 return -1;
102
103 skb_dst_drop(skb);
104 skb_dst_set(skb, dst);
105
106 /* Change in oif may mean change in hh_len. */
107 hh_len = skb_dst(skb)->dev->hard_header_len;
108 if (skb_headroom(skb) < hh_len &&
109 pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
110 return -1;
111 return 0;
112}
113EXPORT_SYMBOL(nf_xfrm_me_harder);
114#endif /* CONFIG_XFRM */
115
49/* We keep an extra hash for each conntrack, for fast searching. */ 116/* We keep an extra hash for each conntrack, for fast searching. */
50static inline unsigned int 117static inline unsigned int
51hash_by_src(const struct net *net, u16 zone, 118hash_by_src(const struct net *net, u16 zone,
@@ -54,10 +121,9 @@ hash_by_src(const struct net *net, u16 zone,
54 unsigned int hash; 121 unsigned int hash;
55 122
56 /* Original src, to ensure we map it consistently if poss. */ 123 /* Original src, to ensure we map it consistently if poss. */
57 hash = jhash_3words((__force u32)tuple->src.u3.ip, 124 hash = jhash2((u32 *)&tuple->src, sizeof(tuple->src) / sizeof(u32),
58 (__force u32)tuple->src.u.all ^ zone, 125 tuple->dst.protonum ^ zone ^ nf_conntrack_hash_rnd);
59 tuple->dst.protonum, nf_conntrack_hash_rnd); 126 return ((u64)hash * net->ct.nat_htable_size) >> 32;
60 return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
61} 127}
62 128
63/* Is this tuple already taken? (not by us) */ 129/* Is this tuple already taken? (not by us) */
@@ -66,10 +132,11 @@ nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
66 const struct nf_conn *ignored_conntrack) 132 const struct nf_conn *ignored_conntrack)
67{ 133{
68 /* Conntrack tracking doesn't keep track of outgoing tuples; only 134 /* Conntrack tracking doesn't keep track of outgoing tuples; only
69 incoming ones. NAT means they don't have a fixed mapping, 135 * incoming ones. NAT means they don't have a fixed mapping,
70 so we invert the tuple and look for the incoming reply. 136 * so we invert the tuple and look for the incoming reply.
71 137 *
72 We could keep a separate hash if this proves too slow. */ 138 * We could keep a separate hash if this proves too slow.
139 */
73 struct nf_conntrack_tuple reply; 140 struct nf_conntrack_tuple reply;
74 141
75 nf_ct_invert_tuplepr(&reply, tuple); 142 nf_ct_invert_tuplepr(&reply, tuple);
@@ -78,31 +145,26 @@ nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
78EXPORT_SYMBOL(nf_nat_used_tuple); 145EXPORT_SYMBOL(nf_nat_used_tuple);
79 146
80/* If we source map this tuple so reply looks like reply_tuple, will 147/* If we source map this tuple so reply looks like reply_tuple, will
81 * that meet the constraints of range. */ 148 * that meet the constraints of range.
82static int 149 */
83in_range(const struct nf_conntrack_tuple *tuple, 150static int in_range(const struct nf_nat_l3proto *l3proto,
84 const struct nf_nat_ipv4_range *range) 151 const struct nf_nat_l4proto *l4proto,
152 const struct nf_conntrack_tuple *tuple,
153 const struct nf_nat_range *range)
85{ 154{
86 const struct nf_nat_protocol *proto;
87 int ret = 0;
88
89 /* If we are supposed to map IPs, then we must be in the 155 /* If we are supposed to map IPs, then we must be in the
90 range specified, otherwise let this drag us onto a new src IP. */ 156 * range specified, otherwise let this drag us onto a new src IP.
91 if (range->flags & NF_NAT_RANGE_MAP_IPS) { 157 */
92 if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || 158 if (range->flags & NF_NAT_RANGE_MAP_IPS &&
93 ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) 159 !l3proto->in_range(tuple, range))
94 return 0; 160 return 0;
95 }
96 161
97 rcu_read_lock();
98 proto = __nf_nat_proto_find(tuple->dst.protonum);
99 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) || 162 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) ||
100 proto->in_range(tuple, NF_NAT_MANIP_SRC, 163 l4proto->in_range(tuple, NF_NAT_MANIP_SRC,
101 &range->min, &range->max)) 164 &range->min_proto, &range->max_proto))
102 ret = 1; 165 return 1;
103 rcu_read_unlock();
104 166
105 return ret; 167 return 0;
106} 168}
107 169
108static inline int 170static inline int
@@ -113,24 +175,25 @@ same_src(const struct nf_conn *ct,
113 175
114 t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 176 t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
115 return (t->dst.protonum == tuple->dst.protonum && 177 return (t->dst.protonum == tuple->dst.protonum &&
116 t->src.u3.ip == tuple->src.u3.ip && 178 nf_inet_addr_cmp(&t->src.u3, &tuple->src.u3) &&
117 t->src.u.all == tuple->src.u.all); 179 t->src.u.all == tuple->src.u.all);
118} 180}
119 181
120/* Only called for SRC manip */ 182/* Only called for SRC manip */
121static int 183static int
122find_appropriate_src(struct net *net, u16 zone, 184find_appropriate_src(struct net *net, u16 zone,
185 const struct nf_nat_l3proto *l3proto,
186 const struct nf_nat_l4proto *l4proto,
123 const struct nf_conntrack_tuple *tuple, 187 const struct nf_conntrack_tuple *tuple,
124 struct nf_conntrack_tuple *result, 188 struct nf_conntrack_tuple *result,
125 const struct nf_nat_ipv4_range *range) 189 const struct nf_nat_range *range)
126{ 190{
127 unsigned int h = hash_by_src(net, zone, tuple); 191 unsigned int h = hash_by_src(net, zone, tuple);
128 const struct nf_conn_nat *nat; 192 const struct nf_conn_nat *nat;
129 const struct nf_conn *ct; 193 const struct nf_conn *ct;
130 const struct hlist_node *n; 194 const struct hlist_node *n;
131 195
132 rcu_read_lock(); 196 hlist_for_each_entry_rcu(nat, n, &net->ct.nat_bysource[h], bysource) {
133 hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
134 ct = nat->ct; 197 ct = nat->ct;
135 if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) { 198 if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
136 /* Copy source part from reply tuple. */ 199 /* Copy source part from reply tuple. */
@@ -138,119 +201,150 @@ find_appropriate_src(struct net *net, u16 zone,
138 &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 201 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
139 result->dst = tuple->dst; 202 result->dst = tuple->dst;
140 203
141 if (in_range(result, range)) { 204 if (in_range(l3proto, l4proto, result, range)) {
142 rcu_read_unlock(); 205 rcu_read_unlock();
143 return 1; 206 return 1;
144 } 207 }
145 } 208 }
146 } 209 }
147 rcu_read_unlock();
148 return 0; 210 return 0;
149} 211}
150 212
151/* For [FUTURE] fragmentation handling, we want the least-used 213/* For [FUTURE] fragmentation handling, we want the least-used
152 src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus 214 * src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
153 if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports 215 * if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
154 1-65535, we don't do pro-rata allocation based on ports; we choose 216 * 1-65535, we don't do pro-rata allocation based on ports; we choose
155 the ip with the lowest src-ip/dst-ip/proto usage. 217 * the ip with the lowest src-ip/dst-ip/proto usage.
156*/ 218 */
157static void 219static void
158find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple, 220find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
159 const struct nf_nat_ipv4_range *range, 221 const struct nf_nat_range *range,
160 const struct nf_conn *ct, 222 const struct nf_conn *ct,
161 enum nf_nat_manip_type maniptype) 223 enum nf_nat_manip_type maniptype)
162{ 224{
163 __be32 *var_ipp; 225 union nf_inet_addr *var_ipp;
226 unsigned int i, max;
164 /* Host order */ 227 /* Host order */
165 u_int32_t minip, maxip, j; 228 u32 minip, maxip, j, dist;
229 bool full_range;
166 230
167 /* No IP mapping? Do nothing. */ 231 /* No IP mapping? Do nothing. */
168 if (!(range->flags & NF_NAT_RANGE_MAP_IPS)) 232 if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
169 return; 233 return;
170 234
171 if (maniptype == NF_NAT_MANIP_SRC) 235 if (maniptype == NF_NAT_MANIP_SRC)
172 var_ipp = &tuple->src.u3.ip; 236 var_ipp = &tuple->src.u3;
173 else 237 else
174 var_ipp = &tuple->dst.u3.ip; 238 var_ipp = &tuple->dst.u3;
175 239
176 /* Fast path: only one choice. */ 240 /* Fast path: only one choice. */
177 if (range->min_ip == range->max_ip) { 241 if (nf_inet_addr_cmp(&range->min_addr, &range->max_addr)) {
178 *var_ipp = range->min_ip; 242 *var_ipp = range->min_addr;
179 return; 243 return;
180 } 244 }
181 245
246 if (nf_ct_l3num(ct) == NFPROTO_IPV4)
247 max = sizeof(var_ipp->ip) / sizeof(u32) - 1;
248 else
249 max = sizeof(var_ipp->ip6) / sizeof(u32) - 1;
250
182 /* Hashing source and destination IPs gives a fairly even 251 /* Hashing source and destination IPs gives a fairly even
183 * spread in practice (if there are a small number of IPs 252 * spread in practice (if there are a small number of IPs
184 * involved, there usually aren't that many connections 253 * involved, there usually aren't that many connections
185 * anyway). The consistency means that servers see the same 254 * anyway). The consistency means that servers see the same
186 * client coming from the same IP (some Internet Banking sites 255 * client coming from the same IP (some Internet Banking sites
187 * like this), even across reboots. */ 256 * like this), even across reboots.
188 minip = ntohl(range->min_ip); 257 */
189 maxip = ntohl(range->max_ip); 258 j = jhash2((u32 *)&tuple->src.u3, sizeof(tuple->src.u3),
190 j = jhash_2words((__force u32)tuple->src.u3.ip, 259 range->flags & NF_NAT_RANGE_PERSISTENT ?
191 range->flags & NF_NAT_RANGE_PERSISTENT ? 260 0 : (__force u32)tuple->dst.u3.all[max] ^ zone);
192 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0); 261
193 j = ((u64)j * (maxip - minip + 1)) >> 32; 262 full_range = false;
194 *var_ipp = htonl(minip + j); 263 for (i = 0; i <= max; i++) {
264 /* If first bytes of the address are at the maximum, use the
265 * distance. Otherwise use the full range.
266 */
267 if (!full_range) {
268 minip = ntohl((__force __be32)range->min_addr.all[i]);
269 maxip = ntohl((__force __be32)range->max_addr.all[i]);
270 dist = maxip - minip + 1;
271 } else {
272 minip = 0;
273 dist = ~0;
274 }
275
276 var_ipp->all[i] = (__force __u32)
277 htonl(minip + (((u64)j * dist) >> 32));
278 if (var_ipp->all[i] != range->max_addr.all[i])
279 full_range = true;
280
281 if (!(range->flags & NF_NAT_RANGE_PERSISTENT))
282 j ^= (__force u32)tuple->dst.u3.all[i];
283 }
195} 284}
196 285
197/* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING, 286/* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING,
198 * we change the source to map into the range. For NF_INET_PRE_ROUTING 287 * we change the source to map into the range. For NF_INET_PRE_ROUTING
199 * and NF_INET_LOCAL_OUT, we change the destination to map into the 288 * and NF_INET_LOCAL_OUT, we change the destination to map into the
200 * range. It might not be possible to get a unique tuple, but we try. 289 * range. It might not be possible to get a unique tuple, but we try.
201 * At worst (or if we race), we will end up with a final duplicate in 290 * At worst (or if we race), we will end up with a final duplicate in
202 * __ip_conntrack_confirm and drop the packet. */ 291 * __ip_conntrack_confirm and drop the packet. */
203static void 292static void
204get_unique_tuple(struct nf_conntrack_tuple *tuple, 293get_unique_tuple(struct nf_conntrack_tuple *tuple,
205 const struct nf_conntrack_tuple *orig_tuple, 294 const struct nf_conntrack_tuple *orig_tuple,
206 const struct nf_nat_ipv4_range *range, 295 const struct nf_nat_range *range,
207 struct nf_conn *ct, 296 struct nf_conn *ct,
208 enum nf_nat_manip_type maniptype) 297 enum nf_nat_manip_type maniptype)
209{ 298{
299 const struct nf_nat_l3proto *l3proto;
300 const struct nf_nat_l4proto *l4proto;
210 struct net *net = nf_ct_net(ct); 301 struct net *net = nf_ct_net(ct);
211 const struct nf_nat_protocol *proto;
212 u16 zone = nf_ct_zone(ct); 302 u16 zone = nf_ct_zone(ct);
213 303
214 /* 1) If this srcip/proto/src-proto-part is currently mapped, 304 rcu_read_lock();
215 and that same mapping gives a unique tuple within the given 305 l3proto = __nf_nat_l3proto_find(orig_tuple->src.l3num);
216 range, use that. 306 l4proto = __nf_nat_l4proto_find(orig_tuple->src.l3num,
307 orig_tuple->dst.protonum);
217 308
218 This is only required for source (ie. NAT/masq) mappings. 309 /* 1) If this srcip/proto/src-proto-part is currently mapped,
219 So far, we don't do local source mappings, so multiple 310 * and that same mapping gives a unique tuple within the given
220 manips not an issue. */ 311 * range, use that.
312 *
313 * This is only required for source (ie. NAT/masq) mappings.
314 * So far, we don't do local source mappings, so multiple
315 * manips not an issue.
316 */
221 if (maniptype == NF_NAT_MANIP_SRC && 317 if (maniptype == NF_NAT_MANIP_SRC &&
222 !(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) { 318 !(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) {
223 /* try the original tuple first */ 319 /* try the original tuple first */
224 if (in_range(orig_tuple, range)) { 320 if (in_range(l3proto, l4proto, orig_tuple, range)) {
225 if (!nf_nat_used_tuple(orig_tuple, ct)) { 321 if (!nf_nat_used_tuple(orig_tuple, ct)) {
226 *tuple = *orig_tuple; 322 *tuple = *orig_tuple;
227 return; 323 goto out;
228 } 324 }
229 } else if (find_appropriate_src(net, zone, orig_tuple, tuple, 325 } else if (find_appropriate_src(net, zone, l3proto, l4proto,
230 range)) { 326 orig_tuple, tuple, range)) {
231 pr_debug("get_unique_tuple: Found current src map\n"); 327 pr_debug("get_unique_tuple: Found current src map\n");
232 if (!nf_nat_used_tuple(tuple, ct)) 328 if (!nf_nat_used_tuple(tuple, ct))
233 return; 329 goto out;
234 } 330 }
235 } 331 }
236 332
237 /* 2) Select the least-used IP/proto combination in the given 333 /* 2) Select the least-used IP/proto combination in the given range */
238 range. */
239 *tuple = *orig_tuple; 334 *tuple = *orig_tuple;
240 find_best_ips_proto(zone, tuple, range, ct, maniptype); 335 find_best_ips_proto(zone, tuple, range, ct, maniptype);
241 336
242 /* 3) The per-protocol part of the manip is made to map into 337 /* 3) The per-protocol part of the manip is made to map into
243 the range to make a unique tuple. */ 338 * the range to make a unique tuple.
244 339 */
245 rcu_read_lock();
246 proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
247 340
248 /* Only bother mapping if it's not already in range and unique */ 341 /* Only bother mapping if it's not already in range and unique */
249 if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) { 342 if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) {
250 if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 343 if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
251 if (proto->in_range(tuple, maniptype, &range->min, 344 if (l4proto->in_range(tuple, maniptype,
252 &range->max) && 345 &range->min_proto,
253 (range->min.all == range->max.all || 346 &range->max_proto) &&
347 (range->min_proto.all == range->max_proto.all ||
254 !nf_nat_used_tuple(tuple, ct))) 348 !nf_nat_used_tuple(tuple, ct)))
255 goto out; 349 goto out;
256 } else if (!nf_nat_used_tuple(tuple, ct)) { 350 } else if (!nf_nat_used_tuple(tuple, ct)) {
@@ -259,14 +353,14 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
259 } 353 }
260 354
261 /* Last change: get protocol to try to obtain unique tuple. */ 355 /* Last change: get protocol to try to obtain unique tuple. */
262 proto->unique_tuple(tuple, range, maniptype, ct); 356 l4proto->unique_tuple(l3proto, tuple, range, maniptype, ct);
263out: 357out:
264 rcu_read_unlock(); 358 rcu_read_unlock();
265} 359}
266 360
267unsigned int 361unsigned int
268nf_nat_setup_info(struct nf_conn *ct, 362nf_nat_setup_info(struct nf_conn *ct,
269 const struct nf_nat_ipv4_range *range, 363 const struct nf_nat_range *range,
270 enum nf_nat_manip_type maniptype) 364 enum nf_nat_manip_type maniptype)
271{ 365{
272 struct net *net = nf_ct_net(ct); 366 struct net *net = nf_ct_net(ct);
@@ -288,10 +382,10 @@ nf_nat_setup_info(struct nf_conn *ct,
288 BUG_ON(nf_nat_initialized(ct, maniptype)); 382 BUG_ON(nf_nat_initialized(ct, maniptype));
289 383
290 /* What we've got will look like inverse of reply. Normally 384 /* What we've got will look like inverse of reply. Normally
291 this is what is in the conntrack, except for prior 385 * this is what is in the conntrack, except for prior
292 manipulations (future optimization: if num_manips == 0, 386 * manipulations (future optimization: if num_manips == 0,
293 orig_tp = 387 * orig_tp = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
294 conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ 388 */
295 nf_ct_invert_tuplepr(&curr_tuple, 389 nf_ct_invert_tuplepr(&curr_tuple,
296 &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 390 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
297 391
@@ -317,11 +411,11 @@ nf_nat_setup_info(struct nf_conn *ct,
317 srchash = hash_by_src(net, nf_ct_zone(ct), 411 srchash = hash_by_src(net, nf_ct_zone(ct),
318 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 412 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
319 spin_lock_bh(&nf_nat_lock); 413 spin_lock_bh(&nf_nat_lock);
320 /* nf_conntrack_alter_reply might re-allocate extension area */ 414 /* nf_conntrack_alter_reply might re-allocate extension aera */
321 nat = nfct_nat(ct); 415 nat = nfct_nat(ct);
322 nat->ct = ct; 416 nat->ct = ct;
323 hlist_add_head_rcu(&nat->bysource, 417 hlist_add_head_rcu(&nat->bysource,
324 &net->ipv4.nat_bysource[srchash]); 418 &net->ct.nat_bysource[srchash]);
325 spin_unlock_bh(&nf_nat_lock); 419 spin_unlock_bh(&nf_nat_lock);
326 } 420 }
327 421
@@ -335,47 +429,14 @@ nf_nat_setup_info(struct nf_conn *ct,
335} 429}
336EXPORT_SYMBOL(nf_nat_setup_info); 430EXPORT_SYMBOL(nf_nat_setup_info);
337 431
338/* Returns true if succeeded. */
339static bool
340manip_pkt(u_int16_t proto,
341 struct sk_buff *skb,
342 unsigned int iphdroff,
343 const struct nf_conntrack_tuple *target,
344 enum nf_nat_manip_type maniptype)
345{
346 struct iphdr *iph;
347 const struct nf_nat_protocol *p;
348
349 if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
350 return false;
351
352 iph = (void *)skb->data + iphdroff;
353
354 /* Manipulate protcol part. */
355
356 /* rcu_read_lock()ed by nf_hook_slow */
357 p = __nf_nat_proto_find(proto);
358 if (!p->manip_pkt(skb, iphdroff, target, maniptype))
359 return false;
360
361 iph = (void *)skb->data + iphdroff;
362
363 if (maniptype == NF_NAT_MANIP_SRC) {
364 csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
365 iph->saddr = target->src.u3.ip;
366 } else {
367 csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
368 iph->daddr = target->dst.u3.ip;
369 }
370 return true;
371}
372
373/* Do packet manipulations according to nf_nat_setup_info. */ 432/* Do packet manipulations according to nf_nat_setup_info. */
374unsigned int nf_nat_packet(struct nf_conn *ct, 433unsigned int nf_nat_packet(struct nf_conn *ct,
375 enum ip_conntrack_info ctinfo, 434 enum ip_conntrack_info ctinfo,
376 unsigned int hooknum, 435 unsigned int hooknum,
377 struct sk_buff *skb) 436 struct sk_buff *skb)
378{ 437{
438 const struct nf_nat_l3proto *l3proto;
439 const struct nf_nat_l4proto *l4proto;
379 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 440 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
380 unsigned long statusbit; 441 unsigned long statusbit;
381 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); 442 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);
@@ -396,129 +457,174 @@ unsigned int nf_nat_packet(struct nf_conn *ct,
396 /* We are aiming to look like inverse of other direction. */ 457 /* We are aiming to look like inverse of other direction. */
397 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 458 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
398 459
399 if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype)) 460 l3proto = __nf_nat_l3proto_find(target.src.l3num);
461 l4proto = __nf_nat_l4proto_find(target.src.l3num,
462 target.dst.protonum);
463 if (!l3proto->manip_pkt(skb, 0, l4proto, &target, mtype))
400 return NF_DROP; 464 return NF_DROP;
401 } 465 }
402 return NF_ACCEPT; 466 return NF_ACCEPT;
403} 467}
404EXPORT_SYMBOL_GPL(nf_nat_packet); 468EXPORT_SYMBOL_GPL(nf_nat_packet);
405 469
406/* Dir is direction ICMP is coming from (opposite to packet it contains) */ 470struct nf_nat_proto_clean {
407int nf_nat_icmp_reply_translation(struct nf_conn *ct, 471 u8 l3proto;
408 enum ip_conntrack_info ctinfo, 472 u8 l4proto;
409 unsigned int hooknum, 473 bool hash;
410 struct sk_buff *skb) 474};
475
476/* Clear NAT section of all conntracks, in case we're loaded again. */
477static int nf_nat_proto_clean(struct nf_conn *i, void *data)
411{ 478{
412 struct { 479 const struct nf_nat_proto_clean *clean = data;
413 struct icmphdr icmp; 480 struct nf_conn_nat *nat = nfct_nat(i);
414 struct iphdr ip;
415 } *inside;
416 struct nf_conntrack_tuple target;
417 int hdrlen = ip_hdrlen(skb);
418 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
419 unsigned long statusbit;
420 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
421 481
422 if (!skb_make_writable(skb, hdrlen + sizeof(*inside))) 482 if (!nat)
423 return 0; 483 return 0;
424 484 if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) ||
425 inside = (void *)skb->data + hdrlen; 485 (clean->l4proto && nf_ct_protonum(i) != clean->l4proto))
426
427 /* We're actually going to mangle it beyond trivial checksum
428 adjustment, so make sure the current checksum is correct. */
429 if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
430 return 0; 486 return 0;
431 487
432 /* Must be RELATED */ 488 if (clean->hash) {
433 NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED || 489 spin_lock_bh(&nf_nat_lock);
434 skb->nfctinfo == IP_CT_RELATED_REPLY); 490 hlist_del_rcu(&nat->bysource);
435 491 spin_unlock_bh(&nf_nat_lock);
436 /* Redirects on non-null nats must be dropped, else they'll 492 } else {
437 start talking to each other without our translation, and be 493 memset(nat, 0, sizeof(*nat));
438 confused... --RR */ 494 i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK |
439 if (inside->icmp.type == ICMP_REDIRECT) { 495 IPS_SEQ_ADJUST);
440 /* If NAT isn't finished, assume it and drop. */
441 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
442 return 0;
443
444 if (ct->status & IPS_NAT_MASK)
445 return 0;
446 } 496 }
497 return 0;
498}
447 499
448 if (manip == NF_NAT_MANIP_SRC) 500static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
449 statusbit = IPS_SRC_NAT; 501{
450 else 502 struct nf_nat_proto_clean clean = {
451 statusbit = IPS_DST_NAT; 503 .l3proto = l3proto,
452 504 .l4proto = l4proto,
453 /* Invert if this is reply dir. */ 505 };
454 if (dir == IP_CT_DIR_REPLY) 506 struct net *net;
455 statusbit ^= IPS_NAT_MASK; 507
456 508 rtnl_lock();
457 if (!(ct->status & statusbit)) 509 /* Step 1 - remove from bysource hash */
458 return 1; 510 clean.hash = true;
459 511 for_each_net(net)
460 pr_debug("icmp_reply_translation: translating error %p manip %u " 512 nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
461 "dir %s\n", skb, manip, 513 synchronize_rcu();
462 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
463
464 /* Change inner back to look like incoming packet. We do the
465 opposite manip on this hook to normal, because it might not
466 pass all hooks (locally-generated ICMP). Consider incoming
467 packet: PREROUTING (DST manip), routing produces ICMP, goes
468 through POSTROUTING (which must correct the DST manip). */
469 if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp),
470 &ct->tuplehash[!dir].tuple, !manip))
471 return 0;
472 514
473 if (skb->ip_summed != CHECKSUM_PARTIAL) { 515 /* Step 2 - clean NAT section */
474 /* Reloading "inside" here since manip_pkt inner. */ 516 clean.hash = false;
475 inside = (void *)skb->data + hdrlen; 517 for_each_net(net)
476 inside->icmp.checksum = 0; 518 nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
477 inside->icmp.checksum = 519 rtnl_unlock();
478 csum_fold(skb_checksum(skb, hdrlen, 520}
479 skb->len - hdrlen, 0));
480 }
481 521
482 /* Change outer to look the reply to an incoming packet 522static void nf_nat_l3proto_clean(u8 l3proto)
483 * (proto 0 means don't invert per-proto part). */ 523{
484 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 524 struct nf_nat_proto_clean clean = {
485 if (!manip_pkt(0, skb, 0, &target, manip)) 525 .l3proto = l3proto,
486 return 0; 526 };
527 struct net *net;
528
529 rtnl_lock();
530 /* Step 1 - remove from bysource hash */
531 clean.hash = true;
532 for_each_net(net)
533 nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
534 synchronize_rcu();
487 535
488 return 1; 536 /* Step 2 - clean NAT section */
537 clean.hash = false;
538 for_each_net(net)
539 nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
540 rtnl_unlock();
489} 541}
490EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
491 542
492/* Protocol registration. */ 543/* Protocol registration. */
493int nf_nat_protocol_register(const struct nf_nat_protocol *proto) 544int nf_nat_l4proto_register(u8 l3proto, const struct nf_nat_l4proto *l4proto)
494{ 545{
546 const struct nf_nat_l4proto **l4protos;
547 unsigned int i;
495 int ret = 0; 548 int ret = 0;
496 549
497 spin_lock_bh(&nf_nat_lock); 550 mutex_lock(&nf_nat_proto_mutex);
551 if (nf_nat_l4protos[l3proto] == NULL) {
552 l4protos = kmalloc(IPPROTO_MAX * sizeof(struct nf_nat_l4proto *),
553 GFP_KERNEL);
554 if (l4protos == NULL) {
555 ret = -ENOMEM;
556 goto out;
557 }
558
559 for (i = 0; i < IPPROTO_MAX; i++)
560 RCU_INIT_POINTER(l4protos[i], &nf_nat_l4proto_unknown);
561
562 /* Before making proto_array visible to lockless readers,
563 * we must make sure its content is committed to memory.
564 */
565 smp_wmb();
566
567 nf_nat_l4protos[l3proto] = l4protos;
568 }
569
498 if (rcu_dereference_protected( 570 if (rcu_dereference_protected(
499 nf_nat_protos[proto->protonum], 571 nf_nat_l4protos[l3proto][l4proto->l4proto],
500 lockdep_is_held(&nf_nat_lock) 572 lockdep_is_held(&nf_nat_proto_mutex)
501 ) != &nf_nat_unknown_protocol) { 573 ) != &nf_nat_l4proto_unknown) {
502 ret = -EBUSY; 574 ret = -EBUSY;
503 goto out; 575 goto out;
504 } 576 }
505 RCU_INIT_POINTER(nf_nat_protos[proto->protonum], proto); 577 RCU_INIT_POINTER(nf_nat_l4protos[l3proto][l4proto->l4proto], l4proto);
506 out: 578 out:
507 spin_unlock_bh(&nf_nat_lock); 579 mutex_unlock(&nf_nat_proto_mutex);
508 return ret; 580 return ret;
509} 581}
510EXPORT_SYMBOL(nf_nat_protocol_register); 582EXPORT_SYMBOL_GPL(nf_nat_l4proto_register);
511 583
512/* No one stores the protocol anywhere; simply delete it. */ 584/* No one stores the protocol anywhere; simply delete it. */
513void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto) 585void nf_nat_l4proto_unregister(u8 l3proto, const struct nf_nat_l4proto *l4proto)
514{ 586{
515 spin_lock_bh(&nf_nat_lock); 587 mutex_lock(&nf_nat_proto_mutex);
516 RCU_INIT_POINTER(nf_nat_protos[proto->protonum], 588 RCU_INIT_POINTER(nf_nat_l4protos[l3proto][l4proto->l4proto],
517 &nf_nat_unknown_protocol); 589 &nf_nat_l4proto_unknown);
518 spin_unlock_bh(&nf_nat_lock); 590 mutex_unlock(&nf_nat_proto_mutex);
519 synchronize_rcu(); 591 synchronize_rcu();
592
593 nf_nat_l4proto_clean(l3proto, l4proto->l4proto);
520} 594}
521EXPORT_SYMBOL(nf_nat_protocol_unregister); 595EXPORT_SYMBOL_GPL(nf_nat_l4proto_unregister);
596
597int nf_nat_l3proto_register(const struct nf_nat_l3proto *l3proto)
598{
599 int err;
600
601 err = nf_ct_l3proto_try_module_get(l3proto->l3proto);
602 if (err < 0)
603 return err;
604
605 mutex_lock(&nf_nat_proto_mutex);
606 RCU_INIT_POINTER(nf_nat_l4protos[l3proto->l3proto][IPPROTO_TCP],
607 &nf_nat_l4proto_tcp);
608 RCU_INIT_POINTER(nf_nat_l4protos[l3proto->l3proto][IPPROTO_UDP],
609 &nf_nat_l4proto_udp);
610 mutex_unlock(&nf_nat_proto_mutex);
611
612 RCU_INIT_POINTER(nf_nat_l3protos[l3proto->l3proto], l3proto);
613 return 0;
614}
615EXPORT_SYMBOL_GPL(nf_nat_l3proto_register);
616
617void nf_nat_l3proto_unregister(const struct nf_nat_l3proto *l3proto)
618{
619 mutex_lock(&nf_nat_proto_mutex);
620 RCU_INIT_POINTER(nf_nat_l3protos[l3proto->l3proto], NULL);
621 mutex_unlock(&nf_nat_proto_mutex);
622 synchronize_rcu();
623
624 nf_nat_l3proto_clean(l3proto->l3proto);
625 nf_ct_l3proto_module_put(l3proto->l3proto);
626}
627EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregister);
522 628
523/* No one using conntrack by the time this called. */ 629/* No one using conntrack by the time this called. */
524static void nf_nat_cleanup_conntrack(struct nf_conn *ct) 630static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
@@ -570,34 +676,34 @@ static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
570 676
571static int nfnetlink_parse_nat_proto(struct nlattr *attr, 677static int nfnetlink_parse_nat_proto(struct nlattr *attr,
572 const struct nf_conn *ct, 678 const struct nf_conn *ct,
573 struct nf_nat_ipv4_range *range) 679 struct nf_nat_range *range)
574{ 680{
575 struct nlattr *tb[CTA_PROTONAT_MAX+1]; 681 struct nlattr *tb[CTA_PROTONAT_MAX+1];
576 const struct nf_nat_protocol *npt; 682 const struct nf_nat_l4proto *l4proto;
577 int err; 683 int err;
578 684
579 err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy); 685 err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
580 if (err < 0) 686 if (err < 0)
581 return err; 687 return err;
582 688
583 rcu_read_lock(); 689 l4proto = __nf_nat_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
584 npt = __nf_nat_proto_find(nf_ct_protonum(ct)); 690 if (l4proto->nlattr_to_range)
585 if (npt->nlattr_to_range) 691 err = l4proto->nlattr_to_range(tb, range);
586 err = npt->nlattr_to_range(tb, range); 692
587 rcu_read_unlock();
588 return err; 693 return err;
589} 694}
590 695
591static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = { 696static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
592 [CTA_NAT_MINIP] = { .type = NLA_U32 }, 697 [CTA_NAT_V4_MINIP] = { .type = NLA_U32 },
593 [CTA_NAT_MAXIP] = { .type = NLA_U32 }, 698 [CTA_NAT_V4_MAXIP] = { .type = NLA_U32 },
594 [CTA_NAT_PROTO] = { .type = NLA_NESTED }, 699 [CTA_NAT_PROTO] = { .type = NLA_NESTED },
595}; 700};
596 701
597static int 702static int
598nfnetlink_parse_nat(const struct nlattr *nat, 703nfnetlink_parse_nat(const struct nlattr *nat,
599 const struct nf_conn *ct, struct nf_nat_ipv4_range *range) 704 const struct nf_conn *ct, struct nf_nat_range *range)
600{ 705{
706 const struct nf_nat_l3proto *l3proto;
601 struct nlattr *tb[CTA_NAT_MAX+1]; 707 struct nlattr *tb[CTA_NAT_MAX+1];
602 int err; 708 int err;
603 709
@@ -607,25 +713,23 @@ nfnetlink_parse_nat(const struct nlattr *nat,
607 if (err < 0) 713 if (err < 0)
608 return err; 714 return err;
609 715
610 if (tb[CTA_NAT_MINIP]) 716 rcu_read_lock();
611 range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]); 717 l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
612 718 if (l3proto == NULL) {
613 if (!tb[CTA_NAT_MAXIP]) 719 err = -EAGAIN;
614 range->max_ip = range->min_ip; 720 goto out;
615 else 721 }
616 range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]); 722 err = l3proto->nlattr_to_range(tb, range);
617 723 if (err < 0)
618 if (range->min_ip) 724 goto out;
619 range->flags |= NF_NAT_RANGE_MAP_IPS;
620 725
621 if (!tb[CTA_NAT_PROTO]) 726 if (!tb[CTA_NAT_PROTO])
622 return 0; 727 goto out;
623 728
624 err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range); 729 err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
625 if (err < 0) 730out:
626 return err; 731 rcu_read_unlock();
627 732 return err;
628 return 0;
629} 733}
630 734
631static int 735static int
@@ -633,10 +737,12 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct,
633 enum nf_nat_manip_type manip, 737 enum nf_nat_manip_type manip,
634 const struct nlattr *attr) 738 const struct nlattr *attr)
635{ 739{
636 struct nf_nat_ipv4_range range; 740 struct nf_nat_range range;
741 int err;
637 742
638 if (nfnetlink_parse_nat(attr, ct, &range) < 0) 743 err = nfnetlink_parse_nat(attr, ct, &range);
639 return -EINVAL; 744 if (err < 0)
745 return err;
640 if (nf_nat_initialized(ct, manip)) 746 if (nf_nat_initialized(ct, manip))
641 return -EEXIST; 747 return -EEXIST;
642 748
@@ -655,30 +761,20 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct,
655static int __net_init nf_nat_net_init(struct net *net) 761static int __net_init nf_nat_net_init(struct net *net)
656{ 762{
657 /* Leave them the same for the moment. */ 763 /* Leave them the same for the moment. */
658 net->ipv4.nat_htable_size = net->ct.htable_size; 764 net->ct.nat_htable_size = net->ct.htable_size;
659 net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&net->ipv4.nat_htable_size, 0); 765 net->ct.nat_bysource = nf_ct_alloc_hashtable(&net->ct.nat_htable_size, 0);
660 if (!net->ipv4.nat_bysource) 766 if (!net->ct.nat_bysource)
661 return -ENOMEM; 767 return -ENOMEM;
662 return 0; 768 return 0;
663} 769}
664 770
665/* Clear NAT section of all conntracks, in case we're loaded again. */
666static int clean_nat(struct nf_conn *i, void *data)
667{
668 struct nf_conn_nat *nat = nfct_nat(i);
669
670 if (!nat)
671 return 0;
672 memset(nat, 0, sizeof(*nat));
673 i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
674 return 0;
675}
676
677static void __net_exit nf_nat_net_exit(struct net *net) 771static void __net_exit nf_nat_net_exit(struct net *net)
678{ 772{
679 nf_ct_iterate_cleanup(net, &clean_nat, NULL); 773 struct nf_nat_proto_clean clean = {};
774
775 nf_ct_iterate_cleanup(net, &nf_nat_proto_clean, &clean);
680 synchronize_rcu(); 776 synchronize_rcu();
681 nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_htable_size); 777 nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size);
682} 778}
683 779
684static struct pernet_operations nf_nat_net_ops = { 780static struct pernet_operations nf_nat_net_ops = {
@@ -697,11 +793,8 @@ static struct nfq_ct_nat_hook nfq_ct_nat = {
697 793
698static int __init nf_nat_init(void) 794static int __init nf_nat_init(void)
699{ 795{
700 size_t i;
701 int ret; 796 int ret;
702 797
703 need_ipv4_conntrack();
704
705 ret = nf_ct_extend_register(&nat_extend); 798 ret = nf_ct_extend_register(&nat_extend);
706 if (ret < 0) { 799 if (ret < 0) {
707 printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); 800 printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
@@ -712,22 +805,11 @@ static int __init nf_nat_init(void)
712 if (ret < 0) 805 if (ret < 0)
713 goto cleanup_extend; 806 goto cleanup_extend;
714 807
715 /* Sew in builtin protocols. */ 808 nf_ct_helper_expectfn_register(&follow_master_nat);
716 spin_lock_bh(&nf_nat_lock);
717 for (i = 0; i < MAX_IP_NAT_PROTO; i++)
718 RCU_INIT_POINTER(nf_nat_protos[i], &nf_nat_unknown_protocol);
719 RCU_INIT_POINTER(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
720 RCU_INIT_POINTER(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
721 RCU_INIT_POINTER(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
722 spin_unlock_bh(&nf_nat_lock);
723 809
724 /* Initialize fake conntrack so that NAT will skip it */ 810 /* Initialize fake conntrack so that NAT will skip it */
725 nf_ct_untracked_status_or(IPS_NAT_DONE_MASK); 811 nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
726 812
727 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
728
729 nf_ct_helper_expectfn_register(&follow_master_nat);
730
731 BUG_ON(nf_nat_seq_adjust_hook != NULL); 813 BUG_ON(nf_nat_seq_adjust_hook != NULL);
732 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); 814 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
733 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); 815 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
@@ -736,6 +818,10 @@ static int __init nf_nat_init(void)
736 BUG_ON(nf_ct_nat_offset != NULL); 818 BUG_ON(nf_ct_nat_offset != NULL);
737 RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset); 819 RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset);
738 RCU_INIT_POINTER(nfq_ct_nat_hook, &nfq_ct_nat); 820 RCU_INIT_POINTER(nfq_ct_nat_hook, &nfq_ct_nat);
821#ifdef CONFIG_XFRM
822 BUG_ON(nf_nat_decode_session_hook != NULL);
823 RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session);
824#endif
739 return 0; 825 return 0;
740 826
741 cleanup_extend: 827 cleanup_extend:
@@ -745,19 +831,24 @@ static int __init nf_nat_init(void)
745 831
746static void __exit nf_nat_cleanup(void) 832static void __exit nf_nat_cleanup(void)
747{ 833{
834 unsigned int i;
835
748 unregister_pernet_subsys(&nf_nat_net_ops); 836 unregister_pernet_subsys(&nf_nat_net_ops);
749 nf_ct_l3proto_put(l3proto);
750 nf_ct_extend_unregister(&nat_extend); 837 nf_ct_extend_unregister(&nat_extend);
751 nf_ct_helper_expectfn_unregister(&follow_master_nat); 838 nf_ct_helper_expectfn_unregister(&follow_master_nat);
752 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); 839 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL);
753 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); 840 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
754 RCU_INIT_POINTER(nf_ct_nat_offset, NULL); 841 RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
755 RCU_INIT_POINTER(nfq_ct_nat_hook, NULL); 842 RCU_INIT_POINTER(nfq_ct_nat_hook, NULL);
843#ifdef CONFIG_XFRM
844 RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL);
845#endif
846 for (i = 0; i < NFPROTO_NUMPROTO; i++)
847 kfree(nf_nat_l4protos[i]);
756 synchronize_net(); 848 synchronize_net();
757} 849}
758 850
759MODULE_LICENSE("GPL"); 851MODULE_LICENSE("GPL");
760MODULE_ALIAS("nf-nat-ipv4");
761 852
762module_init(nf_nat_init); 853module_init(nf_nat_init);
763module_exit(nf_nat_cleanup); 854module_exit(nf_nat_cleanup);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c
index 2fefec5e757..23c2b38676a 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/netfilter/nf_nat_helper.c
@@ -1,4 +1,4 @@
1/* ip_nat_helper.c - generic support functions for NAT helpers 1/* nf_nat_helper.c - generic support functions for NAT helpers
2 * 2 *
3 * (C) 2000-2002 Harald Welte <laforge@netfilter.org> 3 * (C) 2000-2002 Harald Welte <laforge@netfilter.org>
4 * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org> 4 * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org>
@@ -9,23 +9,19 @@
9 */ 9 */
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/gfp.h> 11#include <linux/gfp.h>
12#include <linux/kmod.h>
13#include <linux/types.h> 12#include <linux/types.h>
14#include <linux/timer.h>
15#include <linux/skbuff.h> 13#include <linux/skbuff.h>
16#include <linux/tcp.h> 14#include <linux/tcp.h>
17#include <linux/udp.h> 15#include <linux/udp.h>
18#include <net/checksum.h>
19#include <net/tcp.h> 16#include <net/tcp.h>
20#include <net/route.h>
21 17
22#include <linux/netfilter_ipv4.h>
23#include <net/netfilter/nf_conntrack.h> 18#include <net/netfilter/nf_conntrack.h>
24#include <net/netfilter/nf_conntrack_helper.h> 19#include <net/netfilter/nf_conntrack_helper.h>
25#include <net/netfilter/nf_conntrack_ecache.h> 20#include <net/netfilter/nf_conntrack_ecache.h>
26#include <net/netfilter/nf_conntrack_expect.h> 21#include <net/netfilter/nf_conntrack_expect.h>
27#include <net/netfilter/nf_nat.h> 22#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/nf_nat_protocol.h> 23#include <net/netfilter/nf_nat_l3proto.h>
24#include <net/netfilter/nf_nat_l4proto.h>
29#include <net/netfilter/nf_nat_core.h> 25#include <net/netfilter/nf_nat_core.h>
30#include <net/netfilter/nf_nat_helper.h> 26#include <net/netfilter/nf_nat_helper.h>
31 27
@@ -90,7 +86,6 @@ s16 nf_nat_get_offset(const struct nf_conn *ct,
90 86
91 return offset; 87 return offset;
92} 88}
93EXPORT_SYMBOL_GPL(nf_nat_get_offset);
94 89
95/* Frobs data inside this packet, which is linear. */ 90/* Frobs data inside this packet, which is linear. */
96static void mangle_contents(struct sk_buff *skb, 91static void mangle_contents(struct sk_buff *skb,
@@ -125,9 +120,13 @@ static void mangle_contents(struct sk_buff *skb,
125 __skb_trim(skb, skb->len + rep_len - match_len); 120 __skb_trim(skb, skb->len + rep_len - match_len);
126 } 121 }
127 122
128 /* fix IP hdr checksum information */ 123 if (nf_ct_l3num((struct nf_conn *)skb->nfct) == NFPROTO_IPV4) {
129 ip_hdr(skb)->tot_len = htons(skb->len); 124 /* fix IP hdr checksum information */
130 ip_send_check(ip_hdr(skb)); 125 ip_hdr(skb)->tot_len = htons(skb->len);
126 ip_send_check(ip_hdr(skb));
127 } else
128 ipv6_hdr(skb)->payload_len =
129 htons(skb->len - sizeof(struct ipv6hdr));
131} 130}
132 131
133/* Unusual, but possible case. */ 132/* Unusual, but possible case. */
@@ -166,35 +165,6 @@ void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
166} 165}
167EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust); 166EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust);
168 167
169static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data,
170 int datalen, __sum16 *check, int oldlen)
171{
172 struct rtable *rt = skb_rtable(skb);
173
174 if (skb->ip_summed != CHECKSUM_PARTIAL) {
175 if (!(rt->rt_flags & RTCF_LOCAL) &&
176 (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
177 skb->ip_summed = CHECKSUM_PARTIAL;
178 skb->csum_start = skb_headroom(skb) +
179 skb_network_offset(skb) +
180 iph->ihl * 4;
181 skb->csum_offset = (void *)check - data;
182 *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
183 datalen, iph->protocol, 0);
184 } else {
185 *check = 0;
186 *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
187 datalen, iph->protocol,
188 csum_partial(data, datalen,
189 0));
190 if (iph->protocol == IPPROTO_UDP && !*check)
191 *check = CSUM_MANGLED_0;
192 }
193 } else
194 inet_proto_csum_replace2(check, skb,
195 htons(oldlen), htons(datalen), 1);
196}
197
198/* Generic function for mangling variable-length address changes inside 168/* Generic function for mangling variable-length address changes inside
199 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX 169 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
200 * command in FTP). 170 * command in FTP).
@@ -212,7 +182,7 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
212 const char *rep_buffer, 182 const char *rep_buffer,
213 unsigned int rep_len, bool adjust) 183 unsigned int rep_len, bool adjust)
214{ 184{
215 struct iphdr *iph; 185 const struct nf_nat_l3proto *l3proto;
216 struct tcphdr *tcph; 186 struct tcphdr *tcph;
217 int oldlen, datalen; 187 int oldlen, datalen;
218 188
@@ -226,15 +196,17 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
226 196
227 SKB_LINEAR_ASSERT(skb); 197 SKB_LINEAR_ASSERT(skb);
228 198
229 iph = ip_hdr(skb); 199 tcph = (void *)skb->data + protoff;
230 tcph = (void *)iph + iph->ihl*4;
231 200
232 oldlen = skb->len - iph->ihl*4; 201 oldlen = skb->len - protoff;
233 mangle_contents(skb, iph->ihl*4 + tcph->doff*4, 202 mangle_contents(skb, protoff + tcph->doff*4,
234 match_offset, match_len, rep_buffer, rep_len); 203 match_offset, match_len, rep_buffer, rep_len);
235 204
236 datalen = skb->len - iph->ihl*4; 205 datalen = skb->len - protoff;
237 nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen); 206
207 l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
208 l3proto->csum_recalc(skb, IPPROTO_TCP, tcph, &tcph->check,
209 datalen, oldlen);
238 210
239 if (adjust && rep_len != match_len) 211 if (adjust && rep_len != match_len)
240 nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq, 212 nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
@@ -264,7 +236,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
264 const char *rep_buffer, 236 const char *rep_buffer,
265 unsigned int rep_len) 237 unsigned int rep_len)
266{ 238{
267 struct iphdr *iph; 239 const struct nf_nat_l3proto *l3proto;
268 struct udphdr *udph; 240 struct udphdr *udph;
269 int datalen, oldlen; 241 int datalen, oldlen;
270 242
@@ -276,22 +248,23 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
276 !enlarge_skb(skb, rep_len - match_len)) 248 !enlarge_skb(skb, rep_len - match_len))
277 return 0; 249 return 0;
278 250
279 iph = ip_hdr(skb); 251 udph = (void *)skb->data + protoff;
280 udph = (void *)iph + iph->ihl*4;
281 252
282 oldlen = skb->len - iph->ihl*4; 253 oldlen = skb->len - protoff;
283 mangle_contents(skb, iph->ihl*4 + sizeof(*udph), 254 mangle_contents(skb, protoff + sizeof(*udph),
284 match_offset, match_len, rep_buffer, rep_len); 255 match_offset, match_len, rep_buffer, rep_len);
285 256
286 /* update the length of the UDP packet */ 257 /* update the length of the UDP packet */
287 datalen = skb->len - iph->ihl*4; 258 datalen = skb->len - protoff;
288 udph->len = htons(datalen); 259 udph->len = htons(datalen);
289 260
290 /* fix udp checksum if udp checksum was previously calculated */ 261 /* fix udp checksum if udp checksum was previously calculated */
291 if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL) 262 if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
292 return 1; 263 return 1;
293 264
294 nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen); 265 l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
266 l3proto->csum_recalc(skb, IPPROTO_UDP, udph, &udph->check,
267 datalen, oldlen);
295 268
296 return 1; 269 return 1;
297} 270}
@@ -343,6 +316,7 @@ sack_adjust(struct sk_buff *skb,
343/* TCP SACK sequence number adjustment */ 316/* TCP SACK sequence number adjustment */
344static inline unsigned int 317static inline unsigned int
345nf_nat_sack_adjust(struct sk_buff *skb, 318nf_nat_sack_adjust(struct sk_buff *skb,
319 unsigned int protoff,
346 struct tcphdr *tcph, 320 struct tcphdr *tcph,
347 struct nf_conn *ct, 321 struct nf_conn *ct,
348 enum ip_conntrack_info ctinfo) 322 enum ip_conntrack_info ctinfo)
@@ -350,8 +324,8 @@ nf_nat_sack_adjust(struct sk_buff *skb,
350 unsigned int dir, optoff, optend; 324 unsigned int dir, optoff, optend;
351 struct nf_conn_nat *nat = nfct_nat(ct); 325 struct nf_conn_nat *nat = nfct_nat(ct);
352 326
353 optoff = ip_hdrlen(skb) + sizeof(struct tcphdr); 327 optoff = protoff + sizeof(struct tcphdr);
354 optend = ip_hdrlen(skb) + tcph->doff * 4; 328 optend = protoff + tcph->doff * 4;
355 329
356 if (!skb_make_writable(skb, optend)) 330 if (!skb_make_writable(skb, optend))
357 return 0; 331 return 0;
@@ -432,7 +406,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
432 tcph->seq = newseq; 406 tcph->seq = newseq;
433 tcph->ack_seq = newack; 407 tcph->ack_seq = newack;
434 408
435 return nf_nat_sack_adjust(skb, tcph, ct, ctinfo); 409 return nf_nat_sack_adjust(skb, protoff, tcph, ct, ctinfo);
436} 410}
437 411
438/* Setup NAT on this expected conntrack so it follows master. */ 412/* Setup NAT on this expected conntrack so it follows master. */
@@ -440,22 +414,22 @@ nf_nat_seq_adjust(struct sk_buff *skb,
440void nf_nat_follow_master(struct nf_conn *ct, 414void nf_nat_follow_master(struct nf_conn *ct,
441 struct nf_conntrack_expect *exp) 415 struct nf_conntrack_expect *exp)
442{ 416{
443 struct nf_nat_ipv4_range range; 417 struct nf_nat_range range;
444 418
445 /* This must be a fresh one. */ 419 /* This must be a fresh one. */
446 BUG_ON(ct->status & IPS_NAT_DONE_MASK); 420 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
447 421
448 /* Change src to where master sends to */ 422 /* Change src to where master sends to */
449 range.flags = NF_NAT_RANGE_MAP_IPS; 423 range.flags = NF_NAT_RANGE_MAP_IPS;
450 range.min_ip = range.max_ip 424 range.min_addr = range.max_addr
451 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 425 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
452 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); 426 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
453 427
454 /* For DST manip, map port here to where it's expected. */ 428 /* For DST manip, map port here to where it's expected. */
455 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 429 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
456 range.min = range.max = exp->saved_proto; 430 range.min_proto = range.max_proto = exp->saved_proto;
457 range.min_ip = range.max_ip 431 range.min_addr = range.max_addr
458 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; 432 = ct->master->tuplehash[!exp->dir].tuple.src.u3;
459 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); 433 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
460} 434}
461EXPORT_SYMBOL(nf_nat_follow_master); 435EXPORT_SYMBOL(nf_nat_follow_master);
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c
index 9993bc93e10..9baaf734c14 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/netfilter/nf_nat_proto_common.c
@@ -9,20 +9,18 @@
9 9
10#include <linux/types.h> 10#include <linux/types.h>
11#include <linux/random.h> 11#include <linux/random.h>
12#include <linux/ip.h>
13
14#include <linux/netfilter.h> 12#include <linux/netfilter.h>
15#include <linux/export.h> 13#include <linux/export.h>
16#include <net/secure_seq.h> 14
17#include <net/netfilter/nf_nat.h> 15#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_core.h> 16#include <net/netfilter/nf_nat_core.h>
19#include <net/netfilter/nf_nat_rule.h> 17#include <net/netfilter/nf_nat_l3proto.h>
20#include <net/netfilter/nf_nat_protocol.h> 18#include <net/netfilter/nf_nat_l4proto.h>
21 19
22bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, 20bool nf_nat_l4proto_in_range(const struct nf_conntrack_tuple *tuple,
23 enum nf_nat_manip_type maniptype, 21 enum nf_nat_manip_type maniptype,
24 const union nf_conntrack_man_proto *min, 22 const union nf_conntrack_man_proto *min,
25 const union nf_conntrack_man_proto *max) 23 const union nf_conntrack_man_proto *max)
26{ 24{
27 __be16 port; 25 __be16 port;
28 26
@@ -34,13 +32,14 @@ bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple,
34 return ntohs(port) >= ntohs(min->all) && 32 return ntohs(port) >= ntohs(min->all) &&
35 ntohs(port) <= ntohs(max->all); 33 ntohs(port) <= ntohs(max->all);
36} 34}
37EXPORT_SYMBOL_GPL(nf_nat_proto_in_range); 35EXPORT_SYMBOL_GPL(nf_nat_l4proto_in_range);
38 36
39void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, 37void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,
40 const struct nf_nat_ipv4_range *range, 38 struct nf_conntrack_tuple *tuple,
41 enum nf_nat_manip_type maniptype, 39 const struct nf_nat_range *range,
42 const struct nf_conn *ct, 40 enum nf_nat_manip_type maniptype,
43 u_int16_t *rover) 41 const struct nf_conn *ct,
42 u16 *rover)
44{ 43{
45 unsigned int range_size, min, i; 44 unsigned int range_size, min, i;
46 __be16 *portptr; 45 __be16 *portptr;
@@ -71,15 +70,14 @@ void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
71 range_size = 65535 - 1024 + 1; 70 range_size = 65535 - 1024 + 1;
72 } 71 }
73 } else { 72 } else {
74 min = ntohs(range->min.all); 73 min = ntohs(range->min_proto.all);
75 range_size = ntohs(range->max.all) - min + 1; 74 range_size = ntohs(range->max_proto.all) - min + 1;
76 } 75 }
77 76
78 if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) 77 if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
79 off = secure_ipv4_port_ephemeral(tuple->src.u3.ip, tuple->dst.u3.ip, 78 off = l3proto->secure_port(tuple, maniptype == NF_NAT_MANIP_SRC
80 maniptype == NF_NAT_MANIP_SRC 79 ? tuple->dst.u.all
81 ? tuple->dst.u.all 80 : tuple->src.u.all);
82 : tuple->src.u.all);
83 else 81 else
84 off = *rover; 82 off = *rover;
85 83
@@ -93,22 +91,22 @@ void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
93 } 91 }
94 return; 92 return;
95} 93}
96EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); 94EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple);
97 95
98#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 96#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
99int nf_nat_proto_nlattr_to_range(struct nlattr *tb[], 97int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[],
100 struct nf_nat_ipv4_range *range) 98 struct nf_nat_range *range)
101{ 99{
102 if (tb[CTA_PROTONAT_PORT_MIN]) { 100 if (tb[CTA_PROTONAT_PORT_MIN]) {
103 range->min.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]); 101 range->min_proto.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]);
104 range->max.all = range->min.tcp.port; 102 range->max_proto.all = range->min_proto.all;
105 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 103 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
106 } 104 }
107 if (tb[CTA_PROTONAT_PORT_MAX]) { 105 if (tb[CTA_PROTONAT_PORT_MAX]) {
108 range->max.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]); 106 range->max_proto.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]);
109 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 107 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
110 } 108 }
111 return 0; 109 return 0;
112} 110}
113EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range); 111EXPORT_SYMBOL_GPL(nf_nat_l4proto_nlattr_to_range);
114#endif 112#endif
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/netfilter/nf_nat_proto_dccp.c
index 3f67138d187..c8be2cdac0b 100644
--- a/net/ipv4/netfilter/nf_nat_proto_dccp.c
+++ b/net/netfilter/nf_nat_proto_dccp.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * DCCP NAT protocol helper 2 * DCCP NAT protocol helper
3 * 3 *
4 * Copyright (c) 2005, 2006. 2008 Patrick McHardy <kaber@trash.net> 4 * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 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 7 * it under the terms of the GNU General Public License version 2 as
@@ -13,35 +13,34 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/skbuff.h> 15#include <linux/skbuff.h>
16#include <linux/ip.h>
17#include <linux/dccp.h> 16#include <linux/dccp.h>
18 17
19#include <net/netfilter/nf_conntrack.h> 18#include <net/netfilter/nf_conntrack.h>
20#include <net/netfilter/nf_nat.h> 19#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_protocol.h> 20#include <net/netfilter/nf_nat_l3proto.h>
21#include <net/netfilter/nf_nat_l4proto.h>
22 22
23static u_int16_t dccp_port_rover; 23static u_int16_t dccp_port_rover;
24 24
25static void 25static void
26dccp_unique_tuple(struct nf_conntrack_tuple *tuple, 26dccp_unique_tuple(const struct nf_nat_l3proto *l3proto,
27 const struct nf_nat_ipv4_range *range, 27 struct nf_conntrack_tuple *tuple,
28 const struct nf_nat_range *range,
28 enum nf_nat_manip_type maniptype, 29 enum nf_nat_manip_type maniptype,
29 const struct nf_conn *ct) 30 const struct nf_conn *ct)
30{ 31{
31 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, 32 nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
32 &dccp_port_rover); 33 &dccp_port_rover);
33} 34}
34 35
35static bool 36static bool
36dccp_manip_pkt(struct sk_buff *skb, 37dccp_manip_pkt(struct sk_buff *skb,
37 unsigned int iphdroff, 38 const struct nf_nat_l3proto *l3proto,
39 unsigned int iphdroff, unsigned int hdroff,
38 const struct nf_conntrack_tuple *tuple, 40 const struct nf_conntrack_tuple *tuple,
39 enum nf_nat_manip_type maniptype) 41 enum nf_nat_manip_type maniptype)
40{ 42{
41 const struct iphdr *iph = (const void *)(skb->data + iphdroff);
42 struct dccp_hdr *hdr; 43 struct dccp_hdr *hdr;
43 unsigned int hdroff = iphdroff + iph->ihl * 4;
44 __be32 oldip, newip;
45 __be16 *portptr, oldport, newport; 44 __be16 *portptr, oldport, newport;
46 int hdrsize = 8; /* DCCP connection tracking guarantees this much */ 45 int hdrsize = 8; /* DCCP connection tracking guarantees this much */
47 46
@@ -51,17 +50,12 @@ dccp_manip_pkt(struct sk_buff *skb,
51 if (!skb_make_writable(skb, hdroff + hdrsize)) 50 if (!skb_make_writable(skb, hdroff + hdrsize))
52 return false; 51 return false;
53 52
54 iph = (struct iphdr *)(skb->data + iphdroff);
55 hdr = (struct dccp_hdr *)(skb->data + hdroff); 53 hdr = (struct dccp_hdr *)(skb->data + hdroff);
56 54
57 if (maniptype == NF_NAT_MANIP_SRC) { 55 if (maniptype == NF_NAT_MANIP_SRC) {
58 oldip = iph->saddr;
59 newip = tuple->src.u3.ip;
60 newport = tuple->src.u.dccp.port; 56 newport = tuple->src.u.dccp.port;
61 portptr = &hdr->dccph_sport; 57 portptr = &hdr->dccph_sport;
62 } else { 58 } else {
63 oldip = iph->daddr;
64 newip = tuple->dst.u3.ip;
65 newport = tuple->dst.u.dccp.port; 59 newport = tuple->dst.u.dccp.port;
66 portptr = &hdr->dccph_dport; 60 portptr = &hdr->dccph_dport;
67 } 61 }
@@ -72,30 +66,46 @@ dccp_manip_pkt(struct sk_buff *skb,
72 if (hdrsize < sizeof(*hdr)) 66 if (hdrsize < sizeof(*hdr))
73 return true; 67 return true;
74 68
75 inet_proto_csum_replace4(&hdr->dccph_checksum, skb, oldip, newip, 1); 69 l3proto->csum_update(skb, iphdroff, &hdr->dccph_checksum,
70 tuple, maniptype);
76 inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport, 71 inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport,
77 0); 72 0);
78 return true; 73 return true;
79} 74}
80 75
81static const struct nf_nat_protocol nf_nat_protocol_dccp = { 76static const struct nf_nat_l4proto nf_nat_l4proto_dccp = {
82 .protonum = IPPROTO_DCCP, 77 .l4proto = IPPROTO_DCCP,
83 .manip_pkt = dccp_manip_pkt, 78 .manip_pkt = dccp_manip_pkt,
84 .in_range = nf_nat_proto_in_range, 79 .in_range = nf_nat_l4proto_in_range,
85 .unique_tuple = dccp_unique_tuple, 80 .unique_tuple = dccp_unique_tuple,
86#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 81#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
87 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 82 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
88#endif 83#endif
89}; 84};
90 85
91static int __init nf_nat_proto_dccp_init(void) 86static int __init nf_nat_proto_dccp_init(void)
92{ 87{
93 return nf_nat_protocol_register(&nf_nat_protocol_dccp); 88 int err;
89
90 err = nf_nat_l4proto_register(NFPROTO_IPV4, &nf_nat_l4proto_dccp);
91 if (err < 0)
92 goto err1;
93 err = nf_nat_l4proto_register(NFPROTO_IPV6, &nf_nat_l4proto_dccp);
94 if (err < 0)
95 goto err2;
96 return 0;
97
98err2:
99 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_dccp);
100err1:
101 return err;
94} 102}
95 103
96static void __exit nf_nat_proto_dccp_fini(void) 104static void __exit nf_nat_proto_dccp_fini(void)
97{ 105{
98 nf_nat_protocol_unregister(&nf_nat_protocol_dccp); 106 nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_dccp);
107 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_dccp);
108
99} 109}
100 110
101module_init(nf_nat_proto_dccp_init); 111module_init(nf_nat_proto_dccp_init);
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/netfilter/nf_nat_proto_sctp.c
index 3cce9b6c1c2..e64faa5ca89 100644
--- a/net/ipv4/netfilter/nf_nat_proto_sctp.c
+++ b/net/netfilter/nf_nat_proto_sctp.c
@@ -8,53 +8,46 @@
8 8
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/init.h> 10#include <linux/init.h>
11#include <linux/ip.h>
12#include <linux/sctp.h> 11#include <linux/sctp.h>
13#include <linux/module.h> 12#include <linux/module.h>
14#include <net/sctp/checksum.h> 13#include <net/sctp/checksum.h>
15 14
16#include <net/netfilter/nf_nat_protocol.h> 15#include <net/netfilter/nf_nat_l4proto.h>
17 16
18static u_int16_t nf_sctp_port_rover; 17static u_int16_t nf_sctp_port_rover;
19 18
20static void 19static void
21sctp_unique_tuple(struct nf_conntrack_tuple *tuple, 20sctp_unique_tuple(const struct nf_nat_l3proto *l3proto,
22 const struct nf_nat_ipv4_range *range, 21 struct nf_conntrack_tuple *tuple,
22 const struct nf_nat_range *range,
23 enum nf_nat_manip_type maniptype, 23 enum nf_nat_manip_type maniptype,
24 const struct nf_conn *ct) 24 const struct nf_conn *ct)
25{ 25{
26 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, 26 nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
27 &nf_sctp_port_rover); 27 &nf_sctp_port_rover);
28} 28}
29 29
30static bool 30static bool
31sctp_manip_pkt(struct sk_buff *skb, 31sctp_manip_pkt(struct sk_buff *skb,
32 unsigned int iphdroff, 32 const struct nf_nat_l3proto *l3proto,
33 unsigned int iphdroff, unsigned int hdroff,
33 const struct nf_conntrack_tuple *tuple, 34 const struct nf_conntrack_tuple *tuple,
34 enum nf_nat_manip_type maniptype) 35 enum nf_nat_manip_type maniptype)
35{ 36{
36 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
37 struct sk_buff *frag; 37 struct sk_buff *frag;
38 sctp_sctphdr_t *hdr; 38 sctp_sctphdr_t *hdr;
39 unsigned int hdroff = iphdroff + iph->ihl*4;
40 __be32 oldip, newip;
41 __be32 crc32; 39 __be32 crc32;
42 40
43 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 41 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
44 return false; 42 return false;
45 43
46 iph = (struct iphdr *)(skb->data + iphdroff);
47 hdr = (struct sctphdr *)(skb->data + hdroff); 44 hdr = (struct sctphdr *)(skb->data + hdroff);
48 45
49 if (maniptype == NF_NAT_MANIP_SRC) { 46 if (maniptype == NF_NAT_MANIP_SRC) {
50 /* Get rid of src ip and src pt */ 47 /* Get rid of src port */
51 oldip = iph->saddr;
52 newip = tuple->src.u3.ip;
53 hdr->source = tuple->src.u.sctp.port; 48 hdr->source = tuple->src.u.sctp.port;
54 } else { 49 } else {
55 /* Get rid of dst ip and dst pt */ 50 /* Get rid of dst port */
56 oldip = iph->daddr;
57 newip = tuple->dst.u3.ip;
58 hdr->dest = tuple->dst.u.sctp.port; 51 hdr->dest = tuple->dst.u.sctp.port;
59 } 52 }
60 53
@@ -68,24 +61,38 @@ sctp_manip_pkt(struct sk_buff *skb,
68 return true; 61 return true;
69} 62}
70 63
71static const struct nf_nat_protocol nf_nat_protocol_sctp = { 64static const struct nf_nat_l4proto nf_nat_l4proto_sctp = {
72 .protonum = IPPROTO_SCTP, 65 .l4proto = IPPROTO_SCTP,
73 .manip_pkt = sctp_manip_pkt, 66 .manip_pkt = sctp_manip_pkt,
74 .in_range = nf_nat_proto_in_range, 67 .in_range = nf_nat_l4proto_in_range,
75 .unique_tuple = sctp_unique_tuple, 68 .unique_tuple = sctp_unique_tuple,
76#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 69#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
77 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 70 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
78#endif 71#endif
79}; 72};
80 73
81static int __init nf_nat_proto_sctp_init(void) 74static int __init nf_nat_proto_sctp_init(void)
82{ 75{
83 return nf_nat_protocol_register(&nf_nat_protocol_sctp); 76 int err;
77
78 err = nf_nat_l4proto_register(NFPROTO_IPV4, &nf_nat_l4proto_sctp);
79 if (err < 0)
80 goto err1;
81 err = nf_nat_l4proto_register(NFPROTO_IPV6, &nf_nat_l4proto_sctp);
82 if (err < 0)
83 goto err2;
84 return 0;
85
86err2:
87 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_sctp);
88err1:
89 return err;
84} 90}
85 91
86static void __exit nf_nat_proto_sctp_exit(void) 92static void __exit nf_nat_proto_sctp_exit(void)
87{ 93{
88 nf_nat_protocol_unregister(&nf_nat_protocol_sctp); 94 nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_sctp);
95 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_sctp);
89} 96}
90 97
91module_init(nf_nat_proto_sctp_init); 98module_init(nf_nat_proto_sctp_init);
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/netfilter/nf_nat_proto_tcp.c
index 9fb4b4e72bb..83ec8a6e4c3 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/netfilter/nf_nat_proto_tcp.c
@@ -9,37 +9,36 @@
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/init.h> 10#include <linux/init.h>
11#include <linux/export.h> 11#include <linux/export.h>
12#include <linux/ip.h>
13#include <linux/tcp.h> 12#include <linux/tcp.h>
14 13
15#include <linux/netfilter.h> 14#include <linux/netfilter.h>
16#include <linux/netfilter/nfnetlink_conntrack.h> 15#include <linux/netfilter/nfnetlink_conntrack.h>
17#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_rule.h> 17#include <net/netfilter/nf_nat_l3proto.h>
19#include <net/netfilter/nf_nat_protocol.h> 18#include <net/netfilter/nf_nat_l4proto.h>
20#include <net/netfilter/nf_nat_core.h> 19#include <net/netfilter/nf_nat_core.h>
21 20
22static u_int16_t tcp_port_rover; 21static u16 tcp_port_rover;
23 22
24static void 23static void
25tcp_unique_tuple(struct nf_conntrack_tuple *tuple, 24tcp_unique_tuple(const struct nf_nat_l3proto *l3proto,
26 const struct nf_nat_ipv4_range *range, 25 struct nf_conntrack_tuple *tuple,
26 const struct nf_nat_range *range,
27 enum nf_nat_manip_type maniptype, 27 enum nf_nat_manip_type maniptype,
28 const struct nf_conn *ct) 28 const struct nf_conn *ct)
29{ 29{
30 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover); 30 nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
31 &tcp_port_rover);
31} 32}
32 33
33static bool 34static bool
34tcp_manip_pkt(struct sk_buff *skb, 35tcp_manip_pkt(struct sk_buff *skb,
35 unsigned int iphdroff, 36 const struct nf_nat_l3proto *l3proto,
37 unsigned int iphdroff, unsigned int hdroff,
36 const struct nf_conntrack_tuple *tuple, 38 const struct nf_conntrack_tuple *tuple,
37 enum nf_nat_manip_type maniptype) 39 enum nf_nat_manip_type maniptype)
38{ 40{
39 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
40 struct tcphdr *hdr; 41 struct tcphdr *hdr;
41 unsigned int hdroff = iphdroff + iph->ihl*4;
42 __be32 oldip, newip;
43 __be16 *portptr, newport, oldport; 42 __be16 *portptr, newport, oldport;
44 int hdrsize = 8; /* TCP connection tracking guarantees this much */ 43 int hdrsize = 8; /* TCP connection tracking guarantees this much */
45 44
@@ -52,19 +51,14 @@ tcp_manip_pkt(struct sk_buff *skb,
52 if (!skb_make_writable(skb, hdroff + hdrsize)) 51 if (!skb_make_writable(skb, hdroff + hdrsize))
53 return false; 52 return false;
54 53
55 iph = (struct iphdr *)(skb->data + iphdroff);
56 hdr = (struct tcphdr *)(skb->data + hdroff); 54 hdr = (struct tcphdr *)(skb->data + hdroff);
57 55
58 if (maniptype == NF_NAT_MANIP_SRC) { 56 if (maniptype == NF_NAT_MANIP_SRC) {
59 /* Get rid of src ip and src pt */ 57 /* Get rid of src port */
60 oldip = iph->saddr;
61 newip = tuple->src.u3.ip;
62 newport = tuple->src.u.tcp.port; 58 newport = tuple->src.u.tcp.port;
63 portptr = &hdr->source; 59 portptr = &hdr->source;
64 } else { 60 } else {
65 /* Get rid of dst ip and dst pt */ 61 /* Get rid of dst port */
66 oldip = iph->daddr;
67 newip = tuple->dst.u3.ip;
68 newport = tuple->dst.u.tcp.port; 62 newport = tuple->dst.u.tcp.port;
69 portptr = &hdr->dest; 63 portptr = &hdr->dest;
70 } 64 }
@@ -75,17 +69,17 @@ tcp_manip_pkt(struct sk_buff *skb,
75 if (hdrsize < sizeof(*hdr)) 69 if (hdrsize < sizeof(*hdr))
76 return true; 70 return true;
77 71
78 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1); 72 l3proto->csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
79 inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0); 73 inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0);
80 return true; 74 return true;
81} 75}
82 76
83const struct nf_nat_protocol nf_nat_protocol_tcp = { 77const struct nf_nat_l4proto nf_nat_l4proto_tcp = {
84 .protonum = IPPROTO_TCP, 78 .l4proto = IPPROTO_TCP,
85 .manip_pkt = tcp_manip_pkt, 79 .manip_pkt = tcp_manip_pkt,
86 .in_range = nf_nat_proto_in_range, 80 .in_range = nf_nat_l4proto_in_range,
87 .unique_tuple = tcp_unique_tuple, 81 .unique_tuple = tcp_unique_tuple,
88#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 82#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
89 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 83 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
90#endif 84#endif
91}; 85};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/netfilter/nf_nat_proto_udp.c
index 9883336e628..7df613fb34a 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/netfilter/nf_nat_proto_udp.c
@@ -9,59 +9,53 @@
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/export.h> 10#include <linux/export.h>
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/ip.h>
13#include <linux/udp.h> 12#include <linux/udp.h>
14 13
15#include <linux/netfilter.h> 14#include <linux/netfilter.h>
16#include <net/netfilter/nf_nat.h> 15#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_core.h> 16#include <net/netfilter/nf_nat_core.h>
18#include <net/netfilter/nf_nat_rule.h> 17#include <net/netfilter/nf_nat_l3proto.h>
19#include <net/netfilter/nf_nat_protocol.h> 18#include <net/netfilter/nf_nat_l4proto.h>
20 19
21static u_int16_t udp_port_rover; 20static u16 udp_port_rover;
22 21
23static void 22static void
24udp_unique_tuple(struct nf_conntrack_tuple *tuple, 23udp_unique_tuple(const struct nf_nat_l3proto *l3proto,
25 const struct nf_nat_ipv4_range *range, 24 struct nf_conntrack_tuple *tuple,
25 const struct nf_nat_range *range,
26 enum nf_nat_manip_type maniptype, 26 enum nf_nat_manip_type maniptype,
27 const struct nf_conn *ct) 27 const struct nf_conn *ct)
28{ 28{
29 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &udp_port_rover); 29 nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
30 &udp_port_rover);
30} 31}
31 32
32static bool 33static bool
33udp_manip_pkt(struct sk_buff *skb, 34udp_manip_pkt(struct sk_buff *skb,
34 unsigned int iphdroff, 35 const struct nf_nat_l3proto *l3proto,
36 unsigned int iphdroff, unsigned int hdroff,
35 const struct nf_conntrack_tuple *tuple, 37 const struct nf_conntrack_tuple *tuple,
36 enum nf_nat_manip_type maniptype) 38 enum nf_nat_manip_type maniptype)
37{ 39{
38 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
39 struct udphdr *hdr; 40 struct udphdr *hdr;
40 unsigned int hdroff = iphdroff + iph->ihl*4;
41 __be32 oldip, newip;
42 __be16 *portptr, newport; 41 __be16 *portptr, newport;
43 42
44 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 43 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
45 return false; 44 return false;
46
47 iph = (struct iphdr *)(skb->data + iphdroff);
48 hdr = (struct udphdr *)(skb->data + hdroff); 45 hdr = (struct udphdr *)(skb->data + hdroff);
49 46
50 if (maniptype == NF_NAT_MANIP_SRC) { 47 if (maniptype == NF_NAT_MANIP_SRC) {
51 /* Get rid of src ip and src pt */ 48 /* Get rid of src port */
52 oldip = iph->saddr;
53 newip = tuple->src.u3.ip;
54 newport = tuple->src.u.udp.port; 49 newport = tuple->src.u.udp.port;
55 portptr = &hdr->source; 50 portptr = &hdr->source;
56 } else { 51 } else {
57 /* Get rid of dst ip and dst pt */ 52 /* Get rid of dst port */
58 oldip = iph->daddr;
59 newip = tuple->dst.u3.ip;
60 newport = tuple->dst.u.udp.port; 53 newport = tuple->dst.u.udp.port;
61 portptr = &hdr->dest; 54 portptr = &hdr->dest;
62 } 55 }
63 if (hdr->check || skb->ip_summed == CHECKSUM_PARTIAL) { 56 if (hdr->check || skb->ip_summed == CHECKSUM_PARTIAL) {
64 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1); 57 l3proto->csum_update(skb, iphdroff, &hdr->check,
58 tuple, maniptype);
65 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 59 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
66 0); 60 0);
67 if (!hdr->check) 61 if (!hdr->check)
@@ -71,12 +65,12 @@ udp_manip_pkt(struct sk_buff *skb,
71 return true; 65 return true;
72} 66}
73 67
74const struct nf_nat_protocol nf_nat_protocol_udp = { 68const struct nf_nat_l4proto nf_nat_l4proto_udp = {
75 .protonum = IPPROTO_UDP, 69 .l4proto = IPPROTO_UDP,
76 .manip_pkt = udp_manip_pkt, 70 .manip_pkt = udp_manip_pkt,
77 .in_range = nf_nat_proto_in_range, 71 .in_range = nf_nat_l4proto_in_range,
78 .unique_tuple = udp_unique_tuple, 72 .unique_tuple = udp_unique_tuple,
79#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 73#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
80 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 74 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
81#endif 75#endif
82}; 76};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/netfilter/nf_nat_proto_udplite.c
index d24d10a7beb..776a0d1317b 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udplite.c
+++ b/net/netfilter/nf_nat_proto_udplite.c
@@ -9,59 +9,53 @@
9 9
10#include <linux/types.h> 10#include <linux/types.h>
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/ip.h>
13#include <linux/udp.h> 12#include <linux/udp.h>
14 13
15#include <linux/netfilter.h> 14#include <linux/netfilter.h>
16#include <linux/module.h> 15#include <linux/module.h>
17#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_protocol.h> 17#include <net/netfilter/nf_nat_l3proto.h>
18#include <net/netfilter/nf_nat_l4proto.h>
19 19
20static u_int16_t udplite_port_rover; 20static u16 udplite_port_rover;
21 21
22static void 22static void
23udplite_unique_tuple(struct nf_conntrack_tuple *tuple, 23udplite_unique_tuple(const struct nf_nat_l3proto *l3proto,
24 const struct nf_nat_ipv4_range *range, 24 struct nf_conntrack_tuple *tuple,
25 const struct nf_nat_range *range,
25 enum nf_nat_manip_type maniptype, 26 enum nf_nat_manip_type maniptype,
26 const struct nf_conn *ct) 27 const struct nf_conn *ct)
27{ 28{
28 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, 29 nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
29 &udplite_port_rover); 30 &udplite_port_rover);
30} 31}
31 32
32static bool 33static bool
33udplite_manip_pkt(struct sk_buff *skb, 34udplite_manip_pkt(struct sk_buff *skb,
34 unsigned int iphdroff, 35 const struct nf_nat_l3proto *l3proto,
36 unsigned int iphdroff, unsigned int hdroff,
35 const struct nf_conntrack_tuple *tuple, 37 const struct nf_conntrack_tuple *tuple,
36 enum nf_nat_manip_type maniptype) 38 enum nf_nat_manip_type maniptype)
37{ 39{
38 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
39 struct udphdr *hdr; 40 struct udphdr *hdr;
40 unsigned int hdroff = iphdroff + iph->ihl*4;
41 __be32 oldip, newip;
42 __be16 *portptr, newport; 41 __be16 *portptr, newport;
43 42
44 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 43 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
45 return false; 44 return false;
46 45
47 iph = (struct iphdr *)(skb->data + iphdroff);
48 hdr = (struct udphdr *)(skb->data + hdroff); 46 hdr = (struct udphdr *)(skb->data + hdroff);
49 47
50 if (maniptype == NF_NAT_MANIP_SRC) { 48 if (maniptype == NF_NAT_MANIP_SRC) {
51 /* Get rid of src ip and src pt */ 49 /* Get rid of source port */
52 oldip = iph->saddr;
53 newip = tuple->src.u3.ip;
54 newport = tuple->src.u.udp.port; 50 newport = tuple->src.u.udp.port;
55 portptr = &hdr->source; 51 portptr = &hdr->source;
56 } else { 52 } else {
57 /* Get rid of dst ip and dst pt */ 53 /* Get rid of dst port */
58 oldip = iph->daddr;
59 newip = tuple->dst.u3.ip;
60 newport = tuple->dst.u.udp.port; 54 newport = tuple->dst.u.udp.port;
61 portptr = &hdr->dest; 55 portptr = &hdr->dest;
62 } 56 }
63 57
64 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1); 58 l3proto->csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
65 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 0); 59 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 0);
66 if (!hdr->check) 60 if (!hdr->check)
67 hdr->check = CSUM_MANGLED_0; 61 hdr->check = CSUM_MANGLED_0;
@@ -70,24 +64,38 @@ udplite_manip_pkt(struct sk_buff *skb,
70 return true; 64 return true;
71} 65}
72 66
73static const struct nf_nat_protocol nf_nat_protocol_udplite = { 67static const struct nf_nat_l4proto nf_nat_l4proto_udplite = {
74 .protonum = IPPROTO_UDPLITE, 68 .l4proto = IPPROTO_UDPLITE,
75 .manip_pkt = udplite_manip_pkt, 69 .manip_pkt = udplite_manip_pkt,
76 .in_range = nf_nat_proto_in_range, 70 .in_range = nf_nat_l4proto_in_range,
77 .unique_tuple = udplite_unique_tuple, 71 .unique_tuple = udplite_unique_tuple,
78#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 72#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
79 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 73 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
80#endif 74#endif
81}; 75};
82 76
83static int __init nf_nat_proto_udplite_init(void) 77static int __init nf_nat_proto_udplite_init(void)
84{ 78{
85 return nf_nat_protocol_register(&nf_nat_protocol_udplite); 79 int err;
80
81 err = nf_nat_l4proto_register(NFPROTO_IPV4, &nf_nat_l4proto_udplite);
82 if (err < 0)
83 goto err1;
84 err = nf_nat_l4proto_register(NFPROTO_IPV6, &nf_nat_l4proto_udplite);
85 if (err < 0)
86 goto err2;
87 return 0;
88
89err2:
90 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_udplite);
91err1:
92 return err;
86} 93}
87 94
88static void __exit nf_nat_proto_udplite_fini(void) 95static void __exit nf_nat_proto_udplite_fini(void)
89{ 96{
90 nf_nat_protocol_unregister(&nf_nat_protocol_udplite); 97 nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_udplite);
98 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_udplite);
91} 99}
92 100
93module_init(nf_nat_proto_udplite_init); 101module_init(nf_nat_proto_udplite_init);
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/netfilter/nf_nat_proto_unknown.c
index e0afe8112b1..6e494d58441 100644
--- a/net/ipv4/netfilter/nf_nat_proto_unknown.c
+++ b/net/netfilter/nf_nat_proto_unknown.c
@@ -15,8 +15,7 @@
15 15
16#include <linux/netfilter.h> 16#include <linux/netfilter.h>
17#include <net/netfilter/nf_nat.h> 17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_rule.h> 18#include <net/netfilter/nf_nat_l4proto.h>
19#include <net/netfilter/nf_nat_protocol.h>
20 19
21static bool unknown_in_range(const struct nf_conntrack_tuple *tuple, 20static bool unknown_in_range(const struct nf_conntrack_tuple *tuple,
22 enum nf_nat_manip_type manip_type, 21 enum nf_nat_manip_type manip_type,
@@ -26,26 +25,29 @@ static bool unknown_in_range(const struct nf_conntrack_tuple *tuple,
26 return true; 25 return true;
27} 26}
28 27
29static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple, 28static void unknown_unique_tuple(const struct nf_nat_l3proto *l3proto,
30 const struct nf_nat_ipv4_range *range, 29 struct nf_conntrack_tuple *tuple,
30 const struct nf_nat_range *range,
31 enum nf_nat_manip_type maniptype, 31 enum nf_nat_manip_type maniptype,
32 const struct nf_conn *ct) 32 const struct nf_conn *ct)
33{ 33{
34 /* Sorry: we can't help you; if it's not unique, we can't frob 34 /* Sorry: we can't help you; if it's not unique, we can't frob
35 anything. */ 35 * anything.
36 */
36 return; 37 return;
37} 38}
38 39
39static bool 40static bool
40unknown_manip_pkt(struct sk_buff *skb, 41unknown_manip_pkt(struct sk_buff *skb,
41 unsigned int iphdroff, 42 const struct nf_nat_l3proto *l3proto,
43 unsigned int iphdroff, unsigned int hdroff,
42 const struct nf_conntrack_tuple *tuple, 44 const struct nf_conntrack_tuple *tuple,
43 enum nf_nat_manip_type maniptype) 45 enum nf_nat_manip_type maniptype)
44{ 46{
45 return true; 47 return true;
46} 48}
47 49
48const struct nf_nat_protocol nf_nat_unknown_protocol = { 50const struct nf_nat_l4proto nf_nat_l4proto_unknown = {
49 .manip_pkt = unknown_manip_pkt, 51 .manip_pkt = unknown_manip_pkt,
50 .in_range = unknown_in_range, 52 .in_range = unknown_in_range,
51 .unique_tuple = unknown_unique_tuple, 53 .unique_tuple = unknown_unique_tuple,
diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c
new file mode 100644
index 00000000000..7521368a603
--- /dev/null
+++ b/net/netfilter/xt_nat.c
@@ -0,0 +1,167 @@
1/*
2 * (C) 1999-2001 Paul `Rusty' Russell
3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4 * (C) 2011 Patrick McHardy <kaber@trash.net>
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/skbuff.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter/x_tables.h>
15#include <net/netfilter/nf_nat_core.h>
16
17static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
18{
19 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
20
21 if (mr->rangesize != 1) {
22 pr_info("%s: multiple ranges no longer supported\n",
23 par->target->name);
24 return -EINVAL;
25 }
26 return 0;
27}
28
29static void xt_nat_convert_range(struct nf_nat_range *dst,
30 const struct nf_nat_ipv4_range *src)
31{
32 memset(&dst->min_addr, 0, sizeof(dst->min_addr));
33 memset(&dst->max_addr, 0, sizeof(dst->max_addr));
34
35 dst->flags = src->flags;
36 dst->min_addr.ip = src->min_ip;
37 dst->max_addr.ip = src->max_ip;
38 dst->min_proto = src->min;
39 dst->max_proto = src->max;
40}
41
42static unsigned int
43xt_snat_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
44{
45 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
46 struct nf_nat_range range;
47 enum ip_conntrack_info ctinfo;
48 struct nf_conn *ct;
49
50 ct = nf_ct_get(skb, &ctinfo);
51 NF_CT_ASSERT(ct != NULL &&
52 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
53 ctinfo == IP_CT_RELATED_REPLY));
54
55 xt_nat_convert_range(&range, &mr->range[0]);
56 return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
57}
58
59static unsigned int
60xt_dnat_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
61{
62 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
63 struct nf_nat_range range;
64 enum ip_conntrack_info ctinfo;
65 struct nf_conn *ct;
66
67 ct = nf_ct_get(skb, &ctinfo);
68 NF_CT_ASSERT(ct != NULL &&
69 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
70
71 xt_nat_convert_range(&range, &mr->range[0]);
72 return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
73}
74
75static unsigned int
76xt_snat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
77{
78 const struct nf_nat_range *range = par->targinfo;
79 enum ip_conntrack_info ctinfo;
80 struct nf_conn *ct;
81
82 ct = nf_ct_get(skb, &ctinfo);
83 NF_CT_ASSERT(ct != NULL &&
84 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
85 ctinfo == IP_CT_RELATED_REPLY));
86
87 return nf_nat_setup_info(ct, range, NF_NAT_MANIP_SRC);
88}
89
90static unsigned int
91xt_dnat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
92{
93 const struct nf_nat_range *range = par->targinfo;
94 enum ip_conntrack_info ctinfo;
95 struct nf_conn *ct;
96
97 ct = nf_ct_get(skb, &ctinfo);
98 NF_CT_ASSERT(ct != NULL &&
99 (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
100
101 return nf_nat_setup_info(ct, range, NF_NAT_MANIP_DST);
102}
103
104static struct xt_target xt_nat_target_reg[] __read_mostly = {
105 {
106 .name = "SNAT",
107 .revision = 0,
108 .checkentry = xt_nat_checkentry_v0,
109 .target = xt_snat_target_v0,
110 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
111 .family = NFPROTO_IPV4,
112 .table = "nat",
113 .hooks = (1 << NF_INET_POST_ROUTING) |
114 (1 << NF_INET_LOCAL_OUT),
115 .me = THIS_MODULE,
116 },
117 {
118 .name = "DNAT",
119 .revision = 0,
120 .checkentry = xt_nat_checkentry_v0,
121 .target = xt_dnat_target_v0,
122 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
123 .family = NFPROTO_IPV4,
124 .table = "nat",
125 .hooks = (1 << NF_INET_PRE_ROUTING) |
126 (1 << NF_INET_LOCAL_IN),
127 .me = THIS_MODULE,
128 },
129 {
130 .name = "SNAT",
131 .revision = 1,
132 .target = xt_snat_target_v1,
133 .targetsize = sizeof(struct nf_nat_range),
134 .table = "nat",
135 .hooks = (1 << NF_INET_POST_ROUTING) |
136 (1 << NF_INET_LOCAL_OUT),
137 .me = THIS_MODULE,
138 },
139 {
140 .name = "DNAT",
141 .revision = 1,
142 .target = xt_dnat_target_v1,
143 .targetsize = sizeof(struct nf_nat_range),
144 .table = "nat",
145 .hooks = (1 << NF_INET_PRE_ROUTING) |
146 (1 << NF_INET_LOCAL_IN),
147 .me = THIS_MODULE,
148 },
149};
150
151static int __init xt_nat_init(void)
152{
153 return xt_register_targets(xt_nat_target_reg,
154 ARRAY_SIZE(xt_nat_target_reg));
155}
156
157static void __exit xt_nat_exit(void)
158{
159 xt_unregister_targets(xt_nat_target_reg, ARRAY_SIZE(xt_nat_target_reg));
160}
161
162module_init(xt_nat_init);
163module_exit(xt_nat_exit);
164
165MODULE_LICENSE("GPL");
166MODULE_ALIAS("ipt_SNAT");
167MODULE_ALIAS("ipt_DNAT");