Blame view

net/ipv4/netfilter/nf_nat_core.c 21.4 KB
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /* NAT for netfilter; shared with compatibility layer. */
  
  /* (C) 1999-2001 Paul `Rusty' Russell
   * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/timer.h>
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/gfp.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  #include <net/checksum.h>
  #include <net/icmp.h>
  #include <net/ip.h>
  #include <net/tcp.h>  /* For tcp_prot in getorigdst */
  #include <linux/icmp.h>
  #include <linux/udp.h>
  #include <linux/jhash.h>
  
  #include <linux/netfilter_ipv4.h>
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
  #include <net/netfilter/nf_nat.h>
  #include <net/netfilter/nf_nat_protocol.h>
  #include <net/netfilter/nf_nat_core.h>
  #include <net/netfilter/nf_nat_helper.h>
  #include <net/netfilter/nf_conntrack_helper.h>
  #include <net/netfilter/nf_conntrack_l3proto.h>
  #include <net/netfilter/nf_conntrack_l4proto.h>
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
34
  #include <net/netfilter/nf_conntrack_zones.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
35

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

ce4b1cebd   Patrick McHardy   [NETFILTER]: nf_n...
38
  static struct nf_conntrack_l3proto *l3proto __read_mostly;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
39

5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
40
  #define MAX_IP_NAT_PROTO 256
0906a372f   Arnd Bergmann   net/netfilter: __...
41
  static const struct nf_nat_protocol __rcu *nf_nat_protos[MAX_IP_NAT_PROTO]
ce4b1cebd   Patrick McHardy   [NETFILTER]: nf_n...
42
  						__read_mostly;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
43

2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
44
  static inline const struct nf_nat_protocol *
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
45
46
  __nf_nat_proto_find(u_int8_t protonum)
  {
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
47
  	return rcu_dereference(nf_nat_protos[protonum]);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
48
  }
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
49
  const struct nf_nat_protocol *
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
50
51
  nf_nat_proto_find_get(u_int8_t protonum)
  {
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
52
  	const struct nf_nat_protocol *p;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
53

e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
54
  	rcu_read_lock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
55
56
57
  	p = __nf_nat_proto_find(protonum);
  	if (!try_module_get(p->me))
  		p = &nf_nat_unknown_protocol;
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
58
  	rcu_read_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
59
60
61
62
63
64
  
  	return p;
  }
  EXPORT_SYMBOL_GPL(nf_nat_proto_find_get);
  
  void
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
65
  nf_nat_proto_put(const struct nf_nat_protocol *p)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
66
67
68
69
70
71
72
  {
  	module_put(p->me);
  }
  EXPORT_SYMBOL_GPL(nf_nat_proto_put);
  
  /* We keep an extra hash for each conntrack, for fast searching. */
  static inline unsigned int
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
73
74
  hash_by_src(const struct net *net, u16 zone,
  	    const struct nf_conntrack_tuple *tuple)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
75
  {
34498825c   Patrick McHardy   [NETFILTER]: non-...
76
  	unsigned int hash;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
77
  	/* Original src, to ensure we map it consistently if poss. */
34498825c   Patrick McHardy   [NETFILTER]: non-...
78
  	hash = jhash_3words((__force u32)tuple->src.u3.ip,
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
79
  			    (__force u32)tuple->src.u.all ^ zone,
34498825c   Patrick McHardy   [NETFILTER]: non-...
80
  			    tuple->dst.protonum, 0);
d696c7bda   Patrick McHardy   netfilter: nf_con...
81
  	return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
82
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  /* 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
  	   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. */
  	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
   * that meet the constraints of range. */
  static int
  in_range(const struct nf_conntrack_tuple *tuple,
  	 const struct nf_nat_range *range)
  {
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
106
  	const struct nf_nat_protocol *proto;
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
107
  	int ret = 0;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
108

5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
109
110
111
112
113
114
115
  	/* If we are supposed to map IPs, then we must be in the
  	   range specified, otherwise let this drag us onto a new src IP. */
  	if (range->flags & IP_NAT_RANGE_MAP_IPS) {
  		if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) ||
  		    ntohl(tuple->src.u3.ip) > ntohl(range->max_ip))
  			return 0;
  	}
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
116
117
  	rcu_read_lock();
  	proto = __nf_nat_proto_find(tuple->dst.protonum);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
