From patchwork Sat Jun 22 17:19:40 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 253422 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 97DF42C037D for ; Sun, 23 Jun 2013 03:20:01 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751827Ab3FVRTu (ORCPT ); Sat, 22 Jun 2013 13:19:50 -0400 Received: from mail.us.es ([193.147.175.20]:41389 "EHLO mail.us.es" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751807Ab3FVRTt (ORCPT ); Sat, 22 Jun 2013 13:19:49 -0400 Received: (qmail 26964 invoked from network); 22 Jun 2013 19:19:46 +0200 Received: from unknown (HELO us.es) (192.168.2.13) by us.es with SMTP; 22 Jun 2013 19:19:46 +0200 Received: (qmail 17097 invoked by uid 507); 22 Jun 2013 17:19:46 -0000 X-Qmail-Scanner-Diagnostics: from 127.0.0.1 by antivirus3 (envelope-from , uid 501) with qmail-scanner-2.10 (clamdscan: 0.97.8/17396. spamassassin: 3.3.2. Clear:RC:1(127.0.0.1):SA:0(-97.8/7.5):. Processed in 1.935132 secs); 22 Jun 2013 17:19:46 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on antivirus3 X-Spam-Level: X-Spam-Status: No, score=-97.8 required=7.5 tests=BAYES_50,RCVD_IN_PBL, RCVD_IN_RP_RNBL,RDNS_DYNAMIC,USER_IN_WHITELIST autolearn=disabled version=3.3.2 X-Envelope-From: pablo@netfilter.org Received: from unknown (HELO antivirus3) (127.0.0.1) by us.es with SMTP; 22 Jun 2013 17:19:44 -0000 Received: from 192.168.1.13 (192.168.1.13) by antivirus3 (F-Secure/fsigk_smtp/410/antivirus3); Sat, 22 Jun 2013 19:19:44 +0200 (CEST) X-Virus-Status: clean(F-Secure/fsigk_smtp/410/antivirus3) Received: (qmail 1643 invoked from network); 22 Jun 2013 19:19:44 +0200 Received: from 114.233.78.188.dynamic.jazztel.es (HELO localhost.localdomain) (pneira@us.es@188.78.233.114) by us.es with SMTP; 22 Jun 2013 19:19:44 +0200 From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Cc: kaber@trash.net, eric@regit.org Subject: [nft] netlink: fix network address prefix Date: Sat, 22 Jun 2013 19:19:40 +0200 Message-Id: <1371921580-10866-1-git-send-email-pablo@netfilter.org> X-Mailer: git-send-email 1.7.10.4 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org 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 This patch requires the previous patch that converts nft to use libnftables. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 24 ++++++++++++++++++ src/netlink_delinearize.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ src/netlink_linearize.c | 28 ++++++++++++++++++--- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index d835281..2a7bdb5 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 c24e105..e150567 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -593,6 +593,57 @@ 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 expr_postprocess(struct rule_pp_ctx *ctx, + struct stmt *stmt, struct expr **exprp); + +static int prefix_postprocess(struct expr *expr) +{ + struct expr *binop = expr->left, *value = expr->right; + + 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); + return 1; + } + return 0; +} + static void expr_postprocess(struct rule_pp_ctx *ctx, struct stmt *stmt, struct expr **exprp) { @@ -635,6 +686,15 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, case EXPR_PAYLOAD: payload_match_postprocess(ctx, stmt, expr); return; + case EXPR_BINOP: + expr_postprocess(ctx, stmt, &expr->left); + expr_set_type(expr->right, expr->left->dtype, + expr->left->byteorder); + expr_postprocess(ctx, stmt, &expr->right); + + /* Network address + prefix case */ + prefix_postprocess(expr); + return; default: expr_postprocess(ctx, stmt, &expr->left); break; diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 044815a..326f80f 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -184,18 +184,38 @@ 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; + uint8_t op; 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; + op = netlink_gen_cmp_op(expr->op); + + 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; + op = netlink_gen_cmp_op(right->op); + } + 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); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_OP, op); + netlink_gen_data(right, &nld); nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len); release_register(ctx);