]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
ruleset: add XML/JSON export
authorArturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Thu, 23 Jan 2014 17:42:34 +0000 (17:42 +0000)
committerPatrick McHardy <kaber@trash.net>
Thu, 23 Jan 2014 17:42:34 +0000 (17:42 +0000)
This patch adds the following operation:

 :~# nft export <xml|json>

The XML/JSON output is provided raw by libnftnl, thus without format.

In case of XML, you can give format with the `xmllint' tool from libxml2-tools:
 :~# nft list ruleset xml | xmllint --format -

In case of JSON, you can use `json_pp' from perl standar package:
 :~# nft list ruleset json | json_pp

A format field is added in struct cmd, and it will be reused in the import
operation.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
include/mnl.h
include/netlink.h
include/rule.h
src/evaluate.c
src/mnl.c
src/netlink.c
src/parser.y
src/rule.c
src/scanner.l

index a6306058e6cbbb63481d5c2218016e1dc9a43c9d..f4de27db9fc54d2101bc40067290786269c094ce 100644 (file)
@@ -65,4 +65,6 @@ int mnl_nft_setelem_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
                           unsigned int flags);
 int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls);
 
+struct nft_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
+                                        uint32_t family);
 #endif /* _NFTABLES_MNL_H_ */
index 3f8d465c869226b80e9d6b64323e941a351d22b6..84b24877fe53f2f17999319a63c3075c7fd8f6ac 100644 (file)
@@ -136,4 +136,7 @@ extern int netlink_batch_send(struct list_head *err_list);
 extern int netlink_io_error(struct netlink_ctx *ctx,
                            const struct location *loc, const char *fmt, ...);
 
+extern struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx,
+                                               const struct handle *h,
+                                               const struct location *loc);
 #endif /* NFTABLES_NETLINK_H */
index 30a4d12ccd4286370e2cfa5b55b88056460d01a9..47dd6ab9a85e2f697cb612eb2a7b939f02dc57e3 100644 (file)
@@ -205,6 +205,7 @@ extern void set_print(const struct set *set);
  * @CMD_LIST:          list container
  * @CMD_FLUSH:         flush container
  * @CMD_RENAME:                rename object
+ * @CMD_EXPORT:                export the ruleset in a given format
  */
 enum cmd_ops {
        CMD_INVALID,
@@ -215,6 +216,7 @@ enum cmd_ops {
        CMD_LIST,
        CMD_FLUSH,
        CMD_RENAME,
+       CMD_EXPORT,
 };
 
 /**
@@ -227,6 +229,7 @@ enum cmd_ops {
  * @CMD_OBJ_RULE:      rule
  * @CMD_OBJ_CHAIN:     chain
  * @CMD_OBJ_TABLE:     table
+ * @CMD_OBJ_RULESET:   ruleset
  */
 enum cmd_obj {
        CMD_OBJ_INVALID,
@@ -236,6 +239,7 @@ enum cmd_obj {
        CMD_OBJ_RULE,
        CMD_OBJ_CHAIN,
        CMD_OBJ_TABLE,
+       CMD_OBJ_RULESET,
 };
 
 /**
@@ -249,6 +253,7 @@ enum cmd_obj {
  * @seqnum:    sequence number to match netlink errors
  * @union:     object
  * @arg:       argument data
+ * @format:    info about the export/import format
  */
 struct cmd {
        struct list_head        list;
@@ -266,6 +271,7 @@ struct cmd {
                struct table    *table;
        };
        const void              *arg;
+       uint32_t                format;
 };
 
 extern struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
index cf30ed92ecb43f8d18f851c955cd52bf03875490..215a004af3354f00436a3688923d4773e8f3e42d 100644 (file)
@@ -1405,6 +1405,7 @@ static int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
        case CMD_LIST:
        case CMD_FLUSH:
        case CMD_RENAME:
+       case CMD_EXPORT:
                return 0;
        default:
                BUG("invalid command operation %u\n", cmd->op);
index 7ac1fc5788687aeb45732663ae0d74dd583899b0..3f092ed984e97154081e866f00ebfa2dbd33b293 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -9,6 +9,8 @@
  */
 
 #include <libmnl/libmnl.h>
+#include <libnftnl/common.h>
+#include <libnftnl/ruleset.h>
 #include <libnftnl/table.h>
 #include <libnftnl/chain.h>
 #include <libnftnl/rule.h>
@@ -645,7 +647,8 @@ mnl_nft_set_dump(struct mnl_socket *nf_sock, int family, const char *table)
 
        nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
                                      NLM_F_DUMP|NLM_F_ACK, seq);
-       nft_set_attr_set(s, NFT_SET_ATTR_TABLE, table);
+       if (table != NULL)
+               nft_set_attr_set(s, NFT_SET_ATTR_TABLE, table);
        nft_set_nlmsg_build_payload(nlh, s);
        nft_set_free(s);
 
@@ -733,3 +736,62 @@ int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls)
 
        return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_elem_cb, nls);
 }
