@@ -25,16 +25,14 @@ extern int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
/**
* struct payload_dep_ctx - payload protocol dependency tracking
*
- * @pbase: protocol base of last dependency match
* @icmp_type: extra info for icmp(6) decoding
- * @pdep: last dependency match
* @prev: previous statement
+ * @pdeps: last dependency match per protocol layer
*/
struct payload_dep_ctx {
- enum proto_bases pbase:8;
- uint8_t icmp_type;
- struct stmt *pdep;
- struct stmt *prev;
+ uint8_t icmp_type;
+ struct stmt *prev;
+ struct stmt *pdeps[PROTO_BASE_MAX + 1];
};
extern bool payload_is_known(const struct expr *expr);
@@ -49,7 +47,8 @@ extern bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
enum proto_bases base);
extern struct expr *payload_dependency_get(struct payload_dep_ctx *ctx,
enum proto_bases base);
-extern void payload_dependency_release(struct payload_dep_ctx *ctx);
+extern void payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base);
extern void payload_dependency_kill(struct payload_dep_ctx *ctx,
struct expr *expr, unsigned int family);
extern void exthdr_dependency_kill(struct payload_dep_ctx *ctx,
@@ -2119,11 +2119,12 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx,
relational_expr_pctx_update(&ctx->pctx, expr);
- if (ctx->pdctx.pbase < PROTO_BASE_TRANSPORT_HDR) {
+ if (base < PROTO_BASE_TRANSPORT_HDR) {
if (payload_dependency_exists(&ctx->pdctx, base) &&
meta_may_dependency_kill(&ctx->pdctx,
ctx->pctx.family, expr))
- payload_dependency_release(&ctx->pdctx);
+ payload_dependency_release(&ctx->pdctx, base);
+
if (left->flags & EXPR_F_PROTOCOL)
payload_dependency_store(&ctx->pdctx, ctx->stmt, base);
}
@@ -2653,7 +2654,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
if (stmt->reject.type == NFT_REJECT_TCP_RST &&
payload_dependency_exists(&rctx->pdctx,
PROTO_BASE_TRANSPORT_HDR))
- payload_dependency_release(&rctx->pdctx);
+ payload_dependency_release(&rctx->pdctx,
+ PROTO_BASE_TRANSPORT_HDR);
break;
case NFPROTO_IPV6:
stmt->reject.family = rctx->pctx.family;
@@ -2661,7 +2663,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
if (stmt->reject.type == NFT_REJECT_TCP_RST &&
payload_dependency_exists(&rctx->pdctx,
PROTO_BASE_TRANSPORT_HDR))
- payload_dependency_release(&rctx->pdctx);
+ payload_dependency_release(&rctx->pdctx,
+ PROTO_BASE_TRANSPORT_HDR);
break;
case NFPROTO_INET:
case NFPROTO_BRIDGE:
@@ -2695,7 +2698,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
}
if (payload_dependency_exists(&rctx->pdctx, PROTO_BASE_NETWORK_HDR))
- payload_dependency_release(&rctx->pdctx);
+ payload_dependency_release(&rctx->pdctx,
+ PROTO_BASE_NETWORK_HDR);
break;
default:
break;
@@ -610,8 +610,7 @@ void payload_dependency_store(struct payload_dep_ctx *ctx,
if (ignore_dep)
return;
- ctx->pdep = stmt;
- ctx->pbase = base + 1;
+ ctx->pdeps[base + 1] = stmt;
}
/**
@@ -626,9 +625,11 @@ void payload_dependency_store(struct payload_dep_ctx *ctx,
bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
enum proto_bases base)
{
- return ctx->pbase != PROTO_BASE_INVALID &&
- ctx->pdep != NULL &&
- (ctx->pbase == base || (base == PROTO_BASE_TRANSPORT_HDR && ctx->pbase == base + 1));
+ if (ctx->pdeps[base])
+ return true;
+
+ return base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR];
}
/**
@@ -642,25 +643,35 @@ bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
struct expr *payload_dependency_get(struct payload_dep_ctx *ctx,
enum proto_bases base)
{
- if (ctx->pbase == base)
- return ctx->pdep->expr;
+ if (ctx->pdeps[base])
+ return ctx->pdeps[base]->expr;
if (base == PROTO_BASE_TRANSPORT_HDR &&
- ctx->pbase == PROTO_BASE_INNER_HDR)
- return ctx->pdep->expr;
+ ctx->pdeps[PROTO_BASE_INNER_HDR])
+ return ctx->pdeps[PROTO_BASE_INNER_HDR]->expr;
return NULL;
}
-void payload_dependency_release(struct payload_dep_ctx *ctx)
+static void __payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
{
- list_del(&ctx->pdep->list);
- stmt_free(ctx->pdep);
+ list_del(&ctx->pdeps[base]->list);
+ stmt_free(ctx->pdeps[base]);
- ctx->pbase = PROTO_BASE_INVALID;
- if (ctx->pdep == ctx->prev)
+ if (ctx->pdeps[base] == ctx->prev)
ctx->prev = NULL;
- ctx->pdep = NULL;
+ ctx->pdeps[base] = NULL;
+}
+
+void payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ if (ctx->pdeps[base])
+ __payload_dependency_release(ctx, base);
+ else if (base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR])
+ __payload_dependency_release(ctx, PROTO_BASE_INNER_HDR);
}
static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t)
@@ -786,7 +797,7 @@ void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
{
if (payload_dependency_exists(ctx, expr->payload.base) &&
payload_may_dependency_kill(ctx, family, expr))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, expr->payload.base);
}
void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
@@ -795,15 +806,15 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
switch (expr->exthdr.op) {
case NFT_EXTHDR_OP_TCPOPT:
if (payload_dependency_exists(ctx, PROTO_BASE_TRANSPORT_HDR))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, PROTO_BASE_TRANSPORT_HDR);
break;
case NFT_EXTHDR_OP_IPV6:
if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR);
break;
case NFT_EXTHDR_OP_IPV4:
if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR);
break;
default:
break;