Blame view

net/netfilter/nf_nat_core.c 23.3 KB
c7232c997   Patrick McHardy   netfilter: add pr...
1
2
  /*
   * (C) 1999-2001 Paul `Rusty' Russell
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
3
   * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
c7232c997   Patrick McHardy   netfilter: add pr...
4
   * (C) 2011 Patrick McHardy <kaber@trash.net>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
5
6
7
8
9
10
11
12
13
14
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/timer.h>
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/gfp.h>
c7232c997   Patrick McHardy   netfilter: add pr...
16
  #include <net/xfrm.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
17
  #include <linux/jhash.h>
c7232c997   Patrick McHardy   netfilter: add pr...
18
  #include <linux/rtnetlink.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
19

5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
20
21
22
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
  #include <net/netfilter/nf_nat.h>
c7232c997   Patrick McHardy   netfilter: add pr...
23
24
  #include <net/netfilter/nf_nat_l3proto.h>
  #include <net/netfilter/nf_nat_l4proto.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
25
26
27
  #include <net/netfilter/nf_nat_core.h>
  #include <net/netfilter/nf_nat_helper.h>
  #include <net/netfilter/nf_conntrack_helper.h>
41d73ec05   Patrick McHardy   netfilter: nf_con...
28
  #include <net/netfilter/nf_conntrack_seqadj.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
29
  #include <net/netfilter/nf_conntrack_l3proto.h>
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
30
  #include <net/netfilter/nf_conntrack_zones.h>
c7232c997   Patrick McHardy   netfilter: add pr...
31
  #include <linux/netfilter/nf_nat.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
32

02502f622   Patrick McHardy   [NETFILTER]: nf_n...
33
  static DEFINE_SPINLOCK(nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
34

c7232c997   Patrick McHardy   netfilter: add pr...
35
36
37
38
  static DEFINE_MUTEX(nf_nat_proto_mutex);
  static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO]
  						__read_mostly;
  static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO]
ce4b1cebd   Patrick McHardy   [NETFILTER]: nf_n...
39
  						__read_mostly;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
40

c7232c997   Patrick McHardy   netfilter: add pr...
41
42
43
  
  inline const struct nf_nat_l3proto *
  __nf_nat_l3proto_find(u8 family)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
44
  {
c7232c997   Patrick McHardy   netfilter: add pr...
45
  	return rcu_dereference(nf_nat_l3protos[family]);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
46
  }
c7232c997   Patrick McHardy   netfilter: add pr...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  inline const struct nf_nat_l4proto *
  __nf_nat_l4proto_find(u8 family, u8 protonum)
  {
  	return rcu_dereference(nf_nat_l4protos[family][protonum]);
  }
  EXPORT_SYMBOL_GPL(__nf_nat_l4proto_find);
  
  #ifdef CONFIG_XFRM
  static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
  {
  	const struct nf_nat_l3proto *l3proto;
  	const struct nf_conn *ct;
  	enum ip_conntrack_info ctinfo;
  	enum ip_conntrack_dir dir;
  	unsigned  long statusbit;
  	u8 family;
  
  	ct = nf_ct_get(skb, &ctinfo);
  	if (ct == NULL)
  		return;
  
  	family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
  	rcu_read_lock();
  	l3proto = __nf_nat_l3proto_find(family);
  	if (l3proto == NULL)
  		goto out;
  
  	dir = CTINFO2DIR(ctinfo);
  	if (dir == IP_CT_DIR_ORIGINAL)
  		statusbit = IPS_DST_NAT;
  	else
  		statusbit = IPS_SRC_NAT;
  
  	l3proto->decode_session(skb, ct, dir, statusbit, fl);
  out:
  	rcu_read_unlock();
  }
  
  int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
  {
  	struct flowi fl;
  	unsigned int hh_len;
  	struct dst_entry *dst;
aaa795ad2   Patrick McHardy   netfilter: nat: p...
90
  	int err;
c7232c997   Patrick McHardy   netfilter: add pr...
91

aaa795ad2   Patrick McHardy   netfilter: nat: p...
92
  	err = xfrm_decode_session(skb, &fl, family);
e7e6f6300   Dan Carpenter   netfilter: nf_nat...
93
  	if (err < 0)
aaa795ad2   Patrick McHardy   netfilter: nat: p...
94
  		return err;
c7232c997   Patrick McHardy   netfilter: add pr...
95
96
97
98
99
100
101
102
  
  	dst = skb_dst(skb);
  	if (dst->xfrm)
  		dst = ((struct xfrm_dst *)dst)->route;
  	dst_hold(dst);
  
  	dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
  	if (IS_ERR(dst))
aaa795ad2   Patrick McHardy   netfilter: nat: p...
103
  		return PTR_ERR(dst);
c7232c997   Patrick McHardy   netfilter: add pr...
104
105
106
107
108
109
110
111
  
  	skb_dst_drop(skb);
  	skb_dst_set(skb, dst);
  
  	/* Change in oif may mean change in hh_len. */
  	hh_len = skb_dst(skb)->dev->hard_header_len;
  	if (skb_headroom(skb) < hh_len &&
  	    pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
aaa795ad2   Patrick McHardy   netfilter: nat: p...
112
  		return -ENOMEM;
c7232c997   Patrick McHardy   netfilter: add pr...
113
114
115
116
  	return 0;
  }
  EXPORT_SYMBOL(nf_xfrm_me_harder);
  #endif /* CONFIG_XFRM */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
