summaryrefslogtreecommitdiffstats
path: root/iptables
diff options
context:
space:
mode:
Diffstat (limited to 'iptables')
-rw-r--r--iptables/nft-shared.c65
-rw-r--r--iptables/nft-shared.h5
-rw-r--r--iptables/nft.c25
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 {
@@ -63,6 +64,10 @@ struct nft_xt_ctx {
uint32_t key;
} meta;
struct {
+ uint32_t data[4];
+ uint32_t len, reg;
+ } immediate;
+ struct {
uint32_t mask[4];
uint32_t xor[4];
} bitwise;
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;