aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2015-04-10 21:27:39 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2015-04-13 11:17:31 -0400
commit7d7402642eaf385aef0772eff5a35e34fc4995d7 (patch)
tree340e51ce8070314a423634a21a3dc31fe3e6b0c9
parentd0a11fc3dc4ab4c717642c9c15c8ad1cbc00d2ec (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.h5
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h3
-rw-r--r--net/netfilter/nf_tables_api.c27
-rw-r--r--net/netfilter/nft_hash.c4
-rw-r--r--net/netfilter/nft_rbtree.c3
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 */
160struct nft_set_elem { 160struct 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
2855const struct nft_set_ext_type nft_set_ext_types[] = { 2854const 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);
3395err2: 3392err2:
3396 nft_data_uninit(&elem.key, d1.type); 3393 nft_data_uninit(&elem.key.val, d1.type);
3397err1: 3394err1:
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,
3488err3: 3485err3:
3489 kfree(trans); 3486 kfree(trans);
3490err2: 3487err2:
3491 nft_data_uninit(&elem.key, desc.type); 3488 nft_data_uninit(&elem.key.val, desc.type);
3492err1: 3489err1:
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)