118
119
120
  	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
  	    proto->in_range(tuple, IP_NAT_MANIP_SRC,
  			    &range->min, &range->max))
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
121
122
  		ret = 1;
  	rcu_read_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
123

e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
124
  	return ret;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  }
  
  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 &&
  		t->src.u3.ip == tuple->src.u3.ip &&
  		t->src.u.all == tuple->src.u.all);
  }
  
  /* Only called for SRC manip */
  static int
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
141
  find_appropriate_src(struct net *net, u16 zone,
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
142
  		     const struct nf_conntrack_tuple *tuple,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
143
144
145
  		     struct nf_conntrack_tuple *result,
  		     const struct nf_nat_range *range)
  {
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
146
  	unsigned int h = hash_by_src(net, zone, tuple);
72b72949d   Jan Engelhardt   [NETFILTER]: anno...
147
148
149
  	const struct nf_conn_nat *nat;
  	const struct nf_conn *ct;
  	const struct hlist_node *n;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
150

4d354c578   Patrick McHardy   [NETFILTER]: nf_n...
151
  	rcu_read_lock();
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
152
  	hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
153
  		ct = nat->ct;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
154
  		if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
155
156
157
158
159
160
  			/* Copy source part from reply tuple. */
  			nf_ct_invert_tuplepr(result,
  				       &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
  			result->dst = tuple->dst;
  
  			if (in_range(result, range)) {
4d354c578   Patrick McHardy   [NETFILTER]: nf_n...
161
  				rcu_read_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
162
163
164
165
  				return 1;
  			}
  		}
  	}
4d354c578   Patrick McHardy   [NETFILTER]: nf_n...
166
  	rcu_read_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
167
168
169
170
171
172
173
174
175
176
  	return 0;
  }
  
  /* For [FUTURE] fragmentation handling, we want the least-used
     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.
  */
  static void
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
177
  find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  		    const struct nf_nat_range *range,
  		    const struct nf_conn *ct,
  		    enum nf_nat_manip_type maniptype)
  {
  	__be32 *var_ipp;
  	/* Host order */
  	u_int32_t minip, maxip, j;
  
  	/* No IP mapping?  Do nothing. */
  	if (!(range->flags & IP_NAT_RANGE_MAP_IPS))
  		return;
  
  	if (maniptype == IP_NAT_MANIP_SRC)
  		var_ipp = &tuple->src.u3.ip;
  	else
  		var_ipp = &tuple->dst.u3.ip;
  
  	/* Fast path: only one choice. */
  	if (range->min_ip == range->max_ip) {
  		*var_ipp = range->min_ip;
  		return;
  	}
  
  	/* 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
  	 * like this), even across reboots. */
  	minip = ntohl(range->min_ip);
  	maxip = ntohl(range->max_ip);
  	j = jhash_2words((__force u32)tuple->src.u3.ip,
98d500d66   Patrick McHardy   netfilter: nf_nat...
210
  			 range->flags & IP_NAT_RANGE_PERSISTENT ?
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
211
  				0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
34498825c   Patrick McHardy   [NETFILTER]: non-...
212
213
  	j = ((u64)j * (maxip - minip + 1)) >> 32;
  	*var_ipp = htonl(minip + j);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
214
  }
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
215
216
217
  /* 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
   * and NF_INET_LOCAL_OUT, we change the destination to map into the
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
218
219
220
221
222
223
224
225
226
227
   * range.  It might not be possible to get a unique tuple, but we try.
   * 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,
  		 const struct nf_nat_range *range,
  		 struct nf_conn *ct,
  		 enum nf_nat_manip_type maniptype)
  {
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
228
  	struct net *net = nf_ct_net(ct);
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
229
  	const struct nf_nat_protocol *proto;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
230
  	u16 zone = nf_ct_zone(ct);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
231
232
233
234
235
236
237
238
  
  	/* 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.  */
0dbff689c   Changli Gao   netfilter: nf_nat...
239
240
  	if (maniptype == IP_NAT_MANIP_SRC &&
  	    !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
241
  		if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) {
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
242
243
  			pr_debug("get_unique_tuple: Found current src map
  ");
0dbff689c   Changli Gao   netfilter: nf_nat...
244
245
  			if (!nf_nat_used_tuple(tuple, ct))
  				return;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
246
247
248
249
250
251
  		}
  	}
  
  	/* 2) Select the least-used IP/proto combination in the given
  	   range. */
  	*tuple = *orig_tuple;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
252
  	find_best_ips_proto(zone, tuple, range, ct, maniptype);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
253
254
255
  
  	/* 3) The per-protocol part of the manip is made to map into
  	   the range to make a unique tuple. */
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
256
257
  	rcu_read_lock();
  	proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
258
259
  
  	/* Only bother mapping if it's not already in range and unique */
c36952e52   Changli Gao   netfilter: nf_nat...
260
261
  	if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM) &&
  	    (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
262
  	     proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
263
264
  	    !nf_nat_used_tuple(tuple, ct))
  		goto out;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
