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