Skip to content

Commit 48b0ae0

Browse files
committed
netfilter: nftables: netlink support for several set element expressions
This patch adds three new netlink attributes to encapsulate a list of expressions per set elements: - NFTA_SET_EXPRESSIONS: this attribute provides the set definition in terms of expressions. New set elements get attached the list of expressions that is specified by this new netlink attribute. - NFTA_SET_ELEM_EXPRESSIONS: this attribute allows users to restore (or initialize) the stateful information of set elements when adding an element to the set. - NFTA_DYNSET_EXPRESSIONS: this attribute specifies the list of expressions that the set element gets when it is inserted from the packet path. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 563125a commit 48b0ae0

File tree

3 files changed

+149
-6
lines changed

3 files changed

+149
-6
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ enum nft_set_field_attributes {
361361
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
362362
* @NFTA_SET_HANDLE: set handle (NLA_U64)
363363
* @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
364+
* @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
364365
*/
365366
enum nft_set_attributes {
366367
NFTA_SET_UNSPEC,
@@ -381,6 +382,7 @@ enum nft_set_attributes {
381382
NFTA_SET_OBJ_TYPE,
382383
NFTA_SET_HANDLE,
383384
NFTA_SET_EXPR,
385+
NFTA_SET_EXPRESSIONS,
384386
__NFTA_SET_MAX
385387
};
386388
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -406,6 +408,7 @@ enum nft_set_elem_flags {
406408
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
407409
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
408410
* @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
411+
* @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
409412
*/
410413
enum nft_set_elem_attributes {
411414
NFTA_SET_ELEM_UNSPEC,
@@ -419,6 +422,7 @@ enum nft_set_elem_attributes {
419422
NFTA_SET_ELEM_PAD,
420423
NFTA_SET_ELEM_OBJREF,
421424
NFTA_SET_ELEM_KEY_END,
425+
NFTA_SET_ELEM_EXPRESSIONS,
422426
__NFTA_SET_ELEM_MAX
423427
};
424428
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -715,6 +719,7 @@ enum nft_dynset_flags {
715719
* @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
716720
* @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
717721
* @NFTA_DYNSET_FLAGS: flags (NLA_U32)
722+
* @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
718723
*/
719724
enum nft_dynset_attributes {
720725
NFTA_DYNSET_UNSPEC,
@@ -727,6 +732,7 @@ enum nft_dynset_attributes {
727732
NFTA_DYNSET_EXPR,
728733
NFTA_DYNSET_PAD,
729734
NFTA_DYNSET_FLAGS,
735+
NFTA_DYNSET_EXPRESSIONS,
730736
__NFTA_DYNSET_MAX,
731737
};
732738
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)

net/netfilter/nf_tables_api.c

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3566,6 +3566,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
35663566
[NFTA_SET_OBJ_TYPE] = { .type = NLA_U32 },
35673567
[NFTA_SET_HANDLE] = { .type = NLA_U64 },
35683568
[NFTA_SET_EXPR] = { .type = NLA_NESTED },
3569+
[NFTA_SET_EXPRESSIONS] = { .type = NLA_NESTED },
35693570
};
35703571

35713572
static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
@@ -3773,6 +3774,7 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
37733774
u32 portid = ctx->portid;
37743775
struct nlattr *nest;
37753776
u32 seq = ctx->seq;
3777+
int i;
37763778

37773779
event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
37783780
nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -3847,6 +3849,17 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
38473849
goto nla_put_failure;
38483850

38493851
nla_nest_end(skb, nest);
3852+
} else if (set->num_exprs > 1) {
3853+
nest = nla_nest_start_noflag(skb, NFTA_SET_EXPRESSIONS);
3854+
if (nest == NULL)
3855+
goto nla_put_failure;
3856+
3857+
for (i = 0; i < set->num_exprs; i++) {
3858+
if (nft_expr_dump(skb, NFTA_LIST_ELEM,
3859+
set->exprs[i]) < 0)
3860+
goto nla_put_failure;
3861+
}
3862+
nla_nest_end(skb, nest);
38503863
}
38513864

38523865
nlmsg_end(skb, nlh);
@@ -4215,7 +4228,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
42154228
return err;
42164229
}
42174230

4218-
if (nla[NFTA_SET_EXPR])
4231+
if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS])
42194232
desc.expr = true;
42204233

