1 From: Harsha Sharma <harshasharmaiitr@gmail.com>
2 Date: Wed, 27 Dec 2017 00:59:00 +0530
3 Subject: [PATCH] netfilter: nf_tables: allocate handle and delete objects via
6 This patch allows deletion of objects via unique handle which can be
7 listed via '-a' option.
9 Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com>
10 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
13 --- a/include/net/netfilter/nf_tables.h
14 +++ b/include/net/netfilter/nf_tables.h
15 @@ -376,6 +376,7 @@ void nft_unregister_set(struct nft_set_t
16 * @bindings: list of set bindings
17 * @table: table this set belongs to
18 * @name: name of the set
19 + * @handle: unique handle of the set
20 * @ktype: key type (numeric type defined by userspace, not used in the kernel)
21 * @dtype: data type (verdict or numeric type defined by userspace)
22 * @objtype: object type (see NFT_OBJECT_* definitions)
23 @@ -400,6 +401,7 @@ struct nft_set {
24 struct list_head bindings;
25 struct nft_table *table;
31 @@ -991,6 +993,7 @@ static inline void nft_use_inc_restore(u
32 * @objects: stateful objects in the table
33 * @flowtables: flow tables in the table
34 * @hgenerator: handle generator state
35 + * @handle: table handle
36 * @use: number of chain references to this table
37 * @flags: table flag (see enum nft_table_flags)
38 * @genmask: generation mask
39 @@ -1004,6 +1007,7 @@ struct nft_table {
40 struct list_head objects;
41 struct list_head flowtables;
47 @@ -1028,14 +1032,15 @@ int nft_verdict_dump(struct sk_buff *skb
48 * @name: name of this stateful object
49 * @genmask: generation mask
50 * @use: number of references to this stateful object
51 - * @data: object data, layout depends on type
52 + * @handle: unique object handle
53 * @ops: object operations
54 - * @data: pointer to object data
55 + * @data: object data, layout depends on type
58 struct list_head list;
60 struct nft_table *table;
64 /* runtime data below here */
65 @@ -1119,6 +1124,7 @@ void nft_unregister_obj(struct nft_objec
66 * @ops_len: number of hooks in array
67 * @genmask: generation mask
68 * @use: number of references to this flow table
69 + * @handle: unique object handle
70 * @data: rhashtable and garbage collector
71 * @ops: array of hooks
73 @@ -1131,6 +1137,7 @@ struct nft_flowtable {
78 /* runtime data below here */
79 struct nf_hook_ops *ops ____cacheline_aligned;
80 struct nf_flowtable data;
81 --- a/include/uapi/linux/netfilter/nf_tables.h
82 +++ b/include/uapi/linux/netfilter/nf_tables.h
83 @@ -174,6 +174,8 @@ enum nft_table_attributes {
91 #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
92 @@ -317,6 +319,7 @@ enum nft_set_desc_attributes {
93 * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
94 * @NFTA_SET_USERDATA: user data (NLA_BINARY)
95 * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
96 + * @NFTA_SET_HANDLE: set handle (NLA_U64)
98 enum nft_set_attributes {
100 @@ -335,6 +338,7 @@ enum nft_set_attributes {
107 #define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
108 @@ -1314,6 +1318,7 @@ enum nft_ct_helper_attributes {
109 * @NFTA_OBJ_TYPE: stateful object type (NLA_U32)
110 * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
111 * @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
112 + * @NFTA_OBJ_HANDLE: object handle (NLA_U64)
114 enum nft_object_attributes {
116 @@ -1322,6 +1327,8 @@ enum nft_object_attributes {
124 #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
125 @@ -1333,6 +1340,7 @@ enum nft_object_attributes {
126 * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
127 * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
128 * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
129 + * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
131 enum nft_flowtable_attributes {
132 NFTA_FLOWTABLE_UNSPEC,
133 @@ -1340,6 +1348,8 @@ enum nft_flowtable_attributes {
137 + NFTA_FLOWTABLE_HANDLE,
138 + NFTA_FLOWTABLE_PAD,
141 #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
142 --- a/net/netfilter/nf_tables_api.c
143 +++ b/net/netfilter/nf_tables_api.c
145 static LIST_HEAD(nf_tables_expressions);
146 static LIST_HEAD(nf_tables_objects);
147 static LIST_HEAD(nf_tables_flowtables);
148 +static u64 table_handle;
150 static void nft_ctx_init(struct nft_ctx *ctx,
152 @@ -399,6 +400,20 @@ static struct nft_table *nft_table_looku
156 +static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
157 + const struct nlattr *nla,
160 + struct nft_table *table;
162 + list_for_each_entry(table, &net->nft.tables, list) {
163 + if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
164 + nft_active_genmask(table, genmask))
170 static struct nft_table *nf_tables_table_lookup(const struct net *net,
171 const struct nlattr *nla,
172 u8 family, u8 genmask)
173 @@ -415,6 +430,22 @@ static struct nft_table *nf_tables_table
174 return ERR_PTR(-ENOENT);
177 +static struct nft_table *nf_tables_table_lookup_byhandle(const struct net *net,
178 + const struct nlattr *nla,
181 + struct nft_table *table;
184 + return ERR_PTR(-EINVAL);
186 + table = nft_table_lookup_byhandle(net, nla, genmask);
190 + return ERR_PTR(-ENOENT);
193 static inline u64 nf_tables_alloc_handle(struct nft_table *table)
195 return ++table->hgenerator;
196 @@ -461,6 +492,7 @@ static const struct nla_policy nft_table
197 [NFTA_TABLE_NAME] = { .type = NLA_STRING,
198 .len = NFT_TABLE_MAXNAMELEN - 1 },
199 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
200 + [NFTA_TABLE_HANDLE] = { .type = NLA_U64 },
203 static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
204 @@ -482,7 +514,9 @@ static int nf_tables_fill_table_info(str
206 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
207 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
208 - nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
209 + nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
210 + nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
212 goto nla_put_failure;
215 @@ -741,6 +775,7 @@ static int nf_tables_newtable(struct net
216 INIT_LIST_HEAD(&table->flowtables);
217 table->family = family;
218 table->flags = flags;
219 + table->handle = ++table_handle;
221 nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
222 err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
223 @@ -858,11 +893,18 @@ static int nf_tables_deltable(struct net
226 nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla);
227 - if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
228 + if (family == AF_UNSPEC ||
229 + (!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE]))
230 return nft_flush(&ctx, family);
232 - table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], family,
234 + if (nla[NFTA_TABLE_HANDLE])
235 + table = nf_tables_table_lookup_byhandle(net,
236 + nla[NFTA_TABLE_HANDLE],
239 + table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME],
243 return PTR_ERR(table);
245 @@ -1622,6 +1664,7 @@ static int nf_tables_delchain(struct net
246 struct nft_rule *rule;
247 int family = nfmsg->nfgen_family;
253 @@ -1630,7 +1673,12 @@ static int nf_tables_delchain(struct net
255 return PTR_ERR(table);
257 - chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
258 + if (nla[NFTA_CHAIN_HANDLE]) {
259 + handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
260 + chain = nf_tables_chain_lookup_byhandle(table, handle, genmask);
262 + chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
265 return PTR_ERR(chain);
267 @@ -2609,6 +2657,7 @@ static const struct nla_policy nft_set_p
268 [NFTA_SET_USERDATA] = { .type = NLA_BINARY,
269 .len = NFT_USERDATA_MAXLEN },
270 [NFTA_SET_OBJ_TYPE] = { .type = NLA_U32 },
271 + [NFTA_SET_HANDLE] = { .type = NLA_U64 },
274 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
275 @@ -2652,6 +2701,22 @@ static struct nft_set *nf_tables_set_loo
276 return ERR_PTR(-ENOENT);
279 +static struct nft_set *nf_tables_set_lookup_byhandle(const struct nft_table *table,
280 + const struct nlattr *nla, u8 genmask)
282 + struct nft_set *set;
285 + return ERR_PTR(-EINVAL);
287 + list_for_each_entry(set, &table->sets, list) {
288 + if (be64_to_cpu(nla_get_be64(nla)) == set->handle &&
289 + nft_active_genmask(set, genmask))
292 + return ERR_PTR(-ENOENT);
295 static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
296 const struct nft_table *table,
297 const struct nlattr *nla,
298 @@ -2770,6 +2835,9 @@ static int nf_tables_fill_set(struct sk_
299 goto nla_put_failure;
300 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
301 goto nla_put_failure;
302 + if (nla_put_be64(skb, NFTA_SET_HANDLE, cpu_to_be64(set->handle),
304 + goto nla_put_failure;
306 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
307 goto nla_put_failure;
308 @@ -3188,6 +3256,7 @@ static int nf_tables_newset(struct net *
310 set->timeout = timeout;
311 set->gc_int = gc_int;
312 + set->handle = nf_tables_alloc_handle(table);
314 err = ops->init(set, &desc, nla);
316 @@ -3245,7 +3314,10 @@ static int nf_tables_delset(struct net *
320 - set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
321 + if (nla[NFTA_SET_HANDLE])
322 + set = nf_tables_set_lookup_byhandle(ctx.table, nla[NFTA_SET_HANDLE], genmask);
324 + set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
328 @@ -4416,6 +4488,21 @@ struct nft_object *nf_tables_obj_lookup(
330 EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
332 +struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
333 + const struct nlattr *nla,
334 + u32 objtype, u8 genmask)
336 + struct nft_object *obj;
338 + list_for_each_entry(obj, &table->objects, list) {
339 + if (be64_to_cpu(nla_get_be64(nla)) == obj->handle &&
340 + objtype == obj->ops->type->type &&
341 + nft_active_genmask(obj, genmask))
344 + return ERR_PTR(-ENOENT);
347 static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
348 [NFTA_OBJ_TABLE] = { .type = NLA_STRING,
349 .len = NFT_TABLE_MAXNAMELEN - 1 },
350 @@ -4423,6 +4510,7 @@ static const struct nla_policy nft_obj_p
351 .len = NFT_OBJ_MAXNAMELEN - 1 },
352 [NFTA_OBJ_TYPE] = { .type = NLA_U32 },
353 [NFTA_OBJ_DATA] = { .type = NLA_NESTED },
354 + [NFTA_OBJ_HANDLE] = { .type = NLA_U64},
357 static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
358 @@ -4575,6 +4663,8 @@ static int nf_tables_newobj(struct net *
362 + obj->handle = nf_tables_alloc_handle(table);
364 obj->name = nla_strdup(nla[NFTA_OBJ_NAME], GFP_KERNEL);
367 @@ -4624,7 +4714,9 @@ static int nf_tables_fill_obj_info(struc
368 nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
369 nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
370 nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
371 - nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
372 + nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset) ||
373 + nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle),
375 goto nla_put_failure;
378 @@ -4822,7 +4914,7 @@ static int nf_tables_delobj(struct net *
381 if (!nla[NFTA_OBJ_TYPE] ||
382 - !nla[NFTA_OBJ_NAME])
383 + (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE]))
386 table = nf_tables_table_lookup(net, nla[NFTA_OBJ_TABLE], family,
387 @@ -4831,7 +4923,12 @@ static int nf_tables_delobj(struct net *
388 return PTR_ERR(table);
390 objtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
391 - obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], objtype, genmask);
392 + if (nla[NFTA_OBJ_HANDLE])
393 + obj = nf_tables_obj_lookup_byhandle(table, nla[NFTA_OBJ_HANDLE],
396 + obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME],
401 @@ -4903,6 +5000,7 @@ static const struct nla_policy nft_flowt
402 [NFTA_FLOWTABLE_NAME] = { .type = NLA_STRING,
403 .len = NFT_NAME_MAXLEN - 1 },
404 [NFTA_FLOWTABLE_HOOK] = { .type = NLA_NESTED },
405 + [NFTA_FLOWTABLE_HANDLE] = { .type = NLA_U64 },
408 struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
409 @@ -4920,6 +5018,20 @@ struct nft_flowtable *nf_tables_flowtabl
411 EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
413 +struct nft_flowtable *
414 +nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
415 + const struct nlattr *nla, u8 genmask)
417 + struct nft_flowtable *flowtable;
419 + list_for_each_entry(flowtable, &table->flowtables, list) {
420 + if (be64_to_cpu(nla_get_be64(nla)) == flowtable->handle &&
421 + nft_active_genmask(flowtable, genmask))
424 + return ERR_PTR(-ENOENT);
427 #define NFT_FLOWTABLE_DEVICE_MAX 8
429 static int nf_tables_parse_devices(const struct nft_ctx *ctx,
430 @@ -5128,6 +5240,8 @@ static int nf_tables_newflowtable(struct
433 flowtable->table = table;
434 + flowtable->handle = nf_tables_alloc_handle(table);
436 flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL);
437 if (!flowtable->name) {
439 @@ -5202,8 +5316,14 @@ static int nf_tables_delflowtable(struct
441 return PTR_ERR(table);
443 - flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
445 + if (nla[NFTA_FLOWTABLE_HANDLE])
446 + flowtable = nf_tables_flowtable_lookup_byhandle(table,
447 + nla[NFTA_FLOWTABLE_HANDLE],
450 + flowtable = nf_tables_flowtable_lookup(table,
451 + nla[NFTA_FLOWTABLE_NAME],
453 if (IS_ERR(flowtable))
454 return PTR_ERR(flowtable);
455 if (flowtable->use > 0)
456 @@ -5236,7 +5356,9 @@ static int nf_tables_fill_flowtable_info
458 if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
459 nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
460 - nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)))
461 + nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
462 + nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
463 + NFTA_FLOWTABLE_PAD))
464 goto nla_put_failure;
466 nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);