Skip to content

Commit f3a2181

Browse files
sbrivio-rhummakynes
authored andcommitted
netfilter: nf_tables: Support for sets with multiple ranged fields
Introduce a new nested netlink attribute, NFTA_SET_DESC_CONCAT, used to specify the length of each field in a set concatenation. This allows set implementations to support concatenation of multiple ranged items, as they can divide the input key into matching data for every single field. Such set implementations would be selected as they specify support for NFT_SET_INTERVAL and allow desc->field_count to be greater than one. Explicitly disallow this for nft_set_rbtree. In order to specify the interval for a set entry, userspace would include in NFTA_SET_DESC_CONCAT attributes field lengths, and pass range endpoints as two separate keys, represented by attributes NFTA_SET_ELEM_KEY and NFTA_SET_ELEM_KEY_END. While at it, export the number of 32-bit registers available for packet matching, as nftables will need this to know the maximum number of field lengths that can be specified. For example, "packets with an IPv4 address between 192.0.2.0 and 192.0.2.42, with destination port between 22 and 25", can be expressed as two concatenated elements: NFTA_SET_ELEM_KEY: 192.0.2.0 . 22 NFTA_SET_ELEM_KEY_END: 192.0.2.42 . 25 and NFTA_SET_DESC_CONCAT attribute would contain: NFTA_LIST_ELEM NFTA_SET_FIELD_LEN: 4 NFTA_LIST_ELEM NFTA_SET_FIELD_LEN: 2 v4: No changes v3: Complete rework, NFTA_SET_DESC_CONCAT instead of NFTA_SET_SUBKEY v2: No changes Signed-off-by: Stefano Brivio <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 7b225d0 commit f3a2181

File tree

4 files changed

+115
-1
lines changed

4 files changed