265
266
267
  
  	/* Last change: get protocol to try to obtain unique tuple. */
  	proto->unique_tuple(tuple, range, maniptype, ct);
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
268
269
  out:
  	rcu_read_unlock();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
270
271
272
273
274
  }
  
  unsigned int
  nf_nat_setup_info(struct nf_conn *ct,
  		  const struct nf_nat_range *range,
cc01dcbd2   Patrick McHardy   [NETFILTER]: nf_n...
275
  		  enum nf_nat_manip_type maniptype)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
276
  {
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
277
  	struct net *net = nf_ct_net(ct);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
278
  	struct nf_conntrack_tuple curr_tuple, new_tuple;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
279
  	struct nf_conn_nat *nat;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
280
  	int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
281

2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
282
283
284
285
286
  	/* 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...
287
288
  			pr_debug("failed to add NAT extension
  ");
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
289
290
291
  			return NF_ACCEPT;
  		}
  	}
cc01dcbd2   Patrick McHardy   [NETFILTER]: nf_n...
292
293
  	NF_CT_ASSERT(maniptype == IP_NAT_MANIP_SRC ||
  		     maniptype == IP_NAT_MANIP_DST);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  	BUG_ON(nf_nat_initialized(ct, maniptype));
  
  	/* What we've got will look like inverse of reply. Normally
  	   this is what is in the conntrack, except for prior
  	   manipulations (future optimization: if num_manips == 0,
  	   orig_tp =
  	   conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
  	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. */
  		if (maniptype == IP_NAT_MANIP_SRC)
  			ct->status |= IPS_SRC_NAT;
  		else
  			ct->status |= IPS_DST_NAT;
  	}
  
  	/* Place in source hash if this is the first time. */
  	if (have_to_hash) {
  		unsigned int srchash;
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
323
324
  		srchash = hash_by_src(net, nf_ct_zone(ct),
  				      &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
325
  		spin_lock_bh(&nf_nat_lock);
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
326
  		/* nf_conntrack_alter_reply might re-allocate exntension aera */
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
327
328
  		nat = nfct_nat(ct);
  		nat->ct = ct;
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
329
330
  		hlist_add_head_rcu(&nat->bysource,
  				   &net->ipv4.nat_bysource[srchash]);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
331
  		spin_unlock_bh(&nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
332
333
334
335
336
337
338
339
340
341
342
343
344
  	}
  
  	/* It's done. */
  	if (maniptype == IP_NAT_MANIP_DST)
  		set_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
  	else
  		set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status);
  
  	return NF_ACCEPT;
  }
  EXPORT_SYMBOL(nf_nat_setup_info);
  
  /* Returns true if succeeded. */