117
118
  /* We keep an extra hash for each conntrack, for fast searching. */
  static inline unsigned int
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
119
120
  hash_by_src(const struct net *net, u16 zone,
  	    const struct nf_conntrack_tuple *tuple)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
121
  {
34498825c   Patrick McHardy   [NETFILTER]: non-...
122
  	unsigned int hash;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
123
  	/* Original src, to ensure we map it consistently if poss. */
c7232c997   Patrick McHardy   netfilter: add pr...
124
125
126
  	hash = jhash2((u32 *)&tuple->src, sizeof(tuple->src) / sizeof(u32),
  		      tuple->dst.protonum ^ zone ^ nf_conntrack_hash_rnd);
  	return ((u64)hash * net->ct.nat_htable_size) >> 32;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
127
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
128
129
130
131
132
133
  /* Is this tuple already taken? (not by us) */
  int
  nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
  		  const struct nf_conn *ignored_conntrack)
  {
  	/* Conntrack tracking doesn't keep track of outgoing tuples; only
c7232c997   Patrick McHardy   netfilter: add pr...
134
135
136
137
138
  	 * incoming ones.  NAT means they don't have a fixed mapping,
  	 * so we invert the tuple and look for the incoming reply.
  	 *
  	 * We could keep a separate hash if this proves too slow.
  	 */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
139
140
141
142
143
144
145
146
  	struct nf_conntrack_tuple reply;
  
  	nf_ct_invert_tuplepr(&reply, tuple);
  	return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
  }
  EXPORT_SYMBOL(nf_nat_used_tuple);
  
  /* If we source map this tuple so reply looks like reply_tuple, will
c7232c997   Patrick McHardy   netfilter: add pr...
147
148
149
150
151
152
   * that meet the constraints of range.
   */
  static int in_range(const struct nf_nat_l3proto *l3proto,
  		    const struct nf_nat_l4proto *l4proto,
  		    const struct nf_conntrack_tuple *tuple,
  		    const struct nf_nat_range *range)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
153
  {
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
154
  	/* If we are supposed to map IPs, then we must be in the
c7232c997   Patrick McHardy   netfilter: add pr...
155
156
157
158
159
  	 * range specified, otherwise let this drag us onto a new src IP.
  	 */
  	if (range->flags & NF_NAT_RANGE_MAP_IPS &&
  	    !l3proto->in_range(tuple, range))
  		return 0;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
160

cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
161
  	if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) ||
c7232c997   Patrick McHardy   netfilter: add pr...
162
163
164
  	    l4proto->in_range(tuple, NF_NAT_MANIP_SRC,
  			      &range->min_proto, &range->max_proto))
  		return 1;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
165

c7232c997   Patrick McHardy   netfilter: add pr...
166
  	return 0;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
167
168
169
170
171
172
173
174
175
176
  }
  
  static inline int
  same_src(const struct nf_conn *ct,
  	 const struct nf_conntrack_tuple *tuple)
  {
  	const struct nf_conntrack_tuple *t;
  
  	t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  	return (t->dst.protonum == tuple->dst.protonum &&
c7232c997   Patrick McHardy   netfilter: add pr...
177
  		nf_inet_addr_cmp(&t->src.u3, &tuple->src.u3) &&
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
178
179
180
181
182
  		t->src.u.all == tuple->src.u.all);
  }
  
  /* Only called for SRC manip */
  static int
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
183
  find_appropriate_src(struct net *net, u16 zone,
c7232c997   Patrick McHardy   netfilter: add pr...
184
185
  		     const struct nf_nat_l3proto *l3proto,
  		     const struct nf_nat_l4proto *l4proto,
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
186
  		     const struct nf_conntrack_tuple *tuple,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
187
  		     struct nf_conntrack_tuple *result,
c7232c997   Patrick McHardy   netfilter: add pr...
188
  		     const struct nf_nat_range *range)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
189
  {
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
190
  	unsigned int h = hash_by_src(net, zone, tuple);
72b72949d   Jan Engelhardt   [NETFILTER]: anno...
191
192
  	const struct nf_conn_nat *nat;
  	const struct nf_conn *ct;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
193

b67bfe0d4   Sasha Levin   hlist: drop the n...
194
  	hlist_for_each_entry_rcu(nat, &net->ct.nat_bysource[h], bysource) {
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
195
  		ct = nat->ct;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
196
  		if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
197
198
199
200
  			/* Copy source part from reply tuple. */
  			nf_ct_invert_tuplepr(result,
  				       &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
  			result->dst = tuple->dst;
136251d02   Ulrich Weber   netfilter: nf_nat...
201
  			if (in_range(l3proto, l4proto, result, range))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
202
  				return 1;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
203
204
  		}
  	}
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
205
206
207
208
  	return 0;
  }
  
  /* For [FUTURE] fragmentation handling, we want the least-used
c7232c997   Patrick McHardy   netfilter: add pr...
209
210
211
212
213
   * src-ip/dst-ip/proto triple.  Fairness doesn't come into it.  Thus
   * if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
   * 1-65535, we don't do pro-rata allocation based on ports; we choose
   * the ip with the lowest src-ip/dst-ip/proto usage.
   */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
214
  static void
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
215
  find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
c7232c997   Patrick McHardy   netfilter: add pr...
216
  		    const struct nf_nat_range *range,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
