• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/net/ipv4/netfilter/
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#include <linux/types.h>
9#include <linux/icmp.h>
10#include <linux/gfp.h>
11#include <linux/ip.h>
12#include <linux/netfilter.h>
13#include <linux/netfilter_ipv4.h>
14#include <linux/module.h>
15#include <linux/skbuff.h>
16#include <linux/proc_fs.h>
17#include <net/ip.h>
18#include <net/checksum.h>
19#include <linux/spinlock.h>
20
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_conntrack_core.h>
23#include <net/netfilter/nf_conntrack_extend.h>
24#include <net/netfilter/nf_nat.h>
25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_nat_protocol.h>
27#include <net/netfilter/nf_nat_core.h>
28#include <net/netfilter/nf_nat_helper.h>
29#include <linux/netfilter_ipv4/ip_tables.h>
30#ifdef CONFIG_IP_NF_TARGET_CONE
31#include <linux/netfilter_ipv4/ipt_cone.h>
32#endif /* CONFIG_IP_NF_TARGET_CONE */
33#ifdef CONFIG_XFRM
34static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
35{
36	const struct nf_conn *ct;
37	const struct nf_conntrack_tuple *t;
38	enum ip_conntrack_info ctinfo;
39	enum ip_conntrack_dir dir;
40	unsigned long statusbit;
41
42	ct = nf_ct_get(skb, &ctinfo);
43	if (ct == NULL)
44		return;
45	dir = CTINFO2DIR(ctinfo);
46	t = &ct->tuplehash[dir].tuple;
47
48	if (dir == IP_CT_DIR_ORIGINAL)
49		statusbit = IPS_DST_NAT;
50	else
51		statusbit = IPS_SRC_NAT;
52
53	if (ct->status & statusbit) {
54		fl->fl4_dst = t->dst.u3.ip;
55		if (t->dst.protonum == IPPROTO_TCP ||
56		    t->dst.protonum == IPPROTO_UDP ||
57		    t->dst.protonum == IPPROTO_UDPLITE ||
58		    t->dst.protonum == IPPROTO_DCCP ||
59		    t->dst.protonum == IPPROTO_SCTP)
60			fl->fl_ip_dport = t->dst.u.tcp.port;
61	}
62
63	statusbit ^= IPS_NAT_MASK;
64
65	if (ct->status & statusbit) {
66		fl->fl4_src = t->src.u3.ip;
67		if (t->dst.protonum == IPPROTO_TCP ||
68		    t->dst.protonum == IPPROTO_UDP ||
69		    t->dst.protonum == IPPROTO_UDPLITE ||
70		    t->dst.protonum == IPPROTO_DCCP ||
71		    t->dst.protonum == IPPROTO_SCTP)
72			fl->fl_ip_sport = t->src.u.tcp.port;
73	}
74}
75#endif
76
77static unsigned int
78nf_nat_fn(unsigned int hooknum,
79	  struct sk_buff *skb,
80	  const struct net_device *in,
81	  const struct net_device *out,
82	  int (*okfn)(struct sk_buff *))
83{
84	struct nf_conn *ct;
85	enum ip_conntrack_info ctinfo;
86	struct nf_conn_nat *nat;
87	/* maniptype == SRC for postrouting. */
88	enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
89
90	/* We never see fragments: conntrack defrags on pre-routing
91	   and local-out, and nf_nat_out protects post-routing. */
92	NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
93
94	ct = nf_ct_get(skb, &ctinfo);
95	/* Can't track?  It's not due to stress, or conntrack would
96	   have dropped it.  Hence it's the user's responsibilty to
97	   packet filter it out, or implement conntrack/NAT for that
98	   protocol. 8) --RR */
99	if (!ct)
100		return NF_ACCEPT;
101
102	/* Don't try to NAT if this packet is not conntracked */
103	if (nf_ct_is_untracked(ct))
104		return NF_ACCEPT;
105
106	nat = nfct_nat(ct);
107	if (!nat) {
108		/* NAT module was loaded late. */
109		if (nf_ct_is_confirmed(ct))
110			return NF_ACCEPT;
111		nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
112		if (nat == NULL) {
113			pr_debug("failed to add NAT extension\n");
114			return NF_ACCEPT;
115		}
116	}
117
118	switch (ctinfo) {
119	case IP_CT_RELATED:
120	case IP_CT_RELATED+IP_CT_IS_REPLY:
121		if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
122			if (!nf_nat_icmp_reply_translation(ct, ctinfo,
123							   hooknum, skb))
124				return NF_DROP;
125			else
126				return NF_ACCEPT;
127		}
128		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
129	case IP_CT_NEW:
130
131		/* Seen it before?  This can happen for loopback, retrans,
132		   or local packets.. */
133		if (!nf_nat_initialized(ct, maniptype)) {
134			unsigned int ret;
135
136			ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
137			if (ret != NF_ACCEPT)
138				return ret;
139#ifdef CONFIG_IP_NF_TARGET_CONE
140			/* Place to CONE NAT table */
141			ipt_cone_place_in_hashes(ct);
142#endif /* CONFIG_IP_NF_TARGET_CONE */
143		} else
144			pr_debug("Already setup manip %s for ct %p\n",
145				 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
146				 ct);
147		break;
148
149	default:
150		/* ESTABLISHED */
151		NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
152			     ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
153	}
154
155	return nf_nat_packet(ct, ctinfo, hooknum, skb);
156}
157
158static unsigned int
159nf_nat_in(unsigned int hooknum,
160	  struct sk_buff *skb,
161	  const struct net_device *in,
162	  const struct net_device *out,
163	  int (*okfn)(struct sk_buff *))
164{
165	unsigned int ret;
166	__be32 daddr = ip_hdr(skb)->daddr;
167
168	ret = nf_nat_fn(hooknum, skb, in, out, okfn);
169	if (ret != NF_DROP && ret != NF_STOLEN &&
170	    daddr != ip_hdr(skb)->daddr)
171		skb_dst_drop(skb);
172
173	return ret;
174}
175
176static unsigned int
177nf_nat_out(unsigned int hooknum,
178	   struct sk_buff *skb,
179	   const struct net_device *in,
180	   const struct net_device *out,
181	   int (*okfn)(struct sk_buff *))
182{
183#ifdef CONFIG_XFRM
184	const struct nf_conn *ct;
185	enum ip_conntrack_info ctinfo;
186#endif
187	unsigned int ret;
188
189	/* root is playing with raw sockets. */
190	if (skb->len < sizeof(struct iphdr) ||
191	    ip_hdrlen(skb) < sizeof(struct iphdr))
192		return NF_ACCEPT;
193
194	ret = nf_nat_fn(hooknum, skb, in, out, okfn);
195#ifdef CONFIG_XFRM
196	if (ret != NF_DROP && ret != NF_STOLEN &&
197	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
198		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
199
200		if ((ct->tuplehash[dir].tuple.src.u3.ip !=
201		     ct->tuplehash[!dir].tuple.dst.u3.ip) ||
202		    (ct->tuplehash[dir].tuple.src.u.all !=
203		     ct->tuplehash[!dir].tuple.dst.u.all)
204		   )
205			return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP;
206	}
207#endif
208	return ret;
209}
210
211static unsigned int
212nf_nat_local_fn(unsigned int hooknum,
213		struct sk_buff *skb,
214		const struct net_device *in,
215		const struct net_device *out,
216		int (*okfn)(struct sk_buff *))
217{
218	const struct nf_conn *ct;
219	enum ip_conntrack_info ctinfo;
220	unsigned int ret;
221
222	/* root is playing with raw sockets. */
223	if (skb->len < sizeof(struct iphdr) ||
224	    ip_hdrlen(skb) < sizeof(struct iphdr))
225		return NF_ACCEPT;
226
227	ret = nf_nat_fn(hooknum, skb, in, out, okfn);
228	if (ret != NF_DROP && ret != NF_STOLEN &&
229	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
230		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
231
232		if (ct->tuplehash[dir].tuple.dst.u3.ip !=
233		    ct->tuplehash[!dir].tuple.src.u3.ip) {
234			if (ip_route_me_harder(skb, RTN_UNSPEC))
235				ret = NF_DROP;
236		}
237#ifdef CONFIG_XFRM
238		else if (ct->tuplehash[dir].tuple.dst.u.all !=
239			 ct->tuplehash[!dir].tuple.src.u.all)
240			if (ip_xfrm_me_harder(skb))
241				ret = NF_DROP;
242#endif
243	}
244	return ret;
245}
246
247/* We must be after connection tracking and before packet filtering. */
248
249static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
250	/* Before packet filtering, change destination */
251	{
252		.hook		= nf_nat_in,
253		.owner		= THIS_MODULE,
254		.pf		= NFPROTO_IPV4,
255		.hooknum	= NF_INET_PRE_ROUTING,
256		.priority	= NF_IP_PRI_NAT_DST,
257	},
258	/* After packet filtering, change source */
259	{
260		.hook		= nf_nat_out,
261		.owner		= THIS_MODULE,
262		.pf		= NFPROTO_IPV4,
263		.hooknum	= NF_INET_POST_ROUTING,
264		.priority	= NF_IP_PRI_NAT_SRC,
265	},
266	/* Before packet filtering, change destination */
267	{
268		.hook		= nf_nat_local_fn,
269		.owner		= THIS_MODULE,
270		.pf		= NFPROTO_IPV4,
271		.hooknum	= NF_INET_LOCAL_OUT,
272		.priority	= NF_IP_PRI_NAT_DST,
273	},
274	/* After packet filtering, change source */
275	{
276		.hook		= nf_nat_fn,
277		.owner		= THIS_MODULE,
278		.pf		= NFPROTO_IPV4,
279		.hooknum	= NF_INET_LOCAL_IN,
280		.priority	= NF_IP_PRI_NAT_SRC,
281	},
282};
283
284static int __init nf_nat_standalone_init(void)
285{
286	int ret = 0;
287
288	need_ipv4_conntrack();
289
290#ifdef CONFIG_XFRM
291	BUG_ON(ip_nat_decode_session != NULL);
292	rcu_assign_pointer(ip_nat_decode_session, nat_decode_session);
293#endif
294	ret = nf_nat_rule_init();
295	if (ret < 0) {
296		pr_err("nf_nat_init: can't setup rules.\n");
297		goto cleanup_decode_session;
298	}
299	ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
300	if (ret < 0) {
301		pr_err("nf_nat_init: can't register hooks.\n");
302		goto cleanup_rule_init;
303	}
304	return ret;
305
306 cleanup_rule_init:
307	nf_nat_rule_cleanup();
308 cleanup_decode_session:
309#ifdef CONFIG_XFRM
310	rcu_assign_pointer(ip_nat_decode_session, NULL);
311	synchronize_net();
312#endif
313	return ret;
314}
315
316static void __exit nf_nat_standalone_fini(void)
317{
318	nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
319	nf_nat_rule_cleanup();
320#ifdef CONFIG_XFRM
321	rcu_assign_pointer(ip_nat_decode_session, NULL);
322	synchronize_net();
323#endif
324	/* Conntrack caches are unregistered in nf_conntrack_cleanup */
325}
326
327module_init(nf_nat_standalone_init);
328module_exit(nf_nat_standalone_fini);
329
330MODULE_LICENSE("GPL");
331MODULE_ALIAS("ip_nat");
332