Commit b6b84d4a94e95727a4c65841eea23ac60c6aa329

Authored by Yasuyuki Kozakai
Committed by David S. Miller
1 parent d8a0509a69

[NETFILTER]: nf_nat: merge nf_conn and nf_nat_info

Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 23 additions and 30 deletions Inline Diff

include/net/netfilter/nf_nat.h
1 #ifndef _NF_NAT_H 1 #ifndef _NF_NAT_H
2 #define _NF_NAT_H 2 #define _NF_NAT_H
3 #include <linux/netfilter_ipv4.h> 3 #include <linux/netfilter_ipv4.h>
4 #include <net/netfilter/nf_conntrack_tuple.h> 4 #include <net/netfilter/nf_conntrack_tuple.h>
5 5
6 #define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16 6 #define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16
7 7
8 enum nf_nat_manip_type 8 enum nf_nat_manip_type
9 { 9 {
10 IP_NAT_MANIP_SRC, 10 IP_NAT_MANIP_SRC,
11 IP_NAT_MANIP_DST 11 IP_NAT_MANIP_DST
12 }; 12 };
13 13
14 /* SRC manip occurs POST_ROUTING or LOCAL_IN */ 14 /* SRC manip occurs POST_ROUTING or LOCAL_IN */
15 #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN) 15 #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN)
16 16
17 #define IP_NAT_RANGE_MAP_IPS 1 17 #define IP_NAT_RANGE_MAP_IPS 1
18 #define IP_NAT_RANGE_PROTO_SPECIFIED 2 18 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
19 #define IP_NAT_RANGE_PROTO_RANDOM 4 19 #define IP_NAT_RANGE_PROTO_RANDOM 4
20 20
21 /* NAT sequence number modifications */ 21 /* NAT sequence number modifications */
22 struct nf_nat_seq { 22 struct nf_nat_seq {
23 /* position of the last TCP sequence number modification (if any) */ 23 /* position of the last TCP sequence number modification (if any) */
24 u_int32_t correction_pos; 24 u_int32_t correction_pos;
25 25
26 /* sequence number offset before and after last modification */ 26 /* sequence number offset before and after last modification */
27 int16_t offset_before, offset_after; 27 int16_t offset_before, offset_after;
28 }; 28 };
29 29
30 /* Single range specification. */ 30 /* Single range specification. */
31 struct nf_nat_range 31 struct nf_nat_range
32 { 32 {
33 /* Set to OR of flags above. */ 33 /* Set to OR of flags above. */
34 unsigned int flags; 34 unsigned int flags;
35 35
36 /* Inclusive: network order. */ 36 /* Inclusive: network order. */
37 __be32 min_ip, max_ip; 37 __be32 min_ip, max_ip;
38 38
39 /* Inclusive: network order */ 39 /* Inclusive: network order */
40 union nf_conntrack_man_proto min, max; 40 union nf_conntrack_man_proto min, max;
41 }; 41 };
42 42
43 /* For backwards compat: don't use in modern code. */ 43 /* For backwards compat: don't use in modern code. */
44 struct nf_nat_multi_range_compat 44 struct nf_nat_multi_range_compat
45 { 45 {
46 unsigned int rangesize; /* Must be 1. */ 46 unsigned int rangesize; /* Must be 1. */
47 47
48 /* hangs off end. */ 48 /* hangs off end. */
49 struct nf_nat_range range[1]; 49 struct nf_nat_range range[1];
50 }; 50 };
51 51
52 #ifdef __KERNEL__ 52 #ifdef __KERNEL__
53 #include <linux/list.h> 53 #include <linux/list.h>
54 #include <linux/netfilter/nf_conntrack_pptp.h> 54 #include <linux/netfilter/nf_conntrack_pptp.h>
55 #include <net/netfilter/nf_conntrack_extend.h> 55 #include <net/netfilter/nf_conntrack_extend.h>
56 56
57 struct nf_conn;
58
59 /* The structure embedded in the conntrack structure. */
60 struct nf_nat_info
61 {
62 struct list_head bysource;
63 struct nf_nat_seq seq[IP_CT_DIR_MAX];
64 struct nf_conn *ct;
65 };
66
67 /* per conntrack: nat application helper private data */ 57 /* per conntrack: nat application helper private data */
68 union nf_conntrack_nat_help 58 union nf_conntrack_nat_help
69 { 59 {
70 /* insert nat helper private data here */ 60 /* insert nat helper private data here */
71 struct nf_nat_pptp nat_pptp_info; 61 struct nf_nat_pptp nat_pptp_info;
72 }; 62 };
73 63
64 struct nf_conn;
65
66 /* The structure embedded in the conntrack structure. */
74 struct nf_conn_nat 67 struct nf_conn_nat
75 { 68 {
76 struct nf_nat_info info; 69 struct list_head bysource;
70 struct nf_nat_seq seq[IP_CT_DIR_MAX];
71 struct nf_conn *ct;
77 union nf_conntrack_nat_help help; 72 union nf_conntrack_nat_help help;
78 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ 73 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
79 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) 74 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
80 int masq_index; 75 int masq_index;
81 #endif 76 #endif
82 }; 77 };
83 78
84 /* Set up the info structure to map into this range. */ 79 /* Set up the info structure to map into this range. */
85 extern unsigned int nf_nat_setup_info(struct nf_conn *ct, 80 extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
86 const struct nf_nat_range *range, 81 const struct nf_nat_range *range,
87 unsigned int hooknum); 82 unsigned int hooknum);
88 83
89 /* Is this tuple already taken? (not by us)*/ 84 /* Is this tuple already taken? (not by us)*/
90 extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, 85 extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
91 const struct nf_conn *ignored_conntrack); 86 const struct nf_conn *ignored_conntrack);
92 87
93 static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) 88 static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct)
94 { 89 {
95 return nf_ct_ext_find(ct, NF_CT_EXT_NAT); 90 return nf_ct_ext_find(ct, NF_CT_EXT_NAT);
96 } 91 }
97 92
net/ipv4/netfilter/nf_nat_core.c
1 /* NAT for netfilter; shared with compatibility layer. */ 1 /* NAT for netfilter; shared with compatibility layer. */
2 2
3 /* (C) 1999-2001 Paul `Rusty' Russell 3 /* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
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
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11 #include <linux/module.h> 11 #include <linux/module.h>
12 #include <linux/types.h> 12 #include <linux/types.h>
13 #include <linux/timer.h> 13 #include <linux/timer.h>
14 #include <linux/skbuff.h> 14 #include <linux/skbuff.h>
15 #include <linux/vmalloc.h> 15 #include <linux/vmalloc.h>
16 #include <net/checksum.h> 16 #include <net/checksum.h>
17 #include <net/icmp.h> 17 #include <net/icmp.h>
18 #include <net/ip.h> 18 #include <net/ip.h>
19 #include <net/tcp.h> /* For tcp_prot in getorigdst */ 19 #include <net/tcp.h> /* For tcp_prot in getorigdst */
20 #include <linux/icmp.h> 20 #include <linux/icmp.h>
21 #include <linux/udp.h> 21 #include <linux/udp.h>
22 #include <linux/jhash.h> 22 #include <linux/jhash.h>
23 23
24 #include <linux/netfilter_ipv4.h> 24 #include <linux/netfilter_ipv4.h>
25 #include <net/netfilter/nf_conntrack.h> 25 #include <net/netfilter/nf_conntrack.h>
26 #include <net/netfilter/nf_conntrack_core.h> 26 #include <net/netfilter/nf_conntrack_core.h>
27 #include <net/netfilter/nf_nat.h> 27 #include <net/netfilter/nf_nat.h>
28 #include <net/netfilter/nf_nat_protocol.h> 28 #include <net/netfilter/nf_nat_protocol.h>
29 #include <net/netfilter/nf_nat_core.h> 29 #include <net/netfilter/nf_nat_core.h>
30 #include <net/netfilter/nf_nat_helper.h> 30 #include <net/netfilter/nf_nat_helper.h>
31 #include <net/netfilter/nf_conntrack_helper.h> 31 #include <net/netfilter/nf_conntrack_helper.h>
32 #include <net/netfilter/nf_conntrack_l3proto.h> 32 #include <net/netfilter/nf_conntrack_l3proto.h>
33 #include <net/netfilter/nf_conntrack_l4proto.h> 33 #include <net/netfilter/nf_conntrack_l4proto.h>
34 34
35 #if 0 35 #if 0
36 #define DEBUGP printk 36 #define DEBUGP printk
37 #else 37 #else
38 #define DEBUGP(format, args...) 38 #define DEBUGP(format, args...)
39 #endif 39 #endif
40 40
41 static DEFINE_RWLOCK(nf_nat_lock); 41 static DEFINE_RWLOCK(nf_nat_lock);
42 42
43 static struct nf_conntrack_l3proto *l3proto = NULL; 43 static struct nf_conntrack_l3proto *l3proto = NULL;
44 44
45 /* Calculated at init based on memory size */ 45 /* Calculated at init based on memory size */
46 static unsigned int nf_nat_htable_size; 46 static unsigned int nf_nat_htable_size;
47 47
48 static struct list_head *bysource; 48 static struct list_head *bysource;
49 49
50 #define MAX_IP_NAT_PROTO 256 50 #define MAX_IP_NAT_PROTO 256
51 static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; 51 static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO];
52 52
53 static inline struct nf_nat_protocol * 53 static inline struct nf_nat_protocol *
54 __nf_nat_proto_find(u_int8_t protonum) 54 __nf_nat_proto_find(u_int8_t protonum)
55 { 55 {
56 return rcu_dereference(nf_nat_protos[protonum]); 56 return rcu_dereference(nf_nat_protos[protonum]);
57 } 57 }
58 58
59 struct nf_nat_protocol * 59 struct nf_nat_protocol *
60 nf_nat_proto_find_get(u_int8_t protonum) 60 nf_nat_proto_find_get(u_int8_t protonum)
61 { 61 {
62 struct nf_nat_protocol *p; 62 struct nf_nat_protocol *p;
63 63
64 rcu_read_lock(); 64 rcu_read_lock();
65 p = __nf_nat_proto_find(protonum); 65 p = __nf_nat_proto_find(protonum);
66 if (!try_module_get(p->me)) 66 if (!try_module_get(p->me))
67 p = &nf_nat_unknown_protocol; 67 p = &nf_nat_unknown_protocol;
68 rcu_read_unlock(); 68 rcu_read_unlock();
69 69
70 return p; 70 return p;
71 } 71 }
72 EXPORT_SYMBOL_GPL(nf_nat_proto_find_get); 72 EXPORT_SYMBOL_GPL(nf_nat_proto_find_get);
73 73
74 void 74 void
75 nf_nat_proto_put(struct nf_nat_protocol *p) 75 nf_nat_proto_put(struct nf_nat_protocol *p)
76 { 76 {
77 module_put(p->me); 77 module_put(p->me);
78 } 78 }
79 EXPORT_SYMBOL_GPL(nf_nat_proto_put); 79 EXPORT_SYMBOL_GPL(nf_nat_proto_put);
80 80
81 /* We keep an extra hash for each conntrack, for fast searching. */ 81 /* We keep an extra hash for each conntrack, for fast searching. */
82 static inline unsigned int 82 static inline unsigned int
83 hash_by_src(const struct nf_conntrack_tuple *tuple) 83 hash_by_src(const struct nf_conntrack_tuple *tuple)
84 { 84 {
85 /* Original src, to ensure we map it consistently if poss. */ 85 /* Original src, to ensure we map it consistently if poss. */
86 return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all, 86 return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all,
87 tuple->dst.protonum, 0) % nf_nat_htable_size; 87 tuple->dst.protonum, 0) % nf_nat_htable_size;
88 } 88 }
89 89
90 /* Is this tuple already taken? (not by us) */ 90 /* Is this tuple already taken? (not by us) */
91 int 91 int
92 nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, 92 nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
93 const struct nf_conn *ignored_conntrack) 93 const struct nf_conn *ignored_conntrack)
94 { 94 {
95 /* Conntrack tracking doesn't keep track of outgoing tuples; only 95 /* Conntrack tracking doesn't keep track of outgoing tuples; only
96 incoming ones. NAT means they don't have a fixed mapping, 96 incoming ones. NAT means they don't have a fixed mapping,
97 so we invert the tuple and look for the incoming reply. 97 so we invert the tuple and look for the incoming reply.
98 98
99 We could keep a separate hash if this proves too slow. */ 99 We could keep a separate hash if this proves too slow. */
100 struct nf_conntrack_tuple reply; 100 struct nf_conntrack_tuple reply;
101 101
102 nf_ct_invert_tuplepr(&reply, tuple); 102 nf_ct_invert_tuplepr(&reply, tuple);
103 return nf_conntrack_tuple_taken(&reply, ignored_conntrack); 103 return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
104 } 104 }
105 EXPORT_SYMBOL(nf_nat_used_tuple); 105 EXPORT_SYMBOL(nf_nat_used_tuple);
106 106
107 /* If we source map this tuple so reply looks like reply_tuple, will 107 /* If we source map this tuple so reply looks like reply_tuple, will
108 * that meet the constraints of range. */ 108 * that meet the constraints of range. */
109 static int 109 static int
110 in_range(const struct nf_conntrack_tuple *tuple, 110 in_range(const struct nf_conntrack_tuple *tuple,
111 const struct nf_nat_range *range) 111 const struct nf_nat_range *range)
112 { 112 {
113 struct nf_nat_protocol *proto; 113 struct nf_nat_protocol *proto;
114 int ret = 0; 114 int ret = 0;
115 115
116 /* If we are supposed to map IPs, then we must be in the 116 /* If we are supposed to map IPs, then we must be in the
117 range specified, otherwise let this drag us onto a new src IP. */ 117 range specified, otherwise let this drag us onto a new src IP. */
118 if (range->flags & IP_NAT_RANGE_MAP_IPS) { 118 if (range->flags & IP_NAT_RANGE_MAP_IPS) {
119 if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || 119 if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) ||
120 ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) 120 ntohl(tuple->src.u3.ip) > ntohl(range->max_ip))
121 return 0; 121 return 0;
122 } 122 }
123 123
124 rcu_read_lock(); 124 rcu_read_lock();
125 proto = __nf_nat_proto_find(tuple->dst.protonum); 125 proto = __nf_nat_proto_find(tuple->dst.protonum);
126 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || 126 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
127 proto->in_range(tuple, IP_NAT_MANIP_SRC, 127 proto->in_range(tuple, IP_NAT_MANIP_SRC,
128 &range->min, &range->max)) 128 &range->min, &range->max))
129 ret = 1; 129 ret = 1;
130 rcu_read_unlock(); 130 rcu_read_unlock();
131 131
132 return ret; 132 return ret;
133 } 133 }
134 134
135 static inline int 135 static inline int
136 same_src(const struct nf_conn *ct, 136 same_src(const struct nf_conn *ct,
137 const struct nf_conntrack_tuple *tuple) 137 const struct nf_conntrack_tuple *tuple)
138 { 138 {
139 const struct nf_conntrack_tuple *t; 139 const struct nf_conntrack_tuple *t;
140 140
141 t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 141 t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
142 return (t->dst.protonum == tuple->dst.protonum && 142 return (t->dst.protonum == tuple->dst.protonum &&
143 t->src.u3.ip == tuple->src.u3.ip && 143 t->src.u3.ip == tuple->src.u3.ip &&
144 t->src.u.all == tuple->src.u.all); 144 t->src.u.all == tuple->src.u.all);
145 } 145 }
146 146
147 /* Only called for SRC manip */ 147 /* Only called for SRC manip */
148 static int 148 static int
149 find_appropriate_src(const struct nf_conntrack_tuple *tuple, 149 find_appropriate_src(const struct nf_conntrack_tuple *tuple,
150 struct nf_conntrack_tuple *result, 150 struct nf_conntrack_tuple *result,
151 const struct nf_nat_range *range) 151 const struct nf_nat_range *range)
152 { 152 {
153 unsigned int h = hash_by_src(tuple); 153 unsigned int h = hash_by_src(tuple);
154 struct nf_conn_nat *nat; 154 struct nf_conn_nat *nat;
155 struct nf_conn *ct; 155 struct nf_conn *ct;
156 156
157 read_lock_bh(&nf_nat_lock); 157 read_lock_bh(&nf_nat_lock);
158 list_for_each_entry(nat, &bysource[h], info.bysource) { 158 list_for_each_entry(nat, &bysource[h], bysource) {
159 ct = nat->info.ct; 159 ct = nat->ct;
160 if (same_src(ct, tuple)) { 160 if (same_src(ct, tuple)) {
161 /* Copy source part from reply tuple. */ 161 /* Copy source part from reply tuple. */
162 nf_ct_invert_tuplepr(result, 162 nf_ct_invert_tuplepr(result,
163 &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 163 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
164 result->dst = tuple->dst; 164 result->dst = tuple->dst;
165 165
166 if (in_range(result, range)) { 166 if (in_range(result, range)) {
167 read_unlock_bh(&nf_nat_lock); 167 read_unlock_bh(&nf_nat_lock);
168 return 1; 168 return 1;
169 } 169 }
170 } 170 }
171 } 171 }
172 read_unlock_bh(&nf_nat_lock); 172 read_unlock_bh(&nf_nat_lock);
173 return 0; 173 return 0;
174 } 174 }
175 175
176 /* For [FUTURE] fragmentation handling, we want the least-used 176 /* For [FUTURE] fragmentation handling, we want the least-used
177 src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus 177 src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
178 if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports 178 if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
179 1-65535, we don't do pro-rata allocation based on ports; we choose 179 1-65535, we don't do pro-rata allocation based on ports; we choose
180 the ip with the lowest src-ip/dst-ip/proto usage. 180 the ip with the lowest src-ip/dst-ip/proto usage.
181 */ 181 */
182 static void 182 static void
183 find_best_ips_proto(struct nf_conntrack_tuple *tuple, 183 find_best_ips_proto(struct nf_conntrack_tuple *tuple,
184 const struct nf_nat_range *range, 184 const struct nf_nat_range *range,
185 const struct nf_conn *ct, 185 const struct nf_conn *ct,
186 enum nf_nat_manip_type maniptype) 186 enum nf_nat_manip_type maniptype)
187 { 187 {
188 __be32 *var_ipp; 188 __be32 *var_ipp;
189 /* Host order */ 189 /* Host order */
190 u_int32_t minip, maxip, j; 190 u_int32_t minip, maxip, j;
191 191
192 /* No IP mapping? Do nothing. */ 192 /* No IP mapping? Do nothing. */
193 if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) 193 if (!(range->flags & IP_NAT_RANGE_MAP_IPS))
194 return; 194 return;
195 195
196 if (maniptype == IP_NAT_MANIP_SRC) 196 if (maniptype == IP_NAT_MANIP_SRC)
197 var_ipp = &tuple->src.u3.ip; 197 var_ipp = &tuple->src.u3.ip;
198 else 198 else
199 var_ipp = &tuple->dst.u3.ip; 199 var_ipp = &tuple->dst.u3.ip;
200 200
201 /* Fast path: only one choice. */ 201 /* Fast path: only one choice. */
202 if (range->min_ip == range->max_ip) { 202 if (range->min_ip == range->max_ip) {
203 *var_ipp = range->min_ip; 203 *var_ipp = range->min_ip;
204 return; 204 return;
205 } 205 }
206 206
207 /* Hashing source and destination IPs gives a fairly even 207 /* Hashing source and destination IPs gives a fairly even
208 * spread in practice (if there are a small number of IPs 208 * spread in practice (if there are a small number of IPs
209 * involved, there usually aren't that many connections 209 * involved, there usually aren't that many connections
210 * anyway). The consistency means that servers see the same 210 * anyway). The consistency means that servers see the same
211 * client coming from the same IP (some Internet Banking sites 211 * client coming from the same IP (some Internet Banking sites
212 * like this), even across reboots. */ 212 * like this), even across reboots. */
213 minip = ntohl(range->min_ip); 213 minip = ntohl(range->min_ip);
214 maxip = ntohl(range->max_ip); 214 maxip = ntohl(range->max_ip);
215 j = jhash_2words((__force u32)tuple->src.u3.ip, 215 j = jhash_2words((__force u32)tuple->src.u3.ip,
216 (__force u32)tuple->dst.u3.ip, 0); 216 (__force u32)tuple->dst.u3.ip, 0);
217 *var_ipp = htonl(minip + j % (maxip - minip + 1)); 217 *var_ipp = htonl(minip + j % (maxip - minip + 1));
218 } 218 }
219 219
220 /* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, 220 /* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING,
221 * we change the source to map into the range. For NF_IP_PRE_ROUTING 221 * we change the source to map into the range. For NF_IP_PRE_ROUTING
222 * and NF_IP_LOCAL_OUT, we change the destination to map into the 222 * and NF_IP_LOCAL_OUT, we change the destination to map into the
223 * range. It might not be possible to get a unique tuple, but we try. 223 * range. It might not be possible to get a unique tuple, but we try.
224 * At worst (or if we race), we will end up with a final duplicate in 224 * At worst (or if we race), we will end up with a final duplicate in
225 * __ip_conntrack_confirm and drop the packet. */ 225 * __ip_conntrack_confirm and drop the packet. */
226 static void 226 static void
227 get_unique_tuple(struct nf_conntrack_tuple *tuple, 227 get_unique_tuple(struct nf_conntrack_tuple *tuple,
228 const struct nf_conntrack_tuple *orig_tuple, 228 const struct nf_conntrack_tuple *orig_tuple,
229 const struct nf_nat_range *range, 229 const struct nf_nat_range *range,
230 struct nf_conn *ct, 230 struct nf_conn *ct,
231 enum nf_nat_manip_type maniptype) 231 enum nf_nat_manip_type maniptype)
232 { 232 {
233 struct nf_nat_protocol *proto; 233 struct nf_nat_protocol *proto;
234 234
235 /* 1) If this srcip/proto/src-proto-part is currently mapped, 235 /* 1) If this srcip/proto/src-proto-part is currently mapped,
236 and that same mapping gives a unique tuple within the given 236 and that same mapping gives a unique tuple within the given
237 range, use that. 237 range, use that.
238 238
239 This is only required for source (ie. NAT/masq) mappings. 239 This is only required for source (ie. NAT/masq) mappings.
240 So far, we don't do local source mappings, so multiple 240 So far, we don't do local source mappings, so multiple
241 manips not an issue. */ 241 manips not an issue. */
242 if (maniptype == IP_NAT_MANIP_SRC) { 242 if (maniptype == IP_NAT_MANIP_SRC) {
243 if (find_appropriate_src(orig_tuple, tuple, range)) { 243 if (find_appropriate_src(orig_tuple, tuple, range)) {
244 DEBUGP("get_unique_tuple: Found current src map\n"); 244 DEBUGP("get_unique_tuple: Found current src map\n");
245 if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) 245 if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
246 if (!nf_nat_used_tuple(tuple, ct)) 246 if (!nf_nat_used_tuple(tuple, ct))
247 return; 247 return;
248 } 248 }
249 } 249 }
250 250
251 /* 2) Select the least-used IP/proto combination in the given 251 /* 2) Select the least-used IP/proto combination in the given
252 range. */ 252 range. */
253 *tuple = *orig_tuple; 253 *tuple = *orig_tuple;
254 find_best_ips_proto(tuple, range, ct, maniptype); 254 find_best_ips_proto(tuple, range, ct, maniptype);
255 255
256 /* 3) The per-protocol part of the manip is made to map into 256 /* 3) The per-protocol part of the manip is made to map into
257 the range to make a unique tuple. */ 257 the range to make a unique tuple. */
258 258
259 rcu_read_lock(); 259 rcu_read_lock();
260 proto = __nf_nat_proto_find(orig_tuple->dst.protonum); 260 proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
261 261
262 /* Change protocol info to have some randomization */ 262 /* Change protocol info to have some randomization */
263 if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { 263 if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
264 proto->unique_tuple(tuple, range, maniptype, ct); 264 proto->unique_tuple(tuple, range, maniptype, ct);
265 goto out; 265 goto out;
266 } 266 }
267 267
268 /* Only bother mapping if it's not already in range and unique */ 268 /* Only bother mapping if it's not already in range and unique */
269 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || 269 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
270 proto->in_range(tuple, maniptype, &range->min, &range->max)) && 270 proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
271 !nf_nat_used_tuple(tuple, ct)) 271 !nf_nat_used_tuple(tuple, ct))
272 goto out; 272 goto out;
273 273
274 /* Last change: get protocol to try to obtain unique tuple. */ 274 /* Last change: get protocol to try to obtain unique tuple. */
275 proto->unique_tuple(tuple, range, maniptype, ct); 275 proto->unique_tuple(tuple, range, maniptype, ct);
276 out: 276 out:
277 rcu_read_unlock(); 277 rcu_read_unlock();
278 } 278 }
279 279
280 unsigned int 280 unsigned int
281 nf_nat_setup_info(struct nf_conn *ct, 281 nf_nat_setup_info(struct nf_conn *ct,
282 const struct nf_nat_range *range, 282 const struct nf_nat_range *range,
283 unsigned int hooknum) 283 unsigned int hooknum)
284 { 284 {
285 struct nf_conntrack_tuple curr_tuple, new_tuple; 285 struct nf_conntrack_tuple curr_tuple, new_tuple;
286 struct nf_conn_nat *nat; 286 struct nf_conn_nat *nat;
287 struct nf_nat_info *info;
288 int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); 287 int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK);
289 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 288 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
290 289
291 /* nat helper or nfctnetlink also setup binding */ 290 /* nat helper or nfctnetlink also setup binding */
292 nat = nfct_nat(ct); 291 nat = nfct_nat(ct);
293 if (!nat) { 292 if (!nat) {
294 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); 293 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
295 if (nat == NULL) { 294 if (nat == NULL) {
296 DEBUGP("failed to add NAT extension\n"); 295 DEBUGP("failed to add NAT extension\n");
297 return NF_ACCEPT; 296 return NF_ACCEPT;
298 } 297 }
299 } 298 }
300 299
301 NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || 300 NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
302 hooknum == NF_IP_POST_ROUTING || 301 hooknum == NF_IP_POST_ROUTING ||
303 hooknum == NF_IP_LOCAL_IN || 302 hooknum == NF_IP_LOCAL_IN ||
304 hooknum == NF_IP_LOCAL_OUT); 303 hooknum == NF_IP_LOCAL_OUT);
305 BUG_ON(nf_nat_initialized(ct, maniptype)); 304 BUG_ON(nf_nat_initialized(ct, maniptype));
306 305
307 /* What we've got will look like inverse of reply. Normally 306 /* What we've got will look like inverse of reply. Normally
308 this is what is in the conntrack, except for prior 307 this is what is in the conntrack, except for prior
309 manipulations (future optimization: if num_manips == 0, 308 manipulations (future optimization: if num_manips == 0,
310 orig_tp = 309 orig_tp =
311 conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ 310 conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
312 nf_ct_invert_tuplepr(&curr_tuple, 311 nf_ct_invert_tuplepr(&curr_tuple,
313 &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 312 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
314 313
315 get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype); 314 get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
316 315
317 if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) { 316 if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
318 struct nf_conntrack_tuple reply; 317 struct nf_conntrack_tuple reply;
319 318
320 /* Alter conntrack table so will recognize replies. */ 319 /* Alter conntrack table so will recognize replies. */
321 nf_ct_invert_tuplepr(&reply, &new_tuple); 320 nf_ct_invert_tuplepr(&reply, &new_tuple);
322 nf_conntrack_alter_reply(ct, &reply); 321 nf_conntrack_alter_reply(ct, &reply);
323 322
324 /* Non-atomic: we own this at the moment. */ 323 /* Non-atomic: we own this at the moment. */
325 if (maniptype == IP_NAT_MANIP_SRC) 324 if (maniptype == IP_NAT_MANIP_SRC)
326 ct->status |= IPS_SRC_NAT; 325 ct->status |= IPS_SRC_NAT;
327 else 326 else
328 ct->status |= IPS_DST_NAT; 327 ct->status |= IPS_DST_NAT;
329 } 328 }
330 329
331 /* Place in source hash if this is the first time. */ 330 /* Place in source hash if this is the first time. */
332 if (have_to_hash) { 331 if (have_to_hash) {
333 unsigned int srchash; 332 unsigned int srchash;
334 333
335 srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 334 srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
336 write_lock_bh(&nf_nat_lock); 335 write_lock_bh(&nf_nat_lock);
337 /* nf_conntrack_alter_reply might re-allocate exntension aera */ 336 /* nf_conntrack_alter_reply might re-allocate exntension aera */
338 info = &nfct_nat(ct)->info; 337 nat = nfct_nat(ct);
339 info->ct = ct; 338 nat->ct = ct;
340 list_add(&info->bysource, &bysource[srchash]); 339 list_add(&nat->bysource, &bysource[srchash]);
341 write_unlock_bh(&nf_nat_lock); 340 write_unlock_bh(&nf_nat_lock);
342 } 341 }
343 342
344 /* It's done. */ 343 /* It's done. */
345 if (maniptype == IP_NAT_MANIP_DST) 344 if (maniptype == IP_NAT_MANIP_DST)
346 set_bit(IPS_DST_NAT_DONE_BIT, &ct->status); 345 set_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
347 else 346 else
348 set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); 347 set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status);
349 348
350 return NF_ACCEPT; 349 return NF_ACCEPT;
351 } 350 }
352 EXPORT_SYMBOL(nf_nat_setup_info); 351 EXPORT_SYMBOL(nf_nat_setup_info);
353 352
354 /* Returns true if succeeded. */ 353 /* Returns true if succeeded. */
355 static int 354 static int
356 manip_pkt(u_int16_t proto, 355 manip_pkt(u_int16_t proto,
357 struct sk_buff **pskb, 356 struct sk_buff **pskb,
358 unsigned int iphdroff, 357 unsigned int iphdroff,
359 const struct nf_conntrack_tuple *target, 358 const struct nf_conntrack_tuple *target,
360 enum nf_nat_manip_type maniptype) 359 enum nf_nat_manip_type maniptype)
361 { 360 {
362 struct iphdr *iph; 361 struct iphdr *iph;
363 struct nf_nat_protocol *p; 362 struct nf_nat_protocol *p;
364 363
365 if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) 364 if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
366 return 0; 365 return 0;
367 366
368 iph = (void *)(*pskb)->data + iphdroff; 367 iph = (void *)(*pskb)->data + iphdroff;
369 368
370 /* Manipulate protcol part. */ 369 /* Manipulate protcol part. */
371 370
372 /* rcu_read_lock()ed by nf_hook_slow */ 371 /* rcu_read_lock()ed by nf_hook_slow */
373 p = __nf_nat_proto_find(proto); 372 p = __nf_nat_proto_find(proto);
374 if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) 373 if (!p->manip_pkt(pskb, iphdroff, target, maniptype))
375 return 0; 374 return 0;
376 375
377 iph = (void *)(*pskb)->data + iphdroff; 376 iph = (void *)(*pskb)->data + iphdroff;
378 377
379 if (maniptype == IP_NAT_MANIP_SRC) { 378 if (maniptype == IP_NAT_MANIP_SRC) {
380 nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); 379 nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
381 iph->saddr = target->src.u3.ip; 380 iph->saddr = target->src.u3.ip;
382 } else { 381 } else {
383 nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); 382 nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
384 iph->daddr = target->dst.u3.ip; 383 iph->daddr = target->dst.u3.ip;
385 } 384 }
386 return 1; 385 return 1;
387 } 386 }
388 387
389 /* Do packet manipulations according to nf_nat_setup_info. */ 388 /* Do packet manipulations according to nf_nat_setup_info. */
390 unsigned int nf_nat_packet(struct nf_conn *ct, 389 unsigned int nf_nat_packet(struct nf_conn *ct,
391 enum ip_conntrack_info ctinfo, 390 enum ip_conntrack_info ctinfo,
392 unsigned int hooknum, 391 unsigned int hooknum,
393 struct sk_buff **pskb) 392 struct sk_buff **pskb)
394 { 393 {
395 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 394 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
396 unsigned long statusbit; 395 unsigned long statusbit;
397 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); 396 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);
398 397
399 if (mtype == IP_NAT_MANIP_SRC) 398 if (mtype == IP_NAT_MANIP_SRC)
400 statusbit = IPS_SRC_NAT; 399 statusbit = IPS_SRC_NAT;
401 else 400 else
402 statusbit = IPS_DST_NAT; 401 statusbit = IPS_DST_NAT;
403 402
404 /* Invert if this is reply dir. */ 403 /* Invert if this is reply dir. */
405 if (dir == IP_CT_DIR_REPLY) 404 if (dir == IP_CT_DIR_REPLY)
406 statusbit ^= IPS_NAT_MASK; 405 statusbit ^= IPS_NAT_MASK;
407 406
408 /* Non-atomic: these bits don't change. */ 407 /* Non-atomic: these bits don't change. */
409 if (ct->status & statusbit) { 408 if (ct->status & statusbit) {
410 struct nf_conntrack_tuple target; 409 struct nf_conntrack_tuple target;
411 410
412 /* We are aiming to look like inverse of other direction. */ 411 /* We are aiming to look like inverse of other direction. */
413 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 412 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
414 413
415 if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) 414 if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
416 return NF_DROP; 415 return NF_DROP;
417 } 416 }
418 return NF_ACCEPT; 417 return NF_ACCEPT;
419 } 418 }
420 EXPORT_SYMBOL_GPL(nf_nat_packet); 419 EXPORT_SYMBOL_GPL(nf_nat_packet);
421 420
422 /* Dir is direction ICMP is coming from (opposite to packet it contains) */ 421 /* Dir is direction ICMP is coming from (opposite to packet it contains) */
423 int nf_nat_icmp_reply_translation(struct nf_conn *ct, 422 int nf_nat_icmp_reply_translation(struct nf_conn *ct,
424 enum ip_conntrack_info ctinfo, 423 enum ip_conntrack_info ctinfo,
425 unsigned int hooknum, 424 unsigned int hooknum,
426 struct sk_buff **pskb) 425 struct sk_buff **pskb)
427 { 426 {
428 struct { 427 struct {
429 struct icmphdr icmp; 428 struct icmphdr icmp;
430 struct iphdr ip; 429 struct iphdr ip;
431 } *inside; 430 } *inside;
432 struct nf_conntrack_l4proto *l4proto; 431 struct nf_conntrack_l4proto *l4proto;
433 struct nf_conntrack_tuple inner, target; 432 struct nf_conntrack_tuple inner, target;
434 int hdrlen = ip_hdrlen(*pskb); 433 int hdrlen = ip_hdrlen(*pskb);
435 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 434 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
436 unsigned long statusbit; 435 unsigned long statusbit;
437 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); 436 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
438 437
439 if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) 438 if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
440 return 0; 439 return 0;
441 440
442 inside = (void *)(*pskb)->data + ip_hdrlen(*pskb); 441 inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
443 442
444 /* We're actually going to mangle it beyond trivial checksum 443 /* We're actually going to mangle it beyond trivial checksum
445 adjustment, so make sure the current checksum is correct. */ 444 adjustment, so make sure the current checksum is correct. */
446 if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) 445 if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0))
447 return 0; 446 return 0;
448 447
449 /* Must be RELATED */ 448 /* Must be RELATED */
450 NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || 449 NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
451 (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); 450 (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
452 451
453 /* Redirects on non-null nats must be dropped, else they'll 452 /* Redirects on non-null nats must be dropped, else they'll
454 start talking to each other without our translation, and be 453 start talking to each other without our translation, and be
455 confused... --RR */ 454 confused... --RR */
456 if (inside->icmp.type == ICMP_REDIRECT) { 455 if (inside->icmp.type == ICMP_REDIRECT) {
457 /* If NAT isn't finished, assume it and drop. */ 456 /* If NAT isn't finished, assume it and drop. */
458 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) 457 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
459 return 0; 458 return 0;
460 459
461 if (ct->status & IPS_NAT_MASK) 460 if (ct->status & IPS_NAT_MASK)
462 return 0; 461 return 0;
463 } 462 }
464 463
465 DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", 464 DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n",
466 *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); 465 *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
467 466
468 /* rcu_read_lock()ed by nf_hook_slow */ 467 /* rcu_read_lock()ed by nf_hook_slow */
469 l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); 468 l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
470 469
471 if (!nf_ct_get_tuple(*pskb, 470 if (!nf_ct_get_tuple(*pskb,
472 ip_hdrlen(*pskb) + sizeof(struct icmphdr), 471 ip_hdrlen(*pskb) + sizeof(struct icmphdr),
473 (ip_hdrlen(*pskb) + 472 (ip_hdrlen(*pskb) +
474 sizeof(struct icmphdr) + inside->ip.ihl * 4), 473 sizeof(struct icmphdr) + inside->ip.ihl * 4),
475 (u_int16_t)AF_INET, 474 (u_int16_t)AF_INET,
476 inside->ip.protocol, 475 inside->ip.protocol,
477 &inner, l3proto, l4proto)) 476 &inner, l3proto, l4proto))
478 return 0; 477 return 0;
479 478
480 /* Change inner back to look like incoming packet. We do the 479 /* Change inner back to look like incoming packet. We do the
481 opposite manip on this hook to normal, because it might not 480 opposite manip on this hook to normal, because it might not
482 pass all hooks (locally-generated ICMP). Consider incoming 481 pass all hooks (locally-generated ICMP). Consider incoming
483 packet: PREROUTING (DST manip), routing produces ICMP, goes 482 packet: PREROUTING (DST manip), routing produces ICMP, goes
484 through POSTROUTING (which must correct the DST manip). */ 483 through POSTROUTING (which must correct the DST manip). */
485 if (!manip_pkt(inside->ip.protocol, pskb, 484 if (!manip_pkt(inside->ip.protocol, pskb,
486 ip_hdrlen(*pskb) + sizeof(inside->icmp), 485 ip_hdrlen(*pskb) + sizeof(inside->icmp),
487 &ct->tuplehash[!dir].tuple, 486 &ct->tuplehash[!dir].tuple,
488 !manip)) 487 !manip))
489 return 0; 488 return 0;
490 489
491 if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { 490 if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
492 /* Reloading "inside" here since manip_pkt inner. */ 491 /* Reloading "inside" here since manip_pkt inner. */
493 inside = (void *)(*pskb)->data + ip_hdrlen(*pskb); 492 inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
494 inside->icmp.checksum = 0; 493 inside->icmp.checksum = 0;
495 inside->icmp.checksum = 494 inside->icmp.checksum =
496 csum_fold(skb_checksum(*pskb, hdrlen, 495 csum_fold(skb_checksum(*pskb, hdrlen,
497 (*pskb)->len - hdrlen, 0)); 496 (*pskb)->len - hdrlen, 0));
498 } 497 }
499 498
500 /* Change outer to look the reply to an incoming packet 499 /* Change outer to look the reply to an incoming packet
501 * (proto 0 means don't invert per-proto part). */ 500 * (proto 0 means don't invert per-proto part). */
502 if (manip == IP_NAT_MANIP_SRC) 501 if (manip == IP_NAT_MANIP_SRC)
503 statusbit = IPS_SRC_NAT; 502 statusbit = IPS_SRC_NAT;
504 else 503 else
505 statusbit = IPS_DST_NAT; 504 statusbit = IPS_DST_NAT;
506 505
507 /* Invert if this is reply dir. */ 506 /* Invert if this is reply dir. */
508 if (dir == IP_CT_DIR_REPLY) 507 if (dir == IP_CT_DIR_REPLY)
509 statusbit ^= IPS_NAT_MASK; 508 statusbit ^= IPS_NAT_MASK;
510 509
511 if (ct->status & statusbit) { 510 if (ct->status & statusbit) {
512 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 511 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
513 if (!manip_pkt(0, pskb, 0, &target, manip)) 512 if (!manip_pkt(0, pskb, 0, &target, manip))
514 return 0; 513 return 0;
515 } 514 }
516 515
517 return 1; 516 return 1;
518 } 517 }
519 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); 518 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
520 519
521 /* Protocol registration. */ 520 /* Protocol registration. */
522 int nf_nat_protocol_register(struct nf_nat_protocol *proto) 521 int nf_nat_protocol_register(struct nf_nat_protocol *proto)
523 { 522 {
524 int ret = 0; 523 int ret = 0;
525 524
526 write_lock_bh(&nf_nat_lock); 525 write_lock_bh(&nf_nat_lock);
527 if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { 526 if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) {
528 ret = -EBUSY; 527 ret = -EBUSY;
529 goto out; 528 goto out;
530 } 529 }
531 rcu_assign_pointer(nf_nat_protos[proto->protonum], proto); 530 rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
532 out: 531 out:
533 write_unlock_bh(&nf_nat_lock); 532 write_unlock_bh(&nf_nat_lock);
534 return ret; 533 return ret;
535 } 534 }
536 EXPORT_SYMBOL(nf_nat_protocol_register); 535 EXPORT_SYMBOL(nf_nat_protocol_register);
537 536
538 /* Noone stores the protocol anywhere; simply delete it. */ 537 /* Noone stores the protocol anywhere; simply delete it. */
539 void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) 538 void nf_nat_protocol_unregister(struct nf_nat_protocol *proto)
540 { 539 {
541 write_lock_bh(&nf_nat_lock); 540 write_lock_bh(&nf_nat_lock);
542 rcu_assign_pointer(nf_nat_protos[proto->protonum], 541 rcu_assign_pointer(nf_nat_protos[proto->protonum],
543 &nf_nat_unknown_protocol); 542 &nf_nat_unknown_protocol);
544 write_unlock_bh(&nf_nat_lock); 543 write_unlock_bh(&nf_nat_lock);
545 synchronize_rcu(); 544 synchronize_rcu();
546 } 545 }
547 EXPORT_SYMBOL(nf_nat_protocol_unregister); 546 EXPORT_SYMBOL(nf_nat_protocol_unregister);
548 547
549 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 548 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
550 int 549 int
551 nf_nat_port_range_to_nfattr(struct sk_buff *skb, 550 nf_nat_port_range_to_nfattr(struct sk_buff *skb,
552 const struct nf_nat_range *range) 551 const struct nf_nat_range *range)
553 { 552 {
554 NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), 553 NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16),
555 &range->min.tcp.port); 554 &range->min.tcp.port);
556 NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), 555 NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),
557 &range->max.tcp.port); 556 &range->max.tcp.port);
558 557
559 return 0; 558 return 0;
560 559
561 nfattr_failure: 560 nfattr_failure:
562 return -1; 561 return -1;
563 } 562 }
564 EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); 563 EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range);
565 564
566 int 565 int
567 nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) 566 nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range)
568 { 567 {
569 int ret = 0; 568 int ret = 0;
570 569
571 /* we have to return whether we actually parsed something or not */ 570 /* we have to return whether we actually parsed something or not */
572 571
573 if (tb[CTA_PROTONAT_PORT_MIN-1]) { 572 if (tb[CTA_PROTONAT_PORT_MIN-1]) {
574 ret = 1; 573 ret = 1;
575 range->min.tcp.port = 574 range->min.tcp.port =
576 *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); 575 *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
577 } 576 }
578 577
579 if (!tb[CTA_PROTONAT_PORT_MAX-1]) { 578 if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
580 if (ret) 579 if (ret)
581 range->max.tcp.port = range->min.tcp.port; 580 range->max.tcp.port = range->min.tcp.port;
582 } else { 581 } else {
583 ret = 1; 582 ret = 1;
584 range->max.tcp.port = 583 range->max.tcp.port =
585 *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); 584 *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
586 } 585 }
587 586
588 return ret; 587 return ret;
589 } 588 }
590 EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); 589 EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr);
591 #endif 590 #endif
592 591
593 /* Noone using conntrack by the time this called. */ 592 /* Noone using conntrack by the time this called. */
594 static void nf_nat_cleanup_conntrack(struct nf_conn *ct) 593 static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
595 { 594 {
596 struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT); 595 struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
597 596
598 if (nat == NULL || nat->info.ct == NULL) 597 if (nat == NULL || nat->ct == NULL)
599 return; 598 return;
600 599
601 NF_CT_ASSERT(nat->info.ct->status & IPS_NAT_DONE_MASK); 600 NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK);
602 601
603 write_lock_bh(&nf_nat_lock); 602 write_lock_bh(&nf_nat_lock);
604 list_del(&nat->info.bysource); 603 list_del(&nat->bysource);
605 nat->info.ct = NULL; 604 nat->ct = NULL;
606 write_unlock_bh(&nf_nat_lock); 605 write_unlock_bh(&nf_nat_lock);
607 } 606 }
608 607
609 static void nf_nat_move_storage(struct nf_conn *conntrack, void *old) 608 static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
610 { 609 {
611 struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT); 610 struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT);
612 struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old; 611 struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old;
613 struct nf_conn *ct = old_nat->info.ct; 612 struct nf_conn *ct = old_nat->ct;
614 unsigned int srchash; 613 unsigned int srchash;
615 614
616 if (!(ct->status & IPS_NAT_DONE_MASK)) 615 if (!(ct->status & IPS_NAT_DONE_MASK))
617 return; 616 return;
618 617
619 srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 618 srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
620 619
621 write_lock_bh(&nf_nat_lock); 620 write_lock_bh(&nf_nat_lock);
622 list_replace(&old_nat->info.bysource, &new_nat->info.bysource); 621 list_replace(&old_nat->bysource, &new_nat->bysource);
623 new_nat->info.ct = ct; 622 new_nat->ct = ct;
624 write_unlock_bh(&nf_nat_lock); 623 write_unlock_bh(&nf_nat_lock);
625 } 624 }
626 625
627 struct nf_ct_ext_type nat_extend = { 626 struct nf_ct_ext_type nat_extend = {
628 .len = sizeof(struct nf_conn_nat), 627 .len = sizeof(struct nf_conn_nat),
629 .align = __alignof__(struct nf_conn_nat), 628 .align = __alignof__(struct nf_conn_nat),
630 .destroy = nf_nat_cleanup_conntrack, 629 .destroy = nf_nat_cleanup_conntrack,
631 .move = nf_nat_move_storage, 630 .move = nf_nat_move_storage,
632 .id = NF_CT_EXT_NAT, 631 .id = NF_CT_EXT_NAT,
633 .flags = NF_CT_EXT_F_PREALLOC, 632 .flags = NF_CT_EXT_F_PREALLOC,
634 }; 633 };
635 634
636 static int __init nf_nat_init(void) 635 static int __init nf_nat_init(void)
637 { 636 {
638 size_t i; 637 size_t i;
639 int ret; 638 int ret;
640 639
641 ret = nf_ct_extend_register(&nat_extend); 640 ret = nf_ct_extend_register(&nat_extend);
642 if (ret < 0) { 641 if (ret < 0) {
643 printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); 642 printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
644 return ret; 643 return ret;
645 } 644 }
646 645
647 /* Leave them the same for the moment. */ 646 /* Leave them the same for the moment. */
648 nf_nat_htable_size = nf_conntrack_htable_size; 647 nf_nat_htable_size = nf_conntrack_htable_size;
649 648
650 /* One vmalloc for both hash tables */ 649 /* One vmalloc for both hash tables */
651 bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); 650 bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size);
652 if (!bysource) { 651 if (!bysource) {
653 ret = -ENOMEM; 652 ret = -ENOMEM;
654 goto cleanup_extend; 653 goto cleanup_extend;
655 } 654 }
656 655
657 /* Sew in builtin protocols. */ 656 /* Sew in builtin protocols. */
658 write_lock_bh(&nf_nat_lock); 657 write_lock_bh(&nf_nat_lock);
659 for (i = 0; i < MAX_IP_NAT_PROTO; i++) 658 for (i = 0; i < MAX_IP_NAT_PROTO; i++)
660 rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol); 659 rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
661 rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp); 660 rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
662 rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp); 661 rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
663 rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp); 662 rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
664 write_unlock_bh(&nf_nat_lock); 663 write_unlock_bh(&nf_nat_lock);
665 664
666 for (i = 0; i < nf_nat_htable_size; i++) { 665 for (i = 0; i < nf_nat_htable_size; i++) {
667 INIT_LIST_HEAD(&bysource[i]); 666 INIT_LIST_HEAD(&bysource[i]);
668 } 667 }
669 668
670 /* Initialize fake conntrack so that NAT will skip it */ 669 /* Initialize fake conntrack so that NAT will skip it */
671 nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; 670 nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
672 671
673 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); 672 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
674 return 0; 673 return 0;
675 674
676 cleanup_extend: 675 cleanup_extend:
677 nf_ct_extend_unregister(&nat_extend); 676 nf_ct_extend_unregister(&nat_extend);
678 return ret; 677 return ret;
679 } 678 }
680 679
681 /* Clear NAT section of all conntracks, in case we're loaded again. */ 680 /* Clear NAT section of all conntracks, in case we're loaded again. */
682 static int clean_nat(struct nf_conn *i, void *data) 681 static int clean_nat(struct nf_conn *i, void *data)
683 { 682 {
684 struct nf_conn_nat *nat = nfct_nat(i); 683 struct nf_conn_nat *nat = nfct_nat(i);
685 684
686 if (!nat) 685 if (!nat)
687 return 0; 686 return 0;
688 memset(nat, 0, sizeof(nat)); 687 memset(nat, 0, sizeof(nat));
689 i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); 688 i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
690 return 0; 689 return 0;
691 } 690 }
692 691
693 static void __exit nf_nat_cleanup(void) 692 static void __exit nf_nat_cleanup(void)
694 { 693 {
695 nf_ct_iterate_cleanup(&clean_nat, NULL); 694 nf_ct_iterate_cleanup(&clean_nat, NULL);
696 synchronize_rcu(); 695 synchronize_rcu();
697 vfree(bysource); 696 vfree(bysource);
698 nf_ct_l3proto_put(l3proto); 697 nf_ct_l3proto_put(l3proto);
699 nf_ct_extend_unregister(&nat_extend); 698 nf_ct_extend_unregister(&nat_extend);
700 } 699 }
701 700
702 MODULE_LICENSE("GPL"); 701 MODULE_LICENSE("GPL");
703 702
704 module_init(nf_nat_init); 703 module_init(nf_nat_init);
705 module_exit(nf_nat_cleanup); 704 module_exit(nf_nat_cleanup);
706 705
net/ipv4/netfilter/nf_nat_helper.c
1 /* ip_nat_helper.c - generic support functions for NAT helpers 1 /* ip_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>
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
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 #include <linux/module.h> 10 #include <linux/module.h>
11 #include <linux/kmod.h> 11 #include <linux/kmod.h>
12 #include <linux/types.h> 12 #include <linux/types.h>
13 #include <linux/timer.h> 13 #include <linux/timer.h>
14 #include <linux/skbuff.h> 14 #include <linux/skbuff.h>
15 #include <linux/tcp.h> 15 #include <linux/tcp.h>
16 #include <linux/udp.h> 16 #include <linux/udp.h>
17 #include <net/checksum.h> 17 #include <net/checksum.h>
18 #include <net/tcp.h> 18 #include <net/tcp.h>
19 19
20 #include <linux/netfilter_ipv4.h> 20 #include <linux/netfilter_ipv4.h>
21 #include <net/netfilter/nf_conntrack.h> 21 #include <net/netfilter/nf_conntrack.h>
22 #include <net/netfilter/nf_conntrack_helper.h> 22 #include <net/netfilter/nf_conntrack_helper.h>
23 #include <net/netfilter/nf_conntrack_expect.h> 23 #include <net/netfilter/nf_conntrack_expect.h>
24 #include <net/netfilter/nf_nat.h> 24 #include <net/netfilter/nf_nat.h>
25 #include <net/netfilter/nf_nat_protocol.h> 25 #include <net/netfilter/nf_nat_protocol.h>
26 #include <net/netfilter/nf_nat_core.h> 26 #include <net/netfilter/nf_nat_core.h>
27 #include <net/netfilter/nf_nat_helper.h> 27 #include <net/netfilter/nf_nat_helper.h>
28 28
29 #if 0 29 #if 0
30 #define DEBUGP printk 30 #define DEBUGP printk
31 #define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); 31 #define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
32 #else 32 #else
33 #define DEBUGP(format, args...) 33 #define DEBUGP(format, args...)
34 #define DUMP_OFFSET(x) 34 #define DUMP_OFFSET(x)
35 #endif 35 #endif
36 36
37 static DEFINE_SPINLOCK(nf_nat_seqofs_lock); 37 static DEFINE_SPINLOCK(nf_nat_seqofs_lock);
38 38
39 /* Setup TCP sequence correction given this change at this sequence */ 39 /* Setup TCP sequence correction given this change at this sequence */
40 static inline void 40 static inline void
41 adjust_tcp_sequence(u32 seq, 41 adjust_tcp_sequence(u32 seq,
42 int sizediff, 42 int sizediff,
43 struct nf_conn *ct, 43 struct nf_conn *ct,
44 enum ip_conntrack_info ctinfo) 44 enum ip_conntrack_info ctinfo)
45 { 45 {
46 int dir; 46 int dir;
47 struct nf_nat_seq *this_way, *other_way; 47 struct nf_nat_seq *this_way, *other_way;
48 struct nf_conn_nat *nat = nfct_nat(ct); 48 struct nf_conn_nat *nat = nfct_nat(ct);
49 49
50 DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n", 50 DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n",
51 (*skb)->len, new_size); 51 (*skb)->len, new_size);
52 52
53 dir = CTINFO2DIR(ctinfo); 53 dir = CTINFO2DIR(ctinfo);
54 54
55 this_way = &nat->info.seq[dir]; 55 this_way = &nat->seq[dir];
56 other_way = &nat->info.seq[!dir]; 56 other_way = &nat->seq[!dir];
57 57
58 DEBUGP("nf_nat_resize_packet: Seq_offset before: "); 58 DEBUGP("nf_nat_resize_packet: Seq_offset before: ");
59 DUMP_OFFSET(this_way); 59 DUMP_OFFSET(this_way);
60 60
61 spin_lock_bh(&nf_nat_seqofs_lock); 61 spin_lock_bh(&nf_nat_seqofs_lock);
62 62
63 /* SYN adjust. If it's uninitialized, or this is after last 63 /* SYN adjust. If it's uninitialized, or this is after last
64 * correction, record it: we don't handle more than one 64 * correction, record it: we don't handle more than one
65 * adjustment in the window, but do deal with common case of a 65 * adjustment in the window, but do deal with common case of a
66 * retransmit */ 66 * retransmit */
67 if (this_way->offset_before == this_way->offset_after || 67 if (this_way->offset_before == this_way->offset_after ||
68 before(this_way->correction_pos, seq)) { 68 before(this_way->correction_pos, seq)) {
69 this_way->correction_pos = seq; 69 this_way->correction_pos = seq;
70 this_way->offset_before = this_way->offset_after; 70 this_way->offset_before = this_way->offset_after;
71 this_way->offset_after += sizediff; 71 this_way->offset_after += sizediff;
72 } 72 }
73 spin_unlock_bh(&nf_nat_seqofs_lock); 73 spin_unlock_bh(&nf_nat_seqofs_lock);
74 74
75 DEBUGP("nf_nat_resize_packet: Seq_offset after: "); 75 DEBUGP("nf_nat_resize_packet: Seq_offset after: ");
76 DUMP_OFFSET(this_way); 76 DUMP_OFFSET(this_way);
77 } 77 }
78 78
79 /* Frobs data inside this packet, which is linear. */ 79 /* Frobs data inside this packet, which is linear. */
80 static void mangle_contents(struct sk_buff *skb, 80 static void mangle_contents(struct sk_buff *skb,
81 unsigned int dataoff, 81 unsigned int dataoff,
82 unsigned int match_offset, 82 unsigned int match_offset,
83 unsigned int match_len, 83 unsigned int match_len,
84 const char *rep_buffer, 84 const char *rep_buffer,
85 unsigned int rep_len) 85 unsigned int rep_len)
86 { 86 {
87 unsigned char *data; 87 unsigned char *data;
88 88
89 BUG_ON(skb_is_nonlinear(skb)); 89 BUG_ON(skb_is_nonlinear(skb));
90 data = skb_network_header(skb) + dataoff; 90 data = skb_network_header(skb) + dataoff;
91 91
92 /* move post-replacement */ 92 /* move post-replacement */
93 memmove(data + match_offset + rep_len, 93 memmove(data + match_offset + rep_len,
94 data + match_offset + match_len, 94 data + match_offset + match_len,
95 skb->tail - (skb->network_header + dataoff + 95 skb->tail - (skb->network_header + dataoff +
96 match_offset + match_len)); 96 match_offset + match_len));
97 97
98 /* insert data from buffer */ 98 /* insert data from buffer */
99 memcpy(data + match_offset, rep_buffer, rep_len); 99 memcpy(data + match_offset, rep_buffer, rep_len);
100 100
101 /* update skb info */ 101 /* update skb info */
102 if (rep_len > match_len) { 102 if (rep_len > match_len) {
103 DEBUGP("nf_nat_mangle_packet: Extending packet by " 103 DEBUGP("nf_nat_mangle_packet: Extending packet by "
104 "%u from %u bytes\n", rep_len - match_len, 104 "%u from %u bytes\n", rep_len - match_len,
105 skb->len); 105 skb->len);
106 skb_put(skb, rep_len - match_len); 106 skb_put(skb, rep_len - match_len);
107 } else { 107 } else {
108 DEBUGP("nf_nat_mangle_packet: Shrinking packet from " 108 DEBUGP("nf_nat_mangle_packet: Shrinking packet from "
109 "%u from %u bytes\n", match_len - rep_len, 109 "%u from %u bytes\n", match_len - rep_len,
110 skb->len); 110 skb->len);
111 __skb_trim(skb, skb->len + rep_len - match_len); 111 __skb_trim(skb, skb->len + rep_len - match_len);
112 } 112 }
113 113
114 /* fix IP hdr checksum information */ 114 /* fix IP hdr checksum information */
115 ip_hdr(skb)->tot_len = htons(skb->len); 115 ip_hdr(skb)->tot_len = htons(skb->len);
116 ip_send_check(ip_hdr(skb)); 116 ip_send_check(ip_hdr(skb));
117 } 117 }
118 118
119 /* Unusual, but possible case. */ 119 /* Unusual, but possible case. */
120 static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) 120 static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
121 { 121 {
122 struct sk_buff *nskb; 122 struct sk_buff *nskb;
123 123
124 if ((*pskb)->len + extra > 65535) 124 if ((*pskb)->len + extra > 65535)
125 return 0; 125 return 0;
126 126
127 nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); 127 nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
128 if (!nskb) 128 if (!nskb)
129 return 0; 129 return 0;
130 130
131 /* Transfer socket to new skb. */ 131 /* Transfer socket to new skb. */
132 if ((*pskb)->sk) 132 if ((*pskb)->sk)
133 skb_set_owner_w(nskb, (*pskb)->sk); 133 skb_set_owner_w(nskb, (*pskb)->sk);
134 kfree_skb(*pskb); 134 kfree_skb(*pskb);
135 *pskb = nskb; 135 *pskb = nskb;
136 return 1; 136 return 1;
137 } 137 }
138 138
139 /* Generic function for mangling variable-length address changes inside 139 /* Generic function for mangling variable-length address changes inside
140 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX 140 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
141 * command in FTP). 141 * command in FTP).
142 * 142 *
143 * Takes care about all the nasty sequence number changes, checksumming, 143 * Takes care about all the nasty sequence number changes, checksumming,
144 * skb enlargement, ... 144 * skb enlargement, ...
145 * 145 *
146 * */ 146 * */
147 int 147 int
148 nf_nat_mangle_tcp_packet(struct sk_buff **pskb, 148 nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
149 struct nf_conn *ct, 149 struct nf_conn *ct,
150 enum ip_conntrack_info ctinfo, 150 enum ip_conntrack_info ctinfo,
151 unsigned int match_offset, 151 unsigned int match_offset,
152 unsigned int match_len, 152 unsigned int match_len,
153 const char *rep_buffer, 153 const char *rep_buffer,
154 unsigned int rep_len) 154 unsigned int rep_len)
155 { 155 {
156 struct rtable *rt = (struct rtable *)(*pskb)->dst; 156 struct rtable *rt = (struct rtable *)(*pskb)->dst;
157 struct iphdr *iph; 157 struct iphdr *iph;
158 struct tcphdr *tcph; 158 struct tcphdr *tcph;
159 int oldlen, datalen; 159 int oldlen, datalen;
160 160
161 if (!skb_make_writable(pskb, (*pskb)->len)) 161 if (!skb_make_writable(pskb, (*pskb)->len))
162 return 0; 162 return 0;
163 163
164 if (rep_len > match_len && 164 if (rep_len > match_len &&
165 rep_len - match_len > skb_tailroom(*pskb) && 165 rep_len - match_len > skb_tailroom(*pskb) &&
166 !enlarge_skb(pskb, rep_len - match_len)) 166 !enlarge_skb(pskb, rep_len - match_len))
167 return 0; 167 return 0;
168 168
169 SKB_LINEAR_ASSERT(*pskb); 169 SKB_LINEAR_ASSERT(*pskb);
170 170
171 iph = ip_hdr(*pskb); 171 iph = ip_hdr(*pskb);
172 tcph = (void *)iph + iph->ihl*4; 172 tcph = (void *)iph + iph->ihl*4;
173 173
174 oldlen = (*pskb)->len - iph->ihl*4; 174 oldlen = (*pskb)->len - iph->ihl*4;
175 mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, 175 mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
176 match_offset, match_len, rep_buffer, rep_len); 176 match_offset, match_len, rep_buffer, rep_len);
177 177
178 datalen = (*pskb)->len - iph->ihl*4; 178 datalen = (*pskb)->len - iph->ihl*4;
179 if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { 179 if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
180 if (!(rt->rt_flags & RTCF_LOCAL) && 180 if (!(rt->rt_flags & RTCF_LOCAL) &&
181 (*pskb)->dev->features & NETIF_F_V4_CSUM) { 181 (*pskb)->dev->features & NETIF_F_V4_CSUM) {
182 (*pskb)->ip_summed = CHECKSUM_PARTIAL; 182 (*pskb)->ip_summed = CHECKSUM_PARTIAL;
183 (*pskb)->csum_start = skb_headroom(*pskb) + 183 (*pskb)->csum_start = skb_headroom(*pskb) +
184 skb_network_offset(*pskb) + 184 skb_network_offset(*pskb) +
185 iph->ihl * 4; 185 iph->ihl * 4;
186 (*pskb)->csum_offset = offsetof(struct tcphdr, check); 186 (*pskb)->csum_offset = offsetof(struct tcphdr, check);
187 tcph->check = ~tcp_v4_check(datalen, 187 tcph->check = ~tcp_v4_check(datalen,
188 iph->saddr, iph->daddr, 0); 188 iph->saddr, iph->daddr, 0);
189 } else { 189 } else {
190 tcph->check = 0; 190 tcph->check = 0;
191 tcph->check = tcp_v4_check(datalen, 191 tcph->check = tcp_v4_check(datalen,
192 iph->saddr, iph->daddr, 192 iph->saddr, iph->daddr,
193 csum_partial(tcph, 193 csum_partial(tcph,
194 datalen, 0)); 194 datalen, 0));
195 } 195 }
196 } else 196 } else
197 nf_proto_csum_replace2(&tcph->check, *pskb, 197 nf_proto_csum_replace2(&tcph->check, *pskb,
198 htons(oldlen), htons(datalen), 1); 198 htons(oldlen), htons(datalen), 1);
199 199
200 if (rep_len != match_len) { 200 if (rep_len != match_len) {
201 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); 201 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
202 adjust_tcp_sequence(ntohl(tcph->seq), 202 adjust_tcp_sequence(ntohl(tcph->seq),
203 (int)rep_len - (int)match_len, 203 (int)rep_len - (int)match_len,
204 ct, ctinfo); 204 ct, ctinfo);
205 /* Tell TCP window tracking about seq change */ 205 /* Tell TCP window tracking about seq change */
206 nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), 206 nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb),
207 ct, CTINFO2DIR(ctinfo)); 207 ct, CTINFO2DIR(ctinfo));
208 } 208 }
209 return 1; 209 return 1;
210 } 210 }
211 EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); 211 EXPORT_SYMBOL(nf_nat_mangle_tcp_packet);
212 212
213 /* Generic function for mangling variable-length address changes inside 213 /* Generic function for mangling variable-length address changes inside
214 * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX 214 * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
215 * command in the Amanda protocol) 215 * command in the Amanda protocol)
216 * 216 *
217 * Takes care about all the nasty sequence number changes, checksumming, 217 * Takes care about all the nasty sequence number changes, checksumming,
218 * skb enlargement, ... 218 * skb enlargement, ...
219 * 219 *
220 * XXX - This function could be merged with nf_nat_mangle_tcp_packet which 220 * XXX - This function could be merged with nf_nat_mangle_tcp_packet which
221 * should be fairly easy to do. 221 * should be fairly easy to do.
222 */ 222 */
223 int 223 int
224 nf_nat_mangle_udp_packet(struct sk_buff **pskb, 224 nf_nat_mangle_udp_packet(struct sk_buff **pskb,
225 struct nf_conn *ct, 225 struct nf_conn *ct,
226 enum ip_conntrack_info ctinfo, 226 enum ip_conntrack_info ctinfo,
227 unsigned int match_offset, 227 unsigned int match_offset,
228 unsigned int match_len, 228 unsigned int match_len,
229 const char *rep_buffer, 229 const char *rep_buffer,
230 unsigned int rep_len) 230 unsigned int rep_len)
231 { 231 {
232 struct rtable *rt = (struct rtable *)(*pskb)->dst; 232 struct rtable *rt = (struct rtable *)(*pskb)->dst;
233 struct iphdr *iph; 233 struct iphdr *iph;
234 struct udphdr *udph; 234 struct udphdr *udph;
235 int datalen, oldlen; 235 int datalen, oldlen;
236 236
237 /* UDP helpers might accidentally mangle the wrong packet */ 237 /* UDP helpers might accidentally mangle the wrong packet */
238 iph = ip_hdr(*pskb); 238 iph = ip_hdr(*pskb);
239 if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + 239 if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
240 match_offset + match_len) 240 match_offset + match_len)
241 return 0; 241 return 0;
242 242
243 if (!skb_make_writable(pskb, (*pskb)->len)) 243 if (!skb_make_writable(pskb, (*pskb)->len))
244 return 0; 244 return 0;
245 245
246 if (rep_len > match_len && 246 if (rep_len > match_len &&
247 rep_len - match_len > skb_tailroom(*pskb) && 247 rep_len - match_len > skb_tailroom(*pskb) &&
248 !enlarge_skb(pskb, rep_len - match_len)) 248 !enlarge_skb(pskb, rep_len - match_len))
249 return 0; 249 return 0;
250 250
251 iph = ip_hdr(*pskb); 251 iph = ip_hdr(*pskb);
252 udph = (void *)iph + iph->ihl*4; 252 udph = (void *)iph + iph->ihl*4;
253 253
254 oldlen = (*pskb)->len - iph->ihl*4; 254 oldlen = (*pskb)->len - iph->ihl*4;
255 mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), 255 mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
256 match_offset, match_len, rep_buffer, rep_len); 256 match_offset, match_len, rep_buffer, rep_len);
257 257
258 /* update the length of the UDP packet */ 258 /* update the length of the UDP packet */
259 datalen = (*pskb)->len - iph->ihl*4; 259 datalen = (*pskb)->len - iph->ihl*4;
260 udph->len = htons(datalen); 260 udph->len = htons(datalen);
261 261
262 /* fix udp checksum if udp checksum was previously calculated */ 262 /* fix udp checksum if udp checksum was previously calculated */
263 if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) 263 if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL)
264 return 1; 264 return 1;
265 265
266 if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { 266 if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
267 if (!(rt->rt_flags & RTCF_LOCAL) && 267 if (!(rt->rt_flags & RTCF_LOCAL) &&
268 (*pskb)->dev->features & NETIF_F_V4_CSUM) { 268 (*pskb)->dev->features & NETIF_F_V4_CSUM) {
269 (*pskb)->ip_summed = CHECKSUM_PARTIAL; 269 (*pskb)->ip_summed = CHECKSUM_PARTIAL;
270 (*pskb)->csum_start = skb_headroom(*pskb) + 270 (*pskb)->csum_start = skb_headroom(*pskb) +
271 skb_network_offset(*pskb) + 271 skb_network_offset(*pskb) +
272 iph->ihl * 4; 272 iph->ihl * 4;
273 (*pskb)->csum_offset = offsetof(struct udphdr, check); 273 (*pskb)->csum_offset = offsetof(struct udphdr, check);
274 udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, 274 udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
275 datalen, IPPROTO_UDP, 275 datalen, IPPROTO_UDP,
276 0); 276 0);
277 } else { 277 } else {
278 udph->check = 0; 278 udph->check = 0;
279 udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 279 udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
280 datalen, IPPROTO_UDP, 280 datalen, IPPROTO_UDP,
281 csum_partial(udph, 281 csum_partial(udph,
282 datalen, 0)); 282 datalen, 0));
283 if (!udph->check) 283 if (!udph->check)
284 udph->check = CSUM_MANGLED_0; 284 udph->check = CSUM_MANGLED_0;
285 } 285 }
286 } else 286 } else
287 nf_proto_csum_replace2(&udph->check, *pskb, 287 nf_proto_csum_replace2(&udph->check, *pskb,
288 htons(oldlen), htons(datalen), 1); 288 htons(oldlen), htons(datalen), 1);
289 289
290 return 1; 290 return 1;
291 } 291 }
292 EXPORT_SYMBOL(nf_nat_mangle_udp_packet); 292 EXPORT_SYMBOL(nf_nat_mangle_udp_packet);
293 293
294 /* Adjust one found SACK option including checksum correction */ 294 /* Adjust one found SACK option including checksum correction */
295 static void 295 static void
296 sack_adjust(struct sk_buff *skb, 296 sack_adjust(struct sk_buff *skb,
297 struct tcphdr *tcph, 297 struct tcphdr *tcph,
298 unsigned int sackoff, 298 unsigned int sackoff,
299 unsigned int sackend, 299 unsigned int sackend,
300 struct nf_nat_seq *natseq) 300 struct nf_nat_seq *natseq)
301 { 301 {
302 while (sackoff < sackend) { 302 while (sackoff < sackend) {
303 struct tcp_sack_block_wire *sack; 303 struct tcp_sack_block_wire *sack;
304 __be32 new_start_seq, new_end_seq; 304 __be32 new_start_seq, new_end_seq;
305 305
306 sack = (void *)skb->data + sackoff; 306 sack = (void *)skb->data + sackoff;
307 if (after(ntohl(sack->start_seq) - natseq->offset_before, 307 if (after(ntohl(sack->start_seq) - natseq->offset_before,
308 natseq->correction_pos)) 308 natseq->correction_pos))
309 new_start_seq = htonl(ntohl(sack->start_seq) 309 new_start_seq = htonl(ntohl(sack->start_seq)
310 - natseq->offset_after); 310 - natseq->offset_after);
311 else 311 else
312 new_start_seq = htonl(ntohl(sack->start_seq) 312 new_start_seq = htonl(ntohl(sack->start_seq)
313 - natseq->offset_before); 313 - natseq->offset_before);
314 314
315 if (after(ntohl(sack->end_seq) - natseq->offset_before, 315 if (after(ntohl(sack->end_seq) - natseq->offset_before,
316 natseq->correction_pos)) 316 natseq->correction_pos))
317 new_end_seq = htonl(ntohl(sack->end_seq) 317 new_end_seq = htonl(ntohl(sack->end_seq)
318 - natseq->offset_after); 318 - natseq->offset_after);
319 else 319 else
320 new_end_seq = htonl(ntohl(sack->end_seq) 320 new_end_seq = htonl(ntohl(sack->end_seq)
321 - natseq->offset_before); 321 - natseq->offset_before);
322 322
323 DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", 323 DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
324 ntohl(sack->start_seq), new_start_seq, 324 ntohl(sack->start_seq), new_start_seq,
325 ntohl(sack->end_seq), new_end_seq); 325 ntohl(sack->end_seq), new_end_seq);
326 326
327 nf_proto_csum_replace4(&tcph->check, skb, 327 nf_proto_csum_replace4(&tcph->check, skb,
328 sack->start_seq, new_start_seq, 0); 328 sack->start_seq, new_start_seq, 0);
329 nf_proto_csum_replace4(&tcph->check, skb, 329 nf_proto_csum_replace4(&tcph->check, skb,
330 sack->end_seq, new_end_seq, 0); 330 sack->end_seq, new_end_seq, 0);
331 sack->start_seq = new_start_seq; 331 sack->start_seq = new_start_seq;
332 sack->end_seq = new_end_seq; 332 sack->end_seq = new_end_seq;
333 sackoff += sizeof(*sack); 333 sackoff += sizeof(*sack);
334 } 334 }
335 } 335 }
336 336
337 /* TCP SACK sequence number adjustment */ 337 /* TCP SACK sequence number adjustment */
338 static inline unsigned int 338 static inline unsigned int
339 nf_nat_sack_adjust(struct sk_buff **pskb, 339 nf_nat_sack_adjust(struct sk_buff **pskb,
340 struct tcphdr *tcph, 340 struct tcphdr *tcph,
341 struct nf_conn *ct, 341 struct nf_conn *ct,
342 enum ip_conntrack_info ctinfo) 342 enum ip_conntrack_info ctinfo)
343 { 343 {
344 unsigned int dir, optoff, optend; 344 unsigned int dir, optoff, optend;
345 struct nf_conn_nat *nat = nfct_nat(ct); 345 struct nf_conn_nat *nat = nfct_nat(ct);
346 346
347 optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr); 347 optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
348 optend = ip_hdrlen(*pskb) + tcph->doff * 4; 348 optend = ip_hdrlen(*pskb) + tcph->doff * 4;
349 349
350 if (!skb_make_writable(pskb, optend)) 350 if (!skb_make_writable(pskb, optend))
351 return 0; 351 return 0;
352 352
353 dir = CTINFO2DIR(ctinfo); 353 dir = CTINFO2DIR(ctinfo);
354 354
355 while (optoff < optend) { 355 while (optoff < optend) {
356 /* Usually: option, length. */ 356 /* Usually: option, length. */
357 unsigned char *op = (*pskb)->data + optoff; 357 unsigned char *op = (*pskb)->data + optoff;
358 358
359 switch (op[0]) { 359 switch (op[0]) {
360 case TCPOPT_EOL: 360 case TCPOPT_EOL:
361 return 1; 361 return 1;
362 case TCPOPT_NOP: 362 case TCPOPT_NOP:
363 optoff++; 363 optoff++;
364 continue; 364 continue;
365 default: 365 default:
366 /* no partial options */ 366 /* no partial options */
367 if (optoff + 1 == optend || 367 if (optoff + 1 == optend ||
368 optoff + op[1] > optend || 368 optoff + op[1] > optend ||
369 op[1] < 2) 369 op[1] < 2)
370 return 0; 370 return 0;
371 if (op[0] == TCPOPT_SACK && 371 if (op[0] == TCPOPT_SACK &&
372 op[1] >= 2+TCPOLEN_SACK_PERBLOCK && 372 op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
373 ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) 373 ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
374 sack_adjust(*pskb, tcph, optoff+2, 374 sack_adjust(*pskb, tcph, optoff+2,
375 optoff+op[1], 375 optoff+op[1], &nat->seq[!dir]);
376 &nat->info.seq[!dir]);
377 optoff += op[1]; 376 optoff += op[1];
378 } 377 }
379 } 378 }
380 return 1; 379 return 1;
381 } 380 }
382 381
383 /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ 382 /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
384 int 383 int
385 nf_nat_seq_adjust(struct sk_buff **pskb, 384 nf_nat_seq_adjust(struct sk_buff **pskb,
386 struct nf_conn *ct, 385 struct nf_conn *ct,
387 enum ip_conntrack_info ctinfo) 386 enum ip_conntrack_info ctinfo)
388 { 387 {
389 struct tcphdr *tcph; 388 struct tcphdr *tcph;
390 int dir; 389 int dir;
391 __be32 newseq, newack; 390 __be32 newseq, newack;
392 struct nf_conn_nat *nat = nfct_nat(ct); 391 struct nf_conn_nat *nat = nfct_nat(ct);
393 struct nf_nat_seq *this_way, *other_way; 392 struct nf_nat_seq *this_way, *other_way;
394 393
395 dir = CTINFO2DIR(ctinfo); 394 dir = CTINFO2DIR(ctinfo);
396 395
397 this_way = &nat->info.seq[dir]; 396 this_way = &nat->seq[dir];
398 other_way = &nat->info.seq[!dir]; 397 other_way = &nat->seq[!dir];
399 398
400 if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph))) 399 if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
401 return 0; 400 return 0;
402 401
403 tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb); 402 tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
404 if (after(ntohl(tcph->seq), this_way->correction_pos)) 403 if (after(ntohl(tcph->seq), this_way->correction_pos))
405 newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); 404 newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
406 else 405 else
407 newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); 406 newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
408 407
409 if (after(ntohl(tcph->ack_seq) - other_way->offset_before, 408 if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
410 other_way->correction_pos)) 409 other_way->correction_pos))
411 newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); 410 newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
412 else 411 else
413 newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); 412 newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
414 413
415 nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); 414 nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
416 nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); 415 nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
417 416
418 DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", 417 DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
419 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), 418 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
420 ntohl(newack)); 419 ntohl(newack));
421 420
422 tcph->seq = newseq; 421 tcph->seq = newseq;
423 tcph->ack_seq = newack; 422 tcph->ack_seq = newack;
424 423
425 if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo)) 424 if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo))
426 return 0; 425 return 0;
427 426
428 nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), ct, dir); 427 nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), ct, dir);
429 428
430 return 1; 429 return 1;
431 } 430 }
432 EXPORT_SYMBOL(nf_nat_seq_adjust); 431 EXPORT_SYMBOL(nf_nat_seq_adjust);
433 432
434 /* Setup NAT on this expected conntrack so it follows master. */ 433 /* Setup NAT on this expected conntrack so it follows master. */
435 /* If we fail to get a free NAT slot, we'll get dropped on confirm */ 434 /* If we fail to get a free NAT slot, we'll get dropped on confirm */
436 void nf_nat_follow_master(struct nf_conn *ct, 435 void nf_nat_follow_master(struct nf_conn *ct,
437 struct nf_conntrack_expect *exp) 436 struct nf_conntrack_expect *exp)
438 { 437 {
439 struct nf_nat_range range; 438 struct nf_nat_range range;
440 439
441 /* This must be a fresh one. */ 440 /* This must be a fresh one. */
442 BUG_ON(ct->status & IPS_NAT_DONE_MASK); 441 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
443 442
444 /* Change src to where master sends to */ 443 /* Change src to where master sends to */
445 range.flags = IP_NAT_RANGE_MAP_IPS; 444 range.flags = IP_NAT_RANGE_MAP_IPS;
446 range.min_ip = range.max_ip 445 range.min_ip = range.max_ip
447 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 446 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
448 /* hook doesn't matter, but it has to do source manip */ 447 /* hook doesn't matter, but it has to do source manip */
449 nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); 448 nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
450 449
451 /* For DST manip, map port here to where it's expected. */ 450 /* For DST manip, map port here to where it's expected. */
452 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); 451 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
453 range.min = range.max = exp->saved_proto; 452 range.min = range.max = exp->saved_proto;
454 range.min_ip = range.max_ip 453 range.min_ip = range.max_ip
455 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; 454 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip;
456 /* hook doesn't matter, but it has to do destination manip */ 455 /* hook doesn't matter, but it has to do destination manip */
457 nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); 456 nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
458 } 457 }
459 EXPORT_SYMBOL(nf_nat_follow_master); 458 EXPORT_SYMBOL(nf_nat_follow_master);
460 459