217
218
219
  		    const struct nf_conn *ct,
  		    enum nf_nat_manip_type maniptype)
  {
c7232c997   Patrick McHardy   netfilter: add pr...
220
221
  	union nf_inet_addr *var_ipp;
  	unsigned int i, max;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
222
  	/* Host order */
c7232c997   Patrick McHardy   netfilter: add pr...
223
224
  	u32 minip, maxip, j, dist;
  	bool full_range;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
225
226
  
  	/* No IP mapping?  Do nothing. */
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
227
  	if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
228
  		return;
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
229
  	if (maniptype == NF_NAT_MANIP_SRC)
c7232c997   Patrick McHardy   netfilter: add pr...
230
  		var_ipp = &tuple->src.u3;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
231
  	else
c7232c997   Patrick McHardy   netfilter: add pr...
232
  		var_ipp = &tuple->dst.u3;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
233
234
  
  	/* Fast path: only one choice. */
c7232c997   Patrick McHardy   netfilter: add pr...
235
236
  	if (nf_inet_addr_cmp(&range->min_addr, &range->max_addr)) {
  		*var_ipp = range->min_addr;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
237
238
  		return;
  	}
c7232c997   Patrick McHardy   netfilter: add pr...
239
240
241
242
  	if (nf_ct_l3num(ct) == NFPROTO_IPV4)
  		max = sizeof(var_ipp->ip) / sizeof(u32) - 1;
  	else
  		max = sizeof(var_ipp->ip6) / sizeof(u32) - 1;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
243
244
245
246
247
  	/* Hashing source and destination IPs gives a fairly even
  	 * spread in practice (if there are a small number of IPs
  	 * involved, there usually aren't that many connections
  	 * anyway).  The consistency means that servers see the same
  	 * client coming from the same IP (some Internet Banking sites
c7232c997   Patrick McHardy   netfilter: add pr...
248
249
  	 * like this), even across reboots.
  	 */
5693d68df   Florian Westphal   netfilter: nf_nat...
250
  	j = jhash2((u32 *)&tuple->src.u3, sizeof(tuple->src.u3) / sizeof(u32),
c7232c997   Patrick McHardy   netfilter: add pr...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  		   range->flags & NF_NAT_RANGE_PERSISTENT ?
  			0 : (__force u32)tuple->dst.u3.all[max] ^ zone);
  
  	full_range = false;
  	for (i = 0; i <= max; i++) {
  		/* If first bytes of the address are at the maximum, use the
  		 * distance. Otherwise use the full range.
  		 */
  		if (!full_range) {
  			minip = ntohl((__force __be32)range->min_addr.all[i]);
  			maxip = ntohl((__force __be32)range->max_addr.all[i]);
  			dist  = maxip - minip + 1;
  		} else {
  			minip = 0;
  			dist  = ~0;
  		}
  
  		var_ipp->all[i] = (__force __u32)
  			htonl(minip + (((u64)j * dist) >> 32));
  		if (var_ipp->all[i] != range->max_addr.all[i])
  			full_range = true;
  
  		if (!(range->flags & NF_NAT_RANGE_PERSISTENT))
  			j ^= (__force u32)tuple->dst.u3.all[i];
  	}
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
276
  }
c7232c997   Patrick McHardy   netfilter: add pr...
277
278
  /* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING,
   * we change the source to map into the range. For NF_INET_PRE_ROUTING
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
279
   * and NF_INET_LOCAL_OUT, we change the destination to map into the
c7232c997   Patrick McHardy   netfilter: add pr...
280
   * range. It might not be possible to get a unique tuple, but we try.
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
281
282
283
284
285
   * At worst (or if we race), we will end up with a final duplicate in
   * __ip_conntrack_confirm and drop the packet. */
  static void
  get_unique_tuple(struct nf_conntrack_tuple *tuple,
  		 const struct nf_conntrack_tuple *orig_tuple,
c7232c997   Patrick McHardy   netfilter: add pr...
286
  		 const struct nf_nat_range *range,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
287
288
289
  		 struct nf_conn *ct,
  		 enum nf_nat_manip_type maniptype)
  {
c7232c997   Patrick McHardy   netfilter: add pr...
290
291
  	const struct nf_nat_l3proto *l3proto;
  	const struct nf_nat_l4proto *l4proto;
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
292
  	struct net *net = nf_ct_net(ct);
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
293
  	u16 zone = nf_ct_zone(ct);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
294

c7232c997   Patrick McHardy   netfilter: add pr...
295
296
297
298
  	rcu_read_lock();
  	l3proto = __nf_nat_l3proto_find(orig_tuple->src.l3num);
  	l4proto = __nf_nat_l4proto_find(orig_tuple->src.l3num,
  					orig_tuple->dst.protonum);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
299

c7232c997   Patrick McHardy   netfilter: add pr...
300
301
302
303
304
305
306
307
  	/* 1) If this srcip/proto/src-proto-part is currently mapped,
  	 * and that same mapping gives a unique tuple within the given
  	 * range, use that.
  	 *
  	 * This is only required for source (ie. NAT/masq) mappings.
  	 * So far, we don't do local source mappings, so multiple
  	 * manips not an issue.
  	 */
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
308
  	if (maniptype == NF_NAT_MANIP_SRC &&
34ce32401   Daniel Borkmann   netfilter: nf_nat...
309
  	    !(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) {
41a7cab6d   Changli Gao   netfilter: nf_nat...
310
  		/* try the original tuple first */
c7232c997   Patrick McHardy   netfilter: add pr...
311
  		if (in_range(l3proto, l4proto, orig_tuple, range)) {
41a7cab6d   Changli Gao   netfilter: nf_nat...
312
313
  			if (!nf_nat_used_tuple(orig_tuple, ct)) {
  				*tuple = *orig_tuple;
c7232c997   Patrick McHardy   netfilter: add pr...
314
  				goto out;
41a7cab6d   Changli Gao   netfilter: nf_nat...
315
  			}
c7232c997   Patrick McHardy   netfilter: add pr...
316
317
  		} else if (find_appropriate_src(net, zone, l3proto, l4proto,
  						orig_tuple, tuple, range)) {
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
318
319
  			pr_debug("get_unique_tuple: Found current src map
  ");
0dbff689c   Changli Gao   netfilter: nf_nat...
320
  			if (!nf_nat_used_tuple(tuple, ct))
c7232c997   Patrick McHardy   netfilter: add pr...
321
  				goto out;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
322
323
  		}
  	}
c7232c997   Patrick McHardy   netfilter: add pr...
324
  	/* 2) Select the least-used IP/proto combination in the given range */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
325
  	*tuple = *orig_tuple;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
326
  	find_best_ips_proto(zone, tuple, range, ct, maniptype);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
327
328
  
  	/* 3) The per-protocol part of the manip is made to map into
c7232c997   Patrick McHardy   netfilter: add pr...
329
330
  	 * the range to make a unique tuple.
  	 */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
331
332
  
  	/* Only bother mapping if it's not already in range and unique */
34ce32401   Daniel Borkmann   netfilter: nf_nat...
333
  	if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) {
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
334
  		if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
c7232c997   Patrick McHardy   netfilter: add pr...
335
336
337
338
  			if (l4proto->in_range(tuple, maniptype,
  					      &range->min_proto,
  					      &range->max_proto) &&
  			    (range->min_proto.all == range->max_proto.all ||
99ad3c53b   Changli Gao   netfilter: nf_nat...
339
340
341
342
343
344
  			     !nf_nat_used_tuple(tuple, ct)))
  				goto out;
  		} else if (!nf_nat_used_tuple(tuple, ct)) {
  			goto out;
  		}
  	}
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
345
346
  
  	/* Last change: get protocol to try to obtain unique tuple. */
c7232c997   Patrick McHardy   netfilter: add pr...
347
  	l4proto->unique_tuple(l3proto, tuple, range, maniptype, ct);
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
348
349
  out:
  	rcu_read_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
350
351
352
353
  }
  
  unsigned int
  nf_nat_setup_info(struct nf_conn *ct,
c7232c997   Patrick McHardy   netfilter: add pr...
354
  		  const struct nf_nat_range *range,
cc01dcbd2   Patrick McHardy   [NETFILTER]: nf_n...
355
  		  enum nf_nat_manip_type maniptype)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
