diff options
author | Patrick McHardy <kaber@trash.net> | 2012-08-26 13:14:06 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-08-29 21:00:14 -0400 |
commit | c7232c9979cba684c50b64c513c4a83c9aa70563 (patch) | |
tree | dbe0fdac62191d85935f5a3dfe815c1b1add60f9 | |
parent | 051966c0c644a1c96092d4206e00704ade813c9a (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>
49 files changed, 1495 insertions, 1140 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index c613cf0d7884..1dcf2a38e51f 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); | |||
342 | extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo); | 342 | extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo); |
343 | 343 | ||
344 | #include <net/flow.h> | 344 | #include <net/flow.h> |
345 | extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); | 345 | extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); |
346 | 346 | ||
347 | static inline void | 347 | static inline void |
348 | nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) | 348 | nf_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 8df2d13730b2..bf0cc373ffb6 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 | ||
25 | struct 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 f649f7423ca2..68920eab287c 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h | |||
@@ -142,8 +142,10 @@ enum ctattr_tstamp { | |||
142 | 142 | ||
143 | enum ctattr_nat { | 143 | enum 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 e2b12801378d..b962dfc695ae 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__ |
81 | extern int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type); | 81 | extern int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type); |
82 | extern int ip_xfrm_me_harder(struct sk_buff *skb); | ||
83 | extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, | 82 | extern __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 983f00263243..cc13f377a705 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 b4de990b55f1..1752f1339054 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. */ |
52 | extern unsigned int nf_nat_setup_info(struct nf_conn *ct, | 52 | extern 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 b13d8d18d595..972e1e47ec79 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 | ||
15 | extern int nf_nat_icmp_reply_translation(struct nf_conn *ct, | 15 | extern 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 | ||
20 | static inline int nf_nat_initialized(struct nf_conn *ct, | 17 | static 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 000000000000..beed96961fa7 --- /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 | |||
4 | struct nf_nat_l4proto; | ||
5 | struct 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 | |||
38 | extern int nf_nat_l3proto_register(const struct nf_nat_l3proto *); | ||
39 | extern void nf_nat_l3proto_unregister(const struct nf_nat_l3proto *); | ||
40 | extern const struct nf_nat_l3proto *__nf_nat_l3proto_find(u8 l3proto); | ||
41 | |||
42 | extern 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 000000000000..1f0a4f018fcf --- /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 | |||
7 | struct nf_nat_range; | ||
8 | struct nf_nat_l3proto; | ||
9 | |||
10 | struct 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. */ | ||
45 | extern int nf_nat_l4proto_register(u8 l3proto, const struct nf_nat_l4proto *l4proto); | ||
46 | extern void nf_nat_l4proto_unregister(u8 l3proto, const struct nf_nat_l4proto *l4proto); | ||
47 | |||
48 | extern const struct nf_nat_l4proto *__nf_nat_l4proto_find(u8 l3proto, u8 l4proto); | ||
49 | |||
50 | /* Built-in protocols. */ | ||
51 | extern const struct nf_nat_l4proto nf_nat_l4proto_tcp; | ||
52 | extern const struct nf_nat_l4proto nf_nat_l4proto_udp; | ||
53 | extern const struct nf_nat_l4proto nf_nat_l4proto_icmp; | ||
54 | extern const struct nf_nat_l4proto nf_nat_l4proto_unknown; | ||
55 | |||
56 | extern 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 | |||
61 | extern 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 | |||
68 | extern 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 7b0b51165f70..000000000000 --- 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 | |||
7 | struct nf_nat_ipv4_range; | ||
8 | |||
9 | struct 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. */ | ||
40 | extern int nf_nat_protocol_register(const struct nf_nat_protocol *proto); | ||
41 | extern void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto); | ||
42 | |||
43 | /* Built-in protocols. */ | ||
44 | extern const struct nf_nat_protocol nf_nat_protocol_tcp; | ||
45 | extern const struct nf_nat_protocol nf_nat_protocol_udp; | ||
46 | extern const struct nf_nat_protocol nf_nat_protocol_icmp; | ||
47 | extern const struct nf_nat_protocol nf_nat_unknown_protocol; | ||
48 | |||
49 | extern int init_protocols(void) __init; | ||
50 | extern void cleanup_protocols(void); | ||
51 | extern const struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); | ||
52 | |||
53 | extern 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 | |||
58 | extern 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 | |||
64 | extern 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 2890bdc4cd92..000000000000 --- 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 | |||
7 | extern int nf_nat_rule_init(void) __init; | ||
8 | extern void nf_nat_rule_cleanup(void); | ||
9 | extern 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 3aecdc7a84fb..a1d83cc8bf85 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 1474dd65c66f..ace280d19a20 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 ed1b36783192..f1643c0c3587 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 | } |
73 | EXPORT_SYMBOL(ip_route_me_harder); | 73 | EXPORT_SYMBOL(ip_route_me_harder); |
74 | 74 | ||
75 | #ifdef CONFIG_XFRM | ||
76 | int 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 | } | ||
106 | EXPORT_SYMBOL(ip_xfrm_me_harder); | ||
107 | #endif | ||
108 | |||
109 | void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); | ||
110 | EXPORT_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 fcc543cd987a..b26629681bdb 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 |
146 | config NF_NAT | 146 | config 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 | ||
157 | config NF_NAT_NEEDED | 158 | if NF_NAT_IPV4 |
158 | bool | ||
159 | depends on NF_NAT | ||
160 | default y | ||
161 | 159 | ||
162 | config IP_NF_TARGET_MASQUERADE | 160 | config 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 | ||
175 | config IP_NF_TARGET_NETMAP | 172 | config 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 | ||
186 | config IP_NF_TARGET_REDIRECT | 182 | config 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 | ||
193 | endif | ||
194 | |||
198 | config NF_NAT_SNMP_BASIC | 195 | config 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/). |
222 | config 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 | ||
227 | config NF_NAT_PROTO_GRE | 220 | config 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 | |||
231 | config NF_NAT_PROTO_UDPLITE | ||
232 | tristate | ||
233 | depends on NF_NAT && NF_CT_PROTO_UDPLITE | ||
234 | default NF_NAT && NF_CT_PROTO_UDPLITE | ||
235 | |||
236 | config 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 | ||
242 | config NF_NAT_FTP | 224 | config 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 | ||
247 | config NF_NAT_IRC | 229 | config 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 | ||
252 | config NF_NAT_TFTP | 234 | config 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 | ||
257 | config NF_NAT_AMANDA | 239 | config 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 | ||
262 | config NF_NAT_PPTP | 244 | config 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 | ||
268 | config NF_NAT_H323 | 250 | config 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 | ||
273 | config NF_NAT_SIP | 255 | config 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 |
279 | config IP_NF_MANGLE | 261 | config IP_NF_MANGLE |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index c20674dc9452..0ea3acc510e2 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 | |||
10 | endif | 10 | endif |
11 | endif | 11 | endif |
12 | 12 | ||
13 | nf_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 | ||
14 | iptable_nat-y := nf_nat_rule.o nf_nat_standalone.o | ||
15 | |||
16 | # connection tracking | 13 | # connection tracking |
17 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o | 14 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o |
18 | 15 | ||
19 | obj-$(CONFIG_NF_NAT) += nf_nat.o | 16 | nf_nat_ipv4-y := nf_nat_l3proto_ipv4.o nf_nat_proto_icmp.o |
17 | obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o | ||
20 | 18 | ||
21 | # defrag | 19 | # defrag |
22 | obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o | 20 | obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o |
@@ -32,10 +30,7 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o | |||
32 | obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o | 30 | obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o |
33 | 31 | ||
34 | # NAT protocols (nf_nat) | 32 | # NAT protocols (nf_nat) |
35 | obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o | ||
36 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o | 33 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o |
37 | obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o | ||
38 | obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o | ||
39 | 34 | ||
40 | # generic IP tables | 35 | # generic IP tables |
41 | obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o | 36 | obj-$(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 |
44 | obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o | 39 | obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o |
45 | obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o | 40 | obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o |
46 | obj-$(CONFIG_NF_NAT) += iptable_nat.o | 41 | obj-$(CONFIG_NF_NAT_IPV4) += iptable_nat.o |
47 | obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o | 42 | obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o |
48 | obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o | 43 | obj-$(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 cbb6a1a6f6f7..1c3aa28b51ae 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 | ||
26 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
27 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 27 | MODULE_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 b5bfbbabf70d..85028dc0425d 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 | ||
21 | MODULE_LICENSE("GPL"); | 21 | MODULE_LICENSE("GPL"); |
22 | MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>"); | 22 | MODULE_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 7c0103a5203e..11407d7d2472 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 | ||
24 | MODULE_LICENSE("GPL"); | 24 | MODULE_LICENSE("GPL"); |
25 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 25 | MODULE_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 3828a4229822..9e0ffaf1d942 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 | |
21 | static 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 | 31 | static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) |
32 | static 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; | 47 | static 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 | ||
76 | static unsigned int | 63 | static unsigned int |
77 | nf_nat_fn(unsigned int hooknum, | 64 | nf_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 | ||
153 | static unsigned int | 142 | static unsigned int |
154 | nf_nat_in(unsigned int hooknum, | 143 | nf_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 | ||
171 | static unsigned int | 160 | static unsigned int |
172 | nf_nat_out(unsigned int hooknum, | 161 | nf_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 | ||
206 | static unsigned int | 196 | static unsigned int |
207 | nf_nat_local_fn(unsigned int hooknum, | 197 | nf_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. */ | 233 | static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = { |
243 | |||
244 | static 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 | ||
279 | static int __init nf_nat_standalone_init(void) | 268 | static 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(); | 282 | static 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 | 287 | static 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: | 292 | static 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 | |||
305 | err2: | ||
306 | unregister_pernet_subsys(&iptable_nat_net_ops); | ||
307 | err1: | ||
308 | return err; | ||
309 | } | 309 | } |
310 | 310 | ||
311 | static void __exit nf_nat_standalone_fini(void) | 311 | static 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 | ||
322 | module_init(nf_nat_standalone_init); | 317 | module_init(iptable_nat_init); |
323 | module_exit(nf_nat_standalone_fini); | 318 | module_exit(iptable_nat_exit); |
324 | 319 | ||
325 | MODULE_LICENSE("GPL"); | 320 | MODULE_LICENSE("GPL"); |
326 | MODULE_ALIAS("ip_nat"); | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 4ada3295d9a7..fcdd0c2406e6 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 | ||
32 | int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, | ||
33 | struct nf_conn *ct, | ||
34 | enum ip_conntrack_info ctinfo, | ||
35 | unsigned int protoff); | ||
36 | EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook); | ||
37 | |||
38 | static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | 32 | static 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 75464b62f5f2..42d337881171 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 | ||
22 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); | 21 | MODULE_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 5589f3af4a8e..dd5e387fc03b 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 d2c228db38b5..9c3db10b22d3 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, | |||
392 | static void ip_nat_q931_expect(struct nf_conn *new, | 391 | static 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, | |||
490 | static void ip_nat_callforwarding_expect(struct nf_conn *new, | 490 | static 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 5b0c20a1f08d..1ce37f89ec78 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 000000000000..d8b2e14efddc --- /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 | |||
29 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv4; | ||
30 | |||
31 | #ifdef CONFIG_XFRM | ||
32 | static 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 | |||
65 | static 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 | |||
72 | static 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 | |||
78 | static 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 | |||
108 | static 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 | |||
126 | static 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 | |||
157 | static 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 | |||
173 | static 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 | |||
186 | int 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 | } | ||
251 | EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); | ||
252 | |||
253 | static 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 | |||
265 | err2: | ||
266 | nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_icmp); | ||
267 | err1: | ||
268 | return err; | ||
269 | } | ||
270 | |||
271 | static 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 | |||
277 | MODULE_LICENSE("GPL"); | ||
278 | MODULE_ALIAS("nf-nat-" __stringify(AF_INET)); | ||
279 | |||
280 | module_init(nf_nat_l3proto_ipv4_init); | ||
281 | module_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 31ef890d894b..a06d7d74817d 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 46ba0b9ab985..ea44f02563b5 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 | ||
35 | MODULE_LICENSE("GPL"); | 34 | MODULE_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 ... */ |
40 | static void | 39 | static void |
41 | gre_unique_tuple(struct nf_conntrack_tuple *tuple, | 40 | gre_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 */ |
82 | static bool | 82 | static bool |
83 | gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, | 83 | gre_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 | ||
120 | static const struct nf_nat_protocol gre = { | 120 | static 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 | ||
130 | static int __init nf_nat_proto_gre_init(void) | 130 | static 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 | ||
135 | static void __exit nf_nat_proto_gre_fini(void) | 135 | static 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 | ||
140 | module_init(nf_nat_proto_gre_init); | 140 | module_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 b35172851bae..eb303471bcf6 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 | ||
21 | static bool | 20 | static bool |
22 | icmp_in_range(const struct nf_conntrack_tuple *tuple, | 21 | icmp_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 | ||
31 | static void | 30 | static void |
32 | icmp_unique_tuple(struct nf_conntrack_tuple *tuple, | 31 | icmp_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 | ||
55 | static bool | 56 | static bool |
56 | icmp_manip_pkt(struct sk_buff *skb, | 57 | icmp_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 | ||
75 | const struct nf_nat_protocol nf_nat_protocol_icmp = { | 75 | const 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 d2a9dc314e0e..000000000000 --- 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 | |||
34 | static 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 */ | ||
42 | static unsigned int | ||
43 | ipt_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 | |||
62 | static unsigned int | ||
63 | ipt_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 | |||
80 | static 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 | |||
92 | static 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 | |||
104 | static unsigned int | ||
105 | alloc_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 | |||
121 | int 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 | |||
140 | static 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 | |||
150 | static 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 | |||
160 | static 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 | |||
174 | static void __net_exit nf_nat_rule_net_exit(struct net *net) | ||
175 | { | ||
176 | ipt_unregister_table(net, net->ipv4.nat_table); | ||
177 | } | ||
178 | |||
179 | static struct pernet_operations nf_nat_rule_net_ops = { | ||
180 | .init = nf_nat_rule_net_init, | ||
181 | .exit = nf_nat_rule_net_exit, | ||
182 | }; | ||
183 | |||
184 | int __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 | |||
209 | void 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 df626af8413c..47a47186a791 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) | |||
255 | static void ip_nat_sip_expected(struct nf_conn *ct, | 254 | static 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 9dbb8d284f99..ccabbda71a3e 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 | ||
17 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); | 16 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index c19b214ffd57..91adddae20a4 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 | ||
359 | config NF_NAT | ||
360 | tristate | ||
361 | |||
362 | config NF_NAT_NEEDED | ||
363 | bool | ||
364 | depends on NF_NAT | ||
365 | default y | ||
366 | |||
367 | config NF_NAT_PROTO_DCCP | ||
368 | tristate | ||
369 | depends on NF_NAT && NF_CT_PROTO_DCCP | ||
370 | default NF_NAT && NF_CT_PROTO_DCCP | ||
371 | |||
372 | config NF_NAT_PROTO_UDPLITE | ||
373 | tristate | ||
374 | depends on NF_NAT && NF_CT_PROTO_UDPLITE | ||
375 | default NF_NAT && NF_CT_PROTO_UDPLITE | ||
376 | |||
377 | config 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 | |||
359 | endif # NF_CONNTRACK | 383 | endif # NF_CONNTRACK |
360 | 384 | ||
361 | # transparent proxy support | 385 | # transparent proxy support |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 1c5160f2278e..09c9451bc510 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -43,6 +43,17 @@ obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o | |||
43 | obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o | 43 | obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o |
44 | obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o | 44 | obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o |
45 | 45 | ||
46 | nf_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 | |||
49 | obj-$(CONFIG_NF_NAT) += nf_nat.o | ||
50 | obj-$(CONFIG_NF_NAT) += xt_nat.o | ||
51 | |||
52 | # NAT protocols (nf_nat) | ||
53 | obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o | ||
54 | obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o | ||
55 | obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o | ||
56 | |||
46 | # transparent proxy support | 57 | # transparent proxy support |
47 | obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o | 58 | obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o |
48 | 59 | ||
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 8f4b0b2b6f80..e61b3ac9591b 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 | ||
279 | void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); | ||
280 | EXPORT_SYMBOL(nf_nat_decode_session_hook); | ||
281 | #endif | ||
282 | |||
278 | #ifdef CONFIG_PROC_FS | 283 | #ifdef CONFIG_PROC_FS |
279 | struct proc_dir_entry *proc_net_netfilter; | 284 | struct proc_dir_entry *proc_net_netfilter; |
280 | EXPORT_SYMBOL(proc_net_netfilter); | 285 | EXPORT_SYMBOL(proc_net_netfilter); |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index cf4875565d67..f83e79defed9 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; |
56 | EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); | 56 | EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); |
57 | 57 | ||
58 | int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, | ||
59 | struct nf_conn *ct, | ||
60 | enum ip_conntrack_info ctinfo, | ||
61 | unsigned int protoff); | ||
62 | EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook); | ||
63 | |||
58 | DEFINE_SPINLOCK(nf_conntrack_lock); | 64 | DEFINE_SPINLOCK(nf_conntrack_lock); |
59 | EXPORT_SYMBOL_GPL(nf_conntrack_lock); | 65 | EXPORT_SYMBOL_GPL(nf_conntrack_lock); |
60 | 66 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index da4fc37a8578..966f5133a384 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 | ||
2002 | static const union nf_inet_addr any_addr; | ||
2003 | |||
1982 | static int | 2004 | static int |
1983 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 2005 | ctnetlink_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 a5ac11ebef33..9c2cc716f4a5 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 | ||
514 | static bool tcp_in_window(const struct nf_conn *ct, | 514 | static 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 590f0abaab8c..d5174902db37 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 44b082fd48ab..c577b753fb9a 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 | ||
35 | static DEFINE_SPINLOCK(nf_nat_lock); | 32 | static DEFINE_SPINLOCK(nf_nat_lock); |
36 | 33 | ||
37 | static struct nf_conntrack_l3proto *l3proto __read_mostly; | 34 | static DEFINE_MUTEX(nf_nat_proto_mutex); |
38 | 35 | static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO] | |
39 | #define MAX_IP_NAT_PROTO 256 | 36 | __read_mostly; |
40 | static const struct nf_nat_protocol __rcu *nf_nat_protos[MAX_IP_NAT_PROTO] | 37 | static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO] |
41 | __read_mostly; | 38 | __read_mostly; |
42 | 39 | ||
43 | static inline const struct nf_nat_protocol * | 40 | |
44 | __nf_nat_proto_find(u_int8_t protonum) | 41 | inline 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 | ||
47 | inline 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 | } | ||
52 | EXPORT_SYMBOL_GPL(__nf_nat_l4proto_find); | ||
53 | |||
54 | #ifdef CONFIG_XFRM | ||
55 | static 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); | ||
81 | out: | ||
82 | rcu_read_unlock(); | ||
83 | } | ||
84 | |||
85 | int 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 | } | ||
113 | EXPORT_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. */ |
50 | static inline unsigned int | 117 | static inline unsigned int |
51 | hash_by_src(const struct net *net, u16 zone, | 118 | hash_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, | |||
78 | EXPORT_SYMBOL(nf_nat_used_tuple); | 145 | EXPORT_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. |
82 | static int | 149 | */ |
83 | in_range(const struct nf_conntrack_tuple *tuple, | 150 | static 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 | ||
108 | static inline int | 170 | static 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 */ |
121 | static int | 183 | static int |
122 | find_appropriate_src(struct net *net, u16 zone, | 184 | find_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 | */ |
157 | static void | 219 | static void |
158 | find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple, | 220 | find_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. */ |
203 | static void | 292 | static void |
204 | get_unique_tuple(struct nf_conntrack_tuple *tuple, | 293 | get_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); |
263 | out: | 357 | out: |
264 | rcu_read_unlock(); | 358 | rcu_read_unlock(); |
265 | } | 359 | } |
266 | 360 | ||
267 | unsigned int | 361 | unsigned int |
268 | nf_nat_setup_info(struct nf_conn *ct, | 362 | nf_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 | } |
336 | EXPORT_SYMBOL(nf_nat_setup_info); | 430 | EXPORT_SYMBOL(nf_nat_setup_info); |
337 | 431 | ||
338 | /* Returns true if succeeded. */ | ||
339 | static bool | ||
340 | manip_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. */ |
374 | unsigned int nf_nat_packet(struct nf_conn *ct, | 433 | unsigned 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 | } |
404 | EXPORT_SYMBOL_GPL(nf_nat_packet); | 468 | EXPORT_SYMBOL_GPL(nf_nat_packet); |
405 | 469 | ||
406 | /* Dir is direction ICMP is coming from (opposite to packet it contains) */ | 470 | struct nf_nat_proto_clean { |
407 | int 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. */ | ||
477 | static 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) | 500 | static 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 | 522 | static 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 | } |
490 | EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); | ||
491 | 542 | ||
492 | /* Protocol registration. */ | 543 | /* Protocol registration. */ |
493 | int nf_nat_protocol_register(const struct nf_nat_protocol *proto) | 544 | int 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 | } |
510 | EXPORT_SYMBOL(nf_nat_protocol_register); | 582 | EXPORT_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. */ |
513 | void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto) | 585 | void 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 | } |
521 | EXPORT_SYMBOL(nf_nat_protocol_unregister); | 595 | EXPORT_SYMBOL_GPL(nf_nat_l4proto_unregister); |
596 | |||
597 | int 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 | } | ||
615 | EXPORT_SYMBOL_GPL(nf_nat_l3proto_register); | ||
616 | |||
617 | void 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 | } | ||
627 | EXPORT_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. */ |
524 | static void nf_nat_cleanup_conntrack(struct nf_conn *ct) | 630 | static 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 | ||
571 | static int nfnetlink_parse_nat_proto(struct nlattr *attr, | 677 | static 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 | ||
591 | static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = { | 696 | static 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 | ||
597 | static int | 702 | static int |
598 | nfnetlink_parse_nat(const struct nlattr *nat, | 703 | nfnetlink_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) | 730 | out: |
626 | return err; | 731 | rcu_read_unlock(); |
627 | 732 | return err; | |
628 | return 0; | ||
629 | } | 733 | } |
630 | 734 | ||
631 | static int | 735 | static 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, | |||
655 | static int __net_init nf_nat_net_init(struct net *net) | 761 | static 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. */ | ||
666 | static 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 | |||
677 | static void __net_exit nf_nat_net_exit(struct net *net) | 771 | static 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 | ||
684 | static struct pernet_operations nf_nat_net_ops = { | 780 | static struct pernet_operations nf_nat_net_ops = { |
@@ -697,11 +793,8 @@ static struct nfq_ct_nat_hook nfq_ct_nat = { | |||
697 | 793 | ||
698 | static int __init nf_nat_init(void) | 794 | static 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 | ||
746 | static void __exit nf_nat_cleanup(void) | 832 | static 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 | ||
759 | MODULE_LICENSE("GPL"); | 851 | MODULE_LICENSE("GPL"); |
760 | MODULE_ALIAS("nf-nat-ipv4"); | ||
761 | 852 | ||
762 | module_init(nf_nat_init); | 853 | module_init(nf_nat_init); |
763 | module_exit(nf_nat_cleanup); | 854 | module_exit(nf_nat_cleanup); |
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c index 2fefec5e757c..23c2b38676a6 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 | } |
93 | EXPORT_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. */ |
96 | static void mangle_contents(struct sk_buff *skb, | 91 | static 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 | } |
167 | EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust); | 166 | EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust); |
168 | 167 | ||
169 | static 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 */ |
344 | static inline unsigned int | 317 | static inline unsigned int |
345 | nf_nat_sack_adjust(struct sk_buff *skb, | 318 | nf_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, | |||
440 | void nf_nat_follow_master(struct nf_conn *ct, | 414 | void 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 | } |
461 | EXPORT_SYMBOL(nf_nat_follow_master); | 435 | EXPORT_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 9993bc93e102..9baaf734c142 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 | ||
22 | bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, | 20 | bool 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 | } |
37 | EXPORT_SYMBOL_GPL(nf_nat_proto_in_range); | 35 | EXPORT_SYMBOL_GPL(nf_nat_l4proto_in_range); |
38 | 36 | ||
39 | void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, | 37 | void 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 | } |
96 | EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); | 94 | EXPORT_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) |
99 | int nf_nat_proto_nlattr_to_range(struct nlattr *tb[], | 97 | int 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 | } |
113 | EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range); | 111 | EXPORT_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 3f67138d187c..c8be2cdac0bf 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 | ||
23 | static u_int16_t dccp_port_rover; | 23 | static u_int16_t dccp_port_rover; |
24 | 24 | ||
25 | static void | 25 | static void |
26 | dccp_unique_tuple(struct nf_conntrack_tuple *tuple, | 26 | dccp_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 | ||
35 | static bool | 36 | static bool |
36 | dccp_manip_pkt(struct sk_buff *skb, | 37 | dccp_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 | ||
81 | static const struct nf_nat_protocol nf_nat_protocol_dccp = { | 76 | static 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 | ||
91 | static int __init nf_nat_proto_dccp_init(void) | 86 | static 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 | |||
98 | err2: | ||
99 | nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_dccp); | ||
100 | err1: | ||
101 | return err; | ||
94 | } | 102 | } |
95 | 103 | ||
96 | static void __exit nf_nat_proto_dccp_fini(void) | 104 | static 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 | ||
101 | module_init(nf_nat_proto_dccp_init); | 111 | module_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 3cce9b6c1c29..e64faa5ca893 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 | ||
18 | static u_int16_t nf_sctp_port_rover; | 17 | static u_int16_t nf_sctp_port_rover; |
19 | 18 | ||
20 | static void | 19 | static void |
21 | sctp_unique_tuple(struct nf_conntrack_tuple *tuple, | 20 | sctp_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 | ||
30 | static bool | 30 | static bool |
31 | sctp_manip_pkt(struct sk_buff *skb, | 31 | sctp_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 | ||
71 | static const struct nf_nat_protocol nf_nat_protocol_sctp = { | 64 | static 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 | ||
81 | static int __init nf_nat_proto_sctp_init(void) | 74 | static 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 | |||
86 | err2: | ||
87 | nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_sctp); | ||
88 | err1: | ||
89 | return err; | ||
84 | } | 90 | } |
85 | 91 | ||
86 | static void __exit nf_nat_proto_sctp_exit(void) | 92 | static 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 | ||
91 | module_init(nf_nat_proto_sctp_init); | 98 | module_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 9fb4b4e72bbf..83ec8a6e4c36 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 | ||
22 | static u_int16_t tcp_port_rover; | 21 | static u16 tcp_port_rover; |
23 | 22 | ||
24 | static void | 23 | static void |
25 | tcp_unique_tuple(struct nf_conntrack_tuple *tuple, | 24 | tcp_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 | ||
33 | static bool | 34 | static bool |
34 | tcp_manip_pkt(struct sk_buff *skb, | 35 | tcp_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 | ||
83 | const struct nf_nat_protocol nf_nat_protocol_tcp = { | 77 | const 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 9883336e628f..7df613fb34a2 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 | ||
21 | static u_int16_t udp_port_rover; | 20 | static u16 udp_port_rover; |
22 | 21 | ||
23 | static void | 22 | static void |
24 | udp_unique_tuple(struct nf_conntrack_tuple *tuple, | 23 | udp_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 | ||
32 | static bool | 33 | static bool |
33 | udp_manip_pkt(struct sk_buff *skb, | 34 | udp_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 | ||
74 | const struct nf_nat_protocol nf_nat_protocol_udp = { | 68 | const 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 d24d10a7beb2..776a0d1317b1 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 | ||
20 | static u_int16_t udplite_port_rover; | 20 | static u16 udplite_port_rover; |
21 | 21 | ||
22 | static void | 22 | static void |
23 | udplite_unique_tuple(struct nf_conntrack_tuple *tuple, | 23 | udplite_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 | ||
32 | static bool | 33 | static bool |
33 | udplite_manip_pkt(struct sk_buff *skb, | 34 | udplite_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 | ||
73 | static const struct nf_nat_protocol nf_nat_protocol_udplite = { | 67 | static 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 | ||
83 | static int __init nf_nat_proto_udplite_init(void) | 77 | static 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 | |||
89 | err2: | ||
90 | nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_udplite); | ||
91 | err1: | ||
92 | return err; | ||
86 | } | 93 | } |
87 | 94 | ||
88 | static void __exit nf_nat_proto_udplite_fini(void) | 95 | static 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 | ||
93 | module_init(nf_nat_proto_udplite_init); | 101 | module_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 e0afe8112b1c..6e494d584412 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 | ||
21 | static bool unknown_in_range(const struct nf_conntrack_tuple *tuple, | 20 | static 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 | ||
29 | static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple, | 28 | static 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 | ||
39 | static bool | 40 | static bool |
40 | unknown_manip_pkt(struct sk_buff *skb, | 41 | unknown_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 | ||
48 | const struct nf_nat_protocol nf_nat_unknown_protocol = { | 50 | const 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 000000000000..7521368a6034 --- /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 | |||
17 | static 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 | |||
29 | static 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 | |||
42 | static unsigned int | ||
43 | xt_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 | |||
59 | static unsigned int | ||
60 | xt_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 | |||
75 | static unsigned int | ||
76 | xt_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 | |||
90 | static unsigned int | ||
91 | xt_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 | |||
104 | static 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 | |||
151 | static 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 | |||
157 | static void __exit xt_nat_exit(void) | ||
158 | { | ||
159 | xt_unregister_targets(xt_nat_target_reg, ARRAY_SIZE(xt_nat_target_reg)); | ||
160 | } | ||
161 | |||
162 | module_init(xt_nat_init); | ||
163 | module_exit(xt_nat_exit); | ||
164 | |||
165 | MODULE_LICENSE("GPL"); | ||
166 | MODULE_ALIAS("ipt_SNAT"); | ||
167 | MODULE_ALIAS("ipt_DNAT"); | ||