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