ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv4 / netfilter / ip_nat_standalone.c
1 /* This file contains all the functions required for the standalone
2    ip_nat module.
3
4    These are not required by the compatibility layer.
5 */
6
7 /* (C) 1999-2001 Paul `Rusty' Russell
8  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
15 /*
16  * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
17  *      - new API and handling of conntrack/nat helpers
18  *      - now capable of multiple expectations for one master
19  * */
20
21 #include <linux/config.h>
22 #include <linux/types.h>
23 #include <linux/icmp.h>
24 #include <linux/ip.h>
25 #include <linux/netfilter.h>
26 #include <linux/netfilter_ipv4.h>
27 #include <linux/module.h>
28 #include <linux/skbuff.h>
29 #include <linux/proc_fs.h>
30 #include <net/checksum.h>
31 #include <linux/spinlock.h>
32
33 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
34 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
35
36 #include <linux/netfilter_ipv4/ip_nat.h>
37 #include <linux/netfilter_ipv4/ip_nat_rule.h>
38 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
39 #include <linux/netfilter_ipv4/ip_nat_core.h>
40 #include <linux/netfilter_ipv4/ip_nat_helper.h>
41 #include <linux/netfilter_ipv4/ip_tables.h>
42 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
43 #include <linux/netfilter_ipv4/listhelp.h>
44
45 #if 0
46 #define DEBUGP printk
47 #else
48 #define DEBUGP(format, args...)
49 #endif
50
51 #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING"  \
52                            : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \
53                               : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT"  \
54                                  : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
55                                     : "*ERROR*")))
56
57 static inline int call_expect(struct ip_conntrack *master,
58                               struct sk_buff **pskb,
59                               unsigned int hooknum,
60                               struct ip_conntrack *ct,
61                               struct ip_nat_info *info)
62 {
63         return master->nat.info.helper->expect(pskb, hooknum, ct, info);
64 }
65
66 static unsigned int
67 ip_nat_fn(unsigned int hooknum,
68           struct sk_buff **pskb,
69           const struct net_device *in,
70           const struct net_device *out,
71           int (*okfn)(struct sk_buff *))
72 {
73         struct ip_conntrack *ct;
74         enum ip_conntrack_info ctinfo;
75         struct ip_nat_info *info;
76         /* maniptype == SRC for postrouting. */
77         enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
78
79         /* We never see fragments: conntrack defrags on pre-routing
80            and local-out, and ip_nat_out protects post-routing. */
81         IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
82                        & htons(IP_MF|IP_OFFSET)));
83
84         (*pskb)->nfcache |= NFC_UNKNOWN;
85
86         /* If we had a hardware checksum before, it's now invalid */
87         if ((*pskb)->ip_summed == CHECKSUM_HW)
88                 (*pskb)->ip_summed = CHECKSUM_NONE;
89
90         ct = ip_conntrack_get(*pskb, &ctinfo);
91         /* Can't track?  It's not due to stress, or conntrack would
92            have dropped it.  Hence it's the user's responsibilty to
93            packet filter it out, or implement conntrack/NAT for that
94            protocol. 8) --RR */
95         if (!ct) {
96                 /* Exception: ICMP redirect to new connection (not in
97                    hash table yet).  We must not let this through, in
98                    case we're doing NAT to the same network. */
99                 if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
100                         struct icmphdr hdr;
101
102                         if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
103                                           &hdr, sizeof(hdr)) == 0
104                             && hdr.type == ICMP_REDIRECT)
105                                 return NF_DROP;
106                 }
107                 return NF_ACCEPT;
108         }
109
110         switch (ctinfo) {
111         case IP_CT_RELATED:
112         case IP_CT_RELATED+IP_CT_IS_REPLY:
113                 if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
114                         if (!icmp_reply_translation(pskb, ct, hooknum,
115                                                     CTINFO2DIR(ctinfo)))
116                                 return NF_DROP;
117                         else
118                                 return NF_ACCEPT;
119                 }
120                 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
121         case IP_CT_NEW:
122                 info = &ct->nat.info;
123
124                 WRITE_LOCK(&ip_nat_lock);
125                 /* Seen it before?  This can happen for loopback, retrans,
126                    or local packets.. */
127                 if (!(info->initialized & (1 << maniptype))
128 #ifndef CONFIG_IP_NF_NAT_LOCAL
129                     /* If this session has already been confirmed we must not
130                      * touch it again even if there is no mapping set up.
131                      * Can only happen on local->local traffic with
132                      * CONFIG_IP_NF_NAT_LOCAL disabled.
133                      */
134                     && !(ct->status & IPS_CONFIRMED)
135 #endif
136                     ) {
137                         unsigned int ret;
138
139                         if (ct->master
140                             && master_ct(ct)->nat.info.helper
141                             && master_ct(ct)->nat.info.helper->expect) {
142                                 ret = call_expect(master_ct(ct), pskb, 
143                                                   hooknum, ct, info);
144                         } else {
145 #ifdef CONFIG_IP_NF_NAT_LOCAL
146                                 /* LOCAL_IN hook doesn't have a chain!  */
147                                 if (hooknum == NF_IP_LOCAL_IN)
148                                         ret = alloc_null_binding(ct, info,
149                                                                  hooknum);
150                                 else
151 #endif
152                                 ret = ip_nat_rule_find(pskb, hooknum, in, out,
153                                                        ct, info);
154                         }
155
156                         if (ret != NF_ACCEPT) {
157                                 WRITE_UNLOCK(&ip_nat_lock);
158                                 return ret;
159                         }
160                 } else
161                         DEBUGP("Already setup manip %s for ct %p\n",
162                                maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
163                                ct);
164                 WRITE_UNLOCK(&ip_nat_lock);
165                 break;
166
167         default:
168                 /* ESTABLISHED */
169                 IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
170                              || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
171                 info = &ct->nat.info;
172         }
173
174         IP_NF_ASSERT(info);
175         return do_bindings(ct, ctinfo, info, hooknum, pskb);
176 }
177
178 static unsigned int
179 ip_nat_out(unsigned int hooknum,
180            struct sk_buff **pskb,
181            const struct net_device *in,
182            const struct net_device *out,
183            int (*okfn)(struct sk_buff *))
184 {
185         /* root is playing with raw sockets. */
186         if ((*pskb)->len < sizeof(struct iphdr)
187             || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
188                 return NF_ACCEPT;
189
190         /* We can hit fragment here; forwarded packets get
191            defragmented by connection tracking coming in, then
192            fragmented (grr) by the forward code.
193
194            In future: If we have nfct != NULL, AND we have NAT
195            initialized, AND there is no helper, then we can do full
196            NAPT on the head, and IP-address-only NAT on the rest.
197
198            I'm starting to have nightmares about fragments.  */
199
200         if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
201                 *pskb = ip_ct_gather_frags(*pskb);
202
203                 if (!*pskb)
204                         return NF_STOLEN;
205         }
206
207         return ip_nat_fn(hooknum, pskb, in, out, okfn);
208 }
209
210 #ifdef CONFIG_IP_NF_NAT_LOCAL
211 static unsigned int
212 ip_nat_local_fn(unsigned int hooknum,
213                 struct sk_buff **pskb,
214                 const struct net_device *in,
215                 const struct net_device *out,
216                 int (*okfn)(struct sk_buff *))
217 {
218         u_int32_t saddr, daddr;
219         unsigned int ret;
220
221         /* root is playing with raw sockets. */
222         if ((*pskb)->len < sizeof(struct iphdr)
223             || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
224                 return NF_ACCEPT;
225
226         saddr = (*pskb)->nh.iph->saddr;
227         daddr = (*pskb)->nh.iph->daddr;
228
229         ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
230         if (ret != NF_DROP && ret != NF_STOLEN
231             && ((*pskb)->nh.iph->saddr != saddr
232                 || (*pskb)->nh.iph->daddr != daddr))
233                 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
234         return ret;
235 }
236 #endif
237
238 /* We must be after connection tracking and before packet filtering. */
239
240 /* Before packet filtering, change destination */
241 static struct nf_hook_ops ip_nat_in_ops = {
242         .hook           = ip_nat_fn,
243         .owner          = THIS_MODULE,
244         .pf             = PF_INET,
245         .hooknum        = NF_IP_PRE_ROUTING,
246         .priority       = NF_IP_PRI_NAT_DST,
247 };
248
249 /* After packet filtering, change source */
250 static struct nf_hook_ops ip_nat_out_ops = {
251         .hook           = ip_nat_out,
252         .owner          = THIS_MODULE,
253         .pf             = PF_INET,
254         .hooknum        = NF_IP_POST_ROUTING,
255         .priority       = NF_IP_PRI_NAT_SRC,
256 };
257
258 #ifdef CONFIG_IP_NF_NAT_LOCAL
259 /* Before packet filtering, change destination */
260 static struct nf_hook_ops ip_nat_local_out_ops = {
261         .hook           = ip_nat_local_fn,
262         .owner          = THIS_MODULE,
263         .pf             = PF_INET,
264         .hooknum        = NF_IP_LOCAL_OUT,
265         .priority       = NF_IP_PRI_NAT_DST,
266 };
267
268 /* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
269 static struct nf_hook_ops ip_nat_local_in_ops = {
270         .hook           = ip_nat_fn,
271         .owner          = THIS_MODULE,
272         .pf             = PF_INET,
273         .hooknum        = NF_IP_LOCAL_IN,
274         .priority       = NF_IP_PRI_NAT_SRC,
275 };
276 #endif
277
278 /* Protocol registration. */
279 int ip_nat_protocol_register(struct ip_nat_protocol *proto)
280 {
281         int ret = 0;
282         struct list_head *i;
283
284         WRITE_LOCK(&ip_nat_lock);
285         list_for_each(i, &protos) {
286                 if (((struct ip_nat_protocol *)i)->protonum
287                     == proto->protonum) {
288                         ret = -EBUSY;
289                         goto out;
290                 }
291         }
292
293         list_prepend(&protos, proto);
294  out:
295         WRITE_UNLOCK(&ip_nat_lock);
296         return ret;
297 }
298
299 /* Noone stores the protocol anywhere; simply delete it. */
300 void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
301 {
302         WRITE_LOCK(&ip_nat_lock);
303         LIST_DELETE(&protos, proto);
304         WRITE_UNLOCK(&ip_nat_lock);
305
306         /* Someone could be still looking at the proto in a bh. */
307         synchronize_net();
308 }
309
310 static int init_or_cleanup(int init)
311 {
312         int ret = 0;
313
314         need_ip_conntrack();
315
316         if (!init) goto cleanup;
317
318         ret = ip_nat_rule_init();
319         if (ret < 0) {
320                 printk("ip_nat_init: can't setup rules.\n");
321                 goto cleanup_nothing;
322         }
323         ret = ip_nat_init();
324         if (ret < 0) {
325                 printk("ip_nat_init: can't setup rules.\n");
326                 goto cleanup_rule_init;
327         }
328         ret = nf_register_hook(&ip_nat_in_ops);
329         if (ret < 0) {
330                 printk("ip_nat_init: can't register in hook.\n");
331                 goto cleanup_nat;
332         }
333         ret = nf_register_hook(&ip_nat_out_ops);
334         if (ret < 0) {
335                 printk("ip_nat_init: can't register out hook.\n");
336                 goto cleanup_inops;
337         }
338 #ifdef CONFIG_IP_NF_NAT_LOCAL
339         ret = nf_register_hook(&ip_nat_local_out_ops);
340         if (ret < 0) {
341                 printk("ip_nat_init: can't register local out hook.\n");
342                 goto cleanup_outops;
343         }
344         ret = nf_register_hook(&ip_nat_local_in_ops);
345         if (ret < 0) {
346                 printk("ip_nat_init: can't register local in hook.\n");
347                 goto cleanup_localoutops;
348         }
349 #endif
350         return ret;
351
352  cleanup:
353 #ifdef CONFIG_IP_NF_NAT_LOCAL
354         nf_unregister_hook(&ip_nat_local_in_ops);
355  cleanup_localoutops:
356         nf_unregister_hook(&ip_nat_local_out_ops);
357  cleanup_outops:
358 #endif
359         nf_unregister_hook(&ip_nat_out_ops);
360  cleanup_inops:
361         nf_unregister_hook(&ip_nat_in_ops);
362  cleanup_nat:
363         ip_nat_cleanup();
364  cleanup_rule_init:
365         ip_nat_rule_cleanup();
366  cleanup_nothing:
367         MUST_BE_READ_WRITE_UNLOCKED(&ip_nat_lock);
368         return ret;
369 }
370
371 static int __init init(void)
372 {
373         return init_or_cleanup(1);
374 }
375
376 static void __exit fini(void)
377 {
378         init_or_cleanup(0);
379 }
380
381 module_init(init);
382 module_exit(fini);
383
384 EXPORT_SYMBOL(ip_nat_setup_info);
385 EXPORT_SYMBOL(ip_nat_protocol_register);
386 EXPORT_SYMBOL(ip_nat_protocol_unregister);
387 EXPORT_SYMBOL(ip_nat_helper_register);
388 EXPORT_SYMBOL(ip_nat_helper_unregister);
389 EXPORT_SYMBOL(ip_nat_cheat_check);
390 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
391 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
392 EXPORT_SYMBOL(ip_nat_used_tuple);
393 MODULE_LICENSE("GPL");