f2ea825f4   Jan Engelhardt   [NETFILTER]: nf_n...
345
  static bool
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
346
  manip_pkt(u_int16_t proto,
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
347
  	  struct sk_buff *skb,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
348
349
350
351
352
  	  unsigned int iphdroff,
  	  const struct nf_conntrack_tuple *target,
  	  enum nf_nat_manip_type maniptype)
  {
  	struct iphdr *iph;
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
353
  	const struct nf_nat_protocol *p;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
354

3db05fea5   Herbert Xu   [NETFILTER]: Repl...
355
  	if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
f2ea825f4   Jan Engelhardt   [NETFILTER]: nf_n...
356
  		return false;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
357

3db05fea5   Herbert Xu   [NETFILTER]: Repl...
358
  	iph = (void *)skb->data + iphdroff;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
359
360
  
  	/* Manipulate protcol part. */
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
361
362
363
  
  	/* rcu_read_lock()ed by nf_hook_slow */
  	p = __nf_nat_proto_find(proto);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
364
  	if (!p->manip_pkt(skb, iphdroff, target, maniptype))
f2ea825f4   Jan Engelhardt   [NETFILTER]: nf_n...
365
  		return false;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
366

3db05fea5   Herbert Xu   [NETFILTER]: Repl...
367
  	iph = (void *)skb->data + iphdroff;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
368
369
  
  	if (maniptype == IP_NAT_MANIP_SRC) {
be0ea7d5d   Patrick McHardy   [NETFILTER]: Conv...
370
  		csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
371
372
  		iph->saddr = target->src.u3.ip;
  	} else {
be0ea7d5d   Patrick McHardy   [NETFILTER]: Conv...
373
  		csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
374
375
  		iph->daddr = target->dst.u3.ip;
  	}
f2ea825f4   Jan Engelhardt   [NETFILTER]: nf_n...
376
  	return true;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
377
378
379
380
381
382
  }
  
  /* 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...
383
  			   struct sk_buff *skb)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  {
  	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
  	unsigned long statusbit;
  	enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);
  
  	if (mtype == IP_NAT_MANIP_SRC)
  		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);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
404
  		if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
405
406
407
408
409
410
411
412
413
414
  			return NF_DROP;
  	}
  	return NF_ACCEPT;
  }
  EXPORT_SYMBOL_GPL(nf_nat_packet);
  
  /* Dir is direction ICMP is coming from (opposite to packet it contains) */
  int nf_nat_icmp_reply_translation(struct nf_conn *ct,
  				  enum ip_conntrack_info ctinfo,
  				  unsigned int hooknum,
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
415
  				  struct sk_buff *skb)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
