From db84371beafd011e1f1cbe9688241c4dff1649f7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 10 May 2018 23:25:27 +0200 Subject: xtables: translate nft meta trace set 1 to -j TRACE nft meta expr enables the nfnetlink based trace infrastruvture, so prefer to use that rather than xt_TRACE. Signed-off-by: Florian Westphal --- 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 ed0d0ee9..eb2af851 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 6d04b1a4..d74eeb00 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 08cbdc86..64307375 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; -- cgit v1.2.3