* [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup
@ 2016-06-01 15:23 Arturo Borrero Gonzalez
2016-06-22 18:22 ` Pablo Neira Ayuso
2016-06-23 10:08 ` Pablo Neira Ayuso
0 siblings, 2 replies; 5+ messages in thread
From: Arturo Borrero Gonzalez @ 2016-06-01 15:23 UTC (permalink / raw)
To: netfilter-devel
Introduce a new configuration option for this expression, which allows users
to invert the logic of set lookups.
In _init() we will now return EINVAL if NFT_LOOKUP_F_INV is anyway
related to a map lookup.
The code in the _eval() function has been untangled and updated to sopport the
XOR of options, as we should consider 4 cases:
* lookup false, invert false -> NFT_BREAK
* lookup false, invert true -> return w/o NFT_BREAK
* lookup true, invert false -> return w/o NFT_BREAK
* lookup true, invert true -> NFT_BREAK
I decided to be extra defensive and check again in the _eval() path for an
invalid combination of the invert flag, in order to avoid the potential
disaster of copying registers uncontrollably.
Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
v2: better aling memory of struct nft_lookup, put 'bool invert' before bindings
v3: include flags coherence validation
v4: stronger validation in _init(), stronger validation in _eval(), also untangle
code, and update patch description
include/uapi/linux/netfilter/nf_tables.h | 6 +++++
net/netfilter/nft_lookup.c | 36 ++++++++++++++++++++++++++----
2 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 6a4dbe0..01751fa 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -546,6 +546,10 @@ enum nft_cmp_attributes {
};
#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
+enum nft_lookup_flags {
+ NFT_LOOKUP_F_INV = (1 << 0),
+};
+
/**
* enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes
*
@@ -553,6 +557,7 @@ enum nft_cmp_attributes {
* @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
* @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
* @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
+ * @NFTA_LOOKUP_FLAGS: flags (NLA_U32: enum nft_lookup_flags)
*/
enum nft_lookup_attributes {
NFTA_LOOKUP_UNSPEC,
@@ -560,6 +565,7 @@ enum nft_lookup_attributes {
NFTA_LOOKUP_SREG,
NFTA_LOOKUP_DREG,
NFTA_LOOKUP_SET_ID,
+ NFTA_LOOKUP_FLAGS,
__NFTA_LOOKUP_MAX
};
#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
index b3c31ef..e87e960 100644
--- a/net/netfilter/nft_lookup.c
+++ b/net/netfilter/nft_lookup.c
@@ -22,6 +22,7 @@ struct nft_lookup {
struct nft_set *set;
enum nft_registers sreg:8;
enum nft_registers dreg:8;
+ bool invert;
struct nft_set_binding binding;
};
@@ -32,14 +33,19 @@ static void nft_lookup_eval(const struct nft_expr *expr,
const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set;
const struct nft_set_ext *ext;
+ bool found;
- if (set->ops->lookup(set, ®s->data[priv->sreg], &ext)) {
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(®s->data[priv->dreg],
- nft_set_ext_data(ext), set->dlen);
+ found = set->ops->lookup(set, ®s->data[priv->sreg], &ext);
+
+ if (!(found ^ priv->invert)) {
+ regs->verdict.code = NFT_BREAK;
return;
}
- regs->verdict.code = NFT_BREAK;
+
+ if (set->flags & NFT_SET_MAP && found && !priv->invert)
+ nft_data_copy(®s->data[priv->dreg],
+ nft_set_ext_data(ext), set->dlen);
+
}
static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
@@ -47,6 +53,7 @@ static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
[NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 },
[NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
[NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
+ [NFTA_LOOKUP_FLAGS] = { .type = NLA_U32 },
};
static int nft_lookup_init(const struct nft_ctx *ctx,
@@ -55,6 +62,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
{
struct nft_lookup *priv = nft_expr_priv(expr);
struct nft_set *set;
+ u32 flags;
int err;
if (tb[NFTA_LOOKUP_SET] == NULL ||
@@ -79,7 +87,22 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
if (err < 0)
return err;
+ if (tb[NFTA_LOOKUP_FLAGS]) {
+ flags = ntohl(nla_get_be32(tb[NFTA_LOOKUP_FLAGS]));
+
+ if (flags & ~NFT_LOOKUP_F_INV)
+ return -EINVAL;
+
+ if (flags & NFT_LOOKUP_F_INV) {
+ if (set->flags & NFT_SET_MAP)
+ return -EINVAL;
+ priv->invert = true;
+ }
+ }
+
if (tb[NFTA_LOOKUP_DREG] != NULL) {
+ if (priv->invert)
+ return -EINVAL;
if (!(set->flags & NFT_SET_MAP))
return -EINVAL;
@@ -112,6 +135,7 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx,
static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_lookup *priv = nft_expr_priv(expr);
+ u32 flags = priv->invert ? NFT_LOOKUP_F_INV : 0;
if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
goto nla_put_failure;
@@ -120,6 +144,8 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
if (priv->set->flags & NFT_SET_MAP)
if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg))
goto nla_put_failure;
+ if (nla_put_be32(skb, NFTA_LOOKUP_FLAGS, htonl(flags)))
+ goto nla_put_failure;
return 0;
nla_put_failure:
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup 2016-06-01 15:23 [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup Arturo Borrero Gonzalez @ 2016-06-22 18:22 ` Pablo Neira Ayuso 2016-06-23 7:32 ` Arturo Borrero Gonzalez 2016-06-23 10:08 ` Pablo Neira Ayuso 1 sibling, 1 reply; 5+ messages in thread From: Pablo Neira Ayuso @ 2016-06-22 18:22 UTC (permalink / raw) To: Arturo Borrero Gonzalez; +Cc: netfilter-devel On Wed, Jun 01, 2016 at 05:23:02PM +0200, Arturo Borrero Gonzalez wrote: > Introduce a new configuration option for this expression, which allows users > to invert the logic of set lookups. Any plan to add the missing nftables bits? Let me know, I would like to have all the pieces in places so we can also add automated tests for this. Thanks! ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup 2016-06-22 18:22 ` Pablo Neira Ayuso @ 2016-06-23 7:32 ` Arturo Borrero Gonzalez 2016-06-23 8:39 ` Arturo Borrero Gonzalez 0 siblings, 1 reply; 5+ messages in thread From: Arturo Borrero Gonzalez @ 2016-06-23 7:32 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list On 22 June 2016 at 20:22, Pablo Neira Ayuso <pablo@netfilter.org> wrote: > On Wed, Jun 01, 2016 at 05:23:02PM +0200, Arturo Borrero Gonzalez wrote: >> Introduce a new configuration option for this expression, which allows users >> to invert the logic of set lookups. > > Any plan to add the missing nftables bits? Let me know, I would like > to have all the pieces in places so we can also add automated tests > for this. Eventually yes, but not in the short term. -- Arturo Borrero González -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup 2016-06-23 7:32 ` Arturo Borrero Gonzalez @ 2016-06-23 8:39 ` Arturo Borrero Gonzalez 0 siblings, 0 replies; 5+ messages in thread From: Arturo Borrero Gonzalez @ 2016-06-23 8:39 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list [-- Attachment #1: Type: text/plain, Size: 817 bytes --] On 23 June 2016 at 09:32, Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> wrote: > On 22 June 2016 at 20:22, Pablo Neira Ayuso <pablo@netfilter.org> wrote: >> On Wed, Jun 01, 2016 at 05:23:02PM +0200, Arturo Borrero Gonzalez wrote: >>> Introduce a new configuration option for this expression, which allows users >>> to invert the logic of set lookups. >> >> Any plan to add the missing nftables bits? Let me know, I would like >> to have all the pieces in places so we can also add automated tests >> for this. > > Eventually yes, but not in the short term. > BTW, if you would like to have it done now, I'm attaching the [half] patch I developed back in May. AFAIK, this patch implements the user-to-kernel path but the kernel-to-user path was missing. -- Arturo Borrero González [-- Attachment #2: lookup-inversion.patch --] [-- Type: text/x-patch, Size: 4665 bytes --] evaluate: add support for set lookups inversion From: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> --- include/expression.h | 1 + src/evaluate.c | 13 +++++++++++++ src/expression.c | 1 + src/netlink_delinearize.c | 9 +++++++++ src/netlink_linearize.c | 9 +++++++++ 5 files changed, 33 insertions(+) diff --git a/include/expression.h b/include/expression.h index 6e5e835..c6c6ef8 100644 --- a/include/expression.h +++ b/include/expression.h @@ -82,6 +82,7 @@ enum ops { OP_FLAGCMP, /* Set lookup */ OP_LOOKUP, + OP_LOOKUP_INV, __OP_MAX }; #define OP_MAX (__OP_MAX - 1) diff --git a/src/evaluate.c b/src/evaluate.c index f24e5f3..e1faa79 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1350,6 +1350,17 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) return -1; right = rel->right; + if (rel->op == OP_NEQ) { + switch (right->ops->type) { + case EXPR_SET: + case EXPR_SET_REF: + rel->op = OP_LOOKUP_INV; + break; + default: + break; + } + } + if (rel->op == OP_IMPLICIT) { switch (right->ops->type) { case EXPR_RANGE: @@ -1372,6 +1383,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) } } + if (!expr_is_constant(right)) return expr_binary_error(ctx->msgs, right, rel, "Right hand side of relational " @@ -1385,6 +1397,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) switch (rel->op) { case OP_LOOKUP: + case OP_LOOKUP_INV: switch (right->ops->type) { case EXPR_SET: /* A literal set expression implicitly declares diff --git a/src/expression.c b/src/expression.c index a10af5d..5d6d6b3 100644 --- a/src/expression.c +++ b/src/expression.c @@ -451,6 +451,7 @@ const char *expr_op_symbols[] = { [OP_GTE] = ">=", [OP_RANGE] = "within range", [OP_LOOKUP] = NULL, + [OP_LOOKUP_INV] = "!=", }; static void unary_expr_print(const struct expr *expr) diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 7735699..35bad01 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -259,6 +259,7 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, const char *name; struct expr *expr, *left, *right; struct set *set; + uint32_t flags; name = nftnl_expr_get_str(nle, NFTNL_EXPR_LOOKUP_SET); set = set_lookup(ctx->table, name); @@ -281,13 +282,20 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, right = set_ref_expr_alloc(loc, set); + flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS); + if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOOKUP_DREG)) { dreg = netlink_parse_register(nle, NFTNL_EXPR_LOOKUP_DREG); expr = map_expr_alloc(loc, left, right); + if (flags & NFT_LOOKUP_F_INV) + expr->op = OP_LOOKUP_INV; + if (dreg != NFT_REG_VERDICT) return netlink_set_register(ctx, dreg, expr); } else { expr = relational_expr_alloc(loc, OP_LOOKUP, left, right); + if (flags & NFT_LOOKUP_F_INV) + expr->op = OP_LOOKUP_INV; } ctx->stmt = expr_stmt_alloc(loc, expr); @@ -1168,6 +1176,7 @@ static void ct_meta_common_postprocess(const struct expr *expr) switch (expr->op) { case OP_LOOKUP: + case OP_LOOKUP_INV: expr_set_type(right, left->dtype, left->byteorder); if (right->dtype == &integer_type) integer_type_postprocess(right); diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 01a85d0..f6f608c 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -191,6 +191,10 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx, nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID, expr->mappings->set->handle.set_id); + if (expr->op == OP_LOOKUP_INV) + nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS, + NFT_LOOKUP_F_INV); + if (dreg == NFT_REG_VERDICT) release_register(ctx, expr->map); @@ -217,6 +221,10 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx, nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID, expr->right->set->handle.set_id); + if (expr->op == OP_LOOKUP_INV) + nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS, + NFT_LOOKUP_F_INV); + release_register(ctx, expr->left); nftnl_rule_add_expr(ctx->nlr, nle); } @@ -433,6 +441,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx, case OP_FLAGCMP: return netlink_gen_flagcmp(ctx, expr, dreg); case OP_LOOKUP: + case OP_LOOKUP_INV: return netlink_gen_lookup(ctx, expr, dreg); default: BUG("invalid relational operation %u\n", expr->op); ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup 2016-06-01 15:23 [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup Arturo Borrero Gonzalez 2016-06-22 18:22 ` Pablo Neira Ayuso @ 2016-06-23 10:08 ` Pablo Neira Ayuso 1 sibling, 0 replies; 5+ messages in thread From: Pablo Neira Ayuso @ 2016-06-23 10:08 UTC (permalink / raw) To: Arturo Borrero Gonzalez; +Cc: netfilter-devel On Wed, Jun 01, 2016 at 05:23:02PM +0200, Arturo Borrero Gonzalez wrote: > @@ -32,14 +33,19 @@ static void nft_lookup_eval(const struct nft_expr *expr, > const struct nft_lookup *priv = nft_expr_priv(expr); > const struct nft_set *set = priv->set; > const struct nft_set_ext *ext; > + bool found; > > - if (set->ops->lookup(set, ®s->data[priv->sreg], &ext)) { > - if (set->flags & NFT_SET_MAP) > - nft_data_copy(®s->data[priv->dreg], > - nft_set_ext_data(ext), set->dlen); > + found = set->ops->lookup(set, ®s->data[priv->sreg], &ext); > + > + if (!(found ^ priv->invert)) { > + regs->verdict.code = NFT_BREAK; > return; > } > - regs->verdict.code = NFT_BREAK; > + > + if (set->flags & NFT_SET_MAP && found && !priv->invert) I think this is a bit defensive: if set->flags & NFT_SET_MAP evaluates true, then we can assume priv->invert is always false. We can just add a comment on top of this. Note that, from the _init() path, we reject inversions with maps. So probably something like: /* nft_lookup_init() already rejects maps with inverted lookups. * We assume that inversion is always false with maps. */ found = set->ops->lookup(set, ®s->data[priv->sreg], &ext) ^ priv->invert; if (found && set->flags & NFT_SET_MAP) nft_data_copy(...); would be a bit more simple. > + nft_data_copy(®s->data[priv->dreg], > + nft_set_ext_data(ext), set->dlen); > + > } > > static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2016-06-23 10:08 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-06-01 15:23 [nf-next PATCH v4] netfilter: nf_tables: add support for inverted logic in nft_lookup Arturo Borrero Gonzalez 2016-06-22 18:22 ` Pablo Neira Ayuso 2016-06-23 7:32 ` Arturo Borrero Gonzalez 2016-06-23 8:39 ` Arturo Borrero Gonzalez 2016-06-23 10:08 ` 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).