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