98ec5d1b7ce8594ace9e716c4bf5daa63e867e50
[openwrt/staging/981213.git] /
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
4 handle
5
6 This patch allows deletion of objects via unique handle which can be
7 listed via '-a' option.
8
9 Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com>
10 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 ---
12
13 --- a/include/net/netfilter/nf_tables.h
14 +++ b/include/net/netfilter/nf_tables.h
15 @@ -370,6 +370,7 @@ void nft_unregister_set(struct nft_set_t
16 * @list: table set list node
17 * @bindings: list of set bindings
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 @@ -392,6 +393,7 @@ struct nft_set {
24 struct list_head list;
25 struct list_head bindings;
26 char *name;
27 + u64 handle;
28 u32 ktype;
29 u32 dtype;
30 u32 objtype;
31 @@ -941,6 +943,7 @@ unsigned int nft_do_chain(struct nft_pkt
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 @@ -954,6 +957,7 @@ struct nft_table {
40 struct list_head objects;
41 struct list_head flowtables;
42 u64 hgenerator;
43 + u64 handle;
44 u32 use;
45 u16 family:6,
46 flags:8,
47 @@ -978,9 +982,9 @@ 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
56 */
57 struct nft_object {
58 struct list_head list;
59 @@ -988,6 +992,7 @@ struct nft_object {
60 struct nft_table *table;
61 u32 genmask:2,
62 use:30;
63 + u64 handle;
64 /* runtime data below here */
65 const struct nft_object_ops *ops ____cacheline_aligned;
66 unsigned char data[]
67 @@ -1069,6 +1074,7 @@ void nft_unregister_obj(struct nft_objec
68 * @ops_len: number of hooks in array
69 * @genmask: generation mask
70 * @use: number of references to this flow table
71 + * @handle: unique object handle
72 * @data: rhashtable and garbage collector
73 * @ops: array of hooks
74 */
75 @@ -1081,6 +1087,7 @@ struct nft_flowtable {
76 int ops_len;
77 u32 genmask:2,
78 use:30;
79 + u64 handle;
80 /* runtime data below here */
81 struct nf_hook_ops *ops ____cacheline_aligned;
82 struct nf_flowtable data;
83 --- a/include/uapi/linux/netfilter/nf_tables.h
84 +++ b/include/uapi/linux/netfilter/nf_tables.h
85 @@ -174,6 +174,8 @@ enum nft_table_attributes {
86 NFTA_TABLE_NAME,
87 NFTA_TABLE_FLAGS,
88 NFTA_TABLE_USE,
89 + NFTA_TABLE_HANDLE,
90 + NFTA_TABLE_PAD,
91 __NFTA_TABLE_MAX
92 };
93 #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
94 @@ -317,6 +319,7 @@ enum nft_set_desc_attributes {
95 * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
96 * @NFTA_SET_USERDATA: user data (NLA_BINARY)
97 * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
98 + * @NFTA_SET_HANDLE: set handle (NLA_U64)
99 */
100 enum nft_set_attributes {
101 NFTA_SET_UNSPEC,
102 @@ -335,6 +338,7 @@ enum nft_set_attributes {
103 NFTA_SET_USERDATA,
104 NFTA_SET_PAD,
105 NFTA_SET_OBJ_TYPE,
106 + NFTA_SET_HANDLE,
107 __NFTA_SET_MAX
108 };
109 #define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
110 @@ -1314,6 +1318,7 @@ enum nft_ct_helper_attributes {
111 * @NFTA_OBJ_TYPE: stateful object type (NLA_U32)
112 * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
113 * @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
114 + * @NFTA_OBJ_HANDLE: object handle (NLA_U64)
115 */
116 enum nft_object_attributes {
117 NFTA_OBJ_UNSPEC,
118 @@ -1322,6 +1327,8 @@ enum nft_object_attributes {
119 NFTA_OBJ_TYPE,
120 NFTA_OBJ_DATA,
121 NFTA_OBJ_USE,
122 + NFTA_OBJ_HANDLE,
123 + NFTA_OBJ_PAD,
124 __NFTA_OBJ_MAX
125 };
126 #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
127 @@ -1333,6 +1340,7 @@ enum nft_object_attributes {
128 * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
129 * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
130 * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
131 + * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
132 */
133 enum nft_flowtable_attributes {
134 NFTA_FLOWTABLE_UNSPEC,
135 @@ -1340,6 +1348,8 @@ enum nft_flowtable_attributes {
136 NFTA_FLOWTABLE_NAME,
137 NFTA_FLOWTABLE_HOOK,
138 NFTA_FLOWTABLE_USE,
139 + NFTA_FLOWTABLE_HANDLE,
140 + NFTA_FLOWTABLE_PAD,
141 __NFTA_FLOWTABLE_MAX
142 };
143 #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
144 --- a/net/netfilter/nf_tables_api.c
145 +++ b/net/netfilter/nf_tables_api.c
146 @@ -26,6 +26,7 @@
147 static LIST_HEAD(nf_tables_expressions);
148 static LIST_HEAD(nf_tables_objects);
149 static LIST_HEAD(nf_tables_flowtables);
150 +static u64 table_handle;
151
152 static void nft_ctx_init(struct nft_ctx *ctx,
153 struct net *net,
154 @@ -361,6 +362,20 @@ static struct nft_table *nft_table_looku
155 return NULL;
156 }
157
158 +static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
159 + const struct nlattr *nla,
160 + u8 genmask)
161 +{
162 + struct nft_table *table;
163 +
164 + list_for_each_entry(table, &net->nft.tables, list) {
165 + if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
166 + nft_active_genmask(table, genmask))
167 + return table;
168 + }
169 + return NULL;
170 +}
171 +
172 static struct nft_table *nf_tables_table_lookup(const struct net *net,
173 const struct nlattr *nla,
174 u8 family, u8 genmask)
175 @@ -377,6 +392,22 @@ static struct nft_table *nf_tables_table
176 return ERR_PTR(-ENOENT);
177 }
178
179 +static struct nft_table *nf_tables_table_lookup_byhandle(const struct net *net,
180 + const struct nlattr *nla,
181 + u8 genmask)
182 +{
183 + struct nft_table *table;
184 +
185 + if (nla == NULL)
186 + return ERR_PTR(-EINVAL);
187 +
188 + table = nft_table_lookup_byhandle(net, nla, genmask);
189 + if (table != NULL)
190 + return table;
191 +
192 + return ERR_PTR(-ENOENT);
193 +}
194 +
195 static inline u64 nf_tables_alloc_handle(struct nft_table *table)
196 {
197 return ++table->hgenerator;
198 @@ -423,6 +454,7 @@ static const struct nla_policy nft_table
199 [NFTA_TABLE_NAME] = { .type = NLA_STRING,
200 .len = NFT_TABLE_MAXNAMELEN - 1 },
201 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
202 + [NFTA_TABLE_HANDLE] = { .type = NLA_U64 },
203 };
204
205 static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
206 @@ -444,7 +476,9 @@ static int nf_tables_fill_table_info(str
207
208 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
209 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
210 - nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
211 + nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
212 + nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
213 + NFTA_TABLE_PAD))
214 goto nla_put_failure;
215
216 nlmsg_end(skb, nlh);
217 @@ -703,6 +737,7 @@ static int nf_tables_newtable(struct net
218 INIT_LIST_HEAD(&table->flowtables);
219 table->family = family;
220 table->flags = flags;
221 + table->handle = ++table_handle;
222
223 nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
224 err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
225 @@ -820,11 +855,18 @@ static int nf_tables_deltable(struct net
226 struct nft_ctx ctx;
227
228 nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla);
229 - if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
230 + if (family == AF_UNSPEC ||
231 + (!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE]))
232 return nft_flush(&ctx, family);
233
234 - table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], family,
235 - genmask);
236 + if (nla[NFTA_TABLE_HANDLE])
237 + table = nf_tables_table_lookup_byhandle(net,
238 + nla[NFTA_TABLE_HANDLE],
239 + genmask);
240 + else
241 + table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME],
242 + family, genmask);
243 +
244 if (IS_ERR(table))
245 return PTR_ERR(table);
246
247 @@ -1581,6 +1623,7 @@ static int nf_tables_delchain(struct net
248 struct nft_rule *rule;
249 int family = nfmsg->nfgen_family;
250 struct nft_ctx ctx;
251 + u64 handle;
252 u32 use;
253 int err;
254
255 @@ -1589,7 +1632,12 @@ static int nf_tables_delchain(struct net
256 if (IS_ERR(table))
257 return PTR_ERR(table);
258
259 - chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
260 + if (nla[NFTA_CHAIN_HANDLE]) {
261 + handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
262 + chain = nf_tables_chain_lookup_byhandle(table, handle, genmask);
263 + } else {
264 + chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
265 + }
266 if (IS_ERR(chain))
267 return PTR_ERR(chain);
268
269 @@ -2563,6 +2611,7 @@ static const struct nla_policy nft_set_p
270 [NFTA_SET_USERDATA] = { .type = NLA_BINARY,
271 .len = NFT_USERDATA_MAXLEN },
272 [NFTA_SET_OBJ_TYPE] = { .type = NLA_U32 },
273 + [NFTA_SET_HANDLE] = { .type = NLA_U64 },
274 };
275
276 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
277 @@ -2606,6 +2655,22 @@ static struct nft_set *nf_tables_set_loo
278 return ERR_PTR(-ENOENT);
279 }
280
281 +static struct nft_set *nf_tables_set_lookup_byhandle(const struct nft_table *table,
282 + const struct nlattr *nla, u8 genmask)
283 +{
284 + struct nft_set *set;
285 +
286 + if (nla == NULL)
287 + return ERR_PTR(-EINVAL);
288 +
289 + list_for_each_entry(set, &table->sets, list) {
290 + if (be64_to_cpu(nla_get_be64(nla)) == set->handle &&
291 + nft_active_genmask(set, genmask))
292 + return set;
293 + }
294 + return ERR_PTR(-ENOENT);
295 +}
296 +
297 static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
298 const struct nlattr *nla,
299 u8 genmask)
300 @@ -2722,6 +2787,9 @@ static int nf_tables_fill_set(struct sk_
301 goto nla_put_failure;
302 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
303 goto nla_put_failure;
304 + if (nla_put_be64(skb, NFTA_SET_HANDLE, cpu_to_be64(set->handle),
305 + NFTA_SET_PAD))
306 + goto nla_put_failure;
307 if (set->flags != 0)
308 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
309 goto nla_put_failure;
310 @@ -3130,6 +3198,7 @@ static int nf_tables_newset(struct net *
311 set->udata = udata;
312 set->timeout = timeout;
313 set->gc_int = gc_int;
314 + set->handle = nf_tables_alloc_handle(table);
315
316 err = ops->init(set, &desc, nla);
317 if (err < 0)
318 @@ -3189,7 +3258,10 @@ static int nf_tables_delset(struct net *
319 if (err < 0)
320 return err;
321
322 - set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
323 + if (nla[NFTA_SET_HANDLE])
324 + set = nf_tables_set_lookup_byhandle(ctx.table, nla[NFTA_SET_HANDLE], genmask);
325 + else
326 + set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
327 if (IS_ERR(set))
328 return PTR_ERR(set);
329
330 @@ -4250,6 +4322,21 @@ struct nft_object *nf_tables_obj_lookup(
331 }
332 EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
333
334 +struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
335 + const struct nlattr *nla,
336 + u32 objtype, u8 genmask)
337 +{
338 + struct nft_object *obj;
339 +
340 + list_for_each_entry(obj, &table->objects, list) {
341 + if (be64_to_cpu(nla_get_be64(nla)) == obj->handle &&
342 + objtype == obj->ops->type->type &&
343 + nft_active_genmask(obj, genmask))
344 + return obj;
345 + }
346 + return ERR_PTR(-ENOENT);
347 +}
348 +
349 static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
350 [NFTA_OBJ_TABLE] = { .type = NLA_STRING,
351 .len = NFT_TABLE_MAXNAMELEN - 1 },
352 @@ -4257,6 +4344,7 @@ static const struct nla_policy nft_obj_p
353 .len = NFT_OBJ_MAXNAMELEN - 1 },
354 [NFTA_OBJ_TYPE] = { .type = NLA_U32 },
355 [NFTA_OBJ_DATA] = { .type = NLA_NESTED },
356 + [NFTA_OBJ_HANDLE] = { .type = NLA_U64},
357 };
358
359 static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
360 @@ -4404,6 +4492,8 @@ static int nf_tables_newobj(struct net *
361 goto err1;
362 }
363 obj->table = table;
364 + obj->handle = nf_tables_alloc_handle(table);
365 +
366 obj->name = nla_strdup(nla[NFTA_OBJ_NAME], GFP_KERNEL);
367 if (!obj->name) {
368 err = -ENOMEM;
369 @@ -4450,7 +4540,9 @@ static int nf_tables_fill_obj_info(struc
370 nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
371 nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
372 nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
373 - nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
374 + nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset) ||
375 + nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle),
376 + NFTA_OBJ_PAD))
377 goto nla_put_failure;
378
379 nlmsg_end(skb, nlh);
380 @@ -4648,7 +4740,7 @@ static int nf_tables_delobj(struct net *
381 u32 objtype;
382
383 if (!nla[NFTA_OBJ_TYPE] ||
384 - !nla[NFTA_OBJ_NAME])
385 + (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE]))
386 return -EINVAL;
387
388 table = nf_tables_table_lookup(net, nla[NFTA_OBJ_TABLE], family,
389 @@ -4657,7 +4749,12 @@ static int nf_tables_delobj(struct net *
390 return PTR_ERR(table);
391
392 objtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
393 - obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], objtype, genmask);
394 + if (nla[NFTA_OBJ_HANDLE])
395 + obj = nf_tables_obj_lookup_byhandle(table, nla[NFTA_OBJ_HANDLE],
396 + objtype, genmask);
397 + else
398 + obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME],
399 + objtype, genmask);
400 if (IS_ERR(obj))
401 return PTR_ERR(obj);
402 if (obj->use > 0)
403 @@ -4729,6 +4826,7 @@ static const struct nla_policy nft_flowt
404 [NFTA_FLOWTABLE_NAME] = { .type = NLA_STRING,
405 .len = NFT_NAME_MAXLEN - 1 },
406 [NFTA_FLOWTABLE_HOOK] = { .type = NLA_NESTED },
407 + [NFTA_FLOWTABLE_HANDLE] = { .type = NLA_U64 },
408 };
409
410 struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
411 @@ -4746,6 +4844,20 @@ struct nft_flowtable *nf_tables_flowtabl
412 }
413 EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
414
415 +struct nft_flowtable *
416 +nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
417 + const struct nlattr *nla, u8 genmask)
418 +{
419 + struct nft_flowtable *flowtable;
420 +
421 + list_for_each_entry(flowtable, &table->flowtables, list) {
422 + if (be64_to_cpu(nla_get_be64(nla)) == flowtable->handle &&
423 + nft_active_genmask(flowtable, genmask))
424 + return flowtable;
425 + }
426 + return ERR_PTR(-ENOENT);
427 +}
428 +
429 #define NFT_FLOWTABLE_DEVICE_MAX 8
430
431 static int nf_tables_parse_devices(const struct nft_ctx *ctx,
432 @@ -4954,6 +5066,8 @@ static int nf_tables_newflowtable(struct
433 return -ENOMEM;
434
435 flowtable->table = table;
436 + flowtable->handle = nf_tables_alloc_handle(table);
437 +
438 flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL);
439 if (!flowtable->name) {
440 err = -ENOMEM;
441 @@ -5028,8 +5142,14 @@ static int nf_tables_delflowtable(struct
442 if (IS_ERR(table))
443 return PTR_ERR(table);
444
445 - flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
446 - genmask);
447 + if (nla[NFTA_FLOWTABLE_HANDLE])
448 + flowtable = nf_tables_flowtable_lookup_byhandle(table,
449 + nla[NFTA_FLOWTABLE_HANDLE],
450 + genmask);
451 + else
452 + flowtable = nf_tables_flowtable_lookup(table,
453 + nla[NFTA_FLOWTABLE_NAME],
454 + genmask);
455 if (IS_ERR(flowtable))
456 return PTR_ERR(flowtable);
457 if (flowtable->use > 0)
458 @@ -5062,7 +5182,9 @@ static int nf_tables_fill_flowtable_info
459
460 if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
461 nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
462 - nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)))
463 + nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
464 + nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
465 + NFTA_FLOWTABLE_PAD))
466 goto nla_put_failure;
467
468 nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);