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>
26 enum nft_registers dreg;
27 enum nft_registers sreg;
31 #define IP_CT_DIR_ORIGINAL 0
32 #define IP_CT_DIR_REPLY 1
35 #define NFT_CT_MAX (NFT_CT_BYTES + 1)
39 nftnl_expr_ct_set(
struct nftnl_expr *e, uint16_t type,
40 const void *data, uint32_t data_len)
45 case NFTNL_EXPR_CT_KEY:
46 ct->key = *((uint32_t *)data);
48 case NFTNL_EXPR_CT_DIR:
49 ct->dir = *((uint8_t *)data);
51 case NFTNL_EXPR_CT_DREG:
52 ct->dreg = *((uint32_t *)data);
54 case NFTNL_EXPR_CT_SREG:
55 ct->sreg = *((uint32_t *)data);
64 nftnl_expr_ct_get(
const struct nftnl_expr *e, uint16_t type,
70 case NFTNL_EXPR_CT_KEY:
71 *data_len =
sizeof(ct->key);
73 case NFTNL_EXPR_CT_DIR:
74 *data_len =
sizeof(ct->dir);
76 case NFTNL_EXPR_CT_DREG:
77 *data_len =
sizeof(ct->dreg);
79 case NFTNL_EXPR_CT_SREG:
80 *data_len =
sizeof(ct->sreg);
86 static int nftnl_expr_ct_cb(
const struct nlattr *attr,
void *data)
88 const struct nlattr **tb = data;
89 int type = mnl_attr_get_type(attr);
91 if (mnl_attr_type_valid(attr, NFTA_CT_MAX) < 0)
98 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
101 case NFTA_CT_DIRECTION:
102 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
112 nftnl_expr_ct_build(
struct nlmsghdr *nlh,
const struct nftnl_expr *e)
116 if (e->flags & (1 << NFTNL_EXPR_CT_KEY))
117 mnl_attr_put_u32(nlh, NFTA_CT_KEY, htonl(ct->key));
118 if (e->flags & (1 << NFTNL_EXPR_CT_DREG))
119 mnl_attr_put_u32(nlh, NFTA_CT_DREG, htonl(ct->dreg));
120 if (e->flags & (1 << NFTNL_EXPR_CT_DIR))
121 mnl_attr_put_u8(nlh, NFTA_CT_DIRECTION, ct->dir);
122 if (e->flags & (1 << NFTNL_EXPR_CT_SREG))
123 mnl_attr_put_u32(nlh, NFTA_CT_SREG, htonl(ct->sreg));
127 nftnl_expr_ct_parse(
struct nftnl_expr *e,
struct nlattr *attr)
130 struct nlattr *tb[NFTA_CT_MAX+1] = {};
132 if (mnl_attr_parse_nested(attr, nftnl_expr_ct_cb, tb) < 0)
135 if (tb[NFTA_CT_KEY]) {
136 ct->key = ntohl(mnl_attr_get_u32(tb[NFTA_CT_KEY]));
137 e->flags |= (1 << NFTNL_EXPR_CT_KEY);
139 if (tb[NFTA_CT_DREG]) {
140 ct->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_DREG]));
141 e->flags |= (1 << NFTNL_EXPR_CT_DREG);
143 if (tb[NFTA_CT_SREG]) {
144 ct->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SREG]));
145 e->flags |= (1 << NFTNL_EXPR_CT_SREG);
147 if (tb[NFTA_CT_DIRECTION]) {
148 ct->dir = mnl_attr_get_u8(tb[NFTA_CT_DIRECTION]);
149 e->flags |= (1 << NFTNL_EXPR_CT_DIR);
155 static const char *ctkey2str_array[NFT_CT_MAX] = {
156 [NFT_CT_STATE] =
"state",
157 [NFT_CT_DIRECTION] =
"direction",
158 [NFT_CT_STATUS] =
"status",
159 [NFT_CT_MARK] =
"mark",
160 [NFT_CT_SECMARK] =
"secmark",
161 [NFT_CT_EXPIRATION] =
"expiration",
162 [NFT_CT_HELPER] =
"helper",
163 [NFT_CT_L3PROTOCOL] =
"l3protocol",
164 [NFT_CT_PROTOCOL] =
"protocol",
165 [NFT_CT_SRC] =
"src",
166 [NFT_CT_DST] =
"dst",
167 [NFT_CT_PROTO_SRC] =
"proto_src",
168 [NFT_CT_PROTO_DST] =
"proto_dst",
169 [NFT_CT_LABELS] =
"label",
170 [NFT_CT_PKTS] =
"packets",
171 [NFT_CT_BYTES] =
"bytes",
174 static const char *ctkey2str(uint32_t ctkey)
176 if (ctkey > NFT_CT_MAX)
179 return ctkey2str_array[ctkey];
182 static inline int str2ctkey(
const char *ctkey)
186 for (i = 0; i < NFT_CT_MAX; i++) {
187 if (strcmp(ctkey2str_array[i], ctkey) == 0)
194 static const char *ctdir2str(uint8_t ctdir)
197 case IP_CT_DIR_ORIGINAL:
199 case IP_CT_DIR_REPLY:
206 static inline int str2ctdir(
const char *str, uint8_t *ctdir)
208 if (strcmp(str,
"original") == 0) {
209 *ctdir = IP_CT_DIR_ORIGINAL;
213 if (strcmp(str,
"reply") == 0) {
214 *ctdir = IP_CT_DIR_REPLY;
221 static int nftnl_expr_ct_json_parse(
struct nftnl_expr *e, json_t *root,
222 struct nftnl_parse_err *err)
225 const char *key_str, *dir_str;
230 if (nftnl_jansson_parse_reg(root,
"dreg", NFTNL_TYPE_U32, ®, err) == 0)
231 nftnl_expr_set_u32(e, NFTNL_EXPR_CT_DREG, reg);
233 if (nftnl_jansson_parse_reg(root,
"sreg", NFTNL_TYPE_U32, ®, err) == 0)
234 nftnl_expr_set_u32(e, NFTNL_EXPR_CT_SREG, reg);
236 key_str = nftnl_jansson_parse_str(root,
"key", err);
237 if (key_str != NULL) {
238 key = str2ctkey(key_str);
242 nftnl_expr_set_u32(e, NFTNL_EXPR_CT_KEY, key);
245 dir_str = nftnl_jansson_parse_str(root,
"dir", err);
246 if (dir_str != NULL) {
247 if (str2ctdir(dir_str, &dir) != 0) {
248 err->node_name =
"dir";
249 err->error = NFTNL_PARSE_EBADTYPE;
252 nftnl_expr_set_u8(e, NFTNL_EXPR_CT_DIR, dir);
266 static int nftnl_expr_ct_xml_parse(
struct nftnl_expr *e, mxml_node_t *tree,
267 struct nftnl_parse_err *err)
270 const char *key_str, *dir_str;
275 if (nftnl_mxml_reg_parse(tree,
"dreg", &dreg, MXML_DESCEND_FIRST,
276 NFTNL_XML_OPT, err) == 0)
277 nftnl_expr_set_u32(e, NFTNL_EXPR_CT_DREG, dreg);
279 if (nftnl_mxml_reg_parse(tree,
"sreg", &sreg, MXML_DESCEND_FIRST,
280 NFTNL_XML_OPT, err) == 0)
281 nftnl_expr_set_u32(e, NFTNL_EXPR_CT_SREG, sreg);
283 key_str = nftnl_mxml_str_parse(tree,
"key", MXML_DESCEND_FIRST,
284 NFTNL_XML_MAND, err);
285 if (key_str != NULL) {
286 key = str2ctkey(key_str);
290 nftnl_expr_set_u32(e, NFTNL_EXPR_CT_KEY, key);
292 dir_str = nftnl_mxml_str_parse(tree,
"dir", MXML_DESCEND_FIRST,
294 if (dir_str != NULL) {
295 if (str2ctdir(dir_str, &dir) != 0) {
296 err->node_name =
"dir";
297 err->error = NFTNL_PARSE_EBADTYPE;
300 nftnl_expr_set_u8(e, NFTNL_EXPR_CT_DIR, dir);
314 nftnl_expr_ct_export(
char *buf,
size_t size,
const struct nftnl_expr *e,
318 NFTNL_BUF_INIT(b, buf, size);
320 if (e->flags & (1 << NFTNL_EXPR_CT_SREG))
321 nftnl_buf_u32(&b, type, ct->sreg, SREG);
322 if (e->flags & (1 << NFTNL_EXPR_CT_DREG))
323 nftnl_buf_u32(&b, type, ct->dreg, DREG);
324 if (e->flags & (1 << NFTNL_EXPR_CT_KEY))
325 nftnl_buf_str(&b, type, ctkey2str(ct->key), KEY);
326 if (e->flags & (1 << NFTNL_EXPR_CT_DIR))
327 nftnl_buf_str(&b, type, ctdir2str(ct->dir), DIR);
329 return nftnl_buf_done(&b);
333 nftnl_expr_ct_snprintf_default(
char *buf,
size_t size,
334 const struct nftnl_expr *e)
336 int ret, len = size, offset = 0;
339 if (e->flags & (1 << NFTNL_EXPR_CT_SREG)) {
340 ret = snprintf(buf, size,
"set %s with reg %u ",
341 ctkey2str(ct->key), ct->sreg);
342 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
345 if (e->flags & (1 << NFTNL_EXPR_CT_DREG)) {
346 ret = snprintf(buf, len,
"load %s => reg %u ",
347 ctkey2str(ct->key), ct->dreg);
348 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
351 if (nftnl_expr_is_set(e, NFTNL_EXPR_CT_DIR)) {
352 ret = snprintf(buf+offset, len,
", dir %s ",
354 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
361 nftnl_expr_ct_snprintf(
char *buf,
size_t len, uint32_t type,
362 uint32_t flags,
const struct nftnl_expr *e)
365 case NFTNL_OUTPUT_DEFAULT:
366 return nftnl_expr_ct_snprintf_default(buf, len, e);
367 case NFTNL_OUTPUT_XML:
368 case NFTNL_OUTPUT_JSON:
369 return nftnl_expr_ct_export(buf, len, e, type);
376 struct expr_ops expr_ops_ct = {
379 .max_attr = NFTA_CT_MAX,
380 .set = nftnl_expr_ct_set,
381 .get = nftnl_expr_ct_get,
382 .parse = nftnl_expr_ct_parse,
383 .build = nftnl_expr_ct_build,
384 .snprintf = nftnl_expr_ct_snprintf,
385 .xml_parse = nftnl_expr_ct_xml_parse,
386 .json_parse = nftnl_expr_ct_json_parse,