42214234
table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, genmask);
@@ -4281,6 +4294,29 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
42814294
}
42824295
set->exprs[0] = expr;
42834296
set->num_exprs++;
4297+
} else if (nla[NFTA_SET_EXPRESSIONS]) {
4298+
struct nft_expr *expr;
4299+
struct nlattr *tmp;
4300+
int left;
4301+
4302+
i = 0;
4303+
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
4304+
if (i == NFT_SET_EXPR_MAX) {
4305+
err = -E2BIG;
4306+
goto err_set_init;
4307+
}
4308+
if (nla_type(tmp) != NFTA_LIST_ELEM) {
4309+
err = -EINVAL;
4310+
goto err_set_init;
4311+
}
4312+
expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
4313+
if (IS_ERR(expr)) {
4314+
err = PTR_ERR(expr);
4315+
goto err_set_init;
4316+
}
4317+
set->exprs[i++] = expr;
4318+
set->num_exprs++;
4319+
}
42844320
}
42854321

42864322
udata = NULL;
@@ -4540,6 +4576,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
45404576
[NFTA_SET_ELEM_OBJREF] = { .type = NLA_STRING,
45414577
.len = NFT_OBJ_MAXNAMELEN - 1 },
45424578
[NFTA_SET_ELEM_KEY_END] = { .type = NLA_NESTED },
4579+
[NFTA_SET_ELEM_EXPRESSIONS] = { .type = NLA_NESTED },
45434580
};
45444581

45454582
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
@@ -4580,6 +4617,7 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
45804617
struct nft_set_elem_expr *elem_expr;
45814618
u32 size, num_exprs = 0;
45824619
struct nft_expr *expr;
4620+
struct nlattr *nest;
45834621

45844622
elem_expr = nft_set_ext_expr(ext);
45854623
nft_setelem_expr_foreach(expr, elem_expr, size)
@@ -4591,9 +4629,22 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
45914629
return -1;
45924630

45934631
return 0;
4594-
}
4632+
} else if (num_exprs > 1) {
4633+
nest = nla_nest_start_noflag(skb, NFTA_SET_ELEM_EXPRESSIONS);
4634+
if (nest == NULL)
4635+
goto nla_put_failure;
45954636

4637+
nft_setelem_expr_foreach(expr, elem_expr, size) {
4638+
expr = nft_setelem_expr_at(elem_expr, size);
4639+
if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr) < 0)
4640+
goto nla_put_failure;
4641+
}
4642+
nla_nest_end(skb, nest);
4643+
}
45964644
return 0;
4645+
4646+
nla_put_failure:
4647+
return -1;
45974648
}
45984649

45994650
static int nf_tables_fill_setelem(struct sk_buff *skb,
@@ -5268,7 +5319,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
52685319
nla[NFTA_SET_ELEM_TIMEOUT] ||
52695320
nla[NFTA_SET_ELEM_EXPIRATION] ||
52705321
nla[NFTA_SET_ELEM_USERDATA] ||
5271-
nla[NFTA_SET_ELEM_EXPR]))
5322+
nla[NFTA_SET_ELEM_EXPR] ||
5323+
nla[NFTA_SET_ELEM_EXPRESSIONS]))
52725324
return -EINVAL;
52735325

52745326
timeout = 0;
@@ -5310,6 +5362,41 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
53105362
err = -EOPNOTSUPP;
53115363
goto err_set_elem_expr;
53125364
}
5365+
} else if (nla[NFTA_SET_ELEM_EXPRESSIONS]) {
5366+
struct nft_expr *expr;
5367+
struct nlattr *tmp;
5368+
int left;
5369+
5370+
if (set->num_exprs == 0)
5371+
return -EOPNOTSUPP;
5372+
5373+
i = 0;
5374+
nla_for_each_nested(tmp, nla[NFTA_SET_ELEM_EXPRESSIONS], left) {
5375+
if (i == set->num_exprs) {
5376+
err = -E2BIG;
5377+
goto err_set_elem_expr;
5378+
}
5379+
if (nla_type(tmp) != NFTA_LIST_ELEM) {
5380+
err = -EINVAL;
5381+
goto err_set_elem_expr;
5382+
}
5383+
expr = nft_set_elem_expr_alloc(ctx, set, tmp);
5384+
if (IS_ERR(expr)) {
5385+
err = PTR_ERR(expr);
5386+
goto err_set_elem_expr;
5387+
}
5388+
expr_array[i] = expr;
5389+
5390+
if (expr->ops != set->exprs[i]->ops) {
5391+
err = -EOPNOTSUPP;
5392+
goto err_set_elem_expr;
5393+
}
5394+
i++;
5395+
}
5396+
if (set->num_exprs != i) {
5397+
err = -EOPNOTSUPP;
5398+
goto err_set_elem_expr;
5399+
}
53135400
} else if (set->num_exprs > 0) {
53145401
err = nft_set_elem_expr_clone(ctx, set, expr_array);
53155402
if (err < 0)

net/netfilter/nft_dynset.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
153153
[NFTA_DYNSET_TIMEOUT] = { .type = NLA_U64 },
154154
[NFTA_DYNSET_EXPR] = { .type = NLA_NESTED },
155155
[NFTA_DYNSET_FLAGS] = { .type = NLA_U32 },
156+
[NFTA_DYNSET_EXPRESSIONS] = { .type = NLA_NESTED },
156157
};
157158

