libnftnl  1.1.9
ruleset.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2013 by Arturo Borrero Gonzalez <arturo@debian.org>
4  * (C) 2013 by Alvaro Neira Ayuso <alvaroneay@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
12  */
13 
14 #include <errno.h>
15 
16 #include "internal.h"
17 #include <stdlib.h>
18 
19 #include <libmnl/libmnl.h>
20 #include <libnftnl/ruleset.h>
21 #include <libnftnl/table.h>
22 #include <libnftnl/chain.h>
23 #include <libnftnl/set.h>
24 #include <libnftnl/rule.h>
25 
26 struct nftnl_ruleset {
27  struct nftnl_table_list *table_list;
28  struct nftnl_chain_list *chain_list;
29  struct nftnl_set_list *set_list;
30  struct nftnl_rule_list *rule_list;
31 
32  uint16_t flags;
33 };
34 
36  enum nftnl_cmd_type cmd;
37  enum nftnl_ruleset_type type;
38  union {
39  struct nftnl_table *table;
40  struct nftnl_chain *chain;
41  struct nftnl_rule *rule;
42  struct nftnl_set *set;
43  struct nftnl_set_elem *set_elem;
44  };
45  void *data;
46 
47  /* These fields below are not exposed to the user */
48  uint32_t format;
49  uint32_t set_id;
50  struct nftnl_set_list *set_list;
51 
52  int (*cb)(const struct nftnl_parse_ctx *ctx);
53  uint16_t flags;
54 };
55 
56 EXPORT_SYMBOL(nftnl_ruleset_alloc);
57 struct nftnl_ruleset *nftnl_ruleset_alloc(void)
58 {
59  return calloc(1, sizeof(struct nftnl_ruleset));
60 }
61 
62 EXPORT_SYMBOL(nftnl_ruleset_free);
63 void nftnl_ruleset_free(const struct nftnl_ruleset *r)
64 {
65  if (r->flags & (1 << NFTNL_RULESET_TABLELIST))
66  nftnl_table_list_free(r->table_list);
67  if (r->flags & (1 << NFTNL_RULESET_CHAINLIST))
68  nftnl_chain_list_free(r->chain_list);
69  if (r->flags & (1 << NFTNL_RULESET_SETLIST))
70  nftnl_set_list_free(r->set_list);
71  if (r->flags & (1 << NFTNL_RULESET_RULELIST))
72  nftnl_rule_list_free(r->rule_list);
73  xfree(r);
74 }
75 
76 EXPORT_SYMBOL(nftnl_ruleset_is_set);
77 bool nftnl_ruleset_is_set(const struct nftnl_ruleset *r, uint16_t attr)
78 {
79  return r->flags & (1 << attr);
80 }
81 
82 EXPORT_SYMBOL(nftnl_ruleset_unset);
83 void nftnl_ruleset_unset(struct nftnl_ruleset *r, uint16_t attr)
84 {
85  if (!(r->flags & (1 << attr)))
86  return;
87 
88  switch (attr) {
89  case NFTNL_RULESET_TABLELIST:
90  nftnl_table_list_free(r->table_list);
91  break;
92  case NFTNL_RULESET_CHAINLIST:
93  nftnl_chain_list_free(r->chain_list);
94  break;
95  case NFTNL_RULESET_SETLIST:
96  nftnl_set_list_free(r->set_list);
97  break;
98  case NFTNL_RULESET_RULELIST:
99  nftnl_rule_list_free(r->rule_list);
100  break;
101  }
102  r->flags &= ~(1 << attr);
103 }
104 
105 EXPORT_SYMBOL(nftnl_ruleset_set);
106 void nftnl_ruleset_set(struct nftnl_ruleset *r, uint16_t attr, void *data)
107 {
108  switch (attr) {
109  case NFTNL_RULESET_TABLELIST:
110  nftnl_ruleset_unset(r, NFTNL_RULESET_TABLELIST);
111  r->table_list = data;
112  break;
113  case NFTNL_RULESET_CHAINLIST:
114  nftnl_ruleset_unset(r, NFTNL_RULESET_CHAINLIST);
115  r->chain_list = data;
116  break;
117  case NFTNL_RULESET_SETLIST:
118  nftnl_ruleset_unset(r, NFTNL_RULESET_SETLIST);
119  r->set_list = data;
120  break;
121  case NFTNL_RULESET_RULELIST:
122  nftnl_ruleset_unset(r, NFTNL_RULESET_RULELIST);
123  r->rule_list = data;
124  break;
125  default:
126  return;
127  }
128  r->flags |= (1 << attr);
129 }
130 
131 EXPORT_SYMBOL(nftnl_ruleset_get);
132 void *nftnl_ruleset_get(const struct nftnl_ruleset *r, uint16_t attr)
133 {
134  if (!(r->flags & (1 << attr)))
135  return NULL;
136 
137  switch (attr) {
138  case NFTNL_RULESET_TABLELIST:
139  return r->table_list;
140  case NFTNL_RULESET_CHAINLIST:
141  return r->chain_list;
142  case NFTNL_RULESET_SETLIST:
143  return r->set_list;
144  case NFTNL_RULESET_RULELIST:
145  return r->rule_list;
146  default:
147  return NULL;
148  }
149 }
150 
151 EXPORT_SYMBOL(nftnl_ruleset_ctx_free);
152 void nftnl_ruleset_ctx_free(const struct nftnl_parse_ctx *ctx)
153 {
154  switch (ctx->type) {
155  case NFTNL_RULESET_TABLE:
156  nftnl_table_free(ctx->table);
157  break;
158  case NFTNL_RULESET_CHAIN:
159  nftnl_chain_free(ctx->chain);
160  break;
161  case NFTNL_RULESET_RULE:
162  nftnl_rule_free(ctx->rule);
163  break;
164  case NFTNL_RULESET_SET:
165  case NFTNL_RULESET_SET_ELEMS:
166  nftnl_set_free(ctx->set);
167  break;
168  case NFTNL_RULESET_RULESET:
169  case NFTNL_RULESET_UNSPEC:
170  break;
171  }
172 }
173 
174 EXPORT_SYMBOL(nftnl_ruleset_ctx_is_set);
175 bool nftnl_ruleset_ctx_is_set(const struct nftnl_parse_ctx *ctx, uint16_t attr)
176 {
177  return ctx->flags & (1 << attr);
178 }
179 
180 EXPORT_SYMBOL(nftnl_ruleset_ctx_get);
181 void *nftnl_ruleset_ctx_get(const struct nftnl_parse_ctx *ctx, uint16_t attr)
182 {
183  if (!(ctx->flags & (1 << attr)))
184  return NULL;
185 
186  switch (attr) {
187  case NFTNL_RULESET_CTX_CMD:
188  return (void *)&ctx->cmd;
189  case NFTNL_RULESET_CTX_TYPE:
190  return (void *)&ctx->type;
191  case NFTNL_RULESET_CTX_TABLE:
192  return ctx->table;
193  case NFTNL_RULESET_CTX_CHAIN:
194  return ctx->chain;
195  case NFTNL_RULESET_CTX_RULE:
196  return ctx->rule;
197  case NFTNL_RULESET_CTX_SET:
198  return ctx->set;
199  case NFTNL_RULESET_CTX_DATA:
200  return ctx->data;
201  default:
202  return NULL;
203  }
204 }
205 
206 EXPORT_SYMBOL(nftnl_ruleset_ctx_get_u32);
207 uint32_t nftnl_ruleset_ctx_get_u32(const struct nftnl_parse_ctx *ctx, uint16_t attr)
208 {
209  const void *ret = nftnl_ruleset_ctx_get(ctx, attr);
210  return ret == NULL ? 0 : *((uint32_t *)ret);
211 }
212 
213 
214 EXPORT_SYMBOL(nftnl_ruleset_parse_file_cb);
215 int nftnl_ruleset_parse_file_cb(enum nftnl_parse_type type, FILE *fp,
216  struct nftnl_parse_err *err, void *data,
217  int (*cb)(const struct nftnl_parse_ctx *ctx))
218 {
219  errno = EOPNOTSUPP;
220  return -1;
221 }
222 
223 EXPORT_SYMBOL(nftnl_ruleset_parse_buffer_cb);
224 int nftnl_ruleset_parse_buffer_cb(enum nftnl_parse_type type, const char *buffer,
225  struct nftnl_parse_err *err, void *data,
226  int (*cb)(const struct nftnl_parse_ctx *ctx))
227 {
228  errno = EOPNOTSUPP;
229  return -1;
230 }
231 
232 static int nftnl_ruleset_cb(const struct nftnl_parse_ctx *ctx)
233 {
234  struct nftnl_ruleset *r = ctx->data;
235 
236  if (ctx->cmd != NFTNL_CMD_ADD)
237  return -1;
238 
239  switch (ctx->type) {
240  case NFTNL_RULESET_TABLE:
241  if (r->table_list == NULL) {
242  r->table_list = nftnl_table_list_alloc();
243  if (r->table_list == NULL)
244  return -1;
245 
246  nftnl_ruleset_set(r, NFTNL_RULESET_TABLELIST,
247  r->table_list);
248  }
249  nftnl_table_list_add_tail(ctx->table, r->table_list);
250  break;
251  case NFTNL_RULESET_CHAIN:
252  if (r->chain_list == NULL) {
253  r->chain_list = nftnl_chain_list_alloc();
254  if (r->chain_list == NULL)
255  return -1;
256 
257  nftnl_ruleset_set(r, NFTNL_RULESET_CHAINLIST,
258  r->chain_list);
259  }
260  nftnl_chain_list_add_tail(ctx->chain, r->chain_list);
261  break;
262  case NFTNL_RULESET_SET:
263  if (r->set_list == NULL) {
264  r->set_list = nftnl_set_list_alloc();
265  if (r->set_list == NULL)
266  return -1;
267 
268  nftnl_ruleset_set(r, NFTNL_RULESET_SETLIST,
269  r->set_list);
270  }
271  nftnl_set_list_add_tail(ctx->set, r->set_list);
272  break;
273  case NFTNL_RULESET_RULE:
274  if (r->rule_list == NULL) {
275  r->rule_list = nftnl_rule_list_alloc();
276  if (r->rule_list == NULL)
277  return -1;
278 
279  nftnl_ruleset_set(r, NFTNL_RULESET_RULELIST,
280  r->rule_list);
281  }
282  nftnl_rule_list_add_tail(ctx->rule, r->rule_list);
283  break;
284  case NFTNL_RULESET_RULESET:
285  break;
286  default:
287  return -1;
288  }
289 
290  return 0;
291 }
292 
293 EXPORT_SYMBOL(nftnl_ruleset_parse);
294 int nftnl_ruleset_parse(struct nftnl_ruleset *r, enum nftnl_parse_type type,
295  const char *data, struct nftnl_parse_err *err)
296 {
297  errno = EOPNOTSUPP;
298  return -1;
299 }
300 
301 EXPORT_SYMBOL(nftnl_ruleset_parse_file);
302 int nftnl_ruleset_parse_file(struct nftnl_ruleset *rs, enum nftnl_parse_type type,
303  FILE *fp, struct nftnl_parse_err *err)
304 {
305  return nftnl_ruleset_parse_file_cb(type, fp, err, rs, nftnl_ruleset_cb);
306 }
307 
308 static const char *nftnl_ruleset_o_opentag(uint32_t type)
309 {
310  switch (type) {
311  case NFTNL_OUTPUT_JSON:
312  return "{\"nftables\":[";
313  case NFTNL_OUTPUT_XML:
314  default:
315  return "";
316  }
317 }
318 
319 static const char *nftnl_ruleset_o_separator(void *obj, uint32_t type)
320 {
321  if (obj == NULL)
322  return "";
323 
324  switch (type) {
325  case NFTNL_OUTPUT_JSON:
326  return ",";
327  case NFTNL_OUTPUT_DEFAULT:
328  return "\n";
329  default:
330  return "";
331  }
332 }
333 
334 static const char *nftnl_ruleset_o_closetag(uint32_t type)
335 {
336  switch (type) {
337  case NFTNL_OUTPUT_JSON:
338  return "]}";
339  case NFTNL_OUTPUT_XML:
340  default:
341  return "";
342  }
343 }
344 
345 static int
346 nftnl_ruleset_snprintf_table(char *buf, size_t size,
347  const struct nftnl_ruleset *rs, uint32_t type,
348  uint32_t flags)
349 {
350  struct nftnl_table *t;
351  struct nftnl_table_list_iter *ti;
352  int ret, remain = size, offset = 0;
353 
354  ti = nftnl_table_list_iter_create(rs->table_list);
355  if (ti == NULL)
356  return 0;
357 
358  t = nftnl_table_list_iter_next(ti);
359  while (t != NULL) {
360  ret = nftnl_table_snprintf(buf + offset, remain, t, type, flags);
361  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
362 
363  t = nftnl_table_list_iter_next(ti);
364 
365  ret = snprintf(buf + offset, remain, "%s",
366  nftnl_ruleset_o_separator(t, type));
367  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
368  }
369  nftnl_table_list_iter_destroy(ti);
370 
371  return offset;
372 }
373 
374 static int
375 nftnl_ruleset_snprintf_chain(char *buf, size_t size,
376  const struct nftnl_ruleset *rs, uint32_t type,
377  uint32_t flags)
378 {
379  struct nftnl_chain *c;
380  struct nftnl_chain_list_iter *ci;
381  int ret, remain = size, offset = 0;
382 
383  ci = nftnl_chain_list_iter_create(rs->chain_list);
384  if (ci == NULL)
385  return 0;
386 
387  c = nftnl_chain_list_iter_next(ci);
388  while (c != NULL) {
389  ret = nftnl_chain_snprintf(buf + offset, remain, c, type, flags);
390  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
391 
392  c = nftnl_chain_list_iter_next(ci);
393 
394  ret = snprintf(buf + offset, remain, "%s",
395  nftnl_ruleset_o_separator(c, type));
396  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
397  }
398  nftnl_chain_list_iter_destroy(ci);
399 
400  return offset;
401 }
402 
403 static int
404 nftnl_ruleset_snprintf_set(char *buf, size_t size,
405  const struct nftnl_ruleset *rs, uint32_t type,
406  uint32_t flags)
407 {
408  struct nftnl_set *s;
409  struct nftnl_set_list_iter *si;
410  int ret, remain = size, offset = 0;
411 
412  si = nftnl_set_list_iter_create(rs->set_list);
413  if (si == NULL)
414  return 0;
415 
416  s = nftnl_set_list_iter_next(si);
417  while (s != NULL) {
418  ret = nftnl_set_snprintf(buf + offset, remain, s, type, flags);
419  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
420 
421  s = nftnl_set_list_iter_next(si);
422 
423  ret = snprintf(buf + offset, remain, "%s",
424  nftnl_ruleset_o_separator(s, type));
425  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
426  }
427  nftnl_set_list_iter_destroy(si);
428 
429  return offset;
430 }
431 
432 static int
433 nftnl_ruleset_snprintf_rule(char *buf, size_t size,
434  const struct nftnl_ruleset *rs, uint32_t type,
435  uint32_t flags)
436 {
437  struct nftnl_rule *r;
438  struct nftnl_rule_list_iter *ri;
439  int ret, remain = size, offset = 0;
440 
441  ri = nftnl_rule_list_iter_create(rs->rule_list);
442  if (ri == NULL)
443  return 0;
444 
445  r = nftnl_rule_list_iter_next(ri);
446  while (r != NULL) {
447  ret = nftnl_rule_snprintf(buf + offset, remain, r, type, flags);
448  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
449 
450  r = nftnl_rule_list_iter_next(ri);
451 
452  ret = snprintf(buf + offset, remain, "%s",
453  nftnl_ruleset_o_separator(r, type));
454  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
455  }
456  nftnl_rule_list_iter_destroy(ri);
457 
458  return offset;
459 }
460 
461 static int
462 nftnl_ruleset_do_snprintf(char *buf, size_t size, const struct nftnl_ruleset *rs,
463  uint32_t cmd, uint32_t type, uint32_t flags)
464 {
465  int ret, remain = size, offset = 0;
466  void *prev = NULL;
467  uint32_t inner_flags = flags;
468 
469  /* dont pass events flags to child calls of _snprintf() */
470  inner_flags &= ~NFTNL_OF_EVENT_ANY;
471 
472  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_TABLELIST) &&
473  (!nftnl_table_list_is_empty(rs->table_list))) {
474  ret = nftnl_ruleset_snprintf_table(buf + offset, remain, rs,
475  type, inner_flags);
476  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
477 
478  if (ret > 0)
479  prev = rs->table_list;
480  }
481 
482  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_CHAINLIST) &&
483  (!nftnl_chain_list_is_empty(rs->chain_list))) {
484  ret = snprintf(buf + offset, remain, "%s",
485  nftnl_ruleset_o_separator(prev, type));
486  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
487 
488  ret = nftnl_ruleset_snprintf_chain(buf + offset, remain, rs,
489  type, inner_flags);
490  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
491 
492  if (ret > 0)
493  prev = rs->chain_list;
494  }
495 
496  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_SETLIST) &&
497  (!nftnl_set_list_is_empty(rs->set_list))) {
498  ret = snprintf(buf + offset, remain, "%s",
499  nftnl_ruleset_o_separator(prev, type));
500  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
501 
502  ret = nftnl_ruleset_snprintf_set(buf + offset, remain, rs,
503  type, inner_flags);
504  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
505 
506  if (ret > 0)
507  prev = rs->set_list;
508  }
509 
510  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_RULELIST) &&
511  (!nftnl_rule_list_is_empty(rs->rule_list))) {
512  ret = snprintf(buf + offset, remain, "%s",
513  nftnl_ruleset_o_separator(prev, type));
514  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
515 
516  ret = nftnl_ruleset_snprintf_rule(buf + offset, remain, rs,
517  type, inner_flags);
518  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
519  }
520 
521  return offset;
522 }
523 
524 static int nftnl_ruleset_cmd_snprintf(char *buf, size_t size,
525  const struct nftnl_ruleset *r, uint32_t cmd,
526  uint32_t type, uint32_t flags)
527 {
528  switch (type) {
529  case NFTNL_OUTPUT_DEFAULT:
530  case NFTNL_OUTPUT_JSON:
531  return nftnl_ruleset_do_snprintf(buf, size, r, cmd, type, flags);
532  case NFTNL_OUTPUT_XML:
533  default:
534  errno = EOPNOTSUPP;
535  return -1;
536  }
537 }
538 
539 EXPORT_SYMBOL(nftnl_ruleset_snprintf);
540 int nftnl_ruleset_snprintf(char *buf, size_t size, const struct nftnl_ruleset *r,
541  uint32_t type, uint32_t flags)
542 {
543  if (size)
544  buf[0] = '\0';
545 
546  switch (type) {
547  case NFTNL_OUTPUT_DEFAULT:
548  case NFTNL_OUTPUT_JSON:
549  return nftnl_ruleset_cmd_snprintf(buf, size, r,
550  nftnl_flag2cmd(flags), type,
551  flags);
552  case NFTNL_OUTPUT_XML:
553  default:
554  errno = EOPNOTSUPP;
555  return -1;
556  }
557 }
558 
559 static int nftnl_ruleset_fprintf_tables(FILE *fp, const struct nftnl_ruleset *rs,
560  uint32_t type, uint32_t flags)
561 {
562  int len = 0, ret = 0;
563  struct nftnl_table *t;
564  struct nftnl_table_list_iter *ti;
565 
566  ti = nftnl_table_list_iter_create(rs->table_list);
567  if (ti == NULL)
568  return -1;
569 
570  t = nftnl_table_list_iter_next(ti);
571  while (t != NULL) {
572  ret = nftnl_table_fprintf(fp, t, type, flags);
573  if (ret < 0)
574  goto err;
575 
576  len += ret;
577 
578  t = nftnl_table_list_iter_next(ti);
579 
580  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(t, type));
581  if (ret < 0)
582  goto err;
583 
584  len += ret;
585  }
586  nftnl_table_list_iter_destroy(ti);
587 
588  return len;
589 err:
590  nftnl_table_list_iter_destroy(ti);
591  return -1;
592 }
593 
594 static int nftnl_ruleset_fprintf_chains(FILE *fp, const struct nftnl_ruleset *rs,
595  uint32_t type, uint32_t flags)
596 {
597  int len = 0, ret = 0;
598  struct nftnl_chain *o;
599  struct nftnl_chain_list_iter *i;
600 
601  i = nftnl_chain_list_iter_create(rs->chain_list);
602  if (i == NULL)
603  return -1;
604 
605  o = nftnl_chain_list_iter_next(i);
606  while (o != NULL) {
607  ret = nftnl_chain_fprintf(fp, o, type, flags);
608  if (ret < 0)
609  goto err;
610 
611  len += ret;
612 
613  o = nftnl_chain_list_iter_next(i);
614 
615  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(o, type));
616  if (ret < 0)
617  goto err;
618 
619  len += ret;
620  }
621  nftnl_chain_list_iter_destroy(i);
622 
623  return len;
624 err:
625  nftnl_chain_list_iter_destroy(i);
626  return -1;
627 }
628 
629 static int nftnl_ruleset_fprintf_sets(FILE *fp, const struct nftnl_ruleset *rs,
630  uint32_t type, uint32_t flags)
631 {
632  int len = 0, ret = 0;
633  struct nftnl_set *o;
634  struct nftnl_set_list_iter *i;
635 
636  i = nftnl_set_list_iter_create(rs->set_list);
637  if (i == NULL)
638  return -1;
639 
640  o = nftnl_set_list_iter_next(i);
641  while (o != NULL) {
642  ret = nftnl_set_fprintf(fp, o, type, flags);
643  if (ret < 0)
644  goto err;
645 
646  len += ret;
647 
648  o = nftnl_set_list_iter_next(i);
649 
650  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(o, type));
651  if (ret < 0)
652  goto err;
653 
654  len += ret;
655  }
656  nftnl_set_list_iter_destroy(i);
657 
658  return len;
659 err:
660  nftnl_set_list_iter_destroy(i);
661  return -1;
662 }
663 
664 static int nftnl_ruleset_fprintf_rules(FILE *fp, const struct nftnl_ruleset *rs,
665  uint32_t type, uint32_t flags)
666 {
667  int len = 0, ret = 0;
668  struct nftnl_rule *o;
669  struct nftnl_rule_list_iter *i;
670 
671  i = nftnl_rule_list_iter_create(rs->rule_list);
672  if (i == NULL)
673  return -1;
674 
675  o = nftnl_rule_list_iter_next(i);
676  while (o != NULL) {
677  ret = nftnl_rule_fprintf(fp, o, type, flags);
678  if (ret < 0)
679  goto err;
680 
681  len += ret;
682 
683  o = nftnl_rule_list_iter_next(i);
684 
685  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(o, type));
686  if (ret < 0)
687  goto err;
688 
689  len += ret;
690  }
691  nftnl_rule_list_iter_destroy(i);
692 
693  return len;
694 err:
695  nftnl_rule_list_iter_destroy(i);
696  return -1;
697 }
698 
699 #define NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len) \
700  if (ret < 0) \
701  return -1; \
702  len += ret;
703 
704 static int nftnl_ruleset_cmd_fprintf(FILE *fp, const struct nftnl_ruleset *rs,
705  uint32_t cmd, uint32_t type, uint32_t flags)
706 {
707  int len = 0, ret = 0;
708  void *prev = NULL;
709  uint32_t inner_flags = flags;
710 
711  /* dont pass events flags to child calls of _snprintf() */
712  inner_flags &= ~NFTNL_OF_EVENT_ANY;
713 
714  ret = fprintf(fp, "%s", nftnl_ruleset_o_opentag(type));
715  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
716 
717  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_TABLELIST)) &&
718  (!nftnl_table_list_is_empty(rs->table_list))) {
719  ret = nftnl_ruleset_fprintf_tables(fp, rs, type, inner_flags);
720  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
721 
722  if (ret > 0)
723  prev = rs->table_list;
724  }
725 
726  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_CHAINLIST)) &&
727  (!nftnl_chain_list_is_empty(rs->chain_list))) {
728  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(prev, type));
729  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
730 
731  ret = nftnl_ruleset_fprintf_chains(fp, rs, type, inner_flags);
732  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
733 
734  if (ret > 0)
735  prev = rs->chain_list;
736  }
737 
738  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_SETLIST)) &&
739  (!nftnl_set_list_is_empty(rs->set_list))) {
740  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(prev, type));
741  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
742 
743  ret = nftnl_ruleset_fprintf_sets(fp, rs, type, inner_flags);
744  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
745 
746  if (ret > 0)
747  prev = rs->set_list;
748  }
749 
750  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_RULELIST)) &&
751  (!nftnl_rule_list_is_empty(rs->rule_list))) {
752  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(prev, type));
753  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
754 
755  ret = nftnl_ruleset_fprintf_rules(fp, rs, type, inner_flags);
756  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
757  }
758 
759  ret = fprintf(fp, "%s", nftnl_ruleset_o_closetag(type));
760  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
761 
762  return len;
763 }
764 
765 EXPORT_SYMBOL(nftnl_ruleset_fprintf);
766 int nftnl_ruleset_fprintf(FILE *fp, const struct nftnl_ruleset *rs, uint32_t type,
767  uint32_t flags)
768 {
769  return nftnl_ruleset_cmd_fprintf(fp, rs, nftnl_flag2cmd(flags), type,
770  flags);
771 }