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