libnftnl 1.3.1
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 (nftnl_parse_str_attr(tb[NFTA_RULE_TABLE], NFTNL_RULE_TABLE,
435 &r->table, &r->flags) < 0)
436 return -1;
437 if (nftnl_parse_str_attr(tb[NFTA_RULE_CHAIN], NFTNL_RULE_CHAIN,
438 &r->chain, &r->flags) < 0)
439 return -1;
440 if (tb[NFTA_RULE_HANDLE]) {
441 r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
442 r->flags |= (1 << NFTNL_RULE_HANDLE);
443 }
444 if (tb[NFTA_RULE_EXPRESSIONS]) {
445 ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
446 if (ret < 0)
447 return ret;
448 }
449 if (tb[NFTA_RULE_COMPAT]) {
450 ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
451 if (ret < 0)
452 return ret;
453 }
454 if (tb[NFTA_RULE_POSITION]) {
455 r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
456 r->flags |= (1 << NFTNL_RULE_POSITION);
457 }
458 if (tb[NFTA_RULE_USERDATA]) {
459 const void *udata =
460 mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
461
462 if (r->flags & (1 << NFTNL_RULE_USERDATA))
463 xfree(r->user.data);
464
465 r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
466
467 r->user.data = malloc(r->user.len);
468 if (r->user.data == NULL)
469 return -1;
470
471 memcpy(r->user.data, udata, r->user.len);
472 r->flags |= (1 << NFTNL_RULE_USERDATA);
473 }
474 if (tb[NFTA_RULE_ID]) {
475 r->id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_ID]));
476 r->flags |= (1 << NFTNL_RULE_ID);
477 }
478 if (tb[NFTA_RULE_POSITION_ID]) {
479 r->position_id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_POSITION_ID]));
480 r->flags |= (1 << NFTNL_RULE_POSITION_ID);
481 }
482
483 r->family = nfg->nfgen_family;
484 r->flags |= (1 << NFTNL_RULE_FAMILY);
485
486 return 0;
487}
488
489EXPORT_SYMBOL(nftnl_rule_parse);
490int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
491 const char *data, struct nftnl_parse_err *err)
492{
493 errno = EOPNOTSUPP;
494
495 return -1;
496}
497
498EXPORT_SYMBOL(nftnl_rule_parse_file);
499int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
500 FILE *fp, struct nftnl_parse_err *err)
501{
502 errno = EOPNOTSUPP;
503
504 return -1;
505}
506
507static int nftnl_rule_snprintf_default(char *buf, size_t remain,
508 const struct nftnl_rule *r,
509 uint32_t type, uint32_t flags)
510{
511 struct nftnl_expr *expr;
512 int ret, offset = 0, i;
513 const char *sep = "";
514
515 if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
516 ret = snprintf(buf + offset, remain, "%s%s", sep,
517 nftnl_family2str(r->family));
518 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
519 sep = " ";
520 }
521
522 if (r->flags & (1 << NFTNL_RULE_TABLE)) {
523 ret = snprintf(buf + offset, remain, "%s%s", sep,
524 r->table);
525 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
526 sep = " ";
527 }
528
529 if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
530 ret = snprintf(buf + offset, remain, "%s%s", sep,
531 r->chain);
532 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
533 sep = " ";
534 }
535 if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
536 ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
537 r->handle);
538 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
539 sep = " ";
540 }
541
542 if (r->flags & (1 << NFTNL_RULE_POSITION)) {
543 ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
544 r->position);
545 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
546 sep = " ";
547 }
548
549 if (r->flags & (1 << NFTNL_RULE_ID)) {
550 ret = snprintf(buf + offset, remain, "%s%u", sep, r->id);
551 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
552 sep = " ";
553 }
554
555 if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
556 ret = snprintf(buf + offset, remain, "%s%u", sep,
557 r->position_id);
558 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
559 sep = " ";
560 }
561
562 list_for_each_entry(expr, &r->expr_list, head) {
563 ret = snprintf(buf + offset, remain,
564 "\n [ %s ", expr->ops->name);
565 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
566
567 ret = nftnl_expr_snprintf(buf + offset, remain, expr,
568 type, flags);
569 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
570
571 ret = snprintf(buf + offset, remain, "]");
572 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
573 }
574
575 if (r->user.len) {
576 ret = snprintf(buf + offset, remain, "\n userdata = { ");
577 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
578
579 for (i = 0; i < r->user.len; i++) {
580 char *c = r->user.data;
581
582 ret = snprintf(buf + offset, remain,
583 isprint(c[i]) ? "%c" : "\\x%02hhx",
584 c[i]);
585 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
586 }
587
588 ret = snprintf(buf + offset, remain, " }");
589 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
590
591 }
592
593 return offset;
594}
595
596static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
597 const struct nftnl_rule *r, uint32_t cmd,
598 uint32_t type, uint32_t flags)
599{
600 uint32_t inner_flags = flags;
601 int ret, offset = 0;
602
603 inner_flags &= ~NFTNL_OF_EVENT_ANY;
604
605 if (type != NFTNL_OUTPUT_DEFAULT)
606 return -1;
607
608 ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
609 inner_flags);
610 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
611 return offset;
612}
613
614EXPORT_SYMBOL(nftnl_rule_snprintf);
615int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
616 uint32_t type, uint32_t flags)
617{
618 if (size)
619 buf[0] = '\0';
620
621 return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
622 flags);
623}
624
625static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
626 uint32_t cmd, uint32_t type, uint32_t flags)
627{
628 return nftnl_rule_snprintf(buf, size, r, type, flags);
629}
630
631EXPORT_SYMBOL(nftnl_rule_fprintf);
632int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
633 uint32_t flags)
634{
635 return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
636 nftnl_rule_do_snprintf);
637}
638
639EXPORT_SYMBOL(nftnl_expr_foreach);
640int nftnl_expr_foreach(struct nftnl_rule *r,
641 int (*cb)(struct nftnl_expr *e, void *data),
642 void *data)
643{
644 struct nftnl_expr *cur, *tmp;
645 int ret;
646
647 list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
648 ret = cb(cur, data);
649 if (ret < 0)
650 return ret;
651 }
652 return 0;
653}
654
656 const struct nftnl_rule *r;
657 struct nftnl_expr *cur;
658};
659
660static void nftnl_expr_iter_init(const struct nftnl_rule *r,
661 struct nftnl_expr_iter *iter)
662{
663 iter->r = r;
664 if (list_empty(&r->expr_list))
665 iter->cur = NULL;
666 else
667 iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
668 head);
669}
670
671EXPORT_SYMBOL(nftnl_expr_iter_create);
672struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
673{
674 struct nftnl_expr_iter *iter;
675
676 iter = calloc(1, sizeof(struct nftnl_expr_iter));
677 if (iter == NULL)
678 return NULL;
679
680 nftnl_expr_iter_init(r, iter);
681
682 return iter;
683}
684
685EXPORT_SYMBOL(nftnl_expr_iter_next);
686struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
687{
688 struct nftnl_expr *expr = iter->cur;
689
690 if (expr == NULL)
691 return NULL;
692
693 /* get next expression, if any */
694 iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
695 if (&iter->cur->head == iter->r->expr_list.next)
696 return NULL;
697
698 return expr;
699}
700
701EXPORT_SYMBOL(nftnl_expr_iter_destroy);
702void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
703{
704 xfree(iter);
705}
706
708 struct list_head list;
709};
710
711EXPORT_SYMBOL(nftnl_rule_list_alloc);
712struct nftnl_rule_list *nftnl_rule_list_alloc(void)
713{
714 struct nftnl_rule_list *list;
715
716 list = calloc(1, sizeof(struct nftnl_rule_list));
717 if (list == NULL)
718 return NULL;
719
720 INIT_LIST_HEAD(&list->list);
721
722 return list;
723}
724
725EXPORT_SYMBOL(nftnl_rule_list_free);
726void nftnl_rule_list_free(struct nftnl_rule_list *list)
727{
728 struct nftnl_rule *r, *tmp;
729
730 list_for_each_entry_safe(r, tmp, &list->list, head) {
731 list_del(&r->head);
732 nftnl_rule_free(r);
733 }
734 xfree(list);
735}
736
737EXPORT_SYMBOL(nftnl_rule_list_is_empty);
738int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
739{
740 return list_empty(&list->list);
741}
742
743EXPORT_SYMBOL(nftnl_rule_list_add);
744void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
745{
746 list_add(&r->head, &list->list);
747}
748
749EXPORT_SYMBOL(nftnl_rule_list_insert_at);
750void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
751{
752 list_add(&r->head, &pos->head);
753}
754
755EXPORT_SYMBOL(nftnl_rule_list_add_tail);
756void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
757{
758 list_add_tail(&r->head, &list->list);
759}
760
761EXPORT_SYMBOL(nftnl_rule_list_del);
762void nftnl_rule_list_del(struct nftnl_rule *r)
763{
764 list_del(&r->head);
765}
766
767EXPORT_SYMBOL(nftnl_rule_list_foreach);
768int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
769 int (*cb)(struct nftnl_rule *r, void *data),
770 void *data)
771{
772 struct nftnl_rule *cur, *tmp;
773 int ret;
774
775 list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
776 ret = cb(cur, data);
777 if (ret < 0)
778 return ret;
779 }
780 return 0;
781}
782
784 const struct nftnl_rule_list *list;
785 struct nftnl_rule *cur;
786};
787
788EXPORT_SYMBOL(nftnl_rule_list_iter_create);
790nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
791{
792 struct nftnl_rule_list_iter *iter;
793
794 iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
795 if (iter == NULL)
796 return NULL;
797
798 iter->list = l;
799 if (nftnl_rule_list_is_empty(l))
800 iter->cur = NULL;
801 else
802 iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
803
804 return iter;
805}
806
807EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
808struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
809{
810 return iter->cur;
811}
812
813EXPORT_SYMBOL(nftnl_rule_list_iter_next);
814struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
815{
816 struct nftnl_rule *r = iter->cur;
817
818 if (r == NULL)
819 return NULL;
820
821 /* get next rule, if any */
822 iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
823 if (&iter->cur->head == iter->list->list.next)
824 return NULL;
825
826 return r;
827}
828
829EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
830void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
831{
832 xfree(iter);
833}