]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
src: add low-level ruleset API
authorArturo Borrero <arturo.borrero.glez@gmail.com>
Mon, 30 Sep 2013 22:33:18 +0000 (00:33 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 1 Oct 2013 09:22:06 +0000 (11:22 +0200)
This patch adds a low level ruleset API for libnftables.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
13 files changed:
include/libnftables/Makefile.am
include/libnftables/ruleset.h [new file with mode: 0644]
src/Makefile.am
src/chain.c
src/internal.h
src/libnftables.map
src/rule.c
src/ruleset.c [new file with mode: 0644]
src/set.c
src/table.c
tests/jsonfiles/64-ruleset.json [new file with mode: 0644]
tests/nft-parsing-test.c
tests/xmlfiles/75-ruleset.xml [new file with mode: 0644]

index b05299270f1a8f19ec658208976e514f19d951c4..e243f3210aacda2287a153d6ead271522cd32a7c 100644 (file)
@@ -2,4 +2,5 @@ pkginclude_HEADERS = table.h            \
                     chain.h            \
                     rule.h             \
                     expr.h             \
-                    set.h
+                    set.h              \
+                    ruleset.h
diff --git a/include/libnftables/ruleset.h b/include/libnftables/ruleset.h
new file mode 100644 (file)
index 0000000..a4a1279
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _RULESET_H_
+#define _RULESET_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nft_ruleset;
+
+struct nft_ruleset *nft_ruleset_alloc(void);
+void nft_ruleset_free(struct nft_ruleset *r);
+
+enum {
+       NFT_RULESET_ATTR_TABLELIST = 0,
+       NFT_RULESET_ATTR_CHAINLIST,
+       NFT_RULESET_ATTR_SETLIST,
+       NFT_RULESET_ATTR_RULELIST,
+};
+
+bool nft_ruleset_attr_is_set(const struct nft_ruleset *r, uint16_t attr);
+void nft_ruleset_attr_unset(struct nft_ruleset *r, uint16_t attr);
+void nft_ruleset_attr_set(struct nft_ruleset *r, uint16_t attr, void *data);
+const void *nft_ruleset_attr_get(const struct nft_ruleset *r, uint16_t attr);
+
+enum {
+       NFT_RULESET_O_DEFAULT   = 0,
+       NFT_RULESET_O_XML,
+       NFT_RULESET_O_JSON,
+};
+
+enum nft_ruleset_parse_type {
+       NFT_RULESET_PARSE_NONE  = 0,
+       NFT_RULESET_PARSE_XML,
+       NFT_RULESET_PARSE_JSON,
+       NFT_RULESET_PARSE_MAX,
+};
+
+int nft_ruleset_parse(struct nft_ruleset *rs, enum nft_ruleset_parse_type type, const char *data);
+int nft_ruleset_snprintf(char *buf, size_t size, const struct nft_ruleset *rs, uint32_t type, uint32_t flags);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _RULESET_H_ */
index 51b40a2025e5a1a8d4a9833523d39a9f49e592c8..474dbf002df2e13afd83b0b13244f1bb248c72e3 100644 (file)
@@ -10,6 +10,7 @@ libnftables_la_SOURCES = utils.c              \
                         rule.c                 \
                         set.c                  \
                         set_elem.c             \
+                        ruleset.c              \
                         mxml.c                 \
                         jansson.c              \
                         expr.c                 \
index 874116aadfc890205d35f2cf0c18a83070407241..f83147924beb0de13869421d447a84e0e8902370 100644 (file)
@@ -506,7 +506,7 @@ static inline int nft_str2hooknum(int family, const char *hook)
 }
 
 #ifdef JSON_PARSING
-static int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
+int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree)
 {
        json_t *root;
        uint64_t uval64;
index df64dd8cc4d1fc59b139be3a090bcc4e31d430ab..b29288acc59b852f64b7e8635b39e9ac934cb104 100644 (file)
@@ -71,6 +71,14 @@ int nft_jansson_data_reg_parse(json_t *root, const char *tag,
                               union nft_data_reg *data_reg);
 struct nft_set_elem;
 int nft_set_elem_json_parse(struct nft_set_elem *e, json_t *root);
+struct nft_table;
+int nft_jansson_parse_table(struct nft_table *t, json_t *tree);
+struct nft_chain;
+int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree);
+struct nft_rule;
+int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree);
+struct nft_set;
+int nft_jansson_parse_set(struct nft_set *s, json_t *tree);
 #endif
 
 const char *nft_family2str(uint32_t family);
index 963c03e277721ba3783d79a4877ac3ad8f83640c..12234031efe92ffa6891ca43211d22ee5e342481 100644 (file)
@@ -168,5 +168,14 @@ global:
   nft_set_elems_iter_next;
   nft_set_elems_iter_destroy;
 
