libnftnl 1.2.9
rule.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6 */
7#include "internal.h"
8
9#include <time.h>
10#include <endian.h>
11#include <stdint.h>
12#include <stdlib.h>
13#include <limits.h>
14#include <string.h>
15#include <netinet/in.h>
16#include <errno.h>
17#include <inttypes.h>
18#include <ctype.h>
19
20#include <libmnl/libmnl.h>
21#include <linux/netfilter/nfnetlink.h>
22#include <linux/netfilter/nf_tables.h>
23
24#include <libnftnl/rule.h>
25#include <libnftnl/set.h>
26#include <libnftnl/expr.h>
27
28EXPORT_SYMBOL(nftnl_rule_alloc);
29struct nftnl_rule *nftnl_rule_alloc(void)
30{
31 struct nftnl_rule *r;
32
33 r = calloc(1, sizeof(struct nftnl_rule));
34 if (r == NULL)
35 return NULL;
36
37 INIT_LIST_HEAD(&r->expr_list);
38
39 return r;
40}
41
42EXPORT_SYMBOL(nftnl_rule_free);
43void nftnl_rule_free(const struct nftnl_rule *r)
44{
45 struct nftnl_expr *e, *tmp;
46
47 list_for_each_entry_safe(e, tmp, &r->expr_list, head)
48 nftnl_expr_free(e);
49
50 if (r->flags & (1 << (NFTNL_RULE_TABLE)))
51 xfree(r->table);
52 if (r->flags & (1 << (NFTNL_RULE_CHAIN)))
53 xfree(r->chain);
54 if (r->flags & (1 << (NFTNL_RULE_USERDATA)))
55 xfree(r->user.data);
56
57 xfree(r);
58}
59
60EXPORT_SYMBOL(nftnl_rule_is_set);
61bool nftnl_rule_is_set(const struct nftnl_rule *r, uint16_t attr)
62{
63 return r->flags & (1 << attr);
64}
65
66EXPORT_SYMBOL(nftnl_rule_unset);
67void nftnl_rule_unset(struct nftnl_rule *r, uint16_t attr)
68{
69 if (!(r->flags & (1 << attr)))
70 return;
71
72 switch (attr) {
73 case NFTNL_RULE_TABLE:
74 xfree(r->table);
75 break;
76 case NFTNL_RULE_CHAIN:
77 xfree(r->chain);
78 break;
79 case NFTNL_RULE_HANDLE:
80 case NFTNL_RULE_COMPAT_PROTO:
81 case NFTNL_RULE_COMPAT_FLAGS:
82 case NFTNL_RULE_POSITION:
83 case NFTNL_RULE_FAMILY:
84 case NFTNL_RULE_ID:
85 case NFTNL_RULE_POSITION_ID:
86 break;
87 case NFTNL_RULE_USERDATA:
88 xfree(r->user.data);
89 break;
90 }
91
92 r->flags &= ~(1 << attr);
93}
94
95static uint32_t nftnl_rule_validate[NFTNL_RULE_MAX + 1] = {
96 [NFTNL_RULE_HANDLE] = sizeof(uint64_t),
97 [NFTNL_RULE_COMPAT_PROTO] = sizeof(uint32_t),
98 [NFTNL_RULE_COMPAT_FLAGS] = sizeof(uint32_t),
99 [NFTNL_RULE_FAMILY] = sizeof(uint32_t),
100 [NFTNL_RULE_POSITION] = sizeof(uint64_t),
101 [NFTNL_RULE_ID] = sizeof(uint32_t),
102 [NFTNL_RULE_POSITION_ID] = sizeof(uint32_t),
103};
104
105EXPORT_SYMBOL(nftnl_rule_set_data);
106int nftnl_rule_set_data(struct nftnl_rule *r, uint16_t attr,
107 const void *data, uint32_t data_len)
108{
109 nftnl_assert_attr_exists(attr, NFTNL_RULE_MAX);
110 nftnl_assert_validate(data, nftnl_rule_validate, attr, data_len);
111
112 switch(attr) {
113 case NFTNL_RULE_TABLE:
114 return nftnl_set_str_attr(&r->table, &r->flags,
115 attr, data, data_len);
116 case NFTNL_RULE_CHAIN:
117 return nftnl_set_str_attr(&r->chain, &r->flags,
118 attr, data, data_len);
119 case NFTNL_RULE_HANDLE:
120 memcpy(&r->handle, data, sizeof(r->handle));
121 break;
122 case NFTNL_RULE_COMPAT_PROTO:
123 memcpy(&r->compat.proto, data, sizeof(r->compat.proto));
124 break;
125 case NFTNL_RULE_COMPAT_FLAGS:
126 memcpy(&r->compat.flags, data, sizeof(r->compat.flags));
127 break;
128 case NFTNL_RULE_FAMILY:
129 memcpy(&r->family, data, sizeof(r->family));
130 break;
131 case NFTNL_RULE_POSITION:
132 memcpy(&r->position, data, sizeof(r->position));
133 break;
134 case NFTNL_RULE_USERDATA:
135 if (r->flags & (1 << NFTNL_RULE_USERDATA))
136 xfree(r->user.data);
137
138 r->user.data = malloc(data_len);
139 if (!r->user.data)
140 return -1;
141
142 memcpy(r->user.data, data, data_len);
143 r->user.len = data_len;
144 break;
145 case NFTNL_RULE_ID:
146 memcpy(&r->id, data, sizeof(r->id));
147 break;
148 case NFTNL_RULE_POSITION_ID:
149 memcpy(&r->position_id, data, sizeof(r->position_id));
150 break;
151 }
152 r->flags |= (1 << attr);
153 return 0;
154}
155
156int nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data) __visible;
157int nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data)
158{
159 return nftnl_rule_set_data(r, attr, data, nftnl_rule_validate[attr]);
160}
161
162EXPORT_SYMBOL(nftnl_rule_set_u32);
163void nftnl_rule_set_u32(struct nftnl_rule *r, uint16_t attr, uint32_t val)
164{
165 nftnl_rule_set_data(r, attr, &val, sizeof(uint32_t));
166}
167
168EXPORT_SYMBOL(nftnl_rule_set_u64);
169void nftnl_rule_set_u64(struct nftnl_rule *r, uint16_t attr, uint64_t val)
170{
171 nftnl_rule_set_data(r, attr, &val, sizeof(uint64_t));
172}
173
174EXPORT_SYMBOL(nftnl_rule_set_str);
175int nftnl_rule_set_str(struct nftnl_rule *r, uint16_t attr, const char *str)
176{
177 return nftnl_rule_set_data(r, attr, str, strlen(str) + 1);
178}
179
180EXPORT_SYMBOL(nftnl_rule_get_data);
181const void *nftnl_rule_get_data(const struct nftnl_rule *r, uint16_t attr,
182 uint32_t *data_len)
183{
184 if (!(r->flags & (1 << attr)))
185 return NULL;
186
187 switch(attr) {
188 case NFTNL_RULE_FAMILY:
189 *data_len = sizeof(uint32_t);
190 return &r->family;
191 case NFTNL_RULE_TABLE:
192 *data_len = strlen(r->table) + 1;
193 return r->table;
194 case NFTNL_RULE_CHAIN:
195 *data_len = strlen(r->chain) + 1;
196 return r->chain;
197 case NFTNL_RULE_HANDLE:
198 *data_len = sizeof(uint64_t);
199 return &r->handle;
200 case NFTNL_RULE_COMPAT_PROTO:
201 *data_len = sizeof(uint32_t);
202 return &r->compat.proto;
203 case NFTNL_RULE_COMPAT_FLAGS:
204 *data_len = sizeof(uint32_t);
205 return &r->compat.flags;
206 case NFTNL_RULE_POSITION:
207 *data_len = sizeof(uint64_t);
208 return &r->position;
209 case NFTNL_RULE_USERDATA:
210 *data_len = r->user.len;
211 return r->user.data;
212 case NFTNL_RULE_ID:
213 *data_len = sizeof(uint32_t);
214 return &r->id;
215 case NFTNL_RULE_POSITION_ID:
216 *data_len = sizeof(uint32_t);
217 return &r->position_id;
218 }
219 return NULL;
220}
221
222EXPORT_SYMBOL(nftnl_rule_get);
223const void *nftnl_rule_get(const struct nftnl_rule *r, uint16_t attr)
224{
225 uint32_t data_len;
226 return nftnl_rule_get_data(r, attr, &data_len);
227}
228
229EXPORT_SYMBOL(nftnl_rule_get_str);
230const char *nftnl_rule_get_str(const struct nftnl_rule *r, uint16_t attr)
231{
232 return nftnl_rule_get(r, attr);
233}
234
235EXPORT_SYMBOL(nftnl_rule_get_u32);
236uint32_t nftnl_rule_get_u32(const struct nftnl_rule *r, uint16_t attr)
237{
238 uint32_t data_len;
239 const uint32_t *val = nftnl_rule_get_data(r, attr, &data_len);
240
241 nftnl_assert(val, attr, data_len == sizeof(uint32_t));
242
243 return val ? *val : 0;
244}
245
246EXPORT_SYMBOL(nftnl_rule_get_u64);
247uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr)
248{
249 uint32_t data_len;
250 const uint64_t *val = nftnl_rule_get_data(r, attr, &data_len);
251
252 nftnl_assert(val, attr, data_len == sizeof(uint64_t));
253
254 return val ? *val : 0;
255}
256
257EXPORT_SYMBOL(nftnl_rule_get_u8);
258uint8_t nftnl_rule_get_u8(const struct nftnl_rule *r, uint16_t attr)
259{
260 uint32_t data_len;
261 const uint8_t *val = nftnl_rule_get_data(r, attr, &data_len);
262
263 nftnl_assert(val, attr, data_len == sizeof(uint8_t));
264
265 return val ? *val : 0;
266}
267
268EXPORT_SYMBOL(nftnl_rule_nlmsg_build_payload);
269void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *r)
270{
271 struct nftnl_expr *expr;
272 struct nlattr *nest, *nest2;
273
274 if (r->flags & (1 << NFTNL_RULE_TABLE))
275 mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, r->table);
276 if (r->flags & (1 << NFTNL_RULE_CHAIN))
277 mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, r->chain);
278 if (r->flags & (1 << NFTNL_RULE_HANDLE))
279 mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(r->handle));
280 if (r->flags & (1 << NFTNL_RULE_POSITION))
281 mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
282 if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
283 mnl_attr_put(nlh, NFTA_RULE_USERDATA, r->user.len,
284 r->user.data);
285 }
286
287 if (!list_empty(&r->expr_list)) {
288 nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
289 list_for_each_entry(expr, &r->expr_list, head) {
290 nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
291 nftnl_expr_build_payload(nlh, expr);
292 mnl_attr_nest_end(nlh, nest2);
293 }
294 mnl_attr_nest_end(nlh, nest);
295 }
296
297 if (r->flags & (1 << NFTNL_RULE_COMPAT_PROTO) &&
298 r->flags & (1 << NFTNL_RULE_COMPAT_FLAGS)) {
299
300 nest = mnl_attr_nest_start(nlh, NFTA_RULE_COMPAT);
301 mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_PROTO,
302 htonl(r->compat.proto));
303 mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_FLAGS,
304 htonl(r->compat.flags));
305 mnl_attr_nest_end(nlh, nest);
306 }
307 if (r->flags & (1 << NFTNL_RULE_ID))
308 mnl_attr_put_u32(nlh, NFTA_RULE_ID, htonl(r->id));
309 if (r->flags & (1 << NFTNL_RULE_POSITION_ID))
310 mnl_attr_put_u32(nlh, NFTA_RULE_POSITION_ID, htonl(r->position_id));
311}
312
313EXPORT_SYMBOL(nftnl_rule_add_expr);
314void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr)
315{
316 list_add_tail(&expr->head, &r->expr_list);
317}
318
319EXPORT_SYMBOL(nftnl_rule_del_expr);
320void nftnl_rule_del_expr(struct nftnl_expr *expr)
321{
322 list_del(&expr->head);
323}
324
325static int nftnl_rule_parse_attr_cb(const struct nlattr *attr, void *data)
326{
327 const struct nlattr **tb = data;
328 int type = mnl_attr_get_type(attr);
329
330 if (mnl_attr_type_valid(attr, NFTA_RULE_MAX) < 0)
331 return MNL_CB_OK;
332
333 switch(type) {
334 case NFTA_RULE_TABLE:
335 case NFTA_RULE_CHAIN:
336 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
337 abi_breakage();
338 break;
339 case NFTA_RULE_HANDLE:
340 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
341 abi_breakage();
342 break;
343 case NFTA_RULE_COMPAT:
344 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
345 abi_breakage();
346 break;
347 case NFTA_RULE_POSITION:
348 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
349 abi_breakage();
350 break;
351 case NFTA_RULE_USERDATA:
352 if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
353 abi_breakage();
354 break;
355 case NFTA_RULE_ID:
356 case NFTA_RULE_POSITION_ID:
357 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
358 abi_breakage();
359 break;
360 }
361
362 tb[type] = attr;
363 return MNL_CB_OK;
364}
365
366static int nftnl_rule_parse_expr(struct nlattr *nest, struct nftnl_rule *r)
367{
368 struct nftnl_expr *expr;
369 struct nlattr *attr;
370
371 mnl_attr_for_each_nested(attr, nest) {
372 if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
373 return -1;
374
375 expr = nftnl_expr_parse(attr);
376 if (expr == NULL)
377 return -1;
378
379 list_add_tail(&expr->head, &r->expr_list);
380 }
381 return 0;
382}
383
384static int nftnl_rule_parse_compat_cb(const struct nlattr *attr, void *data)
385{
386 const struct nlattr **tb = data;
387 int type = mnl_attr_get_type(attr);
388
389 if (mnl_attr_type_valid(attr, NFTA_RULE_COMPAT_MAX) < 0)
390 return MNL_CB_OK;
391
392 switch(type) {
393 case NFTA_RULE_COMPAT_PROTO:
394 case NFTA_RULE_COMPAT_FLAGS:
395 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
396 abi_breakage();
397 break;
398 }
399
400 tb[type] = attr;
401 return MNL_CB_OK;
402}
403
404static int nftnl_rule_parse_compat(struct nlattr *nest, struct nftnl_rule *r)
405{
406 struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1] = {};
407
408 if (mnl_attr_parse_nested(nest, nftnl_rule_parse_compat_cb, tb) < 0)
409 return -1;
410
411 if (tb[NFTA_RULE_COMPAT_PROTO]) {
412 r->compat.proto =
413 ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_PROTO]));
414 r->flags |= (1 << NFTNL_RULE_COMPAT_PROTO);
415 }
416 if (tb[NFTA_RULE_COMPAT_FLAGS]) {
417 r->compat.flags =
418 ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_FLAGS]));
419 r->flags |= (1 << NFTNL_RULE_COMPAT_FLAGS);
420 }
421 return 0;
422}
423
424EXPORT_SYMBOL(nftnl_rule_nlmsg_parse);
425int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_rule *r)
426{
427 struct nlattr *tb[NFTA_RULE_MAX+1] = {};
428 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
429 int ret;
430
431 if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_rule_parse_attr_cb, tb) < 0)
432 return -1;
433
434 if (tb[NFTA_RULE_TABLE]) {
435 if (r->flags & (1 << NFTNL_RULE_TABLE))
436 xfree(r->table);
437 r->table = strdup(mnl_attr_get_str(tb[NFTA_RULE_TABLE]));
438 if (!r->table)
439 return -1;
440 r->flags |= (1 << NFTNL_RULE_TABLE);
441 }
442 if (tb[NFTA_RULE_CHAIN]) {
443 if (r->flags & (1 << NFTNL_RULE_CHAIN))
444 xfree(r->chain);
445 r->chain = strdup(mnl_attr_get_str(tb[NFTA_RULE_CHAIN]));
446 if (!r->chain)
447 return -1;
448 r->flags |= (1 << NFTNL_RULE_CHAIN);
449 }
450 if (tb[NFTA_RULE_HANDLE]) {
451 r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
452 r->flags |= (1 << NFTNL_RULE_HANDLE);
453 }
454 if (tb[NFTA_RULE_EXPRESSIONS]) {
455 ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
456 if (ret < 0)
457 return ret;
458 }
459 if (tb[NFTA_RULE_COMPAT]) {
460 ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
461 if (ret < 0)
462 return ret;
463 }
464 if (tb[NFTA_RULE_POSITION]) {
465 r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
466 r->flags |= (1 << NFTNL_RULE_POSITION);
467 }
468 if (tb[NFTA_RULE_USERDATA]) {
469 const void *udata =
470 mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
471
472 if (r->flags & (1 << NFTNL_RULE_USERDATA))
473 xfree(r->user.data);
474
475 r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
476
477 r->user.data = malloc(r->user.len);
478 if (r->user.data == NULL)
479 return -1;
480
481 memcpy(r->user.data, udata, r->user.len);
482 r->flags |= (1 << NFTNL_RULE_USERDATA);
483 }
484 if (tb[NFTA_RULE_ID]) {
485 r->id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_ID]));
486 r->flags |= (1 << NFTNL_RULE_ID);
487 }
488 if (tb[NFTA_RULE_POSITION_ID]) {
489 r->position_id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_POSITION_ID]));
490 r->flags |= (1 << NFTNL_RULE_POSITION_ID);
491 }
492
493 r->family = nfg->nfgen_family;
494 r->flags |= (1 << NFTNL_RULE_FAMILY);
495
496 return 0;
497}
498
499EXPORT_SYMBOL(nftnl_rule_parse);
500int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
501 const char *data, struct nftnl_parse_err *err)
502{
503 errno = EOPNOTSUPP;
504
505 return -1;
506}
507
508EXPORT_SYMBOL(nftnl_rule_parse_file);
509int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
510 FILE *fp, struct nftnl_parse_err *err)
511{
512 errno = EOPNOTSUPP;
513
514 return -1;
515}
516
517static int nftnl_rule_snprintf_default(char *buf, size_t remain,
518 const struct nftnl_rule *r,
519 uint32_t type, uint32_t flags)
520{
521 struct nftnl_expr *expr;
522 int ret, offset = 0, i;
523 const char *sep = "";
524
525 if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
526 ret = snprintf(buf + offset, remain, "%s%s", sep,
527 nftnl_family2str(r->family));
528 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
529 sep = " ";
530 }
531
532 if (r->flags & (1 << NFTNL_RULE_TABLE)) {
533 ret = snprintf(buf + offset, remain, "%s%s", sep,
534 r->table);
535 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
536 sep = " ";
537 }
538
539 if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
540 ret = snprintf(buf + offset, remain, "%s%s", sep,
541 r->chain);
542 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
543 sep = " ";
544 }
545 if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
546 ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
547 r->handle);
548 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
549 sep = " ";
550 }
551
552 if (r->flags & (1 << NFTNL_RULE_POSITION)) {
553 ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
554 r->position);
555 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
556 sep = " ";
557 }
558
559 if (r->flags & (1 << NFTNL_RULE_ID)) {
560 ret = snprintf(buf + offset, remain, "%s%u", sep, r->id);
561 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
562 sep = " ";
563 }
564
565 if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
566 ret = snprintf(buf + offset, remain, "%s%u", sep,
567 r->position_id);
568 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
569 sep = " ";
570 }
571
572 list_for_each_entry(expr, &r->expr_list, head) {
573 ret = snprintf(buf + offset, remain,
574 "\n [ %s ", expr->ops->name);
575 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
576
577 ret = nftnl_expr_snprintf(buf + offset, remain, expr,
578 type, flags);
579 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
580
581 ret = snprintf(buf + offset, remain, "]");
582 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
583 }
584
585 if (r->user.len) {
586 ret = snprintf(buf + offset, remain, "\n userdata = { ");
587 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
588
589 for (i = 0; i < r->user.len; i++) {
590 char *c = r->user.data;
591
592 ret = snprintf(buf + offset, remain,
593 isprint(c[i]) ? "%c" : "\\x%02hhx",
594 c[i]);
595 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
596 }
597
598 ret = snprintf(buf + offset, remain, " }");
599 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
600
601 }
602
603 return offset;
604}
605
606static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
607 const struct nftnl_rule *r, uint32_t cmd,
608 uint32_t type, uint32_t flags)
609{
610 uint32_t inner_flags = flags;
611 int ret, offset = 0;
612
613 inner_flags &= ~NFTNL_OF_EVENT_ANY;
614
615 if (type != NFTNL_OUTPUT_DEFAULT)
616 return -1;
617
618 ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
619 inner_flags);
620 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
621 return offset;
622}
623
624EXPORT_SYMBOL(nftnl_rule_snprintf);
625int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
626 uint32_t type, uint32_t flags)
627{
628 if (size)
629 buf[0] = '\0';
630
631 return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
632 flags);
633}
634
635static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
636 uint32_t cmd, uint32_t type, uint32_t flags)
637{
638 return nftnl_rule_snprintf(buf, size, r, type, flags);
639}
640
641EXPORT_SYMBOL(nftnl_rule_fprintf);
642int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
643 uint32_t flags)
644{
645 return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
646 nftnl_rule_do_snprintf);
647}
648
649EXPORT_SYMBOL(nftnl_expr_foreach);
650int nftnl_expr_foreach(struct nftnl_rule *r,
651 int (*cb)(struct nftnl_expr *e, void *data),
652 void *data)
653{
654 struct nftnl_expr *cur, *tmp;
655 int ret;
656
657 list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
658 ret = cb(cur, data);
659 if (ret < 0)
660 return ret;
661 }
662 return 0;
663}
664
666 const struct nftnl_rule *r;
667 struct nftnl_expr *cur;
668};
669
670static void nftnl_expr_iter_init(const struct nftnl_rule *r,
671 struct nftnl_expr_iter *iter)
672{
673 iter->r = r;
674 if (list_empty(&r->expr_list))
675 iter->cur = NULL;
676 else
677 iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
678 head);
679}
680
681EXPORT_SYMBOL(nftnl_expr_iter_create);
682struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
683{
684 struct nftnl_expr_iter *iter;
685
686 iter = calloc(1, sizeof(struct nftnl_expr_iter));
687 if (iter == NULL)
688 return NULL;
689
690 nftnl_expr_iter_init(r, iter);
691
692 return iter;
693}
694
695EXPORT_SYMBOL(nftnl_expr_iter_next);
696struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
697{
698 struct nftnl_expr *expr = iter->cur;
699
700 if (expr == NULL)
701 return NULL;
702
703 /* get next expression, if any */
704 iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
705 if (&iter->cur->head == iter->r->expr_list.next)
706 return NULL;
707
708 return expr;
709}
710
711EXPORT_SYMBOL(nftnl_expr_iter_destroy);
712void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
713{
714 xfree(iter);
715}
716
718 struct list_head list;
719};
720
721EXPORT_SYMBOL(nftnl_rule_list_alloc);
722struct nftnl_rule_list *nftnl_rule_list_alloc(void)
723{
724 struct nftnl_rule_list *list;
725
726 list = calloc(1, sizeof(struct nftnl_rule_list));
727 if (list == NULL)
728 return NULL;
729
730 INIT_LIST_HEAD(&list->list);
731
732 return list;
733}
734
735EXPORT_SYMBOL(nftnl_rule_list_free);
736void nftnl_rule_list_free(struct nftnl_rule_list *list)
737{
738 struct nftnl_rule *r, *tmp;
739
740 list_for_each_entry_safe(r, tmp, &list->list, head) {
741 list_del(&r->head);
742 nftnl_rule_free(r);
743 }
744 xfree(list);
745}
746
747EXPORT_SYMBOL(nftnl_rule_list_is_empty);
748int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
749{
750 return list_empty(&list->list);
751}
752
753EXPORT_SYMBOL(nftnl_rule_list_add);
754void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
755{
756 list_add(&r->head, &list->list);
757}
758
759EXPORT_SYMBOL(nftnl_rule_list_insert_at);
760void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
761{
762 list_add(&r->head, &pos->head);
763}
764
765EXPORT_SYMBOL(nftnl_rule_list_add_tail);
766void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
767{
768 list_add_tail(&r->head, &list->list);
769}
770
771EXPORT_SYMBOL(nftnl_rule_list_del);
772void nftnl_rule_list_del(struct nftnl_rule *r)
773{
774 list_del(&r->head);
775}
776
777EXPORT_SYMBOL(nftnl_rule_list_foreach);
778int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
779 int (*cb)(struct nftnl_rule *r, void *data),
780 void *data)
781{
782 struct nftnl_rule *cur, *tmp;
783 int ret;
784
785 list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
786 ret = cb(cur, data);
787 if (ret < 0)
788 return ret;
789 }
790 return 0;
791}
792
794 const struct nftnl_rule_list *list;
795 struct nftnl_rule *cur;
796};
797
798EXPORT_SYMBOL(nftnl_rule_list_iter_create);
800nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
801{
802 struct nftnl_rule_list_iter *iter;
803
804 iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
805 if (iter == NULL)
806 return NULL;
807
808 iter->list = l;
809 if (nftnl_rule_list_is_empty(l))
810 iter->cur = NULL;
811 else
812 iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
813
814 return iter;
815}
816
817EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
818struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
819{
820 return iter->cur;
821}
822
823EXPORT_SYMBOL(nftnl_rule_list_iter_next);
824struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
825{
826 struct nftnl_rule *r = iter->cur;
827
828 if (r == NULL)
829 return NULL;
830
831 /* get next rule, if any */
832 iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
833 if (&iter->cur->head == iter->list->list.next)
834 return NULL;
835
836 return r;
837}
838
839EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
840void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
841{
842 xfree(iter);
843}