356
  {
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
357
  	struct net *net = nf_ct_net(ct);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
358
  	struct nf_conntrack_tuple curr_tuple, new_tuple;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
359
  	struct nf_conn_nat *nat;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
360

2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
361
362
363
364
365
  	/* nat helper or nfctnetlink also setup binding */
  	nat = nfct_nat(ct);
  	if (!nat) {
  		nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
  		if (nat == NULL) {
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
366
367
  			pr_debug("failed to add NAT extension
  ");
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
368
369
370
  			return NF_ACCEPT;
  		}
  	}
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
371
372
  	NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC ||
  		     maniptype == NF_NAT_MANIP_DST);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
373
374
375
  	BUG_ON(nf_nat_initialized(ct, maniptype));
  
  	/* What we've got will look like inverse of reply. Normally
c7232c997   Patrick McHardy   netfilter: add pr...
376
377
378
379
  	 * this is what is in the conntrack, except for prior
  	 * manipulations (future optimization: if num_manips == 0,
  	 * orig_tp = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
  	 */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
380
381
382
383
384
385
386
387
388
389
390
391
392
  	nf_ct_invert_tuplepr(&curr_tuple,
  			     &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
  
  	get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
  
  	if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
  		struct nf_conntrack_tuple reply;
  
  		/* Alter conntrack table so will recognize replies. */
  		nf_ct_invert_tuplepr(&reply, &new_tuple);
  		nf_conntrack_alter_reply(ct, &reply);
  
  		/* Non-atomic: we own this at the moment. */
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
393
  		if (maniptype == NF_NAT_MANIP_SRC)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
394
395
396
  			ct->status |= IPS_SRC_NAT;
  		else
  			ct->status |= IPS_DST_NAT;
41d73ec05   Patrick McHardy   netfilter: nf_con...
397
398
399
  
  		if (nfct_help(ct))
  			nfct_seqadj_ext_add(ct);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
400
  	}
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
401
  	if (maniptype == NF_NAT_MANIP_SRC) {
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
402
  		unsigned int srchash;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
403
404
  		srchash = hash_by_src(net, nf_ct_zone(ct),
  				      &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
405
  		spin_lock_bh(&nf_nat_lock);
c7232c997   Patrick McHardy   netfilter: add pr...
406
  		/* nf_conntrack_alter_reply might re-allocate extension aera */
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
407
408
  		nat = nfct_nat(ct);
  		nat->ct = ct;
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
409
  		hlist_add_head_rcu(&nat->bysource,
c7232c997   Patrick McHardy   netfilter: add pr...
410
  				   &net->ct.nat_bysource[srchash]);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
411
  		spin_unlock_bh(&nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
412
413
414
  	}
  
  	/* It's done. */
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
415
  	if (maniptype == NF_NAT_MANIP_DST)
a7c2f4d7d   Changli Gao   netfilter: nf_nat...
416
  		ct->status |= IPS_DST_NAT_DONE;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
417
  	else
a7c2f4d7d   Changli Gao   netfilter: nf_nat...
418
  		ct->status |= IPS_SRC_NAT_DONE;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
419
420
421
422
  
  	return NF_ACCEPT;
  }
  EXPORT_SYMBOL(nf_nat_setup_info);
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
423
424
  static unsigned int
  __nf_nat_alloc_null_binding(struct nf_conn *ct, enum nf_nat_manip_type manip)
f59cb0453   Pablo Neira Ayuso   netfilter: nf_nat...
425
426
427
428
429
430
  {
  	/* Force range to this IP; let proto decide mapping for
  	 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
  	 * Use reply in case it's already been mangled (eg local packet).
  	 */
  	union nf_inet_addr ip =
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
431
  		(manip == NF_NAT_MANIP_SRC ?
f59cb0453   Pablo Neira Ayuso   netfilter: nf_nat...
432
433
434
435
436
437
438
  		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
  		ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
  	struct nf_nat_range range = {
  		.flags		= NF_NAT_RANGE_MAP_IPS,
  		.min_addr	= ip,
  		.max_addr	= ip,
  	};
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
439
440
441
442
443
444
445
  	return nf_nat_setup_info(ct, &range, manip);
  }
  
  unsigned int
  nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
  {
  	return __nf_nat_alloc_null_binding(ct, HOOK2MANIP(hooknum));
f59cb0453   Pablo Neira Ayuso   netfilter: nf_nat...
446
447
  }
  EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
448
449
450
451
  /* Do packet manipulations according to nf_nat_setup_info. */
  unsigned int nf_nat_packet(struct nf_conn *ct,
  			   enum ip_conntrack_info ctinfo,
  			   unsigned int hooknum,
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
452
  			   struct sk_buff *skb)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
453
  {
c7232c997   Patrick McHardy   netfilter: add pr...
454
455
  	const struct nf_nat_l3proto *l3proto;
  	const struct nf_nat_l4proto *l4proto;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
456
457
458
  	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
  	unsigned long statusbit;
  	enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);
cbc9f2f4f   Patrick McHardy   netfilter: nf_nat...
459
  	if (mtype == NF_NAT_MANIP_SRC)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  		statusbit = IPS_SRC_NAT;
  	else
  		statusbit = IPS_DST_NAT;
  
  	/* Invert if this is reply dir. */
  	if (dir == IP_CT_DIR_REPLY)
  		statusbit ^= IPS_NAT_MASK;
  
  	/* Non-atomic: these bits don't change. */
  	if (ct->status & statusbit) {
  		struct nf_conntrack_tuple target;
  
  		/* We are aiming to look like inverse of other direction. */
  		nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
c7232c997   Patrick McHardy   netfilter: add pr...
474
475
476
477
  		l3proto = __nf_nat_l3proto_find(target.src.l3num);
  		l4proto = __nf_nat_l4proto_find(target.src.l3num,
  						target.dst.protonum);
  		if (!l3proto->manip_pkt(skb, 0, l4proto, &target, mtype))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
478
479
480
481
482
  			return NF_DROP;
  	}
  	return NF_ACCEPT;
  }
  EXPORT_SYMBOL_GPL(nf_nat_packet);
c7232c997   Patrick McHardy   netfilter: add pr...
483
484
485
  struct nf_nat_proto_clean {
  	u8	l3proto;
  	u8	l4proto;
c7232c997   Patrick McHardy   netfilter: add pr...
486
  };
c2d421e17   Florian Westphal   netfilter: nf_nat...
487
488
  /* kill conntracks with affected NAT section */
  static int nf_nat_proto_remove(struct nf_conn *i, void *data)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
489
  {
c7232c997   Patrick McHardy   netfilter: add pr...
490
491
  	const struct nf_nat_proto_clean *clean = data;
  	struct nf_conn_nat *nat = nfct_nat(i);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
492

c7232c997   Patrick McHardy   netfilter: add pr...
493
  	if (!nat)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
494
  		return 0;
c2d421e17   Florian Westphal   netfilter: nf_nat...
495

c7232c997   Patrick McHardy   netfilter: add pr...
496
497
  	if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) ||
  	    (clean->l4proto && nf_ct_protonum(i) != clean->l4proto))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
498
  		return 0;
c2d421e17   Florian Westphal   netfilter: nf_nat...
499
  	return i->status & IPS_NAT_MASK ? 1 : 0;
c7232c997   Patrick McHardy   netfilter: add pr...
500
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
501

c7232c997   Patrick McHardy   netfilter: add pr...
502
503
504
505
506
507
508
509
510
  static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
  {
  	struct nf_nat_proto_clean clean = {
  		.l3proto = l3proto,
  		.l4proto = l4proto,
  	};
  	struct net *net;
  
  	rtnl_lock();
c7232c997   Patrick McHardy   netfilter: add pr...
511
  	for_each_net(net)
c655bc689   Florian Westphal   netfilter: nf_con...
512
  		nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean, 0, 0);
c7232c997   Patrick McHardy   netfilter: add pr...
513
514
  	rtnl_unlock();
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
515

c7232c997   Patrick McHardy   netfilter: add pr...
516
517
518
519
520
521
522
523
  static void nf_nat_l3proto_clean(u8 l3proto)
  {
  	struct nf_nat_proto_clean clean = {
  		.l3proto = l3proto,
  	};
  	struct net *net;
  
  	rtnl_lock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
524

c7232c997   Patrick McHardy   netfilter: add pr...
525
  	for_each_net(net)
c655bc689   Florian Westphal   netfilter: nf_con...
526
  		nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean, 0, 0);
c7232c997   Patrick McHardy   netfilter: add pr...
527
  	rtnl_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
528
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
529
530
  
  /* Protocol registration. */
c7232c997   Patrick McHardy   netfilter: add pr...
531
  int nf_nat_l4proto_register(u8 l3proto, const struct nf_nat_l4proto *l4proto)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
532
  {
c7232c997   Patrick McHardy   netfilter: add pr...
533
534
  	const struct nf_nat_l4proto **l4protos;
  	unsigned int i;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
535
  	int ret = 0;
c7232c997   Patrick McHardy   netfilter: add pr...
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
  	mutex_lock(&nf_nat_proto_mutex);
  	if (nf_nat_l4protos[l3proto] == NULL) {
  		l4protos = kmalloc(IPPROTO_MAX * sizeof(struct nf_nat_l4proto *),
  				   GFP_KERNEL);
  		if (l4protos == NULL) {
  			ret = -ENOMEM;
  			goto out;
  		}
  
  		for (i = 0; i < IPPROTO_MAX; i++)
  			RCU_INIT_POINTER(l4protos[i], &nf_nat_l4proto_unknown);
  
  		/* Before making proto_array visible to lockless readers,
  		 * we must make sure its content is committed to memory.
  		 */
  		smp_wmb();
  
  		nf_nat_l4protos[l3proto] = l4protos;
  	}
eb733162a   Eric Dumazet   netfilter: add __...
555
  	if (rcu_dereference_protected(
c7232c997   Patrick McHardy   netfilter: add pr...
556
557
558
  			nf_nat_l4protos[l3proto][l4proto->l4proto],
  			lockdep_is_held(&nf_nat_proto_mutex)
  			) != &nf_nat_l4proto_unknown) {
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
559
560
561
  		ret = -EBUSY;
  		goto out;
  	}
c7232c997   Patrick McHardy   netfilter: add pr...
562
  	RCU_INIT_POINTER(nf_nat_l4protos[l3proto][l4proto->l4proto], l4proto);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
563
   out:
c7232c997   Patrick McHardy   netfilter: add pr...
564
  	mutex_unlock(&nf_nat_proto_mutex);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
565
566
  	return ret;
  }
c7232c997   Patrick McHardy   netfilter: add pr...
567
  EXPORT_SYMBOL_GPL(nf_nat_l4proto_register);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
568

25985edce   Lucas De Marchi   Fix common misspe...
569
  /* No one stores the protocol anywhere; simply delete it. */
c7232c997   Patrick McHardy   netfilter: add pr...
570
  void nf_nat_l4proto_unregister(u8 l3proto, const struct nf_nat_l4proto *l4proto)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
571
  {
c7232c997   Patrick McHardy   netfilter: add pr...
572
573
574
575
  	mutex_lock(&nf_nat_proto_mutex);
  	RCU_INIT_POINTER(nf_nat_l4protos[l3proto][l4proto->l4proto],
  			 &nf_nat_l4proto_unknown);
  	mutex_unlock(&nf_nat_proto_mutex);
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
576
  	synchronize_rcu();
c7232c997   Patrick McHardy   netfilter: add pr...
577
578
  
  	nf_nat_l4proto_clean(l3proto, l4proto->l4proto);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
579
  }
c7232c997   Patrick McHardy   netfilter: add pr...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  EXPORT_SYMBOL_GPL(nf_nat_l4proto_unregister);
  
  int nf_nat_l3proto_register(const struct nf_nat_l3proto *l3proto)
  {
  	int err;
  
  	err = nf_ct_l3proto_try_module_get(l3proto->l3proto);
  	if (err < 0)
  		return err;
  
  	mutex_lock(&nf_nat_proto_mutex);
  	RCU_INIT_POINTER(nf_nat_l4protos[l3proto->l3proto][IPPROTO_TCP],
  			 &nf_nat_l4proto_tcp);
  	RCU_INIT_POINTER(nf_nat_l4protos[l3proto->l3proto][IPPROTO_UDP],
  			 &nf_nat_l4proto_udp);
  	mutex_unlock(&nf_nat_proto_mutex);
  
  	RCU_INIT_POINTER(nf_nat_l3protos[l3proto->l3proto], l3proto);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(nf_nat_l3proto_register);
  
  void nf_nat_l3proto_unregister(const struct nf_nat_l3proto *l3proto)
  {
  	mutex_lock(&nf_nat_proto_mutex);
  	RCU_INIT_POINTER(nf_nat_l3protos[l3proto->l3proto], NULL);
  	mutex_unlock(&nf_nat_proto_mutex);
  	synchronize_rcu();
  
  	nf_nat_l3proto_clean(l3proto->l3proto);
  	nf_ct_l3proto_module_put(l3proto->l3proto);
  }
  EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregister);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
613

25985edce   Lucas De Marchi   Fix common misspe...
614
  /* No one using conntrack by the time this called. */
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
615
616
617
  static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
  {
  	struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
618
  	if (nat == NULL || nat->ct == NULL)
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
619
  		return;
41a7cab6d   Changli Gao   netfilter: nf_nat...
620
  	NF_CT_ASSERT(nat->ct->status & IPS_SRC_NAT_DONE);
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
621

02502f622   Patrick McHardy   [NETFILTER]: nf_n...
622
  	spin_lock_bh(&nf_nat_lock);
4d354c578   Patrick McHardy   [NETFILTER]: nf_n...
623
  	hlist_del_rcu(&nat->bysource);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
624
  	spin_unlock_bh(&nf_nat_lock);
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
625
  }
86577c661   Patrick McHardy   [NETFILTER]: nf_c...
626
  static void nf_nat_move_storage(void *new, void *old)
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
627
  {
86577c661   Patrick McHardy   [NETFILTER]: nf_c...
628
629
  	struct nf_conn_nat *new_nat = new;
  	struct nf_conn_nat *old_nat = old;
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
630
  	struct nf_conn *ct = old_nat->ct;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
631

41a7cab6d   Changli Gao   netfilter: nf_nat...
632
  	if (!ct || !(ct->status & IPS_SRC_NAT_DONE))
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
633
  		return;
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
634
  	spin_lock_bh(&nf_nat_lock);
68b80f113   Patrick McHardy   netfilter: nf_nat...
635
  	hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
636
  	spin_unlock_bh(&nf_nat_lock);
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
637
  }
61eb3107c   Patrick McHardy   [NETFILTER]: nf_c...
638
  static struct nf_ct_ext_type nat_extend __read_mostly = {
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
639
640
641
642
643
644
  	.len		= sizeof(struct nf_conn_nat),
  	.align		= __alignof__(struct nf_conn_nat),
  	.destroy	= nf_nat_cleanup_conntrack,
  	.move		= nf_nat_move_storage,
  	.id		= NF_CT_EXT_NAT,
  	.flags		= NF_CT_EXT_F_PREALLOC,
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
645
  };
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
646
647
648
649
650
651
652
653
654
655
656
657
  #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
  
  #include <linux/netfilter/nfnetlink.h>
  #include <linux/netfilter/nfnetlink_conntrack.h>
  
  static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
  	[CTA_PROTONAT_PORT_MIN]	= { .type = NLA_U16 },
  	[CTA_PROTONAT_PORT_MAX]	= { .type = NLA_U16 },
  };
  
  static int nfnetlink_parse_nat_proto(struct nlattr *attr,
  				     const struct nf_conn *ct,
c7232c997   Patrick McHardy   netfilter: add pr...
658
  				     struct nf_nat_range *range)
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
659
660
  {
  	struct nlattr *tb[CTA_PROTONAT_MAX+1];
c7232c997   Patrick McHardy   netfilter: add pr...
661
  	const struct nf_nat_l4proto *l4proto;
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
662
663
664
665
666
  	int err;
  
  	err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
  	if (err < 0)
  		return err;
c7232c997   Patrick McHardy   netfilter: add pr...
667
668
669
  	l4proto = __nf_nat_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
  	if (l4proto->nlattr_to_range)
  		err = l4proto->nlattr_to_range(tb, range);
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
670
671
672
673
  	return err;
  }
  
  static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
