x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / net / netfilter / nft_ct.c
1 /*
2  * Copyright (c) 2008-2009 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  * Development of this code funded by Astaro AG (http://www.astaro.com/)
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/netlink.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter/nf_tables.h>
17 #include <net/netfilter/nf_tables.h>
18 #include <net/netfilter/nf_conntrack.h>
19 #include <net/netfilter/nf_conntrack_acct.h>
20 #include <net/netfilter/nf_conntrack_tuple.h>
21 #include <net/netfilter/nf_conntrack_helper.h>
22 #include <net/netfilter/nf_conntrack_ecache.h>
23 #include <net/netfilter/nf_conntrack_labels.h>
24
25 struct nft_ct {
26         enum nft_ct_keys        key:8;
27         enum ip_conntrack_dir   dir:8;
28         union {
29                 enum nft_registers      dreg:8;
30                 enum nft_registers      sreg:8;
31         };
32 };
33
34 static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
35                                    enum nft_ct_keys k,
36                                    enum ip_conntrack_dir d)
37 {
38         if (d < IP_CT_DIR_MAX)
39                 return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
40                                            atomic64_read(&c[d].packets);
41
42         return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
43                nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
44 }
45
46 static void nft_ct_get_eval(const struct nft_expr *expr,
47                             struct nft_regs *regs,
48                             const struct nft_pktinfo *pkt)
49 {
50         const struct nft_ct *priv = nft_expr_priv(expr);
51         u32 *dest = &regs->data[priv->dreg];
52         enum ip_conntrack_info ctinfo;
53         const struct nf_conn *ct;
54         const struct nf_conn_help *help;
55         const struct nf_conntrack_tuple *tuple;
56         const struct nf_conntrack_helper *helper;
57         unsigned int state;
58
59         ct = nf_ct_get(pkt->skb, &ctinfo);
60
61         switch (priv->key) {
62         case NFT_CT_STATE:
63                 if (ct == NULL)
64                         state = NF_CT_STATE_INVALID_BIT;
65                 else if (nf_ct_is_untracked(ct))
66                         state = NF_CT_STATE_UNTRACKED_BIT;
67                 else
68                         state = NF_CT_STATE_BIT(ctinfo);
69                 *dest = state;
70                 return;
71         default:
72                 break;
73         }
74
75         if (ct == NULL)
76                 goto err;
77
78         switch (priv->key) {
79         case NFT_CT_DIRECTION:
80                 *dest = CTINFO2DIR(ctinfo);
81                 return;
82         case NFT_CT_STATUS:
83                 *dest = ct->status;
84                 return;
85 #ifdef CONFIG_NF_CONNTRACK_MARK
86         case NFT_CT_MARK:
87                 *dest = ct->mark;
88                 return;
89 #endif
90 #ifdef CONFIG_NF_CONNTRACK_SECMARK
91         case NFT_CT_SECMARK:
92                 *dest = ct->secmark;
93                 return;
94 #endif
95         case NFT_CT_EXPIRATION:
96                 *dest = jiffies_to_msecs(nf_ct_expires(ct));
97                 return;
98         case NFT_CT_HELPER:
99                 if (ct->master == NULL)
100                         goto err;
101                 help = nfct_help(ct->master);
102                 if (help == NULL)
103                         goto err;
104                 helper = rcu_dereference(help->helper);
105                 if (helper == NULL)
106                         goto err;
107                 strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
108                 return;
109 #ifdef CONFIG_NF_CONNTRACK_LABELS
110         case NFT_CT_LABELS: {
111                 struct nf_conn_labels *labels = nf_ct_labels_find(ct);
112
113                 if (labels)
114                         memcpy(dest, labels->bits, NF_CT_LABELS_MAX_SIZE);
115                 else
116                         memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
117                 return;
118         }
119 #endif
120         case NFT_CT_BYTES: /* fallthrough */
121         case NFT_CT_PKTS: {
122                 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
123                 u64 count = 0;
124
125                 if (acct)
126                         count = nft_ct_get_eval_counter(acct->counter,
127                                                         priv->key, priv->dir);
128                 memcpy(dest, &count, sizeof(count));
129                 return;
130         }
131         case NFT_CT_L3PROTOCOL:
132                 *dest = nf_ct_l3num(ct);
133                 return;
134         case NFT_CT_PROTOCOL:
135                 *dest = nf_ct_protonum(ct);
136                 return;
137         default:
138                 break;
139         }
140
141         tuple = &ct->tuplehash[priv->dir].tuple;
142         switch (priv->key) {
143         case NFT_CT_SRC:
144                 memcpy(dest, tuple->src.u3.all,
145                        nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
146                 return;
147         case NFT_CT_DST:
148                 memcpy(dest, tuple->dst.u3.all,
149                        nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
150                 return;
151         case NFT_CT_PROTO_SRC:
152                 *dest = (__force __u16)tuple->src.u.all;
153                 return;
154         case NFT_CT_PROTO_DST:
155                 *dest = (__force __u16)tuple->dst.u.all;
156                 return;
157         default:
158                 break;
159         }
160         return;
161 err:
162         regs->verdict.code = NFT_BREAK;
163 }
164
165 static void nft_ct_set_eval(const struct nft_expr *expr,
166                             struct nft_regs *regs,
167                             const struct nft_pktinfo *pkt)
168 {
169         const struct nft_ct *priv = nft_expr_priv(expr);
170         struct sk_buff *skb = pkt->skb;
171 #ifdef CONFIG_NF_CONNTRACK_MARK
172         u32 value = regs->data[priv->sreg];
173 #endif
174         enum ip_conntrack_info ctinfo;
175         struct nf_conn *ct;
176
177         ct = nf_ct_get(skb, &ctinfo);
178         if (ct == NULL)
179                 return;
180
181         switch (priv->key) {
182 #ifdef CONFIG_NF_CONNTRACK_MARK
183         case NFT_CT_MARK:
184                 if (ct->mark != value) {
185                         ct->mark = value;
186                         nf_conntrack_event_cache(IPCT_MARK, ct);
187                 }
188                 break;
189 #endif
190 #ifdef CONFIG_NF_CONNTRACK_LABELS
191         case NFT_CT_LABELS:
192                 nf_connlabels_replace(ct,
193                                       &regs->data[priv->sreg],
194                                       &regs->data[priv->sreg],
195                                       NF_CT_LABELS_MAX_SIZE / sizeof(u32));
196                 break;
197 #endif
198         default:
199                 break;
200         }
201 }
202
203 static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
204         [NFTA_CT_DREG]          = { .type = NLA_U32 },
205         [NFTA_CT_KEY]           = { .type = NLA_U32 },
206         [NFTA_CT_DIRECTION]     = { .type = NLA_U8 },
207         [NFTA_CT_SREG]          = { .type = NLA_U32 },
208 };
209
210 static int nft_ct_l3proto_try_module_get(uint8_t family)
211 {
212         int err;
213
214         if (family == NFPROTO_INET) {
215                 err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4);
216                 if (err < 0)
217                         goto err1;
218                 err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6);
219                 if (err < 0)
220                         goto err2;
221         } else {
222                 err = nf_ct_l3proto_try_module_get(family);
223                 if (err < 0)
224                         goto err1;
225         }
226         return 0;
227
228 err2:
229         nf_ct_l3proto_module_put(NFPROTO_IPV4);
230 err1:
231         return err;
232 }
233
234 static void nft_ct_l3proto_module_put(uint8_t family)
235 {
236         if (family == NFPROTO_INET) {
237                 nf_ct_l3proto_module_put(NFPROTO_IPV4);
238                 nf_ct_l3proto_module_put(NFPROTO_IPV6);
239         } else
240                 nf_ct_l3proto_module_put(family);
241 }
242
243 static int nft_ct_get_init(const struct nft_ctx *ctx,
244                            const struct nft_expr *expr,
245                            const struct nlattr * const tb[])
246 {
247         struct nft_ct *priv = nft_expr_priv(expr);
248         unsigned int len;
249         int err;
250
251         priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
252         switch (priv->key) {
253         case NFT_CT_DIRECTION:
254                 if (tb[NFTA_CT_DIRECTION] != NULL)
255                         return -EINVAL;
256                 len = sizeof(u8);
257                 break;
258         case NFT_CT_STATE:
259         case NFT_CT_STATUS:
260 #ifdef CONFIG_NF_CONNTRACK_MARK
261         case NFT_CT_MARK:
262 #endif
263 #ifdef CONFIG_NF_CONNTRACK_SECMARK
264         case NFT_CT_SECMARK:
265 #endif
266         case NFT_CT_EXPIRATION:
267                 if (tb[NFTA_CT_DIRECTION] != NULL)
268                         return -EINVAL;
269                 len = sizeof(u32);
270                 break;
271 #ifdef CONFIG_NF_CONNTRACK_LABELS
272         case NFT_CT_LABELS:
273                 if (tb[NFTA_CT_DIRECTION] != NULL)
274                         return -EINVAL;
275                 len = NF_CT_LABELS_MAX_SIZE;
276                 break;
277 #endif
278         case NFT_CT_HELPER:
279                 if (tb[NFTA_CT_DIRECTION] != NULL)
280                         return -EINVAL;
281                 len = NF_CT_HELPER_NAME_LEN;
282                 break;
283
284         case NFT_CT_L3PROTOCOL:
285         case NFT_CT_PROTOCOL:
286                 /* For compatibility, do not report error if NFTA_CT_DIRECTION
287                  * attribute is specified.
288                  */
289                 len = sizeof(u8);
290                 break;
291         case NFT_CT_SRC:
292         case NFT_CT_DST:
293                 if (tb[NFTA_CT_DIRECTION] == NULL)
294                         return -EINVAL;
295
296                 switch (ctx->afi->family) {
297                 case NFPROTO_IPV4:
298                         len = FIELD_SIZEOF(struct nf_conntrack_tuple,
299                                            src.u3.ip);
300                         break;
301                 case NFPROTO_IPV6:
302                 case NFPROTO_INET:
303                         len = FIELD_SIZEOF(struct nf_conntrack_tuple,
304                                            src.u3.ip6);
305                         break;
306                 default:
307                         return -EAFNOSUPPORT;
308                 }
309                 break;
310         case NFT_CT_PROTO_SRC:
311         case NFT_CT_PROTO_DST:
312                 if (tb[NFTA_CT_DIRECTION] == NULL)
313                         return -EINVAL;
314                 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
315                 break;
316         case NFT_CT_BYTES:
317         case NFT_CT_PKTS:
318                 /* no direction? return sum of original + reply */
319                 if (tb[NFTA_CT_DIRECTION] == NULL)
320                         priv->dir = IP_CT_DIR_MAX;
321                 len = sizeof(u64);
322                 break;
323         default:
324                 return -EOPNOTSUPP;
325         }
326
327         if (tb[NFTA_CT_DIRECTION] != NULL) {
328                 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
329                 switch (priv->dir) {
330                 case IP_CT_DIR_ORIGINAL:
331                 case IP_CT_DIR_REPLY:
332                         break;
333                 default:
334                         return -EINVAL;
335                 }
336         }
337
338         priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
339         err = nft_validate_register_store(ctx, priv->dreg, NULL,
340                                           NFT_DATA_VALUE, len);
341         if (err < 0)
342                 return err;
343
344         err = nft_ct_l3proto_try_module_get(ctx->afi->family);
345         if (err < 0)
346                 return err;
347
348         if (priv->key == NFT_CT_BYTES || priv->key == NFT_CT_PKTS)
349                 nf_ct_set_acct(ctx->net, true);
350
351         return 0;
352 }
353
354 static int nft_ct_set_init(const struct nft_ctx *ctx,
355                            const struct nft_expr *expr,
356                            const struct nlattr * const tb[])
357 {
358         struct nft_ct *priv = nft_expr_priv(expr);
359         bool label_got = false;
360         unsigned int len;
361         int err;
362
363         priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
364         switch (priv->key) {
365 #ifdef CONFIG_NF_CONNTRACK_MARK
366         case NFT_CT_MARK:
367                 if (tb[NFTA_CT_DIRECTION])
368                         return -EINVAL;
369                 len = FIELD_SIZEOF(struct nf_conn, mark);
370                 break;
371 #endif
372 #ifdef CONFIG_NF_CONNTRACK_LABELS
373         case NFT_CT_LABELS:
374                 if (tb[NFTA_CT_DIRECTION])
375                         return -EINVAL;
376                 len = NF_CT_LABELS_MAX_SIZE;
377                 err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
378                 if (err)
379                         return err;
380                 label_got = true;
381                 break;
382 #endif
383         default:
384                 return -EOPNOTSUPP;
385         }
386
387         priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
388         err = nft_validate_register_load(priv->sreg, len);
389         if (err < 0)
390                 goto err1;
391
392         err = nft_ct_l3proto_try_module_get(ctx->afi->family);
393         if (err < 0)
394                 goto err1;
395
396         return 0;
397
398 err1:
399         if (label_got)
400                 nf_connlabels_put(ctx->net);
401         return err;
402 }
403
404 static void nft_ct_get_destroy(const struct nft_ctx *ctx,
405                                const struct nft_expr *expr)
406 {
407         nft_ct_l3proto_module_put(ctx->afi->family);
408 }
409
410 static void nft_ct_set_destroy(const struct nft_ctx *ctx,
411                                const struct nft_expr *expr)
412 {
413         struct nft_ct *priv = nft_expr_priv(expr);
414
415         switch (priv->key) {
416 #ifdef CONFIG_NF_CONNTRACK_LABELS
417         case NFT_CT_LABELS:
418                 nf_connlabels_put(ctx->net);
419                 break;
420 #endif
421         default:
422                 break;
423         }
424
425         nft_ct_l3proto_module_put(ctx->afi->family);
426 }
427
428 static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
429 {
430         const struct nft_ct *priv = nft_expr_priv(expr);
431
432         if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
433                 goto nla_put_failure;
434         if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
435                 goto nla_put_failure;
436
437         switch (priv->key) {
438         case NFT_CT_SRC:
439         case NFT_CT_DST:
440         case NFT_CT_PROTO_SRC:
441         case NFT_CT_PROTO_DST:
442                 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
443                         goto nla_put_failure;
444                 break;
445         case NFT_CT_BYTES:
446         case NFT_CT_PKTS:
447                 if (priv->dir < IP_CT_DIR_MAX &&
448                     nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
449                         goto nla_put_failure;
450                 break;
451         default:
452                 break;
453         }
454
455         return 0;
456
457 nla_put_failure:
458         return -1;
459 }
460
461 static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
462 {
463         const struct nft_ct *priv = nft_expr_priv(expr);
464
465         if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
466                 goto nla_put_failure;
467         if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
468                 goto nla_put_failure;
469         return 0;
470
471 nla_put_failure:
472         return -1;
473 }
474
475 static struct nft_expr_type nft_ct_type;
476 static const struct nft_expr_ops nft_ct_get_ops = {
477         .type           = &nft_ct_type,
478         .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
479         .eval           = nft_ct_get_eval,
480         .init           = nft_ct_get_init,
481         .destroy        = nft_ct_get_destroy,
482         .dump           = nft_ct_get_dump,
483 };
484
485 static const struct nft_expr_ops nft_ct_set_ops = {
486         .type           = &nft_ct_type,
487         .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
488         .eval           = nft_ct_set_eval,
489         .init           = nft_ct_set_init,
490         .destroy        = nft_ct_set_destroy,
491         .dump           = nft_ct_set_dump,
492 };
493
494 static const struct nft_expr_ops *
495 nft_ct_select_ops(const struct nft_ctx *ctx,
496                     const struct nlattr * const tb[])
497 {
498         if (tb[NFTA_CT_KEY] == NULL)
499                 return ERR_PTR(-EINVAL);
500
501         if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
502                 return ERR_PTR(-EINVAL);
503
504         if (tb[NFTA_CT_DREG])
505                 return &nft_ct_get_ops;
506
507         if (tb[NFTA_CT_SREG])
508                 return &nft_ct_set_ops;
509
510         return ERR_PTR(-EINVAL);
511 }
512
513 static struct nft_expr_type nft_ct_type __read_mostly = {
514         .name           = "ct",
515         .select_ops     = &nft_ct_select_ops,
516         .policy         = nft_ct_policy,
517         .maxattr        = NFTA_CT_MAX,
518         .owner          = THIS_MODULE,
519 };
520
521 static int __init nft_ct_module_init(void)
522 {
523         BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > NFT_REG_SIZE);
524
525         return nft_register_expr(&nft_ct_type);
526 }
527
528 static void __exit nft_ct_module_exit(void)
529 {
530         nft_unregister_expr(&nft_ct_type);
531 }
532
533 module_init(nft_ct_module_init);
534 module_exit(nft_ct_module_exit);
535
536 MODULE_LICENSE("GPL");
537 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
538 MODULE_ALIAS_NFT_EXPR("ct");