158159
static int nft_dynset_init(const struct nft_ctx *ctx,
@@ -232,12 +233,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
232233
} else if (set->flags & NFT_SET_MAP)
233234
return -EINVAL;
234235

236+
if ((tb[NFTA_DYNSET_EXPR] || tb[NFTA_DYNSET_EXPRESSIONS]) &&
237+
!(set->flags & NFT_SET_EVAL))
238+
return -EINVAL;
239+
235240
if (tb[NFTA_DYNSET_EXPR]) {
236241
struct nft_expr *dynset_expr;
237242

238-
if (!(set->flags & NFT_SET_EVAL))
239-
return -EINVAL;
240-
241243
dynset_expr = nft_dynset_expr_alloc(ctx, set,
242244
tb[NFTA_DYNSET_EXPR], 0);
243245
if (IS_ERR(dynset_expr))
@@ -252,6 +254,40 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
252254
err = -EOPNOTSUPP;
253255
goto err_expr_free;
254256
}
257+
} else if (tb[NFTA_DYNSET_EXPRESSIONS]) {
258+
struct nft_expr *dynset_expr;
259+
struct nlattr *tmp;
260+
int left;
261+
262+
i = 0;
263+
nla_for_each_nested(tmp, tb[NFTA_DYNSET_EXPRESSIONS], left) {
264+
if (i == NFT_SET_EXPR_MAX) {
265+
err = -E2BIG;
266+
goto err_expr_free;
267+
}
268+
if (nla_type(tmp) != NFTA_LIST_ELEM) {
269+
err = -EINVAL;
270+
goto err_expr_free;
271+
}
272+
dynset_expr = nft_dynset_expr_alloc(ctx, set, tmp, i);
273+
if (IS_ERR(dynset_expr)) {
274+
err = PTR_ERR(dynset_expr);
275+
goto err_expr_free;
276+
}
277+
priv->expr_array[i] = dynset_expr;
278+
priv->num_exprs++;
279+
280+
if (set->num_exprs &&
281+
dynset_expr->ops != set->exprs[i]->ops) {
282+
err = -EOPNOTSUPP;
283+
goto err_expr_free;
284+
}
285+
i++;
286+
}
287+
if (set->num_exprs && set->num_exprs != i) {
288+
err = -EOPNOTSUPP;
289+
goto err_expr_free;
290+
}
255291
}
256292

257293
nft_set_ext_prepare(&priv->tmpl);
@@ -318,6 +354,7 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
318354
{
319355
const struct nft_dynset *priv = nft_expr_priv(expr);
320356
u32 flags = priv->invert ? NFT_DYNSET_F_INV : 0;
357+
int i;
321358

322359
if (nft_dump_register(skb, NFTA_DYNSET_SREG_KEY, priv->sreg_key))
323360
goto nla_put_failure;
@@ -335,6 +372,19 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
335372
if (priv->num_exprs == 1) {
336373
if (nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr_array[0]))
337374
goto nla_put_failure;
375+
} else if (priv->num_exprs > 1) {
376+
struct nlattr *nest;
377+
378+
nest = nla_nest_start_noflag(skb, NFTA_DYNSET_EXPRESSIONS);
379+
if (!nest)
380+
goto nla_put_failure;
381+
382+
for (i = 0; i < priv->num_exprs; i++) {
383+
if (nft_expr_dump(skb, NFTA_LIST_ELEM,
384+
priv->expr_array[i]))
385+
goto nla_put_failure;
386+
}
387+
nla_nest_end(skb, nest);
338388
}
339389
if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags)))
340390
goto nla_put_failure;

0 commit comments

Comments
 (0)