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: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
82bec71d46
commit
0071e184a5
@ -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 {
|
|||||||
* @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 {
|
|||||||
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 {
|
|||||||
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,
|
|||||||
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, ®s->data[priv->sreg], &ext)) {
|
found = set->ops->lookup(set, ®s->data[priv->sreg], &ext) ^
|
||||||
if (set->flags & NFT_SET_MAP)
|
priv->invert;
|
||||||
nft_data_copy(®s->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(®s->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] = {
|
|||||||
[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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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:
|
||||||
|
Loading…
Reference in New Issue
Block a user