+
+/*
+ * ruleset
+ */
+struct nft_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
+                                        uint32_t family)
+{
+       struct nft_ruleset *rs;
+       struct nft_table_list *t;
+       struct nft_chain_list *c;
+       struct nft_set_list *sl;
+       struct nft_set_list_iter *i;
+       struct nft_set *s;
+       struct nft_rule_list *r;
+       int ret = 0;
+
+       rs = nft_ruleset_alloc();
+       if (rs == NULL)
+               memory_allocation_error();
+
+       t = mnl_nft_table_dump(nf_sock, family);
+       if (t != NULL)
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST, t);
+
+       c = mnl_nft_chain_dump(nf_sock, family);
+       if (c != NULL)
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, c);
+
+       sl = mnl_nft_set_dump(nf_sock, family, NULL);
+       if (sl != NULL) {
+               i = nft_set_list_iter_create(sl);
+               s = nft_set_list_iter_next(i);
+               while (s != NULL) {
+                       ret = mnl_nft_setelem_get(nf_sock, s);
+                       if (ret != 0)
+                               goto out;
+
+                       s = nft_set_list_iter_next(i);
+               }
+               nft_set_list_iter_destroy(i);
+
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, sl);
+       }
+
+       r = mnl_nft_rule_dump(nf_sock, family);
+       if (r != NULL)
+               nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, r);
+
+       if (!(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_TABLELIST)) &&
+           !(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST)) &&
+           !(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_SETLIST)) &&
+           !(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST)))
+               goto out;
+
+       return rs;
+out:
+       nft_ruleset_free(rs);
+       return NULL;
+}
index 84be505ddb51708d3ad9dc7a2e4e23bd16abff81..98e7fc6c4caed06c7ae613a6362798705b126fad 100644 (file)
 #include <fcntl.h>
 #include <errno.h>
 #include <libmnl/libmnl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <libnftnl/table.h>
 #include <libnftnl/chain.h>
 #include <libnftnl/expr.h>
 #include <libnftnl/set.h>
 #include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter.h>
 
 #include <nftables.h>
 #include <netlink.h>
@@ -1050,3 +1053,17 @@ int netlink_batch_send(struct list_head *err_list)
 {
        return mnl_batch_talk(nf_sock, err_list);
 }
+
+struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx,
+                                        const struct handle *h,
+                                        const struct location *loc)
+{
+       struct nft_ruleset *rs;
+
+       rs = mnl_nft_ruleset_dump(nf_sock, h->family);
+       if (rs == NULL)
+               netlink_io_error(ctx, loc, "Could not receive ruleset: %s",
+                                strerror(errno));
+
+       return rs;
+}
index cd9ade147d8526e58b10c292f3fe3691870857ba..24f022a56d7b7e7383f879a3124677a3b211530e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <libnftnl/common.h>
 
 #include <rule.h>
 #include <statement.h>
@@ -176,6 +177,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token FLUSH                   "flush"
 %token RENAME                  "rename"
 %token DESCRIBE                        "describe"
+%token EXPORT                  "export"
 
 %token ACCEPT                  "accept"
 %token DROP                    "drop"
@@ -346,14 +348,17 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %token POSITION                        "position"
 
