diff options
author | Patrick McHardy <kaber@trash.net> | 2015-04-10 21:27:39 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-04-13 11:17:31 -0400 |
commit | 7d7402642eaf385aef0772eff5a35e34fc4995d7 (patch) | |
tree | 340e51ce8070314a423634a21a3dc31fe3e6b0c9 | |
parent | d0a11fc3dc4ab4c717642c9c15c8ad1cbc00d2ec (diff) |
netfilter: nf_tables: variable sized set element keys / data
This patch changes sets to support variable sized set element keys / data
up to 64 bytes each by using variable sized set extensions. This allows
to use concatenations with bigger data items suchs as IPv6 addresses.
As a side effect, small keys/data now don't require the full 16 bytes
of struct nft_data anymore but just the space they need.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/net/netfilter/nf_tables.h | 5 | ||||
-rw-r--r-- | include/uapi/linux/netfilter/nf_tables.h | 3 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 27 | ||||
-rw-r--r-- | net/netfilter/nft_hash.c | 4 | ||||
-rw-r--r-- | net/netfilter/nft_rbtree.c | 3 |
5 files changed, 23 insertions, 19 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 160577bf0f0a..cb42da1011ef 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -158,7 +158,10 @@ struct nft_userdata { | |||
158 | * @priv: element private data and extensions | 158 | * @priv: element private data and extensions |
159 | */ | 159 | */ |
160 | struct nft_set_elem { | 160 | struct nft_set_elem { |
161 | struct nft_data key; | 161 | union { |
162 | u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)]; | ||
163 | struct nft_data val; | ||
164 | } key; | ||
162 | void *priv; | 165 | void *priv; |
163 | }; | 166 | }; |
164 | 167 | ||
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 4221a6c3a8a5..be8584c95297 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h | |||
@@ -388,6 +388,9 @@ enum nft_data_attributes { | |||
388 | }; | 388 | }; |
389 | #define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1) | 389 | #define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1) |
390 | 390 | ||
391 | /* Maximum length of a value */ | ||
392 | #define NFT_DATA_VALUE_MAXLEN 64 | ||
393 | |||
391 | /** | 394 | /** |
392 | * enum nft_verdict_attributes - nf_tables verdict netlink attributes | 395 | * enum nft_verdict_attributes - nf_tables verdict netlink attributes |
393 | * | 396 | * |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2b3f88f4c70f..ed0e70ea2bc5 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -2608,7 +2608,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
2608 | } | 2608 | } |
2609 | 2609 | ||
2610 | desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN])); | 2610 | desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN])); |
2611 | if (desc.klen == 0 || desc.klen > FIELD_SIZEOF(struct nft_data, data)) | 2611 | if (desc.klen == 0 || desc.klen > NFT_DATA_VALUE_MAXLEN) |
2612 | return -EINVAL; | 2612 | return -EINVAL; |
2613 | 2613 | ||
2614 | flags = 0; | 2614 | flags = 0; |
@@ -2634,11 +2634,10 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
2634 | if (nla[NFTA_SET_DATA_LEN] == NULL) | 2634 | if (nla[NFTA_SET_DATA_LEN] == NULL) |
2635 | return -EINVAL; | 2635 | return -EINVAL; |
2636 | desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN])); | 2636 | desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN])); |
2637 | if (desc.dlen == 0 || | 2637 | if (desc.dlen == 0 || desc.dlen > NFT_DATA_VALUE_MAXLEN) |
2638 | desc.dlen > FIELD_SIZEOF(struct nft_data, data)) | ||
2639 | return -EINVAL; | 2638 | return -EINVAL; |
2640 | } else | 2639 | } else |
2641 | desc.dlen = sizeof(struct nft_data); | 2640 | desc.dlen = sizeof(struct nft_verdict); |
2642 | } else if (flags & NFT_SET_MAP) | 2641 | } else if (flags & NFT_SET_MAP) |
2643 | return -EINVAL; | 2642 | return -EINVAL; |
2644 | 2643 | ||
@@ -2854,12 +2853,10 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, | |||
2854 | 2853 | ||
2855 | const struct nft_set_ext_type nft_set_ext_types[] = { | 2854 | const struct nft_set_ext_type nft_set_ext_types[] = { |
2856 | [NFT_SET_EXT_KEY] = { | 2855 | [NFT_SET_EXT_KEY] = { |
2857 | .len = sizeof(struct nft_data), | 2856 | .align = __alignof__(u32), |
2858 | .align = __alignof__(struct nft_data), | ||
2859 | }, | 2857 | }, |
2860 | [NFT_SET_EXT_DATA] = { | 2858 | [NFT_SET_EXT_DATA] = { |
2861 | .len = sizeof(struct nft_data), | 2859 | .align = __alignof__(u32), |
2862 | .align = __alignof__(struct nft_data), | ||
2863 | }, | 2860 | }, |
2864 | [NFT_SET_EXT_FLAGS] = { | 2861 | [NFT_SET_EXT_FLAGS] = { |
2865 | .len = sizeof(u8), | 2862 | .len = sizeof(u8), |
@@ -3299,7 +3296,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
3299 | timeout = set->timeout; | 3296 | timeout = set->timeout; |
3300 | } | 3297 | } |
3301 | 3298 | ||
3302 | err = nft_data_init(ctx, &elem.key, sizeof(elem.key), &d1, | 3299 | err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1, |
3303 | nla[NFTA_SET_ELEM_KEY]); | 3300 | nla[NFTA_SET_ELEM_KEY]); |
3304 | if (err < 0) | 3301 | if (err < 0) |
3305 | goto err1; | 3302 | goto err1; |
@@ -3307,7 +3304,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
3307 | if (d1.type != NFT_DATA_VALUE || d1.len != set->klen) | 3304 | if (d1.type != NFT_DATA_VALUE || d1.len != set->klen) |
3308 | goto err2; | 3305 | goto err2; |
3309 | 3306 | ||
3310 | nft_set_ext_add(&tmpl, NFT_SET_EXT_KEY); | 3307 | nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len); |
3311 | if (timeout > 0) { | 3308 | if (timeout > 0) { |
3312 | nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION); | 3309 | nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION); |
3313 | if (timeout != set->timeout) | 3310 | if (timeout != set->timeout) |
@@ -3342,7 +3339,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
3342 | goto err3; | 3339 | goto err3; |
3343 | } | 3340 | } |
3344 | 3341 | ||
3345 | nft_set_ext_add(&tmpl, NFT_SET_EXT_DATA); | 3342 | nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len); |
3346 | } | 3343 | } |
3347 | 3344 | ||
3348 | /* The full maximum length of userdata can exceed the maximum | 3345 | /* The full maximum length of userdata can exceed the maximum |
@@ -3358,7 +3355,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
3358 | } | 3355 | } |
3359 | 3356 | ||
3360 | err = -ENOMEM; | 3357 | err = -ENOMEM; |
3361 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.data, data.data, | 3358 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data, |
3362 | timeout, GFP_KERNEL); | 3359 | timeout, GFP_KERNEL); |
3363 | if (elem.priv == NULL) | 3360 | if (elem.priv == NULL) |
3364 | goto err3; | 3361 | goto err3; |
@@ -3393,7 +3390,7 @@ err3: | |||
3393 | if (nla[NFTA_SET_ELEM_DATA] != NULL) | 3390 | if (nla[NFTA_SET_ELEM_DATA] != NULL) |
3394 | nft_data_uninit(&data, d2.type); | 3391 | nft_data_uninit(&data, d2.type); |
3395 | err2: | 3392 | err2: |
3396 | nft_data_uninit(&elem.key, d1.type); | 3393 | nft_data_uninit(&elem.key.val, d1.type); |
3397 | err1: | 3394 | err1: |
3398 | return err; | 3395 | return err; |
3399 | } | 3396 | } |
@@ -3460,7 +3457,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, | |||
3460 | if (nla[NFTA_SET_ELEM_KEY] == NULL) | 3457 | if (nla[NFTA_SET_ELEM_KEY] == NULL) |
3461 | goto err1; | 3458 | goto err1; |
3462 | 3459 | ||
3463 | err = nft_data_init(ctx, &elem.key, sizeof(elem.key), &desc, | 3460 | err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc, |
3464 | nla[NFTA_SET_ELEM_KEY]); | 3461 | nla[NFTA_SET_ELEM_KEY]); |
3465 | if (err < 0) | 3462 | if (err < 0) |
3466 | goto err1; | 3463 | goto err1; |
@@ -3488,7 +3485,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, | |||
3488 | err3: | 3485 | err3: |
3489 | kfree(trans); | 3486 | kfree(trans); |
3490 | err2: | 3487 | err2: |
3491 | nft_data_uninit(&elem.key, desc.type); | 3488 | nft_data_uninit(&elem.key.val, desc.type); |
3492 | err1: | 3489 | err1: |
3493 | return err; | 3490 | return err; |
3494 | } | 3491 | } |
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 767df41d28ea..3f9d45d3d9b7 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c | |||
@@ -133,7 +133,7 @@ static int nft_hash_insert(const struct nft_set *set, | |||
133 | struct nft_hash_cmp_arg arg = { | 133 | struct nft_hash_cmp_arg arg = { |
134 | .genmask = nft_genmask_next(read_pnet(&set->pnet)), | 134 | .genmask = nft_genmask_next(read_pnet(&set->pnet)), |
135 | .set = set, | 135 | .set = set, |
136 | .key = elem->key.data, | 136 | .key = elem->key.val.data, |
137 | }; | 137 | }; |
138 | 138 | ||
139 | return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node, | 139 | return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node, |
@@ -157,7 +157,7 @@ static void *nft_hash_deactivate(const struct nft_set *set, | |||
157 | struct nft_hash_cmp_arg arg = { | 157 | struct nft_hash_cmp_arg arg = { |
158 | .genmask = nft_genmask_next(read_pnet(&set->pnet)), | 158 | .genmask = nft_genmask_next(read_pnet(&set->pnet)), |
159 | .set = set, | 159 | .set = set, |
160 | .key = elem->key.data, | 160 | .key = elem->key.val.data, |
161 | }; | 161 | }; |
162 | 162 | ||
163 | rcu_read_lock(); | 163 | rcu_read_lock(); |
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c index b888e0cdf1e2..1c30f41cff5b 100644 --- a/net/netfilter/nft_rbtree.c +++ b/net/netfilter/nft_rbtree.c | |||
@@ -152,7 +152,8 @@ static void *nft_rbtree_deactivate(const struct nft_set *set, | |||
152 | while (parent != NULL) { | 152 | while (parent != NULL) { |
153 | rbe = rb_entry(parent, struct nft_rbtree_elem, node); | 153 | rbe = rb_entry(parent, struct nft_rbtree_elem, node); |
154 | 154 | ||
155 | d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key, set->klen); | 155 | d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key.val, |
156 | set->klen); | ||
156 | if (d < 0) | 157 | if (d < 0) |
157 | parent = parent->rb_left; | 158 | parent = parent->rb_left; |
158 | else if (d > 0) | 159 | else if (d > 0) |