Patchwork [libnftables,1/2] Add function for exporting rule to JSON format and Order the switch values in the right order

login
register
mail settings
Submitter Alvaro Neira
Date June 27, 2013, 7:56 p.m.
Message ID <20130627195618.13980.95963.stgit@Ph0enix>
Download mbox | patch
Permalink /patch/255193/
State Accepted
Headers show

Comments

Alvaro Neira - June 27, 2013, 7:56 p.m.
From: Álvaro Neira Ayuso <alvaroneay@gmail.com>

Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com>
---
 include/libnftables/rule.h |    1 +
 src/chain.c                |    8 +++--
 src/expr/bitwise.c         |   37 ++++++++++++++++++++++++-
 src/expr/byteorder.c       |   22 +++++++++++++++
 src/expr/cmp.c             |   25 ++++++++++++++++-
 src/expr/counter.c         |    7 +++--
 src/expr/ct.c              |    5 +++
 src/expr/data_reg.c        |   65 +++++++++++++++++++++++++++++++++++++++-----
 src/expr/exthdr.c          |   16 +++++++----
 src/expr/immediate.c       |   40 ++++++++++++++++++++++++++-
 src/expr/limit.c           |    4 +++
 src/expr/log.c             |    7 +++++
 src/expr/lookup.c          |   20 ++++++++++++--
 src/expr/match.c           |   18 +++++++++++-
 src/expr/meta.c            |   10 +++++--
 src/expr/nat.c             |   44 ++++++++++++++++++++++++++++--
 src/expr/payload.c         |   39 ++++++++++++++++++++++++--
 src/expr/target.c          |   19 ++++++++++++-
 src/internal.h             |    1 +
 src/rule.c                 |   52 ++++++++++++++++++++++++++++++++++-
 src/table.c                |    4 +--
 21 files changed, 402 insertions(+), 42 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira - June 29, 2013, 10:01 a.m.
Applied, thanks Alvaro.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/include/libnftables/rule.h b/include/libnftables/rule.h
index fb6e804..186c82c 100644
--- a/include/libnftables/rule.h
+++ b/include/libnftables/rule.h
@@ -44,6 +44,7 @@  void nft_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_rule *t);
 enum {
 	NFT_RULE_O_DEFAULT	= 0,
 	NFT_RULE_O_XML,
+	NFT_RULE_O_JSON,
 };
 
 enum nft_rule_parse_type {
diff --git a/src/chain.c b/src/chain.c
index bdcfec2..68744bc 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -794,12 +794,12 @@  int nft_chain_snprintf(char *buf, size_t size, struct nft_chain *c,
 		       uint32_t type, uint32_t flags)
 {
 	switch(type) {
-	case NFT_CHAIN_O_JSON:
-		return nft_chain_snprintf_json(buf, size, c);
-	case NFT_CHAIN_O_XML:
-		return nft_chain_snprintf_xml(buf, size, c);
 	case NFT_CHAIN_O_DEFAULT:
 		return nft_chain_snprintf_default(buf, size, c);
+	case NFT_CHAIN_O_XML:
+		return nft_chain_snprintf_xml(buf, size, c);
+	case NFT_CHAIN_O_JSON:
+		return nft_chain_snprintf_json(buf, size, c);
 	default:
 		break;
 	}
diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c
index 80c4f20..6843086 100644
--- a/src/expr/bitwise.c
+++ b/src/expr/bitwise.c
@@ -325,6 +325,37 @@  nft_rule_expr_bitwise_xml_parse(struct nft_rule_expr *e, char *xml)
 }
 
 static int
+nft_rule_expr_bitwise_snprintf_json(char *buf, size_t size,
+				   struct nft_expr_bitwise *bitwise)
+{
+	int len = size, offset = 0, ret;
+
+	ret = snprintf(buf, len, "\"sreg\" : %u, "
+				"\"dreg\" : %u, ",
+		       bitwise->sreg, bitwise->dreg);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, "\"mask\" : ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->mask,
+				    NFT_RULE_O_JSON, 0, DATA_VALUE);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, ", \"xor\" : ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->xor,
+				    NFT_RULE_O_JSON, 0, DATA_VALUE);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, "\"");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int
 nft_rule_expr_bitwise_snprintf_xml(char *buf, size_t size,
 				   struct nft_expr_bitwise *bitwise)
 {
@@ -389,11 +420,13 @@  nft_rule_expr_bitwise_snprintf(char *buf, size_t size, uint32_t type,
 	struct nft_expr_bitwise *bitwise = (struct nft_expr_bitwise *)e->data;
 
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_bitwise_snprintf_xml(buf, size, bitwise);
 	case NFT_RULE_O_DEFAULT:
 		return nft_rule_expr_bitwise_snprintf_default(buf, size,
 							      bitwise);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_bitwise_snprintf_xml(buf, size, bitwise);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_bitwise_snprintf_json(buf, size, bitwise);
 	default:
 		break;
 	}
diff --git a/src/expr/byteorder.c b/src/expr/byteorder.c
index b0ba009..bb47f10 100644
--- a/src/expr/byteorder.c
+++ b/src/expr/byteorder.c
@@ -298,6 +298,25 @@  err:
 }
 
 static int
