libnftnl 1.3.0
set.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6 */
7#include "internal.h"
8
9#include <time.h>
10#include <endian.h>
11#include <stdint.h>
12#include <stdlib.h>
13#include <string.h>
14#include <inttypes.h>
15#include <netinet/in.h>
16#include <limits.h>
17#include <errno.h>
18
19#include <libmnl/libmnl.h>
20#include <linux/netfilter/nfnetlink.h>
21#include <linux/netfilter/nf_tables.h>
22
23#include <libnftnl/set.h>
24#include <libnftnl/expr.h>
25
26EXPORT_SYMBOL(nftnl_set_alloc);
27struct nftnl_set *nftnl_set_alloc(void)
28{
29 struct nftnl_set *s;
30
31 s = calloc(1, sizeof(struct nftnl_set));
32 if (s == NULL)
33 return NULL;
34
35 INIT_LIST_HEAD(&s->element_list);
36 INIT_LIST_HEAD(&s->expr_list);
37 return s;
38}
39
40EXPORT_SYMBOL(nftnl_set_free);
41void nftnl_set_free(const struct nftnl_set *s)
42{
43 struct nftnl_set_elem *elem, *tmp;
44 struct nftnl_expr *expr, *next;
45
46 if (s->flags & (1 << NFTNL_SET_TABLE))
47 xfree(s->table);
48 if (s->flags & (1 << NFTNL_SET_NAME))
49 xfree(s->name);
50 if (s->flags & (1 << NFTNL_SET_USERDATA))
51 xfree(s->user.data);
52
53 list_for_each_entry_safe(expr, next, &s->expr_list, head) {
54 list_del(&expr->head);
55 nftnl_expr_free(expr);
56 }
57
58 list_for_each_entry_safe(elem, tmp, &s->element_list, head) {
59 list_del(&elem->head);
60 nftnl_set_elem_free(elem);
61 }
62
63 xfree(s->type);
64 xfree(s);
65}
66
67EXPORT_SYMBOL(nftnl_set_is_set);
68bool nftnl_set_is_set(const struct nftnl_set *s, uint16_t attr)
69{
70 return s->flags & (1 << attr);
71}
72
73EXPORT_SYMBOL(nftnl_set_unset);
74void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
75{
76 struct nftnl_expr *expr, *tmp;
77
78 if (!(s->flags & (1 << attr)))
79 return;
80
81 switch (attr) {
82 case NFTNL_SET_TABLE:
83 xfree(s->table);
84 break;
85 case NFTNL_SET_NAME:
86 xfree(s->name);
87 break;
88 case NFTNL_SET_HANDLE:
89 case NFTNL_SET_FLAGS:
90 case NFTNL_SET_KEY_TYPE:
91 case NFTNL_SET_KEY_LEN:
92 case NFTNL_SET_DATA_TYPE:
93 case NFTNL_SET_DATA_LEN:
94 case NFTNL_SET_OBJ_TYPE:
95 case NFTNL_SET_FAMILY:
96 case NFTNL_SET_ID:
97 case NFTNL_SET_POLICY:
98 case NFTNL_SET_DESC_SIZE:
99 case NFTNL_SET_DESC_CONCAT:
100 case NFTNL_SET_TIMEOUT:
101 case NFTNL_SET_GC_INTERVAL:
102 case NFTNL_SET_COUNT:
103 break;
104 case NFTNL_SET_USERDATA:
105 xfree(s->user.data);
106 break;
107 case NFTNL_SET_EXPR:
108 case NFTNL_SET_EXPRESSIONS:
109 list_for_each_entry_safe(expr, tmp, &s->expr_list, head) {
110 list_del(&expr->head);
111 nftnl_expr_free(expr);
112 }
113 break;
114 default:
115 return;
116 }
117
118 s->flags &= ~(1 << attr);
119}
120
121static uint32_t nftnl_set_validate[NFTNL_SET_MAX + 1] = {
122 [NFTNL_SET_HANDLE] = sizeof(uint64_t),
123 [NFTNL_SET_FLAGS] = sizeof(uint32_t),
124 [NFTNL_SET_KEY_TYPE] = sizeof(uint32_t),
125 [NFTNL_SET_KEY_LEN] = sizeof(uint32_t),
126 [NFTNL_SET_DATA_TYPE] = sizeof(uint32_t),
127 [NFTNL_SET_DATA_LEN] = sizeof(uint32_t),
128 [NFTNL_SET_OBJ_TYPE] = sizeof(uint32_t),
129 [NFTNL_SET_FAMILY] = sizeof(uint32_t),
130 [NFTNL_SET_ID] = sizeof(uint32_t),
131 [NFTNL_SET_POLICY] = sizeof(uint32_t),
132 [NFTNL_SET_DESC_SIZE] = sizeof(uint32_t),
133 [NFTNL_SET_TIMEOUT] = sizeof(uint64_t),
134 [NFTNL_SET_GC_INTERVAL] = sizeof(uint32_t),
135 [NFTNL_SET_COUNT] = sizeof(uint32_t),
136};
137
138EXPORT_SYMBOL(nftnl_set_set_data);
139int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
140 uint32_t data_len)
141{
142 struct nftnl_expr *expr, *tmp;
143
144 nftnl_assert_attr_exists(attr, NFTNL_SET_MAX);
145 nftnl_assert_validate(data, nftnl_set_validate, attr, data_len);
146
147 switch(attr) {
148 case NFTNL_SET_TABLE:
149 return nftnl_set_str_attr(&s->table, &s->flags,
150 attr, data, data_len);
151 case NFTNL_SET_NAME:
152 return nftnl_set_str_attr(&s->name, &s->flags,
153 attr, data, data_len);
154 case NFTNL_SET_HANDLE:
155 memcpy(&s->handle, data, sizeof(s->handle));
156 break;
157 case NFTNL_SET_FLAGS:
158 memcpy(&s->set_flags, data, sizeof(s->set_flags));
159 break;
160 case NFTNL_SET_KEY_TYPE:
161 memcpy(&s->key_type, data, sizeof(s->key_type));
162 break;
163 case NFTNL_SET_KEY_LEN:
164 memcpy(&s->key_len, data, sizeof(s->key_len));
165 break;
166 case NFTNL_SET_DATA_TYPE:
167 memcpy(&s->data_type, data, sizeof(s->data_type));
168 break;
169 case NFTNL_SET_DATA_LEN:
170 memcpy(&s->data_len, data, sizeof(s->data_len));
171 break;
172 case NFTNL_SET_OBJ_TYPE:
173 memcpy(&s->obj_type, data, sizeof(s->obj_type));
174 break;
175 case NFTNL_SET_FAMILY:
176 memcpy(&s->family, data, sizeof(s->family));
177 break;
178 case NFTNL_SET_ID:
179 memcpy(&s->id, data, sizeof(s->id));
180 break;
181 case NFTNL_SET_POLICY:
182 memcpy(&s->policy, data, sizeof(s->policy));
183 break;
184 case NFTNL_SET_DESC_SIZE:
185 memcpy(&s->desc.size, data, sizeof(s->desc.size));
186 break;
187 case NFTNL_SET_DESC_CONCAT:
188 if (data_len > sizeof(s->desc.field_len))
189 return -1;
190
191 memcpy(&s->desc.field_len, data, data_len);
192 for (s->desc.field_count = 0;
193 s->desc.field_count < NFT_REG32_COUNT;
194 s->desc.field_count++) {
195 if (!s->desc.field_len[s->desc.field_count])
196 break;
197 }
198 break;
199 case NFTNL_SET_TIMEOUT:
200 memcpy(&s->timeout, data, sizeof(s->timeout));
201 break;
202 case NFTNL_SET_GC_INTERVAL:
203 memcpy(&s->gc_interval, data, sizeof(s->gc_interval));
204 break;
205 case NFTNL_SET_COUNT:
206 memcpy(&s->elemcount, data, sizeof(s->elemcount));
207 break;
208 case NFTNL_SET_USERDATA:
209 if (s->flags & (1 << NFTNL_SET_USERDATA))
210 xfree(s->user.data);
211
212 s->user.data = malloc(data_len);
213 if (!s->user.data)
214 return -1;
215 memcpy(s->user.data, data, data_len);
216 s->user.len = data_len;
217 break;
218 case NFTNL_SET_EXPR:
219 list_for_each_entry_safe(expr, tmp, &s->expr_list, head) {
220 list_del(&expr->head);
221 nftnl_expr_free(expr);
222 }
223
224 expr = (void *)data;
225 list_add(&expr->head, &s->expr_list);
226 break;
227 }
228 s->flags |= (1 << attr);
229 return 0;
230}
231
232int nftnl_set_set(struct nftnl_set *s, uint16_t attr, const void *data) __visible;
233int nftnl_set_set(struct nftnl_set *s, uint16_t attr, const void *data)
234{
235 return nftnl_set_set_data(s, attr, data, nftnl_set_validate[attr]);
236}
237
238EXPORT_SYMBOL(nftnl_set_set_u32);
239void nftnl_set_set_u32(struct nftnl_set *s, uint16_t attr, uint32_t val)
240{
241 nftnl_set_set_data(s, attr, &val, sizeof(uint32_t));
242}
243
244EXPORT_SYMBOL(nftnl_set_set_u64);
245void nftnl_set_set_u64(struct nftnl_set *s, uint16_t attr, uint64_t val)
246{
247 nftnl_set_set_data(s, attr, &val, sizeof(uint64_t));
248}
249
250EXPORT_SYMBOL(nftnl_set_set_str);
251int nftnl_set_set_str(struct nftnl_set *s, uint16_t attr, const char *str)
252{
253 return nftnl_set_set_data(s, attr, str, strlen(str) + 1);
254}
255
256EXPORT_SYMBOL(nftnl_set_get_data);
257const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
258 uint32_t *data_len)
259{
260 struct nftnl_expr *expr;
261
262 if (!(s->flags & (1 << attr)))
263 return NULL;
264
265 switch(attr) {
266 case NFTNL_SET_TABLE:
267 *data_len = strlen(s->table) + 1;
268 return s->table;
269 case NFTNL_SET_NAME:
270 *data_len = strlen(s->name) + 1;
271 return s->name;
272 case NFTNL_SET_HANDLE:
273 *data_len = sizeof(uint64_t);
274 return &s->handle;
275 case NFTNL_SET_FLAGS:
276 *data_len = sizeof(uint32_t);
277 return &s->set_flags;
278 case NFTNL_SET_KEY_TYPE:
279 *data_len = sizeof(uint32_t);
280 return &s->key_type;
281 case NFTNL_SET_KEY_LEN:
282 *data_len = sizeof(uint32_t);
283 return &s->key_len;
284 case NFTNL_SET_DATA_TYPE:
285 *data_len = sizeof(uint32_t);
286 return &s->data_type;
287 case NFTNL_SET_DATA_LEN:
288 *data_len = sizeof(uint32_t);
289 return &s->data_len;
290 case NFTNL_SET_OBJ_TYPE:
291 *data_len = sizeof(uint32_t);
292 return &s->obj_type;
293 case NFTNL_SET_FAMILY:
294 *data_len = sizeof(uint32_t);
295 return &s->family;
296 case NFTNL_SET_ID:
297 *data_len = sizeof(uint32_t);
298 return &s->id;
299 case NFTNL_SET_POLICY:
300 *data_len = sizeof(uint32_t);
301 return &s->policy;
302 case NFTNL_SET_DESC_SIZE:
303 *data_len = sizeof(uint32_t);
304 return &s->desc.size;
305 case NFTNL_SET_DESC_CONCAT:
306 *data_len = s->desc.field_count;
307 return s->desc.field_len;
308 case NFTNL_SET_TIMEOUT:
309 *data_len = sizeof(uint64_t);
310 return &s->timeout;
311 case NFTNL_SET_GC_INTERVAL:
312 *data_len = sizeof(uint32_t);
313 return &s->gc_interval;
314 case NFTNL_SET_COUNT:
315 *data_len = sizeof(uint32_t);
316 return &s->elemcount;
317 case NFTNL_SET_USERDATA:
318 *data_len = s->user.len;
319 return s->user.data;
320 case NFTNL_SET_EXPR:
321 list_for_each_entry(expr, &s->expr_list, head)
322 break;
323 return expr;
324 }
325 return NULL;
326}
327
328EXPORT_SYMBOL(nftnl_set_get);
329const void *nftnl_set_get(const struct nftnl_set *s, uint16_t attr)
330{
331 uint32_t data_len;
332 return nftnl_set_get_data(s, attr, &data_len);
333}
334
335EXPORT_SYMBOL(nftnl_set_get_str);
336const char *nftnl_set_get_str(const struct nftnl_set *s, uint16_t attr)
337{
338 return nftnl_set_get(s, attr);
339}
340
341EXPORT_SYMBOL(nftnl_set_get_u32);
342uint32_t nftnl_set_get_u32(const struct nftnl_set *s, uint16_t attr)
343{
344 uint32_t data_len;
345 const uint32_t *val = nftnl_set_get_data(s, attr, &data_len);
346
347 nftnl_assert(val, attr, data_len == sizeof(uint32_t));
348
349 return val ? *val : 0;
350}
351
352EXPORT_SYMBOL(nftnl_set_get_u64);
353uint64_t nftnl_set_get_u64(const struct nftnl_set *s, uint16_t attr)
354{
355 uint32_t data_len;
356 const uint64_t *val = nftnl_set_get_data(s, attr, &data_len);
357
358 nftnl_assert(val, attr, data_len == sizeof(uint64_t));
359
360 return val ? *val : 0;
361}
362
363struct nftnl_set *nftnl_set_clone(const struct nftnl_set *set)
364{
365 struct nftnl_set *newset;
366 struct nftnl_set_elem *elem, *newelem;
367
368 newset = nftnl_set_alloc();
369 if (newset == NULL)
370 return NULL;
371
372 memcpy(newset, set, sizeof(*set));
373
374 if (set->flags & (1 << NFTNL_SET_TABLE)) {
375 newset->table = strdup(set->table);
376 if (!newset->table)
377 goto err;
378 }
379 if (set->flags & (1 << NFTNL_SET_NAME)) {
380 newset->name = strdup(set->name);
381 if (!newset->name)
382 goto err;
383 }
384
385 INIT_LIST_HEAD(&newset->element_list);
386 list_for_each_entry(elem, &set->element_list, head) {
387 newelem = nftnl_set_elem_clone(elem);
388 if (newelem == NULL)
389 goto err;
390
391 list_add_tail(&newelem->head, &newset->element_list);
392 }
393
394 newset->type = NULL;
395
396 return newset;
397err:
398 nftnl_set_free(newset);
399 return NULL;
400}
401
402static void nftnl_set_nlmsg_build_desc_size_payload(struct nlmsghdr *nlh,
403 struct nftnl_set *s)
404{
405 mnl_attr_put_u32(nlh, NFTA_SET_DESC_SIZE, htonl(s->desc.size));
406}
407
408static void nftnl_set_nlmsg_build_desc_concat_payload(struct nlmsghdr *nlh,
409 struct nftnl_set *s)
410{
411 struct nlattr *nest;
412 int i;
413
414 nest = mnl_attr_nest_start(nlh, NFTA_SET_DESC_CONCAT);
415 for (i = 0; i < NFT_REG32_COUNT && i < s->desc.field_count; i++) {
416 struct nlattr *nest_elem;
417
418 nest_elem = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
419 mnl_attr_put_u32(nlh, NFTA_SET_FIELD_LEN,
420 htonl(s->desc.field_len[i]));
421 mnl_attr_nest_end(nlh, nest_elem);
422 }
423 mnl_attr_nest_end(nlh, nest);
424}
425
426static void
427nftnl_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
428{
429 struct nlattr *nest;
430
431 nest = mnl_attr_nest_start(nlh, NFTA_SET_DESC);
432
433 if (s->flags & (1 << NFTNL_SET_DESC_SIZE))
434 nftnl_set_nlmsg_build_desc_size_payload(nlh, s);
435 if (s->flags & (1 << NFTNL_SET_DESC_CONCAT))
436 nftnl_set_nlmsg_build_desc_concat_payload(nlh, s);
437
438 mnl_attr_nest_end(nlh, nest);
439}
440
441EXPORT_SYMBOL(nftnl_set_nlmsg_build_payload);
442void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
443{
444 int num_exprs = 0;
445
446 if (s->flags & (1 << NFTNL_SET_TABLE))
447 mnl_attr_put_strz(nlh, NFTA_SET_TABLE, s->table);
448 if (s->flags & (1 << NFTNL_SET_NAME))
449 mnl_attr_put_strz(nlh, NFTA_SET_NAME, s->name);
450 if (s->flags & (1 << NFTNL_SET_HANDLE))
451 mnl_attr_put_u64(nlh, NFTA_SET_HANDLE, htobe64(s->handle));
452 if (s->flags & (1 << NFTNL_SET_FLAGS))
453 mnl_attr_put_u32(nlh, NFTA_SET_FLAGS, htonl(s->set_flags));
454 if (s->flags & (1 << NFTNL_SET_KEY_TYPE))
455 mnl_attr_put_u32(nlh, NFTA_SET_KEY_TYPE, htonl(s->key_type));
456 if (s->flags & (1 << NFTNL_SET_KEY_LEN))
457 mnl_attr_put_u32(nlh, NFTA_SET_KEY_LEN, htonl(s->key_len));
458 /* These are only used to map matching -> action (1:1) */
459 if (s->flags & (1 << NFTNL_SET_DATA_TYPE))
460 mnl_attr_put_u32(nlh, NFTA_SET_DATA_TYPE, htonl(s->data_type));
461 if (s->flags & (1 << NFTNL_SET_DATA_LEN))
462 mnl_attr_put_u32(nlh, NFTA_SET_DATA_LEN, htonl(s->data_len));
463 if (s->flags & (1 << NFTNL_SET_OBJ_TYPE))
464 mnl_attr_put_u32(nlh, NFTA_SET_OBJ_TYPE, htonl(s->obj_type));
465 if (s->flags & (1 << NFTNL_SET_ID))
466 mnl_attr_put_u32(nlh, NFTA_SET_ID, htonl(s->id));
467 if (s->flags & (1 << NFTNL_SET_POLICY))
468 mnl_attr_put_u32(nlh, NFTA_SET_POLICY, htonl(s->policy));
469 if (s->flags & (1 << NFTNL_SET_DESC_SIZE | 1 << NFTNL_SET_DESC_CONCAT))
470 nftnl_set_nlmsg_build_desc_payload(nlh, s);
471 if (s->flags & (1 << NFTNL_SET_TIMEOUT))
472 mnl_attr_put_u64(nlh, NFTA_SET_TIMEOUT, htobe64(s->timeout));
473 if (s->flags & (1 << NFTNL_SET_GC_INTERVAL))
474 mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval));
475 if (s->flags & (1 << NFTNL_SET_USERDATA))
476 mnl_attr_put(nlh, NFTA_SET_USERDATA, s->user.len, s->user.data);
477 if (!list_empty(&s->expr_list)) {
478 struct nftnl_expr *expr;
479
480 list_for_each_entry(expr, &s->expr_list, head)
481 num_exprs++;
482
483 if (num_exprs == 1) {
484 struct nlattr *nest1;
485
486 nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPR);
487 list_for_each_entry(expr, &s->expr_list, head)
488 nftnl_expr_build_payload(nlh, expr);
489
490 mnl_attr_nest_end(nlh, nest1);
491 } else if (num_exprs > 1) {
492 struct nlattr *nest1, *nest2;
493
494 nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPRESSIONS);
495 list_for_each_entry(expr, &s->expr_list, head) {
496 nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
497 nftnl_expr_build_payload(nlh, expr);
498 mnl_attr_nest_end(nlh, nest2);
499 }
500 mnl_attr_nest_end(nlh, nest1);
501 }
502 }
503}
504
505EXPORT_SYMBOL(nftnl_set_add_expr);
506void nftnl_set_add_expr(struct nftnl_set *s, struct nftnl_expr *expr)
507{
508 list_add_tail(&expr->head, &s->expr_list);
509}
510
511EXPORT_SYMBOL(nftnl_set_expr_foreach);
512int nftnl_set_expr_foreach(const struct nftnl_set *s,
513 int (*cb)(struct nftnl_expr *e, void *data),
514 void *data)
515{
516 struct nftnl_expr *cur, *tmp;
517 int ret;
518
519 list_for_each_entry_safe(cur, tmp, &s->expr_list, head) {
520 ret = cb(cur, data);
521 if (ret < 0)
522 return ret;
523 }
524 return 0;
525}
526
527static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
528{
529 const struct nlattr **tb = data;
530 int type = mnl_attr_get_type(attr);
531
532 if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
533 return MNL_CB_OK;
534
535 switch(type) {
536 case NFTA_SET_TABLE:
537 case NFTA_SET_NAME:
538 case NFTA_SET_TYPE:
539 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
540 abi_breakage();
541 break;
542 case NFTA_SET_HANDLE:
543 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
544 abi_breakage();
545 break;
546 case NFTA_SET_FLAGS:
547 case NFTA_SET_KEY_TYPE:
548 case NFTA_SET_KEY_LEN:
549 case NFTA_SET_DATA_TYPE:
550 case NFTA_SET_DATA_LEN:
551 case NFTA_SET_ID:
552 case NFTA_SET_POLICY:
553 case NFTA_SET_GC_INTERVAL:
554 case NFTA_SET_COUNT:
555 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
556 abi_breakage();
557 break;
558 case NFTA_SET_USERDATA:
559 if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
560 abi_breakage();
561 break;
562 case NFTA_SET_TIMEOUT:
563 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
564 abi_breakage();
565 break;
566 case NFTA_SET_DESC:
567 case NFTA_SET_EXPR:
568 case NFTA_SET_EXPRESSIONS:
569 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
570 abi_breakage();
571 break;
572 }
573
574 tb[type] = attr;
575 return MNL_CB_OK;
576}
577
578static int
579nftnl_set_desc_concat_field_parse_attr_cb(const struct nlattr *attr, void *data)
580{
581 int type = mnl_attr_get_type(attr);
582 struct nftnl_set *s = data;
583
584 if (type != NFTA_SET_FIELD_LEN)
585 return MNL_CB_OK;
586
587 if (mnl_attr_validate(attr, MNL_TYPE_U32))
588 return MNL_CB_ERROR;
589
590 s->desc.field_len[s->desc.field_count] = ntohl(mnl_attr_get_u32(attr));
591 s->desc.field_count++;
592
593 return MNL_CB_OK;
594}
595
596static int
597nftnl_set_desc_concat_parse_attr_cb(const struct nlattr *attr, void *data)
598{
599 int type = mnl_attr_get_type(attr);
600 struct nftnl_set *s = data;
601
602 if (type != NFTA_LIST_ELEM)
603 return MNL_CB_OK;
604
605 return mnl_attr_parse_nested(attr,
606 nftnl_set_desc_concat_field_parse_attr_cb,
607 s);
608}
609
610static int nftnl_set_desc_parse_attr_cb(const struct nlattr *attr, void *data)
611{
612 int type = mnl_attr_get_type(attr), err;
613 struct nftnl_set *s = data;
614
615 if (mnl_attr_type_valid(attr, NFTA_SET_DESC_MAX) < 0)
616 return MNL_CB_OK;
617
618 switch (type) {
619 case NFTA_SET_DESC_SIZE:
620 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
621 abi_breakage();
622 break;
623 }
624
625 s->desc.size = ntohl(mnl_attr_get_u32(attr));
626 s->flags |= (1 << NFTNL_SET_DESC_SIZE);
627 break;
628 case NFTA_SET_DESC_CONCAT:
629 err = mnl_attr_parse_nested(attr,
630 nftnl_set_desc_concat_parse_attr_cb,
631 s);
632 if (err != MNL_CB_OK)
633 abi_breakage();
634
635 s->flags |= (1 << NFTNL_SET_DESC_CONCAT);
636 break;
637 default:
638 break;
639 }
640
641 return MNL_CB_OK;
642}
643
644static int nftnl_set_desc_parse(struct nftnl_set *s, const struct nlattr *attr)
645{
646 return mnl_attr_parse_nested(attr, nftnl_set_desc_parse_attr_cb, s);
647}
648
649EXPORT_SYMBOL(nftnl_set_nlmsg_parse);
650int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
651{
652 struct nlattr *tb[NFTA_SET_MAX+1] = {};
653 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
654 struct nftnl_expr *expr, *next;
655 int ret;
656
657 if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_set_parse_attr_cb, tb) < 0)
658 return -1;
659
660 if (tb[NFTA_SET_TABLE]) {
661 if (s->flags & (1 << NFTNL_SET_TABLE))
662 xfree(s->table);
663 s->table = strdup(mnl_attr_get_str(tb[NFTA_SET_TABLE]));
664 if (!s->table)
665 return -1;
666 s->flags |= (1 << NFTNL_SET_TABLE);
667 }
668 if (tb[NFTA_SET_NAME]) {
669 if (s->flags & (1 << NFTNL_SET_NAME))
670 xfree(s->name);
671 s->name = strdup(mnl_attr_get_str(tb[NFTA_SET_NAME]));
672 if (!s->name)
673 return -1;
674 s->flags |= (1 << NFTNL_SET_NAME);
675 }
676 if (tb[NFTA_SET_HANDLE]) {
677 s->handle = be64toh(mnl_attr_get_u64(tb[NFTA_SET_HANDLE]));
678 s->flags |= (1 << NFTNL_SET_HANDLE);
679 }
680 if (tb[NFTA_SET_FLAGS]) {
681 s->set_flags = ntohl(mnl_attr_get_u32(tb[NFTA_SET_FLAGS]));
682 s->flags |= (1 << NFTNL_SET_FLAGS);
683 }
684 if (tb[NFTA_SET_KEY_TYPE]) {
685 s->key_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_KEY_TYPE]));
686 s->flags |= (1 << NFTNL_SET_KEY_TYPE);
687 }
688 if (tb[NFTA_SET_KEY_LEN]) {
689 s->key_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_KEY_LEN]));
690 s->flags |= (1 << NFTNL_SET_KEY_LEN);
691 }
692 if (tb[NFTA_SET_DATA_TYPE]) {
693 s->data_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DATA_TYPE]));
694 s->flags |= (1 << NFTNL_SET_DATA_TYPE);
695 }
696 if (tb[NFTA_SET_DATA_LEN]) {
697 s->data_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DATA_LEN]));
698 s->flags |= (1 << NFTNL_SET_DATA_LEN);
699 }
700 if (tb[NFTA_SET_OBJ_TYPE]) {
701 s->obj_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_OBJ_TYPE]));
702 s->flags |= (1 << NFTNL_SET_OBJ_TYPE);
703 }
704 if (tb[NFTA_SET_ID]) {
705 s->id = ntohl(mnl_attr_get_u32(tb[NFTA_SET_ID]));
706 s->flags |= (1 << NFTNL_SET_ID);
707 }
708 if (tb[NFTA_SET_POLICY]) {
709 s->policy = ntohl(mnl_attr_get_u32(tb[NFTA_SET_POLICY]));
710 s->flags |= (1 << NFTNL_SET_POLICY);
711 }
712 if (tb[NFTA_SET_TIMEOUT]) {
713 s->timeout = be64toh(mnl_attr_get_u64(tb[NFTA_SET_TIMEOUT]));
714 s->flags |= (1 << NFTNL_SET_TIMEOUT);
715 }
716 if (tb[NFTA_SET_GC_INTERVAL]) {
717 s->gc_interval = ntohl(mnl_attr_get_u32(tb[NFTA_SET_GC_INTERVAL]));
718 s->flags |= (1 << NFTNL_SET_GC_INTERVAL);
719 }
720 if (tb[NFTA_SET_USERDATA]) {
721 ret = nftnl_set_set_data(s, NFTNL_SET_USERDATA,
722 mnl_attr_get_payload(tb[NFTA_SET_USERDATA]),
723 mnl_attr_get_payload_len(tb[NFTA_SET_USERDATA]));
724 if (ret < 0)
725 return ret;
726 }
727 if (tb[NFTA_SET_DESC]) {
728 ret = nftnl_set_desc_parse(s, tb[NFTA_SET_DESC]);
729 if (ret < 0)
730 return ret;
731 }
732 if (tb[NFTA_SET_EXPR]) {
733 expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]);
734 if (!expr)
735 goto out_set_expr;
736
737 list_add(&expr->head, &s->expr_list);
738 s->flags |= (1 << NFTNL_SET_EXPR);
739 } else if (tb[NFTA_SET_EXPRESSIONS]) {
740 struct nlattr *attr;
741
742 mnl_attr_for_each_nested(attr, tb[NFTA_SET_EXPRESSIONS]) {
743 if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
744 goto out_set_expr;
745
746 expr = nftnl_expr_parse(attr);
747 if (expr == NULL)
748 goto out_set_expr;
749
750 list_add_tail(&expr->head, &s->expr_list);
751 }
752 s->flags |= (1 << NFTNL_SET_EXPRESSIONS);
753 }
754
755 if (tb[NFTA_SET_TYPE]) {
756 xfree(s->type);
757 s->type = strdup(mnl_attr_get_str(tb[NFTA_SET_TYPE]));
758 }
759
760 if (tb[NFTA_SET_COUNT]) {
761 s->elemcount = ntohl(mnl_attr_get_u32(tb[NFTA_SET_COUNT]));
762 s->flags |= (1 << NFTNL_SET_COUNT);
763 }
764
765 s->family = nfg->nfgen_family;
766 s->flags |= (1 << NFTNL_SET_FAMILY);
767
768 return 0;
769out_set_expr:
770 list_for_each_entry_safe(expr, next, &s->expr_list, head) {
771 list_del(&expr->head);
772 nftnl_expr_free(expr);
773 }
774
775 return -1;
776}
777
778EXPORT_SYMBOL(nftnl_set_parse);
779int nftnl_set_parse(struct nftnl_set *s, enum nftnl_parse_type type,
780 const char *data, struct nftnl_parse_err *err)
781{
782 errno = EOPNOTSUPP;
783
784 return -1;
785}
786
787EXPORT_SYMBOL(nftnl_set_parse_file);
788int nftnl_set_parse_file(struct nftnl_set *s, enum nftnl_parse_type type,
789 FILE *fp, struct nftnl_parse_err *err)
790{
791 errno = EOPNOTSUPP;
792
793 return -1;
794}
795
796static int nftnl_set_snprintf_default(char *buf, size_t remain,
797 const struct nftnl_set *s,
798 uint32_t type, uint32_t flags)
799{
800 struct nftnl_set_elem *elem;
801 int ret, offset = 0;
802
803 ret = snprintf(buf, remain, "%s %s %x",
804 s->name, s->table, s->set_flags);
805 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
806
807 if (s->flags & (1 << NFTNL_SET_TIMEOUT)) {
808 ret = snprintf(buf + offset, remain, " timeout %"PRIu64"ms",
809 s->timeout);
810 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
811 }
812
813 if (s->flags & (1 << NFTNL_SET_GC_INTERVAL)) {
814 ret = snprintf(buf + offset, remain, " gc_interval %ums",
815 s->gc_interval);
816 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
817 }
818
819 if (s->flags & (1 << NFTNL_SET_POLICY)) {
820 ret = snprintf(buf + offset, remain, " policy %u", s->policy);
821 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
822 }
823
824 if (s->flags & (1 << NFTNL_SET_DESC_SIZE)) {
825 ret = snprintf(buf + offset, remain, " size %u", s->desc.size);
826 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
827 }
828
829 if (s->type) {
830 ret = snprintf(buf + offset, remain, " backend %s", s->type);
831 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
832 }
833
834 if (s->elemcount) {
835 ret = snprintf(buf + offset, remain, " count %u", s->elemcount);
836 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
837 }
838
839 /* Empty set? Skip printinf of elements */
840 if (list_empty(&s->element_list))
841 return offset;
842
843 ret = snprintf(buf + offset, remain, "\n");
844 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
845
846 list_for_each_entry(elem, &s->element_list, head) {
847 ret = snprintf(buf + offset, remain, "\t");
848 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
849
850 ret = nftnl_set_elem_snprintf_default(buf + offset, remain,
851 elem);
852 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
853 }
854
855 return offset;
856}
857
858static int nftnl_set_cmd_snprintf(char *buf, size_t remain,
859 const struct nftnl_set *s, uint32_t cmd,
860 uint32_t type, uint32_t flags)
861{
862 uint32_t inner_flags = flags;
863 int ret, offset = 0;
864
865 if (type != NFTNL_OUTPUT_DEFAULT)
866 return -1;
867
868 /* prevent set_elems to print as events */
869 inner_flags &= ~NFTNL_OF_EVENT_ANY;
870
871 ret = nftnl_set_snprintf_default(buf + offset, remain, s, type,
872 inner_flags);
873 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
874 return offset;
875}
876
877EXPORT_SYMBOL(nftnl_set_snprintf);
878int nftnl_set_snprintf(char *buf, size_t size, const struct nftnl_set *s,
879 uint32_t type, uint32_t flags)
880{
881 if (size)
882 buf[0] = '\0';
883
884 return nftnl_set_cmd_snprintf(buf, size, s, nftnl_flag2cmd(flags), type,
885 flags);
886}
887
888static int nftnl_set_do_snprintf(char *buf, size_t size, const void *s,
889 uint32_t cmd, uint32_t type, uint32_t flags)
890{
891 return nftnl_set_snprintf(buf, size, s, type, flags);
892}
893
894EXPORT_SYMBOL(nftnl_set_fprintf);
895int nftnl_set_fprintf(FILE *fp, const struct nftnl_set *s, uint32_t type,
896 uint32_t flags)
897{
898 return nftnl_fprintf(fp, s, NFTNL_CMD_UNSPEC, type, flags,
899 nftnl_set_do_snprintf);
900}
901
902EXPORT_SYMBOL(nftnl_set_elem_add);
903void nftnl_set_elem_add(struct nftnl_set *s, struct nftnl_set_elem *elem)
904{
905 list_add_tail(&elem->head, &s->element_list);
906}
907
908#define SET_NAME_HSIZE 512
909
911 struct list_head list;
912 struct hlist_head name_hash[SET_NAME_HSIZE];
913};
914
915EXPORT_SYMBOL(nftnl_set_list_alloc);
916struct nftnl_set_list *nftnl_set_list_alloc(void)
917{
918 struct nftnl_set_list *list;
919 int i;
920
921 list = calloc(1, sizeof(struct nftnl_set_list));
922 if (list == NULL)
923 return NULL;
924
925 INIT_LIST_HEAD(&list->list);
926 for (i = 0; i < SET_NAME_HSIZE; i++)
927 INIT_HLIST_HEAD(&list->name_hash[i]);
928
929 return list;
930}
931
932EXPORT_SYMBOL(nftnl_set_list_free);
933void nftnl_set_list_free(struct nftnl_set_list *list)
934{
935 struct nftnl_set *s, *tmp;
936
937 list_for_each_entry_safe(s, tmp, &list->list, head) {
938 list_del(&s->head);
939 hlist_del(&s->hnode);
940 nftnl_set_free(s);
941 }
942 xfree(list);
943}
944
945EXPORT_SYMBOL(nftnl_set_list_is_empty);
946int nftnl_set_list_is_empty(const struct nftnl_set_list *list)
947{
948 return list_empty(&list->list);
949}
950
951static uint32_t djb_hash(const char *key)
952{
953 uint32_t i, hash = 5381;
954
955 for (i = 0; i < strlen(key); i++)
956 hash = ((hash << 5) + hash) + key[i];
957
958 return hash;
959}
960
961EXPORT_SYMBOL(nftnl_set_list_add);
962void nftnl_set_list_add(struct nftnl_set *s, struct nftnl_set_list *list)
963{
964 int key = djb_hash(s->name) % SET_NAME_HSIZE;
965
966 hlist_add_head(&s->hnode, &list->name_hash[key]);
967 list_add(&s->head, &list->list);
968}
969
970EXPORT_SYMBOL(nftnl_set_list_add_tail);
971void nftnl_set_list_add_tail(struct nftnl_set *s, struct nftnl_set_list *list)
972{
973 int key = djb_hash(s->name) % SET_NAME_HSIZE;
974
975 hlist_add_head(&s->hnode, &list->name_hash[key]);
976 list_add_tail(&s->head, &list->list);
977}
978
979EXPORT_SYMBOL(nftnl_set_list_del);
980void nftnl_set_list_del(struct nftnl_set *s)
981{
982 list_del(&s->head);
983 hlist_del(&s->hnode);
984}
985
986EXPORT_SYMBOL(nftnl_set_list_foreach);
987int nftnl_set_list_foreach(struct nftnl_set_list *set_list,
988 int (*cb)(struct nftnl_set *t, void *data), void *data)
989{
990 struct nftnl_set *cur, *tmp;
991 int ret;
992
993 list_for_each_entry_safe(cur, tmp, &set_list->list, head) {
994 ret = cb(cur, data);
995 if (ret < 0)
996 return ret;
997 }
998 return 0;
999}
1000
1002 const struct nftnl_set_list *list;
1003 struct nftnl_set *cur;
1004};
1005
1006EXPORT_SYMBOL(nftnl_set_list_iter_create);
1007struct nftnl_set_list_iter *
1008nftnl_set_list_iter_create(const struct nftnl_set_list *l)
1009{
1010 struct nftnl_set_list_iter *iter;
1011
1012 iter = calloc(1, sizeof(struct nftnl_set_list_iter));
1013 if (iter == NULL)
1014 return NULL;
1015
1016 iter->list = l;
1017 if (nftnl_set_list_is_empty(l))
1018 iter->cur = NULL;
1019 else
1020 iter->cur = list_entry(l->list.next, struct nftnl_set, head);
1021
1022 return iter;
1023}
1024
1025EXPORT_SYMBOL(nftnl_set_list_iter_cur);
1026struct nftnl_set *
1027nftnl_set_list_iter_cur(const struct nftnl_set_list_iter *iter)
1028{
1029 return iter->cur;
1030}
1031
1032EXPORT_SYMBOL(nftnl_set_list_iter_next);
1033struct nftnl_set *nftnl_set_list_iter_next(struct nftnl_set_list_iter *iter)
1034{
1035 struct nftnl_set *s = iter->cur;
1036
1037 if (s == NULL)
1038 return NULL;
1039
1040 /* get next rule, if any */
1041 iter->cur = list_entry(iter->cur->head.next, struct nftnl_set, head);
1042 if (&iter->cur->head == iter->list->list.next)
1043 return NULL;
1044
1045 return s;
1046}
1047
1048EXPORT_SYMBOL(nftnl_set_list_iter_destroy);
1049void nftnl_set_list_iter_destroy(const struct nftnl_set_list_iter *iter)
1050{
1051 xfree(iter);
1052}
1053
1054EXPORT_SYMBOL(nftnl_set_list_lookup_byname);
1055struct nftnl_set *
1056nftnl_set_list_lookup_byname(struct nftnl_set_list *set_list, const char *set)
1057{
1058 int key = djb_hash(set) % SET_NAME_HSIZE;
1059 struct hlist_node *n;
1060 struct nftnl_set *s;
1061
1062 hlist_for_each_entry(s, n, &set_list->name_hash[key], hnode) {
1063 if (!strcmp(set, s->name))
1064 return s;
1065 }
1066 return NULL;
1067}
1068
1069int nftnl_set_lookup_id(struct nftnl_expr *e,
1070 struct nftnl_set_list *set_list, uint32_t *set_id)
1071{
1072 const char *set_name;
1073 struct nftnl_set *s;
1074
1075 set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
1076 if (set_name == NULL)
1077 return 0;
1078
1079 s = nftnl_set_list_lookup_byname(set_list, set_name);
1080 if (s == NULL)
1081 return 0;
1082
1083 *set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
1084 return 1;
1085}