From da015ff415f021294aed8668ddf212acb279cd68 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 22 Jun 2013 19:12:24 +0200 Subject: netlink: fix network address prefix eg. nft add rule filter output ip daddr 192.168.1.0/24 counter so far, this operation was only possible using sets. nft add rule filter output ip daddr \{ 192.168.1.0/24 \} counter While at it, move all binop postprocess code to a new function that contains this transformation and the existing bitmask to constant (as used by eg. ct state new,established). Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 24 +++++++++++++ src/netlink_delinearize.c | 85 +++++++++++++++++++++++++++++++++++------------ src/netlink_linearize.c | 24 +++++++++++-- 3 files changed, 109 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index d835281c..2a7bdb56 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -228,6 +228,28 @@ static void netlink_gen_verdict(const struct expr *expr, } } +static void netlink_gen_prefix(const struct expr *expr, + struct nft_data_linearize *data) +{ + uint32_t i, cidr, idx; + uint32_t mask; + + assert(expr->ops->type == EXPR_PREFIX); + + data->len = div_round_up(expr->prefix->len, BITS_PER_BYTE); + cidr = expr->prefix_len; + + for (i = 0; i < data->len; i+= 32) { + if (cidr - i >= 32) + mask = 0; + else + mask = (1 << cidr) - 1; + + idx = i / 32; + data->value[idx] = mask; + } +} + void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data) { switch (expr->ops->type) { @@ -237,6 +259,8 @@ void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data) return netlink_gen_concat_data(expr, data); case EXPR_VERDICT: return netlink_gen_verdict(expr, data); + case EXPR_PREFIX: + return netlink_gen_prefix(expr, data); default: BUG("invalid data expression type %s\n", expr->ops->name); } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index c24e105c..93489138 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -593,11 +593,73 @@ static void meta_match_postprocess(struct payload_ctx *ctx, } } +static int expr_value2cidr(struct expr *expr) +{ + int i, j, k = 0; + uint32_t data[4], bits; + uint32_t len = div_round_up(expr->len, BITS_PER_BYTE) / sizeof(uint32_t); + + assert(expr->ops->type == EXPR_VALUE); + + mpz_export_data(data, expr->value, expr->byteorder, len); + + for (i = len - 1; i >= 0; i--) { + j = 32; + bits = UINT32_MAX >> 1; + + if (data[i] == UINT32_MAX) + goto next; + + while (--j >= 0) { + if (data[i] == bits) + break; + + bits >>=1; + } +next: + k += j; + } + return k; +} + +static void relational_binop_postprocess(struct expr *expr) +{ + struct expr *binop = expr->left, *value = expr->right, *i; + unsigned long n; + + if (binop->op == OP_AND && expr->op == OP_NEQ && + expr->right->dtype->basetype->type == TYPE_BITMASK) { + expr_free(expr->right); + expr->right = list_expr_alloc(&binop->left->location); + n = 0; + while ((n = mpz_scan1(binop->right->value, n)) != ULONG_MAX) { + i = constant_expr_alloc(&binop->right->location, + binop->left->dtype, + binop->right->byteorder, + binop->right->len, NULL); + mpz_set_ui(i->value, 1); + mpz_lshift_ui(i->value, n); + compound_expr_add(expr->right, i); + n++; + } + expr->left = binop->left; + expr->op = OP_FLAGCMP; + } else if ((binop->left->dtype->type == TYPE_IPADDR || + binop->left->dtype->type == TYPE_IP6ADDR) && + binop->op == OP_AND) { + expr->left = expr_clone(binop->left); + expr->right = prefix_expr_alloc(&expr->location, + expr_clone(value), + expr_value2cidr(binop->right)); + expr_free(value); + expr_free(binop); + } +} + static void expr_postprocess(struct rule_pp_ctx *ctx, struct stmt *stmt, struct expr **exprp) { struct expr *expr = *exprp, *i; - unsigned long n; //pr_debug("%s len %u\n", expr->ops->name, expr->len); @@ -648,26 +710,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, meta_match_postprocess(&ctx->pctx, expr); break; case EXPR_BINOP: - if (expr->left->op != OP_AND || - expr->op != OP_NEQ || - expr->right->dtype->basetype->type != TYPE_BITMASK) - break; - - expr_free(expr->right); - expr->right = list_expr_alloc(&expr->left->left->location); - n = 0; - while ((n = mpz_scan1(expr->left->right->value, n)) != ULONG_MAX) { - i = constant_expr_alloc(&expr->left->right->location, - expr->left->left->dtype, - expr->left->right->byteorder, - expr->left->right->len, NULL); - mpz_set_ui(i->value, 1); - mpz_lshift_ui(i->value, n); - compound_expr_add(expr->right, i); - n++; - } - expr->left = expr->left->left; - expr->op = OP_FLAGCMP; + relational_binop_postprocess(expr); break; default: break; diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 044815a3..e507f912 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -184,18 +184,36 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx, { struct nft_rule_expr *nle; enum nft_registers sreg; - struct nft_data_linearize nld; + struct nft_data_linearize nld, zero = {}; + struct expr *right; assert(dreg == NFT_REG_VERDICT); sreg = get_register(ctx); netlink_gen_expr(ctx, expr->left, sreg); + if (expr->right->ops->type == EXPR_PREFIX) { + right = expr->right->prefix; + + netlink_gen_data(expr->right, &nld); + zero.len = nld.len; + + nle = alloc_nft_expr("bitwise"); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_SREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_DREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_LEN, nld.len); + nft_rule_expr_set(nle, NFT_EXPR_BITWISE_MASK, &nld.value, nld.len); + nft_rule_expr_set(nle, NFT_EXPR_BITWISE_XOR, &zero.value, zero.len); + nft_rule_add_expr(ctx->nlr, nle); + } else { + right = expr->right; + } + nle = alloc_nft_expr("cmp"); nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_SREG, sreg); nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_OP, - netlink_gen_cmp_op(expr->op)); - netlink_gen_data(expr->right, &nld); + netlink_gen_cmp_op(expr->op)); + netlink_gen_data(right, &nld); nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len); release_register(ctx); -- cgit v1.2.3