]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/netfilter/nft_ct.c
netfilter: nft_set_bitmap: fetch the element key based on the set->klen
[mirror_ubuntu-bionic-kernel.git] / net / netfilter / nft_ct.c
CommitLineData
96518518 1/*
ef1f7df9 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
25443261 3 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
96518518
PM
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>
48f66c90 20#include <net/netfilter/nf_conntrack_acct.h>
96518518
PM
21#include <net/netfilter/nf_conntrack_tuple.h>
22#include <net/netfilter/nf_conntrack_helper.h>
c4ede3d3 23#include <net/netfilter/nf_conntrack_ecache.h>
d2bf2f34 24#include <net/netfilter/nf_conntrack_labels.h>
96518518
PM
25
26struct nft_ct {
27 enum nft_ct_keys key:8;
28 enum ip_conntrack_dir dir:8;
d46f2cd2 29 union {
c4ede3d3
KE
30 enum nft_registers dreg:8;
31 enum nft_registers sreg:8;
32 };
96518518
PM
33};
34
edee4f1e
FW
35#ifdef CONFIG_NF_CONNTRACK_ZONES
36static DEFINE_PER_CPU(struct nf_conn *, nft_ct_pcpu_template);
37static unsigned int nft_ct_pcpu_template_refcnt __read_mostly;
38#endif
39
48f66c90
FW
40static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
41 enum nft_ct_keys k,
42 enum ip_conntrack_dir d)
43{
44 if (d < IP_CT_DIR_MAX)
45 return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
46 atomic64_read(&c[d].packets);
47
48 return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
49 nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
50}
51
c4ede3d3 52static void nft_ct_get_eval(const struct nft_expr *expr,
a55e22e9 53 struct nft_regs *regs,
c4ede3d3 54 const struct nft_pktinfo *pkt)
96518518
PM
55{
56 const struct nft_ct *priv = nft_expr_priv(expr);
49499c3e 57 u32 *dest = &regs->data[priv->dreg];
96518518
PM
58 enum ip_conntrack_info ctinfo;
59 const struct nf_conn *ct;
60 const struct nf_conn_help *help;
61 const struct nf_conntrack_tuple *tuple;
62 const struct nf_conntrack_helper *helper;
96518518
PM
63 unsigned int state;
64
65 ct = nf_ct_get(pkt->skb, &ctinfo);
66
67 switch (priv->key) {
68 case NFT_CT_STATE:
69 if (ct == NULL)
70 state = NF_CT_STATE_INVALID_BIT;
71 else if (nf_ct_is_untracked(ct))
72 state = NF_CT_STATE_UNTRACKED_BIT;
73 else
74 state = NF_CT_STATE_BIT(ctinfo);
fad136ea 75 *dest = state;
96518518 76 return;
c1f86676
DM
77 default:
78 break;
96518518
PM
79 }
80
81 if (ct == NULL)
82 goto err;
83
84 switch (priv->key) {
85 case NFT_CT_DIRECTION:
fad136ea 86 *dest = CTINFO2DIR(ctinfo);
96518518
PM
87 return;
88 case NFT_CT_STATUS:
fad136ea 89 *dest = ct->status;
96518518
PM
90 return;
91#ifdef CONFIG_NF_CONNTRACK_MARK
92 case NFT_CT_MARK:
fad136ea 93 *dest = ct->mark;
96518518
PM
94 return;
95#endif
96#ifdef CONFIG_NF_CONNTRACK_SECMARK
97 case NFT_CT_SECMARK:
fad136ea 98 *dest = ct->secmark;
96518518
PM
99 return;
100#endif
101 case NFT_CT_EXPIRATION:
c8607e02 102 *dest = jiffies_to_msecs(nf_ct_expires(ct));
96518518
PM
103 return;
104 case NFT_CT_HELPER:
105 if (ct->master == NULL)
106 goto err;
107 help = nfct_help(ct->master);
108 if (help == NULL)
109 goto err;
110 helper = rcu_dereference(help->helper);
111 if (helper == NULL)
112 goto err;
fad136ea 113 strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
96518518 114 return;
d2bf2f34
FW
115#ifdef CONFIG_NF_CONNTRACK_LABELS
116 case NFT_CT_LABELS: {
117 struct nf_conn_labels *labels = nf_ct_labels_find(ct);
d2bf2f34 118
23014011
FW
119 if (labels)
120 memcpy(dest, labels->bits, NF_CT_LABELS_MAX_SIZE);
121 else
fad136ea 122 memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
d2bf2f34
FW
123 return;
124 }
efaea94a 125#endif
48f66c90
FW
126 case NFT_CT_BYTES: /* fallthrough */
127 case NFT_CT_PKTS: {
128 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
129 u64 count = 0;
130
131 if (acct)
132 count = nft_ct_get_eval_counter(acct->counter,
133 priv->key, priv->dir);
134 memcpy(dest, &count, sizeof(count));
135 return;
136 }
949a3584
LZ
137 case NFT_CT_AVGPKT: {
138 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
139 u64 avgcnt = 0, bcnt = 0, pcnt = 0;
140
141 if (acct) {
142 pcnt = nft_ct_get_eval_counter(acct->counter,
143 NFT_CT_PKTS, priv->dir);
144 bcnt = nft_ct_get_eval_counter(acct->counter,
145 NFT_CT_BYTES, priv->dir);
146 if (pcnt != 0)
147 avgcnt = div64_u64(bcnt, pcnt);
148 }
149
150 memcpy(dest, &avgcnt, sizeof(avgcnt));
151 return;
152 }
d767ff2c
LZ
153 case NFT_CT_L3PROTOCOL:
154 *dest = nf_ct_l3num(ct);
155 return;
156 case NFT_CT_PROTOCOL:
157 *dest = nf_ct_protonum(ct);
158 return;
ab23821f
FW
159#ifdef CONFIG_NF_CONNTRACK_ZONES
160 case NFT_CT_ZONE: {
161 const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
162
163 if (priv->dir < IP_CT_DIR_MAX)
164 *dest = nf_ct_zone_id(zone, priv->dir);
165 else
166 *dest = zone->id;
167
168 return;
169 }
170#endif
c1f86676
DM
171 default:
172 break;
96518518
PM
173 }
174
175 tuple = &ct->tuplehash[priv->dir].tuple;
176 switch (priv->key) {
96518518 177 case NFT_CT_SRC:
fad136ea 178 memcpy(dest, tuple->src.u3.all,
96518518
PM
179 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
180 return;
181 case NFT_CT_DST:
fad136ea 182 memcpy(dest, tuple->dst.u3.all,
96518518
PM
183 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
184 return;
96518518 185 case NFT_CT_PROTO_SRC:
fad136ea 186 *dest = (__force __u16)tuple->src.u.all;
96518518
PM
187 return;
188 case NFT_CT_PROTO_DST:
fad136ea 189 *dest = (__force __u16)tuple->dst.u.all;
96518518 190 return;
c1f86676
DM
191 default:
192 break;
96518518
PM
193 }
194 return;
195err:
a55e22e9 196 regs->verdict.code = NFT_BREAK;
96518518
PM
197}
198
edee4f1e
FW
199#ifdef CONFIG_NF_CONNTRACK_ZONES
200static void nft_ct_set_zone_eval(const struct nft_expr *expr,
201 struct nft_regs *regs,
202 const struct nft_pktinfo *pkt)
203{
204 struct nf_conntrack_zone zone = { .dir = NF_CT_DEFAULT_ZONE_DIR };
205 const struct nft_ct *priv = nft_expr_priv(expr);
206 struct sk_buff *skb = pkt->skb;
207 enum ip_conntrack_info ctinfo;
208 u16 value = regs->data[priv->sreg];
209 struct nf_conn *ct;
210
211 ct = nf_ct_get(skb, &ctinfo);
212 if (ct) /* already tracked */
213 return;
214
215 zone.id = value;
216
217 switch (priv->dir) {
218 case IP_CT_DIR_ORIGINAL:
219 zone.dir = NF_CT_ZONE_DIR_ORIG;
220 break;
221 case IP_CT_DIR_REPLY:
222 zone.dir = NF_CT_ZONE_DIR_REPL;
223 break;
224 default:
225 break;
226 }
227
228 ct = this_cpu_read(nft_ct_pcpu_template);
229
230 if (likely(atomic_read(&ct->ct_general.use) == 1)) {
231 nf_ct_zone_add(ct, &zone);
232 } else {
233 /* previous skb got queued to userspace */
234 ct = nf_ct_tmpl_alloc(nft_net(pkt), &zone, GFP_ATOMIC);
235 if (!ct) {
236 regs->verdict.code = NF_DROP;
237 return;
238 }
239 }
240
241 atomic_inc(&ct->ct_general.use);
242 nf_ct_set(skb, ct, IP_CT_NEW);
243}
244#endif
245
c4ede3d3 246static void nft_ct_set_eval(const struct nft_expr *expr,
a55e22e9 247 struct nft_regs *regs,
c4ede3d3
KE
248 const struct nft_pktinfo *pkt)
249{
250 const struct nft_ct *priv = nft_expr_priv(expr);
251 struct sk_buff *skb = pkt->skb;
847c8e29 252#ifdef CONFIG_NF_CONNTRACK_MARK
49499c3e 253 u32 value = regs->data[priv->sreg];
847c8e29 254#endif
c4ede3d3
KE
255 enum ip_conntrack_info ctinfo;
256 struct nf_conn *ct;
257
258 ct = nf_ct_get(skb, &ctinfo);
259 if (ct == NULL)
260 return;
261
262 switch (priv->key) {
263#ifdef CONFIG_NF_CONNTRACK_MARK
264 case NFT_CT_MARK:
265 if (ct->mark != value) {
266 ct->mark = value;
267 nf_conntrack_event_cache(IPCT_MARK, ct);
268 }
269 break;
1ad8f48d
FW
270#endif
271#ifdef CONFIG_NF_CONNTRACK_LABELS
272 case NFT_CT_LABELS:
273 nf_connlabels_replace(ct,
274 &regs->data[priv->sreg],
275 &regs->data[priv->sreg],
276 NF_CT_LABELS_MAX_SIZE / sizeof(u32));
277 break;
c4ede3d3 278#endif
c1f86676
DM
279 default:
280 break;
c4ede3d3
KE
281 }
282}
283
96518518
PM
284static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
285 [NFTA_CT_DREG] = { .type = NLA_U32 },
286 [NFTA_CT_KEY] = { .type = NLA_U32 },
287 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
c4ede3d3 288 [NFTA_CT_SREG] = { .type = NLA_U32 },
96518518
PM
289};
290
ecb2421b 291static int nft_ct_netns_get(struct net *net, uint8_t family)
9638f33e
PM
292{
293 int err;
294
295 if (family == NFPROTO_INET) {
ecb2421b 296 err = nf_ct_netns_get(net, NFPROTO_IPV4);
9638f33e
PM
297 if (err < 0)
298 goto err1;
ecb2421b 299 err = nf_ct_netns_get(net, NFPROTO_IPV6);
9638f33e
PM
300 if (err < 0)
301 goto err2;
302 } else {
ecb2421b 303 err = nf_ct_netns_get(net, family);
9638f33e
PM
304 if (err < 0)
305 goto err1;
306 }
307 return 0;
308
309err2:
ecb2421b 310 nf_ct_netns_put(net, NFPROTO_IPV4);
9638f33e
PM
311err1:
312 return err;
313}
314
ecb2421b 315static void nft_ct_netns_put(struct net *net, uint8_t family)
9638f33e
PM
316{
317 if (family == NFPROTO_INET) {
ecb2421b
FW
318 nf_ct_netns_put(net, NFPROTO_IPV4);
319 nf_ct_netns_put(net, NFPROTO_IPV6);
9638f33e 320 } else
ecb2421b 321 nf_ct_netns_put(net, family);
9638f33e
PM
322}
323
edee4f1e
FW
324#ifdef CONFIG_NF_CONNTRACK_ZONES
325static void nft_ct_tmpl_put_pcpu(void)
326{
327 struct nf_conn *ct;
328 int cpu;
329
330 for_each_possible_cpu(cpu) {
331 ct = per_cpu(nft_ct_pcpu_template, cpu);
332 if (!ct)
333 break;
334 nf_ct_put(ct);
335 per_cpu(nft_ct_pcpu_template, cpu) = NULL;
336 }
337}
338
339static bool nft_ct_tmpl_alloc_pcpu(void)
340{
341 struct nf_conntrack_zone zone = { .id = 0 };
342 struct nf_conn *tmp;
343 int cpu;
344
345 if (nft_ct_pcpu_template_refcnt)
346 return true;
347
348 for_each_possible_cpu(cpu) {
349 tmp = nf_ct_tmpl_alloc(&init_net, &zone, GFP_KERNEL);
350 if (!tmp) {
351 nft_ct_tmpl_put_pcpu();
352 return false;
353 }
354
355 atomic_set(&tmp->ct_general.use, 1);
356 per_cpu(nft_ct_pcpu_template, cpu) = tmp;
357 }
358
359 return true;
360}
361#endif
362
fe92ca45
PM
363static int nft_ct_get_init(const struct nft_ctx *ctx,
364 const struct nft_expr *expr,
365 const struct nlattr * const tb[])
96518518
PM
366{
367 struct nft_ct *priv = nft_expr_priv(expr);
45d9bcda 368 unsigned int len;
fe92ca45 369 int err;
96518518 370
fe92ca45 371 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
ab23821f 372 priv->dir = IP_CT_DIR_MAX;
96518518 373 switch (priv->key) {
96518518 374 case NFT_CT_DIRECTION:
45d9bcda
PM
375 if (tb[NFTA_CT_DIRECTION] != NULL)
376 return -EINVAL;
377 len = sizeof(u8);
378 break;
379 case NFT_CT_STATE:
96518518
PM
380 case NFT_CT_STATUS:
381#ifdef CONFIG_NF_CONNTRACK_MARK
382 case NFT_CT_MARK:
383#endif
384#ifdef CONFIG_NF_CONNTRACK_SECMARK
385 case NFT_CT_SECMARK:
d2bf2f34 386#endif
45d9bcda
PM
387 case NFT_CT_EXPIRATION:
388 if (tb[NFTA_CT_DIRECTION] != NULL)
389 return -EINVAL;
390 len = sizeof(u32);
391 break;
d2bf2f34
FW
392#ifdef CONFIG_NF_CONNTRACK_LABELS
393 case NFT_CT_LABELS:
45d9bcda
PM
394 if (tb[NFTA_CT_DIRECTION] != NULL)
395 return -EINVAL;
396 len = NF_CT_LABELS_MAX_SIZE;
397 break;
96518518 398#endif
96518518
PM
399 case NFT_CT_HELPER:
400 if (tb[NFTA_CT_DIRECTION] != NULL)
401 return -EINVAL;
45d9bcda 402 len = NF_CT_HELPER_NAME_LEN;
96518518 403 break;
45d9bcda 404
51292c07 405 case NFT_CT_L3PROTOCOL:
96518518 406 case NFT_CT_PROTOCOL:
d767ff2c
LZ
407 /* For compatibility, do not report error if NFTA_CT_DIRECTION
408 * attribute is specified.
409 */
45d9bcda
PM
410 len = sizeof(u8);
411 break;
96518518
PM
412 case NFT_CT_SRC:
413 case NFT_CT_DST:
45d9bcda
PM
414 if (tb[NFTA_CT_DIRECTION] == NULL)
415 return -EINVAL;
416
417 switch (ctx->afi->family) {
418 case NFPROTO_IPV4:
419 len = FIELD_SIZEOF(struct nf_conntrack_tuple,
420 src.u3.ip);
421 break;
422 case NFPROTO_IPV6:
423 case NFPROTO_INET:
424 len = FIELD_SIZEOF(struct nf_conntrack_tuple,
425 src.u3.ip6);
426 break;
427 default:
428 return -EAFNOSUPPORT;
429 }
430 break;
96518518
PM
431 case NFT_CT_PROTO_SRC:
432 case NFT_CT_PROTO_DST:
433 if (tb[NFTA_CT_DIRECTION] == NULL)
434 return -EINVAL;
45d9bcda 435 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
96518518 436 break;
48f66c90
FW
437 case NFT_CT_BYTES:
438 case NFT_CT_PKTS:
949a3584 439 case NFT_CT_AVGPKT:
48f66c90
FW
440 len = sizeof(u64);
441 break;
ab23821f
FW
442#ifdef CONFIG_NF_CONNTRACK_ZONES
443 case NFT_CT_ZONE:
444 len = sizeof(u16);
445 break;
446#endif
96518518
PM
447 default:
448 return -EOPNOTSUPP;
449 }
450
fe92ca45
PM
451 if (tb[NFTA_CT_DIRECTION] != NULL) {
452 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
453 switch (priv->dir) {
454 case IP_CT_DIR_ORIGINAL:
455 case IP_CT_DIR_REPLY:
456 break;
457 default:
458 return -EINVAL;
459 }
460 }
461
b1c96ed3 462 priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
1ec10212
PM
463 err = nft_validate_register_store(ctx, priv->dreg, NULL,
464 NFT_DATA_VALUE, len);
fe92ca45
PM
465 if (err < 0)
466 return err;
467
ecb2421b 468 err = nft_ct_netns_get(ctx->net, ctx->afi->family);
fe92ca45
PM
469 if (err < 0)
470 return err;
471
949a3584
LZ
472 if (priv->key == NFT_CT_BYTES ||
473 priv->key == NFT_CT_PKTS ||
474 priv->key == NFT_CT_AVGPKT)
3f8b61b7
LZ
475 nf_ct_set_acct(ctx->net, true);
476
c4ede3d3
KE
477 return 0;
478}
479
5c178d81
FW
480static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
481{
482 switch (priv->key) {
483#ifdef CONFIG_NF_CONNTRACK_LABELS
484 case NFT_CT_LABELS:
485 nf_connlabels_put(ctx->net);
486 break;
edee4f1e
FW
487#endif
488#ifdef CONFIG_NF_CONNTRACK_ZONES
489 case NFT_CT_ZONE:
490 if (--nft_ct_pcpu_template_refcnt == 0)
491 nft_ct_tmpl_put_pcpu();
5c178d81
FW
492#endif
493 default:
494 break;
495 }
496}
497
fe92ca45
PM
498static int nft_ct_set_init(const struct nft_ctx *ctx,
499 const struct nft_expr *expr,
500 const struct nlattr * const tb[])
c4ede3d3 501{
fe92ca45 502 struct nft_ct *priv = nft_expr_priv(expr);
d07db988 503 unsigned int len;
fe92ca45
PM
504 int err;
505
edee4f1e 506 priv->dir = IP_CT_DIR_MAX;
fe92ca45
PM
507 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
508 switch (priv->key) {
e88e514e 509#ifdef CONFIG_NF_CONNTRACK_MARK
c4ede3d3 510 case NFT_CT_MARK:
7bfdde70
LZ
511 if (tb[NFTA_CT_DIRECTION])
512 return -EINVAL;
d07db988 513 len = FIELD_SIZEOF(struct nf_conn, mark);
c4ede3d3 514 break;
1ad8f48d
FW
515#endif
516#ifdef CONFIG_NF_CONNTRACK_LABELS
517 case NFT_CT_LABELS:
518 if (tb[NFTA_CT_DIRECTION])
519 return -EINVAL;
520 len = NF_CT_LABELS_MAX_SIZE;
521 err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
522 if (err)
523 return err;
524 break;
edee4f1e
FW
525#endif
526#ifdef CONFIG_NF_CONNTRACK_ZONES
527 case NFT_CT_ZONE:
528 if (!nft_ct_tmpl_alloc_pcpu())
529 return -ENOMEM;
530 nft_ct_pcpu_template_refcnt++;
427345d6 531 len = sizeof(u16);
edee4f1e 532 break;
e88e514e 533#endif
c4ede3d3
KE
534 default:
535 return -EOPNOTSUPP;
536 }
537
edee4f1e
FW
538 if (tb[NFTA_CT_DIRECTION]) {
539 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
540 switch (priv->dir) {
541 case IP_CT_DIR_ORIGINAL:
542 case IP_CT_DIR_REPLY:
543 break;
544 default:
545 return -EINVAL;
546 }
547 }
548
b1c96ed3 549 priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
d07db988 550 err = nft_validate_register_load(priv->sreg, len);
fe92ca45 551 if (err < 0)
590025a2 552 goto err1;
c4ede3d3 553
ecb2421b 554 err = nft_ct_netns_get(ctx->net, ctx->afi->family);
96518518 555 if (err < 0)
590025a2 556 goto err1;
96518518 557
96518518 558 return 0;
590025a2
LZ
559
560err1:
5c178d81 561 __nft_ct_set_destroy(ctx, priv);
590025a2
LZ
562 return err;
563}
564
565static void nft_ct_get_destroy(const struct nft_ctx *ctx,
566 const struct nft_expr *expr)
567{
ecb2421b 568 nf_ct_netns_put(ctx->net, ctx->afi->family);
96518518
PM
569}
570
590025a2
LZ
571static void nft_ct_set_destroy(const struct nft_ctx *ctx,
572 const struct nft_expr *expr)
96518518 573{
1ad8f48d
FW
574 struct nft_ct *priv = nft_expr_priv(expr);
575
5c178d81 576 __nft_ct_set_destroy(ctx, priv);
ecb2421b 577 nft_ct_netns_put(ctx->net, ctx->afi->family);
96518518
PM
578}
579
c4ede3d3 580static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
96518518
PM
581{
582 const struct nft_ct *priv = nft_expr_priv(expr);
583
b1c96ed3 584 if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
96518518
PM
585 goto nla_put_failure;
586 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
587 goto nla_put_failure;
2a53bfb3
AB
588
589 switch (priv->key) {
2a53bfb3
AB
590 case NFT_CT_SRC:
591 case NFT_CT_DST:
592 case NFT_CT_PROTO_SRC:
593 case NFT_CT_PROTO_DST:
594 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
595 goto nla_put_failure;
48f66c90
FW
596 break;
597 case NFT_CT_BYTES:
598 case NFT_CT_PKTS:
949a3584 599 case NFT_CT_AVGPKT:
ab23821f 600 case NFT_CT_ZONE:
48f66c90
FW
601 if (priv->dir < IP_CT_DIR_MAX &&
602 nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
603 goto nla_put_failure;
604 break;
2a53bfb3
AB
605 default:
606 break;
607 }
608
96518518
PM
609 return 0;
610
611nla_put_failure:
612 return -1;
613}
614
c4ede3d3
KE
615static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
616{
617 const struct nft_ct *priv = nft_expr_priv(expr);
618
b1c96ed3 619 if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
c4ede3d3
KE
620 goto nla_put_failure;
621 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
622 goto nla_put_failure;
edee4f1e
FW
623
624 switch (priv->key) {
625 case NFT_CT_ZONE:
626 if (priv->dir < IP_CT_DIR_MAX &&
627 nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
628 goto nla_put_failure;
629 break;
630 default:
631 break;
632 }
633
c4ede3d3
KE
634 return 0;
635
636nla_put_failure:
637 return -1;
638}
639
ef1f7df9 640static struct nft_expr_type nft_ct_type;
c4ede3d3 641static const struct nft_expr_ops nft_ct_get_ops = {
ef1f7df9 642 .type = &nft_ct_type,
96518518 643 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
c4ede3d3 644 .eval = nft_ct_get_eval,
fe92ca45 645 .init = nft_ct_get_init,
590025a2 646 .destroy = nft_ct_get_destroy,
c4ede3d3 647 .dump = nft_ct_get_dump,
ef1f7df9
PM
648};
649
c4ede3d3
KE
650static const struct nft_expr_ops nft_ct_set_ops = {
651 .type = &nft_ct_type,
652 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
653 .eval = nft_ct_set_eval,
fe92ca45 654 .init = nft_ct_set_init,
590025a2 655 .destroy = nft_ct_set_destroy,
c4ede3d3
KE
656 .dump = nft_ct_set_dump,
657};
658
edee4f1e
FW
659#ifdef CONFIG_NF_CONNTRACK_ZONES
660static const struct nft_expr_ops nft_ct_set_zone_ops = {
661 .type = &nft_ct_type,
662 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
663 .eval = nft_ct_set_zone_eval,
664 .init = nft_ct_set_init,
665 .destroy = nft_ct_set_destroy,
666 .dump = nft_ct_set_dump,
667};
668#endif
669
c4ede3d3
KE
670static const struct nft_expr_ops *
671nft_ct_select_ops(const struct nft_ctx *ctx,
672 const struct nlattr * const tb[])
673{
674 if (tb[NFTA_CT_KEY] == NULL)
675 return ERR_PTR(-EINVAL);
676
677 if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
678 return ERR_PTR(-EINVAL);
679
680 if (tb[NFTA_CT_DREG])
681 return &nft_ct_get_ops;
682
edee4f1e
FW
683 if (tb[NFTA_CT_SREG]) {
684#ifdef CONFIG_NF_CONNTRACK_ZONES
685 if (nla_get_be32(tb[NFTA_CT_KEY]) == htonl(NFT_CT_ZONE))
686 return &nft_ct_set_zone_ops;
687#endif
c4ede3d3 688 return &nft_ct_set_ops;
edee4f1e 689 }
c4ede3d3
KE
690
691 return ERR_PTR(-EINVAL);
692}
693
ef1f7df9
PM
694static struct nft_expr_type nft_ct_type __read_mostly = {
695 .name = "ct",
c4ede3d3 696 .select_ops = &nft_ct_select_ops,
96518518
PM
697 .policy = nft_ct_policy,
698 .maxattr = NFTA_CT_MAX,
ef1f7df9 699 .owner = THIS_MODULE,
96518518
PM
700};
701
25443261
PNA
702static void nft_notrack_eval(const struct nft_expr *expr,
703 struct nft_regs *regs,
704 const struct nft_pktinfo *pkt)
705{
706 struct sk_buff *skb = pkt->skb;
707 enum ip_conntrack_info ctinfo;
708 struct nf_conn *ct;
709
710 ct = nf_ct_get(pkt->skb, &ctinfo);
711 /* Previously seen (loopback or untracked)? Ignore. */
712 if (ct)
713 return;
714
715 ct = nf_ct_untracked_get();
716 atomic_inc(&ct->ct_general.use);
c74454fa 717 nf_ct_set(skb, ct, IP_CT_NEW);
25443261
PNA
718}
719
720static struct nft_expr_type nft_notrack_type;
721static const struct nft_expr_ops nft_notrack_ops = {
722 .type = &nft_notrack_type,
723 .size = NFT_EXPR_SIZE(0),
724 .eval = nft_notrack_eval,
725};
726
727static struct nft_expr_type nft_notrack_type __read_mostly = {
728 .name = "notrack",
729 .ops = &nft_notrack_ops,
730 .owner = THIS_MODULE,
731};
732
96518518
PM
733static int __init nft_ct_module_init(void)
734{
25443261
PNA
735 int err;
736
adff6c65
FW
737 BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > NFT_REG_SIZE);
738
25443261
PNA
739 err = nft_register_expr(&nft_ct_type);
740 if (err < 0)
741 return err;
742
743 err = nft_register_expr(&nft_notrack_type);
744 if (err < 0)
745 goto err1;
746
747 return 0;
748err1:
749 nft_unregister_expr(&nft_ct_type);
750 return err;
96518518
PM
751}
752
753static void __exit nft_ct_module_exit(void)
754{
25443261 755 nft_unregister_expr(&nft_notrack_type);
ef1f7df9 756 nft_unregister_expr(&nft_ct_type);
96518518
PM
757}
758
759module_init(nft_ct_module_init);
760module_exit(nft_ct_module_exit);
761
762MODULE_LICENSE("GPL");
763MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
764MODULE_ALIAS_NFT_EXPR("ct");
25443261 765MODULE_ALIAS_NFT_EXPR("notrack");