+  nft_ruleset_alloc;
+  nft_ruleset_free;
+  nft_ruleset_attr_is_set;
+  nft_ruleset_attr_unset;
+  nft_ruleset_attr_set;
+  nft_ruleset_attr_get;
+  nft_ruleset_parse;
+  nft_ruleset_snprintf;
+
 local: *;
 };
index 550b325af6135636521e523f3f00a084123d95c9..7f2bce630a0f272e108a5b88c15b4114057e8f7d 100644 (file)
@@ -470,7 +470,7 @@ int nft_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_rule *r)
 EXPORT_SYMBOL(nft_rule_nlmsg_parse);
 
 #ifdef JSON_PARSING
-static int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree)
+int nft_jansson_parse_rule(struct nft_rule *r, json_t *tree)
 {
        json_t *root, *array;
        struct nft_rule_expr *e;
diff --git a/src/ruleset.c b/src/ruleset.c
new file mode 100644 (file)
index 0000000..a7fbc33
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2013 by Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
+ * (C) 2013 by Alvaro Neira Ayuso <alvaroneay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <errno.h>
+
+#include "internal.h"
+
+#include <libmnl/libmnl.h>
+#include <libnftables/ruleset.h>
+#include <libnftables/table.h>
+#include <libnftables/chain.h>
+#include <libnftables/set.h>
+#include <libnftables/rule.h>
+
+struct nft_ruleset {
+       struct nft_table_list   *table_list;
+       struct nft_chain_list   *chain_list;
+       struct nft_set_list     *set_list;
+       struct nft_rule_list    *rule_list;
+
+       uint16_t                flags;
+};
+
+struct nft_ruleset *nft_ruleset_alloc(void)
+{
+       return calloc(1, sizeof(struct nft_ruleset));
+}
+EXPORT_SYMBOL(nft_ruleset_alloc);
+
+void nft_ruleset_free(struct nft_ruleset *r)
+{
+       if (r->flags & (1 << NFT_RULESET_ATTR_TABLELIST))
+               nft_table_list_free(r->table_list);
+       if (r->flags & (1 << NFT_RULESET_ATTR_CHAINLIST))
+               nft_chain_list_free(r->chain_list);
+       if (r->flags & (1 << NFT_RULESET_ATTR_SETLIST))
+               nft_set_list_free(r->set_list);
+       if (r->flags & (1 << NFT_RULESET_ATTR_RULELIST))
+               nft_rule_list_free(r->rule_list);
+       xfree(r);
+}
+EXPORT_SYMBOL(nft_ruleset_free);
+
+bool nft_ruleset_attr_is_set(const struct nft_ruleset *r, uint16_t attr)
+{
+       return r->flags & (1 << attr);
+}
+EXPORT_SYMBOL(nft_ruleset_attr_is_set);
+
+void nft_ruleset_attr_unset(struct nft_ruleset *r, uint16_t attr)
+{
+       if (!(r->flags & (1 << attr)))
+               return;
+
+       switch (attr) {
+       case NFT_RULESET_ATTR_TABLELIST:
+               nft_table_list_free(r->table_list);
+               r->table_list = NULL;
+               break;
+       case NFT_RULESET_ATTR_CHAINLIST:
+               nft_chain_list_free(r->chain_list);
+               r->chain_list = NULL;
+               break;
+       case NFT_RULESET_ATTR_SETLIST:
+               nft_set_list_free(r->set_list);
+               r->set_list = NULL;
+               break;
+       case NFT_RULESET_ATTR_RULELIST:
+               nft_rule_list_free(r->rule_list);
+               r->rule_list = NULL;
+               break;
+       }
+       r->flags &= ~(1 << attr);
+}
+EXPORT_SYMBOL(nft_ruleset_attr_unset);
+
+void nft_ruleset_attr_set(struct nft_ruleset *r, uint16_t attr, void *data)
+{
+       switch (attr) {
+       case NFT_RULESET_ATTR_TABLELIST:
+               nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_TABLELIST);
+               r->table_list = data;
+               break;
+       case NFT_RULESET_ATTR_CHAINLIST:
+               nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_CHAINLIST);
+               r->chain_list = data;
+               break;
+       case NFT_RULESET_ATTR_SETLIST:
+               nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_SETLIST);
+               r->set_list = data;
+               break;
+       case NFT_RULESET_ATTR_RULELIST:
+               nft_ruleset_attr_unset(r, NFT_RULESET_ATTR_RULELIST);
+               r->rule_list = data;
+               break;
+       default:
+               return;
+       }
+       r->flags |= (1 << attr);
+}
+EXPORT_SYMBOL(nft_ruleset_attr_set);
+
+const void *nft_ruleset_attr_get(const struct nft_ruleset *r, uint16_t attr)
+{
+       if (!(r->flags & (1 << attr)))
+               return NULL;
+
+       switch (attr) {
+       case NFT_RULESET_ATTR_TABLELIST:
+               return r->table_list;
+       case NFT_RULESET_ATTR_CHAINLIST:
+               return r->chain_list;
+       case NFT_RULESET_ATTR_SETLIST:
+               return r->set_list;
+       case NFT_RULESET_ATTR_RULELIST:
+               return r->rule_list;
+       default:
+               return NULL;
+       }
+}
+EXPORT_SYMBOL(nft_ruleset_attr_get);
+
+#ifdef JSON_PARSING
+static int nft_ruleset_json_parse_tables(struct nft_ruleset *rs, json_t *array)
+{
+       int i, len;
+       json_t *node;
+       struct nft_table *o;
+       struct nft_table_list *list = nft_table_list_alloc();
+
+       if (list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       len = json_array_size(array);
+       for (i = 0; i < len; i++) {
+               node = json_array_get(array, i);
+               if (node == NULL) {
+                       errno = EINVAL;
+                       goto err;
+               }
+
+               if (!(nft_jansson_node_exist(node, "table")))
+                       continue;
+
+               o = nft_table_alloc();
+               if (o == NULL) {
+                       errno = ENOMEM;
+                       goto err;
+               }
+
+               if (nft_jansson_parse_table(o, node) < 0) {
+                       nft_table_free(o);
+                       goto err;
+               }
+
+               nft_table_list_add_tail(o, list);
+       }
+
+       if (!nft_table_list_is_empty(list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST, list);
+       else
+               nft_table_list_free(list);
+
+       return 0;
+err:
+       nft_table_list_free(list);
+       return -1;
+}
+
+static int nft_ruleset_json_parse_chains(struct nft_ruleset *rs, json_t *array)
+{
+       int i, len;
+       json_t *node;
+       struct nft_chain *o;
+       struct nft_chain_list *list = nft_chain_list_alloc();
+
+       if (list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       len = json_array_size(array);
+       for (i = 0; i < len; i++) {
+               node = json_array_get(array, i);
+               if (node == NULL) {
+                       errno = EINVAL;
+                       goto err;
+               }
+
+               if (!(nft_jansson_node_exist(node, "chain")))
+                       continue;
+
+               o = nft_chain_alloc();
+               if (o == NULL) {
+                       errno = ENOMEM;
+                       goto err;
+               }
+
+               if (nft_jansson_parse_chain(o, node) < 0) {
+                       nft_chain_free(o);
+                       goto err;
+               }
+
+               nft_chain_list_add_tail(o, list);
+       }
+
+       if (!nft_chain_list_is_empty(list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, list);
+       else
+               nft_chain_list_free(list);
+
+       return 0;
+err:
+       nft_chain_list_free(list);
+       return -1;
+}
+
+static int nft_ruleset_json_parse_sets(struct nft_ruleset *rs, json_t *array)
+{
+       int i, len;
+       json_t *node;
+       struct nft_set *s = NULL;
+       struct nft_set_list *list = nft_set_list_alloc();
+
+       if (list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       len = json_array_size(array);
+       for (i = 0; i < len; i++) {
+               node = json_array_get(array, i);
+               if (node == NULL) {
+                       errno = EINVAL;
+                       goto err;
+               }
+
+               if (!(nft_jansson_node_exist(node, "set")))
+                       continue;
+
+               s = nft_set_alloc();
+               if (s == NULL) {
+                       errno = ENOMEM;
+                       goto err;
+               }
+
+               if (nft_jansson_parse_set(s, node) < 0) {
+                       nft_set_free(s);
+                       goto err;
+               }
+
+               nft_set_list_add_tail(s, list);
+       }
+
+       if (!nft_set_list_is_empty(list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, list);
+       else
+               nft_set_list_free(list);
+
+       return 0;
+err:
+       nft_set_list_free(list);
+       return -1;
+}
+
+static int nft_ruleset_json_parse_rules(struct nft_ruleset *rs, json_t *array)
+{
+       int i, len;
+       json_t *node;
+       struct nft_rule *o = NULL;
+       struct nft_rule_list *list = nft_rule_list_alloc();
+
+       if (list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       len = json_array_size(array);
+       for (i = 0; i < len; i++) {
+               node = json_array_get(array, i);
+               if (node == NULL) {
+                       errno = EINVAL;
+                       goto err;
+               }
+
+               if (!(nft_jansson_node_exist(node, "rule")))
+                       continue;
+
+               o = nft_rule_alloc();
+               if (o == NULL) {
+                       errno = ENOMEM;
+                       goto err;
+               }
+
+               if (nft_jansson_parse_rule(o, node) < 0) {
+                       nft_rule_free(o);
+                       goto err;
+               }
+
+               nft_rule_list_add_tail(o, list);
+       }
+
+       if (!nft_rule_list_is_empty(list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, list);
+       else
+               nft_rule_list_free(list);
+
+       return 0;
+err:
+       nft_rule_list_free(list);
+       return -1;
+}
+
+#endif
+
+static int nft_ruleset_json_parse(struct nft_ruleset *rs, const char *json)
+{
+#ifdef JSON_PARSING
+       json_t *root, *array;
+       json_error_t error;
+
+       root = nft_jansson_create_root(json, &error);
+       if (root == NULL)
+               return -1;
+
+       array = json_object_get(root, "nftables");
+       if (array == NULL) {
+               errno = EINVAL;
+               goto err;
+       }
+
+       if (nft_ruleset_json_parse_tables(rs, array) != 0)
+               goto err;
+
+       if (nft_ruleset_json_parse_chains(rs, array) != 0)
+               goto err;
+
+       if (nft_ruleset_json_parse_sets(rs, array) != 0)
+               goto err;
+
+       if (nft_ruleset_json_parse_rules(rs, array) != 0)
+               goto err;
+
+       nft_jansson_free_root(root);
+       return 0;
+err:
+       nft_jansson_free_root(root);
+       return -1;
+#else
+       errno = EOPNOTSUPP;
+       return -1;
+#endif
+}
+
+#ifdef XML_PARSING
+static int
+nft_ruleset_xml_parse_tables(struct nft_ruleset *rs, mxml_node_t *tree)
+{
+       mxml_node_t *node;
+       struct nft_table *t;
+       struct nft_table_list *table_list = nft_table_list_alloc();
+       if (table_list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       for (node = mxmlFindElement(tree, tree, "table", NULL, NULL,
+                                   MXML_DESCEND_FIRST);
+            node != NULL;
+            node = mxmlFindElement(node, tree, "table", NULL, NULL,
+                                   MXML_NO_DESCEND)) {
+               t = nft_table_alloc();
+               if (t == NULL)
+                       goto err_free;
+
+               if (nft_mxml_table_parse(node, t) != 0) {
+                       nft_table_free(t);
+                       goto err_free;
+               }
+
+               nft_table_list_add_tail(t, table_list);
+       }
+
+       if (!nft_table_list_is_empty(table_list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST,
+                                    table_list);
+       else
+               nft_table_list_free(table_list);
+
+       return 0;
+err_free:
+       nft_table_list_free(table_list);
+       return -1;
+}
+
+static int
+nft_ruleset_xml_parse_chains(struct nft_ruleset *rs, mxml_node_t *tree)
+{
+       mxml_node_t *node;
+       struct nft_chain *c;
+       struct nft_chain_list *chain_list = nft_chain_list_alloc();
+       if (chain_list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       for (node = mxmlFindElement(tree, tree, "chain", NULL, NULL,
+                                   MXML_DESCEND_FIRST);
+            node != NULL;
+            node = mxmlFindElement(node, tree, "chain", NULL, NULL,
+                                   MXML_NO_DESCEND)) {
+               c = nft_chain_alloc();
+               if (c == NULL)
+                       goto err_free;
+
+               if (nft_mxml_chain_parse(node, c) != 0) {
+                       nft_chain_free(c);
+                       goto err_free;
+               }
+
+               nft_chain_list_add_tail(c, chain_list);
+       }
+
+       if (!nft_chain_list_is_empty(chain_list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST,
+                                    chain_list);
+       else
+               nft_chain_list_free(chain_list);
+
+       return 0;
+err_free:
+       nft_chain_list_free(chain_list);
+       return -1;
+}
+
+static int
+nft_ruleset_xml_parse_sets(struct nft_ruleset *rs, mxml_node_t *tree)
+{
+       mxml_node_t *node;
+       struct nft_set *s;
+       struct nft_set_list *set_list = nft_set_list_alloc();
+       if (set_list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       for (node = mxmlFindElement(tree, tree, "set", NULL, NULL,
+                                   MXML_DESCEND_FIRST);
+            node != NULL;
+            node = mxmlFindElement(node, tree, "set", NULL, NULL,
+                                   MXML_NO_DESCEND)) {
+               s = nft_set_alloc();
+               if (s == NULL)
+                       goto err_free;
+
+               if (nft_mxml_set_parse(node, s) != 0) {
+                       nft_set_free(s);
+                       goto err_free;
+               }
+
+               nft_set_list_add_tail(s, set_list);
+       }
+
+       if (!nft_set_list_is_empty(set_list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, set_list);
+       else
+               nft_set_list_free(set_list);
+
+       return 0;
+err_free:
+       nft_set_list_free(set_list);
+       return -1;
+}
+
+static int
+nft_ruleset_xml_parse_rules(struct nft_ruleset *rs, mxml_node_t *tree)
+{
+       mxml_node_t *node;
+       struct nft_rule *r;
+       struct nft_rule_list *rule_list = nft_rule_list_alloc();
+       if (rule_list == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       for (node = mxmlFindElement(tree, tree, "rule", NULL, NULL,
+                                   MXML_DESCEND_FIRST);
+            node != NULL;
+            node = mxmlFindElement(node, tree, "rule", NULL, NULL,
+                                   MXML_NO_DESCEND)) {
+               r = nft_rule_alloc();
+               if (r == NULL)
+                       goto err_free;
+
+               if (nft_mxml_rule_parse(node, r) != 0) {
+                       nft_rule_free(r);
+                       goto err_free;
+               }
+
+               nft_rule_list_add_tail(r, rule_list);
+       }
+
+       if (!nft_rule_list_is_empty(rule_list))
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, rule_list);
+       else
+               nft_rule_list_free(rule_list);
+
+       return 0;
+err_free:
+       nft_rule_list_free(rule_list);
+       return -1;
+}
+#endif
+
+static int nft_ruleset_xml_parse(struct nft_ruleset *rs, const char *xml)
+{
+#ifdef XML_PARSING
+       mxml_node_t *tree;
+
+       tree = nft_mxml_build_tree(xml, "nftables");
+       if (tree == NULL)
+               return -1;
+
+       if (nft_ruleset_xml_parse_tables(rs, tree) != 0)
+               goto err;
+
+       if (nft_ruleset_xml_parse_chains(rs, tree) != 0)
+               goto err;
+
+       if (nft_ruleset_xml_parse_sets(rs, tree) != 0)
+               goto err;
+
+       if (nft_ruleset_xml_parse_rules(rs, tree) != 0)
+               goto err;
+
+       mxmlDelete(tree);
+       return 0;
+err:
+       mxmlDelete(tree);
+       return -1;
+#else
+       errno = EOPNOTSUPP;
+       return -1;
+#endif
+}
+
+int nft_ruleset_parse(struct nft_ruleset *r, enum nft_ruleset_parse_type type,
+                     const char *data)
+{
+       int ret;
+
+       switch (type) {
+       case NFT_RULESET_PARSE_XML:
+               ret = nft_ruleset_xml_parse(r, data);
+               break;
+       case NFT_RULESET_PARSE_JSON:
+               ret = nft_ruleset_json_parse(r, data);
+               break;
+       default:
+               ret = -1;
+               errno = EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(nft_ruleset_parse);
+
+static int separator_snprintf(char *buf, size_t size, void *obj, uint32_t type)
+{
+       if (obj == NULL)
+               return 0;
+
+       switch (type) {
+       case NFT_RULESET_O_JSON:
+               return snprintf(buf, size, ",");
+       case NFT_RULESET_O_DEFAULT:
+               return snprintf(buf, size, "\n");
+       default:
+               return 0;
+       }
+}
+
+static int
+nft_ruleset_snprintf_table(char *buf, size_t size,
+                          const struct nft_ruleset *rs, uint32_t type,
+                          uint32_t flags)
+{
+       struct nft_table *t;
+       struct nft_table_list_iter *ti;
+       int ret, len = size, offset = 0;
+
+       ti = nft_table_list_iter_create(rs->table_list);
+       if (ti == NULL)
+               return 0;
+
+       t = nft_table_list_iter_next(ti);
+       while (t != NULL) {
+               ret = nft_table_snprintf(buf+offset, len, t, type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               t = nft_table_list_iter_next(ti);
+               ret = separator_snprintf(buf+offset, len, t, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+       nft_table_list_iter_destroy(ti);
+
+       return offset;
+}
+
+static int
+nft_ruleset_snprintf_chain(char *buf, size_t size,
+                          const struct nft_ruleset *rs, uint32_t type,
+                          uint32_t flags)
+{
+       struct nft_chain *c;
+       struct nft_chain_list_iter *ci;
+       int ret, len = size, offset = 0;
+
+       ci = nft_chain_list_iter_create(rs->chain_list);
+       if (ci == NULL)
+               return 0;
+
+       c = nft_chain_list_iter_next(ci);
+       while (c != NULL) {
+               ret = nft_chain_snprintf(buf+offset, len, c, type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               c = nft_chain_list_iter_next(ci);
+               ret = separator_snprintf(buf+offset, len, c, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+       nft_chain_list_iter_destroy(ci);
+
+       return offset;
+}
+
+static int
+nft_ruleset_snprintf_set(char *buf, size_t size,
+                        const struct nft_ruleset *rs, uint32_t type,
+                        uint32_t flags)
+{
+       struct nft_set *s;
+       struct nft_set_list_iter *si;
+       int ret, len = size, offset = 0;
+
+       si = nft_set_list_iter_create(rs->set_list);
+       if (si == NULL)
+               return 0;
+
+       s = nft_set_list_iter_next(si);
+       while (s != NULL) {
+               ret = nft_set_snprintf(buf+offset, len, s, type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               s = nft_set_list_iter_next(si);
+               ret = separator_snprintf(buf+offset, len, s, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+       nft_set_list_iter_destroy(si);
+
+       return offset;
+}
+
+static int
+nft_ruleset_snprintf_rule(char *buf, size_t size,
+                         const struct nft_ruleset *rs, uint32_t type,
+                         uint32_t flags)
+{
+       struct nft_rule *r;
+       struct nft_rule_list_iter *ri;
+       int ret, len = size, offset = 0;
+
+       ri = nft_rule_list_iter_create(rs->rule_list);
+       if (ri == NULL)
+               return 0;
+
+       r = nft_rule_list_iter_next(ri);
+       while (r != NULL) {
+               ret = nft_rule_snprintf(buf+offset, len, r, type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               r = nft_rule_list_iter_next(ri);
+               ret = separator_snprintf(buf+offset, len, r, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+       nft_rule_list_iter_destroy(ri);
+
+       return offset;
+}
+
+static int
+nft_ruleset_do_snprintf(char *buf, size_t size, const struct nft_ruleset *rs,
+                       uint32_t type, uint32_t flags)
+{
+       int ret, len = size, offset = 0;
+       void *prev = NULL;
+
+       if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_TABLELIST) &&
+           (!nft_table_list_is_empty(rs->table_list))) {
+               ret = nft_ruleset_snprintf_table(buf+offset, len, rs,
+                                                type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               if (ret > 0)
+                       prev = rs->table_list;
+       }
+
+       if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST) &&
+           (!nft_chain_list_is_empty(rs->chain_list))) {
+               ret = separator_snprintf(buf+offset, len, prev, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               ret = nft_ruleset_snprintf_chain(buf+offset, len, rs,
+                                                type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               if (ret > 0)
+                       prev = rs->chain_list;
+       }
+
+       if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_SETLIST) &&
+           (!nft_set_list_is_empty(rs->set_list))) {
+               ret = separator_snprintf(buf+offset, len, prev, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               ret = nft_ruleset_snprintf_set(buf+offset, len, rs,
+                                              type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               if (ret > 0)
+                       prev = rs->set_list;
+       }
+
+       if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST) &&
+           (!nft_rule_list_is_empty(rs->rule_list))) {
+               ret = separator_snprintf(buf+offset, len, prev, type);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               ret = nft_ruleset_snprintf_rule(buf+offset, len, rs,
+                                               type, flags);
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
+       return offset;
+}
+
+static int
+nft_ruleset_snprintf_xml(char *buf, size_t size, const struct nft_ruleset *rs,
+                        uint32_t flags)
+{
+       int ret, len = size, offset = 0;
+
+       ret = snprintf(buf, size, "<nftables>");
+       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       ret = nft_ruleset_do_snprintf(buf+offset, len, rs, NFT_RULESET_O_XML,
+                                     flags);
+       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       ret = snprintf(buf+offset, len, "</nftables>");
+       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       return offset;
+}
+
+static int
+nft_ruleset_snprintf_json(char *buf, size_t size, const struct nft_ruleset *rs,
+                         uint32_t flags)
+{
+       int ret, len = size, offset = 0;
+
+       ret = snprintf(buf, size, "{ \"nftables\": [");
+       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       ret = nft_ruleset_do_snprintf(buf+offset, len, rs, NFT_RULESET_O_JSON,
+                                     flags);
+       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       ret = snprintf(buf+offset, len, "]}");
+       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       return offset;
+}
+
+int nft_ruleset_snprintf(char *buf, size_t size, const struct nft_ruleset *r,
+                        uint32_t type, uint32_t flags)
+{
+       switch (type) {
+       case NFT_RULESET_O_DEFAULT:
+               return nft_ruleset_do_snprintf(buf, size, r, type, flags);
+       case NFT_RULESET_O_XML:
+               return nft_ruleset_snprintf_xml(buf, size, r, flags);
+       case NFT_RULESET_O_JSON:
+               return nft_ruleset_snprintf_json(buf, size, r, flags);
+       default:
+               break;
+       }
+       return -1;
+}
+EXPORT_SYMBOL(nft_ruleset_snprintf);
index 1b81c6cb5939923e3c6b90b4ac2e0c2fccace6eb..31185a0bb926c7297521dd78348210c3e623c22e 100644 (file)
--- a/src/set.c
+++ b/src/set.c
@@ -304,7 +304,7 @@ int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
 EXPORT_SYMBOL(nft_set_nlmsg_parse);
 
 #ifdef JSON_PARSING
-static int nft_jansson_parse_set(struct nft_set *s, json_t *tree)
+int nft_jansson_parse_set(struct nft_set *s, json_t *tree)
 {
        json_t *root, *array, *json_elem;
        uint32_t uval32;
index c095053c2b4898a35f1c3ca82d3eb3df93f71841..7f14b322f2f80e9bba8160c1053423a793feb7d6 100644 (file)
@@ -272,7 +272,7 @@ static int nft_table_xml_parse(struct nft_table *t, const char *xml)
 }
 
 #ifdef JSON_PARSING
-static int nft_jansson_parse_table(struct nft_table *t, json_t *tree)
+int nft_jansson_parse_table(struct nft_table *t, json_t *tree)
 {
        json_t *root;
        uint32_t flags;
diff --git a/tests/jsonfiles/64-ruleset.json b/tests/jsonfiles/64-ruleset.json
new file mode 100644 (file)
index 0000000..c4fffa1
--- /dev/null
@@ -0,0 +1,2 @@
+{ "nftables": [{"table" : {"name" : "filter","family" : "ip","flags" : 0}},{"table" : {"name" : "filter2","family" : "ip6","flags" : 0}},{ "chain": {"name": "input","handle": 1,"bytes": 10681449,"packets": 16216,"family": "ip","table": "filter","use": 0,"type": "filter","hooknum": "input","prio": 0,"policy": "accept"}},{ "chain": {"name": "forward","handle": 2,"bytes": 0,"packets": 0,"family": "ip","table": "filter","use": 0,"type": "filter","hooknum": "forward","prio": 0,"policy": "accept"}},{ "chain": {"name": "output","handle": 3,"bytes": 2375830,"packets": 15184,"family": "ip","table": "filter","use": 0,"type": "filter","hooknum": "output","prio": 0,"policy": "accept"}},{ "chain": {"name": "chain1","handle": 4,"bytes": 0,"packets": 0,"family": "ip","table": "filter","use": 0}},{ "set": { "name": "set0","table": "filter","flags": 3,"family": "ip","key_type": 12,"key_len": 2}},{ "rule": { "family" : "ip", "table" : "filter", "chain"  : "output", "handle" : 6,"flags" : 0, " expr" : [ { "type" : "payload", "dreg" : 1, "offset" : 16, "len" : 4, "base" : "link"}, { "type" : "cmp", "sreg" : 1, "op" : "eq", "cmpdata" : {"data_reg": { "type" : "value", "len" : 4, "data0" : "0x0100a8c0"}}}, { "type" : "counter", "pkts" : 0, "bytes" : 0}, { "type" : "immediate", "dreg" : 0, "immediatedata" : {"data_reg": {"type" : "verdict", "verdict" : "drop"}}}]}},{ "rule": { "family" : "ip", "table" : "filter", "chain"  : "output", "handle" : 9,"flags" : 0, "expr" : [ { "type" : "payload", "dreg" : 1, "offset" : 9, "len" : 1, "base" : "link"}, { "type" : "cmp", "sreg" : 1, "op" : "eq", "cmpdata" : {"data_reg": { "type" : "value", "len" : 1, "data0" : "0x00000006"}}}, { "type" : "payload", "dreg" : 1, "offset" : 2, "len" : 2, "base" : "link"}, { "type" : "cmp", "sreg" : 1, "op" : "eq", "cmpdata" : {"data_reg": { "type" : "value", "len" : 2, "data0" : "0x00001600"}}}, { "type" : "counter", "pkts" : 0, "bytes" : 0}]}},{ "rule": { "family" : "ip", "table" : "filter", "chain"  : "output", "handle" : 10,"flags" : 0, "expr" : [ { "type" : "payload", "dreg" : 1, "offset" : 16, "len" : 4, "base" : "link"}, { "type" : "cmp", "sreg" : 1, "op" : "eq", "cmpdata" : {"data_reg": { "type" : "value", "len" : 4, "data0" : "0x0100a8c0"}}}, { "type" : "counter", "pkts" : 0, "bytes" : 0}]}},{ "rule": { "family" : "ip", "table" : "filter", "chain"  : "output", "handle" : 11,"flags" : 0, "expr" : [ { "type" : "payload", "dreg" : 1, "offset" : 16, "len" : 4, "base" : "link"}, { "type" : "cmp", "sreg" : 1, "op" : "eq", "cmpdata" : {"data_reg": { "type" : "value", "len" : 4, "data0" : "0x0100a8c0"}}}, { "type" : "counter", "pkts" : 0, "bytes" : 0}, { "type" : "immediate", "dreg" : 0, "immediatedata" : {"data_reg": {"type" : "verdict", "verdict" : "drop"}}}]}}]}
+
index ecde0e27544a7c932aad66bc3004afb78adf8b69..866c9850432d572518abc1530dfeaeb067ce87d5 100644 (file)
@@ -6,6 +6,7 @@
 #include <errno.h>
 
 #include <libmnl/libmnl.h> /*nlmsghdr*/
+#include <libnftables/ruleset.h>
 #include <libnftables/table.h>
 #include <libnftables/chain.h>
 #include <libnftables/rule.h>
@@ -24,10 +25,12 @@ enum {
        TEST_XML_CHAIN,
        TEST_XML_RULE,
        TEST_XML_SET,
+       TEST_XML_RULESET,
        TEST_JSON_TABLE,
        TEST_JSON_CHAIN,
        TEST_JSON_RULE,
        TEST_JSON_SET,
+       TEST_JSON_RULESET,
 };
 
 #if defined(XML_PARSING) || defined(JSON_PARSING)
@@ -76,6 +79,7 @@ static int compare_test(uint32_t type, void *input, const char *filename)
        struct nft_chain *c = NULL;
        struct nft_rule *r = NULL;
        struct nft_set *s = NULL;
+       struct nft_ruleset *rs = NULL;
        char orig[4096];
        char out[4096];
        FILE *fp;
@@ -97,6 +101,10 @@ static int compare_test(uint32_t type, void *input, const char *filename)
        case TEST_JSON_SET:
                s = (struct nft_set *)input;
                break;
+       case TEST_XML_RULESET:
+       case TEST_JSON_RULESET:
+               rs = (struct nft_ruleset *)input;
+               break;
        default:
                errno = EINVAL;
                return -1;
@@ -127,6 +135,14 @@ static int compare_test(uint32_t type, void *input, const char *filename)
        case TEST_JSON_SET:
                nft_set_snprintf(out, sizeof(out), s, NFT_SET_O_JSON, 0);
                break;
+       case TEST_XML_RULESET:
+               nft_ruleset_snprintf(out, sizeof(out), rs,
+                                    NFT_RULESET_O_XML, 0);
+               break;
+       case TEST_JSON_RULESET:
+               nft_ruleset_snprintf(out, sizeof(out), rs,
+                                    NFT_RULESET_O_JSON, 0);
+               break;
        default:
                errno = EINVAL;
                return -1;
@@ -159,6 +175,7 @@ static int test_json(const char *filename)
        struct nft_chain *c;
        struct nft_rule *r;
        struct nft_set *s;
+       struct nft_ruleset *rs;
        json_t *root;
        json_error_t error;
        char *json;
@@ -211,6 +228,16 @@ static int test_json(const char *filename)
 
                        nft_set_free(s);
                        }
+       } else if (json_object_get(root, "nftables") != NULL) {
+               rs = nft_ruleset_alloc();
+               if (rs != NULL) {
+                       if (nft_ruleset_parse(rs, NFT_RULESET_PARSE_JSON, json) == 0)
+                               ret = compare_test(TEST_JSON_RULESET, rs, filename);
+                       else
+                               ret = -1;
+
+                       nft_ruleset_free(rs);
+                       }
        }
 
        free(json);
@@ -237,6 +264,7 @@ static int test_xml(const char *filename)
        struct nft_chain *c;
        struct nft_rule *r;
        struct nft_set *s;
+       struct nft_ruleset *rs;
        FILE *fp;
        mxml_node_t *tree;
        char *xml;
@@ -293,6 +321,18 @@ static int test_xml(const char *filename)
 
                        nft_set_free(s);
                }
+       } else if (strcmp(tree->value.opaque, "nftables") == 0) {
+               rs = nft_ruleset_alloc();
+               if (rs != NULL) {
+                       if (nft_ruleset_parse(rs, NFT_RULESET_PARSE_XML,
+                                             xml) == 0)
+                               ret = compare_test(TEST_XML_RULESET, rs,
+                                                  filename);
+                       else
+                               ret = -1;
+
+                       nft_ruleset_free(rs);
+               }
        }
 
        return ret;
diff --git a/tests/xmlfiles/75-ruleset.xml b/tests/xmlfiles/75-ruleset.xml
new file mode 100644 (file)
index 0000000..926c2be
--- /dev/null
@@ -0,0 +1 @@
+<nftables><table><name>filter</name><family>ip</family><flags>0</flags></table><table><name>filter2</name><family>ip</family><flags>0</flags></table><chain><name>input</name><handle>1</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family></chain><chain><name>output</name><handle>3</handle><bytes>0</bytes><packets>0</packets><table>filter</table><family>ip</family></chain><set><family>ip</family><table>filter</table><name>set0</name><flags>3</flags><key_type>12</key_type><key_len>2</key_len><data_type>0</data_type><data_len>0</data_len><set_elem><flags>0</flags><key><data_reg type="value"><len>2</len><data0>0x00001900</data0></data_reg></key></set_elem><set_elem><flags>0</flags><key><data_reg type="value"><len>2</len><data0>0x00001600</data0></data_reg></key></set_elem></set><set><family>ip</family><table>filter</table><name>set1</name><flags>3</flags><key_type>12</key_type><key_len>2</key_len><data_type>0</data_type><data_len>0</data_len><set_el