nft meta expr enables the nfnetlink based trace infrastruvture, so
prefer to use that rather than xt_TRACE.

Signed-off-by: Florian Westphal <[email protected]>
---
 iptables/nft-shared.c | 65 +++++++++++++++++++++++++++++++++++++++++--
 iptables/nft-shared.h |  5 ++++
 iptables/nft.c        | 25 +++++++++++++++++
 3 files changed, 93 insertions(+), 2 deletions(-)

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;
-- 
2.17.1

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

Reply via email to