]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
payload: auto-remove simple icmp/icmpv6 dependency expressions
authorFlorian Westphal <fw@strlen.de>
Tue, 8 Dec 2020 22:51:59 +0000 (23:51 +0100)
committerFlorian Westphal <fw@strlen.de>
Wed, 9 Dec 2020 17:33:53 +0000 (18:33 +0100)
Instead of:
icmpv6 type packet-too-big icmpv6 mtu 1280
display just
icmpv6 mtu 1280

The dependency added for id/sequence is still kept, its handled
by a anon set instead to cover both the echo 'request' and 'reply' cases.

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

index 7bbb19b936a9cbe97b810c653244ee7d3e20ac06..8bc3fb9a8a5456a45180aa09d953525cae32f5d3 100644 (file)
@@ -26,11 +26,13 @@ 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
  */
 struct payload_dep_ctx {
-       enum proto_bases        pbase;
+       enum proto_bases        pbase:8;
+       uint8_t                 icmp_type;
        struct stmt             *pdep;
        struct stmt             *prev;
 };
index 9faddde6397431f5452454153c768a363b86b2fc..8b06c4c0985f524103493fdab8e901d3dd07854a 100644 (file)
@@ -1771,6 +1771,9 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
        enum proto_bases base = left->payload.base;
        bool stacked;
 
+       if (ctx->pdctx.icmp_type)
+               ctx->pctx.th_dep.icmp.type = ctx->pdctx.icmp_type;
+
        payload_expr_expand(&list, left, &ctx->pctx);
 
        list_for_each_entry(left, &list, list) {
index 7cfa530c06c60b75988263433fe10377b893242c..48529bcf5c5140f3a835064f69f81d4d7ccaed5d 100644 (file)
@@ -98,7 +98,7 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
        desc = proto_find_upper(base, proto);
 
        if (!desc) {
-               if (base == &proto_icmp) {
+               if (base == &proto_icmp || base == &proto_icmp6) {
                        /* proto 0 is ECHOREPLY, just pretend its ECHO.
                         * Not doing this would need an additional marker
                         * bit to tell when icmp.type was set.
@@ -554,6 +554,35 @@ void payload_dependency_reset(struct payload_dep_ctx *ctx)
        memset(ctx, 0, sizeof(*ctx));
 }
 
+static uint8_t icmp_get_type(const struct proto_desc *desc, uint8_t value)
+{
+       if (desc == &proto_icmp && value == 0)
+               return ICMP_ECHO;
+
+       return value;
+}
+
+static uint8_t icmp_get_dep_type(const struct proto_desc *desc, struct expr *right)
+{
+       if (right->etype == EXPR_VALUE && right->len == BITS_PER_BYTE)
+               return icmp_get_type(desc, mpz_get_uint8(right->value));
+
+       return 0;
+}
+
+static void payload_dependency_store_icmp_type(struct payload_dep_ctx *ctx)
+{
+       struct expr *dep = ctx->pdep->expr;
+       const struct proto_desc *desc;
+
+       if (dep->left->etype != EXPR_PAYLOAD)
+               return;
+
+       desc = dep->left->payload.desc;
+       if (desc == &proto_icmp || desc == &proto_icmp6)
+               ctx->icmp_type = icmp_get_dep_type(dep->left->payload.desc, dep->right);
+}
+
 /**
  * payload_dependency_store - store a possibly redundant protocol match
  *
@@ -566,6 +595,8 @@ void payload_dependency_store(struct payload_dep_ctx *ctx,
 {
        ctx->pbase = base + 1;
        ctx->pdep  = stmt;
+
+       payload_dependency_store_icmp_type(ctx);
 }
 
 /**
@@ -581,8 +612,8 @@ bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
                               enum proto_bases base)
 {
        return ctx->pbase != PROTO_BASE_INVALID &&
-              ctx->pbase == base &&
-              ctx->pdep != NULL;
+              ctx->pdep != NULL &&
+              (ctx->pbase == base || (base == PROTO_BASE_TRANSPORT_HDR && ctx->pbase == base + 1));
 }
 
 void payload_dependency_release(struct payload_dep_ctx *ctx)
@@ -649,6 +680,10 @@ 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);
+       else if (ctx->icmp_type && ctx->pdep) {
+               fprintf(stderr, "Did not kill \n");
+               payload_dependency_release(ctx);
+       }
 }
 
 void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
@@ -716,6 +751,11 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
                if (tmpl->offset != expr->payload.offset ||
                    tmpl->len    != expr->len)
                        continue;
+
+               if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
+                   ctx->th_dep.icmp.type != icmp_dep_to_type(tmpl->icmp_dep))
+                       continue;
+
                expr->dtype        = tmpl->dtype;
                expr->payload.desc = desc;
                expr->payload.tmpl = tmpl;
@@ -842,6 +882,10 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
                if (tmpl->offset != expr->payload.offset)
                        continue;
 
+               if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
+                    ctx->th_dep.icmp.type != icmp_dep_to_type(tmpl->icmp_dep))
+                       continue;
+
                if (tmpl->len <= expr->len) {
                        new = payload_expr_alloc(&expr->location, desc, i);
                        list_add_tail(&new->list, list);