+%token XML                     "xml"
+%token JSON                    "json"
+
 %type <string>                 identifier string
 %destructor { xfree($$); }     identifier string
 
 %type <cmd>                    line
 %destructor { cmd_free($$); }  line
 
-%type <cmd>                    base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd
-%destructor { cmd_free($$); }  base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd
+%type <cmd>                    base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd
+%destructor { cmd_free($$); }  base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd
 
 %type <handle>                 table_spec tables_spec chain_spec chain_identifier ruleid_spec
 %destructor { handle_free(&$$); } table_spec tables_spec chain_spec chain_identifier ruleid_spec
@@ -476,6 +481,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %destructor { expr_free($$); } ct_expr
 %type <val>                    ct_key
 
+%type <val>                    export_format
+
 %%
 
 input                  :       /* empty */
@@ -544,6 +551,7 @@ base_cmd            :       /* empty */     add_cmd         { $$ = $1; }
                        |       LIST            list_cmd        { $$ = $2; }
                        |       FLUSH           flush_cmd       { $$ = $2; }
                        |       RENAME          rename_cmd      { $$ = $2; }
+                       |       EXPORT          export_cmd      { $$ = $2; }
                        |       DESCRIBE        primary_expr
                        {
                                expr_describe($2);
@@ -703,6 +711,14 @@ rename_cmd         :       CHAIN           chain_spec      identifier
                        }
                        ;
 
+export_cmd             :       export_format
+                       {
+                               struct handle h = { .family = NFPROTO_UNSPEC };
+                               $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_RULESET, &h, &@$, NULL);
+                               $$->format = $1;
+                       }
+                       ;
+
 table_block_alloc      :       /* empty */
                        {
                                $$ = table_alloc();
@@ -1914,4 +1930,7 @@ mh_hdr_field              :       NEXTHDR         { $$ = MHHDR_NEXTHDR; }
                        |       CHECKSUM        { $$ = MHHDR_CHECKSUM; }
                        ;
 
+export_format          :       XML             { $$ = NFT_OUTPUT_XML; }
+                       |       JSON            { $$ = NFT_OUTPUT_JSON; }
+                       ;
 %%
index b43ce107364c8ab9174250266f6455d5c9e7c507..38cd63cf1b5b5034bdc93f3578a64455fa08a804 100644 (file)
 #include <statement.h>
 #include <rule.h>
 #include <utils.h>
+#include <netlink.h>
 
+#include <libnftnl/common.h>
+#include <libnftnl/ruleset.h>
 #include <netinet/ip.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_arp.h>
@@ -592,6 +595,21 @@ static int do_list_sets(struct netlink_ctx *ctx, const struct location *loc,
        return 0;
 }
 
+static int do_command_export(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+       struct nft_ruleset *rs = netlink_dump_ruleset(ctx, &cmd->handle,
+                                                     &cmd->location);
+
+       if (rs == NULL)
+               return -1;
+
+       nft_ruleset_fprintf(stdout, rs, cmd->format, 0);
+       fprintf(stdout, "\n");
+
+       nft_ruleset_free(rs);
+       return 0;
+}
+
 static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
 {
        struct table *table = NULL;
@@ -744,6 +762,8 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
                return do_command_flush(ctx, cmd);
        case CMD_RENAME:
                return do_command_rename(ctx, cmd);
+       case CMD_EXPORT:
+               return do_command_export(ctx, cmd);
        default:
                BUG("invalid command object type %u\n", cmd->obj);
        }
index f133f237bbe284a54794c50b722b628cb9254572..47ab1e238291b752fab4dd3735b0594164298ff6 100644 (file)
@@ -255,6 +255,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "list"                 { return LIST; }
 "flush"                        { return FLUSH; }
 "rename"               { return RENAME; }
+"export"               { return EXPORT; }
 
 "position"             { return POSITION; }
 
@@ -411,6 +412,9 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "proto-src"            { return PROTO_SRC; }
 "proto-dst"            { return PROTO_DST; }
 
+"xml"                  { return XML; }
+"json"                 { return JSON; }
+
 {addrstring}           {
                                yylval->string = xstrdup(yytext);
                                return STRING;