]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
set: add XML parsing
authorArturo Borrero <arturo.borrero.glez@gmail.com>
Fri, 26 Jul 2013 12:22:03 +0000 (14:22 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 26 Jul 2013 12:54:10 +0000 (14:54 +0200)
Sets are now parsed, following this previous snprintf pattern:

<set>
<set_name>string</set_name>
<set_table>table</set_table>
<set_xml_version>int</set_xml_version>
<set_flags>uint32_t</set_flags>
<key_type>uint32_t</key_type>
<key_len>size_t</key_len>
<data_type>uint32_t</data_type>
<data_len>size_t</data_len>
<set_elem>
<set_elem_flags>uint32_t</set_elem_flags>
<set_elem_key>
<data_reg type="value">
<len></len>
<dataN></dataN>
</data_reg>
</set_elem_key>
<set_elem_data>
<data_reg type="xx">
[...]
</data_reg>
</set_elem_data>
</set_elem>
</set>

Signed-off-by: Arturo Borrero González <arturo.borrero.glez@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/libnftables/set.h
src/internal.h
src/libnftables.map
src/mxml.c
src/set.c
src/set_elem.c
tests/nft-parsing-test.c
tests/xmlfiles/73-set.xml [new file with mode: 0644]
tests/xmlfiles/74-set.xml [new file with mode: 0644]

index 6023d503e59bc99b5b42c669eab32d92d28296b0..4fc3a8d1b171d35a34d1e26efae73688b524a6c8 100644 (file)
@@ -52,6 +52,14 @@ struct nft_set *nft_set_list_iter_cur(struct nft_set_list_iter *iter);
 struct nft_set *nft_set_list_iter_next(struct nft_set_list_iter *iter);
 void nft_set_list_iter_destroy(struct nft_set_list_iter *iter);
 
+enum nft_set_parse_type {
+       NFT_SET_PARSE_NONE      = 0,
+       NFT_SET_PARSE_XML,
+       NFT_SET_PARSE_MAX,
+};
+
+int nft_set_parse(struct nft_set *s, enum nft_set_parse_type type, char *data);
+
 /*
  * Set elements
  */
@@ -94,6 +102,7 @@ void nft_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set_elem
 
 int nft_set_elem_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set_elem *s);
 
+int nft_set_elem_parse(struct nft_set_elem *e, enum nft_set_parse_type type, char *data);
 int nft_set_elem_snprintf(char *buf, size_t size, struct nft_set_elem *s, uint32_t type, uint32_t flags);
 
 int nft_set_elem_foreach(struct nft_set *s, int (*cb)(struct nft_set_elem *e, void *data), void *data);
index 47cd6358ffac605d325ae355d52d22dd25ba357c..1970c9cfb369aca5ff44503e26ffdfeb1a1b477b 100644 (file)
@@ -36,6 +36,7 @@ union nft_data_reg;
 int nft_mxml_data_reg_parse(mxml_node_t *tree, const char *node_name, union nft_data_reg *data_reg);
 int nft_mxml_num_parse(mxml_node_t *tree, const char *node_name, uint32_t mxml_flags, int base, void *number, enum nft_type type);
 const char *nft_mxml_str_parse(mxml_node_t *tree, const char *node_name, uint32_t mxml_flags);
+struct nft_set_elem *nft_mxml_set_elem_parse(mxml_node_t *node);
 #endif
 
 #ifdef JSON_PARSING
index f2084d9d9e138c8d6172688aa4d34faaf73a5644..614c705ef87efbce591f2cc45e4866c12769c7c0 100644 (file)
@@ -120,6 +120,7 @@ global:
   nft_set_nlmsg_build_hdr;
   nft_set_nlmsg_build_payload;
   nft_set_nlmsg_parse;
+  nft_set_parse;
   nft_set_snprintf;
 
   nft_set_list_alloc;
@@ -149,6 +150,7 @@ global:
   nft_set_elem_nlmsg_build_hdr;
   nft_set_elem_nlmsg_build_payload;
   nft_set_elem_nlmsg_parse;
+  nft_set_elem_parse;
   nft_set_elem_snprintf;
 
   nft_set_elems_nlmsg_build_payload;
index f812bf6ba5558579963a4038e34c86273d3d0657..84514da5dcb4061b6a988738997df7ca3b6a6b31 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/netfilter/nf_tables.h>
 #include <libnftables/rule.h>
 #include <libnftables/expr.h>
+#include <libnftables/set.h>
 
 #ifdef XML_PARSING
 struct nft_rule_expr *nft_mxml_expr_parse(mxml_node_t *node)
@@ -165,4 +166,49 @@ const char *nft_mxml_str_parse(mxml_node_t *tree, const char *node_name,
        return strdup(node->child->value.opaque);
 }
 
