]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/xt_CT.c
Merge remote-tracking branches 'regulator/topic/notifier', 'regulator/topic/pfuze100...
[karo-tx-linux.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 inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
24 {
25         /* Previously seen (loopback)? Ignore. */
26         if (skb->_nfct != 0)
27                 return XT_CONTINUE;
28
29         /* special case the untracked ct : we want the percpu object */
30         if (!ct)
31                 ct = nf_ct_untracked_get();
32         atomic_inc(&ct->ct_general.use);
33         nf_ct_set(skb, ct, IP_CT_NEW);
34
35         return XT_CONTINUE;
36 }
37
38 static unsigned int xt_ct_target_v0(struct sk_buff *skb,
39                                     const struct xt_action_param *par)
40 {
41         const struct xt_ct_target_info *info = par->targinfo;
42         struct nf_conn *ct = info->ct;
43
44         return xt_ct_target(skb, ct);
45 }
46
47 static unsigned int xt_ct_target_v1(struct sk_buff *skb,
48                                     const struct xt_action_param *par)
49 {
50         const struct xt_ct_target_info_v1 *info = par->targinfo;
51         struct nf_conn *ct = info->ct;
52
53         return xt_ct_target(skb, ct);
54 }
55
56 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
57 {
58         if (par->family == NFPROTO_IPV4) {
59                 const struct ipt_entry *e = par->entryinfo;
60
61                 if (e->ip.invflags & IPT_INV_PROTO)
62                         return 0;
63                 return e->ip.proto;
64         } else if (par->family == NFPROTO_IPV6) {
65                 const struct ip6t_entry *e = par->entryinfo;
66
67                 if (e->ipv6.invflags & IP6T_INV_PROTO)
68                         return 0;
69                 return e->ipv6.proto;
70         } else
71                 return 0;
72 }
73
74 static int
75 xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
76                  const struct xt_tgchk_param *par)
77 {
78         struct nf_conntrack_helper *helper;
79         struct nf_conn_help *help;
80         u8 proto;
81
82         proto = xt_ct_find_proto(par);
83         if (!proto) {
84                 pr_info("You must specify a L4 protocol, and not use "
85                         "inversions on it.\n");
86                 return -ENOENT;
87         }
88
89         helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
90                                                     proto);
91         if (helper == NULL) {
92                 pr_info("No such helper \"%s\"\n", helper_name);
93                 return -ENOENT;
94         }
95
96         help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
97         if (help == NULL) {
98                 module_put(helper->me);
99                 return -ENOMEM;
100         }
101
102         help->helper = helper;
103         return 0;
104 }
105
106 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
107 static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
108 {
109         typeof(nf_ct_timeout_put_hook) timeout_put;
110
111         timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
112         if (timeout_put)
113                 timeout_put(timeout);
114 }
115 #endif
116
117 static int
118 xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
119                   const char *timeout_name)
120 {
121 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
122         typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
123         struct ctnl_timeout *timeout;
124         struct nf_conn_timeout *timeout_ext;
125         struct nf_conntrack_l4proto *l4proto;
126         int ret = 0;
127         u8 proto;
128
129         rcu_read_lock();
130         timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
131         if (timeout_find_get == NULL) {
132                 ret = -ENOENT;
133                 pr_info("Timeout policy base is empty\n");
134                 goto out;
135         }
136
137         proto = xt_ct_find_proto(par);
138         if (!proto) {
139                 ret = -EINVAL;
140                 pr_info("You must specify a L4 protocol, and not use "
141                         "inversions on it.\n");
142                 goto out;
143         }
144
145         timeout = timeout_find_get(par->net, timeout_name);
146         if (timeout == NULL) {
147                 ret = -ENOENT;
148                 pr_info("No such timeout policy \"%s\"\n", timeout_name);
149                 goto out;
150         }
151
152         if (timeout->l3num != par->family) {
153                 ret = -EINVAL;
154                 pr_info("Timeout policy `%s' can only be used by L3 protocol "
155                         "number %d\n", timeout_name, timeout->l3num);
156                 goto err_put_timeout;
157         }
158         /* Make sure the timeout policy matches any existing protocol tracker,
159          * otherwise default to generic.
160          */
161         l4proto = __nf_ct_l4proto_find(par->family, proto);
162         if (timeout->l4proto->l4proto != l4proto->l4proto) {
163                 ret = -EINVAL;
164                 pr_info("Timeout policy `%s' can only be used by L4 protocol "
165                         "number %d\n",
166                         timeout_name, timeout->l4proto->l4proto);
167                 goto err_put_timeout;
168         }
169         timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
170         if (timeout_ext == NULL)
171                 ret = -ENOMEM;
172
173         rcu_read_unlock();
174         return ret;
175
176 err_put_timeout:
177         __xt_ct_tg_timeout_put(timeout);
178 out:
179         rcu_read_unlock();
180         return ret;
181 #else
182         return -EOPNOTSUPP;
183 #endif
184 }
185
186 static u16 xt_ct_flags_to_dir(const struct xt_ct_target_info_v1 *info)
187 {
188         switch (info->flags & (XT_CT_ZONE_DIR_ORIG |
189                                XT_CT_ZONE_DIR_REPL)) {
190         case XT_CT_ZONE_DIR_ORIG:
191                 return NF_CT_ZONE_DIR_ORIG;
192         case XT_CT_ZONE_DIR_REPL:
193                 return NF_CT_ZONE_DIR_REPL;
194         default:
195                 return NF_CT_DEFAULT_ZONE_DIR;
196         }
197 }
198
199 static int xt_ct_tg_check(const struct xt_tgchk_param *par,
200                           struct xt_ct_target_info_v1 *info)
201 {
202         struct nf_conntrack_zone zone;
203         struct nf_conn *ct;
204         int ret = -EOPNOTSUPP;
205
206         if (info->flags & XT_CT_NOTRACK) {
207                 ct = NULL;
208                 goto out;
209         }
210
211 #ifndef CONFIG_NF_CONNTRACK_ZONES
212         if (info->zone || info->flags & (XT_CT_ZONE_DIR_ORIG |
213                                          XT_CT_ZONE_DIR_REPL |
214                                          XT_CT_ZONE_MARK))
215                 goto err1;
216 #endif
217
218         ret = nf_ct_netns_get(par->net, par->family);
219         if (ret < 0)
220                 goto err1;
221
222         memset(&zone, 0, sizeof(zone));
223         zone.id = info->zone;
224         zone.dir = xt_ct_flags_to_dir(info);
225         if (info->flags & XT_CT_ZONE_MARK)
226                 zone.flags |= NF_CT_FLAG_MARK;
227
228         ct = nf_ct_tmpl_alloc(par->net, &zone, GFP_KERNEL);
229         if (!ct) {
230                 ret = -ENOMEM;
231                 goto err2;
232         }
233
234         ret = 0;
235         if ((info->ct_events || info->exp_events) &&
236             !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
237                                   GFP_KERNEL)) {
238                 ret = -EINVAL;
239                 goto err3;
240         }
241
242         if (info->helper[0]) {
243                 ret = xt_ct_set_helper(ct, info->helper, par);
244                 if (ret < 0)
245                         goto err3;
246         }
247
248         if (info->timeout[0]) {
249                 ret = xt_ct_set_timeout(ct, par, info->timeout);
250                 if (ret < 0)
251                         goto err3;
252         }
253         __set_bit(IPS_CONFIRMED_BIT, &ct->status);
254         nf_conntrack_get(&ct->ct_general);
255 out:
256         info->ct = ct;
257         return 0;
258
259 err3:
260         nf_ct_tmpl_free(ct);
261 err2:
262         nf_ct_netns_put(par->net, par->family);
263 err1:
264         return ret;
265 }
266
267 static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
268 {
269         struct xt_ct_target_info *info = par->targinfo;
270         struct xt_ct_target_info_v1 info_v1 = {
271                 .flags          = info->flags,
272                 .zone           = info->zone,
273                 .ct_events      = info->ct_events,
274                 .exp_events     = info->exp_events,
275         };
276         int ret;
277
278         if (info->flags & ~XT_CT_NOTRACK)
279                 return -EINVAL;
280
281         memcpy(info_v1.helper, info->helper, sizeof(info->helper));
282
283         ret = xt_ct_tg_check(par, &info_v1);
284         if (ret < 0)
285                 return ret;
286
287         info->ct = info_v1.ct;
288
289         return ret;
290 }
291
292 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
293 {
294         struct xt_ct_target_info_v1 *info = par->targinfo;
295
296         if (info->flags & ~XT_CT_NOTRACK)
297                 return -EINVAL;
298
299         return xt_ct_tg_check(par, par->targinfo);
300 }
301
302 static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
303 {
304         struct xt_ct_target_info_v1 *info = par->targinfo;
305
306         if (info->flags & ~XT_CT_MASK)
307                 return -EINVAL;
308
309         return xt_ct_tg_check(par, par->targinfo);
310 }
311
312 static void xt_ct_destroy_timeout(struct nf_conn *ct)
313 {
314 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
315         struct nf_conn_timeout *timeout_ext;
316         typeof(nf_ct_timeout_put_hook) timeout_put;
317
318         rcu_read_lock();
319         timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
320
321         if (timeout_put) {
322                 timeout_ext = nf_ct_timeout_find(ct);
323                 if (timeout_ext) {
324                         timeout_put(timeout_ext->timeout);
325                         RCU_INIT_POINTER(timeout_ext->timeout, NULL);
326                 }
327         }
328         rcu_read_unlock();
329 #endif
330 }
331
332 static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
333                              struct xt_ct_target_info_v1 *info)
334 {
335         struct nf_conn *ct = info->ct;
336         struct nf_conn_help *help;
337
338         if (ct && !nf_ct_is_untracked(ct)) {
339                 help = nfct_help(ct);
340                 if (help)
341                         module_put(help->helper->me);
342
343                 nf_ct_netns_put(par->net, par->family);
344
345                 xt_ct_destroy_timeout(ct);
346                 nf_ct_put(info->ct);
347         }
348 }
349
350 static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
351 {
352         struct xt_ct_target_info *info = par->targinfo;
353         struct xt_ct_target_info_v1 info_v1 = {
354                 .flags          = info->flags,
355                 .zone           = info->zone,
356                 .ct_events      = info->ct_events,
357                 .exp_events     = info->exp_events,
358                 .ct             = info->ct,
359         };
360         memcpy(info_v1.helper, info->helper, sizeof(info->helper));
361
362         xt_ct_tg_destroy(par, &info_v1);
363 }
364
365 static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
366 {
367         xt_ct_tg_destroy(par, par->targinfo);
368 }
369
370 static struct xt_target xt_ct_tg_reg[] __read_mostly = {
371         {
372                 .name           = "CT",
373                 .family         = NFPROTO_UNSPEC,
374                 .targetsize     = sizeof(struct xt_ct_target_info),
375                 .usersize       = offsetof(struct xt_ct_target_info, ct),
376                 .checkentry     = xt_ct_tg_check_v0,
377                 .destroy        = xt_ct_tg_destroy_v0,
378                 .target         = xt_ct_target_v0,
379                 .table          = "raw",
380                 .me             = THIS_MODULE,
381         },
382         {
383                 .name           = "CT",
384                 .family         = NFPROTO_UNSPEC,
385                 .revision       = 1,
386                 .targetsize     = sizeof(struct xt_ct_target_info_v1),
387                 .usersize       = offsetof(struct xt_ct_target_info, ct),
388                 .checkentry     = xt_ct_tg_check_v1,
389                 .destroy        = xt_ct_tg_destroy_v1,
390                 .target         = xt_ct_target_v1,
391                 .table          = "raw",
392                 .me             = THIS_MODULE,
393         },
394         {
395                 .name           = "CT",
396                 .family         = NFPROTO_UNSPEC,
397                 .revision       = 2,
398                 .targetsize     = sizeof(struct xt_ct_target_info_v1),
399                 .usersize       = offsetof(struct xt_ct_target_info, ct),
400                 .checkentry     = xt_ct_tg_check_v2,
401                 .destroy        = xt_ct_tg_destroy_v1,
402                 .target         = xt_ct_target_v1,
403                 .table          = "raw",
404                 .me             = THIS_MODULE,
405         },
406 };
407
408 static unsigned int
409 notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
410 {
411         /* Previously seen (loopback)? Ignore. */
412         if (skb->_nfct != 0)
413                 return XT_CONTINUE;
414
415         nf_ct_set(skb, nf_ct_untracked_get(), IP_CT_NEW);
416         nf_conntrack_get(skb_nfct(skb));
417
418         return XT_CONTINUE;
419 }
420
421 static int notrack_chk(const struct xt_tgchk_param *par)
422 {
423         if (!par->net->xt.notrack_deprecated_warning) {
424                 pr_info("netfilter: NOTRACK target is deprecated, "
425                         "use CT instead or upgrade iptables\n");
426                 par->net->xt.notrack_deprecated_warning = true;
427         }
428         return 0;
429 }
430
431 static struct xt_target notrack_tg_reg __read_mostly = {
432         .name           = "NOTRACK",
433         .revision       = 0,
434         .family         = NFPROTO_UNSPEC,
435         .checkentry     = notrack_chk,
436         .target         = notrack_tg,
437         .table          = "raw",
438         .me             = THIS_MODULE,
439 };
440
441 static int __init xt_ct_tg_init(void)
442 {
443         int ret;
444
445         ret = xt_register_target(&notrack_tg_reg);
446         if (ret < 0)
447                 return ret;
448
449         ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
450         if (ret < 0) {
451                 xt_unregister_target(&notrack_tg_reg);
452                 return ret;
453         }
454         return 0;
455 }
456
457 static void __exit xt_ct_tg_exit(void)
458 {
459         xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
460         xt_unregister_target(&notrack_tg_reg);
461 }
462
463 module_init(xt_ct_tg_init);
464 module_exit(xt_ct_tg_exit);
465
466 MODULE_LICENSE("GPL");
467 MODULE_DESCRIPTION("Xtables: connection tracking target");
468 MODULE_ALIAS("ipt_CT");
469 MODULE_ALIAS("ip6t_CT");
470 MODULE_ALIAS("ipt_NOTRACK");
471 MODULE_ALIAS("ip6t_NOTRACK");