416
417
418
419
420
  {
  	struct {
  		struct icmphdr icmp;
  		struct iphdr ip;
  	} *inside;
72b72949d   Jan Engelhardt   [NETFILTER]: anno...
421
  	const struct nf_conntrack_l4proto *l4proto;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
422
  	struct nf_conntrack_tuple inner, target;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
423
  	int hdrlen = ip_hdrlen(skb);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
424
425
426
  	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
  	unsigned long statusbit;
  	enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
427
  	if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
428
  		return 0;
794dbc1d7   Changli Gao   netfilter: nf_nat...
429
  	inside = (void *)skb->data + hdrlen;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
430
431
432
  
  	/* We're actually going to mangle it beyond trivial checksum
  	   adjustment, so make sure the current checksum is correct. */
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
433
  	if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
434
435
436
  		return 0;
  
  	/* Must be RELATED */
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
437
438
  	NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED ||
  		     skb->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
439
440
  
  	/* Redirects on non-null nats must be dropped, else they'll
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
441
442
  	   start talking to each other without our translation, and be
  	   confused... --RR */
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
443
444
445
446
447
448
449
450
  	if (inside->icmp.type == ICMP_REDIRECT) {
  		/* If NAT isn't finished, assume it and drop. */
  		if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
  			return 0;
  
  		if (ct->status & IPS_NAT_MASK)
  			return 0;
  	}
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
451
  	pr_debug("icmp_reply_translation: translating error %p manip %u "
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
452
453
  		 "dir %s
  ", skb, manip,
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
454
  		 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
455

923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
456
457
  	/* rcu_read_lock()ed by nf_hook_slow */
  	l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
794dbc1d7   Changli Gao   netfilter: nf_nat...
458
459
  	if (!nf_ct_get_tuple(skb, hdrlen + sizeof(struct icmphdr),
  			     (hdrlen +
c9bdd4b52   Arnaldo Carvalho de Melo   [IP]: Introduce i...
460
  			      sizeof(struct icmphdr) + inside->ip.ihl * 4),
794dbc1d7   Changli Gao   netfilter: nf_nat...
461
  			     (u_int16_t)AF_INET, inside->ip.protocol,
923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
462
  			     &inner, l3proto, l4proto))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
463
464
465
466
467
468
469
  		return 0;
  
  	/* Change inner back to look like incoming packet.  We do the
  	   opposite manip on this hook to normal, because it might not
  	   pass all hooks (locally-generated ICMP).  Consider incoming
  	   packet: PREROUTING (DST manip), routing produces ICMP, goes
  	   through POSTROUTING (which must correct the DST manip). */
794dbc1d7   Changli Gao   netfilter: nf_nat...
470
471
  	if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp),
  		       &ct->tuplehash[!dir].tuple, !manip))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
472
  		return 0;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
473
  	if (skb->ip_summed != CHECKSUM_PARTIAL) {
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
474
  		/* Reloading "inside" here since manip_pkt inner. */
794dbc1d7   Changli Gao   netfilter: nf_nat...
475
  		inside = (void *)skb->data + hdrlen;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
476
477
  		inside->icmp.checksum = 0;
  		inside->icmp.checksum =
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
478
479
  			csum_fold(skb_checksum(skb, hdrlen,
  					       skb->len - hdrlen, 0));
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  	}
  
  	/* Change outer to look the reply to an incoming packet
  	 * (proto 0 means don't invert per-proto part). */
  	if (manip == IP_NAT_MANIP_SRC)
  		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;
  
  	if (ct->status & statusbit) {
  		nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
495
  		if (!manip_pkt(0, skb, 0, &target, manip))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
496
497
498
499
500
501
502
503
  			return 0;
  	}
  
  	return 1;
  }
  EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
  
  /* Protocol registration. */
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
504
  int nf_nat_protocol_register(const struct nf_nat_protocol *proto)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
505
506
  {
  	int ret = 0;
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
507
  	spin_lock_bh(&nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
508
509
510
511
  	if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) {
  		ret = -EBUSY;
  		goto out;
  	}
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
512
  	rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
513
   out:
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
514
  	spin_unlock_bh(&nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
515
516
517
518
519
  	return ret;
  }
  EXPORT_SYMBOL(nf_nat_protocol_register);
  
  /* Noone stores the protocol anywhere; simply delete it. */
2b628a086   Patrick McHardy   [NETFILTER]: nf_n...
520
  void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
521
  {
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
522
  	spin_lock_bh(&nf_nat_lock);
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
523
524
  	rcu_assign_pointer(nf_nat_protos[proto->protonum],
  			   &nf_nat_unknown_protocol);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
525
  	spin_unlock_bh(&nf_nat_lock);
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
526
  	synchronize_rcu();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
527
528
  }
  EXPORT_SYMBOL(nf_nat_protocol_unregister);
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
529
530
531
532
  /* Noone using conntrack by the time this called. */
  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...
533
  	if (nat == NULL || nat->ct == NULL)
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
534
  		return;
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
535
  	NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK);
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
536

02502f622   Patrick McHardy   [NETFILTER]: nf_n...
537
  	spin_lock_bh(&nf_nat_lock);