+115
-1
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,15 @@ struct nft_set_iter {
264264
* @klen: key length
265265
* @dlen: data length
266266
* @size: number of set elements
267+
* @field_len: length of each field in concatenation, bytes
268+
* @field_count: number of concatenated fields in element
267269
*/
268270
struct nft_set_desc {
269271
unsigned int klen;
270272
unsigned int dlen;
271273
unsigned int size;
274+
u8 field_len[NFT_REG32_COUNT];
275+
u8 field_count;
272276
};
273277

274278
/**
@@ -409,6 +413,8 @@ void nft_unregister_set(struct nft_set_type *type);
409413
* @dtype: data type (verdict or numeric type defined by userspace)
410414
* @objtype: object type (see NFT_OBJECT_* definitions)
411415
* @size: maximum set size
416+
* @field_len: length of each field in concatenation, bytes
417+
* @field_count: number of concatenated fields in element
412418
* @use: number of rules references to this set
413419
* @nelems: number of elements
414420
* @ndeact: number of deactivated elements queued for removal
@@ -435,6 +441,8 @@ struct nft_set {
435441
u32 dtype;
436442
u32 objtype;
437443
u32 size;
444+
u8 field_len[NFT_REG32_COUNT];
445+
u8 field_count;
438446
u32 use;
439447
atomic_t nelems;
440448
u32 ndeact;

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ enum nft_registers {
4848

4949
#define NFT_REG_SIZE 16
5050
#define NFT_REG32_SIZE 4
51+
#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1)
5152

5253
/**
5354
* enum nft_verdicts - nf_tables internal verdicts
@@ -301,14 +302,28 @@ enum nft_set_policies {
301302
* enum nft_set_desc_attributes - set element description
302303
*
303304
* @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
305+
* @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED)
304306
*/
305307
enum nft_set_desc_attributes {
306308
NFTA_SET_DESC_UNSPEC,
307309
NFTA_SET_DESC_SIZE,
310+
NFTA_SET_DESC_CONCAT,
308311
__NFTA_SET_DESC_MAX
309312
};
310313
#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
311314

315+
/**
316+
* enum nft_set_field_attributes - attributes of concatenated fields
317+
*
318+
* @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32)
319+
*/
320+
enum nft_set_field_attributes {
321+
NFTA_SET_FIELD_UNSPEC,
322+
NFTA_SET_FIELD_LEN,
323+
__NFTA_SET_FIELD_MAX
324+
};
325+
#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1)
326+
312327
/**
313328
* enum nft_set_attributes - nf_tables set netlink attributes
314329
*

net/netfilter/nf_tables_api.c

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3391,6 +3391,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
33913391

33923392
static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
33933393
[NFTA_SET_DESC_SIZE] = { .type = NLA_U32 },
3394+
[NFTA_SET_DESC_CONCAT] = { .type = NLA_NESTED },
33943395
};
33953396

33963397
static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
@@ -3557,6 +3558,33 @@ static __be64 nf_jiffies64_to_msecs(u64 input)
35573558
return cpu_to_be64(jiffies64_to_msecs(input));
35583559
}
35593560

3561+
static int nf_tables_fill_set_concat(struct sk_buff *skb,
3562+
const struct nft_set *set)
3563+
{
3564+
struct nlattr *concat, *field;
3565+
int i;
3566+
3567+
concat = nla_nest_start_noflag(skb, NFTA_SET_DESC_CONCAT);
3568+
if (!concat)
3569+
return -ENOMEM;
3570+
3571+
for (i = 0; i < set->field_count; i++) {
3572+
field = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
3573+
if (!field)
3574+
return -ENOMEM;
3575+
3576+
if (nla_put_be32(skb, NFTA_SET_FIELD_LEN,
3577+
htonl(set->field_len[i])))
3578+
return -ENOMEM;
3579+
3580+
nla_nest_end(skb, field);
3581+
}
3582+
3583+
nla_nest_end(skb, concat);
3584+
3585+
return 0;
3586+
}
3587+
35603588
static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
35613589
const struct nft_set *set, u16 event, u16 flags)
35623590
{
@@ -3620,11 +3648,17 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
36203648
goto nla_put_failure;
36213649

36223650
desc = nla_nest_start_noflag(skb, NFTA_SET_DESC);
3651+
36233652
if (desc == NULL)
36243653
goto nla_put_failure;
36253654
if (set->size &&
36263655
nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size)))
36273656
goto nla_put_failure;
3657+
3658+
if (set->field_count > 1 &&
3659+
nf_tables_fill_set_concat(skb, set))
3660+
goto nla_put_failure;
3661+
36283662
nla_nest_end(skb, desc);
36293663

36303664
nlmsg_end(skb, nlh);
@@ -3797,6 +3831,53 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
37973831
return err;
37983832
}
37993833

3834+
static const struct nla_policy nft_concat_policy[NFTA_SET_FIELD_MAX + 1] = {
3835+
[NFTA_SET_FIELD_LEN] = { .type = NLA_U32 },
3836+
};
3837+
3838+
static int nft_set_desc_concat_parse(const struct nlattr *attr,
3839+
struct nft_set_desc *desc)
3840+
{
3841+
struct nlattr *tb[NFTA_SET_FIELD_MAX + 1];
3842+
u32 len;
3843+
int err;
3844+
3845+
err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr,
3846+
nft_concat_policy, NULL);
3847+
if (err < 0)
3848+
return err;
3849+
3850+
if (!tb[NFTA_SET_FIELD_LEN])
3851+
return -EINVAL;
3852+
3853+
len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN]));
3854+
3855+
if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT)
3856+
return -E2BIG;
3857+
3858+
desc->field_len[desc->field_count++] = len;
3859+
3860+
return 0;
3861+
}
3862+
3863+
static int nft_set_desc_concat(struct nft_set_desc *desc,
3864+
const struct nlattr *nla)
3865+
{
3866+
struct nlattr *attr;
3867+
int rem, err;
3868+
3869+
nla_for_each_nested(attr, nla, rem) {
3870+
if (nla_type(attr) != NFTA_LIST_ELEM)
3871+
return -EINVAL;
3872+
3873+
err = nft_set_desc_concat_parse(attr, desc);
3874+
if (err < 0)
3875+
return err;
3876+
}
3877+
3878+
return 0;
3879+
}
3880+
38003881
static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
38013882
const struct nlattr *nla)
38023883
{
@@ -3810,8 +3891,10 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
38103891

38113892
if (da[NFTA_SET_DESC_SIZE] != NULL)
38123893
desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE]));
3894+
if (da[NFTA_SET_DESC_CONCAT])
3895+
err = nft_set_desc_concat(desc, da[NFTA_SET_DESC_CONCAT]);
38133896

3814-
return 0;
3897+
return err;
38153898
}
38163899

38173900
static int nf_tables_newset(struct net *net, struct sock *nlsk,
@@ -3834,6 +3917,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
38343917
unsigned char *udata;
38353918
u16 udlen;
38363919
int err;
3920+
int i;
38373921

38383922
if (nla[NFTA_SET_TABLE] == NULL ||
38393923
nla[NFTA_SET_NAME] == NULL ||
@@ -4012,6 +4096,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
40124096
set->gc_int = gc_int;
40134097
set->handle = nf_tables_alloc_handle(table);
40144098

4099+
set->field_count = desc.field_count;
4100+
for (i = 0; i < desc.field_count; i++)
4101+
set->field_len[i] = desc.field_len[i];
4102+
40154103
err = ops->init(set, &desc, nla);
40164104
if (err < 0)
40174105
goto err3;

net/netfilter/nft_set_rbtree.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ static void nft_rbtree_destroy(const struct nft_set *set)
466466
static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
467467
struct nft_set_estimate *est)
468468
{
469+
if (desc->field_count > 1)
470+
return false;
471+
469472
if (desc->size)
470473
est->size = sizeof(struct nft_rbtree) +
471474
desc->size * sizeof(struct nft_rbtree_elem);

0 commit comments

Comments
 (0)