]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink: add support for handling shift expressions.
authorJeremy Sowden <jeremy@azazel.net>
Sun, 19 Jan 2020 22:57:09 +0000 (22:57 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 28 Jan 2020 19:16:02 +0000 (20:16 +0100)
The kernel supports bitwise shift operations, so add support to the
netlink linearization and delinearization code.  The number of bits (the
righthand operand) is expected to be a 32-bit value in host endianness.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/netlink_delinearize.c
src/netlink_linearize.c

index 1d2b2aa42989acf5a6b46525fc8bd0cb104ed9f1..7d9c764625c5195ca65a3c11f9e9f389e499062a 100644 (file)
@@ -363,22 +363,17 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
        ctx->stmt = expr_stmt_alloc(loc, expr);
 }
 
-static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
-                                 const struct location *loc,
-                                 const struct nftnl_expr *nle)
+static struct expr *netlink_parse_bitwise_bool(struct netlink_parse_ctx *ctx,
+                                              const struct location *loc,
+                                              const struct nftnl_expr *nle,
+                                              enum nft_registers sreg,
+                                              struct expr *left)
+
 {
        struct nft_data_delinearize nld;
-       enum nft_registers sreg, dreg;
-       struct expr *expr, *left, *mask, *xor, *or;
+       struct expr *expr, *mask, *xor, *or;
        mpz_t m, x, o;
 
-       sreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_SREG);
-       left = netlink_get_register(ctx, loc, sreg);
-       if (left == NULL)
-               return netlink_error(ctx, loc,
-                                    "Bitwise expression has no left "
-                                    "hand side");
-
        expr = left;
 
        nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_MASK, &nld.len);
@@ -430,6 +425,62 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
        mpz_clear(x);
        mpz_clear(o);
 
+       return expr;
+}
+
+static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx,
+                                               const struct location *loc,
+                                               const struct nftnl_expr *nle,
+                                               enum ops op,
+                                               enum nft_registers sreg,
+                                               struct expr *left)
+{
+       struct nft_data_delinearize nld;
+       struct expr *expr, *right;
+
+       nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_DATA, &nld.len);
+       right = netlink_alloc_value(loc, &nld);
+
+       expr = binop_expr_alloc(loc, op, left, right);
+       expr->len = left->len;
+
+       return expr;
+}
+
+static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
+                                 const struct location *loc,
+                                 const struct nftnl_expr *nle)
+{
+       enum nft_registers sreg, dreg;
+       struct expr *expr, *left;
+       enum nft_bitwise_ops op;
+
+       sreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_SREG);
+       left = netlink_get_register(ctx, loc, sreg);
+       if (left == NULL)
+               return netlink_error(ctx, loc,
+                                    "Bitwise expression has no left "
+                                    "hand side");
+
+       op = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_OP);
+
+       switch (op) {
+       case NFT_BITWISE_BOOL:
+               expr = netlink_parse_bitwise_bool(ctx, loc, nle, sreg,
+                                                 left);
+               break;
+       case NFT_BITWISE_LSHIFT:
+               expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_LSHIFT,
+                                                  sreg, left);
+               break;
+       case NFT_BITWISE_RSHIFT:
+               expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_RSHIFT,
+                                                  sreg, left);
+               break;
+       default:
+               BUG("invalid bitwise operation %u\n", op);
+       }
+
        dreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_DREG);
        netlink_set_register(ctx, dreg, expr);
 }
@@ -2100,8 +2151,16 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
                break;
        case EXPR_BINOP:
                expr_postprocess(ctx, &expr->left);
-               expr_set_type(expr->right, expr->left->dtype,
-                             expr->left->byteorder);
+               switch (expr->op) {
+               case OP_LSHIFT:
+               case OP_RSHIFT:
+                       expr_set_type(expr->right, &integer_type,
+                                     BYTEORDER_HOST_ENDIAN);
+                       break;
+               default:
+                       expr_set_type(expr->right, expr->left->dtype,
+                                     expr->left->byteorder);
+               }
                expr_postprocess(ctx, &expr->right);
 
                expr_set_type(expr, expr->left->dtype,
index 9261796491c923d3be58c688b4715edebbaa12b4..b542aa3be23ffec6a25c279dfae788b756fcbd56 100644 (file)
@@ -545,9 +545,36 @@ static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x)
        mpz_and(mask, mask, m);
 }
 
-static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
+static void netlink_gen_shift(struct netlink_linearize_ctx *ctx,
                              const struct expr *expr,
                              enum nft_registers dreg)
+{
+       enum nft_bitwise_ops op = expr->op == OP_LSHIFT ?
+               NFT_BITWISE_LSHIFT : NFT_BITWISE_RSHIFT;
+       unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+       struct nft_data_linearize nld;
+       struct nftnl_expr *nle;
+
+       netlink_gen_expr(ctx, expr->left, dreg);
+
+       nle = alloc_nft_expr("bitwise");
+       netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
+       netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, op);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+
+       netlink_gen_raw_data(expr->right->value, expr->right->byteorder,
+                            sizeof(uint32_t), &nld);
+
+       nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_DATA, nld.value,
+                      nld.len);
+
+       nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
+static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
+                               const struct expr *expr,
+                               enum nft_registers dreg)
 {
        struct nftnl_expr *nle;
        struct nft_data_linearize nld;
@@ -562,8 +589,9 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
        mpz_init(val);
        mpz_init(tmp);
 
-       binops[n++] = left = (void *)expr;
-       while (left->etype == EXPR_BINOP && left->left != NULL)
+       binops[n++] = left = (struct expr *) expr;
+       while (left->etype == EXPR_BINOP && left->left != NULL &&
+              (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR))
                binops[n++] = left = left->left;
        n--;
 
@@ -598,6 +626,7 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
        nle = alloc_nft_expr("bitwise");
        netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
        netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_BOOL);
        nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
 
        netlink_gen_raw_data(mask, expr->byteorder, len, &nld);
@@ -613,6 +642,21 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
        nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
+                             const struct expr *expr,
+                             enum nft_registers dreg)
+{
+       switch(expr->op) {
+       case OP_LSHIFT:
+       case OP_RSHIFT:
+               netlink_gen_shift(ctx, expr, dreg);
+               break;
+       default:
+               netlink_gen_bitwise(ctx, expr, dreg);
+               break;
+       }
+}
+
 static enum nft_byteorder_ops netlink_gen_unary_op(enum ops op)
 {
        switch (op) {