* [nft] netlink: fix network address prefix
@ 2013-06-22 17:19 Pablo Neira Ayuso
0 siblings, 0 replies; only message in thread
From: Pablo Neira Ayuso @ 2013-06-22 17:19 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber, eric
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 <pablo@netfilter.org>
---
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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2013-06-22 17:19 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-22 17:19 [nft] netlink: fix network address prefix Pablo Neira Ayuso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).