+nft_rule_expr_byteorder_snprintf_json(char *buf, size_t size,
+				       struct nft_expr_byteorder *byteorder)
+{
+	int len = size, offset = 0, ret;
+
+	ret = snprintf(buf, len, "\"sreg\" : %u, "
+				 "\"dreg\" : %u, "
+				 "\"op\" : \"%s\", "
+				 "\"len\" : %u, "
+				 "\"size\" : %u",
+		       byteorder->sreg, byteorder->dreg,
+		       expr_byteorder_str[byteorder->op],
+		       byteorder->len, byteorder->size);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int
 nft_rule_expr_byteorder_snprintf_xml(char *buf, size_t size,
 				   struct nft_expr_byteorder *byteorder)
 {
@@ -344,6 +363,9 @@  nft_rule_expr_byteorder_snprintf(char *buf, size_t size, uint32_t type,
 	case NFT_RULE_O_XML:
 		return nft_rule_expr_byteorder_snprintf_xml(buf, size,
 							    byteorder);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_byteorder_snprintf_json(buf, size,
+							    byteorder);
 	default:
 		break;
 	}
diff --git a/src/expr/cmp.c b/src/expr/cmp.c
index 9507a0e..f92b3b6 100644
--- a/src/expr/cmp.c
+++ b/src/expr/cmp.c
@@ -265,6 +265,25 @@  static int nft_rule_expr_cmp_xml_parse(struct nft_rule_expr *e, char *xml)
 }
 
 static int
+nft_rule_expr_cmp_snprintf_json(char *buf, size_t size, struct nft_expr_cmp *cmp)
+{
+	int len = size, offset = 0, ret;
+
+	ret = snprintf(buf, len, "\"sreg\" : %u, \"op\" : \"%s\", \"cmpdata\" : {",
+		       cmp->sreg, expr_cmp_str[cmp->op]);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = nft_data_reg_snprintf(buf+offset, len, &cmp->data,
+				    NFT_RULE_O_JSON, 0, DATA_VALUE);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, "}");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int
 nft_rule_expr_cmp_snprintf_xml(char *buf, size_t size, struct nft_expr_cmp *cmp)
 {
 	int len = size, offset = 0, ret;
@@ -306,10 +325,12 @@  nft_rule_expr_cmp_snprintf(char *buf, size_t size, uint32_t type,
 {
 	struct nft_expr_cmp *cmp = (struct nft_expr_cmp *)e->data;
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_cmp_snprintf_xml(buf, size, cmp);
 	case NFT_RULE_O_DEFAULT:
 		return nft_rule_expr_cmp_snprintf_default(buf, size, cmp);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_cmp_snprintf_xml(buf, size, cmp);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_cmp_snprintf_json(buf, size, cmp);
 	default:
 		break;
 	}
diff --git a/src/expr/counter.c b/src/expr/counter.c
index 77054e2..62bd143 100644
--- a/src/expr/counter.c
+++ b/src/expr/counter.c
@@ -194,11 +194,14 @@  nft_rule_expr_counter_snprintf(char *buf, size_t len, uint32_t type,
 	struct nft_expr_counter *ctr = (struct nft_expr_counter *)e->data;
 
 	switch(type) {
+	case NFT_RULE_O_DEFAULT:
+		return snprintf(buf, len, "pkts=%lu bytes=%lu ",
+				ctr->pkts, ctr->bytes);
 	case NFT_RULE_O_XML:
 		return snprintf(buf, len, "<pkts>%lu</pkts><bytes>%lu</bytes>",
 				ctr->pkts, ctr->bytes);
-	case NFT_RULE_O_DEFAULT:
-		return snprintf(buf, len, "pkts=%lu bytes=%lu ",
+	case NFT_RULE_O_JSON:
+		return snprintf(buf, len, "\"pkts\" : %lu, \"bytes\" : %lu",
 				ctr->pkts, ctr->bytes);
 	default:
 		break;
diff --git a/src/expr/ct.c b/src/expr/ct.c
index e4ab3ed..fcdabce 100644
--- a/src/expr/ct.c
+++ b/src/expr/ct.c
@@ -279,6 +279,11 @@  nft_rule_expr_ct_snprintf(char *buf, size_t len, uint32_t type,
 					  "<key>%s</key>"
 					  "<dir>%u</dir>",
 				ct->dreg, ctkey2str(ct->key), ct->dir);
+	case NFT_RULE_O_JSON:
+		return snprintf(buf, len, "\"dreg\" : %u, "
+					  "\"key\" : \"%s\", "
+					  "\"dir\" : %u",
+				ct->dreg, ctkey2str(ct->key), ct->dir);
 	default:
 		break;
 	}
diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c
index c123d88..b8c9fe2 100644
--- a/src/expr/data_reg.c
+++ b/src/expr/data_reg.c
@@ -253,6 +253,44 @@  int nft_data_reg_xml_parse(union nft_data_reg *reg, char *xml)
 #endif
 }
 
+static int 
+nft_data_reg_value_snprintf_json(char *buf, size_t size,
+					   union nft_data_reg *reg,
+					   uint32_t flags)
+{
+	int len = size, offset = 0, ret, i, j;
+	uint32_t utemp;
+	uint8_t *tmp;
+	int data_len = reg->len/sizeof(uint32_t);
+
+	ret = snprintf(buf, len, "\"data_reg\": { \"type\" : \"value\", ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, "\"len\" : %zd, ", reg->len);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	for (i = 0; i<data_len; i++) {
+		ret = snprintf(buf+offset, len, "\"data%d\" : \"0x", i);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+		utemp = htonl(reg->val[i]);
+		tmp = (uint8_t *)&utemp;
+
+		for (j = 0; j<sizeof(uint32_t); j++) {
+			ret = snprintf(buf+offset, len, "%.02x", tmp[j]);
+			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		}
+
+		ret = snprintf(buf+offset, len, "\"");
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	ret = snprintf(buf+offset, len, "}");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
 static
 int nft_data_reg_value_snprintf_xml(char *buf, size_t size,
 				    union nft_data_reg *reg, uint32_t flags)
@@ -310,36 +348,49 @@  int nft_data_reg_snprintf(char *buf, size_t size, union nft_data_reg *reg,
 	switch(reg_type) {
 	case DATA_VALUE:
 		switch(output_format) {
-		case NFT_RULE_O_XML:
-			return nft_data_reg_value_snprintf_xml(buf, size,
-							       reg, flags);
 		case NFT_RULE_O_DEFAULT:
 			return nft_data_reg_value_snprintf_default(buf, size,
 								   reg, flags);
+		case NFT_RULE_O_XML:
+			return nft_data_reg_value_snprintf_xml(buf, size,
+							       reg, flags);
+		case NFT_RULE_O_JSON:
+			return nft_data_reg_value_snprintf_json(buf, size,
+							       reg, flags);
 		default:
 			break;
 		}
 	case DATA_VERDICT:
 		switch(output_format) {
+		case NFT_RULE_O_DEFAULT:
+			return snprintf(buf, size, "verdict=%d", reg->verdict);
 		case NFT_RULE_O_XML:
 			return snprintf(buf, size,
 					"<data_reg type=\"verdict\">"
 						"<verdict>%d</verdict>"
 					"</data_reg>", reg->verdict);
-		case NFT_RULE_O_DEFAULT:
-			return snprintf(buf, size, "verdict=%d", reg->verdict);
+		case NFT_RULE_O_JSON:
+			return snprintf(buf, size,
+					"\"data_reg\": { \"type\" : \"verdict\", "
+						"\"verdict\" : %d"
+					"}", reg->verdict);
 		default:
 			break;
 		}
 	case DATA_CHAIN:
 		switch(output_format) {
+		case NFT_RULE_O_DEFAULT:
+			return snprintf(buf, size, "chain=%s", reg->chain);
 		case NFT_RULE_O_XML:
 			return snprintf(buf, size,
 					"<data_reg type=\"chain\">"
 						"<chain>%s</chain>"
 					"</data_reg>", reg->chain);
-		case NFT_RULE_O_DEFAULT:
-			return snprintf(buf, size, "chain=%s", reg->chain);
+		case NFT_RULE_O_JSON:
+			return snprintf(buf, size,
+					"\"data_reg\": { \"type\" : \"chain\", "
+						"\"chain\" : %d"
+					"}", reg->verdict);
 		default:
 			break;
 		}
diff --git a/src/expr/exthdr.c b/src/expr/exthdr.c
index a31f079..b4b9c13 100644
--- a/src/expr/exthdr.c
+++ b/src/expr/exthdr.c
@@ -325,6 +325,10 @@  nft_rule_expr_exthdr_snprintf(char *buf, size_t len, uint32_t type,
 	struct nft_expr_exthdr *exthdr = (struct nft_expr_exthdr *)e->data;
 
 	switch(type) {
+	case NFT_RULE_O_DEFAULT:
+		return snprintf(buf, len, "dreg=%u type=%u offset=%u len=%u ",
+				exthdr->dreg, exthdr->type,
+				exthdr->offset, exthdr->len);
 	case NFT_RULE_O_XML:
 		return snprintf(buf, len, "<dreg>%u</dreg>"
 					  "<exthdr_type>%s</exthdr_type>"
@@ -333,11 +337,13 @@  nft_rule_expr_exthdr_snprintf(char *buf, size_t len, uint32_t type,
 					exthdr->dreg,
 					exthdr_type2str(exthdr->type),
 					exthdr->offset, exthdr->len);
-
-	case NFT_RULE_O_DEFAULT:
-		return snprintf(buf, len, "dreg=%u type=%u offset=%u len=%u ",
-				exthdr->dreg, exthdr->type,
-				exthdr->offset, exthdr->len);
+	case NFT_RULE_O_JSON:
+		return snprintf(buf, len, "\"dreg\" : %u, "
+					  "\"exthdr_type\" : \"%s\", \"offset\" : %u, "
+					  "\"len\" : %u",
+					exthdr->dreg,
+					exthdr_type2str(exthdr->type),
+					exthdr->offset, exthdr->len);
 	default:
 		break;
 	}
diff --git a/src/expr/immediate.c b/src/expr/immediate.c
index 8bc810c..1937d82 100644
--- a/src/expr/immediate.c
+++ b/src/expr/immediate.c
@@ -300,6 +300,40 @@  nft_rule_expr_immediate_xml_parse(struct nft_rule_expr *e, char *xml)
 }
 
 static int
+nft_rule_expr_immediate_snprintf_json(char *buf, size_t len,
+				     struct nft_rule_expr *e, uint32_t flags)
+{
+	int size = len, offset = 0, ret;
+	struct nft_expr_immediate *imm = (struct nft_expr_immediate *)e->data;
+
+	ret = snprintf(buf, len, "\"dreg\" : %u, "
+				"\"immediatedata\" : {", imm->dreg);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+
+	if (e->flags & (1 << NFT_EXPR_IMM_DATA)) {
+		ret = nft_data_reg_snprintf(buf+offset, len, &imm->data,
+					    NFT_RULE_O_JSON, flags, DATA_VALUE);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	} else if (e->flags & (1 << NFT_EXPR_IMM_VERDICT)) {
+		ret = nft_data_reg_snprintf(buf+offset, len, &imm->data,
+					  NFT_RULE_O_JSON, flags, DATA_VERDICT);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	} else if (e->flags & (1 << NFT_EXPR_IMM_CHAIN)) {
+		ret = nft_data_reg_snprintf(buf+offset, len, &imm->data,
+					    NFT_RULE_O_JSON, flags, DATA_CHAIN);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	ret = snprintf(buf+offset, len, "}");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int
 nft_rule_expr_immediate_snprintf_xml(char *buf, size_t len,
 				     struct nft_rule_expr *e, uint32_t flags)
 {
@@ -367,10 +401,12 @@  nft_rule_expr_immediate_snprintf(char *buf, size_t len, uint32_t type,
 				 uint32_t flags, struct nft_rule_expr *e)
 {
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_immediate_snprintf_xml(buf, len, e, flags);
 	case NFT_RULE_O_DEFAULT:
 		return nft_rule_expr_immediate_snprintf_default(buf, len, e, flags);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_immediate_snprintf_xml(buf, len, e, flags);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_immediate_snprintf_json(buf, len, e, flags);
 	default:
 		break;
 	}
diff --git a/src/expr/limit.c b/src/expr/limit.c
index d6dc900..1e843ce 100644
--- a/src/expr/limit.c
+++ b/src/expr/limit.c
@@ -195,6 +195,10 @@  nft_rule_expr_limit_snprintf(char *buf, size_t len, uint32_t type,
 		return snprintf(buf, len, "<rate>%"PRIu64"</rate>"
 					  "<depth>%"PRIu64"</depth>",
 				limit->rate, limit->depth);
+	case NFT_RULE_O_JSON:
+		return snprintf(buf, len, "\"rate\" : %"PRIu64", "
+					  "\"depth\" : %"PRIu64" ",
+				limit->rate, limit->depth);
 	default:
 		break;
 	}
diff --git a/src/expr/log.c b/src/expr/log.c
index 2d93b2a..8dc5201 100644
--- a/src/expr/log.c
+++ b/src/expr/log.c
@@ -263,6 +263,13 @@  nft_rule_expr_log_snprintf(char *buf, size_t len, uint32_t type,
 					  "<qthreshold>%u</qthreshold>",
 				log->prefix, log->group,
 				log->snaplen, log->qthreshold);
+	case NFT_RULE_O_JSON:
+		return snprintf(buf, len, "\"prefix\" : \"%s\", "
+					  "\"group\" : %u, "
+					  "\"snaplen\" : %u, "
+					  "\"qthreshold\" : %u ",
+				log->prefix, log->group,
+				log->snaplen, log->qthreshold);
 	default:
 		break;
 	}
diff --git a/src/expr/lookup.c b/src/expr/lookup.c
index ecc07cb..8591d4e 100644
--- a/src/expr/lookup.c
+++ b/src/expr/lookup.c
@@ -239,6 +239,20 @@  nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, char *xml)
 }
 
 static int
+nft_rule_expr_lookup_snprintf_json(char *buf, size_t size,
+				  struct nft_expr_lookup *l)
+{
+	int len = size, offset = 0, ret;
+
+	ret = snprintf(buf, len, "\"set\" : \"%s\", \"sreg\" : %u, \"dreg\" : %u",
+			l->set_name, l->sreg, l->dreg);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+
+static int
 nft_rule_expr_lookup_snprintf_xml(char *buf, size_t size,
 				  struct nft_expr_lookup *l)
 {
@@ -271,10 +285,12 @@  nft_rule_expr_lookup_snprintf(char *buf, size_t size, uint32_t type,
 	struct nft_expr_lookup *lookup = (struct nft_expr_lookup *)e->data;
 
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_lookup_snprintf_xml(buf, size, lookup);
 	case NFT_RULE_O_DEFAULT:
 		return nft_rule_expr_lookup_snprintf_default(buf, size, lookup);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_lookup_snprintf_xml(buf, size, lookup);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_lookup_snprintf_json(buf, size, lookup);
 	default:
 		break;
 	}
diff --git a/src/expr/match.c b/src/expr/match.c
index 7b4377f..7d0f078 100644
--- a/src/expr/match.c
+++ b/src/expr/match.c
@@ -226,6 +226,18 @@  static int nft_rule_expr_match_xml_parse(struct nft_rule_expr *e, char *xml)
 #endif
 }
 
+static int nft_rule_expr_match_snprintf_json(char *buf, size_t len,
+					    struct nft_expr_match *mt)
+{
+	int ret, size = len, offset = 0;
+
+	ret = snprintf(buf, len, "\"name\" : \"%s\"",
+				mt->name);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
 static int nft_rule_expr_match_snprintf_xml(char *buf, size_t len,
 					    struct nft_expr_match *mt)
 {
@@ -246,11 +258,13 @@  nft_rule_expr_match_snprintf(char *buf, size_t len, uint32_t type,
 	struct nft_expr_match *match = (struct nft_expr_match *)e->data;
 
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_match_snprintf_xml(buf, len, match);
 	case NFT_RULE_O_DEFAULT:
 		return snprintf(buf, len, "name=%s rev=%u ",
 				match->name, match->rev);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_match_snprintf_xml(buf, len, match);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_match_snprintf_json(buf, len, match);
 	default:
 		break;
 	}
diff --git a/src/expr/meta.c b/src/expr/meta.c
index d5d297b..1a609cf 100644
--- a/src/expr/meta.c
+++ b/src/expr/meta.c
@@ -246,13 +246,17 @@  nft_rule_expr_meta_snprintf(char *buf, size_t len, uint32_t type,
 	struct nft_expr_meta *meta = (struct nft_expr_meta *)e->data;
 
 	switch(type) {
+	case NFT_RULE_O_DEFAULT:
+		return snprintf(buf, len, "dreg=%u key=%u ",
+				meta->dreg, meta->key);
 	case NFT_RULE_O_XML:
 		return snprintf(buf, len, "<dreg>%u</dreg>"
 					  "<key>%s</key>",
 				meta->dreg, meta_key2str(meta->key));
-	case NFT_RULE_O_DEFAULT:
-		return snprintf(buf, len, "dreg=%u key=%u ",
-				meta->dreg, meta->key);
+	case NFT_RULE_O_JSON:
+		return snprintf(buf, len, "\"dreg\" : %u, "
+					  "\"key\" : %s",
+				meta->dreg, meta_key2str(meta->key));
 	default:
 		break;
 	}
diff --git a/src/expr/nat.c b/src/expr/nat.c
index 506c0b1..a1e6700 100644
--- a/src/expr/nat.c
+++ b/src/expr/nat.c
@@ -328,6 +328,44 @@  static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, char *xml)
 }
 
 static int
+nft_rule_expr_nat_snprintf_json(char *buf, size_t size,
+				struct nft_rule_expr *e)
+{
+	struct nft_expr_nat *nat = (struct nft_expr_nat *)e->data;
+	int len = size, offset = 0, ret = 0;
+
+	if (nat->type == NFT_NAT_SNAT)
+		ret = snprintf(buf, len, "\"nat_type\" : \"snat\", ");
+	else if (nat->type == NFT_NAT_DNAT)
+		ret = snprintf(buf, len, "\nat_type\" : \"dnat\", ");
+
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, "\"family\" : \"%s\", ",
+		       nft_family2str(nat->family));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN)) {
+		ret = snprintf(buf+offset, len, 
+				"\"sreg_addr_min\" : %u, "
+				"\"sreg_addr_max\" : %u, ",
+			       nat->sreg_addr_min, nat->sreg_addr_max);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN)) {
+		ret = snprintf(buf+offset, len, 
+				"\"sreg_proto_min\" : %u, "
+				"\"sreg_proto_max\" : %u",
+		       nat->sreg_proto_min, nat->sreg_proto_max);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	return offset;
+}
+
+
+static int
 nft_rule_expr_nat_snprintf_xml(char *buf, size_t size,
 				struct nft_rule_expr *e)
 {
@@ -410,10 +448,12 @@  nft_rule_expr_nat_snprintf(char *buf, size_t size, uint32_t type,
 			   uint32_t flags, struct nft_rule_expr *e)
 {
 	switch (type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_nat_snprintf_xml(buf, size, e);
 	case NFT_RULE_O_DEFAULT:
 		return nft_rule_expr_nat_snprintf_default(buf, size, e);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_nat_snprintf_xml(buf, size, e);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_nat_snprintf_json(buf, size, e);
 	default:
 		break;
 	}
diff --git a/src/expr/payload.c b/src/expr/payload.c
index ae72fa2..2111c47 100644
--- a/src/expr/payload.c
+++ b/src/expr/payload.c
@@ -167,6 +167,36 @@  nft_rule_expr_payload_parse(struct nft_rule_expr *e, struct nlattr *attr)
 }
 
 static int
+nft_rule_expr_payload_snprintf_json(char *buf, size_t len, uint32_t flags,
+				   struct nft_expr_payload *p)
+{
+	int size = len, offset = 0, ret;
+
+	ret = snprintf(buf, len, "\"dreg\" : %u, \"offset\" : %u, \"len\" : %u, ",
+					p->dreg, p->offset, p->len);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	switch (p->base) {
+	case NFT_PAYLOAD_LL_HEADER:
+		ret = snprintf(buf+offset, len, "\"base\" : \"link\"");
+		break;
+	case NFT_PAYLOAD_NETWORK_HEADER:
+		ret = snprintf(buf+offset, len, "\"base\" : \"network\"");
+		break;
+	case NFT_PAYLOAD_TRANSPORT_HEADER:
+		ret = snprintf(buf+offset, len, "\"base\" : \"transport\"");
+		break;
+	default:
+		ret = snprintf(buf+offset, len, "\"base\" : \"unknown\"");
+		break;
+	}
+
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int
 nft_rule_expr_payload_xml_parse(struct nft_rule_expr *e, char *xml)
 {
 #ifdef XML_PARSING
@@ -304,13 +334,16 @@  nft_rule_expr_payload_snprintf(char *buf, size_t len, uint32_t type,
 	struct nft_expr_payload *payload = (struct nft_expr_payload *)e->data;
 
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_expr_payload_snprintf_xml(buf, len, flags,
-							  payload);
 	case NFT_RULE_O_DEFAULT:
 		return snprintf(buf, len, "dreg=%u base=%u offset=%u len=%u ",
 				payload->dreg, payload->base,
 				payload->offset, payload->len);
+	case NFT_RULE_O_XML:
+		return nft_rule_expr_payload_snprintf_xml(buf, len, flags,
+							  payload);
+	case NFT_RULE_O_JSON:
+		return nft_rule_expr_payload_snprintf_json(buf, len, flags,
+							  payload);
 	default:
 		break;
 	}
diff --git a/src/expr/target.c b/src/expr/target.c
index ed29f6d..0ad39d5 100644
--- a/src/expr/target.c
+++ b/src/expr/target.c
@@ -228,6 +228,19 @@  nft_rule_expr_target_xml_parse(struct nft_rule_expr *e, char *xml)
 }
 
 static
+int nft_rule_exp_target_snprintf_json(char *buf, size_t len,
+				struct nft_expr_target *tg)
+{
+	int ret, size = len, offset = 0;
+
+	ret = snprintf(buf, len, "\"name\" : \"%s\"",
+			tg->name);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static
 int nft_rule_exp_target_snprintf_xml(char *buf, size_t len,
 				struct nft_expr_target *tg)
 {
@@ -247,11 +260,13 @@  nft_rule_expr_target_snprintf(char *buf, size_t len, uint32_t type,
 	struct nft_expr_target *target = (struct nft_expr_target *)e->data;
 
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_exp_target_snprintf_xml(buf, len, target);
 	case NFT_RULE_O_DEFAULT:
 		return snprintf(buf, len, "name=%s rev=%u ",
 				target->name, target->rev);
+	case NFT_RULE_O_XML:
+		return nft_rule_exp_target_snprintf_xml(buf, len, target);
+	case NFT_RULE_O_JSON:
+		return nft_rule_exp_target_snprintf_json(buf, len, target);
 	default:
 		break;
 	}
diff --git a/src/internal.h b/src/internal.h
index 23a3e59..55505be 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -22,6 +22,7 @@ 
 #define NFT_RULE_XML_VERSION 0
 #define NFT_TABLE_JSON_VERSION 0
 #define NFT_CHAIN_JSON_VERSION 0
+#define NFT_RULE_JSON_VERSION 0
 
 const char *nft_family2str(uint32_t family);
 int nft_str2family(const char *family);
diff --git a/src/rule.c b/src/rule.c
index e792169..ca6981d 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -668,6 +668,52 @@  int nft_rule_parse(struct nft_rule *r, enum nft_rule_parse_type type, char *data
 }
 EXPORT_SYMBOL(nft_rule_parse);
 
+static int nft_rule_snprintf_json(char *buf, size_t size, struct nft_rule *r,
+					 uint32_t type, uint32_t flags)
+{
+	int ret, len = size, offset = 0;
+	struct nft_rule_expr *expr;
+
+	ret = snprintf(buf, size,
+				"{ \"rule\": { \"family\" : \"%s\", \"table\" : \"%s\", "
+				"\"chain\"  : \"%s\", \"handle\" : %llu, \"version\" : %d, ",
+				nft_family2str(r->family), r->table, r->chain,
+				(unsigned long long)r->handle,
+				NFT_RULE_JSON_VERSION);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, "\"rule_flags\" : %u, ",
+					r->rule_flags);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	
+	if(NFT_RULE_ATTR_COMPAT_PROTO != 0 || NFT_RULE_ATTR_COMPAT_FLAGS != 0){
+		ret = snprintf(buf+offset,len,"\"compat_flags\" : %u, "
+									  "\"compat_proto\" : %u, ",
+					r->compat.flags, r->compat.proto);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	ret = snprintf(buf+offset, len, "\"expr\" : [");
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	list_for_each_entry(expr, &r->expr_list, head) {
+		ret = snprintf(buf+offset, len,
+				" { \"type\" : \"%s\", ", expr->ops->name);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+		ret = expr->ops->snprintf(buf+offset, len, type, flags, expr);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+		ret = snprintf(buf+offset, len, "},");
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	}
+	ret = snprintf(buf+offset-1, len, "]}}");
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
 static int nft_rule_snprintf_xml(char *buf, size_t size, struct nft_rule *r,
 				 uint32_t type, uint32_t flags)
 {
@@ -739,10 +785,12 @@  int nft_rule_snprintf(char *buf, size_t size, struct nft_rule *r,
 		       uint32_t type, uint32_t flags)
 {
 	switch(type) {
-	case NFT_RULE_O_XML:
-		return nft_rule_snprintf_xml(buf, size, r, type, flags);
 	case NFT_RULE_O_DEFAULT:
 		return nft_rule_snprintf_default(buf, size, r, type, flags);
+	case NFT_RULE_O_XML:
+		return nft_rule_snprintf_xml(buf, size, r, type, flags);
+	case NFT_RULE_O_JSON:
+		return nft_rule_snprintf_json(buf, size, r, type, flags);
 	default:
 		break;
 	}
diff --git a/src/table.c b/src/table.c
index dc0c2a1..982d101 100644
--- a/src/table.c
+++ b/src/table.c
@@ -367,12 +367,12 @@  int nft_table_snprintf(char *buf, size_t size, struct nft_table *t,
 		       uint32_t type, uint32_t flags)
 {
 	switch(type) {
+	case NFT_TABLE_O_DEFAULT:
+		return nft_table_snprintf_default(buf, size, t);
 	case NFT_TABLE_O_XML:
 		return nft_table_snprintf_xml(buf, size, t);
 	case NFT_TABLE_O_JSON:
 		return nft_table_snprintf_json(buf, size, t);
-	case NFT_TABLE_O_DEFAULT:
-		return nft_table_snprintf_default(buf, size, t);
 	default:
 		break;
 	}