2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
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.
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
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>
26 enum nft_ct_keys key
:8;
27 enum ip_conntrack_dir dir
:8;
29 enum nft_registers dreg
:8;
30 enum nft_registers sreg
:8;
34 static u64
nft_ct_get_eval_counter(const struct nf_conn_counter
*c
,
36 enum ip_conntrack_dir d
)
38 if (d
< IP_CT_DIR_MAX
)
39 return k
== NFT_CT_BYTES
? atomic64_read(&c
[d
].bytes
) :
40 atomic64_read(&c
[d
].packets
);
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
);
46 static void nft_ct_get_eval(const struct nft_expr
*expr
,
47 struct nft_regs
*regs
,
48 const struct nft_pktinfo
*pkt
)
50 const struct nft_ct
*priv
= nft_expr_priv(expr
);
51 u32
*dest
= ®s
->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
;
59 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
64 state
= NF_CT_STATE_INVALID_BIT
;
65 else if (nf_ct_is_untracked(ct
))
66 state
= NF_CT_STATE_UNTRACKED_BIT
;
68 state
= NF_CT_STATE_BIT(ctinfo
);
79 case NFT_CT_DIRECTION
:
80 *dest
= CTINFO2DIR(ctinfo
);
85 #ifdef CONFIG_NF_CONNTRACK_MARK
90 #ifdef CONFIG_NF_CONNTRACK_SECMARK
95 case NFT_CT_EXPIRATION
:
96 *dest
= jiffies_to_msecs(nf_ct_expires(ct
));
99 if (ct
->master
== NULL
)
101 help
= nfct_help(ct
->master
);
104 helper
= rcu_dereference(help
->helper
);
107 strncpy((char *)dest
, helper
->name
, NF_CT_HELPER_NAME_LEN
);
109 #ifdef CONFIG_NF_CONNTRACK_LABELS
110 case NFT_CT_LABELS
: {
111 struct nf_conn_labels
*labels
= nf_ct_labels_find(ct
);
114 memcpy(dest
, labels
->bits
, NF_CT_LABELS_MAX_SIZE
);
116 memset(dest
, 0, NF_CT_LABELS_MAX_SIZE
);
120 case NFT_CT_BYTES
: /* fallthrough */
122 const struct nf_conn_acct
*acct
= nf_conn_acct_find(ct
);
126 count
= nft_ct_get_eval_counter(acct
->counter
,
127 priv
->key
, priv
->dir
);
128 memcpy(dest
, &count
, sizeof(count
));
131 case NFT_CT_L3PROTOCOL
:
132 *dest
= nf_ct_l3num(ct
);
134 case NFT_CT_PROTOCOL
:
135 *dest
= nf_ct_protonum(ct
);
141 tuple
= &ct
->tuplehash
[priv
->dir
].tuple
;
144 memcpy(dest
, tuple
->src
.u3
.all
,
145 nf_ct_l3num(ct
) == NFPROTO_IPV4
? 4 : 16);
148 memcpy(dest
, tuple
->dst
.u3
.all
,
149 nf_ct_l3num(ct
) == NFPROTO_IPV4
? 4 : 16);
151 case NFT_CT_PROTO_SRC
:
152 *dest
= (__force __u16
)tuple
->src
.u
.all
;
154 case NFT_CT_PROTO_DST
:
155 *dest
= (__force __u16
)tuple
->dst
.u
.all
;
162 regs
->verdict
.code
= NFT_BREAK
;
165 static void nft_ct_set_eval(const struct nft_expr
*expr
,
166 struct nft_regs
*regs
,
167 const struct nft_pktinfo
*pkt
)
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
];
174 enum ip_conntrack_info ctinfo
;
177 ct
= nf_ct_get(skb
, &ctinfo
);
182 #ifdef CONFIG_NF_CONNTRACK_MARK
184 if (ct
->mark
!= value
) {
186 nf_conntrack_event_cache(IPCT_MARK
, ct
);
190 #ifdef CONFIG_NF_CONNTRACK_LABELS
192 nf_connlabels_replace(ct
,
193 ®s
->data
[priv
->sreg
],
194 ®s
->data
[priv
->sreg
],
195 NF_CT_LABELS_MAX_SIZE
/ sizeof(u32
));
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
},
210 static int nft_ct_l3proto_try_module_get(uint8_t family
)
214 if (family
== NFPROTO_INET
) {
215 err
= nf_ct_l3proto_try_module_get(NFPROTO_IPV4
);
218 err
= nf_ct_l3proto_try_module_get(NFPROTO_IPV6
);
222 err
= nf_ct_l3proto_try_module_get(family
);
229 nf_ct_l3proto_module_put(NFPROTO_IPV4
);
234 static void nft_ct_l3proto_module_put(uint8_t family
)
236 if (family
== NFPROTO_INET
) {
237 nf_ct_l3proto_module_put(NFPROTO_IPV4
);
238 nf_ct_l3proto_module_put(NFPROTO_IPV6
);
240 nf_ct_l3proto_module_put(family
);
243 static int nft_ct_get_init(const struct nft_ctx
*ctx
,
244 const struct nft_expr
*expr
,
245 const struct nlattr
* const tb
[])
247 struct nft_ct
*priv
= nft_expr_priv(expr
);
251 priv
->key
= ntohl(nla_get_be32(tb
[NFTA_CT_KEY
]));
253 case NFT_CT_DIRECTION
:
254 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
260 #ifdef CONFIG_NF_CONNTRACK_MARK
263 #ifdef CONFIG_NF_CONNTRACK_SECMARK
266 case NFT_CT_EXPIRATION
:
267 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
271 #ifdef CONFIG_NF_CONNTRACK_LABELS
273 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
275 len
= NF_CT_LABELS_MAX_SIZE
;
279 if (tb
[NFTA_CT_DIRECTION
] != NULL
)
281 len
= NF_CT_HELPER_NAME_LEN
;
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.
293 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
296 switch (ctx
->afi
->family
) {
298 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
,
303 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
,
307 return -EAFNOSUPPORT
;
310 case NFT_CT_PROTO_SRC
:
311 case NFT_CT_PROTO_DST
:
312 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
314 len
= FIELD_SIZEOF(struct nf_conntrack_tuple
, src
.u
.all
);
318 /* no direction? return sum of original + reply */
319 if (tb
[NFTA_CT_DIRECTION
] == NULL
)
320 priv
->dir
= IP_CT_DIR_MAX
;
327 if (tb
[NFTA_CT_DIRECTION
] != NULL
) {
328 priv
->dir
= nla_get_u8(tb
[NFTA_CT_DIRECTION
]);
330 case IP_CT_DIR_ORIGINAL
:
331 case IP_CT_DIR_REPLY
:
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
);
344 err
= nft_ct_l3proto_try_module_get(ctx
->afi
->family
);
348 if (priv
->key
== NFT_CT_BYTES
|| priv
->key
== NFT_CT_PKTS
)
349 nf_ct_set_acct(ctx
->net
, true);
354 static int nft_ct_set_init(const struct nft_ctx
*ctx
,
355 const struct nft_expr
*expr
,
356 const struct nlattr
* const tb
[])
358 struct nft_ct
*priv
= nft_expr_priv(expr
);
359 bool label_got
= false;
363 priv
->key
= ntohl(nla_get_be32(tb
[NFTA_CT_KEY
]));
365 #ifdef CONFIG_NF_CONNTRACK_MARK
367 if (tb
[NFTA_CT_DIRECTION
])
369 len
= FIELD_SIZEOF(struct nf_conn
, mark
);
372 #ifdef CONFIG_NF_CONNTRACK_LABELS
374 if (tb
[NFTA_CT_DIRECTION
])
376 len
= NF_CT_LABELS_MAX_SIZE
;
377 err
= nf_connlabels_get(ctx
->net
, (len
* BITS_PER_BYTE
) - 1);
387 priv
->sreg
= nft_parse_register(tb
[NFTA_CT_SREG
]);
388 err
= nft_validate_register_load(priv
->sreg
, len
);
392 err
= nft_ct_l3proto_try_module_get(ctx
->afi
->family
);
400 nf_connlabels_put(ctx
->net
);
404 static void nft_ct_get_destroy(const struct nft_ctx
*ctx
,
405 const struct nft_expr
*expr
)
407 nft_ct_l3proto_module_put(ctx
->afi
->family
);
410 static void nft_ct_set_destroy(const struct nft_ctx
*ctx
,
411 const struct nft_expr
*expr
)
413 struct nft_ct
*priv
= nft_expr_priv(expr
);
416 #ifdef CONFIG_NF_CONNTRACK_LABELS
418 nf_connlabels_put(ctx
->net
);
425 nft_ct_l3proto_module_put(ctx
->afi
->family
);
428 static int nft_ct_get_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
430 const struct nft_ct
*priv
= nft_expr_priv(expr
);
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
;
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
;
447 if (priv
->dir
< IP_CT_DIR_MAX
&&
448 nla_put_u8(skb
, NFTA_CT_DIRECTION
, priv
->dir
))
449 goto nla_put_failure
;
461 static int nft_ct_set_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
463 const struct nft_ct
*priv
= nft_expr_priv(expr
);
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
;
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
,
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
,
494 static const struct nft_expr_ops
*
495 nft_ct_select_ops(const struct nft_ctx
*ctx
,
496 const struct nlattr
* const tb
[])
498 if (tb
[NFTA_CT_KEY
] == NULL
)
499 return ERR_PTR(-EINVAL
);
501 if (tb
[NFTA_CT_DREG
] && tb
[NFTA_CT_SREG
])
502 return ERR_PTR(-EINVAL
);
504 if (tb
[NFTA_CT_DREG
])
505 return &nft_ct_get_ops
;
507 if (tb
[NFTA_CT_SREG
])
508 return &nft_ct_set_ops
;
510 return ERR_PTR(-EINVAL
);
513 static struct nft_expr_type nft_ct_type __read_mostly
= {
515 .select_ops
= &nft_ct_select_ops
,
516 .policy
= nft_ct_policy
,
517 .maxattr
= NFTA_CT_MAX
,
518 .owner
= THIS_MODULE
,
521 static int __init
nft_ct_module_init(void)
523 BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE
> NFT_REG_SIZE
);
525 return nft_register_expr(&nft_ct_type
);
528 static void __exit
nft_ct_module_exit(void)
530 nft_unregister_expr(&nft_ct_type
);
533 module_init(nft_ct_module_init
);
534 module_exit(nft_ct_module_exit
);
536 MODULE_LICENSE("GPL");
537 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
538 MODULE_ALIAS_NFT_EXPR("ct");