4d354c578   Patrick McHardy   [NETFILTER]: nf_n...
538
  	hlist_del_rcu(&nat->bysource);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
539
  	spin_unlock_bh(&nf_nat_lock);
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
540
  }
86577c661   Patrick McHardy   [NETFILTER]: nf_c...
541
  static void nf_nat_move_storage(void *new, void *old)
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
542
  {
86577c661   Patrick McHardy   [NETFILTER]: nf_c...
543
544
  	struct nf_conn_nat *new_nat = new;
  	struct nf_conn_nat *old_nat = old;
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
545
  	struct nf_conn *ct = old_nat->ct;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
546

1f305323f   Evgeniy Polyakov   [NETFILTER]: Fix ...
547
  	if (!ct || !(ct->status & IPS_NAT_DONE_MASK))
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
548
  		return;
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
549
  	spin_lock_bh(&nf_nat_lock);
b6b84d4a9   Yasuyuki Kozakai   [NETFILTER]: nf_n...
550
  	new_nat->ct = ct;
68b80f113   Patrick McHardy   netfilter: nf_nat...
551
  	hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
552
  	spin_unlock_bh(&nf_nat_lock);
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
553
  }
61eb3107c   Patrick McHardy   [NETFILTER]: nf_c...
554
  static struct nf_ct_ext_type nat_extend __read_mostly = {
d8a0509a6   Yasuyuki Kozakai   [NETFILTER]: nf_n...
555
556
557
558
559
560
  	.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...
561
  };
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
  #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,
  				     struct nf_nat_range *range)
  {
  	struct nlattr *tb[CTA_PROTONAT_MAX+1];
  	const struct nf_nat_protocol *npt;
  	int err;
  
  	err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
  	if (err < 0)
  		return err;
  
  	npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
  	if (npt->nlattr_to_range)
  		err = npt->nlattr_to_range(tb, range);
  	nf_nat_proto_put(npt);
  	return err;
  }
  
  static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
  	[CTA_NAT_MINIP]		= { .type = NLA_U32 },
  	[CTA_NAT_MAXIP]		= { .type = NLA_U32 },
  };
  
  static int
