]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: store more than one payload dependency
authorJeremy Sowden <jeremy@azazel.net>
Sat, 15 Jan 2022 18:27:07 +0000 (18:27 +0000)
committerFlorian Westphal <fw@strlen.de>
Sat, 15 Jan 2022 19:17:41 +0000 (20:17 +0100)
Change the payload-dependency context to store a dependency for every
protocol layer.  This allows us to eliminate more redundant protocol
expressions.

Signed-off-by: Florian Westphal <fw@strlen.de>
include/payload.h
src/netlink_delinearize.c
src/payload.c

index af6fa478270604b7802159edf5b28d572b45ae3c..378699283c0a1ce80947a8072b3dd8af4732b7a1 100644 (file)
@@ -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,
index 068d305b3943b6e743e30ef99c04335755155850..6619b4121a2c273d0ddc806558549c505d3a8feb 100644 (file)
@@ -2126,11 +2126,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);
                }
@@ -2660,7 +2661,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;
@@ -2668,7 +2670,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:
@@ -2702,7 +2705,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;
index accbe0ab6066822b6beec740e7015aed81239ae2..f433c38421a4ee3830e8388b07b8c0a5e3612cf4 100644 (file)
@@ -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;