c7232c997   Patrick McHardy   netfilter: add pr...
674
675
  	[CTA_NAT_V4_MINIP]	= { .type = NLA_U32 },
  	[CTA_NAT_V4_MAXIP]	= { .type = NLA_U32 },
58a317f10   Patrick McHardy   netfilter: ipv6: ...
676
677
  	[CTA_NAT_V6_MINIP]	= { .len = sizeof(struct in6_addr) },
  	[CTA_NAT_V6_MAXIP]	= { .len = sizeof(struct in6_addr) },
329fb58a9   Patrick McHardy   netfilter: nf_nat...
678
  	[CTA_NAT_PROTO]		= { .type = NLA_NESTED },
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
679
680
681
  };
  
  static int
399383246   Patrick McHardy   netfilter: nfnetl...
682
  nfnetlink_parse_nat(const struct nlattr *nat,
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
683
684
  		    const struct nf_conn *ct, struct nf_nat_range *range,
  		    const struct nf_nat_l3proto *l3proto)
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
685
686
687
688
689
690
691
692
693
  {
  	struct nlattr *tb[CTA_NAT_MAX+1];
  	int err;
  
  	memset(range, 0, sizeof(*range));
  
  	err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
  	if (err < 0)
  		return err;
c7232c997   Patrick McHardy   netfilter: add pr...
694
695
  	err = l3proto->nlattr_to_range(tb, range);
  	if (err < 0)
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
696
  		return err;
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
697
698
  
  	if (!tb[CTA_NAT_PROTO])
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
699
  		return 0;
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
700

0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
701
  	return nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
702
  }
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
703
  /* This function is called under rcu_read_lock() */
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
704
705
706
  static int
  nfnetlink_parse_nat_setup(struct nf_conn *ct,
  			  enum nf_nat_manip_type manip,
399383246   Patrick McHardy   netfilter: nfnetl...
707
  			  const struct nlattr *attr)
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
708
  {
c7232c997   Patrick McHardy   netfilter: add pr...
709
  	struct nf_nat_range range;
0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
710
  	const struct nf_nat_l3proto *l3proto;
c7232c997   Patrick McHardy   netfilter: add pr...
711
  	int err;
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
712

0eba801b6   Pablo Neira Ayuso   netfilter: ctnetl...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  	/* Should not happen, restricted to creating new conntracks
  	 * via ctnetlink.
  	 */
  	if (WARN_ON_ONCE(nf_nat_initialized(ct, manip)))
  		return -EEXIST;
  
  	/* Make sure that L3 NAT is there by when we call nf_nat_setup_info to
  	 * attach the null binding, otherwise this may oops.
  	 */
  	l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
  	if (l3proto == NULL)
  		return -EAGAIN;
  
  	/* No NAT information has been passed, allocate the null-binding */
  	if (attr == NULL)
  		return __nf_nat_alloc_null_binding(ct, manip);
  
  	err = nfnetlink_parse_nat(attr, ct, &range, l3proto);
c7232c997   Patrick McHardy   netfilter: add pr...
731
732
  	if (err < 0)
  		return err;
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
733
734
735
736
737
738
739
  
  	return nf_nat_setup_info(ct, &range, manip);
  }
  #else
  static int
  nfnetlink_parse_nat_setup(struct nf_conn *ct,
  			  enum nf_nat_manip_type manip,
399383246   Patrick McHardy   netfilter: nfnetl...
740
  			  const struct nlattr *attr)
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
741
742
743
744
  {
  	return -EOPNOTSUPP;
  }
  #endif
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
745
746
  static int __net_init nf_nat_net_init(struct net *net)
  {
d696c7bda   Patrick McHardy   netfilter: nf_con...
747
  	/* Leave them the same for the moment. */
c7232c997   Patrick McHardy   netfilter: add pr...
748
749
750
  	net->ct.nat_htable_size = net->ct.htable_size;
  	net->ct.nat_bysource = nf_ct_alloc_hashtable(&net->ct.nat_htable_size, 0);
  	if (!net->ct.nat_bysource)
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
751
752
753
  		return -ENOMEM;
  	return 0;
  }
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
754
755
  static void __net_exit nf_nat_net_exit(struct net *net)
  {
c7232c997   Patrick McHardy   netfilter: add pr...
756
  	struct nf_nat_proto_clean clean = {};
c655bc689   Florian Westphal   netfilter: nf_con...
757
  	nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean, 0, 0);
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
758
  	synchronize_rcu();
