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