libnftnl  1.0.2
ruleset.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2013 by Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
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 nft_ruleset {
27  struct nft_table_list *table_list;
28  struct nft_chain_list *chain_list;
29  struct nft_set_list *set_list;
30  struct nft_rule_list *rule_list;
31 
32  uint16_t flags;
33 };
34 
35 struct nft_ruleset *nft_ruleset_alloc(void)
36 {
37  return calloc(1, sizeof(struct nft_ruleset));
38 }
39 EXPORT_SYMBOL(nft_ruleset_alloc);
40 
41 void nft_ruleset_free(struct nft_ruleset *r)
42 {
43  if (r->flags & (1 << NFT_RULESET_ATTR_TABLELIST))
44  nft_table_list_free(r->table_list);
45  if (r->flags & (1 << NFT_RULESET_ATTR_CHAINLIST))
46  nft_chain_list_free(r->chain_list);
47  if (r->flags & (1 << NFT_RULESET_ATTR_SETLIST))
48  nft_set_list_free(r->set_list);
49  if (r->flags & (1 << NFT_RULESET_ATTR_RULELIST))
50  nft_rule_list_free(r->rule_list);
51  xfree(r);
52 }
53 EXPORT_SYMBOL(nft_ruleset_free);
54 
55 bool nft_ruleset_attr_is_set(const struct nft_ruleset *r, uint16_t attr)
56 {
57  return r->flags & (1 << attr);
58 }
59 EXPORT_SYMBOL(nft_ruleset_attr_is_set);
60 
61 void nft_ruleset_attr_unset(struct nft_ruleset *r, uint16_t attr)
62 {
63  if (!(r->flags & (1 << attr)))
64  return;
65 
66  switch (attr) {
67  case NFT_RULESET_ATTR_TABLELIST:
68  nft_table_list_free(r->table_list);
69  r->table_list = NULL;
70  break;
71  case NFT_RULESET_ATTR_CHAINLIST:
72  nft_chain_list_free(r->chain_list);
73  r->chain_list = NULL;
74  break;
75  case NFT_RULESET_ATTR_SETLIST:
76  nft_set_list_free(r->set_list);
77  r->set_list = NULL;
78  break;
79  case NFT_RULESET_ATTR_RULELIST:
80  nft_rule_list_free(r->rule_list);
81  r->rule_list = NULL;
82  break;
83  }
84  r->flags &= ~(1 << attr);
85 }
86 EXPORT_SYMBOL(nft_ruleset_attr_unset);
87 
88 void nft_ruleset_attr_set(struct nft_ruleset *r, uint16_t attr, void *data)
89 {
90  switch (attr) {
91  case NFT_RULESET_ATTR_TABLELIST:
92  nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_TABLELIST);
93  r->table_list = data;
94  break;
95  case NFT_RULESET_ATTR_CHAINLIST:
96  nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_CHAINLIST);
97  r->chain_list = data;
98  break;
99  case NFT_RULESET_ATTR_SETLIST:
100  nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_SETLIST);
101  r->set_list = data;
102  break;
103  case NFT_RULESET_ATTR_RULELIST:
104  nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_RULELIST);
105  r->rule_list = data;
106  break;
107  default:
108  return;
109  }
110  r->flags |= (1 << attr);
111 }
112 EXPORT_SYMBOL(nft_ruleset_attr_set);
113 
114 const void *nft_ruleset_attr_get(const struct nft_ruleset *r, uint16_t attr)
115 {
116  if (!(r->flags & (1 << attr)))
117  return NULL;
118 
119  switch (attr) {
120  case NFT_RULESET_ATTR_TABLELIST:
121  return r->table_list;
122  case NFT_RULESET_ATTR_CHAINLIST:
123  return r->chain_list;
124  case NFT_RULESET_ATTR_SETLIST:
125  return r->set_list;
126  case NFT_RULESET_ATTR_RULELIST:
127  return r->rule_list;
128  default:
129  return NULL;
130  }
131 }
132 EXPORT_SYMBOL(nft_ruleset_attr_get);
133 
134 #ifdef JSON_PARSING
135 static int nft_ruleset_json_parse_tables(struct nft_ruleset *rs, json_t *array,
136  struct nft_parse_err *err)
137 {
138  int i, len;
139  json_t *node;
140  struct nft_table *o;
141  struct nft_table_list *list = nft_table_list_alloc();
142 
143  if (list == NULL) {
144  errno = ENOMEM;
145  return -1;
146  }
147 
148  len = json_array_size(array);
149  for (i = 0; i < len; i++) {
150  node = json_array_get(array, i);
151  if (node == NULL) {
152  errno = EINVAL;
153  goto err;
154  }
155 
156  if (!(nft_jansson_node_exist(node, "table")))
157  continue;
158 
159  o = nft_table_alloc();
160  if (o == NULL) {
161  errno = ENOMEM;
162  goto err;
163  }
164 
165  if (nft_jansson_parse_table(o, node, err) < 0) {
166  nft_table_free(o);
167  goto err;
168  }
169 
170  nft_table_list_add_tail(o, list);
171  }
172 
173  if (!nft_table_list_is_empty(list))
174  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST, list);
175  else
176  nft_table_list_free(list);
177 
178  return 0;
179 err:
180  nft_table_list_free(list);
181  return -1;
182 }
183 
184 static int nft_ruleset_json_parse_chains(struct nft_ruleset *rs, json_t *array,
185  struct nft_parse_err *err)
186 {
187  int i, len;
188  json_t *node;
189  struct nft_chain *o;
190  struct nft_chain_list *list = nft_chain_list_alloc();
191 
192  if (list == NULL) {
193  errno = ENOMEM;
194  return -1;
195  }
196 
197  len = json_array_size(array);
198  for (i = 0; i < len; i++) {
199  node = json_array_get(array, i);
200  if (node == NULL) {
201  errno = EINVAL;
202  goto err;
203  }
204 
205  if (!(nft_jansson_node_exist(node, "chain")))
206  continue;
207 
208  o = nft_chain_alloc();
209  if (o == NULL) {
210  errno = ENOMEM;
211  goto err;
212  }
213 
214  if (nft_jansson_parse_chain(o, node, err) < 0) {
215  nft_chain_free(o);
216  goto err;
217  }
218 
219  nft_chain_list_add_tail(o, list);
220  }
221 
222  if (!nft_chain_list_is_empty(list))
223  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, list);
224  else
225  nft_chain_list_free(list);
226 
227  return 0;
228 err:
229  nft_chain_list_free(list);
230  return -1;
231 }
232 
233 static int nft_ruleset_json_parse_sets(struct nft_ruleset *rs, json_t *array,
234  struct nft_parse_err *err)
235 {
236  int i, len;
237  json_t *node;
238  struct nft_set *s = NULL;
239  struct nft_set_list *list = nft_set_list_alloc();
240 
241  if (list == NULL) {
242  errno = ENOMEM;
243  return -1;
244  }
245 
246  len = json_array_size(array);
247  for (i = 0; i < len; i++) {
248  node = json_array_get(array, i);
249  if (node == NULL) {
250  errno = EINVAL;
251  goto err;
252  }
253 
254  if (!(nft_jansson_node_exist(node, "set")))
255  continue;
256 
257  s = nft_set_alloc();
258  if (s == NULL) {
259  errno = ENOMEM;
260  goto err;
261  }
262 
263  if (nft_jansson_parse_set(s, node, err) < 0) {
264  nft_set_free(s);
265  goto err;
266  }
267 
268  nft_set_list_add_tail(s, list);
269  }
270 
271  if (!nft_set_list_is_empty(list))
272  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, list);
273  else
274  nft_set_list_free(list);
275 
276  return 0;
277 err:
278  nft_set_list_free(list);
279  return -1;
280 }
281 
282 static int nft_ruleset_json_parse_rules(struct nft_ruleset *rs, json_t *array,
283  struct nft_parse_err *err)
284 {
285  int i, len;
286  json_t *node;
287  struct nft_rule *o = NULL;
288  struct nft_rule_list *list = nft_rule_list_alloc();
289 
290  if (list == NULL) {
291  errno = ENOMEM;
292  return -1;
293  }
294 
295  len = json_array_size(array);
296  for (i = 0; i < len; i++) {
297  node = json_array_get(array, i);
298  if (node == NULL) {
299  errno = EINVAL;
300  goto err;
301  }
302 
303  if (!(nft_jansson_node_exist(node, "rule")))
304  continue;
305 
306  o = nft_rule_alloc();
307  if (o == NULL) {
308  errno = ENOMEM;
309  goto err;
310  }
311 
312  if (nft_jansson_parse_rule(o, node, err) < 0) {
313  nft_rule_free(o);
314  goto err;
315  }
316 
317  nft_rule_list_add_tail(o, list);
318  }
319 
320  if (!nft_rule_list_is_empty(list))
321  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, list);
322  else
323  nft_rule_list_free(list);
324 
325  return 0;
326 err:
327  nft_rule_list_free(list);
328  return -1;
329 }
330 
331 #endif
332 
333 static int nft_ruleset_json_parse(struct nft_ruleset *rs, const void *json,
334  struct nft_parse_err *err, enum nft_parse_input input)
335 {
336 #ifdef JSON_PARSING
337  json_t *root, *array;
338  json_error_t error;
339 
340  root = nft_jansson_create_root(json, &error, err, input);
341  if (root == NULL)
342  return -1;
343 
344  array = json_object_get(root, "nftables");
345  if (array == NULL) {
346  errno = EINVAL;
347  goto err;
348  }
349 
350  if (nft_ruleset_json_parse_tables(rs, array, err) != 0)
351  goto err;
352 
353  if (nft_ruleset_json_parse_chains(rs, array, err) != 0)
354  goto err;
355 
356  if (nft_ruleset_json_parse_sets(rs, array, err) != 0)
357  goto err;
358 
359  if (nft_ruleset_json_parse_rules(rs, array, err) != 0)
360  goto err;
361 
362  nft_jansson_free_root(root);
363  return 0;
364 err:
365  nft_jansson_free_root(root);
366  return -1;
367 #else
368  errno = EOPNOTSUPP;
369  return -1;
370 #endif
371 }
372 
373 #ifdef XML_PARSING
374 static int
375 nft_ruleset_xml_parse_tables(struct nft_ruleset *rs, mxml_node_t *tree,
376  struct nft_parse_err *err)
377 {
378  mxml_node_t *node;
379  struct nft_table *t;
380  struct nft_table_list *table_list = nft_table_list_alloc();
381  if (table_list == NULL) {
382  errno = ENOMEM;
383  return -1;
384  }
385 
386  for (node = mxmlFindElement(tree, tree, "table", NULL, NULL,
387  MXML_DESCEND_FIRST);
388  node != NULL;
389  node = mxmlFindElement(node, tree, "table", NULL, NULL,
390  MXML_NO_DESCEND)) {
391  t = nft_table_alloc();
392  if (t == NULL)
393  goto err_free;
394 
395  if (nft_mxml_table_parse(node, t, err) != 0) {
396  nft_table_free(t);
397  goto err_free;
398  }
399 
400  nft_table_list_add_tail(t, table_list);
401  }
402 
403  if (!nft_table_list_is_empty(table_list))
404  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST,
405  table_list);
406  else
407  nft_table_list_free(table_list);
408 
409  return 0;
410 err_free:
411  nft_table_list_free(table_list);
412  return -1;
413 }
414 
415 static int
416 nft_ruleset_xml_parse_chains(struct nft_ruleset *rs, mxml_node_t *tree,
417  struct nft_parse_err *err)
418 {
419  mxml_node_t *node;
420  struct nft_chain *c;
421  struct nft_chain_list *chain_list = nft_chain_list_alloc();
422  if (chain_list == NULL) {
423  errno = ENOMEM;
424  return -1;
425  }
426 
427  for (node = mxmlFindElement(tree, tree, "chain", NULL, NULL,
428  MXML_DESCEND_FIRST);
429  node != NULL;
430  node = mxmlFindElement(node, tree, "chain", NULL, NULL,
431  MXML_NO_DESCEND)) {
432  c = nft_chain_alloc();
433  if (c == NULL)
434  goto err_free;
435 
436  if (nft_mxml_chain_parse(node, c, err) != 0) {
437  nft_chain_free(c);
438  goto err_free;
439  }
440 
441  nft_chain_list_add_tail(c, chain_list);
442  }
443 
444  if (!nft_chain_list_is_empty(chain_list))
445  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST,
446  chain_list);
447  else
448  nft_chain_list_free(chain_list);
449 
450  return 0;
451 err_free:
452  nft_chain_list_free(chain_list);
453  return -1;
454 }
455 
456 static int
457 nft_ruleset_xml_parse_sets(struct nft_ruleset *rs, mxml_node_t *tree,
458  struct nft_parse_err *err)
459 {
460  mxml_node_t *node;
461  struct nft_set *s;
462  struct nft_set_list *set_list = nft_set_list_alloc();
463  if (set_list == NULL) {
464  errno = ENOMEM;
465  return -1;
466  }
467 
468  for (node = mxmlFindElement(tree, tree, "set", NULL, NULL,
469  MXML_DESCEND_FIRST);
470  node != NULL;
471  node = mxmlFindElement(node, tree, "set", NULL, NULL,
472  MXML_NO_DESCEND)) {
473  s = nft_set_alloc();
474  if (s == NULL)
475  goto err_free;
476 
477  if (nft_mxml_set_parse(node, s, err) != 0) {
478  nft_set_free(s);
479  goto err_free;
480  }
481 
482  nft_set_list_add_tail(s, set_list);
483  }
484 
485  if (!nft_set_list_is_empty(set_list))
486  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, set_list);
487  else
488  nft_set_list_free(set_list);
489 
490  return 0;
491 err_free:
492  nft_set_list_free(set_list);
493  return -1;
494 }
495 
496 static int
497 nft_ruleset_xml_parse_rules(struct nft_ruleset *rs, mxml_node_t *tree,
498  struct nft_parse_err *err)
499 {
500  mxml_node_t *node;
501  struct nft_rule *r;
502  struct nft_rule_list *rule_list = nft_rule_list_alloc();
503  if (rule_list == NULL) {
504  errno = ENOMEM;
505  return -1;
506  }
507 
508  for (node = mxmlFindElement(tree, tree, "rule", NULL, NULL,
509  MXML_DESCEND_FIRST);
510  node != NULL;
511  node = mxmlFindElement(node, tree, "rule", NULL, NULL,
512  MXML_NO_DESCEND)) {
513  r = nft_rule_alloc();
514  if (r == NULL)
515  goto err_free;
516 
517  if (nft_mxml_rule_parse(node, r, err) != 0) {
518  nft_rule_free(r);
519  goto err_free;
520  }
521 
522  nft_rule_list_add_tail(r, rule_list);
523  }
524 
525  if (!nft_rule_list_is_empty(rule_list))
526  nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, rule_list);
527  else
528  nft_rule_list_free(rule_list);
529 
530  return 0;
531 err_free:
532  nft_rule_list_free(rule_list);
533  return -1;
534 }
535 #endif
536 
537 static int nft_ruleset_xml_parse(struct nft_ruleset *rs, const void *xml,
538  struct nft_parse_err *err, enum nft_parse_input input)
539 {
540 #ifdef XML_PARSING
541  mxml_node_t *tree;
542 
543  tree = nft_mxml_build_tree(xml, "nftables", err, input);
544  if (tree == NULL)
545  return -1;
546 
547  if (nft_ruleset_xml_parse_tables(rs, tree, err) != 0)
548  goto err;
549 
550  if (nft_ruleset_xml_parse_chains(rs, tree, err) != 0)
551  goto err;
552 
553  if (nft_ruleset_xml_parse_sets(rs, tree, err) != 0)
554  goto err;
555 
556  if (nft_ruleset_xml_parse_rules(rs, tree, err) != 0)
557  goto err;
558 
559  mxmlDelete(tree);
560  return 0;
561 err:
562  mxmlDelete(tree);
563  return -1;
564 #else
565  errno = EOPNOTSUPP;
566  return -1;
567 #endif
568 }
569 
570 static int
571 nft_ruleset_do_parse(struct nft_ruleset *r, enum nft_parse_type type,
572  const void *data, struct nft_parse_err *err,
573  enum nft_parse_input input)
574 {
575  int ret;
576 
577  switch (type) {
578  case NFT_PARSE_XML:
579  ret = nft_ruleset_xml_parse(r, data, err, input);
580  break;
581  case NFT_PARSE_JSON:
582  ret = nft_ruleset_json_parse(r, data, err, input);
583  break;
584  default:
585  ret = -1;
586  errno = EOPNOTSUPP;
587  break;
588  }
589 
590  return ret;
591 }
592 
593 int nft_ruleset_parse(struct nft_ruleset *r, enum nft_parse_type type,
594  const char *data, struct nft_parse_err *err)
595 {
596  return nft_ruleset_do_parse(r, type, data, err, NFT_PARSE_BUFFER);
597 }
598 EXPORT_SYMBOL(nft_ruleset_parse);
599 
600 int nft_ruleset_parse_file(struct nft_ruleset *rs, enum nft_parse_type type,
601  FILE *fp, struct nft_parse_err *err)
602 {
603  return nft_ruleset_do_parse(rs, type, fp, err, NFT_PARSE_FILE);
604 }
605 EXPORT_SYMBOL(nft_ruleset_parse_file);
606 
607 static const char *nft_ruleset_o_opentag(uint32_t type)
608 {
609  switch (type) {
610  case NFT_OUTPUT_XML:
611  return "<nftables>";
612  case NFT_OUTPUT_JSON:
613  return "{\"nftables\":[";
614  default:
615  return "";
616  }
617 }
618 
619 static const char *nft_ruleset_o_separator(void *obj, uint32_t type)
620 {
621  if (obj == NULL)
622  return "";
623 
624  switch (type) {
625  case NFT_OUTPUT_JSON:
626  return ",";
627  case NFT_OUTPUT_DEFAULT:
628  return "\n";
629  default:
630  return "";
631  }
632 }
633 
634 static const char *nft_ruleset_o_closetag(uint32_t type)
635 {
636  switch (type) {
637  case NFT_OUTPUT_XML:
638  return "</nftables>";
639  case NFT_OUTPUT_JSON:
640  return "]}";
641  default:
642  return "";
643  }
644 }
645 
646 static int
647 nft_ruleset_snprintf_table(char *buf, size_t size,
648  const struct nft_ruleset *rs, uint32_t type,
649  uint32_t flags)
650 {
651  struct nft_table *t;
652  struct nft_table_list_iter *ti;
653  int ret, len = size, offset = 0;
654 
655  ti = nft_table_list_iter_create(rs->table_list);
656  if (ti == NULL)
657  return 0;
658 
659  t = nft_table_list_iter_next(ti);
660  while (t != NULL) {
661  ret = nft_table_snprintf(buf+offset, len, t, type, flags);
662  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
663 
664  t = nft_table_list_iter_next(ti);
665 
666  ret = snprintf(buf+offset, len, "%s",
667  nft_ruleset_o_separator(t, type));
668  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
669  }
670  nft_table_list_iter_destroy(ti);
671 
672  return offset;
673 }
674 
675 static int
676 nft_ruleset_snprintf_chain(char *buf, size_t size,
677  const struct nft_ruleset *rs, uint32_t type,
678  uint32_t flags)
679 {
680  struct nft_chain *c;
681  struct nft_chain_list_iter *ci;
682  int ret, len = size, offset = 0;
683 
684  ci = nft_chain_list_iter_create(rs->chain_list);
685  if (ci == NULL)
686  return 0;
687 
688  c = nft_chain_list_iter_next(ci);
689  while (c != NULL) {
690  ret = nft_chain_snprintf(buf+offset, len, c, type, flags);
691  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
692 
693  c = nft_chain_list_iter_next(ci);
694 
695  ret = snprintf(buf+offset, len, "%s",
696  nft_ruleset_o_separator(c, type));
697  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
698  }
699  nft_chain_list_iter_destroy(ci);
700 
701  return offset;
702 }
703 
704 static int
705 nft_ruleset_snprintf_set(char *buf, size_t size,
706  const struct nft_ruleset *rs, uint32_t type,
707  uint32_t flags)
708 {
709  struct nft_set *s;
710  struct nft_set_list_iter *si;
711  int ret, len = size, offset = 0;
712 
713  si = nft_set_list_iter_create(rs->set_list);
714  if (si == NULL)
715  return 0;
716 
717  s = nft_set_list_iter_next(si);
718  while (s != NULL) {
719  ret = nft_set_snprintf(buf+offset, len, s, type, flags);
720  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
721 
722  s = nft_set_list_iter_next(si);
723 
724  ret = snprintf(buf+offset, len, "%s",
725  nft_ruleset_o_separator(s, type));
726  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
727  }
728  nft_set_list_iter_destroy(si);
729 
730  return offset;
731 }
732 
733 static int
734 nft_ruleset_snprintf_rule(char *buf, size_t size,
735  const struct nft_ruleset *rs, uint32_t type,
736  uint32_t flags)
737 {
738  struct nft_rule *r;
739  struct nft_rule_list_iter *ri;
740  int ret, len = size, offset = 0;
741 
742  ri = nft_rule_list_iter_create(rs->rule_list);
743  if (ri == NULL)
744  return 0;
745 
746  r = nft_rule_list_iter_next(ri);
747  while (r != NULL) {
748  ret = nft_rule_snprintf(buf+offset, len, r, type, flags);
749  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
750 
751  r = nft_rule_list_iter_next(ri);
752 
753  ret = snprintf(buf+offset, len, "%s",
754  nft_ruleset_o_separator(r, type));
755  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
756  }
757  nft_rule_list_iter_destroy(ri);
758 
759  return offset;
760 }
761 
762 static int
763 nft_ruleset_do_snprintf(char *buf, size_t size, const struct nft_ruleset *rs,
764  uint32_t type, uint32_t flags)
765 {
766  int ret, len = size, offset = 0;
767  void *prev = NULL;
768  uint32_t inner_flags = flags;
769 
770  /* dont pass events flags to child calls of _snprintf() */
771  inner_flags &= ~NFT_OF_EVENT_ANY;
772 
773  ret = nft_event_header_snprintf(buf+offset, len, type, flags);
774  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
775 
776  ret = snprintf(buf+offset, len, "%s", nft_ruleset_o_opentag(type));
777  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
778 
779  if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_TABLELIST) &&
780  (!nft_table_list_is_empty(rs->table_list))) {
781  ret = nft_ruleset_snprintf_table(buf+offset, len, rs,
782  type, inner_flags);
783  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
784 
785  if (ret > 0)
786  prev = rs->table_list;
787  }
788 
789  if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST) &&
790  (!nft_chain_list_is_empty(rs->chain_list))) {
791  ret = snprintf(buf+offset, len, "%s",
792  nft_ruleset_o_separator(prev, type));
793  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
794 
795  ret = nft_ruleset_snprintf_chain(buf+offset, len, rs,
796  type, inner_flags);
797  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
798 
799  if (ret > 0)
800  prev = rs->chain_list;
801  }
802 
803  if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_SETLIST) &&
804  (!nft_set_list_is_empty(rs->set_list))) {
805  ret = snprintf(buf+offset, len, "%s",
806  nft_ruleset_o_separator(prev, type));
807  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
808 
809  ret = nft_ruleset_snprintf_set(buf+offset, len, rs,
810  type, inner_flags);
811  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
812 
813  if (ret > 0)
814  prev = rs->set_list;
815  }
816 
817  if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST) &&
818  (!nft_rule_list_is_empty(rs->rule_list))) {
819  ret = snprintf(buf+offset, len, "%s",
820  nft_ruleset_o_separator(prev, type));
821  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
822 
823  ret = nft_ruleset_snprintf_rule(buf+offset, len, rs,
824  type, inner_flags);
825  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
826  }
827 
828  ret = snprintf(buf+offset, len, "%s", nft_ruleset_o_closetag(type));
829  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
830 
831  ret = nft_event_footer_snprintf(buf+offset, len, type, flags);
832  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
833 
834  return offset;
835 }
836 
837 int nft_ruleset_snprintf(char *buf, size_t size, const struct nft_ruleset *r,
838  uint32_t type, uint32_t flags)
839 {
840  switch (type) {
841  case NFT_OUTPUT_DEFAULT:
842  case NFT_OUTPUT_XML:
843  case NFT_OUTPUT_JSON:
844  return nft_ruleset_do_snprintf(buf, size, r, type, flags);
845  default:
846  errno = EOPNOTSUPP;
847  return -1;
848  }
849 }
850 EXPORT_SYMBOL(nft_ruleset_snprintf);
851 
852 static int nft_ruleset_fprintf_tables(FILE *fp, const struct nft_ruleset *rs,
853  uint32_t type, uint32_t flags)
854 {
855  int len = 0, ret = 0;
856  struct nft_table *t;
857  struct nft_table_list_iter *ti;
858 
859  ti = nft_table_list_iter_create(rs->table_list);
860  if (ti == NULL)
861  return -1;
862 
863  t = nft_table_list_iter_next(ti);
864  while (t != NULL) {
865  ret = nft_table_fprintf(fp, t, type, flags);
866  if (ret < 0)
867  goto err;
868 
869  len += ret;
870 
871  t = nft_table_list_iter_next(ti);
872 
873  ret = fprintf(fp, "%s", nft_ruleset_o_separator(t, type));
874  if (ret < 0)
875  goto err;
876 
877  len += ret;
878  }
879  nft_table_list_iter_destroy(ti);
880 
881  return len;
882 err:
883  nft_table_list_iter_destroy(ti);
884  return -1;
885 }
886 
887 static int nft_ruleset_fprintf_chains(FILE *fp, const struct nft_ruleset *rs,
888  uint32_t type, uint32_t flags)
889 {
890  int len = 0, ret = 0;
891  struct nft_chain *o;
892  struct nft_chain_list_iter *i;
893 
894  i = nft_chain_list_iter_create(rs->chain_list);
895  if (i == NULL)
896  return -1;
897 
898  o = nft_chain_list_iter_next(i);
899  while (o != NULL) {
900  ret = nft_chain_fprintf(fp, o, type, flags);
901  if (ret < 0)
902  goto err;
903 
904  len += ret;
905 
906  o = nft_chain_list_iter_next(i);
907 
908  ret = fprintf(fp, "%s", nft_ruleset_o_separator(o, type));
909  if (ret < 0)
910  goto err;
911 
912  len += ret;
913  }
914  nft_chain_list_iter_destroy(i);
915 
916  return len;
917 err:
918  nft_chain_list_iter_destroy(i);
919  return -1;
920 }
921 
922 static int nft_ruleset_fprintf_sets(FILE *fp, const struct nft_ruleset *rs,
923  uint32_t type, uint32_t flags)
924 {
925  int len = 0, ret = 0;
926  struct nft_set *o;
927  struct nft_set_list_iter *i;
928 
929  i = nft_set_list_iter_create(rs->set_list);
930  if (i == NULL)
931  return -1;
932 
933  o = nft_set_list_iter_next(i);
934  while (o != NULL) {
935  ret = nft_set_fprintf(fp, o, type, flags);
936  if (ret < 0)
937  goto err;
938 
939  len += ret;
940 
941  o = nft_set_list_iter_next(i);
942 
943  ret = fprintf(fp, "%s", nft_ruleset_o_separator(o, type));
944  if (ret < 0)
945  goto err;
946 
947  len += ret;
948  }
949  nft_set_list_iter_destroy(i);
950 
951  return len;
952 err:
953  nft_set_list_iter_destroy(i);
954  return -1;
955 }
956 
957 static int nft_ruleset_fprintf_rules(FILE *fp, const struct nft_ruleset *rs,
958  uint32_t type, uint32_t flags)
959 {
960  int len = 0, ret = 0;
961  struct nft_rule *o;
962  struct nft_rule_list_iter *i;
963 
964  i = nft_rule_list_iter_create(rs->rule_list);
965  if (i == NULL)
966  return -1;
967 
968  o = nft_rule_list_iter_next(i);
969  while (o != NULL) {
970  ret = nft_rule_fprintf(fp, o, type, flags);
971  if (ret < 0)
972  goto err;
973 
974  len += ret;
975 
976  o = nft_rule_list_iter_next(i);
977 
978  ret = fprintf(fp, "%s", nft_ruleset_o_separator(o, type));
979  if (ret < 0)
980  goto err;
981 
982  len += ret;
983  }
984  nft_rule_list_iter_destroy(i);
985 
986  return len;
987 err:
988  nft_rule_list_iter_destroy(i);
989  return -1;
990 }
991 
992 #define NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len) \
993  if (ret < 0) \
994  return -1; \
995  len += ret;
996 
997 int nft_ruleset_fprintf(FILE *fp, const struct nft_ruleset *rs, uint32_t type,
998  uint32_t flags)
999 {
1000  int len = 0, ret = 0;
1001  void *prev = NULL;
1002  uint32_t inner_flags = flags;
1003 
1004  /* dont pass events flags to child calls of _snprintf() */
1005  inner_flags &= ~NFT_OF_EVENT_ANY;
1006 
1007  ret = nft_event_header_fprintf(fp, type, flags);
1008  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1009 
1010  ret = fprintf(fp, "%s", nft_ruleset_o_opentag(type));
1011  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1012 
1013  if ((nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_TABLELIST)) &&
1014  (!nft_table_list_is_empty(rs->table_list))) {
1015  ret = nft_ruleset_fprintf_tables(fp, rs, type, inner_flags);
1016  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1017 
1018  if (ret > 0)
1019  prev = rs->table_list;
1020  }
1021 
1022  if ((nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST)) &&
1023  (!nft_chain_list_is_empty(rs->chain_list))) {
1024  ret = fprintf(fp, "%s", nft_ruleset_o_separator(prev, type));
1025  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1026 
1027  ret = nft_ruleset_fprintf_chains(fp, rs, type, inner_flags);
1028  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1029 
1030  if (ret > 0)
1031  prev = rs->chain_list;
1032  }
1033 
1034  if ((nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_SETLIST)) &&
1035  (!nft_set_list_is_empty(rs->set_list))) {
1036  ret = fprintf(fp, "%s", nft_ruleset_o_separator(prev, type));
1037  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1038 
1039  ret = nft_ruleset_fprintf_sets(fp, rs, type, inner_flags);
1040  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1041 
1042  if (ret > 0)
1043  prev = rs->set_list;
1044  }
1045 
1046  if ((nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST)) &&
1047  (!nft_rule_list_is_empty(rs->rule_list))) {
1048  ret = fprintf(fp, "%s", nft_ruleset_o_separator(prev, type));
1049  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1050 
1051  ret = nft_ruleset_fprintf_rules(fp, rs, type, inner_flags);
1052  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1053  }
1054 
1055  ret = fprintf(fp, "%s", nft_ruleset_o_closetag(type));
1056  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1057 
1058  ret = nft_event_footer_fprintf(fp, type, flags);
1059  NFT_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1060 
1061  return len;
1062 }
1063 EXPORT_SYMBOL(nft_ruleset_fprintf);
Definition: rule.c:34