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