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