summaryrefslogtreecommitdiffstats
path: root/src/ruleset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ruleset.c')
-rw-r--r--src/ruleset.c795
1 files changed, 482 insertions, 313 deletions
diff --git a/src/ruleset.c b/src/ruleset.c
index d05f907..15e84cf 100644
--- a/src/ruleset.c
+++ b/src/ruleset.c
@@ -32,6 +32,32 @@ struct nft_ruleset {
uint16_t flags;
};
+struct nft_parse_ctx {
+ enum nft_cmd_type cmd;
+ enum nft_ruleset_type type;
+ union {
+ struct nft_table *table;
+ struct nft_chain *chain;
+ struct nft_rule *rule;
+ struct nft_set *set;
+ struct nft_set_elem *set_elem;
+ };
+ void *data;
+
+ /* These fields below are not exposed to the user */
+ union {
+ json_t *json;
+ mxml_node_t *xml;
+ };
+
+ uint32_t format;
+ uint32_t set_id;
+ struct nft_set_list *set_list;
+
+ int (*cb)(const struct nft_parse_ctx *ctx);
+ uint16_t flags;
+};
+
struct nft_ruleset *nft_ruleset_alloc(void)
{
return calloc(1, sizeof(struct nft_ruleset));
@@ -131,453 +157,518 @@ void *nft_ruleset_attr_get(const struct nft_ruleset *r, uint16_t attr)
}
EXPORT_SYMBOL(nft_ruleset_attr_get);
-#ifdef JSON_PARSING
-static int nft_ruleset_json_parse_tables(struct nft_ruleset *rs, json_t *array,
- struct nft_parse_err *err)
+bool nft_ruleset_ctx_is_set(const struct nft_parse_ctx *ctx, uint16_t attr)
{
- int i, len;
- json_t *node;
- struct nft_table *table;
- struct nft_table_list *list = nft_table_list_alloc();
+ return ctx->flags & (1 << attr);
+}
+EXPORT_SYMBOL(nft_ruleset_ctx_is_set);
- if (list == NULL) {
- errno = ENOMEM;
- return -1;
+void *nft_ruleset_ctx_get(const struct nft_parse_ctx *ctx, uint16_t attr)
+{
+ if (!(ctx->flags & (1 << attr)))
+ return NULL;
+
+ switch (attr) {
+ case NFT_RULESET_CTX_CMD:
+ return (void *)&ctx->cmd;
+ case NFT_RULESET_CTX_TYPE:
+ return (void *)&ctx->type;
+ case NFT_RULESET_CTX_TABLE:
+ return ctx->table;
+ case NFT_RULESET_CTX_CHAIN:
+ return ctx->chain;
+ case NFT_RULESET_CTX_RULE:
+ return ctx->rule;
+ case NFT_RULESET_CTX_SET:
+ return ctx->set;
+ case NFT_RULESET_CTX_DATA:
+ return ctx->data;
+ default:
+ return NULL;
}
+}
+EXPORT_SYMBOL(nft_ruleset_ctx_get);
- len = json_array_size(array);
- for (i = 0; i < len; i++) {
- node = json_array_get(array, i);
- if (node == NULL) {
- errno = EINVAL;
- goto err;
- }
+uint32_t nft_ruleset_ctx_get_u32(const struct nft_parse_ctx *ctx, uint16_t attr)
+{
+ const void *ret = nft_ruleset_ctx_get(ctx, attr);
+ return ret == NULL ? 0 : *((uint32_t *)ret);
+}
+EXPORT_SYMBOL(nft_ruleset_ctx_get_u32);
- if (!(nft_jansson_node_exist(node, "table")))
- continue;
+#if defined(JSON_PARSING) || defined(XML_PARSING)
+static void nft_ruleset_ctx_set(struct nft_parse_ctx *ctx, uint16_t attr,
+ void *data)
+{
+ switch (attr) {
+ case NFT_RULESET_CTX_CMD:
+ ctx->cmd = *((uint32_t *)data);
+ break;
+ case NFT_RULESET_CTX_TYPE:
+ ctx->type = *((uint32_t *)data);
+ break;
+ case NFT_RULESET_CTX_TABLE:
+ ctx->table = data;
+ break;
+ case NFT_RULESET_CTX_CHAIN:
+ ctx->chain = data;
+ break;
+ case NFT_RULESET_CTX_RULE:
+ ctx->rule = data;
+ break;
+ case NFT_RULESET_CTX_SET:
+ ctx->set = data;
+ break;
+ case NFT_RULESET_CTX_DATA:
+ ctx->data = data;
+ break;
+ }
+ ctx->flags |= (1 << attr);
+}
- table = nft_table_alloc();
- if (table == NULL) {
- errno = ENOMEM;
- goto err;
- }
+static void nft_ruleset_ctx_set_u32(struct nft_parse_ctx *ctx, uint16_t attr,
+ uint32_t val)
+{
+ nft_ruleset_ctx_set(ctx, attr, &val);
+}
- if (nft_jansson_parse_table(table, node, err) < 0) {
- nft_table_free(table);
- goto err;
- }
+static int nft_ruleset_parse_tables(struct nft_parse_ctx *ctx,
+ struct nft_parse_err *err)
+{
+ struct nft_table *table;
- nft_table_list_add_tail(table, list);
+ table = nft_table_alloc();
+ if (table == NULL)
+ return -1;
+
+ switch (ctx->format) {
+ case NFT_OUTPUT_JSON:
+#ifdef JSON_PARSING
+ if (nft_jansson_parse_table(table, ctx->json, err) < 0)
+ goto err;
+#endif
+ break;
+ case NFT_OUTPUT_XML:
+#ifdef XML_PARSING
+ if (nft_mxml_table_parse(ctx->xml, table, err) < 0)
+ goto err;
+#endif
+ break;
+ default:
+ return -1;
}
- if (!nft_table_list_is_empty(list))
- nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST, list);
- else
- nft_table_list_free(list);
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE, NFT_RULESET_TABLE);
+ nft_ruleset_ctx_set(ctx, NFT_RULESET_CTX_TABLE, table);
+ if (ctx->cb(ctx) < 0)
+ goto err;
return 0;
err:
- nft_table_list_free(list);
+ nft_table_free(table);
return -1;
}
-static int nft_ruleset_json_parse_chains(struct nft_ruleset *rs, json_t *array,
- struct nft_parse_err *err)
+static int nft_ruleset_parse_chains(struct nft_parse_ctx *ctx,
+ struct nft_parse_err *err)
{
- int i, len;
- json_t *node;
struct nft_chain *chain;
- struct nft_chain_list *list = nft_chain_list_alloc();
- if (list == NULL) {
- errno = ENOMEM;
+ chain = nft_chain_alloc();
+ if (chain == NULL)
return -1;
- }
- len = json_array_size(array);
- for (i = 0; i < len; i++) {
- node = json_array_get(array, i);
- if (node == NULL) {
- errno = EINVAL;
+ switch (ctx->format) {
+ case NFT_OUTPUT_JSON:
+#ifdef JSON_PARSING
+ if (nft_jansson_parse_chain(chain, ctx->json, err) < 0)
goto err;
- }
-
- if (!(nft_jansson_node_exist(node, "chain")))
- continue;
-
- chain = nft_chain_alloc();
- if (chain == NULL) {
- errno = ENOMEM;
+#endif
+ break;
+ case NFT_OUTPUT_XML:
+#ifdef XML_PARSING
+ if (nft_mxml_chain_parse(ctx->xml, chain, err) < 0)
goto err;
- }
+#endif
+ break;
+ default:
+ return -1;
+ }
- if (nft_jansson_parse_chain(chain, node, err) < 0) {
- nft_chain_free(chain);
- goto err;
- }
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE, NFT_RULESET_CHAIN);
+ nft_ruleset_ctx_set(ctx, NFT_RULESET_CTX_CHAIN, chain);
+ if (ctx->cb(ctx) < 0)
+ goto err;
- nft_chain_list_add_tail(chain, list);
- }
+ return 0;
+err:
+ nft_chain_free(chain);
+ return -1;
+}
- if (!nft_chain_list_is_empty(list))
- nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, list);
- else
- nft_chain_list_free(list);
+static int nft_ruleset_parse_set(struct nft_parse_ctx *ctx,
+ struct nft_set *set, uint32_t type,
+ struct nft_parse_err *err)
+{
+ nft_set_attr_set_u32(set, NFT_SET_ATTR_ID, ctx->set_id++);
+ nft_set_list_add_tail(set, ctx->set_list);
+
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE, type);
+ nft_ruleset_ctx_set(ctx, NFT_RULESET_CTX_SET, set);
+ if (ctx->cb(ctx) < 0)
+ goto err;
return 0;
err:
- nft_chain_list_free(list);
return -1;
}
-static int nft_ruleset_json_parse_sets(struct nft_ruleset *rs, json_t *array,
+static int nft_ruleset_parse_set_elems(struct nft_parse_ctx *ctx,
struct nft_parse_err *err)
{
- int i, len;
- uint32_t set_id = 0;
- json_t *node;
struct nft_set *set;
- struct nft_set_list *list = nft_set_list_alloc();
- if (list == NULL) {
- errno = ENOMEM;
+ set = nft_set_alloc();
+ if (set == NULL)
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;
- set = nft_set_alloc();
- if (set == NULL) {
- errno = ENOMEM;
+ switch (ctx->format) {
+ case NFT_OUTPUT_JSON:
+#ifdef JSON_PARSING
+ if (nft_jansson_parse_elem(set, ctx->json, err) < 0)
goto err;
- }
-
- if (nft_jansson_parse_set(set, node, err) < 0) {
- nft_set_free(set);
+#endif
+ break;
+ case NFT_OUTPUT_XML:
+#ifdef XML_PARSING
+ if (nft_mxml_set_parse(ctx->xml, set, err) < 0)
goto err;
- }
-
- nft_set_attr_set_u32(set, NFT_SET_ATTR_ID, set_id++);
- nft_set_list_add_tail(set, list);
+#endif
+ break;
+ default:
+ return -1;
}
- if (!nft_set_list_is_empty(list))
- nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, list);
- else
- nft_set_list_free(list);
+ if (nft_ruleset_parse_set(ctx, set, NFT_RULESET_SET_ELEMS, err) < 0)
+ goto err;
return 0;
err:
- nft_set_list_free(list);
+ nft_set_free(set);
return -1;
}
-static int nft_ruleset_json_parse_rules(struct nft_ruleset *rs, json_t *array,
- struct nft_parse_err *err)
+static int nft_ruleset_parse_sets(struct nft_parse_ctx *ctx,
+ struct nft_parse_err *err)
{
- int i, len;
- json_t *node;
- struct nft_rule *rule = NULL;
- struct nft_rule_list *list = nft_rule_list_alloc();
+ struct nft_set *set;
- if (list == NULL) {
- errno = ENOMEM;
+ set = nft_set_alloc();
+ if (set == NULL)
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;
-
- rule = nft_rule_alloc();
- if (rule == NULL) {
- errno = ENOMEM;
+ switch (ctx->format) {
+ case NFT_OUTPUT_JSON:
+#ifdef JSON_PARSING
+ if (nft_jansson_parse_set(set, ctx->json, err) < 0)
goto err;
- }
-
- if (nft_jansson_parse_rule(rule, node, err, rs->set_list) < 0) {
- nft_rule_free(rule);
+#endif
+ break;
+ case NFT_OUTPUT_XML:
+#ifdef XML_PARSING
+ if (nft_mxml_set_parse(ctx->xml, set, err) < 0)
goto err;
- }
-
- nft_rule_list_add_tail(rule, list);
+#endif
+ break;
+ default:
+ return -1;
}
- if (!nft_rule_list_is_empty(list))
- nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, list);
- else
- nft_rule_list_free(list);
+ if (nft_ruleset_parse_set(ctx, set, NFT_RULESET_SET, err) < 0)
+ goto err;
return 0;
err:
- nft_rule_list_free(list);
+ nft_set_free(set);
return -1;
}
-static int nft_ruleset_json_parse_ruleset(struct nft_ruleset *rs, json_t *array,
- struct nft_parse_err *err)
+static int nft_ruleset_parse_rules(struct nft_parse_ctx *ctx,
+ struct nft_parse_err *err)
{
- if (nft_ruleset_json_parse_tables(rs, array, err) != 0)
- return -1;
-
- if (nft_ruleset_json_parse_chains(rs, array, err) != 0)
- return -1;
-
- if (nft_ruleset_json_parse_sets(rs, array, err) != 0)
- return -1;
+ struct nft_rule *rule;
- if (nft_ruleset_json_parse_rules(rs, array, err) != 0)
+ rule = nft_rule_alloc();
+ if (rule == NULL)
return -1;
- return 0;
-}
-#endif
-
-static int nft_ruleset_json_parse(struct nft_ruleset *rs, const void *json,
- struct nft_parse_err *err, enum nft_parse_input input)
-{
+ switch (ctx->format) {
+ case NFT_OUTPUT_JSON:
#ifdef JSON_PARSING
- json_t *root, *array;
- json_error_t error;
-
- root = nft_jansson_create_root(json, &error, err, input);
- if (root == NULL)
+ if (nft_jansson_parse_rule(rule, ctx->json, err,
+ ctx->set_list) < 0)
+ goto err;
+#endif
+ break;
+ case NFT_OUTPUT_XML:
+#ifdef XML_PARSING
+ if (nft_mxml_rule_parse(ctx->xml, rule, err, ctx->set_list) < 0)
+ goto err;
+#endif
+ break;
+ default:
return -1;
-
- array = json_object_get(root, "nftables");
- if (array == NULL) {
- errno = EINVAL;
- goto err;
}
- if (nft_ruleset_json_parse_ruleset(rs, array, err) != 0)
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE, NFT_RULESET_RULE);
+ nft_ruleset_ctx_set(ctx, NFT_RULESET_CTX_RULE, rule);
+ if (ctx->cb(ctx) < 0)
goto err;
- nft_jansson_free_root(root);
return 0;
err:
- nft_jansson_free_root(root);
- return -1;
-#else
- errno = EOPNOTSUPP;
+ nft_rule_free(rule);
return -1;
-#endif
}
+#endif
-#ifdef XML_PARSING
-static int
-nft_ruleset_xml_parse_tables(struct nft_ruleset *rs, mxml_node_t *tree,
- struct nft_parse_err *err)
+#ifdef JSON_PARSING
+static int nft_ruleset_json_parse_ruleset(struct nft_parse_ctx *ctx,
+ struct nft_parse_err *err)
{
- mxml_node_t *node;
- struct nft_table *table;
- struct nft_table_list *table_list = nft_table_list_alloc();
- if (table_list == NULL) {
- errno = ENOMEM;
- return -1;
- }
+ json_t *node, *array = ctx->json;
+ int len, i, ret;
- for (node = mxmlFindElement(tree, tree, "table", NULL, NULL,
- MXML_DESCEND_FIRST);
- node != NULL;
- node = mxmlFindElement(node, tree, "table", NULL, NULL,
- MXML_NO_DESCEND)) {
- table = nft_table_alloc();
- if (table == NULL)
- goto err_free;
+ ctx->set_list = nft_set_list_alloc();
+ if (ctx->set_list == NULL)
+ return -1;
- if (nft_mxml_table_parse(node, table, err) != 0) {
- nft_table_free(table);
- goto err_free;
+ len = json_array_size(array);
+ for (i = 0; i < len; i++) {
+ node = json_array_get(array, i);
+ if (node == NULL) {
+ errno = EINVAL;
+ return -1;
}
- nft_table_list_add_tail(table, table_list);
+ ctx->json = node;
+ if (nft_jansson_node_exist(node, "table"))
+ ret = nft_ruleset_parse_tables(ctx, err);
+ else if (nft_jansson_node_exist(node, "chain"))
+ ret = nft_ruleset_parse_chains(ctx, err);
+ else if (nft_jansson_node_exist(node, "set"))
+ ret = nft_ruleset_parse_sets(ctx, err);
+ else if (nft_jansson_node_exist(node, "rule"))
+ ret = nft_ruleset_parse_rules(ctx, err);
+ else if (nft_jansson_node_exist(node, "element"))
+ ret = nft_ruleset_parse_set_elems(ctx, err);
+ else
+ return -1;
+
+ if (ret < 0)
+ return ret;
}
- 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);
+ if (len == 0 && ctx->cmd == NFT_CMD_FLUSH) {
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE,
+ NFT_RULESET_RULESET);
+ if (ctx->cb(ctx) < 0)
+ return -1;
+ }
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,
- struct nft_parse_err *err)
+static int nft_ruleset_json_parse_cmd(const char *cmd,
+ struct nft_parse_err *err,
+ struct nft_parse_ctx *ctx)
{
- mxml_node_t *node;
- struct nft_chain *chain;
- struct nft_chain_list *chain_list = nft_chain_list_alloc();
- if (chain_list == NULL) {
- errno = ENOMEM;
+ uint32_t cmdnum;
+ json_t *nodecmd;
+
+ cmdnum = nft_str2cmd(cmd);
+ if (cmdnum == NFT_CMD_UNSPEC) {
+ err->error = NFT_PARSE_EMISSINGNODE;
+ err->node_name = strdup(cmd);
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)) {
- chain = nft_chain_alloc();
- if (chain == NULL)
- goto err_free;
-
- if (nft_mxml_chain_parse(node, chain, err) != 0) {
- nft_chain_free(chain);
- goto err_free;
- }
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_CMD, cmdnum);
- nft_chain_list_add_tail(chain, chain_list);
- }
+ nodecmd = json_object_get(ctx->json, cmd);
+ if (nodecmd == NULL)
+ return 0;
- 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);
+ ctx->json = nodecmd;
+ if (nft_ruleset_json_parse_ruleset(ctx, err) != 0)
+ goto err;
return 0;
-err_free:
- nft_chain_list_free(chain_list);
+err:
return -1;
}
+#endif
-static int
-nft_ruleset_xml_parse_sets(struct nft_ruleset *rs, mxml_node_t *tree,
- struct nft_parse_err *err)
+static int nft_ruleset_json_parse(const void *json,
+ struct nft_parse_err *err,
+ enum nft_parse_input input,
+ enum nft_parse_type type, void *arg,
+ int (*cb)(const struct nft_parse_ctx *ctx))
{
- uint32_t set_id = 0;
- mxml_node_t *node;
- struct nft_set *set;
- struct nft_set_list *set_list = nft_set_list_alloc();
- if (set_list == NULL) {
- errno = ENOMEM;
+#ifdef JSON_PARSING
+ json_t *root, *array, *node;
+ json_error_t error;
+ int i, len;
+ const char *key;
+ struct nft_parse_ctx ctx;
+
+ ctx.cb = cb;
+ ctx.format = type;
+
+ if (arg != NULL)
+ nft_ruleset_ctx_set(&ctx, NFT_RULESET_CTX_DATA, arg);
+
+ root = nft_jansson_create_root(json, &error, err, input);
+ if (root == NULL)
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)) {
- set = nft_set_alloc();
- if (set == NULL)
- goto err_free;
+ array = json_object_get(root, "nftables");
+ if (array == NULL) {
+ errno = EINVAL;
+ goto err;
+ }
- if (nft_mxml_set_parse(node, set, err) != 0) {
- nft_set_free(set);
- goto err_free;
+ len = json_array_size(array);
+ for (i = 0; i < len; i++) {
+ node = json_array_get(array, i);
+ if (node == NULL) {
+ errno = EINVAL;
+ goto err;
}
+ ctx.json = node;
+ key = json_object_iter_key(json_object_iter(node));
+ if (key == NULL)
+ goto err;
- nft_set_attr_set_u32(set, NFT_SET_ATTR_ID, set_id++);
- nft_set_list_add_tail(set, set_list);
+ if (nft_ruleset_json_parse_cmd(key, err, &ctx) < 0)
+ goto err;
}
- 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);
-
+ nft_jansson_free_root(root);
return 0;
-err_free:
- nft_set_list_free(set_list);
+err:
+ nft_jansson_free_root(root);
return -1;
+#else
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
}
-static int
-nft_ruleset_xml_parse_rules(struct nft_ruleset *rs, mxml_node_t *tree,
- struct nft_parse_err *err,
- struct nft_set_list *set_list)
+#ifdef XML_PARSING
+static int nft_ruleset_xml_parse_ruleset(struct nft_parse_ctx *ctx,
+ struct nft_parse_err *err)
{
- mxml_node_t *node;
- struct nft_rule *rule;
- struct nft_rule_list *rule_list = nft_rule_list_alloc();
- if (rule_list == NULL) {
- errno = ENOMEM;
+ const char *node_type;
+ mxml_node_t *node, *array = ctx->xml;
+ int len = 0, ret;
+
+ ctx->set_list = nft_set_list_alloc();
+ if (ctx->set_list == NULL)
return -1;
- }
- for (node = mxmlFindElement(tree, tree, "rule", NULL, NULL,
+ for (node = mxmlFindElement(array, array, NULL, NULL, NULL,
MXML_DESCEND_FIRST);
node != NULL;
- node = mxmlFindElement(node, tree, "rule", NULL, NULL,
+ node = mxmlFindElement(node, array, NULL, NULL, NULL,
MXML_NO_DESCEND)) {
- rule = nft_rule_alloc();
- if (rule == NULL)
- goto err_free;
+ len++;
+ node_type = node->value.opaque;
+ ctx->xml = node;
+ if (strcmp(node_type, "table") == 0)
+ ret = nft_ruleset_parse_tables(ctx, err);
+ else if (strcmp(node_type, "chain") == 0)
+ ret = nft_ruleset_parse_chains(ctx, err);
+ else if (strcmp(node_type, "set") == 0)
+ ret = nft_ruleset_parse_sets(ctx, err);
+ else if (strcmp(node_type, "rule") == 0)
+ ret = nft_ruleset_parse_rules(ctx, err);
+ else if (strcmp(node_type, "element") == 0)
+ ret = nft_ruleset_parse_set_elems(ctx, err);
+ else
+ return -1;
- if (nft_mxml_rule_parse(node, rule, err, set_list) != 0) {
- nft_rule_free(rule);
- goto err_free;
- }
-
- nft_rule_list_add_tail(rule, rule_list);
+ if (ret < 0)
+ return ret;
}
- 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);
+ if (len == 0 && ctx->cmd == NFT_CMD_FLUSH) {
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE,
+ NFT_RULESET_RULESET);
+ if (ctx->cb(ctx) < 0)
+ return -1;
+ }
return 0;
-err_free:
- nft_rule_list_free(rule_list);
- return -1;
}
-static int nft_ruleset_xml_parse_ruleset(struct nft_ruleset *rs,
- mxml_node_t *tree,
- struct nft_parse_err *err)
+static int nft_ruleset_xml_parse_cmd(const char *cmd, struct nft_parse_err *err,
+ struct nft_parse_ctx *ctx)
{
- if (nft_ruleset_xml_parse_tables(rs, tree, err) != 0)
- return -1;
+ uint32_t cmdnum;
+ mxml_node_t *nodecmd;
- if (nft_ruleset_xml_parse_chains(rs, tree, err) != 0)
+ cmdnum = nft_str2cmd(cmd);
+ if (cmdnum == NFT_CMD_UNSPEC) {
+ err->error = NFT_PARSE_EMISSINGNODE;
+ err->node_name = strdup(cmd);
return -1;
+ }
- if (nft_ruleset_xml_parse_sets(rs, tree, err) != 0)
- return -1;
+ nodecmd = mxmlFindElement(ctx->xml, ctx->xml, cmd, NULL, NULL,
+ MXML_DESCEND_FIRST);
- if (nft_ruleset_xml_parse_rules(rs, tree, err, rs->set_list) != 0)
- return -1;
+ ctx->xml = nodecmd;
+ nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_CMD, cmdnum);
+
+ if (nft_ruleset_xml_parse_ruleset(ctx, err) != 0)
+ goto err;
return 0;
+err:
+ return -1;
}
#endif
-static int nft_ruleset_xml_parse(struct nft_ruleset *rs, const void *xml,
- struct nft_parse_err *err, enum nft_parse_input input)
+static int nft_ruleset_xml_parse(const void *xml, struct nft_parse_err *err,
+ enum nft_parse_input input,
+ enum nft_parse_type type, void *arg,
+ int (*cb)(const struct nft_parse_ctx *ctx))
{
#ifdef XML_PARSING
- mxml_node_t *tree;
+ mxml_node_t *tree, *nodecmd = NULL;
+ char *cmd;
+ struct nft_parse_ctx ctx;
+
+ ctx.cb = cb;
+ ctx.format = type;
+
+ if (arg != NULL)
+ nft_ruleset_ctx_set(&ctx, NFT_RULESET_CTX_DATA, arg);
tree = nft_mxml_build_tree(xml, "nftables", err, input);
if (tree == NULL)
return -1;
- if (nft_ruleset_xml_parse_ruleset(rs, tree, err) != 0)
- goto err;
+ ctx.xml = tree;
+
+ nodecmd = mxmlWalkNext(tree, tree, MXML_DESCEND_FIRST);
+ while (nodecmd != NULL) {
+ cmd = nodecmd->value.opaque;
+ if (nft_ruleset_xml_parse_cmd(cmd, err, &ctx) < 0)
+ goto err;
+ nodecmd = mxmlWalkNext(tree, tree, MXML_NO_DESCEND);
+ }
mxmlDelete(tree);
return 0;
@@ -591,18 +682,18 @@ err:
}
static int
-nft_ruleset_do_parse(struct nft_ruleset *r, enum nft_parse_type type,
- const void *data, struct nft_parse_err *err,
- enum nft_parse_input input)
+nft_ruleset_do_parse(enum nft_parse_type type, const void *data,
+ struct nft_parse_err *err, enum nft_parse_input input,
+ void *arg, int (*cb)(const struct nft_parse_ctx *ctx))
{
int ret;
switch (type) {
case NFT_PARSE_XML:
- ret = nft_ruleset_xml_parse(r, data, err, input);
+ ret = nft_ruleset_xml_parse(data, err, input, type, arg, cb);
break;
case NFT_PARSE_JSON:
- ret = nft_ruleset_json_parse(r, data, err, input);
+ ret = nft_ruleset_json_parse(data, err, input, type, arg, cb);
break;
default:
ret = -1;
@@ -613,17 +704,95 @@ nft_ruleset_do_parse(struct nft_ruleset *r, enum nft_parse_type type,
return ret;
}
+int nft_ruleset_parse_file_cb(enum nft_parse_type type, FILE *fp,
+ struct nft_parse_err *err, void *data,
+ int (*cb)(const struct nft_parse_ctx *ctx))
+{
+ return nft_ruleset_do_parse(type, fp, err, NFT_PARSE_FILE, data, cb);
+}
+EXPORT_SYMBOL(nft_ruleset_parse_file_cb);
+
+int nft_ruleset_parse_buffer_cb(enum nft_parse_type type, const char *buffer,
+ struct nft_parse_err *err, void *data,
+ int (*cb)(const struct nft_parse_ctx *ctx))
+{
+ return nft_ruleset_do_parse(type, buffer, err, NFT_PARSE_BUFFER, data,
+ cb);
+}
+EXPORT_SYMBOL(nft_ruleset_parse_buffer_cb);
+
+static int nft_ruleset_cb(const struct nft_parse_ctx *ctx)
+{
+ struct nft_ruleset *r = ctx->data;
+
+ if (ctx->cmd != NFT_CMD_ADD)
+ return -1;
+
+ switch (ctx->type) {
+ case NFT_RULESET_TABLE:
+ if (r->table_list == NULL) {
+ r->table_list = nft_table_list_alloc();
+ if (r->table_list == NULL)
+ return -1;
+
+ nft_ruleset_attr_set(r, NFT_RULESET_ATTR_TABLELIST,
+ r->table_list);
+ }
+ nft_table_list_add_tail(ctx->table, r->table_list);
+ break;
+ case NFT_RULESET_CHAIN:
+ if (r->chain_list == NULL) {
+ r->chain_list = nft_chain_list_alloc();
+ if (r->chain_list == NULL)
+ return -1;
+
+ nft_ruleset_attr_set(r, NFT_RULESET_ATTR_CHAINLIST,
+ r->chain_list);
+ }
+ nft_chain_list_add_tail(ctx->chain, r->chain_list);
+ break;
+ case NFT_RULESET_SET:
+ if (r->set_list == NULL) {
+ r->set_list = nft_set_list_alloc();
+ if (r->set_list == NULL)
+ return -1;
+
+ nft_ruleset_attr_set(r, NFT_RULESET_ATTR_SETLIST,
+ r->set_list);
+ }
+ nft_set_list_add_tail(ctx->set, r->set_list);
+ break;
+ case NFT_RULESET_RULE:
+ if (r->rule_list == NULL) {
+ r->rule_list = nft_rule_list_alloc();
+ if (r->rule_list == NULL)
+ return -1;
+
+ nft_ruleset_attr_set(r, NFT_RULESET_ATTR_RULELIST,
+ r->rule_list);
+ }
+ nft_rule_list_add_tail(ctx->rule, r->rule_list);
+ break;
+ case NFT_RULESET_RULESET:
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
int nft_ruleset_parse(struct nft_ruleset *r, enum nft_parse_type type,
const char *data, struct nft_parse_err *err)
{
- return nft_ruleset_do_parse(r, type, data, err, NFT_PARSE_BUFFER);
+ return nft_ruleset_parse_buffer_cb(type, data, err, r, nft_ruleset_cb);
}
EXPORT_SYMBOL(nft_ruleset_parse);
int nft_ruleset_parse_file(struct nft_ruleset *rs, enum nft_parse_type type,
FILE *fp, struct nft_parse_err *err)
{
- return nft_ruleset_do_parse(rs, type, fp, err, NFT_PARSE_FILE);
+ return nft_ruleset_parse_file_cb(type, fp, err, rs, nft_ruleset_cb);
}
EXPORT_SYMBOL(nft_ruleset_parse_file);