libnftnl  1.0.8
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  json_t *json;
49 
50  uint32_t format;
51  uint32_t set_id;
52  struct nftnl_set_list *set_list;
53 
54  int (*cb)(const struct nftnl_parse_ctx *ctx);
55  uint16_t flags;
56 };
57 
58 struct nftnl_ruleset *nftnl_ruleset_alloc(void)
59 {
60  return calloc(1, sizeof(struct nftnl_ruleset));
61 }
62 EXPORT_SYMBOL(nftnl_ruleset_alloc);
63 
64 void nftnl_ruleset_free(const struct nftnl_ruleset *r)
65 {
66  if (r->flags & (1 << NFTNL_RULESET_TABLELIST))
67  nftnl_table_list_free(r->table_list);
68  if (r->flags & (1 << NFTNL_RULESET_CHAINLIST))
69  nftnl_chain_list_free(r->chain_list);
70  if (r->flags & (1 << NFTNL_RULESET_SETLIST))
71  nftnl_set_list_free(r->set_list);
72  if (r->flags & (1 << NFTNL_RULESET_RULELIST))
73  nftnl_rule_list_free(r->rule_list);
74  xfree(r);
75 }
76 EXPORT_SYMBOL(nftnl_ruleset_free);
77 
78 bool nftnl_ruleset_is_set(const struct nftnl_ruleset *r, uint16_t attr)
79 {
80  return r->flags & (1 << attr);
81 }
82 EXPORT_SYMBOL(nftnl_ruleset_is_set);
83 
84 void nftnl_ruleset_unset(struct nftnl_ruleset *r, uint16_t attr)
85 {
86  if (!(r->flags & (1 << attr)))
87  return;
88 
89  switch (attr) {
90  case NFTNL_RULESET_TABLELIST:
91  nftnl_table_list_free(r->table_list);
92  break;
93  case NFTNL_RULESET_CHAINLIST:
94  nftnl_chain_list_free(r->chain_list);
95  break;
96  case NFTNL_RULESET_SETLIST:
97  nftnl_set_list_free(r->set_list);
98  break;
99  case NFTNL_RULESET_RULELIST:
100  nftnl_rule_list_free(r->rule_list);
101  break;
102  }
103  r->flags &= ~(1 << attr);
104 }
105 EXPORT_SYMBOL(nftnl_ruleset_unset);
106 
107 void nftnl_ruleset_set(struct nftnl_ruleset *r, uint16_t attr, void *data)
108 {
109  switch (attr) {
110  case NFTNL_RULESET_TABLELIST:
111  nftnl_ruleset_unset(r, NFTNL_RULESET_TABLELIST);
112  r->table_list = data;
113  break;
114  case NFTNL_RULESET_CHAINLIST:
115  nftnl_ruleset_unset(r, NFTNL_RULESET_CHAINLIST);
116  r->chain_list = data;
117  break;
118  case NFTNL_RULESET_SETLIST:
119  nftnl_ruleset_unset(r, NFTNL_RULESET_SETLIST);
120  r->set_list = data;
121  break;
122  case NFTNL_RULESET_RULELIST:
123  nftnl_ruleset_unset(r, NFTNL_RULESET_RULELIST);
124  r->rule_list = data;
125  break;
126  default:
127  return;
128  }
129  r->flags |= (1 << attr);
130 }
131 EXPORT_SYMBOL(nftnl_ruleset_set);
132 
133 void *nftnl_ruleset_get(const struct nftnl_ruleset *r, uint16_t attr)
134 {
135  if (!(r->flags & (1 << attr)))
136  return NULL;
137 
138  switch (attr) {
139  case NFTNL_RULESET_TABLELIST:
140  return r->table_list;
141  case NFTNL_RULESET_CHAINLIST:
142  return r->chain_list;
143  case NFTNL_RULESET_SETLIST:
144  return r->set_list;
145  case NFTNL_RULESET_RULELIST:
146  return r->rule_list;
147  default:
148  return NULL;
149  }
150 }
151 EXPORT_SYMBOL(nftnl_ruleset_get);
152 
153 void nftnl_ruleset_ctx_free(const struct nftnl_parse_ctx *ctx)
154 {
155  switch (ctx->type) {
156  case NFTNL_RULESET_TABLE:
157  nftnl_table_free(ctx->table);
158  break;
159  case NFTNL_RULESET_CHAIN:
160  nftnl_chain_free(ctx->chain);
161  break;
162  case NFTNL_RULESET_RULE:
163  nftnl_rule_free(ctx->rule);
164  break;
165  case NFTNL_RULESET_SET:
166  case NFTNL_RULESET_SET_ELEMS:
167  nftnl_set_free(ctx->set);
168  break;
169  case NFTNL_RULESET_RULESET:
170  case NFTNL_RULESET_UNSPEC:
171  break;
172  }
173 }
174 EXPORT_SYMBOL(nftnl_ruleset_ctx_free);
175 
176 bool nftnl_ruleset_ctx_is_set(const struct nftnl_parse_ctx *ctx, uint16_t attr)
177 {
178  return ctx->flags & (1 << attr);
179 }
180 EXPORT_SYMBOL(nftnl_ruleset_ctx_is_set);
181 
182 void *nftnl_ruleset_ctx_get(const struct nftnl_parse_ctx *ctx, uint16_t attr)
183 {
184  if (!(ctx->flags & (1 << attr)))
185  return NULL;
186 
187  switch (attr) {
188  case NFTNL_RULESET_CTX_CMD:
189  return (void *)&ctx->cmd;
190  case NFTNL_RULESET_CTX_TYPE:
191  return (void *)&ctx->type;
192  case NFTNL_RULESET_CTX_TABLE:
193  return ctx->table;
194  case NFTNL_RULESET_CTX_CHAIN:
195  return ctx->chain;
196  case NFTNL_RULESET_CTX_RULE:
197  return ctx->rule;
198  case NFTNL_RULESET_CTX_SET:
199  return ctx->set;
200  case NFTNL_RULESET_CTX_DATA:
201  return ctx->data;
202  default:
203  return NULL;
204  }
205 }
206 EXPORT_SYMBOL(nftnl_ruleset_ctx_get);
207 
208 uint32_t nftnl_ruleset_ctx_get_u32(const struct nftnl_parse_ctx *ctx, uint16_t attr)
209 {
210  const void *ret = nftnl_ruleset_ctx_get(ctx, attr);
211  return ret == NULL ? 0 : *((uint32_t *)ret);
212 }
213 EXPORT_SYMBOL(nftnl_ruleset_ctx_get_u32);
214 
215 #if defined(JSON_PARSING)
216 static void nftnl_ruleset_ctx_set(struct nftnl_parse_ctx *ctx, uint16_t attr,
217  void *data)
218 {
219  switch (attr) {
220  case NFTNL_RULESET_CTX_CMD:
221  ctx->cmd = *((uint32_t *)data);
222  break;
223  case NFTNL_RULESET_CTX_TYPE:
224  ctx->type = *((uint32_t *)data);
225  break;
226  case NFTNL_RULESET_CTX_TABLE:
227  ctx->table = data;
228  break;
229  case NFTNL_RULESET_CTX_CHAIN:
230  ctx->chain = data;
231  break;
232  case NFTNL_RULESET_CTX_RULE:
233  ctx->rule = data;
234  break;
235  case NFTNL_RULESET_CTX_SET:
236  ctx->set = data;
237  break;
238  case NFTNL_RULESET_CTX_DATA:
239  ctx->data = data;
240  break;
241  }
242  ctx->flags |= (1 << attr);
243 }
244 
245 static void nftnl_ruleset_ctx_set_u32(struct nftnl_parse_ctx *ctx, uint16_t attr,
246  uint32_t val)
247 {
248  nftnl_ruleset_ctx_set(ctx, attr, &val);
249 }
250 
251 static int nftnl_ruleset_parse_tables(struct nftnl_parse_ctx *ctx,
252  struct nftnl_parse_err *err)
253 {
254  struct nftnl_table *table;
255 
256  table = nftnl_table_alloc();
257  if (table == NULL)
258  return -1;
259 
260  switch (ctx->format) {
261  case NFTNL_OUTPUT_JSON:
262 #ifdef JSON_PARSING
263  if (nftnl_jansson_parse_table(table, ctx->json, err) < 0)
264  goto err;
265 #endif
266  break;
267  case NFTNL_OUTPUT_XML:
268  default:
269  errno = EOPNOTSUPP;
270  goto err;
271  }
272 
273  nftnl_ruleset_ctx_set_u32(ctx, NFTNL_RULESET_CTX_TYPE, NFTNL_RULESET_TABLE);
274  nftnl_ruleset_ctx_set(ctx, NFTNL_RULESET_CTX_TABLE, table);
275  if (ctx->cb(ctx) < 0)
276  goto err;
277 
278  return 0;
279 err:
280  nftnl_table_free(table);
281  return -1;
282 }
283 
284 static int nftnl_ruleset_parse_chains(struct nftnl_parse_ctx *ctx,
285  struct nftnl_parse_err *err)
286 {
287  struct nftnl_chain *chain;
288 
289  chain = nftnl_chain_alloc();
290  if (chain == NULL)
291  return -1;
292 
293  switch (ctx->format) {
294  case NFTNL_OUTPUT_JSON:
295 #ifdef JSON_PARSING
296  if (nftnl_jansson_parse_chain(chain, ctx->json, err) < 0)
297  goto err;
298 #endif
299  break;
300  case NFTNL_OUTPUT_XML:
301  default:
302  errno = EOPNOTSUPP;
303  goto err;
304  }
305 
306  nftnl_ruleset_ctx_set_u32(ctx, NFTNL_RULESET_CTX_TYPE, NFTNL_RULESET_CHAIN);
307  nftnl_ruleset_ctx_set(ctx, NFTNL_RULESET_CTX_CHAIN, chain);
308  if (ctx->cb(ctx) < 0)
309  goto err;
310 
311  return 0;
312 err:
313  nftnl_chain_free(chain);
314  return -1;
315 }
316 
317 static int nftnl_ruleset_parse_set(struct nftnl_parse_ctx *ctx,
318  struct nftnl_set *set, uint32_t type,
319  struct nftnl_parse_err *err)
320 {
321  struct nftnl_set *newset;
322 
323  nftnl_set_set_u32(set, NFTNL_SET_ID, ctx->set_id++);
324 
325  newset = nftnl_set_clone(set);
326  if (newset == NULL)
327  goto err;
328 
329  nftnl_set_list_add_tail(newset, ctx->set_list);
330 
331  nftnl_ruleset_ctx_set_u32(ctx, NFTNL_RULESET_CTX_TYPE, type);
332  nftnl_ruleset_ctx_set(ctx, NFTNL_RULESET_CTX_SET, set);
333  if (ctx->cb(ctx) < 0)
334  goto err;
335 
336  return 0;
337 err:
338  return -1;
339 }
340 
341 static int nftnl_ruleset_parse_set_elems(struct nftnl_parse_ctx *ctx,
342  struct nftnl_parse_err *err)
343 {
344  struct nftnl_set *set;
345 
346  set = nftnl_set_alloc();
347  if (set == NULL)
348  return -1;
349 
350  switch (ctx->format) {
351  case NFTNL_OUTPUT_JSON:
352 #ifdef JSON_PARSING
353  if (nftnl_jansson_parse_elem(set, ctx->json, err) < 0)
354  goto err;
355 #endif
356  break;
357  case NFTNL_OUTPUT_XML:
358  default:
359  errno = EOPNOTSUPP;
360  goto err;
361  }
362 
363  if (nftnl_ruleset_parse_set(ctx, set, NFTNL_RULESET_SET_ELEMS, err) < 0)
364  goto err;
365 
366  return 0;
367 err:
368  nftnl_set_free(set);
369  return -1;
370 }
371 
372 static int nftnl_ruleset_parse_sets(struct nftnl_parse_ctx *ctx,
373  struct nftnl_parse_err *err)
374 {
375  struct nftnl_set *set;
376 
377  set = nftnl_set_alloc();
378  if (set == NULL)
379  return -1;
380 
381  switch (ctx->format) {
382  case NFTNL_OUTPUT_JSON:
383 #ifdef JSON_PARSING
384  if (nftnl_jansson_parse_set(set, ctx->json, err) < 0)
385  goto err;
386 #endif
387  break;
388  case NFTNL_OUTPUT_XML:
389  default:
390  errno = EOPNOTSUPP;
391  goto err;
392  }
393 
394  if (nftnl_ruleset_parse_set(ctx, set, NFTNL_RULESET_SET, err) < 0)
395  goto err;
396 
397  return 0;
398 err:
399  nftnl_set_free(set);
400  return -1;
401 }
402 
403 static int nftnl_ruleset_parse_rules(struct nftnl_parse_ctx *ctx,
404  struct nftnl_parse_err *err)
405 {
406  struct nftnl_rule *rule;
407 
408  rule = nftnl_rule_alloc();
409  if (rule == NULL)
410  return -1;
411 
412  switch (ctx->format) {
413  case NFTNL_OUTPUT_JSON:
414 #ifdef JSON_PARSING
415  if (nftnl_jansson_parse_rule(rule, ctx->json, err,
416  ctx->set_list) < 0)
417  goto err;
418 #endif
419  break;
420  case NFTNL_OUTPUT_XML:
421  default:
422  errno = EOPNOTSUPP;
423  goto err;
424  }
425 
426  nftnl_ruleset_ctx_set_u32(ctx, NFTNL_RULESET_CTX_TYPE, NFTNL_RULESET_RULE);
427  nftnl_ruleset_ctx_set(ctx, NFTNL_RULESET_CTX_RULE, rule);
428  if (ctx->cb(ctx) < 0)
429  goto err;
430 
431  return 0;
432 err:
433  nftnl_rule_free(rule);
434  return -1;
435 }
436 #endif
437 
438 #ifdef JSON_PARSING
439 static int nftnl_ruleset_json_parse_ruleset(struct nftnl_parse_ctx *ctx,
440  struct nftnl_parse_err *err)
441 {
442  json_t *node, *array = ctx->json;
443  int len, i, ret;
444 
445  len = json_array_size(array);
446  for (i = 0; i < len; i++) {
447  node = json_array_get(array, i);
448  if (node == NULL) {
449  errno = EINVAL;
450  return -1;
451  }
452 
453  ctx->json = node;
454  if (nftnl_jansson_node_exist(node, "table"))
455  ret = nftnl_ruleset_parse_tables(ctx, err);
456  else if (nftnl_jansson_node_exist(node, "chain"))
457  ret = nftnl_ruleset_parse_chains(ctx, err);
458  else if (nftnl_jansson_node_exist(node, "set"))
459  ret = nftnl_ruleset_parse_sets(ctx, err);
460  else if (nftnl_jansson_node_exist(node, "rule"))
461  ret = nftnl_ruleset_parse_rules(ctx, err);
462  else if (nftnl_jansson_node_exist(node, "element"))
463  ret = nftnl_ruleset_parse_set_elems(ctx, err);
464  else
465  return -1;
466 
467  if (ret < 0)
468  return ret;
469  }
470 
471  if (len == 0 && ctx->cmd == NFTNL_CMD_FLUSH) {
472  nftnl_ruleset_ctx_set_u32(ctx, NFTNL_RULESET_CTX_TYPE,
473  NFTNL_RULESET_RULESET);
474  if (ctx->cb(ctx) < 0)
475  return -1;
476  }
477 
478  return 0;
479 }
480 
481 static int nftnl_ruleset_json_parse_cmd(const char *cmd,
482  struct nftnl_parse_err *err,
483  struct nftnl_parse_ctx *ctx)
484 {
485  uint32_t cmdnum;
486  json_t *nodecmd;
487 
488  cmdnum = nftnl_str2cmd(cmd);
489  if (cmdnum == NFTNL_CMD_UNSPEC) {
490  err->error = NFTNL_PARSE_EMISSINGNODE;
491  err->node_name = strdup(cmd);
492  return -1;
493  }
494 
495  nftnl_ruleset_ctx_set_u32(ctx, NFTNL_RULESET_CTX_CMD, cmdnum);
496 
497  nodecmd = json_object_get(ctx->json, cmd);
498  if (nodecmd == NULL)
499  return 0;
500 
501  ctx->json = nodecmd;
502  if (nftnl_ruleset_json_parse_ruleset(ctx, err) != 0)
503  goto err;
504 
505  return 0;
506 err:
507  return -1;
508 }
509 #endif
510 
511 static int nftnl_ruleset_json_parse(const void *json,
512  struct nftnl_parse_err *err,
513  enum nftnl_parse_input input,
514  enum nftnl_parse_type type, void *arg,
515  int (*cb)(const struct nftnl_parse_ctx *ctx))
516 {
517 #ifdef JSON_PARSING
518  json_t *root, *array, *node;
519  json_error_t error;
520  int i, len;
521  const char *key;
522  struct nftnl_parse_ctx ctx;
523 
524  ctx.cb = cb;
525  ctx.format = type;
526  ctx.flags = 0;
527 
528  ctx.set_list = nftnl_set_list_alloc();
529  if (ctx.set_list == NULL)
530  return -1;
531 
532  if (arg != NULL)
533  nftnl_ruleset_ctx_set(&ctx, NFTNL_RULESET_CTX_DATA, arg);
534 
535  root = nftnl_jansson_create_root(json, &error, err, input);
536  if (root == NULL)
537  goto err1;
538 
539  array = json_object_get(root, "nftables");
540  if (array == NULL) {
541  errno = EINVAL;
542  goto err2;
543  }
544 
545  len = json_array_size(array);
546  for (i = 0; i < len; i++) {
547  node = json_array_get(array, i);
548  if (node == NULL) {
549  errno = EINVAL;
550  goto err2;
551  }
552  ctx.json = node;
553  key = json_object_iter_key(json_object_iter(node));
554  if (key == NULL)
555  goto err2;
556 
557  if (nftnl_ruleset_json_parse_cmd(key, err, &ctx) < 0)
558  goto err2;
559  }
560 
561  nftnl_set_list_free(ctx.set_list);
562  nftnl_jansson_free_root(root);
563  return 0;
564 err2:
565  nftnl_jansson_free_root(root);
566 err1:
567  nftnl_set_list_free(ctx.set_list);
568  return -1;
569 #else
570  errno = EOPNOTSUPP;
571  return -1;
572 #endif
573 }
574 
575 static int
576 nftnl_ruleset_do_parse(enum nftnl_parse_type type, const void *data,
577  struct nftnl_parse_err *err, enum nftnl_parse_input input,
578  void *arg, int (*cb)(const struct nftnl_parse_ctx *ctx))
579 {
580  int ret;
581 
582  switch (type) {
583  case NFTNL_PARSE_JSON:
584  ret = nftnl_ruleset_json_parse(data, err, input, type, arg, cb);
585  break;
586  case NFTNL_PARSE_XML:
587  default:
588  ret = -1;
589  errno = EOPNOTSUPP;
590  break;
591  }
592 
593  return ret;
594 }
595 
596 int nftnl_ruleset_parse_file_cb(enum nftnl_parse_type type, FILE *fp,
597  struct nftnl_parse_err *err, void *data,
598  int (*cb)(const struct nftnl_parse_ctx *ctx))
599 {
600  return nftnl_ruleset_do_parse(type, fp, err, NFTNL_PARSE_FILE, data, cb);
601 }
602 EXPORT_SYMBOL(nftnl_ruleset_parse_file_cb);
603 
604 int nftnl_ruleset_parse_buffer_cb(enum nftnl_parse_type type, const char *buffer,
605  struct nftnl_parse_err *err, void *data,
606  int (*cb)(const struct nftnl_parse_ctx *ctx))
607 {
608  return nftnl_ruleset_do_parse(type, buffer, err, NFTNL_PARSE_BUFFER, data,
609  cb);
610 }
611 EXPORT_SYMBOL(nftnl_ruleset_parse_buffer_cb);
612 
613 static int nftnl_ruleset_cb(const struct nftnl_parse_ctx *ctx)
614 {
615  struct nftnl_ruleset *r = ctx->data;
616 
617  if (ctx->cmd != NFTNL_CMD_ADD)
618  return -1;
619 
620  switch (ctx->type) {
621  case NFTNL_RULESET_TABLE:
622  if (r->table_list == NULL) {
623  r->table_list = nftnl_table_list_alloc();
624  if (r->table_list == NULL)
625  return -1;
626 
627  nftnl_ruleset_set(r, NFTNL_RULESET_TABLELIST,
628  r->table_list);
629  }
630  nftnl_table_list_add_tail(ctx->table, r->table_list);
631  break;
632  case NFTNL_RULESET_CHAIN:
633  if (r->chain_list == NULL) {
634  r->chain_list = nftnl_chain_list_alloc();
635  if (r->chain_list == NULL)
636  return -1;
637 
638  nftnl_ruleset_set(r, NFTNL_RULESET_CHAINLIST,
639  r->chain_list);
640  }
641  nftnl_chain_list_add_tail(ctx->chain, r->chain_list);
642  break;
643  case NFTNL_RULESET_SET:
644  if (r->set_list == NULL) {
645  r->set_list = nftnl_set_list_alloc();
646  if (r->set_list == NULL)
647  return -1;
648 
649  nftnl_ruleset_set(r, NFTNL_RULESET_SETLIST,
650  r->set_list);
651  }
652  nftnl_set_list_add_tail(ctx->set, r->set_list);
653  break;
654  case NFTNL_RULESET_RULE:
655  if (r->rule_list == NULL) {
656  r->rule_list = nftnl_rule_list_alloc();
657  if (r->rule_list == NULL)
658  return -1;
659 
660  nftnl_ruleset_set(r, NFTNL_RULESET_RULELIST,
661  r->rule_list);
662  }
663  nftnl_rule_list_add_tail(ctx->rule, r->rule_list);
664  break;
665  case NFTNL_RULESET_RULESET:
666  break;
667  default:
668  return -1;
669  }
670 
671  return 0;
672 }
673 
674 int nftnl_ruleset_parse(struct nftnl_ruleset *r, enum nftnl_parse_type type,
675  const char *data, struct nftnl_parse_err *err)
676 {
677  return nftnl_ruleset_parse_buffer_cb(type, data, err, r, nftnl_ruleset_cb);
678 }
679 EXPORT_SYMBOL(nftnl_ruleset_parse);
680 
681 int nftnl_ruleset_parse_file(struct nftnl_ruleset *rs, enum nftnl_parse_type type,
682  FILE *fp, struct nftnl_parse_err *err)
683 {
684  return nftnl_ruleset_parse_file_cb(type, fp, err, rs, nftnl_ruleset_cb);
685 }
686 EXPORT_SYMBOL(nftnl_ruleset_parse_file);
687 
688 static const char *nftnl_ruleset_o_opentag(uint32_t type)
689 {
690  switch (type) {
691  case NFTNL_OUTPUT_JSON:
692  return "{\"nftables\":[";
693  case NFTNL_OUTPUT_XML:
694  default:
695  return "";
696  }
697 }
698 
699 static const char *nftnl_ruleset_o_separator(void *obj, uint32_t type)
700 {
701  if (obj == NULL)
702  return "";
703 
704  switch (type) {
705  case NFTNL_OUTPUT_JSON:
706  return ",";
707  case NFTNL_OUTPUT_DEFAULT:
708  return "\n";
709  default:
710  return "";
711  }
712 }
713 
714 static const char *nftnl_ruleset_o_closetag(uint32_t type)
715 {
716  switch (type) {
717  case NFTNL_OUTPUT_JSON:
718  return "]}";
719  case NFTNL_OUTPUT_XML:
720  default:
721  return "";
722  }
723 }
724 
725 static int
726 nftnl_ruleset_snprintf_table(char *buf, size_t size,
727  const struct nftnl_ruleset *rs, uint32_t type,
728  uint32_t flags)
729 {
730  struct nftnl_table *t;
731  struct nftnl_table_list_iter *ti;
732  int ret, remain = size, offset = 0;
733 
734  ti = nftnl_table_list_iter_create(rs->table_list);
735  if (ti == NULL)
736  return 0;
737 
738  t = nftnl_table_list_iter_next(ti);
739  while (t != NULL) {
740  ret = nftnl_table_snprintf(buf + offset, remain, t, type, flags);
741  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
742 
743  t = nftnl_table_list_iter_next(ti);
744 
745  ret = snprintf(buf + offset, remain, "%s",
746  nftnl_ruleset_o_separator(t, type));
747  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
748  }
749  nftnl_table_list_iter_destroy(ti);
750 
751  return offset;
752 }
753 
754 static int
755 nftnl_ruleset_snprintf_chain(char *buf, size_t size,
756  const struct nftnl_ruleset *rs, uint32_t type,
757  uint32_t flags)
758 {
759  struct nftnl_chain *c;
760  struct nftnl_chain_list_iter *ci;
761  int ret, remain = size, offset = 0;
762 
763  ci = nftnl_chain_list_iter_create(rs->chain_list);
764  if (ci == NULL)
765  return 0;
766 
767  c = nftnl_chain_list_iter_next(ci);
768  while (c != NULL) {
769  ret = nftnl_chain_snprintf(buf + offset, remain, c, type, flags);
770  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
771 
772  c = nftnl_chain_list_iter_next(ci);
773 
774  ret = snprintf(buf + offset, remain, "%s",
775  nftnl_ruleset_o_separator(c, type));
776  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
777  }
778  nftnl_chain_list_iter_destroy(ci);
779 
780  return offset;
781 }
782 
783 static int
784 nftnl_ruleset_snprintf_set(char *buf, size_t size,
785  const struct nftnl_ruleset *rs, uint32_t type,
786  uint32_t flags)
787 {
788  struct nftnl_set *s;
789  struct nftnl_set_list_iter *si;
790  int ret, remain = size, offset = 0;
791 
792  si = nftnl_set_list_iter_create(rs->set_list);
793  if (si == NULL)
794  return 0;
795 
796  s = nftnl_set_list_iter_next(si);
797  while (s != NULL) {
798  ret = nftnl_set_snprintf(buf + offset, remain, s, type, flags);
799  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
800 
801  s = nftnl_set_list_iter_next(si);
802 
803  ret = snprintf(buf + offset, remain, "%s",
804  nftnl_ruleset_o_separator(s, type));
805  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
806  }
807  nftnl_set_list_iter_destroy(si);
808 
809  return offset;
810 }
811 
812 static int
813 nftnl_ruleset_snprintf_rule(char *buf, size_t size,
814  const struct nftnl_ruleset *rs, uint32_t type,
815  uint32_t flags)
816 {
817  struct nftnl_rule *r;
818  struct nftnl_rule_list_iter *ri;
819  int ret, remain = size, offset = 0;
820 
821  ri = nftnl_rule_list_iter_create(rs->rule_list);
822  if (ri == NULL)
823  return 0;
824 
825  r = nftnl_rule_list_iter_next(ri);
826  while (r != NULL) {
827  ret = nftnl_rule_snprintf(buf + offset, remain, r, type, flags);
828  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
829 
830  r = nftnl_rule_list_iter_next(ri);
831 
832  ret = snprintf(buf + offset, remain, "%s",
833  nftnl_ruleset_o_separator(r, type));
834  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
835  }
836  nftnl_rule_list_iter_destroy(ri);
837 
838  return offset;
839 }
840 
841 static int
842 nftnl_ruleset_do_snprintf(char *buf, size_t size, const struct nftnl_ruleset *rs,
843  uint32_t cmd, uint32_t type, uint32_t flags)
844 {
845  int ret, remain = size, offset = 0;
846  void *prev = NULL;
847  uint32_t inner_flags = flags;
848 
849  /* dont pass events flags to child calls of _snprintf() */
850  inner_flags &= ~NFTNL_OF_EVENT_ANY;
851 
852  ret = snprintf(buf + offset, remain, "%s",
853  nftnl_ruleset_o_opentag(type));
854  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
855 
856  ret = nftnl_cmd_header_snprintf(buf + offset, remain, cmd, type, flags);
857  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
858 
859  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_TABLELIST) &&
860  (!nftnl_table_list_is_empty(rs->table_list))) {
861  ret = nftnl_ruleset_snprintf_table(buf + offset, remain, rs,
862  type, inner_flags);
863  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
864 
865  if (ret > 0)
866  prev = rs->table_list;
867  }
868 
869  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_CHAINLIST) &&
870  (!nftnl_chain_list_is_empty(rs->chain_list))) {
871  ret = snprintf(buf + offset, remain, "%s",
872  nftnl_ruleset_o_separator(prev, type));
873  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
874 
875  ret = nftnl_ruleset_snprintf_chain(buf + offset, remain, rs,
876  type, inner_flags);
877  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
878 
879  if (ret > 0)
880  prev = rs->chain_list;
881  }
882 
883  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_SETLIST) &&
884  (!nftnl_set_list_is_empty(rs->set_list))) {
885  ret = snprintf(buf + offset, remain, "%s",
886  nftnl_ruleset_o_separator(prev, type));
887  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
888 
889  ret = nftnl_ruleset_snprintf_set(buf + offset, remain, rs,
890  type, inner_flags);
891  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
892 
893  if (ret > 0)
894  prev = rs->set_list;
895  }
896 
897  if (nftnl_ruleset_is_set(rs, NFTNL_RULESET_RULELIST) &&
898  (!nftnl_rule_list_is_empty(rs->rule_list))) {
899  ret = snprintf(buf + offset, remain, "%s",
900  nftnl_ruleset_o_separator(prev, type));
901  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
902 
903  ret = nftnl_ruleset_snprintf_rule(buf + offset, remain, rs,
904  type, inner_flags);
905  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
906  }
907 
908  ret = nftnl_cmd_footer_snprintf(buf + offset, remain, cmd, type, flags);
909  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
910 
911  ret = snprintf(buf + offset, remain, "%s",
912  nftnl_ruleset_o_closetag(type));
913  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
914 
915  return offset;
916 }
917 
918 static int nftnl_ruleset_cmd_snprintf(char *buf, size_t size,
919  const struct nftnl_ruleset *r, uint32_t cmd,
920  uint32_t type, uint32_t flags)
921 {
922  switch (type) {
923  case NFTNL_OUTPUT_DEFAULT:
924  case NFTNL_OUTPUT_JSON:
925  return nftnl_ruleset_do_snprintf(buf, size, r, cmd, type, flags);
926  case NFTNL_OUTPUT_XML:
927  default:
928  errno = EOPNOTSUPP;
929  return -1;
930  }
931 }
932 
933 int nftnl_ruleset_snprintf(char *buf, size_t size, const struct nftnl_ruleset *r,
934  uint32_t type, uint32_t flags)
935 {
936  if (size)
937  buf[0] = '\0';
938 
939  switch (type) {
940  case NFTNL_OUTPUT_DEFAULT:
941  case NFTNL_OUTPUT_JSON:
942  return nftnl_ruleset_cmd_snprintf(buf, size, r,
943  nftnl_flag2cmd(flags), type,
944  flags);
945  case NFTNL_OUTPUT_XML:
946  default:
947  errno = EOPNOTSUPP;
948  return -1;
949  }
950 }
951 EXPORT_SYMBOL(nftnl_ruleset_snprintf);
952 
953 static int nftnl_ruleset_fprintf_tables(FILE *fp, const struct nftnl_ruleset *rs,
954  uint32_t type, uint32_t flags)
955 {
956  int len = 0, ret = 0;
957  struct nftnl_table *t;
958  struct nftnl_table_list_iter *ti;
959 
960  ti = nftnl_table_list_iter_create(rs->table_list);
961  if (ti == NULL)
962  return -1;
963 
964  t = nftnl_table_list_iter_next(ti);
965  while (t != NULL) {
966  ret = nftnl_table_fprintf(fp, t, type, flags);
967  if (ret < 0)
968  goto err;
969 
970  len += ret;
971 
972  t = nftnl_table_list_iter_next(ti);
973 
974  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(t, type));
975  if (ret < 0)
976  goto err;
977 
978  len += ret;
979  }
980  nftnl_table_list_iter_destroy(ti);
981 
982  return len;
983 err:
984  nftnl_table_list_iter_destroy(ti);
985  return -1;
986 }
987 
988 static int nftnl_ruleset_fprintf_chains(FILE *fp, const struct nftnl_ruleset *rs,
989  uint32_t type, uint32_t flags)
990 {
991  int len = 0, ret = 0;
992  struct nftnl_chain *o;
993  struct nftnl_chain_list_iter *i;
994 
995  i = nftnl_chain_list_iter_create(rs->chain_list);
996  if (i == NULL)
997  return -1;
998 
999  o = nftnl_chain_list_iter_next(i);
1000  while (o != NULL) {
1001  ret = nftnl_chain_fprintf(fp, o, type, flags);
1002  if (ret < 0)
1003  goto err;
1004 
1005  len += ret;
1006 
1007  o = nftnl_chain_list_iter_next(i);
1008 
1009  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(o, type));
1010  if (ret < 0)
1011  goto err;
1012 
1013  len += ret;
1014  }
1015  nftnl_chain_list_iter_destroy(i);
1016 
1017  return len;
1018 err:
1019  nftnl_chain_list_iter_destroy(i);
1020  return -1;
1021 }
1022 
1023 static int nftnl_ruleset_fprintf_sets(FILE *fp, const struct nftnl_ruleset *rs,
1024  uint32_t type, uint32_t flags)
1025 {
1026  int len = 0, ret = 0;
1027  struct nftnl_set *o;
1028  struct nftnl_set_list_iter *i;
1029 
1030  i = nftnl_set_list_iter_create(rs->set_list);
1031  if (i == NULL)
1032  return -1;
1033 
1034  o = nftnl_set_list_iter_next(i);
1035  while (o != NULL) {
1036  ret = nftnl_set_fprintf(fp, o, type, flags);
1037  if (ret < 0)
1038  goto err;
1039 
1040  len += ret;
1041 
1042  o = nftnl_set_list_iter_next(i);
1043 
1044  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(o, type));
1045  if (ret < 0)
1046  goto err;
1047 
1048  len += ret;
1049  }
1050  nftnl_set_list_iter_destroy(i);
1051 
1052  return len;
1053 err:
1054  nftnl_set_list_iter_destroy(i);
1055  return -1;
1056 }
1057 
1058 static int nftnl_ruleset_fprintf_rules(FILE *fp, const struct nftnl_ruleset *rs,
1059  uint32_t type, uint32_t flags)
1060 {
1061  int len = 0, ret = 0;
1062  struct nftnl_rule *o;
1063  struct nftnl_rule_list_iter *i;
1064 
1065  i = nftnl_rule_list_iter_create(rs->rule_list);
1066  if (i == NULL)
1067  return -1;
1068 
1069  o = nftnl_rule_list_iter_next(i);
1070  while (o != NULL) {
1071  ret = nftnl_rule_fprintf(fp, o, type, flags);
1072  if (ret < 0)
1073  goto err;
1074 
1075  len += ret;
1076 
1077  o = nftnl_rule_list_iter_next(i);
1078 
1079  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(o, type));
1080  if (ret < 0)
1081  goto err;
1082 
1083  len += ret;
1084  }
1085  nftnl_rule_list_iter_destroy(i);
1086 
1087  return len;
1088 err:
1089  nftnl_rule_list_iter_destroy(i);
1090  return -1;
1091 }
1092 
1093 #define NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len) \
1094  if (ret < 0) \
1095  return -1; \
1096  len += ret;
1097 
1098 static int nftnl_ruleset_cmd_fprintf(FILE *fp, const struct nftnl_ruleset *rs,
1099  uint32_t cmd, uint32_t type, uint32_t flags)
1100 {
1101  int len = 0, ret = 0;
1102  void *prev = NULL;
1103  uint32_t inner_flags = flags;
1104 
1105  /* dont pass events flags to child calls of _snprintf() */
1106  inner_flags &= ~NFTNL_OF_EVENT_ANY;
1107 
1108  ret = fprintf(fp, "%s", nftnl_ruleset_o_opentag(type));
1109  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1110 
1111  ret = nftnl_cmd_header_fprintf(fp, cmd, type, flags);
1112  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1113 
1114  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_TABLELIST)) &&
1115  (!nftnl_table_list_is_empty(rs->table_list))) {
1116  ret = nftnl_ruleset_fprintf_tables(fp, rs, type, inner_flags);
1117  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1118 
1119  if (ret > 0)
1120  prev = rs->table_list;
1121  }
1122 
1123  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_CHAINLIST)) &&
1124  (!nftnl_chain_list_is_empty(rs->chain_list))) {
1125  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(prev, type));
1126  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1127 
1128  ret = nftnl_ruleset_fprintf_chains(fp, rs, type, inner_flags);
1129  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1130 
1131  if (ret > 0)
1132  prev = rs->chain_list;
1133  }
1134 
1135  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_SETLIST)) &&
1136  (!nftnl_set_list_is_empty(rs->set_list))) {
1137  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(prev, type));
1138  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1139 
1140  ret = nftnl_ruleset_fprintf_sets(fp, rs, type, inner_flags);
1141  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1142 
1143  if (ret > 0)
1144  prev = rs->set_list;
1145  }
1146 
1147  if ((nftnl_ruleset_is_set(rs, NFTNL_RULESET_RULELIST)) &&
1148  (!nftnl_rule_list_is_empty(rs->rule_list))) {
1149  ret = fprintf(fp, "%s", nftnl_ruleset_o_separator(prev, type));
1150  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1151 
1152  ret = nftnl_ruleset_fprintf_rules(fp, rs, type, inner_flags);
1153  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1154  }
1155 
1156  ret = nftnl_cmd_footer_fprintf(fp, cmd, type, flags);
1157  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1158 
1159  ret = fprintf(fp, "%s", nftnl_ruleset_o_closetag(type));
1160  NFTNL_FPRINTF_RETURN_OR_FIXLEN(ret, len);
1161 
1162  return len;
1163 }
1164 
1165 int nftnl_ruleset_fprintf(FILE *fp, const struct nftnl_ruleset *rs, uint32_t type,
1166  uint32_t flags)
1167 {
1168  return nftnl_ruleset_cmd_fprintf(fp, rs, nftnl_flag2cmd(flags), type,
1169  flags);
1170 }
1171 EXPORT_SYMBOL(nftnl_ruleset_fprintf);