+struct nft_set_elem *nft_mxml_set_elem_parse(mxml_node_t *node)
+{
+       mxml_node_t *save;
+       char *set_elem_str;
+       struct nft_set_elem *elem;
+
+       if (node == NULL)
+               goto einval;
+
+       if (strcmp(node->value.opaque, "set_elem") != 0)
+               goto einval;
+
+       elem = nft_set_elem_alloc();
+       if (elem == NULL)
+               goto enomem;
+
+       /* This is a hack for mxml to print just the current node */
+       save = node->next;
+       node->next = NULL;
+
+       set_elem_str = mxmlSaveAllocString(node, MXML_NO_CALLBACK);
+       node->next = save;
+
+       if (set_elem_str == NULL) {
+               free(elem);
+               goto enomem;
+       }
+
+       if (nft_set_elem_parse(elem, NFT_SET_PARSE_XML,
+                              set_elem_str) != 0) {
+               free(set_elem_str);
+               free(elem);
+               return NULL;
+       }
+
+       free(set_elem_str);
+
+       return elem;
+einval:
+       errno = EINVAL;
+       return NULL;
+enomem:
+       errno = ENOMEM;
+       return NULL;
+}
 #endif
index b7291952c966fb3909d0eaee88e93acfa91a539d..4b0ec6affade21028fbd94ee14a0a73d9b6ec4cf 100644 (file)
--- a/src/set.c
+++ b/src/set.c
@@ -16,6 +16,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <netinet/in.h>
+#include <limits.h>
+#include <errno.h>
 
 #include <libmnl/libmnl.h>
 #include <linux/netfilter/nfnetlink.h>
@@ -301,6 +303,144 @@ int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
 }
 EXPORT_SYMBOL(nft_set_nlmsg_parse);
 
