Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / net / netfilter / xt_CT.c
1 /*
2  * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 #include <linux/module.h>
10 #include <linux/gfp.h>
11 #include <linux/skbuff.h>
12 #include <linux/netfilter_ipv4/ip_tables.h>
13 #include <linux/netfilter_ipv6/ip6_tables.h>
14 #include <linux/netfilter/x_tables.h>
15 #include <linux/netfilter/xt_CT.h>
16 #include <net/netfilter/nf_conntrack.h>
17 #include <net/netfilter/nf_conntrack_l4proto.h>
18 #include <net/netfilter/nf_conntrack_helper.h>
19 #include <net/netfilter/nf_conntrack_ecache.h>
20 #include <net/netfilter/nf_conntrack_timeout.h>
21 #include <net/netfilter/nf_conntrack_zones.h>
22
23 static unsigned int xt_ct_target_v0(struct sk_buff *skb,
24                                     const struct xt_action_param *par)
25 {
26         const struct xt_ct_target_info *info = par->targinfo;
27         struct nf_conn *ct = info->ct;
28
29         /* Previously seen (loopback)? Ignore. */
30         if (skb->nfct != NULL)
31                 return XT_CONTINUE;
32
33         atomic_inc(&ct->ct_general.use);
34         skb->nfct = &ct->ct_general;
35         skb->nfctinfo = IP_CT_NEW;
36
37         return XT_CONTINUE;
38 }
39
40 static unsigned int xt_ct_target_v1(struct sk_buff *skb,
41                                     const struct xt_action_param *par)
42 {
43         const struct xt_ct_target_info_v1 *info = par->targinfo;
44         struct nf_conn *ct = info->ct;
45
46         /* Previously seen (loopback)? Ignore. */
47         if (skb->nfct != NULL)
48                 return XT_CONTINUE;
49
50         atomic_inc(&ct->ct_general.use);
51         skb->nfct = &ct->ct_general;
52         skb->nfctinfo = IP_CT_NEW;
53
54         return XT_CONTINUE;
55 }
56
57 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
58 {
59         if (par->family == NFPROTO_IPV4) {
60                 const struct ipt_entry *e = par->entryinfo;
61
62                 if (e->ip.invflags & IPT_INV_PROTO)
63                         return 0;
64                 return e->ip.proto;
65         } else if (par->family == NFPROTO_IPV6) {
66                 const struct ip6t_entry *e = par->entryinfo;
67
68                 if (e->ipv6.invflags & IP6T_INV_PROTO)
69                         return 0;
70                 return e->ipv6.proto;
71         } else
72                 return 0;
73 }
74
75 static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
76 {
77         struct xt_ct_target_info *info = par->targinfo;
78         struct nf_conntrack_tuple t;
79         struct nf_conn_help *help;
80         struct nf_conn *ct;
81         int ret = 0;
82         u8 proto;
83
84         if (info->flags & ~XT_CT_NOTRACK)
85                 return -EINVAL;
86
87         if (info->flags & XT_CT_NOTRACK) {
88                 ct = nf_ct_untracked_get();
89                 atomic_inc(&ct->ct_general.use);
90                 goto out;
91         }
92
93 #ifndef CONFIG_NF_CONNTRACK_ZONES
94         if (info->zone)
95                 goto err1;
96 #endif
97
98         ret = nf_ct_l3proto_try_module_get(par->family);
99         if (ret < 0)
100                 goto err1;
101
102         memset(&t, 0, sizeof(t));
103         ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
104         ret = PTR_ERR(ct);
105         if (IS_ERR(ct))
106                 goto err2;
107
108         ret = 0;
109         if ((info->ct_events || info->exp_events) &&
110             !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
111                                   GFP_KERNEL))
112                 goto err3;
113
114         if (info->helper[0]) {
115                 ret = -ENOENT;
116                 proto = xt_ct_find_proto(par);
117                 if (!proto) {
118                         pr_info("You must specify a L4 protocol, "
119                                 "and not use inversions on it.\n");
120                         goto err3;
121                 }
122
123                 ret = -ENOMEM;
124                 help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
125                 if (help == NULL)
126                         goto err3;
127
128                 ret = -ENOENT;
129                 help->helper = nf_conntrack_helper_try_module_get(info->helper,
130                                                                   par->family,
131                                                                   proto);
132                 if (help->helper == NULL) {
133                         pr_info("No such helper \"%s\"\n", info->helper);
134                         goto err3;
135                 }
136         }
137
138         __set_bit(IPS_TEMPLATE_BIT, &ct->status);
139         __set_bit(IPS_CONFIRMED_BIT, &ct->status);
140 out:
141         info->ct = ct;
142         return 0;
143
144 err3:
145         nf_conntrack_free(ct);
146 err2:
147         nf_ct_l3proto_module_put(par->family);
148 err1:
149         return ret;
150 }
151
152 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
153 static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
154 {
155         typeof(nf_ct_timeout_put_hook) timeout_put;
156
157         timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
158         if (timeout_put)
159                 timeout_put(timeout);
160 }
161 #endif
162
163 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
164 {
165         struct xt_ct_target_info_v1 *info = par->targinfo;
166         struct nf_conntrack_tuple t;
167         struct nf_conn_help *help;
168         struct nf_conn *ct;
169         int ret = 0;
170         u8 proto;
171 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
172         struct ctnl_timeout *timeout;
173 #endif
174         if (info->flags & ~XT_CT_NOTRACK)
175                 return -EINVAL;
176
177         if (info->flags & XT_CT_NOTRACK) {
178                 ct = nf_ct_untracked_get();
179                 atomic_inc(&ct->ct_general.use);
180                 goto out;
181         }
182
183 #ifndef CONFIG_NF_CONNTRACK_ZONES
184         if (info->zone)
185                 goto err1;
186 #endif
187
188         ret = nf_ct_l3proto_try_module_get(par->family);
189         if (ret < 0)
190                 goto err1;
191
192         memset(&t, 0, sizeof(t));
193         ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
194         ret = PTR_ERR(ct);
195         if (IS_ERR(ct))
196                 goto err2;
197
198         ret = 0;
199         if ((info->ct_events || info->exp_events) &&
200             !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
201                                   GFP_KERNEL))
202                 goto err3;
203
204         if (info->helper[0]) {
205                 ret = -ENOENT;
206                 proto = xt_ct_find_proto(par);
207                 if (!proto) {
208                         pr_info("You must specify a L4 protocol, "
209                                 "and not use inversions on it.\n");
210                         goto err3;
211                 }
212
213                 ret = -ENOMEM;
214                 help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
215                 if (help == NULL)
216                         goto err3;
217
218                 ret = -ENOENT;
219                 help->helper = nf_conntrack_helper_try_module_get(info->helper,
220                                                                   par->family,
221                                                                   proto);
222                 if (help->helper == NULL) {
223                         pr_info("No such helper \"%s\"\n", info->helper);
224                         goto err3;
225                 }
226         }
227
228 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
229         if (info->timeout[0]) {
230                 typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
231                 struct nf_conn_timeout *timeout_ext;
232
233                 rcu_read_lock();
234                 timeout_find_get =
235                         rcu_dereference(nf_ct_timeout_find_get_hook);
236
237                 if (timeout_find_get) {
238                         const struct ipt_entry *e = par->entryinfo;
239                         struct nf_conntrack_l4proto *l4proto;
240
241                         if (e->ip.invflags & IPT_INV_PROTO) {
242                                 ret = -EINVAL;
243                                 pr_info("You cannot use inversion on "
244                                          "L4 protocol\n");
245                                 goto err4;
246                         }
247                         timeout = timeout_find_get(info->timeout);
248                         if (timeout == NULL) {
249                                 ret = -ENOENT;
250                                 pr_info("No such timeout policy \"%s\"\n",
251                                         info->timeout);
252                                 goto err4;
253                         }
254                         if (timeout->l3num != par->family) {
255                                 ret = -EINVAL;
256                                 pr_info("Timeout policy `%s' can only be "
257                                         "used by L3 protocol number %d\n",
258                                         info->timeout, timeout->l3num);
259                                 goto err5;
260                         }
261                         /* Make sure the timeout policy matches any existing
262                          * protocol tracker, otherwise default to generic.
263                          */
264                         l4proto = __nf_ct_l4proto_find(par->family,
265                                                        e->ip.proto);
266                         if (timeout->l4proto->l4proto != l4proto->l4proto) {
267                                 ret = -EINVAL;
268                                 pr_info("Timeout policy `%s' can only be "
269                                         "used by L4 protocol number %d\n",
270                                         info->timeout,
271                                         timeout->l4proto->l4proto);
272                                 goto err5;
273                         }
274                         timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
275                                                             GFP_ATOMIC);
276                         if (timeout_ext == NULL) {
277                                 ret = -ENOMEM;
278                                 goto err5;
279                         }
280                 } else {
281                         ret = -ENOENT;
282                         pr_info("Timeout policy base is empty\n");
283                         goto err4;
284                 }
285                 rcu_read_unlock();
286         }
287 #endif
288
289         __set_bit(IPS_TEMPLATE_BIT, &ct->status);
290         __set_bit(IPS_CONFIRMED_BIT, &ct->status);
291 out:
292         info->ct = ct;
293         return 0;
294
295 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
296 err5:
297         __xt_ct_tg_timeout_put(timeout);
298 err4:
299         rcu_read_unlock();
300 #endif
301 err3:
302         nf_conntrack_free(ct);
303 err2:
304         nf_ct_l3proto_module_put(par->family);
305 err1:
306         return ret;
307 }
308
309 static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
310 {
311         struct xt_ct_target_info *info = par->targinfo;
312         struct nf_conn *ct = info->ct;
313         struct nf_conn_help *help;
314
315         if (!nf_ct_is_untracked(ct)) {
316                 help = nfct_help(ct);
317                 if (help)
318                         module_put(help->helper->me);
319
320                 nf_ct_l3proto_module_put(par->family);
321         }
322         nf_ct_put(info->ct);
323 }
324
325 static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
326 {
327         struct xt_ct_target_info_v1 *info = par->targinfo;
328         struct nf_conn *ct = info->ct;
329         struct nf_conn_help *help;
330 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
331         struct nf_conn_timeout *timeout_ext;
332         typeof(nf_ct_timeout_put_hook) timeout_put;
333 #endif
334         if (!nf_ct_is_untracked(ct)) {
335                 help = nfct_help(ct);
336                 if (help)
337                         module_put(help->helper->me);
338
339                 nf_ct_l3proto_module_put(par->family);
340
341 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
342                 rcu_read_lock();
343                 timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
344
345                 if (timeout_put) {
346                         timeout_ext = nf_ct_timeout_find(ct);
347                         if (timeout_ext)
348                                 timeout_put(timeout_ext->timeout);
349                 }
350                 rcu_read_unlock();
351 #endif
352         }
353         nf_ct_put(info->ct);
354 }
355
356 static struct xt_target xt_ct_tg_reg[] __read_mostly = {
357         {
358                 .name           = "CT",
359                 .family         = NFPROTO_UNSPEC,
360                 .targetsize     = sizeof(struct xt_ct_target_info),
361                 .checkentry     = xt_ct_tg_check_v0,
362                 .destroy        = xt_ct_tg_destroy_v0,
363                 .target         = xt_ct_target_v0,
364                 .table          = "raw",
365                 .me             = THIS_MODULE,
366         },
367         {
368                 .name           = "CT",
369                 .family         = NFPROTO_UNSPEC,
370                 .revision       = 1,
371                 .targetsize     = sizeof(struct xt_ct_target_info_v1),
372                 .checkentry     = xt_ct_tg_check_v1,
373                 .destroy        = xt_ct_tg_destroy_v1,
374                 .target         = xt_ct_target_v1,
375                 .table          = "raw",
376                 .me             = THIS_MODULE,
377         },
378 };
379
380 static int __init xt_ct_tg_init(void)
381 {
382         return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
383 }
384
385 static void __exit xt_ct_tg_exit(void)
386 {
387         xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
388 }
389
390 module_init(xt_ct_tg_init);
391 module_exit(xt_ct_tg_exit);
392
393 MODULE_LICENSE("GPL");
394 MODULE_DESCRIPTION("Xtables: connection tracking target");
395 MODULE_ALIAS("ipt_CT");
396 MODULE_ALIAS("ip6t_CT");