399383246   Patrick McHardy   netfilter: nfnetl...
597
  nfnetlink_parse_nat(const struct nlattr *nat,
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
  		    const struct nf_conn *ct, struct nf_nat_range *range)
  {
  	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;
  
  	if (tb[CTA_NAT_MINIP])
  		range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
  
  	if (!tb[CTA_NAT_MAXIP])
  		range->max_ip = range->min_ip;
  	else
  		range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
  
  	if (range->min_ip)
  		range->flags |= IP_NAT_RANGE_MAP_IPS;
  
  	if (!tb[CTA_NAT_PROTO])
  		return 0;
  
  	err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
  	if (err < 0)
  		return err;
  
  	return 0;
  }
  
  static int
  nfnetlink_parse_nat_setup(struct nf_conn *ct,
  			  enum nf_nat_manip_type manip,
399383246   Patrick McHardy   netfilter: nfnetl...
633
  			  const struct nlattr *attr)
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  {
  	struct nf_nat_range range;
  
  	if (nfnetlink_parse_nat(attr, ct, &range) < 0)
  		return -EINVAL;
  	if (nf_nat_initialized(ct, manip))
  		return -EEXIST;
  
  	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...
648
  			  const struct nlattr *attr)
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
649
650
651
652
  {
  	return -EOPNOTSUPP;
  }
  #endif
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
653
654
  static int __net_init nf_nat_net_init(struct net *net)
  {
d696c7bda   Patrick McHardy   netfilter: nf_con...
655
656
657
658
  	/* Leave them the same for the moment. */
  	net->ipv4.nat_htable_size = net->ct.htable_size;
  	net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&net->ipv4.nat_htable_size,
  						       &net->ipv4.nat_vmalloced, 0);
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  	if (!net->ipv4.nat_bysource)
  		return -ENOMEM;
  	return 0;
  }
  
  /* Clear NAT section of all conntracks, in case we're loaded again. */
  static int clean_nat(struct nf_conn *i, void *data)
  {
  	struct nf_conn_nat *nat = nfct_nat(i);
  
  	if (!nat)
  		return 0;
  	memset(nat, 0, sizeof(*nat));
  	i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
  	return 0;
  }
  
  static void __net_exit nf_nat_net_exit(struct net *net)
  {
  	nf_ct_iterate_cleanup(net, &clean_nat, NULL);
  	synchronize_rcu();
  	nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_vmalloced,
d696c7bda   Patrick McHardy   netfilter: nf_con...
681
  			     net->ipv4.nat_htable_size);
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
682
683
684
685
686
687
  }
  
  static struct pernet_operations nf_nat_net_ops = {
  	.init = nf_nat_net_init,
  	.exit = nf_nat_net_exit,
  };
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
688
689
690
  static int __init nf_nat_init(void)
  {
  	size_t i;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
691
  	int ret;
475959d47   Jan Engelhardt   [NETFILTER]: nf_n...
692
  	need_ipv4_conntrack();
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
693
694
695
696
697
698
  	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 ...
699

0c4c9288a   Alexey Dobriyan   netfilter: netns ...
700
701
  	ret = register_pernet_subsys(&nf_nat_net_ops);
  	if (ret < 0)
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
702
  		goto cleanup_extend;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
703
704
  
  	/* Sew in builtin protocols. */
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
705
  	spin_lock_bh(&nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
706
  	for (i = 0; i < MAX_IP_NAT_PROTO; i++)
e22a05486   Patrick McHardy   [NETFILTER]: nf_n...
707
708
709
710
  		rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
  	rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
  	rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
  	rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
02502f622   Patrick McHardy   [NETFILTER]: nf_n...
711
  	spin_unlock_bh(&nf_nat_lock);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
712

5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
713
  	/* Initialize fake conntrack so that NAT will skip it */
5bfddbd46   Eric Dumazet   netfilter: nf_con...
714
  	nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
715
716
  
  	l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
dd13b0103   Patrick McHardy   [NETFILTER]: nf_n...
717
718
719
  
  	BUG_ON(nf_nat_seq_adjust_hook != NULL);
  	rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
720
721
722
  	BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
  	rcu_assign_pointer(nfnetlink_parse_nat_setup_hook,
  			   nfnetlink_parse_nat_setup);
f9dd09c7f   Jozsef Kadlecsik   netfilter: nf_nat...
723
724
  	BUG_ON(nf_ct_nat_offset != NULL);
  	rcu_assign_pointer(nf_ct_nat_offset, nf_nat_get_offset);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
725
  	return 0;
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
726
727
728
729
  
   cleanup_extend:
  	nf_ct_extend_unregister(&nat_extend);
  	return ret;
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
730
  }
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
731
732
  static void __exit nf_nat_cleanup(void)
  {
0c4c9288a   Alexey Dobriyan   netfilter: netns ...
733
  	unregister_pernet_subsys(&nf_nat_net_ops);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
734
  	nf_ct_l3proto_put(l3proto);
2d59e5ca8   Yasuyuki Kozakai   [NETFILTER]: nf_n...
735
  	nf_ct_extend_unregister(&nat_extend);
dd13b0103   Patrick McHardy   [NETFILTER]: nf_n...
736
  	rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
737
  	rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL);
f9dd09c7f   Jozsef Kadlecsik   netfilter: nf_nat...
738
  	rcu_assign_pointer(nf_ct_nat_offset, NULL);
dd13b0103   Patrick McHardy   [NETFILTER]: nf_n...
739
  	synchronize_net();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
740
741
742
  }
  
  MODULE_LICENSE("GPL");
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
743
  MODULE_ALIAS("nf-nat-ipv4");
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
744
745
746
  
  module_init(nf_nat_init);
  module_exit(nf_nat_cleanup);