c7232c997   Patrick McHardy   netfilter: add pr...
759
  	nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size);
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
760
761
762
763
764
765
  }
  
  static struct pernet_operations nf_nat_net_ops = {
  	.init = nf_nat_net_init,
  	.exit = nf_nat_net_exit,
  };
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
766
767
768
769
  static struct nf_ct_helper_expectfn follow_master_nat = {
  	.name		= "nat-follow-master",
  	.expectfn	= nf_nat_follow_master,
  };
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
770
771
  static int __init nf_nat_init(void)
  {
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
772
773
774
775
776
777
778
779
  	int ret;
  
  	ret = nf_ct_extend_register(&nat_extend);
  	if (ret < 0) {
  		printk(KERN_ERR "nf_nat_core: Unable to register extension
  ");
  		return ret;
  	}
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
780

0c4c9288a   Alexey Dobriyan   netfilter: netns ...
781
782
  	ret = register_pernet_subsys(&nf_nat_net_ops);
  	if (ret < 0)
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
783
  		goto cleanup_extend;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
784

c7232c997   Patrick McHardy   netfilter: add pr...
785
  	nf_ct_helper_expectfn_register(&follow_master_nat);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
786

5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
787
  	/* Initialize fake conntrack so that NAT will skip it */
5bfddbd46   Eric Dumazet   netfilter: nf_con...
788
  	nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
789

e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
790
  	BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
791
  	RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook,
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
792
  			   nfnetlink_parse_nat_setup);
c7232c997   Patrick McHardy   netfilter: add pr...
793
794
795
796
  #ifdef CONFIG_XFRM
  	BUG_ON(nf_nat_decode_session_hook != NULL);
  	RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session);
  #endif
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
797
  	return 0;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
798
799
800
801
  
   cleanup_extend:
  	nf_ct_extend_unregister(&nat_extend);
  	return ret;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
802
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
803
804
  static void __exit nf_nat_cleanup(void)
  {
c7232c997   Patrick McHardy   netfilter: add pr...
805
  	unsigned int i;
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
806
  	unregister_pernet_subsys(&nf_nat_net_ops);
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
807
  	nf_ct_extend_unregister(&nat_extend);
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
808
  	nf_ct_helper_expectfn_unregister(&follow_master_nat);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
809
  	RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
c7232c997   Patrick McHardy   netfilter: add pr...
810
811
812
813
814
  #ifdef CONFIG_XFRM
  	RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL);
  #endif
  	for (i = 0; i < NFPROTO_NUMPROTO; i++)
  		kfree(nf_nat_l4protos[i]);
dd13b0103   Patrick McHardy   [NETFILTER]: nf_n...
815
  	synchronize_net();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
816
817
818
819
820
821
  }
  
  MODULE_LICENSE("GPL");
  
  module_init(nf_nat_init);
  module_exit(nf_nat_cleanup);