Merge tag 'regmap-fix-v4.8-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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         default:
132                 break;
133         }
134
135         tuple = &ct->tuplehash[priv->dir].tuple;
136         switch (priv->key) {
137         case NFT_CT_L3PROTOCOL:
138                 *dest = nf_ct_l3num(ct);
139                 return;
140         case NFT_CT_SRC:
141                 memcpy(dest, tuple->src.u3.all,
142                        nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
143                 return;
144         case NFT_CT_DST:
145                 memcpy(dest, tuple->dst.u3.all,
146                        nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
147                 return;
148         case NFT_CT_PROTOCOL:
149                 *dest = nf_ct_protonum(ct);
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                 if (tb[NFTA_CT_DIRECTION] == NULL)
287                         return -EINVAL;
288                 len = sizeof(u8);
289                 break;
290         case NFT_CT_SRC:
291         case NFT_CT_DST:
292                 if (tb[NFTA_CT_DIRECTION] == NULL)
293                         return -EINVAL;
294
295                 switch (ctx->afi->family) {
296                 case NFPROTO_IPV4:
297                         len = FIELD_SIZEOF(struct nf_conntrack_tuple,
298                                            src.u3.ip);
299                         break;
300                 case NFPROTO_IPV6:
301                 case NFPROTO_INET:
302                         len = FIELD_SIZEOF(struct nf_conntrack_tuple,
303                                            src.u3.ip6);
304                         break;
305                 default:
306                         return -EAFNOSUPPORT;
307                 }
308                 break;
309         case NFT_CT_PROTO_SRC:
310         case NFT_CT_PROTO_DST:
311                 if (tb[NFTA_CT_DIRECTION] == NULL)
312                         return -EINVAL;
313                 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
314                 break;
315         case NFT_CT_BYTES:
316         case NFT_CT_PKTS:
317                 /* no direction? return sum of original + reply */
318                 if (tb[NFTA_CT_DIRECTION] == NULL)
319                         priv->dir = IP_CT_DIR_MAX;
320                 len = sizeof(u64);
321                 break;
322         default:
323                 return -EOPNOTSUPP;
324         }
325
326         if (tb[NFTA_CT_DIRECTION] != NULL) {
327                 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
328                 switch (priv->dir) {
329                 case IP_CT_DIR_ORIGINAL:
330                 case IP_CT_DIR_REPLY:
331                         break;
332                 default:
333                         return -EINVAL;
334                 }
335         }
336
337         priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
338         err = nft_validate_register_store(ctx, priv->dreg, NULL,
339                                           NFT_DATA_VALUE, len);
340         if (err < 0)
341                 return err;
342
343         err = nft_ct_l3proto_try_module_get(ctx->afi->family);
344         if (err < 0)
345                 return err;
346
347         if (priv->key == NFT_CT_BYTES || priv->key == NFT_CT_PKTS)
348                 nf_ct_set_acct(ctx->net, true);
349
350         return 0;
351 }
352
353 static int nft_ct_set_init(const struct nft_ctx *ctx,
354                            const struct nft_expr *expr,
355                            const struct nlattr * const tb[])
356 {
357         struct nft_ct *priv = nft_expr_priv(expr);
358         bool label_got = false;
359         unsigned int len;
360         int err;
361
362         priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
363         switch (priv->key) {
364 #ifdef CONFIG_NF_CONNTRACK_MARK
365         case NFT_CT_MARK:
366                 len = FIELD_SIZEOF(struct nf_conn, mark);
367                 break;
368 #endif
369 #ifdef CONFIG_NF_CONNTRACK_LABELS
370         case NFT_CT_LABELS:
371                 if (tb[NFTA_CT_DIRECTION])
372                         return -EINVAL;
373                 len = NF_CT_LABELS_MAX_SIZE;
374                 err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
375                 if (err)
376                         return err;
377                 label_got = true;
378                 break;
379 #endif
380         default:
381                 return -EOPNOTSUPP;
382         }
383
384         priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
385         err = nft_validate_register_load(priv->sreg, len);
386         if (err < 0)
387                 goto err1;
388
389         err = nft_ct_l3proto_try_module_get(ctx->afi->family);
390         if (err < 0)
391                 goto err1;
392
393         return 0;
394
395 err1:
396         if (label_got)
397                 nf_connlabels_put(ctx->net);
398         return err;
399 }
400
401 static void nft_ct_get_destroy(const struct nft_ctx *ctx,
402                                const struct nft_expr *expr)
403 {
404         nft_ct_l3proto_module_put(ctx->afi->family);
405 }
406
407 static void nft_ct_set_destroy(const struct nft_ctx *ctx,
408                                const struct nft_expr *expr)
409 {
410         struct nft_ct *priv = nft_expr_priv(expr);
411
412         switch (priv->key) {
413 #ifdef CONFIG_NF_CONNTRACK_LABELS
414         case NFT_CT_LABELS:
415                 nf_connlabels_put(ctx->net);
416                 break;
417 #endif
418         default:
419                 break;
420         }
421
422         nft_ct_l3proto_module_put(ctx->afi->family);
423 }
424
425 static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
426 {
427         const struct nft_ct *priv = nft_expr_priv(expr);
428
429         if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
430                 goto nla_put_failure;
431         if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
432                 goto nla_put_failure;
433
434         switch (priv->key) {
435         case NFT_CT_L3PROTOCOL:
436         case NFT_CT_PROTOCOL:
437         case NFT_CT_SRC:
438         case NFT_CT_DST:
439         case NFT_CT_PROTO_SRC:
440         case NFT_CT_PROTO_DST:
441                 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
442                         goto nla_put_failure;
443                 break;
444         case NFT_CT_BYTES:
445         case NFT_CT_PKTS:
446                 if (priv->dir < IP_CT_DIR_MAX &&
447                     nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
448                         goto nla_put_failure;
449                 break;
450         default:
451                 break;
452         }
453
454         return 0;
455
456 nla_put_failure:
457         return -1;
458 }
459
460 static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
461 {
462         const struct nft_ct *priv = nft_expr_priv(expr);
463
464         if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
465                 goto nla_put_failure;
466         if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
467                 goto nla_put_failure;
468         return 0;
469
470 nla_put_failure:
471         return -1;
472 }
473
474 static struct nft_expr_type nft_ct_type;
475 static const struct nft_expr_ops nft_ct_get_ops = {
476         .type           = &nft_ct_type,
477         .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
478         .eval           = nft_ct_get_eval,
479         .init           = nft_ct_get_init,
480         .destroy        = nft_ct_get_destroy,
481         .dump           = nft_ct_get_dump,
482 };
483
484 static const struct nft_expr_ops nft_ct_set_ops = {
485         .type           = &nft_ct_type,
486         .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
487         .eval           = nft_ct_set_eval,
488         .init           = nft_ct_set_init,
489         .destroy        = nft_ct_set_destroy,
490         .dump           = nft_ct_set_dump,
491 };
492
493 static const struct nft_expr_ops *
494 nft_ct_select_ops(const struct nft_ctx *ctx,
495                     const struct nlattr * const tb[])
496 {
497         if (tb[NFTA_CT_KEY] == NULL)
498                 return ERR_PTR(-EINVAL);
499
500         if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
501                 return ERR_PTR(-EINVAL);
502
503         if (tb[NFTA_CT_DREG])
504                 return &nft_ct_get_ops;
505
506         if (tb[NFTA_CT_SREG])
507                 return &nft_ct_set_ops;
508
509         return ERR_PTR(-EINVAL);
510 }
511
512 static struct nft_expr_type nft_ct_type __read_mostly = {
513         .name           = "ct",
514         .select_ops     = &nft_ct_select_ops,
515         .policy         = nft_ct_policy,
516         .maxattr        = NFTA_CT_MAX,
517         .owner          = THIS_MODULE,
518 };
519
520 static int __init nft_ct_module_init(void)
521 {
522         BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > NFT_REG_SIZE);
523
524         return nft_register_expr(&nft_ct_type);
525 }
526
527 static void __exit nft_ct_module_exit(void)
528 {
529         nft_unregister_expr(&nft_ct_type);
530 }
531
532 module_init(nft_ct_module_init);
533 module_exit(nft_ct_module_exit);
534
535 MODULE_LICENSE("GPL");
536 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
537 MODULE_ALIAS_NFT_EXPR("ct");