]> git.ipfire.org Git - thirdparty/nftables.git/blame_incremental - src/netlink.c
tests: shell: use binary defined by run-tests.sh
[thirdparty/nftables.git] / src / netlink.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2008-2012 Patrick McHardy <kaber@trash.net>
3 * Copyright (c) 2013 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 <nft.h>
13
14#include <errno.h>
15#include <libmnl/libmnl.h>
16#include <netinet/in.h>
17#include <arpa/inet.h>
18#include <inttypes.h>
19
20#include <libnftnl/table.h>
21#include <libnftnl/trace.h>
22#include <libnftnl/chain.h>
23#include <libnftnl/expr.h>
24#include <libnftnl/object.h>
25#include <libnftnl/set.h>
26#include <libnftnl/flowtable.h>
27#include <libnftnl/udata.h>
28#include <libnftnl/ruleset.h>
29#include <libnftnl/common.h>
30#include <libnftnl/udata.h>
31#include <linux/netfilter/nfnetlink.h>
32#include <linux/netfilter/nf_tables.h>
33#include <linux/netfilter.h>
34
35#include <nftables.h>
36#include <parser.h>
37#include <netlink.h>
38#include <mnl.h>
39#include <expression.h>
40#include <statement.h>
41#include <gmputil.h>
42#include <utils.h>
43#include <erec.h>
44#include <iface.h>
45
46#define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__)
47
48const struct input_descriptor indesc_netlink = {
49 .name = "netlink",
50 .type = INDESC_NETLINK,
51};
52
53const struct location netlink_location = {
54 .indesc = &indesc_netlink,
55};
56
57void __noreturn __netlink_abi_error(const char *file, int line,
58 const char *reason)
59{
60 fprintf(stderr, "E: Contact urgently your Linux kernel vendor. "
61 "Netlink ABI is broken: %s:%d %s\n", file, line, reason);
62 abort();
63}
64
65int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc,
66 const char *fmt, ...)
67{
68 struct error_record *erec;
69 va_list ap;
70
71 if (loc == NULL)
72 loc = &netlink_location;
73
74 va_start(ap, fmt);
75 erec = erec_vcreate(EREC_ERROR, loc, fmt, ap);
76 va_end(ap);
77 erec_queue(erec, ctx->msgs);
78 return -1;
79}
80
81void __noreturn __netlink_init_error(const char *filename, int line,
82 const char *reason)
83{
84 fprintf(stderr, "%s:%d: Unable to initialize Netlink socket: %s\n",
85 filename, line, reason);
86 exit(NFT_EXIT_NONL);
87}
88
89struct nftnl_expr *alloc_nft_expr(const char *name)
90{
91 struct nftnl_expr *nle;
92
93 nle = nftnl_expr_alloc(name);
94 if (nle == NULL)
95 memory_allocation_error();
96
97 return nle;
98}
99static void netlink_gen_key(const struct expr *expr,
100 struct nft_data_linearize *data);
101static void __netlink_gen_data(const struct expr *expr,
102 struct nft_data_linearize *data, bool expand);
103
104struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
105 const struct expr *expr)
106{
107 const struct expr *elem, *data;
108 struct nftnl_set_elem *nlse;
109 struct nft_data_linearize nld;
110 struct nftnl_udata_buf *udbuf = NULL;
111 uint32_t flags = 0;
112 int num_exprs = 0;
113 struct stmt *stmt;
114 struct expr *key;
115
116 nlse = nftnl_set_elem_alloc();
117 if (nlse == NULL)
118 memory_allocation_error();
119
120 data = NULL;
121 if (expr->etype == EXPR_MAPPING) {
122 elem = expr->left;
123 if (!(expr->flags & EXPR_F_INTERVAL_END))
124 data = expr->right;
125 } else {
126 elem = expr;
127 }
128 if (elem->etype != EXPR_SET_ELEM)
129 BUG("Unexpected expression type: got %d\n", elem->etype);
130
131 key = elem->key;
132
133 switch (key->etype) {
134 case EXPR_SET_ELEM_CATCHALL:
135 break;
136 default:
137 if (set->set_flags & NFT_SET_INTERVAL &&
138 key->etype == EXPR_CONCAT && key->field_count > 1) {
139 key->flags |= EXPR_F_INTERVAL;
140 netlink_gen_key(key, &nld);
141 key->flags &= ~EXPR_F_INTERVAL;
142
143 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
144
145 key->flags |= EXPR_F_INTERVAL_END;
146 netlink_gen_key(key, &nld);
147 key->flags &= ~EXPR_F_INTERVAL_END;
148
149 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END,
150 &nld.value, nld.len);
151 } else {
152 netlink_gen_key(key, &nld);
153 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
154 }
155 break;
156 }
157
158 if (elem->timeout) {
159 uint64_t timeout = elem->timeout;
160
161 if (elem->timeout == NFT_NEVER_TIMEOUT)
162 timeout = 0;
163
164 nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT, timeout);
165 }
166 if (elem->expiration)
167 nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_EXPIRATION,
168 elem->expiration);
169 list_for_each_entry(stmt, &elem->stmt_list, list)
170 num_exprs++;
171
172 if (num_exprs == 1) {
173 list_for_each_entry(stmt, &elem->stmt_list, list) {
174 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_EXPR,
175 netlink_gen_stmt_stateful(stmt), 0);
176 }
177 } else if (num_exprs > 1) {
178 list_for_each_entry(stmt, &elem->stmt_list, list) {
179 nftnl_set_elem_add_expr(nlse,
180 netlink_gen_stmt_stateful(stmt));
181 }
182 }
183 if (elem->comment || expr->flags & EXPR_F_INTERVAL_OPEN) {
184 udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
185 if (!udbuf)
186 memory_allocation_error();
187 }
188 if (elem->comment) {
189 if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_SET_ELEM_COMMENT,
190 elem->comment))
191 memory_allocation_error();
192 }
193 if (expr->flags & EXPR_F_INTERVAL_OPEN) {
194 if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_ELEM_FLAGS,
195 NFTNL_SET_ELEM_F_INTERVAL_OPEN))
196 memory_allocation_error();
197 }
198 if (udbuf) {
199 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_USERDATA,
200 nftnl_udata_buf_data(udbuf),
201 nftnl_udata_buf_len(udbuf));
202 nftnl_udata_buf_free(udbuf);
203 }
204 if (set_is_datamap(set->set_flags) && data != NULL) {
205 __netlink_gen_data(data, &nld, !(data->flags & EXPR_F_SINGLETON));
206 switch (data->etype) {
207 case EXPR_VERDICT:
208 nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_VERDICT,
209 data->verdict);
210 if (data->chain != NULL)
211 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_CHAIN,
212 nld.chain, strlen(nld.chain));
213 break;
214 case EXPR_CONCAT:
215 assert(nld.len > 0);
216 /* fallthrough */
217 case EXPR_VALUE:
218 case EXPR_RANGE:
219 case EXPR_RANGE_VALUE:
220 case EXPR_PREFIX:
221 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_DATA,
222 nld.value, nld.len);
223 break;
224 default:
225 BUG("unexpected set element expression\n");
226 break;
227 }
228 }
229 if (set_is_objmap(set->set_flags) && data != NULL) {
230 netlink_gen_data(data, &nld);
231 nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_OBJREF,
232 nld.value, nld.len);
233 }
234
235 if (expr->flags & EXPR_F_INTERVAL_END)
236 flags |= NFT_SET_ELEM_INTERVAL_END;
237 if (key->etype == EXPR_SET_ELEM_CATCHALL)
238 flags |= NFT_SET_ELEM_CATCHALL;
239
240 if (flags)
241 nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS, flags);
242
243 return nlse;
244}
245
246void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
247 unsigned int len, struct nft_data_linearize *data)
248{
249 assert(len > 0);
250 mpz_export_data(data->value, value, byteorder, len);
251 data->len = len;
252}
253
254static int netlink_export_pad(unsigned char *data, const mpz_t v,
255 const struct expr *i)
256{
257 mpz_export_data(data, v, i->byteorder,
258 div_round_up(i->len, BITS_PER_BYTE));
259
260 return netlink_padded_len(i->len) / BITS_PER_BYTE;
261}
262
263static void byteorder_switch_expr_value(mpz_t v, const struct expr *e)
264{
265 mpz_switch_byteorder(v, div_round_up(e->len, BITS_PER_BYTE));
266}
267
268static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i,
269 unsigned char *data)
270{
271 struct expr *expr;
272 mpz_t value;
273 int ret;
274
275 switch (i->etype) {
276 case EXPR_RANGE:
277 if (flags & EXPR_F_INTERVAL_END)
278 expr = i->right;
279 else
280 expr = i->left;
281
282 mpz_init_set(value, expr->value);
283
284 if (expr_basetype(expr)->type == TYPE_INTEGER &&
285 expr->byteorder == BYTEORDER_HOST_ENDIAN)
286 byteorder_switch_expr_value(value, expr);
287
288 i = expr;
289 break;
290 case EXPR_RANGE_VALUE:
291 if (flags & EXPR_F_INTERVAL_END)
292 mpz_init_set(value, i->range.high);
293 else
294 mpz_init_set(value, i->range.low);
295
296 if (expr_basetype(i)->type == TYPE_INTEGER &&
297 i->byteorder == BYTEORDER_HOST_ENDIAN)
298 byteorder_switch_expr_value(value, i);
299
300 break;
301 case EXPR_PREFIX:
302 if (flags & EXPR_F_INTERVAL_END) {
303 int count;
304 mpz_t v;
305
306 mpz_init_bitmask(v, i->len - i->prefix_len);
307
308 if (i->byteorder == BYTEORDER_HOST_ENDIAN)
309 byteorder_switch_expr_value(v, i);
310
311 mpz_add(v, i->prefix->value, v);
312 count = netlink_export_pad(data, v, i);
313 mpz_clear(v);
314 return count;
315 }
316 return netlink_export_pad(data, i->prefix->value, i);
317 case EXPR_VALUE:
318 mpz_init_set(value, i->value);
319
320 /* Switch byteorder to big endian representation when the set
321 * contains concatenation of intervals.
322 */
323 if (!(flags & (EXPR_F_INTERVAL| EXPR_F_INTERVAL_END)))
324 break;
325
326 expr = (struct expr *)i;
327 if (expr_basetype(expr)->type == TYPE_INTEGER &&
328 expr->byteorder == BYTEORDER_HOST_ENDIAN)
329 byteorder_switch_expr_value(value, expr);
330 break;
331 default:
332 BUG("invalid expression type '%s' in set", expr_ops(i)->name);
333 }
334
335 ret = netlink_export_pad(data, value, i);
336 mpz_clear(value);
337
338 return ret;
339}
340
341static void nft_data_memcpy(struct nft_data_linearize *nld,
342 const void *src, unsigned int len)
343{
344 if (len > sizeof(nld->value))
345 BUG("nld buffer overflow: want to copy %u, max %u\n", len, (unsigned int)sizeof(nld->value));
346
347 memcpy(nld->value, src, len);
348 nld->len = len;
349}
350
351static void netlink_gen_concat_key(const struct expr *expr,
352 struct nft_data_linearize *nld)
353{
354 unsigned int len = netlink_padded_len(expr->len) / BITS_PER_BYTE;
355 unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
356 unsigned int offset = 0;
357 const struct expr *i;
358
359 if (len > sizeof(data))
360 BUG("Value export of %u bytes would overflow", len);
361
362 memset(data, 0, sizeof(data));
363
364 list_for_each_entry(i, &expr->expressions, list)
365 offset += __netlink_gen_concat_key(expr->flags, i, data + offset);
366
367 nft_data_memcpy(nld, data, len);
368}
369
370static int __netlink_gen_concat_data(int end, const struct expr *i,
371 unsigned char *data)
372{
373 mpz_t value;
374 int ret;
375
376 switch (i->etype) {
377 case EXPR_RANGE:
378 if (end)
379 i = i->right;
380 else
381 i = i->left;
382
383 mpz_init_set(value, i->value);
384 break;
385 case EXPR_RANGE_VALUE:
386 if (end)
387 mpz_init_set(value, i->range.high);
388 else
389 mpz_init_set(value, i->range.low);
390 break;
391 case EXPR_PREFIX:
392 if (end) {
393 int count;
394
395 mpz_init_bitmask(value, i->len - i->prefix_len);
396 mpz_add(value, i->prefix->value, value);
397 count = netlink_export_pad(data, value, i);
398 mpz_clear(value);
399 return count;
400 }
401 return netlink_export_pad(data, i->prefix->value, i);
402 case EXPR_VALUE:
403 mpz_init_set(value, i->value);
404 break;
405 default:
406 BUG("invalid expression type '%s' in set", expr_ops(i)->name);
407 }
408
409 ret = netlink_export_pad(data, value, i);
410 mpz_clear(value);
411
412 return ret;
413}
414
415static void __netlink_gen_concat_expand(const struct expr *expr,
416 struct nft_data_linearize *nld)
417{
418 unsigned int len = (netlink_padded_len(expr->len) / BITS_PER_BYTE) * 2;
419 unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
420 unsigned int offset = 0;
421 const struct expr *i;
422
423 if (len > sizeof(data))
424 BUG("Value export of %u bytes would overflow", len);
425
426 memset(data, 0, sizeof(data));
427
428 list_for_each_entry(i, &expr->expressions, list)
429 offset += __netlink_gen_concat_data(false, i, data + offset);
430
431 list_for_each_entry(i, &expr->expressions, list)
432 offset += __netlink_gen_concat_data(true, i, data + offset);
433
434 nft_data_memcpy(nld, data, len);
435}
436
437static void __netlink_gen_concat(const struct expr *expr,
438 struct nft_data_linearize *nld)
439{
440 unsigned int len = netlink_padded_len(expr->len) / BITS_PER_BYTE;
441 unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
442 unsigned int offset = 0;
443 const struct expr *i;
444
445 if (len > sizeof(data))
446 BUG("Value export of %u bytes would overflow", len);
447
448 memset(data, 0, sizeof(data));
449
450 list_for_each_entry(i, &expr->expressions, list)
451 offset += __netlink_gen_concat_data(expr->flags, i, data + offset);
452
453 nft_data_memcpy(nld, data, len);
454}
455
456static void netlink_gen_concat_data(const struct expr *expr,
457 struct nft_data_linearize *nld, bool expand)
458{
459 if (expand)
460 __netlink_gen_concat_expand(expr, nld);
461 else
462 __netlink_gen_concat(expr, nld);
463}
464
465static void netlink_gen_constant_data(const struct expr *expr,
466 struct nft_data_linearize *data)
467{
468 assert(expr->etype == EXPR_VALUE);
469 netlink_gen_raw_data(expr->value, expr->byteorder,
470 div_round_up(expr->len, BITS_PER_BYTE), data);
471}
472
473static void netlink_gen_chain(const struct expr *expr,
474 struct nft_data_linearize *data)
475{
476 char chain[NFT_CHAIN_MAXNAMELEN];
477 unsigned int len;
478
479 len = expr->chain->len / BITS_PER_BYTE;
480
481 if (!len)
482 BUG("chain length is 0");
483
484 if (len > sizeof(chain))
485 BUG("chain is too large (%u, %u max)",
486 len, (unsigned int)sizeof(chain));
487
488 memset(chain, 0, sizeof(chain));
489
490 mpz_export_data(chain, expr->chain->value,
491 BYTEORDER_HOST_ENDIAN, len);
492 snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain);
493}
494
495static void netlink_gen_verdict(const struct expr *expr,
496 struct nft_data_linearize *data)
497{
498
499 data->verdict = expr->verdict;
500
501 switch (expr->verdict) {
502 case NFT_JUMP:
503 case NFT_GOTO:
504 if (expr->chain)
505 netlink_gen_chain(expr, data);
506 else
507 data->chain_id = expr->chain_id;
508 break;
509 }
510}
511
512static void netlink_gen_range(const struct expr *expr,
513 struct nft_data_linearize *nld)
514{
515 unsigned int len = (netlink_padded_len(expr->left->len) / BITS_PER_BYTE) * 2;
516 unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
517 unsigned int offset;
518
519 if (len > sizeof(data))
520 BUG("Value export of %u bytes would overflow", len);
521
522 memset(data, 0, sizeof(data));
523 offset = netlink_export_pad(data, expr->left->value, expr->left);
524 netlink_export_pad(data + offset, expr->right->value, expr->right);
525 nft_data_memcpy(nld, data, len);
526}
527
528static void netlink_gen_range_value(const struct expr *expr,
529 struct nft_data_linearize *nld)
530{
531 unsigned int len = (netlink_padded_len(expr->len) / BITS_PER_BYTE) * 2;
532 unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
533 unsigned int offset;
534
535 if (len > sizeof(data))
536 BUG("Value export of %u bytes would overflow", len);
537
538 memset(data, 0, sizeof(data));
539 offset = netlink_export_pad(data, expr->range.low, expr);
540 netlink_export_pad(data + offset, expr->range.high, expr);
541 nft_data_memcpy(nld, data, len);
542}
543
544static void netlink_gen_prefix(const struct expr *expr,
545 struct nft_data_linearize *nld)
546{
547 unsigned int len = (netlink_padded_len(expr->len) / BITS_PER_BYTE) * 2;
548 unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
549 int offset;
550 mpz_t v;
551
552 if (len > sizeof(data))
553 BUG("Value export of %u bytes would overflow", len);
554
555 offset = netlink_export_pad(data, expr->prefix->value, expr);
556 mpz_init_bitmask(v, expr->len - expr->prefix_len);
557 mpz_add(v, expr->prefix->value, v);
558 netlink_export_pad(data + offset, v, expr->prefix);
559 mpz_clear(v);
560
561 nft_data_memcpy(nld, data, len);
562}
563
564static void netlink_gen_key(const struct expr *expr,
565 struct nft_data_linearize *data)
566{
567 switch (expr->etype) {
568 case EXPR_VALUE:
569 return netlink_gen_constant_data(expr, data);
570 case EXPR_CONCAT:
571 return netlink_gen_concat_key(expr, data);
572 case EXPR_RANGE:
573 return netlink_gen_range(expr, data);
574 case EXPR_PREFIX:
575 return netlink_gen_prefix(expr, data);
576 default:
577 BUG("invalid data expression type %s\n", expr_name(expr));
578 }
579}
580
581static void __netlink_gen_data(const struct expr *expr,
582 struct nft_data_linearize *data, bool expand)
583{
584 switch (expr->etype) {
585 case EXPR_VALUE:
586 return netlink_gen_constant_data(expr, data);
587 case EXPR_CONCAT:
588 return netlink_gen_concat_data(expr, data, expand);
589 case EXPR_VERDICT:
590 return netlink_gen_verdict(expr, data);
591 case EXPR_RANGE:
592 return netlink_gen_range(expr, data);
593 case EXPR_RANGE_VALUE:
594 return netlink_gen_range_value(expr, data);
595 case EXPR_PREFIX:
596 return netlink_gen_prefix(expr, data);
597 default:
598 BUG("invalid data expression type %s\n", expr_name(expr));
599 }
600}
601
602void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
603{
604 __netlink_gen_data(expr, data, false);
605}
606
607struct expr *netlink_alloc_value(const struct location *loc,
608 const struct nft_data_delinearize *nld)
609{
610 return constant_expr_alloc(loc, &invalid_type, BYTEORDER_INVALID,
611 nld->len * BITS_PER_BYTE, nld->value);
612}
613
614static struct expr *netlink_alloc_verdict(const struct location *loc,
615 const struct nft_data_delinearize *nld)
616{
617 struct expr *chain;
618
619 switch (nld->verdict) {
620 case NFT_JUMP:
621 case NFT_GOTO:
622 chain = constant_expr_alloc(loc, &string_type,
623 BYTEORDER_HOST_ENDIAN,
624 strlen(nld->chain) * BITS_PER_BYTE,
625 nld->chain);
626 break;
627 default:
628 chain = NULL;
629 break;
630 }
631
632 return verdict_expr_alloc(loc, nld->verdict, chain);
633}
634
635struct expr *netlink_alloc_data(const struct location *loc,
636 const struct nft_data_delinearize *nld,
637 enum nft_registers dreg)
638{
639 switch (dreg) {
640 case NFT_REG_VERDICT:
641 return netlink_alloc_verdict(loc, nld);
642 default:
643 return netlink_alloc_value(loc, nld);
644 }
645}
646
647void netlink_dump_rule(const struct nftnl_rule *nlr, struct netlink_ctx *ctx)
648{
649 FILE *fp = ctx->nft->output.output_fp;
650
651 if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
652 return;
653
654 nftnl_rule_fprintf(fp, nlr, 0, 0);
655 fprintf(fp, "\n");
656}
657
658void netlink_dump_expr(const struct nftnl_expr *nle,
659 FILE *fp, unsigned int debug_mask)
660{
661 if (!(debug_mask & NFT_DEBUG_NETLINK))
662 return;
663
664 nftnl_expr_fprintf(fp, nle, 0, 0);
665 fprintf(fp, "\n");
666}
667
668void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
669{
670 FILE *fp = ctx->nft->output.output_fp;
671
672 if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
673 return;
674
675 nftnl_chain_fprintf(fp, nlc, 0, 0);
676 fprintf(fp, "\n");
677}
678
679static int chain_parse_udata_cb(const struct nftnl_udata *attr, void *data)
680{
681 unsigned char *value = nftnl_udata_get(attr);
682 uint8_t type = nftnl_udata_type(attr);
683 const struct nftnl_udata **tb = data;
684 uint8_t len = nftnl_udata_len(attr);
685
686 switch (type) {
687 case NFTNL_UDATA_CHAIN_COMMENT:
688 if (value[len - 1] != '\0')
689 return -1;
690 break;
691 default:
692 return 0;
693 }
694 tb[type] = attr;
695 return 0;
696}
697
698static int qsort_device_cmp(const void *a, const void *b)
699{
700 const char **x = (const char **)a;
701 const char **y = (const char **)b;
702
703 return strcmp(*x, *y);
704}
705
706struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
707 const struct nftnl_chain *nlc)
708{
709 const struct nftnl_udata *ud[NFTNL_UDATA_CHAIN_MAX + 1] = {};
710 int priority, policy, len = 0, i;
711 const char * const *dev_array;
712 struct chain *chain;
713 const char *udata;
714 uint32_t ulen;
715
716 chain = chain_alloc();
717 chain->handle.family =
718 nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
719 chain->handle.table.name =
720 xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE));
721 chain->handle.chain.name =
722 xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
723 chain->handle.handle.id =
724 nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE);
725 if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_FLAGS))
726 chain->flags = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FLAGS);
727
728 if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_HOOKNUM) &&
729 nftnl_chain_is_set(nlc, NFTNL_CHAIN_PRIO) &&
730 nftnl_chain_is_set(nlc, NFTNL_CHAIN_TYPE) &&
731 nftnl_chain_is_set(nlc, NFTNL_CHAIN_POLICY)) {
732 chain->hook.num =
733 nftnl_chain_get_u32(nlc, NFTNL_CHAIN_HOOKNUM);
734 chain->hook.name =
735 hooknum2str(chain->handle.family, chain->hook.num);
736 priority = nftnl_chain_get_s32(nlc, NFTNL_CHAIN_PRIO);
737 chain->priority.expr =
738 constant_expr_alloc(&netlink_location,
739 &integer_type,
740 BYTEORDER_HOST_ENDIAN,
741 sizeof(int) * BITS_PER_BYTE,
742 &priority);
743 chain->type.str =
744 xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TYPE));
745 policy = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
746 chain->policy = constant_expr_alloc(&netlink_location,
747 &integer_type,
748 BYTEORDER_HOST_ENDIAN,
749 sizeof(int) * BITS_PER_BYTE,
750 &policy);
751 nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
752 if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) {
753 chain->dev_array = xmalloc(sizeof(char *) * 2);
754 chain->dev_array_len = 1;
755 chain->dev_array[0] =
756 xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_DEV));
757 chain->dev_array[1] = NULL;
758 } else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) {
759 dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES);
760 while (dev_array[len])
761 len++;
762
763 chain->dev_array = xmalloc((len + 1)* sizeof(char *));
764 for (i = 0; i < len; i++)
765 chain->dev_array[i] = xstrdup(dev_array[i]);
766
767 chain->dev_array[i] = NULL;
768 chain->dev_array_len = len;
769 }
770 chain->flags |= CHAIN_F_BASECHAIN;
771
772 if (chain->dev_array_len) {
773 qsort(chain->dev_array, chain->dev_array_len,
774 sizeof(char *), qsort_device_cmp);
775 }
776 }
777
778 if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_USERDATA)) {
779 udata = nftnl_chain_get_data(nlc, NFTNL_CHAIN_USERDATA, &ulen);
780 if (nftnl_udata_parse(udata, ulen, chain_parse_udata_cb, ud) < 0) {
781 netlink_io_error(ctx, NULL, "Cannot parse userdata");
782 chain_free(chain);
783 return NULL;
784 }
785 if (ud[NFTNL_UDATA_CHAIN_COMMENT])
786 chain->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_CHAIN_COMMENT]));
787 }
788
789 return chain;
790}
791
792static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data)
793{
794 unsigned char *value = nftnl_udata_get(attr);
795 const struct nftnl_udata **tb = data;
796 uint8_t type = nftnl_udata_type(attr);
797 uint8_t len = nftnl_udata_len(attr);
798
799 switch (type) {
800 case NFTNL_UDATA_TABLE_COMMENT:
801 if (value[len - 1] != '\0')
802 return -1;
803 break;
804 default:
805 return 0;
806 }
807 tb[type] = attr;
808 return 0;
809}
810
811struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
812 const struct nftnl_table *nlt)
813{
814 const struct nftnl_udata *ud[NFTNL_UDATA_TABLE_MAX + 1] = {};
815 struct table *table;
816 const char *udata;
817 uint32_t ulen;
818
819 table = table_alloc();
820 table->handle.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
821 table->handle.table.name = xstrdup(nftnl_table_get_str(nlt, NFTNL_TABLE_NAME));
822 table->flags = nftnl_table_get_u32(nlt, NFTNL_TABLE_FLAGS);
823 table->handle.handle.id = nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE);
824 table->owner = nftnl_table_get_u32(nlt, NFTNL_TABLE_OWNER);
825
826 if (nftnl_table_is_set(nlt, NFTNL_TABLE_USERDATA)) {
827 udata = nftnl_table_get_data(nlt, NFTNL_TABLE_USERDATA, &ulen);
828 if (nftnl_udata_parse(udata, ulen, table_parse_udata_cb, ud) < 0) {
829 netlink_io_error(ctx, NULL, "Cannot parse userdata");
830 table_free(table);
831 return NULL;
832 }
833 if (ud[NFTNL_UDATA_TABLE_COMMENT])
834 table->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_TABLE_COMMENT]));
835 }
836
837 return table;
838}
839
840static int list_table_cb(struct nftnl_table *nlt, void *arg)
841{
842 struct netlink_ctx *ctx = arg;
843 struct table *table;
844
845 table = netlink_delinearize_table(ctx, nlt);
846 list_add_tail(&table->list, &ctx->list);
847
848 return 0;
849}
850
851int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h,
852 const struct nft_cache_filter *filter)
853{
854 struct nftnl_table_list *table_cache;
855 uint32_t family = h->family;
856 const char *table = NULL;
857
858 if (filter) {
859 family = filter->list.family;
860 table = filter->list.table;
861 }
862
863 table_cache = mnl_nft_table_dump(ctx, family, table);
864 if (table_cache == NULL) {
865 if (errno == EINTR)
866 return -1;
867
868 return -1;
869 }
870
871 ctx->data = h;
872 nftnl_table_list_foreach(table_cache, list_table_cb, ctx);
873 nftnl_table_list_free(table_cache);
874 return 0;
875}
876
877enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
878{
879 switch (dtype->type) {
880 case TYPE_VERDICT:
881 return NFT_DATA_VERDICT;
882 default:
883 return dtype->type;
884 }
885}
886
887static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
888{
889 /* The function always returns ownership of a reference. But for
890 * &verdict_Type and datatype_lookup(), those are static instances,
891 * we can omit the datatype_get() call.
892 */
893 switch (type) {
894 case NFT_DATA_VERDICT:
895 return &verdict_type;
896 default:
897 if (type & ~TYPE_MASK)
898 return concat_type_alloc(type);
899 return datatype_lookup((enum datatypes) type);
900 }
901}
902
903void netlink_dump_set(const struct nftnl_set *nls, struct netlink_ctx *ctx)
904{
905 FILE *fp = ctx->nft->output.output_fp;
906 uint32_t family;
907
908 if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
909 return;
910
911 family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
912 fprintf(fp, "family %d ", family);
913 nftnl_set_fprintf(fp, nls, 0, 0);
914 fprintf(fp, "\n");
915}
916
917static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data)
918{
919 unsigned char *value = nftnl_udata_get(attr);
920 const struct nftnl_udata **tb = data;
921 uint8_t type = nftnl_udata_type(attr);
922 uint8_t len = nftnl_udata_len(attr);
923
924 switch (type) {
925 case NFTNL_UDATA_SET_KEYBYTEORDER:
926 case NFTNL_UDATA_SET_DATABYTEORDER:
927 case NFTNL_UDATA_SET_MERGE_ELEMENTS:
928 case NFTNL_UDATA_SET_DATA_INTERVAL:
929 if (len != sizeof(uint32_t))
930 return -1;
931 break;
932 case NFTNL_UDATA_SET_KEY_TYPEOF:
933 case NFTNL_UDATA_SET_DATA_TYPEOF:
934 if (len < 3)
935 return -1;
936 break;
937 case NFTNL_UDATA_SET_COMMENT:
938 if (value[len - 1] != '\0')
939 return -1;
940 break;
941 default:
942 return 0;
943 }
944 tb[type] = attr;
945 return 0;
946}
947
948static int set_key_parse_udata(const struct nftnl_udata *attr, void *data)
949{
950 const struct nftnl_udata **tb = data;
951 uint8_t type = nftnl_udata_type(attr);
952 uint8_t len = nftnl_udata_len(attr);
953
954 switch (type) {
955 case NFTNL_UDATA_SET_TYPEOF_EXPR:
956 if (len != sizeof(uint32_t))
957 return -1;
958 break;
959 case NFTNL_UDATA_SET_TYPEOF_DATA:
960 break;
961 default:
962 return 0;
963 }
964 tb[type] = attr;
965 return 0;
966}
967
968static struct expr *set_make_key(const struct nftnl_udata *attr)
969{
970 const struct nftnl_udata *ud[NFTNL_UDATA_SET_TYPEOF_MAX + 1] = {};
971 const struct expr_ops *ops;
972 struct expr *expr;
973 uint32_t etype;
974 int err;
975
976 if (!attr)
977 return NULL;
978
979 err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
980 set_key_parse_udata, ud);
981 if (err < 0)
982 return NULL;
983
984 if (!ud[NFTNL_UDATA_SET_TYPEOF_EXPR] ||
985 !ud[NFTNL_UDATA_SET_TYPEOF_DATA])
986 return NULL;
987
988 etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]);
989 ops = expr_ops_by_type_u32(etype);
990 if (!ops || !ops->parse_udata)
991 return NULL;
992
993 expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]);
994 if (!expr)
995 return NULL;
996
997 return expr;
998}
999
1000static bool set_udata_key_valid(const struct expr *e, uint32_t len)
1001{
1002 if (!e)
1003 return false;
1004
1005 return div_round_up(e->len, BITS_PER_BYTE) == len / BITS_PER_BYTE;
1006}
1007
1008struct setelem_parse_ctx {
1009 struct set *set;
1010 struct nft_cache *cache;
1011 struct list_head stmt_list;
1012};
1013
1014static int set_elem_parse_expressions(struct nftnl_expr *e, void *data)
1015{
1016 struct setelem_parse_ctx *setelem_parse_ctx = data;
1017 struct nft_cache *cache = setelem_parse_ctx->cache;
1018 struct set *set = setelem_parse_ctx->set;
1019 struct stmt *stmt;
1020
1021 stmt = netlink_parse_set_expr(set, cache, e);
1022 if (stmt)
1023 list_add_tail(&stmt->list, &setelem_parse_ctx->stmt_list);
1024
1025 return 0;
1026}
1027
1028struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
1029 const struct nftnl_set *nls)
1030{
1031 const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
1032 enum byteorder keybyteorder = BYTEORDER_INVALID;
1033 enum byteorder databyteorder = BYTEORDER_INVALID;
1034 struct setelem_parse_ctx set_parse_ctx;
1035 const struct datatype *datatype = NULL;
1036 const struct datatype *keytype = NULL;
1037 const struct datatype *dtype2 = NULL;
1038 const struct datatype *dtype = NULL;
1039 struct expr *typeof_expr_data = NULL;
1040 struct expr *typeof_expr_key = NULL;
1041 const char *udata, *comment = NULL;
1042 uint32_t flags, key, objtype = 0;
1043 uint32_t data_interval = 0;
1044 bool automerge = false;
1045 struct set *set;
1046 uint32_t ulen;
1047 uint32_t klen;
1048
1049 if (nftnl_set_is_set(nls, NFTNL_SET_USERDATA)) {
1050 udata = nftnl_set_get_data(nls, NFTNL_SET_USERDATA, &ulen);
1051 if (nftnl_udata_parse(udata, ulen, set_parse_udata_cb, ud) < 0) {
1052 netlink_io_error(ctx, NULL, "Cannot parse userdata");
1053 return NULL;
1054 }
1055
1056#define GET_U32_UDATA(var, attr) \
1057 if (ud[attr]) \
1058 var = nftnl_udata_get_u32(ud[attr])
1059
1060 GET_U32_UDATA(keybyteorder, NFTNL_UDATA_SET_KEYBYTEORDER);
1061 GET_U32_UDATA(databyteorder, NFTNL_UDATA_SET_DATABYTEORDER);
1062 GET_U32_UDATA(automerge, NFTNL_UDATA_SET_MERGE_ELEMENTS);
1063 GET_U32_UDATA(data_interval, NFTNL_UDATA_SET_DATA_INTERVAL);
1064
1065#undef GET_U32_UDATA
1066 typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_KEY_TYPEOF]);
1067 if (ud[NFTNL_UDATA_SET_DATA_TYPEOF])
1068 typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_DATA_TYPEOF]);
1069 if (ud[NFTNL_UDATA_SET_COMMENT])
1070 comment = nftnl_udata_get(ud[NFTNL_UDATA_SET_COMMENT]);
1071 }
1072
1073 key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE);
1074 keytype = dtype_map_from_kernel(key);
1075 if (keytype == NULL) {
1076 netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
1077 key);
1078 return NULL;
1079 }
1080
1081 flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
1082 if (set_is_datamap(flags)) {
1083 uint32_t data;
1084
1085 data = nftnl_set_get_u32(nls, NFTNL_SET_DATA_TYPE);
1086 datatype = dtype_map_from_kernel(data);
1087 if (datatype == NULL) {
1088 netlink_io_error(ctx, NULL,
1089 "Unknown data type in set key %u",
1090 data);
1091 set = NULL;
1092 goto out;
1093 }
1094 }
1095
1096 if (set_is_objmap(flags)) {
1097 objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE);
1098 assert(!datatype);
1099 datatype = &string_type;
1100 }
1101
1102 set = set_alloc(&netlink_location);
1103 set->handle.family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
1104 set->handle.table.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_TABLE));
1105 set->handle.set.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME));
1106 set->automerge = automerge;
1107 if (comment)
1108 set->comment = xstrdup(comment);
1109
1110 init_list_head(&set_parse_ctx.stmt_list);
1111
1112 if (nftnl_set_is_set(nls, NFTNL_SET_EXPR)) {
1113 const struct nftnl_expr *nle;
1114 struct stmt *stmt;
1115
1116 nle = nftnl_set_get(nls, NFTNL_SET_EXPR);
1117 stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
1118 list_add_tail(&stmt->list, &set_parse_ctx.stmt_list);
1119 } else if (nftnl_set_is_set(nls, NFTNL_SET_EXPRESSIONS)) {
1120 set_parse_ctx.cache = &ctx->nft->cache;
1121 set_parse_ctx.set = set;
1122 nftnl_set_expr_foreach(nls, set_elem_parse_expressions,
1123 &set_parse_ctx);
1124 }
1125 list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list);
1126
1127 set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
1128
1129 if (datatype) {
1130 uint32_t dlen;
1131
1132 dtype2 = set_datatype_alloc(datatype, databyteorder);
1133 klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE;
1134
1135 dlen = data_interval ? klen / 2 : klen;
1136
1137 if (set_udata_key_valid(typeof_expr_data, dlen)) {
1138 typeof_expr_data->len = klen;
1139 set->data = typeof_expr_data;
1140 typeof_expr_data = NULL;
1141 } else if (set->flags & NFT_SET_OBJECT) {
1142 set->data = constant_expr_alloc(&netlink_location,
1143 dtype2,
1144 databyteorder, klen,
1145 NULL);
1146 } else {
1147 set->data = constant_expr_alloc(&netlink_location,
1148 dtype2,
1149 databyteorder, klen,
1150 NULL);
1151
1152 /* Can't use 'typeof' keyword, so discard key too */
1153 expr_free(typeof_expr_key);
1154 typeof_expr_key = NULL;
1155 }
1156
1157 if (data_interval)
1158 set->data->flags |= EXPR_F_INTERVAL;
1159 }
1160
1161 dtype = set_datatype_alloc(keytype, keybyteorder);
1162 klen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE;
1163
1164 if (set_udata_key_valid(typeof_expr_key, klen)) {
1165 set->key = typeof_expr_key;
1166 typeof_expr_key = NULL;
1167 set->key_typeof_valid = true;
1168 } else {
1169 set->key = constant_expr_alloc(&netlink_location, dtype,
1170 keybyteorder, klen,
1171 NULL);
1172 }
1173
1174 set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
1175
1176 set->objtype = objtype;
1177
1178 if (nftnl_set_is_set(nls, NFTNL_SET_TIMEOUT))
1179 set->timeout = nftnl_set_get_u64(nls, NFTNL_SET_TIMEOUT);
1180 if (nftnl_set_is_set(nls, NFTNL_SET_GC_INTERVAL))
1181 set->gc_int = nftnl_set_get_u32(nls, NFTNL_SET_GC_INTERVAL);
1182
1183 if (nftnl_set_is_set(nls, NFTNL_SET_POLICY))
1184 set->policy = nftnl_set_get_u32(nls, NFTNL_SET_POLICY);
1185
1186 if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE))
1187 set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE);
1188
1189 if (nftnl_set_is_set(nls, NFTNL_SET_COUNT))
1190 set->count = nftnl_set_get_u32(nls, NFTNL_SET_COUNT);
1191
1192 if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) {
1193 uint32_t len = NFT_REG32_COUNT;
1194 const uint8_t *data;
1195
1196 data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len);
1197 if (data) {
1198 memcpy(set->desc.field_len, data, len);
1199 set->desc.field_count = len;
1200 }
1201 }
1202
1203out:
1204 expr_free(typeof_expr_data);
1205 expr_free(typeof_expr_key);
1206 datatype_free(datatype);
1207 datatype_free(keytype);
1208 datatype_free(dtype2);
1209 datatype_free(dtype);
1210 return set;
1211}
1212
1213void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
1214{
1215 struct nftnl_set_elem *nlse;
1216 const struct expr *expr;
1217
1218 list_for_each_entry(expr, &set->expressions, list) {
1219 nlse = alloc_nftnl_setelem(set, expr);
1220 nftnl_set_elem_add(nls, nlse);
1221 }
1222}
1223
1224static bool range_expr_is_prefix(const struct expr *range, uint32_t *prefix_len)
1225{
1226 const struct expr *right = range->right;
1227 const struct expr *left = range->left;
1228 uint32_t len = left->len;
1229 unsigned long n1, n2;
1230 uint32_t plen;
1231 mpz_t bitmask;
1232
1233 mpz_init2(bitmask, left->len);
1234 mpz_xor(bitmask, left->value, right->value);
1235
1236 n1 = mpz_scan0(bitmask, 0);
1237 if (n1 == ULONG_MAX)
1238 goto not_a_prefix;
1239
1240 n2 = mpz_scan1(bitmask, n1 + 1);
1241 if (n2 < len)
1242 goto not_a_prefix;
1243
1244 plen = len - n1;
1245
1246 if (mpz_scan1(left->value, 0) < len - plen)
1247 goto not_a_prefix;
1248
1249 mpz_clear(bitmask);
1250 *prefix_len = plen;
1251
1252 return true;
1253
1254not_a_prefix:
1255 mpz_clear(bitmask);
1256
1257 return false;
1258}
1259
1260struct expr *range_expr_to_prefix(struct expr *range)
1261{
1262 struct expr *prefix;
1263 uint32_t prefix_len;
1264
1265 if (range_expr_is_prefix(range, &prefix_len)) {
1266 prefix = prefix_expr_alloc(&range->location,
1267 expr_get(range->left),
1268 prefix_len);
1269 expr_free(range);
1270 return prefix;
1271 }
1272
1273 return range;
1274}
1275
1276static struct expr *range_expr_reduce(struct expr *range)
1277{
1278 struct expr *expr;
1279
1280 if (!mpz_cmp(range->left->value, range->right->value)) {
1281 expr = expr_get(range->left);
1282 expr_free(range);
1283 return expr;
1284 }
1285
1286 if (range->left->dtype->type != TYPE_IPADDR &&
1287 range->left->dtype->type != TYPE_IP6ADDR)
1288 return range;
1289
1290 return range_expr_to_prefix(range);
1291}
1292
1293static struct expr *netlink_parse_interval_elem(const struct set *set,
1294 struct expr *expr)
1295{
1296 unsigned int len = netlink_padded_len(expr->len) / BITS_PER_BYTE;
1297 const struct datatype *dtype = set->data->dtype;
1298 struct expr *range, *left, *right;
1299 char data[NFT_MAX_EXPR_LEN_BYTES];
1300
1301 if (len > sizeof(data))
1302 BUG("Value export of %u bytes would overflow", len);
1303
1304 memset(data, 0, sizeof(data));
1305
1306 mpz_export_data(data, expr->value, dtype->byteorder, len);
1307 left = constant_expr_alloc(&internal_location, dtype,
1308 dtype->byteorder,
1309 (len / 2) * BITS_PER_BYTE, &data[0]);
1310 right = constant_expr_alloc(&internal_location, dtype,
1311 dtype->byteorder,
1312 (len / 2) * BITS_PER_BYTE, &data[len / 2]);
1313 range = range_expr_alloc(&expr->location, left, right);
1314 expr_free(expr);
1315
1316 return range_expr_to_prefix(range);
1317}
1318
1319static struct expr *concat_elem_expr(const struct set *set, struct expr *key,
1320 const struct datatype *dtype,
1321 struct expr *data, int *off)
1322{
1323 const struct datatype *subtype;
1324 unsigned int sub_length;
1325 struct expr *expr;
1326
1327 if (key) {
1328 (*off)--;
1329 sub_length = round_up(key->len, BITS_PER_BYTE);
1330
1331 expr = constant_expr_splice(data, sub_length);
1332 expr->dtype = datatype_get(key->dtype);
1333 expr->byteorder = key->byteorder;
1334 expr->len = key->len;
1335 } else {
1336 subtype = concat_subtype_lookup(dtype->type, --(*off));
1337 sub_length = round_up(subtype->size, BITS_PER_BYTE);
1338 expr = constant_expr_splice(data, sub_length);
1339 expr->dtype = subtype;
1340 expr->byteorder = subtype->byteorder;
1341 }
1342
1343 if (expr_basetype(expr)->type == TYPE_STRING ||
1344 (!(set->flags & NFT_SET_INTERVAL) &&
1345 expr->byteorder == BYTEORDER_HOST_ENDIAN))
1346 mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
1347
1348 if (expr->dtype->basetype != NULL &&
1349 expr->dtype->basetype->type == TYPE_BITMASK)
1350 expr = bitmask_expr_to_binops(expr);
1351
1352 data->len -= netlink_padding_len(sub_length);
1353
1354 return expr;
1355}
1356
1357static struct expr *netlink_parse_concat_elem_key(const struct set *set,
1358 struct expr *data)
1359{
1360 const struct datatype *dtype = set->key->dtype;
1361 struct expr *concat, *expr, *n = NULL;
1362 int off = dtype->subtypes;
1363
1364 if (set->key->etype == EXPR_CONCAT)
1365 n = list_first_entry(&set->key->expressions, struct expr, list);
1366
1367 concat = concat_expr_alloc(&data->location);
1368 while (off > 0) {
1369 expr = concat_elem_expr(set, n, dtype, data, &off);
1370 compound_expr_add(concat, expr);
1371 if (set->key->etype == EXPR_CONCAT)
1372 n = list_next_entry(n, list);
1373 }
1374
1375 expr_free(data);
1376
1377 return concat;
1378}
1379
1380static struct expr *netlink_parse_concat_elem(const struct set *set,
1381 struct expr *data)
1382{
1383 const struct datatype *dtype = set->data->dtype;
1384 struct expr *concat, *expr, *left, *range;
1385 struct list_head expressions;
1386 int off = dtype->subtypes;
1387
1388 init_list_head(&expressions);
1389
1390 concat = concat_expr_alloc(&data->location);
1391 while (off > 0) {
1392 expr = concat_elem_expr(set, NULL, dtype, data, &off);
1393 list_add_tail(&expr->list, &expressions);
1394 }
1395
1396 if (set->data->flags & EXPR_F_INTERVAL) {
1397 assert(!list_empty(&expressions));
1398
1399 off = dtype->subtypes;
1400
1401 while (off > 0) {
1402 left = list_first_entry(&expressions, struct expr, list);
1403
1404 expr = concat_elem_expr(set, NULL, dtype, data, &off);
1405 list_del(&left->list);
1406
1407 range = range_expr_alloc(&data->location, left, expr);
1408 range = range_expr_reduce(range);
1409 compound_expr_add(concat, range);
1410 }
1411 assert(list_empty(&expressions));
1412 } else {
1413 list_splice_tail(&expressions, &concat->expressions);
1414 }
1415
1416 expr_free(data);
1417
1418 return concat;
1419}
1420
1421static int set_elem_parse_udata_cb(const struct nftnl_udata *attr, void *data)
1422{
1423 const struct nftnl_udata **tb = data;
1424 unsigned char *value = nftnl_udata_get(attr);
1425 uint8_t type = nftnl_udata_type(attr);
1426 uint8_t len = nftnl_udata_len(attr);
1427
1428 switch (type) {
1429 case NFTNL_UDATA_SET_ELEM_COMMENT:
1430 if (value[len - 1] != '\0')
1431 return -1;
1432 break;
1433 case NFTNL_UDATA_SET_ELEM_FLAGS:
1434 if (len != sizeof(uint32_t))
1435 return -1;
1436 break;
1437 default:
1438 return 0;
1439 }
1440 tb[type] = attr;
1441 return 0;
1442}
1443
1444static void set_elem_parse_udata(struct nftnl_set_elem *nlse,
1445 struct expr *expr)
1446{
1447 const struct nftnl_udata *ud[NFTNL_UDATA_SET_ELEM_MAX + 1] = {};
1448 const void *data;
1449 uint32_t len;
1450
1451 data = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_USERDATA, &len);
1452 if (nftnl_udata_parse(data, len, set_elem_parse_udata_cb, ud))
1453 return;
1454
1455 if (ud[NFTNL_UDATA_SET_ELEM_COMMENT])
1456 expr->comment =
1457 xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_SET_ELEM_COMMENT]));
1458 if (ud[NFTNL_UDATA_SET_ELEM_FLAGS]) {
1459 uint32_t elem_flags;
1460
1461 elem_flags =
1462 nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_ELEM_FLAGS]);
1463 if (elem_flags & NFTNL_SET_ELEM_F_INTERVAL_OPEN)
1464 expr->flags |= EXPR_F_INTERVAL_OPEN;
1465 }
1466}
1467
1468int netlink_delinearize_setelem(struct netlink_ctx *ctx,
1469 struct nftnl_set_elem *nlse,
1470 struct set *set)
1471{
1472 struct setelem_parse_ctx setelem_parse_ctx = {
1473 .set = set,
1474 .cache = &ctx->nft->cache,
1475 };
1476 struct nft_data_delinearize nld;
1477 struct expr *expr, *key, *data;
1478 uint32_t flags = 0;
1479
1480 init_list_head(&setelem_parse_ctx.stmt_list);
1481
1482 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY))
1483 nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len);
1484 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
1485 flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
1486
1487key_end:
1488 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY)) {
1489 key = netlink_alloc_value(&netlink_location, &nld);
1490 datatype_set(key, set->key->dtype);
1491 key->byteorder = set->key->byteorder;
1492 if (set->key->dtype->subtypes)
1493 key = netlink_parse_concat_elem_key(set, key);
1494
1495 if (!(set->flags & NFT_SET_INTERVAL) &&
1496 key->byteorder == BYTEORDER_HOST_ENDIAN)
1497 mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
1498
1499 if (key->dtype->basetype != NULL &&
1500 key->dtype->basetype->type == TYPE_BITMASK)
1501 key = bitmask_expr_to_binops(key);
1502 } else if (flags & NFT_SET_ELEM_CATCHALL) {
1503 key = set_elem_catchall_expr_alloc(&netlink_location);
1504 datatype_set(key, set->key->dtype);
1505 key->byteorder = set->key->byteorder;
1506 key->len = set->key->len;
1507 } else {
1508 netlink_io_error(ctx, NULL,
1509 "Unexpected set element with no key");
1510 return 0;
1511 }
1512
1513 expr = set_elem_expr_alloc(&netlink_location, key);
1514 expr->flags |= EXPR_F_KERNEL;
1515
1516 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) {
1517 expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
1518 if (expr->timeout == 0)
1519 expr->timeout = NFT_NEVER_TIMEOUT;
1520 }
1521
1522 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION))
1523 expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION);
1524 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA)) {
1525 set_elem_parse_udata(nlse, expr);
1526 if (expr->comment)
1527 set->elem_has_comment = true;
1528 }
1529 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) {
1530 const struct nftnl_expr *nle;
1531 struct stmt *stmt;
1532
1533 nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL);
1534 stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
1535 list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list);
1536 } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) {
1537 nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions,
1538 &setelem_parse_ctx);
1539 }
1540 list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list);
1541
1542 if (flags & NFT_SET_ELEM_INTERVAL_END) {
1543 expr->flags |= EXPR_F_INTERVAL_END;
1544 if (mpz_cmp_ui(set->key->value, 0) == 0)
1545 set->root = true;
1546 }
1547
1548 if (set_is_datamap(set->flags)) {
1549 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) {
1550 nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_DATA,
1551 &nld.len);
1552 } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_CHAIN)) {
1553 nld.chain = nftnl_set_elem_get_str(nlse, NFTNL_SET_ELEM_CHAIN);
1554 nld.verdict = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_VERDICT);
1555 } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_VERDICT)) {
1556 nld.verdict = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_VERDICT);
1557 } else
1558 goto out;
1559
1560 data = netlink_alloc_data(&netlink_location, &nld,
1561 set->data->dtype->type == TYPE_VERDICT ?
1562 NFT_REG_VERDICT : NFT_REG_1);
1563
1564 if (set->data->dtype->is_typeof)
1565 datatype_set(data, set->data->dtype->basetype);
1566 else
1567 datatype_set(data, set->data->dtype);
1568 data->byteorder = set->data->byteorder;
1569
1570 if (set->data->dtype->subtypes) {
1571 data = netlink_parse_concat_elem(set, data);
1572 } else if (set->data->flags & EXPR_F_INTERVAL)
1573 data = netlink_parse_interval_elem(set, data);
1574
1575 if (data->byteorder == BYTEORDER_HOST_ENDIAN)
1576 mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
1577
1578 expr = mapping_expr_alloc(&netlink_location, expr, data);
1579 }
1580 if (set_is_objmap(set->flags)) {
1581 if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_OBJREF)) {
1582 nld.value = nftnl_set_elem_get(nlse,
1583 NFTNL_SET_ELEM_OBJREF,
1584 &nld.len);
1585 } else
1586 goto out;
1587
1588 data = netlink_alloc_value(&netlink_location, &nld);
1589 data->dtype = &string_type;
1590 data->byteorder = BYTEORDER_HOST_ENDIAN;
1591 mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
1592 expr = mapping_expr_alloc(&netlink_location, expr, data);
1593 }
1594out:
1595 compound_expr_add(set->init, expr);
1596
1597 if (!(flags & NFT_SET_ELEM_INTERVAL_END) &&
1598 nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY_END)) {
1599 flags |= NFT_SET_ELEM_INTERVAL_END;
1600 nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY_END,
1601 &nld.len);
1602 goto key_end;
1603 }
1604
1605 return 0;
1606}
1607
1608static int list_setelem_cb(struct nftnl_set_elem *nlse, void *arg)
1609{
1610 struct netlink_ctx *ctx = arg;
1611 return netlink_delinearize_setelem(ctx, nlse, ctx->set);
1612}
1613
1614static int list_setelem_debug_cb(struct nftnl_set_elem *nlse, void *arg)
1615{
1616 int r;
1617
1618 r = list_setelem_cb(nlse, arg);
1619 if (r == 0) {
1620 struct netlink_ctx *ctx = arg;
1621 FILE *fp = ctx->nft->output.output_fp;
1622
1623 fprintf(fp, "\t");
1624 nftnl_set_elem_fprintf(fp, nlse, 0, 0);
1625 fprintf(fp, "\n");
1626 }
1627
1628 return r;
1629}
1630
1631static int list_setelements(struct nftnl_set *s, struct netlink_ctx *ctx)
1632{
1633 FILE *fp = ctx->nft->output.output_fp;
1634
1635 if (fp && (ctx->nft->debug_mask & NFT_DEBUG_NETLINK)) {
1636 const char *table, *name;
1637 uint32_t family = nftnl_set_get_u32(s, NFTNL_SET_FAMILY);
1638
1639 table = nftnl_set_get_str(s, NFTNL_SET_TABLE);
1640 name = nftnl_set_get_str(s, NFTNL_SET_NAME);
1641
1642 fprintf(fp, "%s %s @%s\n", family2str(family), table, name);
1643
1644 return nftnl_set_elem_foreach(s, list_setelem_debug_cb, ctx);
1645 }
1646
1647 return nftnl_set_elem_foreach(s, list_setelem_cb, ctx);
1648}
1649
1650int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
1651 struct set *set, bool reset)
1652{
1653 struct nftnl_set *nls;
1654 int err;
1655
1656 nls = nftnl_set_alloc();
1657 if (nls == NULL)
1658 memory_allocation_error();
1659
1660 nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
1661 nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
1662 nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
1663 if (h->handle.id)
1664 nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
1665
1666 err = mnl_nft_setelem_get(ctx, nls, reset);
1667 if (err < 0) {
1668 nftnl_set_free(nls);
1669 if (errno == EINTR)
1670 return -1;
1671
1672 return 0;
1673 }
1674
1675 ctx->set = set;
1676 set->init = set_expr_alloc(&internal_location, set);
1677 list_setelements(nls, ctx);
1678
1679 if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
1680 concat_range_aggregate(set->init);
1681 else if (set->flags & NFT_SET_INTERVAL)
1682 interval_map_decompose(set->init);
1683 else
1684 list_expr_sort(&ctx->set->init->expressions);
1685
1686 nftnl_set_free(nls);
1687 ctx->set = NULL;
1688
1689 return 0;
1690}
1691
1692int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
1693 const struct location *loc, struct set *cache_set,
1694 struct set *set, struct expr *init, bool reset)
1695{
1696 struct nftnl_set *nls, *nls_out = NULL;
1697 int err = 0;
1698
1699 nls = nftnl_set_alloc();
1700 if (nls == NULL)
1701 memory_allocation_error();
1702
1703 nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
1704 nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
1705 nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
1706 if (h->handle.id)
1707 nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
1708
1709 alloc_setelem_cache(init, nls);
1710
1711 netlink_dump_set(nls, ctx);
1712
1713 nls_out = mnl_nft_setelem_get_one(ctx, nls, reset);
1714 if (!nls_out) {
1715 nftnl_set_free(nls);
1716 return -1;
1717 }
1718
1719 ctx->set = set;
1720 set->init = set_expr_alloc(loc, set);
1721 list_setelements(nls_out, ctx);
1722
1723 if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
1724 concat_range_aggregate(set->init);
1725 else if (set->flags & NFT_SET_INTERVAL)
1726 err = get_set_decompose(cache_set, set);
1727 else
1728 list_expr_sort(&ctx->set->init->expressions);
1729
1730 nftnl_set_free(nls);
1731 nftnl_set_free(nls_out);
1732 ctx->set = NULL;
1733
1734 return err;
1735}
1736
1737void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx)
1738{
1739 FILE *fp = ctx->nft->output.output_fp;
1740
1741 if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
1742 return;
1743
1744 nftnl_obj_fprintf(fp, nln, 0, 0);
1745 fprintf(fp, "\n");
1746}
1747
1748static int obj_parse_udata_cb(const struct nftnl_udata *attr, void *data)
1749{
1750 unsigned char *value = nftnl_udata_get(attr);
1751 uint8_t type = nftnl_udata_type(attr);
1752 const struct nftnl_udata **tb = data;
1753 uint8_t len = nftnl_udata_len(attr);
1754
1755 switch (type) {
1756 case NFTNL_UDATA_OBJ_COMMENT:
1757 if (value[len - 1] != '\0')
1758 return -1;
1759 break;
1760 default:
1761 return 0;
1762 }
1763 tb[type] = attr;
1764 return 0;
1765}
1766
1767struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
1768 struct nftnl_obj *nlo)
1769{
1770 const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {};
1771 const char *udata;
1772 struct obj *obj;
1773 uint32_t type;
1774 uint32_t ulen;
1775
1776 obj = obj_alloc(&netlink_location);
1777 obj->handle.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
1778 obj->handle.table.name =
1779 xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE));
1780 obj->handle.obj.name =
1781 xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
1782 obj->handle.handle.id =
1783 nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
1784 if (nftnl_obj_is_set(nlo, NFTNL_OBJ_USERDATA)) {
1785 udata = nftnl_obj_get_data(nlo, NFTNL_OBJ_USERDATA, &ulen);
1786 if (nftnl_udata_parse(udata, ulen, obj_parse_udata_cb, ud) < 0) {
1787 netlink_io_error(ctx, NULL, "Cannot parse userdata");
1788 obj_free(obj);
1789 return NULL;
1790 }
1791 if (ud[NFTNL_UDATA_OBJ_COMMENT])
1792 obj->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_OBJ_COMMENT]));
1793 }
1794
1795 type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
1796 switch (type) {
1797 case NFT_OBJECT_COUNTER:
1798 obj->counter.packets =
1799 nftnl_obj_get_u64(nlo, NFTNL_OBJ_CTR_PKTS);
1800 obj->counter.bytes =
1801 nftnl_obj_get_u64(nlo, NFTNL_OBJ_CTR_BYTES);
1802 break;
1803 case NFT_OBJECT_QUOTA:
1804 obj->quota.bytes =
1805 nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_BYTES);
1806 obj->quota.used =
1807 nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED);
1808 obj->quota.flags =
1809 nftnl_obj_get_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS);
1810 break;
1811 case NFT_OBJECT_SECMARK:
1812 snprintf(obj->secmark.ctx, sizeof(obj->secmark.ctx), "%s",
1813 nftnl_obj_get_str(nlo, NFTNL_OBJ_SECMARK_CTX));
1814 break;
1815 case NFT_OBJECT_CT_HELPER:
1816 snprintf(obj->ct_helper.name, sizeof(obj->ct_helper.name), "%s",
1817 nftnl_obj_get_str(nlo, NFTNL_OBJ_CT_HELPER_NAME));
1818 obj->ct_helper.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO);
1819 obj->ct_helper.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO);
1820 break;
1821 case NFT_OBJECT_CT_TIMEOUT:
1822 init_list_head(&obj->ct_timeout.timeout_list);
1823 obj->ct_timeout.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO);
1824 obj->ct_timeout.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO);
1825 if (nftnl_obj_is_set(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY))
1826 memcpy(obj->ct_timeout.timeout,
1827 nftnl_obj_get(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY),
1828 NFTNL_CTTIMEOUT_ARRAY_MAX * sizeof(uint32_t));
1829 break;
1830 case NFT_OBJECT_LIMIT:
1831 obj->limit.rate =
1832 nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_RATE);
1833 obj->limit.unit =
1834 nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_UNIT);
1835 obj->limit.burst =
1836 nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_BURST);
1837 obj->limit.type =
1838 nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_TYPE);
1839 obj->limit.flags =
1840 nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS);
1841 break;
1842 case NFT_OBJECT_CT_EXPECT:
1843 obj->ct_expect.l3proto =
1844 nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO);
1845 obj->ct_expect.l4proto =
1846 nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO);
1847 obj->ct_expect.dport =
1848 nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT);
1849 obj->ct_expect.timeout =
1850 nftnl_obj_get_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT);
1851 obj->ct_expect.size =
1852 nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE);
1853 break;
1854 case NFT_OBJECT_SYNPROXY:
1855 obj->synproxy.mss =
1856 nftnl_obj_get_u16(nlo, NFTNL_OBJ_SYNPROXY_MSS);
1857 obj->synproxy.wscale =
1858 nftnl_obj_get_u8(nlo, NFTNL_OBJ_SYNPROXY_WSCALE);
1859 obj->synproxy.flags =
1860 nftnl_obj_get_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS);
1861 break;
1862 default:
1863 netlink_io_error(ctx, NULL, "Unknown object type %u", type);
1864 obj_free(obj);
1865 return NULL;
1866 }
1867 obj->type = type;
1868
1869 return obj;
1870}
1871
1872void netlink_dump_flowtable(struct nftnl_flowtable *flo,
1873 struct netlink_ctx *ctx)
1874{
1875 FILE *fp = ctx->nft->output.output_fp;
1876
1877 if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
1878 return;
1879
1880 nftnl_flowtable_fprintf(fp, flo, 0, 0);
1881 fprintf(fp, "\n");
1882}
1883
1884struct flowtable *
1885netlink_delinearize_flowtable(struct netlink_ctx *ctx,
1886 struct nftnl_flowtable *nlo)
1887{
1888 struct flowtable *flowtable;
1889 const char * const *dev_array;
1890 int len = 0, i, priority;
1891
1892 flowtable = flowtable_alloc(&netlink_location);
1893 flowtable->handle.family =
1894 nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY);
1895 flowtable->handle.table.name =
1896 xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE));
1897 flowtable->handle.flowtable.name =
1898 xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME));
1899 flowtable->handle.handle.id =
1900 nftnl_flowtable_get_u64(nlo, NFTNL_FLOWTABLE_HANDLE);
1901 if (nftnl_flowtable_is_set(nlo, NFTNL_FLOWTABLE_FLAGS))
1902 flowtable->flags = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
1903 dev_array = nftnl_flowtable_get(nlo, NFTNL_FLOWTABLE_DEVICES);
1904 while (dev_array && dev_array[len])
1905 len++;
1906
1907 if (len)
1908 flowtable->dev_array = xmalloc(len * sizeof(char *));
1909 for (i = 0; i < len; i++)
1910 flowtable->dev_array[i] = xstrdup(dev_array[i]);
1911
1912 flowtable->dev_array_len = len;
1913
1914 if (flowtable->dev_array_len) {
1915 qsort(flowtable->dev_array, flowtable->dev_array_len,
1916 sizeof(char *), qsort_device_cmp);
1917 }
1918
1919 if (nftnl_flowtable_is_set(nlo, NFTNL_FLOWTABLE_PRIO)) {
1920 priority = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_PRIO);
1921 flowtable->priority.expr =
1922 constant_expr_alloc(&netlink_location,
1923 &integer_type,
1924 BYTEORDER_HOST_ENDIAN,
1925 sizeof(int) *
1926 BITS_PER_BYTE,
1927 &priority);
1928 }
1929 flowtable->hook.num =
1930 nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM);
1931 flowtable->flags =
1932 nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
1933
1934 return flowtable;
1935}
1936
1937static int list_flowtable_cb(struct nftnl_flowtable *nls, void *arg)
1938{
1939 struct netlink_ctx *ctx = arg;
1940 struct flowtable *flowtable;
1941
1942 flowtable = netlink_delinearize_flowtable(ctx, nls);
1943 if (flowtable == NULL)
1944 return -1;
1945 list_add_tail(&flowtable->list, &ctx->list);
1946 return 0;
1947}
1948
1949int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h)
1950{
1951 struct nftnl_flowtable_list *flowtable_cache;
1952 int err;
1953
1954 flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family,
1955 h->table.name, NULL);
1956 if (flowtable_cache == NULL) {
1957 if (errno == EINTR)
1958 return -1;
1959
1960 return 0;
1961 }
1962
1963 err = nftnl_flowtable_list_foreach(flowtable_cache, list_flowtable_cb, ctx);
1964 nftnl_flowtable_list_free(flowtable_cache);
1965 return err;
1966}
1967
1968static void trace_print_hdr(const struct nftnl_trace *nlt,
1969 struct output_ctx *octx)
1970{
1971 nft_print(octx, "trace id %08x %s ",
1972 nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
1973 family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY)));
1974 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE))
1975 nft_print(octx, "%s ",
1976 nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE));
1977 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN))
1978 nft_print(octx, "%s ",
1979 nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
1980}
1981
1982static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr,
1983 struct expr *lhs, struct output_ctx *octx)
1984{
1985 struct expr *rhs, *rel;
1986 const void *data;
1987 uint32_t len;
1988
1989 data = nftnl_trace_get_data(nlt, attr, &len);
1990 rhs = constant_expr_alloc(&netlink_location,
1991 lhs->dtype, lhs->byteorder,
1992 len * BITS_PER_BYTE, data);
1993 rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs);
1994
1995 expr_print(rel, octx);
1996 nft_print(octx, " ");
1997 expr_free(rel);
1998}
1999
2000static void trace_print_verdict(const struct nftnl_trace *nlt,
2001 struct output_ctx *octx)
2002{
2003 struct expr *chain_expr = NULL;
2004 const char *chain = NULL;
2005 unsigned int verdict;
2006 struct expr *expr;
2007
2008 verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
2009 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) {
2010 chain = xstrdup(nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET));
2011 chain_expr = constant_expr_alloc(&netlink_location,
2012 &string_type,
2013 BYTEORDER_HOST_ENDIAN,
2014 strlen(chain) * BITS_PER_BYTE,
2015 chain);
2016 }
2017 expr = verdict_expr_alloc(&netlink_location, verdict, chain_expr);
2018
2019 nft_print(octx, "verdict ");
2020 expr_print(expr, octx);
2021 expr_free(expr);
2022}
2023
2024static void trace_print_policy(const struct nftnl_trace *nlt,
2025 struct output_ctx *octx)
2026{
2027 unsigned int policy;
2028 struct expr *expr;
2029
2030 policy = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY);
2031
2032 expr = verdict_expr_alloc(&netlink_location, policy, NULL);
2033
2034 nft_print(octx, "policy ");
2035 expr_print(expr, octx);
2036 expr_free(expr);
2037}
2038
2039static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt,
2040 uint64_t rule_handle,
2041 struct nft_cache *cache)
2042{
2043 struct chain *chain;
2044 struct table *table;
2045 struct handle h;
2046
2047 h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
2048 h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
2049 h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
2050
2051 if (!h.table.name)
2052 return NULL;
2053
2054 table = table_cache_find(&cache->table_cache, h.table.name, h.family);
2055 if (!table)
2056 return NULL;
2057
2058 chain = chain_cache_find(table, h.chain.name);
2059 if (!chain)
2060 return NULL;
2061
2062 return rule_lookup(chain, rule_handle);
2063}
2064
2065static void trace_print_rule(const struct nftnl_trace *nlt,
2066 struct output_ctx *octx, struct nft_cache *cache)
2067{
2068 uint64_t rule_handle;
2069 struct rule *rule;
2070
2071 rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE);
2072 rule = trace_lookup_rule(nlt, rule_handle, cache);
2073
2074 trace_print_hdr(nlt, octx);
2075
2076 if (rule) {
2077 nft_print(octx, "rule ");
2078 rule_print(rule, octx);
2079 } else {
2080 nft_print(octx, "unknown rule handle %" PRIu64, rule_handle);
2081 }
2082
2083 nft_print(octx, " (");
2084 trace_print_verdict(nlt, octx);
2085 nft_print(octx, ")\n");
2086}
2087
2088static void trace_gen_stmts(struct list_head *stmts,
2089 struct proto_ctx *ctx, struct payload_dep_ctx *pctx,
2090 const struct nftnl_trace *nlt, unsigned int attr,
2091 enum proto_bases base)
2092{
2093 struct list_head unordered = LIST_HEAD_INIT(unordered);
2094 struct list_head list;
2095 struct expr *rel, *lhs, *rhs, *tmp, *nexpr;
2096 struct stmt *stmt;
2097 const struct proto_desc *desc;
2098 const void *hdr;
2099 uint32_t hlen;
2100 unsigned int n;
2101
2102 if (!nftnl_trace_is_set(nlt, attr))
2103 return;
2104 hdr = nftnl_trace_get_data(nlt, attr, &hlen);
2105
2106 lhs = payload_expr_alloc(&netlink_location, NULL, 0);
2107 payload_init_raw(lhs, base, 0, hlen * BITS_PER_BYTE);
2108 rhs = constant_expr_alloc(&netlink_location,
2109 &invalid_type, BYTEORDER_INVALID,
2110 hlen * BITS_PER_BYTE, hdr);
2111
2112restart:
2113 init_list_head(&list);
2114 payload_expr_expand(&list, lhs, ctx);
2115 expr_free(lhs);
2116
2117 desc = NULL;
2118 list_for_each_entry_safe(lhs, nexpr, &list, list) {
2119 if (desc && desc != ctx->protocol[base].desc) {
2120 /* Chained protocols */
2121 lhs->payload.offset = 0;
2122 if (ctx->protocol[base].desc == NULL)
2123 break;
2124 goto restart;
2125 }
2126
2127 tmp = constant_expr_splice(rhs, lhs->len);
2128 expr_set_type(tmp, lhs->dtype, lhs->byteorder);
2129 if (tmp->byteorder == BYTEORDER_HOST_ENDIAN)
2130 mpz_switch_byteorder(tmp->value, tmp->len / BITS_PER_BYTE);
2131
2132 /* Skip unknown and filtered expressions */
2133 desc = lhs->payload.desc;
2134 if (lhs->dtype == &invalid_type ||
2135 lhs->payload.tmpl == &proto_unknown_template ||
2136 desc->checksum_key == payload_hdr_field(lhs) ||
2137 desc->format.filter & (1 << payload_hdr_field(lhs))) {
2138 expr_free(lhs);
2139 expr_free(tmp);
2140 continue;
2141 }
2142
2143 rel = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp);
2144 stmt = expr_stmt_alloc(&rel->location, rel);
2145 list_add_tail(&stmt->list, &unordered);
2146
2147 desc = ctx->protocol[base].desc;
2148 relational_expr_pctx_update(ctx, rel);
2149 }
2150
2151 expr_free(rhs);
2152
2153 n = 0;
2154next:
2155 list_for_each_entry(stmt, &unordered, list) {
2156 enum proto_bases b = base;
2157
2158 rel = stmt->expr;
2159 lhs = rel->left;
2160
2161 /* Move statements to result list in defined order */
2162 desc = lhs->payload.desc;
2163 if (desc->format.order[n] &&
2164 desc->format.order[n] != payload_hdr_field(lhs))
2165 continue;
2166
2167 list_move_tail(&stmt->list, stmts);
2168 n++;
2169
2170 if (payload_is_stacked(desc, rel))
2171 b--;
2172
2173 /* Don't strip 'icmp type' from payload dump. */
2174 if (pctx->icmp_type == 0)
2175 payload_dependency_kill(pctx, lhs, ctx->family);
2176 if (lhs->flags & EXPR_F_PROTOCOL)
2177 payload_dependency_store(pctx, stmt, b);
2178
2179 goto next;
2180 }
2181}
2182
2183static void trace_print_packet(const struct nftnl_trace *nlt,
2184 struct output_ctx *octx)
2185{
2186 struct list_head stmts = LIST_HEAD_INIT(stmts);
2187 const struct proto_desc *ll_desc;
2188 struct payload_dep_ctx pctx = {};
2189 struct proto_ctx ctx;
2190 uint16_t dev_type;
2191 uint32_t nfproto;
2192 struct stmt *stmt, *next;
2193
2194 trace_print_hdr(nlt, octx);
2195
2196 nft_print(octx, "packet: ");
2197 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
2198 trace_print_expr(nlt, NFTNL_TRACE_IIF,
2199 meta_expr_alloc(&netlink_location,
2200 NFT_META_IIF), octx);
2201 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
2202 trace_print_expr(nlt, NFTNL_TRACE_OIF,
2203 meta_expr_alloc(&netlink_location,
2204 NFT_META_OIF), octx);
2205
2206 proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0, false);
2207 ll_desc = ctx.protocol[PROTO_BASE_LL_HDR].desc;
2208 if ((ll_desc == &proto_inet || ll_desc == &proto_netdev) &&
2209 nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) {
2210 nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO);
2211
2212 proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, NULL);
2213 proto_ctx_update(&ctx, PROTO_BASE_NETWORK_HDR, &netlink_location,
2214 proto_find_upper(ll_desc, nfproto));
2215 }
2216 if (ctx.protocol[PROTO_BASE_LL_HDR].desc == NULL &&
2217 nftnl_trace_is_set(nlt, NFTNL_TRACE_IIFTYPE)) {
2218 dev_type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE);
2219 proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location,
2220 proto_dev_desc(dev_type));
2221 }
2222
2223 trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_LL_HEADER,
2224 PROTO_BASE_LL_HDR);
2225 trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_NETWORK_HEADER,
2226 PROTO_BASE_NETWORK_HDR);
2227 trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER,
2228 PROTO_BASE_TRANSPORT_HDR);
2229
2230 list_for_each_entry_safe(stmt, next, &stmts, list) {
2231 stmt_print(stmt, octx);
2232 nft_print(octx, " ");
2233 stmt_free(stmt);
2234 }
2235 nft_print(octx, "\n");
2236}
2237
2238int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
2239 struct netlink_mon_handler *monh)
2240{
2241 struct nftnl_trace *nlt;
2242
2243 assert(type == NFT_MSG_TRACE);
2244
2245 nlt = nftnl_trace_alloc();
2246 if (!nlt)
2247 memory_allocation_error();
2248
2249 if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
2250 netlink_abi_error();
2251
2252 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
2253 nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
2254 trace_print_packet(nlt, &monh->ctx->nft->output);
2255
2256 switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
2257 case NFT_TRACETYPE_RULE:
2258 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE))
2259 trace_print_rule(nlt, &monh->ctx->nft->output,
2260 &monh->ctx->nft->cache);
2261 break;
2262 case NFT_TRACETYPE_POLICY:
2263 trace_print_hdr(nlt, &monh->ctx->nft->output);
2264
2265 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_POLICY)) {
2266 trace_print_policy(nlt, &monh->ctx->nft->output);
2267 nft_mon_print(monh, " ");
2268 }
2269
2270 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK))
2271 trace_print_expr(nlt, NFTNL_TRACE_MARK,
2272 meta_expr_alloc(&netlink_location,
2273 NFT_META_MARK),
2274 &monh->ctx->nft->output);
2275 nft_mon_print(monh, "\n");
2276 break;
2277 case NFT_TRACETYPE_RETURN:
2278 trace_print_hdr(nlt, &monh->ctx->nft->output);
2279
2280 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) {
2281 trace_print_verdict(nlt, &monh->ctx->nft->output);
2282 nft_mon_print(monh, " ");
2283 }
2284
2285 if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK))
2286 trace_print_expr(nlt, NFTNL_TRACE_MARK,
2287 meta_expr_alloc(&netlink_location,
2288 NFT_META_MARK),
2289 &monh->ctx->nft->output);
2290 nft_mon_print(monh, "\n");
2291 break;
2292 }
2293
2294 nftnl_trace_free(nlt);
2295 return MNL_CB_OK;
2296}