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