summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJeremy Sowden <jeremy@azazel.net>2020-01-19 22:57:09 +0000
committerPablo Neira Ayuso <pablo@netfilter.org>2020-01-28 20:16:02 +0100
commit694cf23999eea468dc3124f1269f333d47a75a5e (patch)
tree10f61ff69b87508a9a2e61bcf94b116bdd1f6a8c /src
parent21099e5e2dc0650e88ec7bbe6b3b3e56cb20bc65 (diff)
netlink: add support for handling shift expressions.
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>
Diffstat (limited to 'src')
-rw-r--r--src/netlink_delinearize.c87
-rw-r--r--src/netlink_linearize.c50
2 files changed, 120 insertions, 17 deletions
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 1d2b2aa4..7d9c7646 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -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,
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 92617964..b542aa3b 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -545,10 +545,37 @@ 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;
struct expr *left, *i;
@@ -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) {