diff options
author | Arturo Borrero <arturo.borrero.glez@gmail.com> | 2016-06-23 06:24:08 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-06-24 05:03:29 -0400 |
commit | 0071e184a535e40ce487528cb04f4690cb0da881 (patch) | |
tree | 6267df19373697d545ba080be1f3ababaf9e6d5b /net/netfilter | |
parent | 82bec71d46b83f39860e2838ff8394e4fcd6efab (diff) |
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>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/nft_lookup.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 8a102cf855d0..b8d18f598569 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c | |||
@@ -22,6 +22,7 @@ struct nft_lookup { | |||
22 | struct nft_set *set; | 22 | struct nft_set *set; |
23 | enum nft_registers sreg:8; | 23 | enum nft_registers sreg:8; |
24 | enum nft_registers dreg:8; | 24 | enum nft_registers dreg:8; |
25 | bool invert; | ||
25 | struct nft_set_binding binding; | 26 | struct nft_set_binding binding; |
26 | }; | 27 | }; |
27 | 28 | ||
@@ -32,14 +33,20 @@ static void nft_lookup_eval(const struct nft_expr *expr, | |||
32 | const struct nft_lookup *priv = nft_expr_priv(expr); | 33 | const struct nft_lookup *priv = nft_expr_priv(expr); |
33 | const struct nft_set *set = priv->set; | 34 | const struct nft_set *set = priv->set; |
34 | const struct nft_set_ext *ext; | 35 | const struct nft_set_ext *ext; |
36 | bool found; | ||
35 | 37 | ||
36 | if (set->ops->lookup(set, ®s->data[priv->sreg], &ext)) { | 38 | found = set->ops->lookup(set, ®s->data[priv->sreg], &ext) ^ |
37 | if (set->flags & NFT_SET_MAP) | 39 | priv->invert; |
38 | nft_data_copy(®s->data[priv->dreg], | 40 | |
39 | nft_set_ext_data(ext), set->dlen); | 41 | if (!found) { |
42 | regs->verdict.code = NFT_BREAK; | ||
40 | return; | 43 | return; |
41 | } | 44 | } |
42 | regs->verdict.code = NFT_BREAK; | 45 | |
46 | if (found && set->flags & NFT_SET_MAP) | ||
47 | nft_data_copy(®s->data[priv->dreg], | ||
48 | nft_set_ext_data(ext), set->dlen); | ||
49 | |||
43 | } | 50 | } |
44 | 51 | ||
45 | static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { | 52 | 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 | [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, | 54 | [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, |
48 | [NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, | 55 | [NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, |
49 | [NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, | 56 | [NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, |
57 | [NFTA_LOOKUP_FLAGS] = { .type = NLA_U32 }, | ||
50 | }; | 58 | }; |
51 | 59 | ||
52 | static int nft_lookup_init(const struct nft_ctx *ctx, | 60 | 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 | struct nft_lookup *priv = nft_expr_priv(expr); | 64 | struct nft_lookup *priv = nft_expr_priv(expr); |
57 | u8 genmask = nft_genmask_next(ctx->net); | 65 | u8 genmask = nft_genmask_next(ctx->net); |
58 | struct nft_set *set; | 66 | struct nft_set *set; |
67 | u32 flags; | ||
59 | int err; | 68 | int err; |
60 | 69 | ||
61 | if (tb[NFTA_LOOKUP_SET] == NULL || | 70 | if (tb[NFTA_LOOKUP_SET] == NULL || |
@@ -81,7 +90,22 @@ static int nft_lookup_init(const struct nft_ctx *ctx, | |||
81 | if (err < 0) | 90 | if (err < 0) |
82 | return err; | 91 | return err; |
83 | 92 | ||
93 | if (tb[NFTA_LOOKUP_FLAGS]) { | ||
94 | flags = ntohl(nla_get_be32(tb[NFTA_LOOKUP_FLAGS])); | ||
95 | |||
96 | if (flags & ~NFT_LOOKUP_F_INV) | ||
97 | return -EINVAL; | ||
98 | |||
99 | if (flags & NFT_LOOKUP_F_INV) { | ||
100 | if (set->flags & NFT_SET_MAP) | ||
101 | return -EINVAL; | ||
102 | priv->invert = true; | ||
103 | } | ||
104 | } | ||
105 | |||
84 | if (tb[NFTA_LOOKUP_DREG] != NULL) { | 106 | if (tb[NFTA_LOOKUP_DREG] != NULL) { |
107 | if (priv->invert) | ||
108 | return -EINVAL; | ||
85 | if (!(set->flags & NFT_SET_MAP)) | 109 | if (!(set->flags & NFT_SET_MAP)) |
86 | return -EINVAL; | 110 | return -EINVAL; |
87 | 111 | ||
@@ -114,6 +138,7 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx, | |||
114 | static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) | 138 | static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) |
115 | { | 139 | { |
116 | const struct nft_lookup *priv = nft_expr_priv(expr); | 140 | const struct nft_lookup *priv = nft_expr_priv(expr); |
141 | u32 flags = priv->invert ? NFT_LOOKUP_F_INV : 0; | ||
117 | 142 | ||
118 | if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name)) | 143 | if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name)) |
119 | goto nla_put_failure; | 144 | goto nla_put_failure; |
@@ -122,6 +147,8 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) | |||
122 | if (priv->set->flags & NFT_SET_MAP) | 147 | if (priv->set->flags & NFT_SET_MAP) |
123 | if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg)) | 148 | if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg)) |
124 | goto nla_put_failure; | 149 | goto nla_put_failure; |
150 | if (nla_put_be32(skb, NFTA_LOOKUP_FLAGS, htonl(flags))) | ||
151 | goto nla_put_failure; | ||
125 | return 0; | 152 | return 0; |
126 | 153 | ||
127 | nla_put_failure: | 154 | nla_put_failure: |