+static int nft_set_xml_parse(struct nft_set *s, char *xml)
+{
+#ifdef XML_PARSING
+       mxml_node_t *tree;
+       mxml_node_t *node = NULL;
+       struct nft_set_elem *elem;
+       char *name;
+       char *table;
+       int version;
+       int family;
+       char *family_str;
+
+       tree = mxmlLoadString(NULL, xml, MXML_OPAQUE_CALLBACK);
+       if (tree == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (strcmp(tree->value.opaque, "set") != 0)
+               goto err;
+
+       if (nft_mxml_num_parse(tree, "set_xml_version", MXML_DESCEND_FIRST,
+                              BASE_DEC, &version, NFT_TYPE_S32) != 0)
+               goto err;
+
+       if (version != NFT_SET_XML_VERSION)
+               goto err;
+
+       name = (char *)nft_mxml_str_parse(tree, "set_name",
+                                         MXML_DESCEND_FIRST);
+       if (name == NULL)
+               goto err;
+
+       if (s->name)
+               free(s->name);
+
+       s->name = name;
+       s->flags |= (1 << NFT_SET_ATTR_NAME);
+
+       table = (char *)nft_mxml_str_parse(tree, "set_table",
+                                         MXML_DESCEND_FIRST);
+       if (table == NULL)
+               goto err;
+
+       if (s->table)
+               free(s->table);
+
+       s->table = strdup(table);
+       s->flags |= (1 << NFT_SET_ATTR_TABLE);
+
+       family_str = (char *)nft_mxml_str_parse(tree, "family",
+                                               MXML_DESCEND_FIRST);
+       if (family_str == NULL)
+               goto err;
+
+       family = nft_str2family(family_str);
+
+       if (family < 0)
+               goto err;
+
+       s->family = family;
+
+       s->flags |= (1 << NFT_SET_ATTR_FAMILY);
+
+       if (nft_mxml_num_parse(tree, "set_flags", MXML_DESCEND_FIRST,
+                              BASE_DEC, &s->set_flags, NFT_TYPE_U32) != 0)
+               goto err;
+
+       s->flags |= (1 << NFT_SET_ATTR_FLAGS);
+
+
+       if (nft_mxml_num_parse(tree, "key_type", MXML_DESCEND_FIRST,
+                              BASE_DEC, &s->key_type, NFT_TYPE_U32) != 0)
+               goto err;
+
+       s->flags |= (1 << NFT_SET_ATTR_KEY_TYPE);
+
+       if (nft_mxml_num_parse(tree, "key_len", MXML_DESCEND_FIRST,
+                              BASE_DEC, &s->key_type, NFT_TYPE_U32) != 0)
+               goto err;
+
+       s->flags |= (1 << NFT_SET_ATTR_KEY_LEN);
+
+       if (nft_mxml_num_parse(tree, "data_type", MXML_DESCEND_FIRST,
+                              BASE_DEC, &s->data_type, NFT_TYPE_U32) != 0)
+               goto err;
+
+       s->flags |= (1 << NFT_SET_ATTR_DATA_TYPE);
+
+       if (nft_mxml_num_parse(tree, "data_len", MXML_DESCEND_FIRST,
+                              BASE_DEC, &s->data_len, NFT_TYPE_U32) != 0)
+               goto err;
+
+       s->flags |= (1 << NFT_SET_ATTR_DATA_LEN);
+
+       /* Iterate over each <set_elem> */
+       for (node = mxmlFindElement(tree, tree, "set_elem", NULL,
+                                   NULL, MXML_DESCEND);
+               node != NULL;
+               node = mxmlFindElement(node, tree, "set_elem", NULL,
+                                      NULL, MXML_DESCEND)) {
+
+               elem = nft_mxml_set_elem_parse(node);
+               if (elem == NULL)
+                       goto err;
+
+               list_add_tail(&elem->head, &s->element_list);
+       }
+
+       mxmlDelete(tree);
+       return 0;
+err:
+       mxmlDelete(tree);
+       return -1;
+#else
+       errno = EOPNOTSUPP;
+       return -1;
+#endif
+}
+
+int nft_set_parse(struct nft_set *s, enum nft_set_parse_type type, char *data)
+{
+       int ret;
+
+       switch (type) {
+       case NFT_SET_PARSE_XML:
+               ret = nft_set_xml_parse(s, data);
+               break;
+       default:
+               ret = -1;
+               errno = EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(nft_set_parse);
+
 static int nft_set_snprintf_json(char *buf, size_t size, struct nft_set *s,
                                  uint32_t type, uint32_t flags)
 {
index 4adba91ad0c27062ce109420dca239ee458f46a0..5325373f75e19de2474af2e54884ab706a565ef2 100644 (file)
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <netinet/in.h>
+#include <errno.h>
 
 #include <libmnl/libmnl.h>
 #include <linux/netfilter/nfnetlink.h>
@@ -374,8 +375,90 @@ int nft_set_elems_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
 }
 EXPORT_SYMBOL(nft_set_elems_nlmsg_parse);
 
+static int nft_set_elem_xml_parse(struct nft_set_elem *e, char *xml)
+{
+#ifdef XML_PARSING
+       mxml_node_t *tree;
+       mxml_node_t *node;
+       int set_elem_data;
+
+       tree = mxmlLoadString(NULL, xml, MXML_OPAQUE_CALLBACK);
+       if (tree == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (strcmp(tree->value.opaque, "set_elem") != 0) {
+               errno = EINVAL;
+               goto err;
+       }
+
+       if (nft_mxml_num_parse(tree, "set_elem_flags", MXML_DESCEND_FIRST,
+                              BASE_DEC, &e->set_elem_flags,
+                              NFT_TYPE_U32) != 0)
+               goto err;
+
+       e->flags |= (1 << NFT_SET_ELEM_ATTR_FLAGS);
+
+       if (nft_mxml_data_reg_parse(tree, "set_elem_key",
+                                   &e->key) != DATA_VALUE)
+               goto err;
+
+       e->flags |= (1 << NFT_SET_ELEM_ATTR_KEY);
+
+       /* <set_elem_data> is not mandatory */
+       node = mxmlFindElement(tree, tree, "set_elem_data", NULL, NULL,
+                              MXML_DESCEND_FIRST);
+       if (node != NULL && node->child != NULL) {
+               set_elem_data = nft_mxml_data_reg_parse(tree, "set_elem_data",
+                                                       &e->data);
+               switch (set_elem_data) {
+               case DATA_VALUE:
+                       e->flags |= (1 << NFT_SET_ELEM_ATTR_DATA);
+                       break;
+               case DATA_VERDICT:
+                       e->flags |= (1 << NFT_SET_ELEM_ATTR_VERDICT);
+                       break;
+               case DATA_CHAIN:
+                       e->flags |= (1 << NFT_SET_ELEM_ATTR_CHAIN);
+                       break;
+               default:
+                       goto err;
+               }
+       }
+
+       mxmlDelete(tree);
+       return 0;
+
+err:
+       mxmlDelete(tree);
+       return -1;
+#else
+       errno = EOPNOTSUPP;
+       return -1;
+#endif
+}
+
+int nft_set_elem_parse(struct nft_set_elem *e,
+                      enum nft_set_parse_type type, char *data) {
+       int ret;
+
+       switch (type) {
+       case NFT_SET_PARSE_XML:
+               ret = nft_set_elem_xml_parse(e, data);
+               break;
+       default:
+               errno = EOPNOTSUPP;
+               ret = -1;
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(nft_set_elem_parse);
+
 static int nft_set_elem_snprintf_json(char *buf, size_t size,
-                                      struct nft_set_elem *e, uint32_t flags)
+                                     struct nft_set_elem *e, uint32_t flags)
 {
        int ret, len = size, offset = 0, type = -1;
 
index 83a627c874deb388a8ef3fbe57c757e3b79fbf76..0734f0793ab64b71d562a897ad2deb69e345d24f 100644 (file)
@@ -9,6 +9,7 @@
 #include <libnftables/table.h>
 #include <libnftables/chain.h>
 #include <libnftables/rule.h>
+#include <libnftables/set.h>
 
 #ifdef XML_PARSING
 #include <mxml.h>
@@ -62,6 +63,7 @@ static int test_xml(const char *filename)
        struct nft_table *t = NULL;
        struct nft_chain *c = NULL;
        struct nft_rule *r = NULL;
+       struct nft_set *s = NULL;
        FILE *fp;
        mxml_node_t *tree = NULL;;
        char *xml = NULL;
@@ -102,6 +104,14 @@ static int test_xml(const char *filename)
 
                        nft_rule_free(r);
                }
+       } else if (strcmp(tree->value.opaque, "set") == 0) {
+               s = nft_set_alloc();
+               if (s != NULL) {
+                       if (nft_set_parse(s, NFT_SET_PARSE_XML, xml) == 0)
+                               ret = 0;
+
+                       nft_set_free(s);
+               }
        }
 
        return ret;
diff --git a/tests/xmlfiles/73-set.xml b/tests/xmlfiles/73-set.xml
new file mode 100644 (file)
index 0000000..6807ea7
--- /dev/null
@@ -0,0 +1,39 @@
+<set>
+       <set_name>set0</set_name>
+       <set_table>filter</set_table>
+       <set_xml_version>0</set_xml_version>
+       <family>ip</family>
+       <set_flags>0</set_flags>
+       <key_type>0</key_type>
+       <key_len>0</key_len>
+       <data_type>0</data_type>
+       <data_len>0</data_len>
+       <set_elem>
+               <set_elem_flags>0</set_elem_flags>
+               <set_elem_key>
+                       <data_reg type="value">
+                               <len>4</len>
+                               <data0>0x0300a8c0</data0>
+                       </data_reg>
+               </set_elem_key>
+       </set_elem>
+       <set_elem>
+               <set_elem_flags>0</set_elem_flags>
+               <set_elem_key>
+                       <data_reg type="value">
+                               <len>4</len>
+                               <data0>0x0200a8c0</data0>
+                       </data_reg>
+               </set_elem_key>
+       </set_elem>
+       <set_elem>
+               <set_elem_flags>0</set_elem_flags>
+               <set_elem_key>
+                       <data_reg type="value">
+                               <len>4</len>
+                               <data0>0x0100a8c0</data0>
+                       </data_reg>
+               </set_elem_key>
+       </set_elem>
+</set>
+<!-- nft add rule ip filter test ip daddr { 192.168.0.1, 192.168.0.2, 192.168.0.3 } tcp dport 443 counter accept -->
diff --git a/tests/xmlfiles/74-set.xml b/tests/xmlfiles/74-set.xml
new file mode 100644 (file)
index 0000000..dd65703
--- /dev/null
@@ -0,0 +1,36 @@
+<set>
+       <set_name>set0</set_name>
+       <set_table>filter</set_table>
+       <set_xml_version>0</set_xml_version>
+       <family>ip6</family>
+       <set_flags>0</set_flags>
+       <key_type>0</key_type>
+       <key_len>0</key_len>
+       <data_type>0</data_type>
+       <data_len>0</data_len>
+       <set_elem>
+               <set_elem_flags>0</set_elem_flags>
+               <set_elem_key>
+                       <data_reg type="value">
+                               <len>16</len>
+                               <data0>0xc09a002a</data0>
+                               <data1>0x2700cac1</data1>
+                               <data2>0x00000000</data2>
+                               <data3>0x70010000</data3>
+                       </data_reg>
+               </set_elem_key>
+       </set_elem>
+       <set_elem>
+               <set_elem_flags>0</set_elem_flags>
+               <set_elem_key>
+                       <data_reg type="value">
+                               <len>16</len>
+                               <data0>0xc09a002a</data0>
+                               <data1>0x2700cac1</data1>
+                               <data2>0x00000000</data2>
+                               <data3>0x50010000</data3>
+                       </data_reg>
+               </set_elem_key>
+       </set_elem>
+</set>
+<!-- nft add rule ip6 filter test ip6 daddr { 2a00:9ac0:c1ca:27::150, 2a00:9ac0:c1ca:27::170, } counter accept -->