[nft PATCH] src: add support for listing the entire ruleset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch add the following operation:

 :~# nft list ruleset [xml|json]

With this, you can backup your current ruleset in 3 formats:
 * nft standar/default
 * xml
 * json

The XML/JSON output is provided raw by libnftables, 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

Exporting your ruleset gives the possibility of a later import. In default
nft format, the workflow is as follow:

 :~# nft list ruleset > ruleset.nft
 :~# nft -f ruleset.nft

In XML/JSON format, the import operation is currently under development.

About this implementation:

By now, `struct netlink_ctx' can't handle a complete ruleset, so the ruleset
listing operation is done as follow.

if XML/JSON:
 * Obtain the ruleset from the kernel, 4 queries (one per object type),
   using NFPROTO_UNSPEC. Note that this requires sets to be fetched with
   NFPROTO_UNSPECT. This is an incoming kernel patch.
 * Call libnftables's nft_ruleset_fprintf() directly.

if default nft format:
 * Obtain tables from kernel, using NFPROTO_UNSPEC (one netlink query).
 * Iterate these obtained tables calling recursively do_command_list(). This is
   done by filling a temporal netlink_ctx, and using it as an index.
 * Proceed normally as when listing one single table (several netlink queries).

I would prefer to have just one path to print the ruleset, but I can't avoid
modifying netlink_ctx, and seems a major change to me.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx>
---
 include/linux/netfilter.h |    2 ++
 include/mnl.h             |    1 +
 include/netlink.h         |    5 +++++
 include/rule.h            |    1 +
 src/mnl.c                 |   40 +++++++++++++++++++++++++++++++++++++++-
 src/netlink.c             |   12 +++++++++++-
 src/parser.y              |   37 +++++++++++++++++++++++++++++++++++--
 src/rule.c                |   45 +++++++++++++++++++++++++++++++++++++++++++++
 src/scanner.l             |    4 ++++
 9 files changed, 143 insertions(+), 4 deletions(-)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 2eb00b6..b4c84b1 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_NETFILTER_H
 #define __LINUX_NETFILTER_H
 
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <linux/types.h>
 
 
diff --git a/include/mnl.h b/include/mnl.h
index fe2fb40..34d9cb2 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -65,4 +65,5 @@ 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_ruleset_dump(struct mnl_socket *nf_sock, uint32_t family);
 #endif /* _NFTABLES_MNL_H_ */
diff --git a/include/netlink.h b/include/netlink.h
index 85e8434..3dd6c4f 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -1,6 +1,10 @@
 #ifndef NFTABLES_NETLINK_H
 #define NFTABLES_NETLINK_H
 
+#include <stdint.h>
+
+#include <libnftables/common.h>
+#include <libnftables/ruleset.h>
 #include <libnftables/table.h>
 #include <libnftables/chain.h>
 #include <libnftables/rule.h>
@@ -136,4 +140,5 @@ 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(void);
 #endif /* NFTABLES_NETLINK_H */
diff --git a/include/rule.h b/include/rule.h
index 6ad8af3..28b45ce 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -234,6 +234,7 @@ enum cmd_obj {
 	CMD_OBJ_RULE,
 	CMD_OBJ_CHAIN,
 	CMD_OBJ_TABLE,
+	CMD_OBJ_RULESET,
 };
 
 /**
diff --git a/src/mnl.c b/src/mnl.c
index a711b5e..e1310c5 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -9,6 +9,8 @@
  */
 
 #include <libmnl/libmnl.h>
+#include <libnftables/common.h>
+#include <libnftables/ruleset.h>
 #include <libnftables/table.h>
 #include <libnftables/chain.h>
 #include <libnftables/rule.h>
@@ -643,7 +645,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);
 
@@ -731,3 +734,38 @@ 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_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 *s;
+	struct nft_rule_list *r;
+
+	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);
+
+	s = mnl_nft_set_dump(nf_sock, family, NULL);
+	if (s != NULL)
+		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, s);
+
+	r = mnl_nft_rule_dump(nf_sock, family);
+	if (r != NULL)
+		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, r);
+
+	return rs;
+}
diff --git a/src/netlink.c b/src/netlink.c
index 59bd8e4..c73d362 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -19,7 +19,7 @@
 #include <libnftables/expr.h>
 #include <libnftables/set.h>
 #include <linux/netfilter/nf_tables.h>
-
+#include <linux/netfilter.h>
 #include <nftables.h>
 #include <netlink.h>
 #include <mnl.h>
@@ -1048,3 +1048,13 @@ int netlink_batch_send(struct list_head *err_list)
 {
 	return mnl_batch_talk(nf_sock, err_list);
 }
+
+struct nft_ruleset *netlink_dump_ruleset(void)
+{
+	struct nft_ruleset *rs = nft_ruleset_alloc();
+
+	if (rs == NULL)
+		memory_allocation_error();
+
+	return mnl_ruleset_dump(nf_sock, NFPROTO_UNSPEC);
+}
diff --git a/src/parser.y b/src/parser.y
index 26e71e3..2628cde 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -18,6 +18,8 @@
 #include <linux/netfilter/nf_tables.h>
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 
+#include <libnftables/common.h>
+
 #include <rule.h>
 #include <statement.h>
 #include <expression.h>
@@ -158,6 +160,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token HOOK			"hook"
 %token TABLE			"table"
 %token TABLES			"tables"
+%token RULESET			"ruleset"
 %token CHAIN			"chain"
 %token RULE			"rule"
 %token SETS			"sets"
@@ -332,6 +335,9 @@ 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
 
@@ -341,8 +347,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <cmd>			base_cmd add_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd
 %destructor { cmd_free($$); }	base_cmd add_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_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
+%type <handle>			table_spec tables_spec ruleset_spec chain_spec chain_identifier ruleid_spec
+%destructor { handle_free(&$$); } table_spec tables_spec ruleset_spec chain_spec chain_identifier ruleid_spec
 %type <handle>			set_spec set_identifier
 %destructor { handle_free(&$$); } set_spec set_identifier
 %type <val>			handle_spec family_spec position_spec
@@ -457,6 +463,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 */
@@ -623,6 +631,10 @@ list_cmd		:	TABLE		table_spec
 			{
 				$$ = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &$2, &@$, NULL);
 			}
+			|	RULESET		ruleset_spec	export_format
+			{
+				$$ = cmd_alloc(CMD_LIST, CMD_OBJ_RULESET, &$2, &@$, &$3);
+			}
 			|	CHAIN		chain_spec
 			{
 				$$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &$2, &@$, NULL);
@@ -838,6 +850,14 @@ tables_spec		:	family_spec
 			}
 			;
 
+ruleset_spec		:
+			{
+				memset(&$$, 0, sizeof($$));
+				$$.family	= NFPROTO_UNSPEC;
+				$$.table	= NULL;
+			}
+			;
+
 chain_spec		:	table_spec	identifier
 			{
 				$$		= $1;
@@ -1751,4 +1771,17 @@ mh_hdr_field		:	NEXTHDR		{ $$ = MHHDR_NEXTHDR; }
 			|	CHECKSUM	{ $$ = MHHDR_CHECKSUM; }
 			;
 
+export_format		: /* default */
+			{
+				$$ = 0;
+			}
+			| XML
+			{
+				$$ = NFT_OUTPUT_XML;
+			}
+			| JSON
+			{
+				$$ = NFT_OUTPUT_JSON;
+			}
+			;
 %%
diff --git a/src/rule.c b/src/rule.c
index ec8b6a4..e141dc2 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -18,6 +18,10 @@
 #include <statement.h>
 #include <rule.h>
 #include <utils.h>
+#include <netlink.h>
+
+#include <libnftables/common.h>
+#include <libnftables/ruleset.h>
 
 #include <netinet/ip.h>
 #include <linux/netfilter.h>
@@ -441,6 +445,8 @@ void cmd_free(struct cmd *cmd)
 		case CMD_OBJ_TABLE:
 			table_free(cmd->table);
 			break;
+		case CMD_OBJ_RULESET:
+			break;
 		default:
 			BUG("invalid command object type %u\n", cmd->obj);
 		}
@@ -577,12 +583,28 @@ static int do_list_sets(struct netlink_ctx *ctx, const struct location *loc,
 	return 0;
 }
 
+static int do_list_formatted_ruleset(uint32_t format)
+{
+	struct nft_ruleset *rs = netlink_dump_ruleset();
+
+	if (rs == NULL)
+		return -1;
+
+	nft_ruleset_fprintf(stdout, rs, 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;
 	struct chain *chain, *nchain;
 	struct rule *rule, *nrule;
 	struct set *set, *nset;
+	struct netlink_ctx ctx_index;
+	uint32_t format;
 
 	/* No need to allocate the table object when listing all tables */
 	if (cmd->handle.table != NULL) {
@@ -595,6 +617,29 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
 	}
 
 	switch (cmd->obj) {
+	case CMD_OBJ_RULESET:
+		format = *(uint32_t *)cmd->data;
+		if (format != 0)
+			return do_list_formatted_ruleset(format);
+
+		if (netlink_list_tables(ctx, &cmd->handle, &cmd->location) < 0)
+			return -1;
+
+		init_list_head(&ctx_index.list);
+		ctx_index.msgs = ctx->msgs;
+		ctx_index.seqnum = cmd->seqnum;
+
+		cmd->obj = CMD_OBJ_TABLE;
+
+		list_for_each_entry(table, &ctx->list, list) {
+			cmd->handle.family = table->handle.family;
+			cmd->handle.table = table->handle.table;
+			if (do_command_list(&ctx_index, cmd) != 0)
+				return -1;
+		}
+
+		cmd->obj = CMD_OBJ_RULESET;
+		return 0;
 	case CMD_OBJ_TABLE:
 		if (!cmd->handle.table) {
 			/* List all existing tables */
diff --git a/src/scanner.l b/src/scanner.l
index cee6aa6..c9e9478 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -220,6 +220,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "hook"			{ return HOOK; }
 "table"			{ return TABLE; }
 "tables"		{ return TABLES; }
+"ruleset"		{ return RULESET; }
 "chain"			{ return CHAIN; }
 "rule"			{ return RULE; }
 "sets"			{ return SETS; }
@@ -386,6 +387,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;

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux