]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink_delinearize: postprocess binary ands in concatenations
authorFlorian Westphal <fw@strlen.de>
Tue, 14 Jun 2022 19:56:48 +0000 (21:56 +0200)
committerFlorian Westphal <fw@strlen.de>
Thu, 4 Aug 2022 23:46:39 +0000 (01:46 +0200)
Input:
update ether saddr . vlan id timeout 5s @macset
ether saddr . vlan id @macset

Before this patch, gets rendered as:
update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s }
@ll,48,48 . @ll,112,16 & 0xfff @macset

After this, listing will show:
update @macset { @ll,48,48 . vlan id timeout 5s }
@ll,48,48 . vlan id @macset

The @ll, ... is due to vlan description replacing the ethernet one,
so payload decode fails to take the concatenation apart (the ethernet
header payload info is matched vs. vlan template).

This will be adjusted by a followup patch.

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

index e8e0f68ae1a49a139cb3539b7c76190b92bcf6a9..71c888fa0b407d47e073ec92f460eb0c805c401d 100644 (file)
@@ -42,10 +42,16 @@ struct netlink_parse_ctx {
        struct netlink_ctx      *nlctx;
 };
 
+
+#define RULE_PP_IN_CONCATENATION       (1 << 0)
+
+#define RULE_PP_REMOVE_OP_AND          (RULE_PP_IN_CONCATENATION)
+
 struct rule_pp_ctx {
        struct proto_ctx        pctx;
        struct payload_dep_ctx  pdctx;
        struct stmt             *stmt;
+       unsigned int            flags;
 };
 
 extern const struct input_descriptor indesc_netlink;
index 3835b3e522b9b5ce9c3198c12a0e78f3adbeb8e9..42221f8ca52606be2a1ca371781133e12fe602b0 100644 (file)
@@ -2260,12 +2260,13 @@ static void binop_adjust(const struct expr *binop, struct expr *right,
        }
 }
 
-static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
-                             struct expr **expr_binop)
+static void __binop_postprocess(struct rule_pp_ctx *ctx,
+                               struct expr *expr,
+                               struct expr *left,
+                               struct expr *mask,
+                               struct expr **expr_binop)
 {
        struct expr *binop = *expr_binop;
-       struct expr *left = binop->left;
-       struct expr *mask = binop->right;
        unsigned int shift;
 
        assert(binop->etype == EXPR_BINOP);
@@ -2301,15 +2302,26 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
 
                assert(binop->left == left);
                *expr_binop = expr_get(left);
-               expr_free(binop);
 
                if (left->etype == EXPR_PAYLOAD)
                        payload_match_postprocess(ctx, expr, left);
                else if (left->etype == EXPR_EXTHDR && right)
                        expr_set_type(right, left->dtype, left->byteorder);
+
+               expr_free(binop);
        }
 }
 
+static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
+                             struct expr **expr_binop)
+{
+       struct expr *binop = *expr_binop;
+       struct expr *left = binop->left;
+       struct expr *mask = binop->right;
+
+       __binop_postprocess(ctx, expr, left, mask, expr_binop);
+}
+
 static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
 {
        struct expr *binop = expr->map;
@@ -2542,6 +2554,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
                LIST_HEAD(tmp);
                struct expr *n;
 
+               ctx->flags |= RULE_PP_IN_CONCATENATION;
                list_for_each_entry_safe(i, n, &expr->expressions, list) {
                        if (type) {
                                dtype = concat_subtype_lookup(type, --off);
@@ -2553,6 +2566,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
 
                        ntype = concat_subtype_add(ntype, i->dtype->type);
                }
+               ctx->flags &= ~RULE_PP_IN_CONCATENATION;
                list_splice(&tmp, &expr->expressions);
                datatype_set(expr, concat_type_alloc(ntype));
                break;
@@ -2569,6 +2583,27 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
                        expr_set_type(expr->right, &integer_type,
                                      BYTEORDER_HOST_ENDIAN);
                        break;
+               case OP_AND:
+                       expr_set_type(expr->right, expr->left->dtype,
+                                     expr->left->byteorder);
+
+                       /* Do not process OP_AND in ordinary rule context.
+                        *
+                        * Removal needs to be performed as part of the relational
+                        * operation because the RHS constant might need to be adjusted
+                        * (shifted).
+                        *
+                        * This is different in set element context or concatenations:
+                        * There is no relational operation (eq, neq and so on), thus
+                        * it needs to be processed right away.
+                        */
+                       if ((ctx->flags & RULE_PP_REMOVE_OP_AND) &&
+                           expr->left->etype == EXPR_PAYLOAD &&
+                           expr->right->etype == EXPR_VALUE) {
+                               __binop_postprocess(ctx, expr, expr->left, expr->right, exprp);
+                               return;
+                       }
+                       break;
                default:
                        expr_set_type(expr->right, expr->left->dtype,
                                      expr->left->byteorder);