libnftnl 1.2.6
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,
626 isprint(c[i]) ? "%c" : "\\x%02hhx",
627 c[i]);
628 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
629 }
630
631 ret = snprintf(buf + offset, remain, " }");
632 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
633
634 }
635
636 return offset;
637}
638
639static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
640 const struct nftnl_rule *r, uint32_t cmd,
641 uint32_t type, uint32_t flags)
642{
643 uint32_t inner_flags = flags;
644 int ret, offset = 0;
645
646 inner_flags &= ~NFTNL_OF_EVENT_ANY;
647
648 if (type != NFTNL_OUTPUT_DEFAULT)
649 return -1;
650
651 ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
652 inner_flags);
653 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
654 return offset;
655}
656
657EXPORT_SYMBOL(nftnl_rule_snprintf);
658int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
659 uint32_t type, uint32_t flags)
660{
661 if (size)
662 buf[0] = '\0';
663
664 return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
665 flags);
666}
667
668static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
669 uint32_t cmd, uint32_t type, uint32_t flags)
670{
671 return nftnl_rule_snprintf(buf, size, r, type, flags);
672}
673
674EXPORT_SYMBOL(nftnl_rule_fprintf);
675int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
676 uint32_t flags)
677{
678 return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
679 nftnl_rule_do_snprintf);
680}
681
682EXPORT_SYMBOL(nftnl_expr_foreach);
683int nftnl_expr_foreach(struct nftnl_rule *r,
684 int (*cb)(struct nftnl_expr *e, void *data),
685 void *data)
686{
687 struct nftnl_expr *cur, *tmp;
688 int ret;
689
690 list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
691 ret = cb(cur, data);
692 if (ret < 0)
693 return ret;
694 }
695 return 0;
696}
697
699 const struct nftnl_rule *r;
700 struct nftnl_expr *cur;
701};
702
703static void nftnl_expr_iter_init(const struct nftnl_rule *r,
704 struct nftnl_expr_iter *iter)
705{
706 iter->r = r;
707 if (list_empty(&r->expr_list))
708 iter->cur = NULL;
709 else
710 iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
711 head);
712}
713
714EXPORT_SYMBOL(nftnl_expr_iter_create);
715struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
716{
717 struct nftnl_expr_iter *iter;
718
719 iter = calloc(1, sizeof(struct nftnl_expr_iter));
720 if (iter == NULL)
721 return NULL;
722
723 nftnl_expr_iter_init(r, iter);
724
725 return iter;
726}
727
728EXPORT_SYMBOL(nftnl_expr_iter_next);
729struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
730{
731 struct nftnl_expr *expr = iter->cur;
732
733 if (expr == NULL)
734 return NULL;
735
736 /* get next expression, if any */
737 iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
738 if (&iter->cur->head == iter->r->expr_list.next)
739 return NULL;
740
741 return expr;
742}
743
744EXPORT_SYMBOL(nftnl_expr_iter_destroy);
745void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
746{
747 xfree(iter);
748}
749
751 struct list_head list;
752};
753
754EXPORT_SYMBOL(nftnl_rule_list_alloc);
755struct nftnl_rule_list *nftnl_rule_list_alloc(void)
756{
757 struct nftnl_rule_list *list;
758
759 list = calloc(1, sizeof(struct nftnl_rule_list));
760 if (list == NULL)
761 return NULL;
762
763 INIT_LIST_HEAD(&list->list);
764
765 return list;
766}
767
768EXPORT_SYMBOL(nftnl_rule_list_free);
769void nftnl_rule_list_free(struct nftnl_rule_list *list)
770{
771 struct nftnl_rule *r, *tmp;
772
773 list_for_each_entry_safe(r, tmp, &list->list, head) {
774 list_del(&r->head);
775 nftnl_rule_free(r);
776 }
777 xfree(list);
778}
779
780EXPORT_SYMBOL(nftnl_rule_list_is_empty);
781int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
782{
783 return list_empty(&list->list);
784}
785
786EXPORT_SYMBOL(nftnl_rule_list_add);
787void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
788{
789 list_add(&r->head, &list->list);
790}
791
792EXPORT_SYMBOL(nftnl_rule_list_insert_at);
793void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
794{
795 list_add(&r->head, &pos->head);
796}
797
798EXPORT_SYMBOL(nftnl_rule_list_add_tail);
799void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
800{
801 list_add_tail(&r->head, &list->list);
802}
803
804EXPORT_SYMBOL(nftnl_rule_list_del);
805void nftnl_rule_list_del(struct nftnl_rule *r)
806{
807 list_del(&r->head);
808}
809
810EXPORT_SYMBOL(nftnl_rule_list_foreach);
811int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
812 int (*cb)(struct nftnl_rule *r, void *data),
813 void *data)
814{
815 struct nftnl_rule *cur, *tmp;
816 int ret;
817
818 list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
819 ret = cb(cur, data);
820 if (ret < 0)
821 return ret;
822 }
823 return 0;
824}
825
827 const struct nftnl_rule_list *list;
828 struct nftnl_rule *cur;
829};
830
831EXPORT_SYMBOL(nftnl_rule_list_iter_create);
833nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
834{
835 struct nftnl_rule_list_iter *iter;
836
837 iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
838 if (iter == NULL)
839 return NULL;
840
841 iter->list = l;
842 if (nftnl_rule_list_is_empty(l))
843 iter->cur = NULL;
844 else
845 iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
846
847 return iter;
848}
849
850EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
851struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
852{
853 return iter->cur;
854}
855
856EXPORT_SYMBOL(nftnl_rule_list_iter_next);
857struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
858{
859 struct nftnl_rule *r = iter->cur;
860
861 if (r == NULL)
862 return NULL;
863
864 /* get next rule, if any */
865 iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
866 if (&iter->cur->head == iter->list->list.next)
867 return NULL;
868
869 return r;
870}
871
872EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
873void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
874{
875 xfree(iter);
876}