15 #include <arpa/inet.h>
17 #include <linux/netfilter/nf_tables.h>
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
27 enum nft_registers dreg;
28 enum nft_registers sreg;
32 #define IP_CT_DIR_ORIGINAL 0
33 #define IP_CT_DIR_REPLY 1
36 #define NFT_CT_MAX (NFT_CT_LABELS + 1)
40 nft_rule_expr_ct_set(
struct nft_rule_expr *e, uint16_t type,
41 const void *data, uint32_t data_len)
47 ct->key = *((uint32_t *)data);
50 ct->dir = *((uint8_t *)data);
52 case NFT_EXPR_CT_DREG:
53 ct->dreg = *((uint32_t *)data);
55 case NFT_EXPR_CT_SREG:
56 ct->sreg = *((uint32_t *)data);
65 nft_rule_expr_ct_get(
const struct nft_rule_expr *e, uint16_t type,
72 *data_len =
sizeof(ct->key);
75 *data_len =
sizeof(ct->dir);
77 case NFT_EXPR_CT_DREG:
78 *data_len =
sizeof(ct->dreg);
80 case NFT_EXPR_CT_SREG:
81 *data_len =
sizeof(ct->sreg);
87 static int nft_rule_expr_ct_cb(
const struct nlattr *attr,
void *data)
89 const struct nlattr **tb = data;
90 int type = mnl_attr_get_type(attr);
92 if (mnl_attr_type_valid(attr, NFTA_CT_MAX) < 0)
99 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
100 perror(
"mnl_attr_validate");
104 case NFTA_CT_DIRECTION:
105 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
106 perror(
"mnl_attr_validate");
117 nft_rule_expr_ct_build(
struct nlmsghdr *nlh,
struct nft_rule_expr *e)
121 if (e->flags & (1 << NFT_EXPR_CT_KEY))
122 mnl_attr_put_u32(nlh, NFTA_CT_KEY, htonl(ct->key));
123 if (e->flags & (1 << NFT_EXPR_CT_DREG))
124 mnl_attr_put_u32(nlh, NFTA_CT_DREG, htonl(ct->dreg));
125 if (e->flags & (1 << NFT_EXPR_CT_DIR))
126 mnl_attr_put_u8(nlh, NFTA_CT_DIRECTION, ct->dir);
127 if (e->flags & (1 << NFT_EXPR_CT_SREG))
128 mnl_attr_put_u32(nlh, NFTA_CT_SREG, htonl(ct->sreg));
132 nft_rule_expr_ct_parse(
struct nft_rule_expr *e,
struct nlattr *attr)
135 struct nlattr *tb[NFTA_CT_MAX+1] = {};
137 if (mnl_attr_parse_nested(attr, nft_rule_expr_ct_cb, tb) < 0)
140 if (tb[NFTA_CT_KEY]) {
141 ct->key = ntohl(mnl_attr_get_u32(tb[NFTA_CT_KEY]));
142 e->flags |= (1 << NFT_EXPR_CT_KEY);
144 if (tb[NFTA_CT_DREG]) {
145 ct->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_DREG]));
146 e->flags |= (1 << NFT_EXPR_CT_DREG);
148 if (tb[NFTA_CT_SREG]) {
149 ct->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SREG]));
150 e->flags |= (1 << NFT_EXPR_CT_SREG);
152 if (tb[NFTA_CT_DIRECTION]) {
153 ct->dir = mnl_attr_get_u8(tb[NFTA_CT_DIRECTION]);
154 e->flags |= (1 << NFT_EXPR_CT_DIR);
160 const char *ctkey2str_array[NFT_CT_MAX] = {
161 [NFT_CT_STATE] =
"state",
162 [NFT_CT_DIRECTION] =
"direction",
163 [NFT_CT_STATUS] =
"status",
164 [NFT_CT_MARK] =
"mark",
165 [NFT_CT_SECMARK] =
"secmark",
166 [NFT_CT_EXPIRATION] =
"expiration",
167 [NFT_CT_HELPER] =
"helper",
168 [NFT_CT_L3PROTOCOL] =
"l3protocol",
169 [NFT_CT_PROTOCOL] =
"protocol",
170 [NFT_CT_SRC] =
"src",
171 [NFT_CT_DST] =
"dst",
172 [NFT_CT_PROTO_SRC] =
"proto_src",
173 [NFT_CT_PROTO_DST] =
"proto_dst",
174 [NFT_CT_LABELS] =
"label",
177 static const char *ctkey2str(uint32_t ctkey)
179 if (ctkey > NFT_CT_MAX)
182 return ctkey2str_array[ctkey];
185 static inline int str2ctkey(
const char *ctkey)
189 for (i = 0; i < NFT_CT_MAX; i++) {
190 if (strcmp(ctkey2str_array[i], ctkey) == 0)
197 static const char *ctdir2str(uint8_t ctdir)
200 case IP_CT_DIR_ORIGINAL:
202 case IP_CT_DIR_REPLY:
209 static inline int str2ctdir(
const char *str, uint8_t *ctdir)
211 if (strcmp(str,
"original") == 0) {
212 *ctdir = IP_CT_DIR_ORIGINAL;
216 if (strcmp(str,
"reply") == 0) {
217 *ctdir = IP_CT_DIR_REPLY;
224 static int nft_rule_expr_ct_json_parse(
struct nft_rule_expr *e, json_t *root,
225 struct nft_parse_err *err)
228 const char *key_str, *dir_str;
233 if (nft_jansson_parse_reg(root,
"dreg", NFT_TYPE_U32, ®, err) == 0)
234 nft_rule_expr_set_u32(e, NFT_EXPR_CT_DREG, reg);
236 if (nft_jansson_parse_reg(root,
"sreg", NFT_TYPE_U32, ®, err) == 0)
237 nft_rule_expr_set_u32(e, NFT_EXPR_CT_SREG, reg);
239 key_str = nft_jansson_parse_str(root,
"key", err);
240 if (key_str != NULL) {
241 key = str2ctkey(key_str);
245 nft_rule_expr_set_u32(e, NFT_EXPR_CT_KEY, key);
248 dir_str = nft_jansson_parse_str(root,
"dir", err);
249 if (dir_str != NULL) {
250 if (str2ctdir(dir_str, &dir) != 0) {
251 err->node_name =
"dir";
252 err->error = NFT_PARSE_EBADTYPE;
255 nft_rule_expr_set_u8(e, NFT_EXPR_CT_DIR, dir);
269 static int nft_rule_expr_ct_xml_parse(
struct nft_rule_expr *e, mxml_node_t *tree,
270 struct nft_parse_err *err)
273 const char *key_str, *dir_str;
278 if (nft_mxml_reg_parse(tree,
"dreg", &dreg, MXML_DESCEND_FIRST,
279 NFT_XML_OPT, err) == 0)
280 nft_rule_expr_set_u32(e, NFT_EXPR_CT_DREG, dreg);
282 if (nft_mxml_reg_parse(tree,
"sreg", &sreg, MXML_DESCEND_FIRST,
283 NFT_XML_OPT, err) == 0)
284 nft_rule_expr_set_u32(e, NFT_EXPR_CT_SREG, sreg);
286 key_str = nft_mxml_str_parse(tree,
"key", MXML_DESCEND_FIRST,
288 if (key_str != NULL) {
289 key = str2ctkey(key_str);
293 nft_rule_expr_set_u32(e, NFT_EXPR_CT_KEY, key);
295 dir_str = nft_mxml_str_parse(tree,
"dir", MXML_DESCEND_FIRST,
297 if (dir_str != NULL) {
298 if (str2ctdir(dir_str, &dir) != 0) {
299 err->node_name =
"dir";
300 err->error = NFT_PARSE_EBADTYPE;
303 nft_rule_expr_set_u8(e, NFT_EXPR_CT_DIR, dir);
317 nft_expr_ct_snprintf_json(
char *buf,
size_t size,
struct nft_rule_expr *e)
319 int ret, len = size, offset = 0;
322 if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
323 ret = snprintf(buf+offset, len,
"\"dreg\":%u,", ct->dreg);
324 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
327 if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
328 ret = snprintf(buf+offset, len,
"\"sreg:\":%u,", ct->sreg);
329 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
332 if (e->flags & (1 << NFT_EXPR_CT_KEY)) {
333 ret = snprintf(buf+offset, len,
"\"key\":\"%s\",",
335 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
338 if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
339 ret = snprintf(buf+offset, len,
"\"dir\":\"%s\",",
341 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
352 nft_expr_ct_snprintf_xml(
char *buf,
size_t size,
struct nft_rule_expr *e)
354 int ret, len = size, offset = 0;
357 if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
358 ret = snprintf(buf + offset, len,
"<dreg>%u</dreg>", ct->dreg);
359 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
361 if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
362 ret = snprintf(buf + offset, len,
"<sreg>%u</sreg>", ct->sreg);
363 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
365 if (e->flags & (1 << NFT_EXPR_CT_KEY)) {
366 ret = snprintf(buf + offset, len,
"<key>%s</key>",
368 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
370 if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
371 ret = snprintf(buf + offset, len,
"<dir>%s</dir>",
373 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
380 nft_expr_ct_snprintf_default(
char *buf,
size_t size,
struct nft_rule_expr *e)
382 int ret, len = size, offset = 0;
385 if (e->flags & (1 << NFT_EXPR_CT_SREG)) {
386 ret = snprintf(buf, size,
"set %s with reg %u ",
387 ctkey2str(ct->key), ct->sreg);
388 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
391 if (e->flags & (1 << NFT_EXPR_CT_DREG)) {
392 ret = snprintf(buf, len,
"load %s => reg %u ",
393 ctkey2str(ct->key), ct->dreg);
394 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
397 if (nft_rule_expr_is_set(e, NFT_EXPR_CT_DIR)) {
398 ret = snprintf(buf+offset, len,
", dir %s ",
400 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
407 nft_rule_expr_ct_snprintf(
char *buf,
size_t len, uint32_t type,
408 uint32_t flags,
struct nft_rule_expr *e)
411 case NFT_OUTPUT_DEFAULT:
412 return nft_expr_ct_snprintf_default(buf, len, e);
414 return nft_expr_ct_snprintf_xml(buf, len, e);
415 case NFT_OUTPUT_JSON:
416 return nft_expr_ct_snprintf_json(buf, len, e);
423 struct expr_ops expr_ops_ct = {
426 .max_attr = NFTA_CT_MAX,
427 .set = nft_rule_expr_ct_set,
428 .get = nft_rule_expr_ct_get,
429 .parse = nft_rule_expr_ct_parse,
430 .build = nft_rule_expr_ct_build,
431 .snprintf = nft_rule_expr_ct_snprintf,
432 .xml_parse = nft_rule_expr_ct_xml_parse,
433 .json_parse = nft_rule_expr_ct_json_parse,
436 static void __init expr_ct_init(
void)
438 nft_expr_ops_register(&expr_ops_ct);