libnftnl 1.2.7
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
503static int nftnl_rule_do_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
504 const void *data, struct nftnl_parse_err *err,
505 enum nftnl_parse_input input)
506{
507 int ret;
508 struct nftnl_parse_err perr = {};
509
510 switch (type) {
511 case NFTNL_PARSE_JSON:
512 case NFTNL_PARSE_XML:
513 default:
514 ret = -1;
515 errno = EOPNOTSUPP;
516 break;
517 }
518 if (err != NULL)
519 *err = perr;
520
521 return ret;
522}
523
524EXPORT_SYMBOL(nftnl_rule_parse);
525int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
526 const char *data, struct nftnl_parse_err *err)
527{
528 return nftnl_rule_do_parse(r, type, data, err, NFTNL_PARSE_BUFFER);
529}
530
531EXPORT_SYMBOL(nftnl_rule_parse_file);
532int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
533 FILE *fp, struct nftnl_parse_err *err)
534{
535 return nftnl_rule_do_parse(r, type, fp, err, NFTNL_PARSE_FILE);
536}
537
538static int nftnl_rule_snprintf_default(char *buf, size_t remain,
539 const struct nftnl_rule *r,
540 uint32_t type, uint32_t flags)
541{
542 struct nftnl_expr *expr;
543 int ret, offset = 0, i;
544 const char *sep = "";
545
546 if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
547 ret = snprintf(buf + offset, remain, "%s%s", sep,
548 nftnl_family2str(r->family));
549 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
550 sep = " ";
551 }
552
553 if (r->flags & (1 << NFTNL_RULE_TABLE)) {
554 ret = snprintf(buf + offset, remain, "%s%s", sep,
555 r->table);
556 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
557 sep = " ";
558 }
559
560 if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
561 ret = snprintf(buf + offset, remain, "%s%s", sep,
562 r->chain);
563 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
564 sep = " ";
565 }
566 if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
567 ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
568 r->handle);
569 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
570 sep = " ";
571 }
572
573 if (r->flags & (1 << NFTNL_RULE_POSITION)) {
574 ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
575 r->position);
576 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
577 sep = " ";
578 }
579
580 if (r->flags & (1 << NFTNL_RULE_ID)) {
581 ret = snprintf(buf + offset, remain, "%s%u", sep, r->id);
582 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
583 sep = " ";
584 }
585
586 if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
587 ret = snprintf(buf + offset, remain, "%s%u", sep,
588 r->position_id);
589 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
590 sep = " ";
591 }
592
593 ret = snprintf(buf + offset, remain, "\n");
594 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
595
596 list_for_each_entry(expr, &r->expr_list, head) {
597 ret = snprintf(buf + offset, remain, " [ %s ", expr->ops->name);
598 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
599
600 ret = nftnl_expr_snprintf(buf + offset, remain, expr,
601 type, flags);
602 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
603
604 ret = snprintf(buf + offset, remain, "]\n");
605 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
606 }
607
608 if (r->user.len) {
609 ret = snprintf(buf + offset, remain, " userdata = { ");
610 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
611
612 for (i = 0; i < r->user.len; i++) {
613 char *c = r->user.data;
614
615 ret = snprintf(buf + offset, remain,
616 isprint(c[i]) ? "%c" : "\\x%02hhx",
617 c[i]);
618 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
619 }
620
621 ret = snprintf(buf + offset, remain, " }");
622 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
623
624 }
625
626 return offset;
627}
628
629static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
630 const struct nftnl_rule *r, uint32_t cmd,
631 uint32_t type, uint32_t flags)
632{
633 uint32_t inner_flags = flags;
634 int ret, offset = 0;
635
636 inner_flags &= ~NFTNL_OF_EVENT_ANY;
637
638 if (type != NFTNL_OUTPUT_DEFAULT)
639 return -1;
640
641 ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
642 inner_flags);
643 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
644 return offset;
645}
646
647EXPORT_SYMBOL(nftnl_rule_snprintf);
648int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
649 uint32_t type, uint32_t flags)
650{
651 if (size)
652 buf[0] = '\0';
653
654 return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
655 flags);
656}
657
658static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
659 uint32_t cmd, uint32_t type, uint32_t flags)
660{
661 return nftnl_rule_snprintf(buf, size, r, type, flags);
662}
663
664EXPORT_SYMBOL(nftnl_rule_fprintf);
665int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
666 uint32_t flags)
667{
668 return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
669 nftnl_rule_do_snprintf);
670}
671
672EXPORT_SYMBOL(nftnl_expr_foreach);
673int nftnl_expr_foreach(struct nftnl_rule *r,
674 int (*cb)(struct nftnl_expr *e, void *data),
675 void *data)
676{
677 struct nftnl_expr *cur, *tmp;
678 int ret;
679
680 list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
681 ret = cb(cur, data);
682 if (ret < 0)
683 return ret;
684 }
685 return 0;
686}
687
689 const struct nftnl_rule *r;
690 struct nftnl_expr *cur;
691};
692
693static void nftnl_expr_iter_init(const struct nftnl_rule *r,
694 struct nftnl_expr_iter *iter)
695{
696 iter->r = r;
697 if (list_empty(&r->expr_list))
698 iter->cur = NULL;
699 else
700 iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
701 head);
702}
703
704EXPORT_SYMBOL(nftnl_expr_iter_create);
705struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
706{
707 struct nftnl_expr_iter *iter;
708
709 iter = calloc(1, sizeof(struct nftnl_expr_iter));
710 if (iter == NULL)
711 return NULL;
712
713 nftnl_expr_iter_init(r, iter);
714
715 return iter;
716}
717
718EXPORT_SYMBOL(nftnl_expr_iter_next);
719struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
720{
721 struct nftnl_expr *expr = iter->cur;
722
723 if (expr == NULL)
724 return NULL;
725
726 /* get next expression, if any */
727 iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
728 if (&iter->cur->head == iter->r->expr_list.next)
729 return NULL;
730
731 return expr;
732}
733
734EXPORT_SYMBOL(nftnl_expr_iter_destroy);
735void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
736{
737 xfree(iter);
738}
739
741 struct list_head list;
742};
743
744EXPORT_SYMBOL(nftnl_rule_list_alloc);
745struct nftnl_rule_list *nftnl_rule_list_alloc(void)
746{
747 struct nftnl_rule_list *list;
748
749 list = calloc(1, sizeof(struct nftnl_rule_list));
750 if (list == NULL)
751 return NULL;
752
753 INIT_LIST_HEAD(&list->list);
754
755 return list;
756}
757
758EXPORT_SYMBOL(nftnl_rule_list_free);
759void nftnl_rule_list_free(struct nftnl_rule_list *list)
760{
761 struct nftnl_rule *r, *tmp;
762
763 list_for_each_entry_safe(r, tmp, &list->list, head) {
764 list_del(&r->head);
765 nftnl_rule_free(r);
766 }
767 xfree(list);
768}
769
770EXPORT_SYMBOL(nftnl_rule_list_is_empty);
771int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
772{
773 return list_empty(&list->list);
774}
775
776EXPORT_SYMBOL(nftnl_rule_list_add);
777void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
778{
779 list_add(&r->head, &list->list);
780}
781
782EXPORT_SYMBOL(nftnl_rule_list_insert_at);
783void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
784{
785 list_add(&r->head, &pos->head);
786}
787
788EXPORT_SYMBOL(nftnl_rule_list_add_tail);
789void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
790{
791 list_add_tail(&r->head, &list->list);
792}
793
794EXPORT_SYMBOL(nftnl_rule_list_del);
795void nftnl_rule_list_del(struct nftnl_rule *r)
796{
797 list_del(&r->head);
798}
799
800EXPORT_SYMBOL(nftnl_rule_list_foreach);
801int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
802 int (*cb)(struct nftnl_rule *r, void *data),
803 void *data)
804{
805 struct nftnl_rule *cur, *tmp;
806 int ret;
807
808 list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
809 ret = cb(cur, data);
810 if (ret < 0)
811 return ret;
812 }
813 return 0;
814}
815
817 const struct nftnl_rule_list *list;
818 struct nftnl_rule *cur;
819};
820
821EXPORT_SYMBOL(nftnl_rule_list_iter_create);
823nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
824{
825 struct nftnl_rule_list_iter *iter;
826
827 iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
828 if (iter == NULL)
829 return NULL;
830
831 iter->list = l;
832 if (nftnl_rule_list_is_empty(l))
833 iter->cur = NULL;
834 else
835 iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
836
837 return iter;
838}
839
840EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
841struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
842{
843 return iter->cur;
844}
845
846EXPORT_SYMBOL(nftnl_rule_list_iter_next);
847struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
848{
849 struct nftnl_rule *r = iter->cur;
850
851 if (r == NULL)
852 return NULL;
853
854 /* get next rule, if any */
855 iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
856 if (&iter->cur->head == iter->list->list.next)
857 return NULL;
858
859 return r;
860}
861
862EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
863void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
864{
865 xfree(iter);
866}