diff mbox series

[xtables,2/3] xtables: translate nft meta trace set 1 to -j TRACE

Message ID 20180617211513.5203-2-fw@strlen.de
State Accepted
Delegated to: Pablo Neira
Headers show
Series [xtables,1/3] include: update kernel netfilter header files | expand

Commit Message

Florian Westphal June 17, 2018, 9:15 p.m. UTC
nft meta expr enables the nfnetlink based trace infrastruvture, so
prefer to use that rather than xt_TRACE.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 iptables/nft-shared.c | 65 +++++++++++++++++++++++++++++++++++++++++--
 iptables/nft-shared.h |  5 ++++
 iptables/nft.c        | 25 +++++++++++++++++
 3 files changed, 93 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index b89a3e7b9d31..c9eca9c46757 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -414,10 +414,54 @@  void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
 		*inv = false;
 }
 
+static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
+{
+	const struct nft_family_ops *ops;
+	struct xtables_target *target;
+	struct xt_entry_target *t;
+	unsigned int size;
+	const char *targname;
+
+	switch (ctx->meta.key) {
+	case NFT_META_NFTRACE:
+		if (ctx->immediate.data[0] == 0)
+			return;
+		targname = "TRACE";
+		break;
+	default:
+		return;
+	}
+
+	target = xtables_find_target(targname, XTF_TRY_LOAD);
+	if (target == NULL)
+		return;
+
+	size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
+
+	t = xtables_calloc(1, size);
+	t->u.target_size = size;
+	t->u.user.revision = target->revision;
+	strcpy(t->u.user.name, targname);
+
+	target->t = t;
+
+	ops = nft_family_ops_lookup(ctx->family);
+	ops->parse_target(target, nft_get_data(ctx));
+}
+
 void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
 {
-	ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
 	ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
+
+	if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) &&
+	    (ctx->flags & NFT_XT_CTX_IMMEDIATE) &&
+	     nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) {
+		ctx->flags &= ~NFT_XT_CTX_IMMEDIATE;
+		nft_meta_set_to_target(ctx);
+		return;
+	}
+
+	ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
 	ctx->flags |= NFT_XT_CTX_META;
 }
 
@@ -473,13 +517,30 @@  void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
 
 void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
 {
-	int verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT);
 	const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
 	struct nft_family_ops *ops;
 	const char *jumpto = NULL;
 	bool nft_goto = false;
 	void *data = nft_get_data(ctx);
+	int verdict;
+
+	if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
+		const void *imm_data;
+		uint32_t len;
+
+		imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len);
+
+		if (len > sizeof(ctx->immediate.data))
+			return;
+
+		memcpy(ctx->immediate.data, imm_data, len);
+		ctx->immediate.len = len;
+		ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG);
+		ctx->flags |= NFT_XT_CTX_IMMEDIATE;
+		return;
+	}
 
+	verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT);
 	/* Standard target? */
 	switch(verdict) {
 	case NF_ACCEPT:
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 0108b7f976c1..76f28d91a390 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -43,6 +43,7 @@  enum {
 	NFT_XT_CTX_PAYLOAD	= (1 << 0),
 	NFT_XT_CTX_META		= (1 << 1),
 	NFT_XT_CTX_BITWISE	= (1 << 2),
+	NFT_XT_CTX_IMMEDIATE	= (1 << 3),
 };
 
 struct nft_xt_ctx {
@@ -62,6 +63,10 @@  struct nft_xt_ctx {
 	struct {
 		uint32_t key;
 	} meta;
+	struct {
+		uint32_t data[4];
+		uint32_t len, reg;
+	} immediate;
 	struct {
 		uint32_t mask[4];
 		uint32_t xor[4];
diff --git a/iptables/nft.c b/iptables/nft.c
index 08cbdc86450c..64307375f99b 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -929,11 +929,36 @@  static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
 	return 0;
 }
 
+static int add_meta_nftrace(struct nftnl_rule *r)
+{
+	struct nftnl_expr *expr;
+
+	expr = nftnl_expr_alloc("immediate");
+	if (expr == NULL)
+		return -ENOMEM;
+
+	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
+	nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
+	nftnl_rule_add_expr(r, expr);
+
+	expr = nftnl_expr_alloc("meta");
+	if (expr == NULL)
+		return -ENOMEM;
+	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_NFTRACE);
+	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
+
+	nftnl_rule_add_expr(r, expr);
+	return 0;
+}
+
 int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
 {
 	struct nftnl_expr *expr;
 	int ret;
 
+	if (strcmp(t->u.user.name, "TRACE") == 0)
+		return add_meta_nftrace(r);
+
 	expr = nftnl_expr_alloc("target");
 	if (expr == NULL)
 		return -ENOMEM;