Commit 0071e184 authored by Arturo Borrero's avatar Arturo Borrero Committed by Pablo Neira Ayuso

netfilter: nf_tables: add support for inverted logic in nft_lookup

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 in 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
Signed-off-by: default avatarArturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 82bec71d
...@@ -546,6 +546,10 @@ enum nft_cmp_attributes { ...@@ -546,6 +546,10 @@ enum nft_cmp_attributes {
}; };
#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1) #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 * enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes
* *
...@@ -553,6 +557,7 @@ enum nft_cmp_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_SREG: source register of the data to look for (NLA_U32: nft_registers)
* @NFTA_LOOKUP_DREG: destination register (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_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 { enum nft_lookup_attributes {
NFTA_LOOKUP_UNSPEC, NFTA_LOOKUP_UNSPEC,
...@@ -560,6 +565,7 @@ enum nft_lookup_attributes { ...@@ -560,6 +565,7 @@ enum nft_lookup_attributes {
NFTA_LOOKUP_SREG, NFTA_LOOKUP_SREG,
NFTA_LOOKUP_DREG, NFTA_LOOKUP_DREG,
NFTA_LOOKUP_SET_ID, NFTA_LOOKUP_SET_ID,
NFTA_LOOKUP_FLAGS,
__NFTA_LOOKUP_MAX __NFTA_LOOKUP_MAX
}; };
#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1) #define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
......
...@@ -22,6 +22,7 @@ struct nft_lookup { ...@@ -22,6 +22,7 @@ struct nft_lookup {
struct nft_set *set; struct nft_set *set;
enum nft_registers sreg:8; enum nft_registers sreg:8;
enum nft_registers dreg:8; enum nft_registers dreg:8;
bool invert;
struct nft_set_binding binding; struct nft_set_binding binding;
}; };
...@@ -32,14 +33,20 @@ static void nft_lookup_eval(const struct nft_expr *expr, ...@@ -32,14 +33,20 @@ static void nft_lookup_eval(const struct nft_expr *expr,
const struct nft_lookup *priv = nft_expr_priv(expr); const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set; const struct nft_set *set = priv->set;
const struct nft_set_ext *ext; const struct nft_set_ext *ext;
bool found;
if (set->ops->lookup(set, &regs->data[priv->sreg], &ext)) { found = set->ops->lookup(set, &regs->data[priv->sreg], &ext) ^
if (set->flags & NFT_SET_MAP) priv->invert;
nft_data_copy(&regs->data[priv->dreg],
nft_set_ext_data(ext), set->dlen); if (!found) {
regs->verdict.code = NFT_BREAK;
return; return;
} }
regs->verdict.code = NFT_BREAK;
if (found && set->flags & NFT_SET_MAP)
nft_data_copy(&regs->data[priv->dreg],
nft_set_ext_data(ext), set->dlen);
} }
static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
...@@ -47,6 +54,7 @@ static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { ...@@ -47,6 +54,7 @@ static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
[NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 },
[NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
[NFTA_LOOKUP_DREG] = { .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, static int nft_lookup_init(const struct nft_ctx *ctx,
...@@ -56,6 +64,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx, ...@@ -56,6 +64,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
struct nft_lookup *priv = nft_expr_priv(expr); struct nft_lookup *priv = nft_expr_priv(expr);
u8 genmask = nft_genmask_next(ctx->net); u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set; struct nft_set *set;
u32 flags;
int err; int err;
if (tb[NFTA_LOOKUP_SET] == NULL || if (tb[NFTA_LOOKUP_SET] == NULL ||
...@@ -81,7 +90,22 @@ static int nft_lookup_init(const struct nft_ctx *ctx, ...@@ -81,7 +90,22 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
if (err < 0) if (err < 0)
return err; 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 (tb[NFTA_LOOKUP_DREG] != NULL) {
if (priv->invert)
return -EINVAL;
if (!(set->flags & NFT_SET_MAP)) if (!(set->flags & NFT_SET_MAP))
return -EINVAL; return -EINVAL;
...@@ -114,6 +138,7 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx, ...@@ -114,6 +138,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) static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_lookup *priv = nft_expr_priv(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)) if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
goto nla_put_failure; goto nla_put_failure;
...@@ -122,6 +147,8 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -122,6 +147,8 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
if (priv->set->flags & NFT_SET_MAP) if (priv->set->flags & NFT_SET_MAP)
if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg)) if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_LOOKUP_FLAGS, htonl(flags)))
goto nla_put_failure;
return 0; return 0;
nla_put_failure: nla_put_failure:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment