Skip to content

Commit 8aeff92

Browse files
committed
netfilter: nf_tables: add stateful object reference to set elements
This patch allows you to refer to stateful objects from set elements. This provides the infrastructure to create maps where the right hand side of the mapping is a stateful object. This allows us to build dictionaries of stateful objects, that you can use to perform fast lookups using any arbitrary key combination. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 1896531 commit 8aeff92

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
326326
* @name: name of the set
327327
* @ktype: key type (numeric type defined by userspace, not used in the kernel)
328328
* @dtype: data type (verdict or numeric type defined by userspace)
329+
* @objtype: object type (see NFT_OBJECT_* definitions)
329330
* @size: maximum set size
330331
* @nelems: number of elements
331332
* @ndeact: number of deactivated elements queued for removal
@@ -347,6 +348,7 @@ struct nft_set {
347348
char name[NFT_SET_MAXNAMELEN];
348349
u32 ktype;
349350
u32 dtype;
351+
u32 objtype;
350352
u32 size;
351353
atomic_t nelems;
352354
u32 ndeact;
@@ -416,6 +418,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
416418
* @NFT_SET_EXT_EXPIRATION: element expiration time
417419
* @NFT_SET_EXT_USERDATA: user data associated with the element
418420
* @NFT_SET_EXT_EXPR: expression assiociated with the element
421+
* @NFT_SET_EXT_OBJREF: stateful object reference associated with element
419422
* @NFT_SET_EXT_NUM: number of extension types
420423
*/
421424
enum nft_set_extensions {
@@ -426,6 +429,7 @@ enum nft_set_extensions {
426429
NFT_SET_EXT_EXPIRATION,
427430
NFT_SET_EXT_USERDATA,
428431
NFT_SET_EXT_EXPR,
432+
NFT_SET_EXT_OBJREF,
429433
NFT_SET_EXT_NUM
430434
};
431435

@@ -554,6 +558,11 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
554558
return elem + set->ops->elemsize;
555559
}
556560

561+
static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
562+
{
563+
return nft_set_ext(ext, NFT_SET_EXT_OBJREF);
564+
}
565+
557566
void *nft_set_elem_init(const struct nft_set *set,
558567
const struct nft_set_ext_tmpl *tmpl,
559568
const u32 *key, const u32 *data,

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ enum nft_rule_compat_attributes {
255255
* @NFT_SET_MAP: set is used as a dictionary
256256
* @NFT_SET_TIMEOUT: set uses timeouts
257257
* @NFT_SET_EVAL: set contains expressions for evaluation
258+
* @NFT_SET_OBJECT: set contains stateful objects
258259
*/
259260
enum nft_set_flags {
260261
NFT_SET_ANONYMOUS = 0x1,
@@ -263,6 +264,7 @@ enum nft_set_flags {
263264
NFT_SET_MAP = 0x8,
264265
NFT_SET_TIMEOUT = 0x10,
265266
NFT_SET_EVAL = 0x20,
267+
NFT_SET_OBJECT = 0x40,
266268
};
267269

268270
/**
@@ -304,6 +306,7 @@ enum nft_set_desc_attributes {
304306
* @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
305307
* @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
306308
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
309+
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
307310
*/
308311
enum nft_set_attributes {
309312
NFTA_SET_UNSPEC,
@@ -321,6 +324,7 @@ enum nft_set_attributes {
321324
NFTA_SET_GC_INTERVAL,
322325
NFTA_SET_USERDATA,
323326
NFTA_SET_PAD,
327+
NFTA_SET_OBJ_TYPE,
324328
__NFTA_SET_MAX
325329
};
326330
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -344,6 +348,7 @@ enum nft_set_elem_flags {
344348
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
345349
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
346350
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
351+
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
347352
*/
348353
enum nft_set_elem_attributes {
349354
NFTA_SET_ELEM_UNSPEC,
@@ -355,6 +360,7 @@ enum nft_set_elem_attributes {
355360
NFTA_SET_ELEM_USERDATA,
356361
NFTA_SET_ELEM_EXPR,
357362
NFTA_SET_ELEM_PAD,
363+
NFTA_SET_ELEM_OBJREF,
358364
__NFTA_SET_ELEM_MAX
359365
};
360366
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -1207,6 +1213,8 @@ enum nft_fib_flags {
12071213
#define NFT_OBJECT_UNSPEC 0
12081214
#define NFT_OBJECT_COUNTER 1
12091215
#define NFT_OBJECT_QUOTA 2
1216+
#define __NFT_OBJECT_MAX 3
1217+
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
12101218

12111219
/**
12121220
* enum nft_object_attributes - nf_tables stateful object netlink attributes

net/netfilter/nf_tables_api.c

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,6 +2452,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
24522452
[NFTA_SET_GC_INTERVAL] = { .type = NLA_U32 },
24532453
[NFTA_SET_USERDATA] = { .type = NLA_BINARY,
24542454
.len = NFT_USERDATA_MAXLEN },
2455+
[NFTA_SET_OBJ_TYPE] = { .type = NLA_U32 },
24552456
};
24562457

24572458
static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
@@ -2609,6 +2610,9 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
26092610
if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
26102611
goto nla_put_failure;
26112612
}
2613+
if (set->flags & NFT_SET_OBJECT &&
2614+
nla_put_be32(skb, NFTA_SET_OBJ_TYPE, htonl(set->objtype)))
2615+
goto nla_put_failure;
26122616

26132617
if (set->timeout &&
26142618
nla_put_be64(skb, NFTA_SET_TIMEOUT,
@@ -2838,7 +2842,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
28382842
unsigned int size;
28392843
bool create;
28402844
u64 timeout;
2841-
u32 ktype, dtype, flags, policy, gc_int;
2845+
u32 ktype, dtype, flags, policy, gc_int, objtype;
28422846
struct nft_set_desc desc;
28432847
unsigned char *udata;
28442848
u16 udlen;
@@ -2868,11 +2872,12 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
28682872
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
28692873
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
28702874
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
2871-
NFT_SET_MAP | NFT_SET_EVAL))
2875+
NFT_SET_MAP | NFT_SET_EVAL |
2876+
NFT_SET_OBJECT))
28722877
return -EINVAL;
2873-
/* Only one of both operations is supported */
2874-
if ((flags & (NFT_SET_MAP | NFT_SET_EVAL)) ==
2875-
(NFT_SET_MAP | NFT_SET_EVAL))
2878+
/* Only one of these operations is supported */
2879+
if ((flags & (NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT)) ==
2880+
(NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT))
28762881
return -EOPNOTSUPP;
28772882
}
28782883

@@ -2897,6 +2902,19 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
28972902
} else if (flags & NFT_SET_MAP)
28982903
return -EINVAL;
28992904

2905+
if (nla[NFTA_SET_OBJ_TYPE] != NULL) {
2906+
if (!(flags & NFT_SET_OBJECT))
2907+
return -EINVAL;
2908+
2909+
objtype = ntohl(nla_get_be32(nla[NFTA_SET_OBJ_TYPE]));
2910+
if (objtype == NFT_OBJECT_UNSPEC ||
2911+
objtype > NFT_OBJECT_MAX)
2912+
return -EINVAL;
2913+
} else if (flags & NFT_SET_OBJECT)
2914+
return -EINVAL;
2915+
else
2916+
objtype = NFT_OBJECT_UNSPEC;
2917+
29002918
timeout = 0;
29012919
if (nla[NFTA_SET_TIMEOUT] != NULL) {
29022920
if (!(flags & NFT_SET_TIMEOUT))
@@ -2984,6 +3002,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
29843002
set->ktype = ktype;
29853003
set->klen = desc.klen;
29863004
set->dtype = dtype;
3005+
set->objtype = objtype;
29873006
set->dlen = desc.dlen;
29883007
set->flags = flags;
29893008
set->size = desc.size;
@@ -3126,6 +3145,10 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
31263145
[NFT_SET_EXT_EXPR] = {
31273146
.align = __alignof__(struct nft_expr),
31283147
},
3148+
[NFT_SET_EXT_OBJREF] = {
3149+
.len = sizeof(struct nft_object *),
3150+
.align = __alignof__(struct nft_object *),
3151+
},
31293152
[NFT_SET_EXT_FLAGS] = {
31303153
.len = sizeof(u8),
31313154
.align = __alignof__(u8),
@@ -3214,6 +3237,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
32143237
nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, nft_set_ext_expr(ext)) < 0)
32153238
goto nla_put_failure;
32163239

3240+
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) &&
3241+
nla_put_string(skb, NFTA_SET_ELEM_OBJREF,
3242+
(*nft_set_ext_obj(ext))->name) < 0)
3243+
goto nla_put_failure;
3244+
32173245
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
32183246
nla_put_be32(skb, NFTA_SET_ELEM_FLAGS,
32193247
htonl(*nft_set_ext_flags(ext))))
@@ -3508,7 +3536,8 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
35083536
nft_data_uninit(nft_set_ext_data(ext), set->dtype);
35093537
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
35103538
nf_tables_expr_destroy(NULL, nft_set_ext_expr(ext));
3511-
3539+
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
3540+
(*nft_set_ext_obj(ext))->use--;
35123541
kfree(elem);
35133542
}
35143543
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
@@ -3533,11 +3562,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
35333562
const struct nlattr *attr, u32 nlmsg_flags)
35343563
{
35353564
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
3565+
u8 genmask = nft_genmask_next(ctx->net);
35363566
struct nft_data_desc d1, d2;
35373567
struct nft_set_ext_tmpl tmpl;
35383568
struct nft_set_ext *ext, *ext2;
35393569
struct nft_set_elem elem;
35403570
struct nft_set_binding *binding;
3571+
struct nft_object *obj = NULL;
35413572
struct nft_userdata *udata;
35423573
struct nft_data data;
35433574
enum nft_registers dreg;
@@ -3600,6 +3631,20 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
36003631
nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
36013632
}
36023633

3634+
if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
3635+
if (!(set->flags & NFT_SET_OBJECT)) {
3636+
err = -EINVAL;
3637+
goto err2;
3638+
}
3639+
obj = nf_tables_obj_lookup(ctx->table, nla[NFTA_SET_ELEM_OBJREF],
3640+
set->objtype, genmask);
3641+
if (IS_ERR(obj)) {
3642+
err = PTR_ERR(obj);
3643+
goto err2;
3644+
}
3645+
nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
3646+
}
3647+
36033648
if (nla[NFTA_SET_ELEM_DATA] != NULL) {
36043649
err = nft_data_init(ctx, &data, sizeof(data), &d2,
36053650
nla[NFTA_SET_ELEM_DATA]);
@@ -3658,6 +3703,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
36583703
udata->len = ulen - 1;
36593704
nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
36603705
}
3706+
if (obj) {
3707+
*nft_set_ext_obj(ext) = obj;
3708+
obj->use++;
3709+
}
36613710

36623711
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
36633712
if (trans == NULL)
@@ -3667,10 +3716,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
36673716
err = set->ops->insert(ctx->net, set, &elem, &ext2);
36683717
if (err) {
36693718
if (err == -EEXIST) {
3670-
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
3671-
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
3672-
memcmp(nft_set_ext_data(ext),
3673-
nft_set_ext_data(ext2), set->dlen) != 0)
3719+
if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
3720+
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
3721+
memcmp(nft_set_ext_data(ext),
3722+
nft_set_ext_data(ext2), set->dlen) != 0) ||
3723+
(nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) &&
3724+
nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF) &&
3725+
*nft_set_ext_obj(ext) != *nft_set_ext_obj(ext2)))
36743726
err = -EBUSY;
36753727
else if (!(nlmsg_flags & NLM_F_EXCL))
36763728
err = 0;

0 commit comments

Comments
 (0)