libnftnl  1.0.2
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 <netinet/in.h>
19 #include <limits.h>
20 #include <errno.h>
21 
22 #include <libmnl/libmnl.h>
23 #include <linux/netfilter/nfnetlink.h>
24 #include <linux/netfilter/nf_tables.h>
25 
26 #include <libnftnl/set.h>
27 
28 #include "linux_list.h"
29 #include "expr/data_reg.h"
30 
31 struct nft_set *nft_set_alloc(void)
32 {
33  struct nft_set *s;
34 
35  s = calloc(1, sizeof(struct nft_set));
36  if (s == NULL)
37  return NULL;
38 
39  INIT_LIST_HEAD(&s->element_list);
40  return s;
41 }
42 EXPORT_SYMBOL(nft_set_alloc);
43 
44 void nft_set_free(struct nft_set *s)
45 {
46  struct nft_set_elem *elem, *tmp;
47 
48  if (s->table != NULL)
49  xfree(s->table);
50  if (s->name != NULL)
51  xfree(s->name);
52 
53  list_for_each_entry_safe(elem, tmp, &s->element_list, head) {
54  list_del(&elem->head);
55  nft_set_elem_free(elem);
56  }
57  xfree(s);
58 }
59 EXPORT_SYMBOL(nft_set_free);
60 
61 bool nft_set_attr_is_set(const struct nft_set *s, uint16_t attr)
62 {
63  return s->flags & (1 << attr);
64 }
65 EXPORT_SYMBOL(nft_set_attr_is_set);
66 
67 void nft_set_attr_unset(struct nft_set *s, uint16_t attr)
68 {
69  switch (attr) {
70  case NFT_SET_ATTR_TABLE:
71  if (s->flags & (1 << NFT_SET_ATTR_TABLE))
72  if (s->table) {
73  xfree(s->table);
74  s->table = NULL;
75  }
76  break;
77  case NFT_SET_ATTR_NAME:
78  if (s->flags & (1 << NFT_SET_ATTR_NAME))
79  if (s->name) {
80  xfree(s->name);
81  s->name = NULL;
82  }
83  break;
84  case NFT_SET_ATTR_FLAGS:
85  case NFT_SET_ATTR_KEY_TYPE:
86  case NFT_SET_ATTR_KEY_LEN:
87  case NFT_SET_ATTR_DATA_TYPE:
88  case NFT_SET_ATTR_DATA_LEN:
89  case NFT_SET_ATTR_FAMILY:
90  case NFT_SET_ATTR_ID:
91  break;
92  default:
93  return;
94  }
95 
96  s->flags &= ~(1 << attr);
97 }
98 EXPORT_SYMBOL(nft_set_attr_unset);
99 
100 static uint32_t nft_set_attr_validate[NFT_SET_ATTR_MAX + 1] = {
101  [NFT_SET_ATTR_FLAGS] = sizeof(uint32_t),
102  [NFT_SET_ATTR_KEY_TYPE] = sizeof(uint32_t),
103  [NFT_SET_ATTR_KEY_LEN] = sizeof(uint32_t),
104  [NFT_SET_ATTR_DATA_TYPE] = sizeof(uint32_t),
105  [NFT_SET_ATTR_DATA_LEN] = sizeof(uint32_t),
106  [NFT_SET_ATTR_FAMILY] = sizeof(uint32_t),
107 };
108 
109 void nft_set_attr_set_data(struct nft_set *s, uint16_t attr, const void *data,
110  uint32_t data_len)
111 {
112  if (attr > NFT_SET_ATTR_MAX)
113  return;
114 
115  nft_assert_validate(data, nft_set_attr_validate, attr, data_len);
116 
117  switch(attr) {
118  case NFT_SET_ATTR_TABLE:
119  if (s->table)
120  xfree(s->table);
121 
122  s->table = strdup(data);
123  break;
124  case NFT_SET_ATTR_NAME:
125  if (s->name)
126  xfree(s->name);
127 
128  s->name = strdup(data);
129  break;
130  case NFT_SET_ATTR_FLAGS:
131  s->set_flags = *((uint32_t *)data);
132  break;
133  case NFT_SET_ATTR_KEY_TYPE:
134  s->key_type = *((uint32_t *)data);
135  break;
136  case NFT_SET_ATTR_KEY_LEN:
137  s->key_len = *((uint32_t *)data);
138  break;
139  case NFT_SET_ATTR_DATA_TYPE:
140  s->data_type = *((uint32_t *)data);
141  break;
142  case NFT_SET_ATTR_DATA_LEN:
143  s->data_len = *((uint32_t *)data);
144  break;
145  case NFT_SET_ATTR_FAMILY:
146  s->family = *((uint32_t *)data);
147  break;
148  case NFT_SET_ATTR_ID:
149  s->id = *((uint32_t *)data);
150  break;
151  }
152  s->flags |= (1 << attr);
153 }
154 EXPORT_SYMBOL(nft_set_attr_set_data);
155 
156 void nft_set_attr_set(struct nft_set *s, uint16_t attr, const void *data)
157 {
158  nft_set_attr_set_data(s, attr, data, nft_set_attr_validate[attr]);
159 }
160 EXPORT_SYMBOL(nft_set_attr_set);
161 
162 void nft_set_attr_set_u32(struct nft_set *s, uint16_t attr, uint32_t val)
163 {
164  nft_set_attr_set(s, attr, &val);
165 }
166 EXPORT_SYMBOL(nft_set_attr_set_u32);
167 
168 void nft_set_attr_set_str(struct nft_set *s, uint16_t attr, const char *str)
169 {
170  nft_set_attr_set(s, attr, str);
171 }
172 EXPORT_SYMBOL(nft_set_attr_set_str);
173 
174 const void *nft_set_attr_get_data(struct nft_set *s, uint16_t attr,
175  uint32_t *data_len)
176 {
177  if (!(s->flags & (1 << attr)))
178  return NULL;
179 
180  switch(attr) {
181  case NFT_SET_ATTR_TABLE:
182  return s->table;
183  case NFT_SET_ATTR_NAME:
184  return s->name;
185  case NFT_SET_ATTR_FLAGS:
186  *data_len = sizeof(uint32_t);
187  return &s->set_flags;
188  case NFT_SET_ATTR_KEY_TYPE:
189  *data_len = sizeof(uint32_t);
190  return &s->key_type;
191  case NFT_SET_ATTR_KEY_LEN:
192  *data_len = sizeof(uint32_t);
193  return &s->key_len;
194  case NFT_SET_ATTR_DATA_TYPE:
195  *data_len = sizeof(uint32_t);
196  return &s->data_type;
197  case NFT_SET_ATTR_DATA_LEN:
198  *data_len = sizeof(uint32_t);
199  return &s->data_len;
200  case NFT_SET_ATTR_FAMILY:
201  *data_len = sizeof(uint32_t);
202  return &s->family;
203  case NFT_SET_ATTR_ID:
204  *data_len = sizeof(uint32_t);
205  return &s->id;
206  }
207  return NULL;
208 }
209 EXPORT_SYMBOL(nft_set_attr_get_data);
210 
211 const void *nft_set_attr_get(struct nft_set *s, uint16_t attr)
212 {
213  uint32_t data_len;
214  return nft_set_attr_get_data(s, attr, &data_len);
215 }
216 EXPORT_SYMBOL(nft_set_attr_get);
217 
218 const char *nft_set_attr_get_str(struct nft_set *s, uint16_t attr)
219 {
220  return nft_set_attr_get(s, attr);
221 }
222 EXPORT_SYMBOL(nft_set_attr_get_str);
223 
224 uint32_t nft_set_attr_get_u32(struct nft_set *s, uint16_t attr)
225 {
226  uint32_t data_len;
227  const uint32_t *val = nft_set_attr_get_data(s, attr, &data_len);
228 
229  nft_assert(val, attr, data_len == sizeof(uint32_t));
230 
231  return val ? *val : 0;
232 }
233 EXPORT_SYMBOL(nft_set_attr_get_u32);
234 
235 void nft_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s)
236 {
237  if (s->flags & (1 << NFT_SET_ATTR_TABLE))
238  mnl_attr_put_strz(nlh, NFTA_SET_TABLE, s->table);
239  if (s->flags & (1 << NFT_SET_ATTR_NAME))
240  mnl_attr_put_strz(nlh, NFTA_SET_NAME, s->name);
241  if (s->flags & (1 << NFT_SET_ATTR_FLAGS))
242  mnl_attr_put_u32(nlh, NFTA_SET_FLAGS, htonl(s->set_flags));
243  if (s->flags & (1 << NFT_SET_ATTR_KEY_TYPE))
244  mnl_attr_put_u32(nlh, NFTA_SET_KEY_TYPE, htonl(s->key_type));
245  if (s->flags & (1 << NFT_SET_ATTR_KEY_LEN))
246  mnl_attr_put_u32(nlh, NFTA_SET_KEY_LEN, htonl(s->key_len));
247  /* These are only used to map matching -> action (1:1) */
248  if (s->flags & (1 << NFT_SET_ATTR_DATA_TYPE))
249  mnl_attr_put_u32(nlh, NFTA_SET_DATA_TYPE, htonl(s->data_type));
250  if (s->flags & (1 << NFT_SET_ATTR_DATA_LEN))
251  mnl_attr_put_u32(nlh, NFTA_SET_DATA_LEN, htonl(s->data_len));
252  if (s->flags & (1 << NFT_SET_ATTR_ID))
253  mnl_attr_put_u32(nlh, NFTA_SET_ID, htonl(s->id));
254 }
255 EXPORT_SYMBOL(nft_set_nlmsg_build_payload);
256 
257 static int nft_set_parse_attr_cb(const struct nlattr *attr, void *data)
258 {
259  const struct nlattr **tb = data;
260  int type = mnl_attr_get_type(attr);
261 
262  if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
263  return MNL_CB_OK;
264 
265  switch(type) {
266  case NFTA_SET_TABLE:
267  case NFTA_SET_NAME:
268  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
269  perror("mnl_attr_validate");
270  return MNL_CB_ERROR;
271  }
272  break;
273  case NFTA_SET_FLAGS:
274  case NFTA_SET_KEY_TYPE:
275  case NFTA_SET_KEY_LEN:
276  case NFTA_SET_DATA_TYPE:
277  case NFTA_SET_DATA_LEN:
278  case NFTA_SET_ID:
279  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
280  perror("mnl_attr_validate");
281  return MNL_CB_ERROR;
282  }
283  break;
284  }
285 
286  tb[type] = attr;
287  return MNL_CB_OK;
288 }
289 
290 int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
291 {
292  struct nlattr *tb[NFTA_SET_MAX+1] = {};
293  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
294 
295  if (mnl_attr_parse(nlh, sizeof(*nfg), nft_set_parse_attr_cb, tb) < 0)
296  return -1;
297 
298  if (tb[NFTA_SET_TABLE]) {
299  s->table = strdup(mnl_attr_get_str(tb[NFTA_SET_TABLE]));
300  s->flags |= (1 << NFT_SET_ATTR_TABLE);
301  }
302  if (tb[NFTA_SET_NAME]) {
303  s->name = strdup(mnl_attr_get_str(tb[NFTA_SET_NAME]));
304  s->flags |= (1 << NFT_SET_ATTR_NAME);
305  }
306  if (tb[NFTA_SET_FLAGS]) {
307  s->set_flags = ntohl(mnl_attr_get_u32(tb[NFTA_SET_FLAGS]));
308  s->flags |= (1 << NFT_SET_ATTR_FLAGS);
309  }
310  if (tb[NFTA_SET_KEY_TYPE]) {
311  s->key_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_KEY_TYPE]));
312  s->flags |= (1 << NFT_SET_ATTR_KEY_TYPE);
313  }
314  if (tb[NFTA_SET_KEY_LEN]) {
315  s->key_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_KEY_LEN]));
316  s->flags |= (1 << NFT_SET_ATTR_KEY_LEN);
317  }
318  if (tb[NFTA_SET_DATA_TYPE]) {
319  s->data_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DATA_TYPE]));
320  s->flags |= (1 << NFT_SET_ATTR_DATA_TYPE);
321  }
322  if (tb[NFTA_SET_DATA_LEN]) {
323  s->data_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DATA_LEN]));
324  s->flags |= (1 << NFT_SET_ATTR_DATA_LEN);
325  }
326  if (tb[NFTA_SET_ID]) {
327  s->id = ntohl(mnl_attr_get_u32(tb[NFTA_SET_ID]));
328  s->flags |= (1 << NFT_SET_ATTR_ID);
329  }
330  s->family = nfg->nfgen_family;
331  s->flags |= (1 << NFT_SET_ATTR_FAMILY);
332 
333  return 0;
334 }
335 EXPORT_SYMBOL(nft_set_nlmsg_parse);
336 
337 #ifdef JSON_PARSING
338 int nft_jansson_parse_set(struct nft_set *s, json_t *tree,
339  struct nft_parse_err *err)
340 {
341  json_t *root, *array, *json_elem;
342  uint32_t flags, key_type, key_len, data_type, data_len;
343  int family, i;
344  const char *name, *table;
345  struct nft_set_elem *elem;
346 
347  root = nft_jansson_get_node(tree, "set", err);
348  if (root == NULL)
349  return -1;
350 
351  name = nft_jansson_parse_str(root, "name", err);
352  if (name == NULL)
353  return -1;
354 
355  nft_set_attr_set_str(s, NFT_SET_ATTR_NAME, name);
356 
357  table = nft_jansson_parse_str(root, "table", err);
358  if (table == NULL)
359  return -1;
360 
361  nft_set_attr_set_str(s, NFT_SET_ATTR_TABLE, table);
362 
363  if (nft_jansson_parse_family(root, &family, err) == 0)
364  nft_set_attr_set_u32(s, NFT_SET_ATTR_FAMILY, family);
365 
366  if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &flags, err) == 0)
367  nft_set_attr_set_u32(s, NFT_SET_ATTR_FLAGS, flags);
368 
369  if (nft_jansson_parse_val(root, "key_type", NFT_TYPE_U32, &key_type,
370  err) == 0)
371  nft_set_attr_set_u32(s, NFT_SET_ATTR_KEY_TYPE, key_type);
372 
373  if (nft_jansson_parse_val(root, "key_len", NFT_TYPE_U32, &key_len,
374  err) == 0)
375  nft_set_attr_set_u32(s, NFT_SET_ATTR_KEY_LEN, key_len);
376 
377  if (nft_jansson_node_exist(root, "data_type")) {
378  if (nft_jansson_parse_val(root, "data_type", NFT_TYPE_U32,
379  &data_type, err) < 0)
380  return -1;
381 
382  nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_TYPE, data_type);
383  }
384 
385  if (nft_jansson_node_exist(root, "data_len")) {
386  if (nft_jansson_parse_val(root, "data_len", NFT_TYPE_U32,
387  &data_len, err) < 0)
388  return -1;
389 
390  nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_LEN, data_len);
391  }
392 
393  if (nft_jansson_node_exist(root, "set_elem")) {
394  array = json_object_get(root, "set_elem");
395  for (i = 0; i < json_array_size(array); i++) {
396  elem = nft_set_elem_alloc();
397  if (elem == NULL)
398  return -1;
399 
400  json_elem = json_array_get(array, i);
401  if (json_elem == NULL)
402  return -1;
403 
404  if (nft_jansson_set_elem_parse(elem,
405  json_elem, err) < 0)
406  return -1;
407 
408  list_add_tail(&elem->head, &s->element_list);
409  }
410 
411  }
412 
413  return 0;
414 }
415 #endif
416 
417 static int nft_set_json_parse(struct nft_set *s, const void *json,
418  struct nft_parse_err *err,
419  enum nft_parse_input input)
420 {
421 #ifdef JSON_PARSING
422  json_t *tree;
423  json_error_t error;
424  int ret;
425 
426  tree = nft_jansson_create_root(json, &error, err, input);
427  if (tree == NULL)
428  return -1;
429 
430  ret = nft_jansson_parse_set(s, tree, err);
431  nft_jansson_free_root(tree);
432 
433  return ret;
434 #else
435  errno = EOPNOTSUPP;
436  return -1;
437 #endif
438 }
439 
440 #ifdef XML_PARSING
441 int nft_mxml_set_parse(mxml_node_t *tree, struct nft_set *s,
442  struct nft_parse_err *err)
443 {
444  mxml_node_t *node = NULL;
445  struct nft_set_elem *elem;
446  const char *name, *table;
447  int family;
448  uint32_t set_flags, key_type, key_len;
449  uint32_t data_type, data_len;
450 
451  name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
452  NFT_XML_MAND, err);
453  if (name == NULL)
454  return -1;
455  nft_set_attr_set_str(s, NFT_SET_ATTR_NAME, name);
456 
457  table = nft_mxml_str_parse(tree, "table", MXML_DESCEND_FIRST,
458  NFT_XML_MAND, err);
459  if (table == NULL)
460  return -1;
461  nft_set_attr_set_str(s, NFT_SET_ATTR_TABLE, table);
462 
463  family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
464  NFT_XML_MAND, err);
465  if (family >= 0)
466  nft_set_attr_set_u32(s, NFT_SET_ATTR_FAMILY, family);
467 
468  if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
469  &set_flags, NFT_TYPE_U32, NFT_XML_MAND,
470  err) == 0)
471  nft_set_attr_set_u32(s, NFT_SET_ATTR_FLAGS, set_flags);
472 
473  if (nft_mxml_num_parse(tree, "key_type", MXML_DESCEND_FIRST, BASE_DEC,
474  &key_type, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
475  nft_set_attr_set_u32(s, NFT_SET_ATTR_KEY_TYPE, key_type);
476 
477  if (nft_mxml_num_parse(tree, "key_len", MXML_DESCEND_FIRST, BASE_DEC,
478  &key_len, NFT_TYPE_U32, NFT_XML_MAND, err) < 0)
479  return -1;
480  nft_set_attr_set_u32(s, NFT_SET_ATTR_KEY_LEN, key_len);
481 
482  if (nft_mxml_num_parse(tree, "data_type", MXML_DESCEND_FIRST, BASE_DEC,
483  &data_type, NFT_TYPE_U32,
484  NFT_XML_OPT, err) == 0) {
485  nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_TYPE, data_type);
486 
487  if (nft_mxml_num_parse(tree, "data_len", MXML_DESCEND_FIRST,
488  BASE_DEC, &data_len, NFT_TYPE_U32,
489  NFT_XML_MAND, err) == 0)
490  nft_set_attr_set_u32(s, NFT_SET_ATTR_DATA_LEN, data_len);
491 
492  }
493 
494  for (node = mxmlFindElement(tree, tree, "set_elem", NULL,
495  NULL, MXML_DESCEND);
496  node != NULL;
497  node = mxmlFindElement(node, tree, "set_elem", NULL,
498  NULL, MXML_DESCEND)) {
499 
500  elem = nft_set_elem_alloc();
501  if (elem == NULL)
502  return -1;
503 
504  if (nft_mxml_set_elem_parse(node, elem, err) < 0)
505  return -1;
506 
507  list_add_tail(&elem->head, &s->element_list);
508  }
509 
510  return 0;
511 }
512 #endif
513 
514 static int nft_set_xml_parse(struct nft_set *s, const void *xml,
515  struct nft_parse_err *err,
516  enum nft_parse_input input)
517 {
518 #ifdef XML_PARSING
519  int ret;
520  mxml_node_t *tree = nft_mxml_build_tree(xml, "set", err, input);
521  if (tree == NULL)
522  return -1;
523 
524  ret = nft_mxml_set_parse(tree, s, err);
525  mxmlDelete(tree);
526  return ret;
527 #else
528  errno = EOPNOTSUPP;
529  return -1;
530 #endif
531 }
532 
533 static int nft_set_do_parse(struct nft_set *s, enum nft_parse_type type,
534  const void *data, struct nft_parse_err *err,
535  enum nft_parse_input input)
536 {
537  int ret;
538  struct nft_parse_err perr;
539 
540  switch (type) {
541  case NFT_PARSE_XML:
542  ret = nft_set_xml_parse(s, data, &perr, input);
543  break;
544  case NFT_PARSE_JSON:
545  ret = nft_set_json_parse(s, data, &perr, input);
546  break;
547  default:
548  ret = -1;
549  errno = EOPNOTSUPP;
550  break;
551  }
552 
553  if (err != NULL)
554  *err = perr;
555 
556  return ret;
557 }
558 int nft_set_parse(struct nft_set *s, enum nft_parse_type type,
559  const char *data, struct nft_parse_err *err)
560 {
561  return nft_set_do_parse(s, type, data, err, NFT_PARSE_BUFFER);
562 }
563 EXPORT_SYMBOL(nft_set_parse);
564 
565 int nft_set_parse_file(struct nft_set *s, enum nft_parse_type type,
566  FILE *fp, struct nft_parse_err *err)
567 {
568  return nft_set_do_parse(s, type, fp, err, NFT_PARSE_FILE);
569 }
570 EXPORT_SYMBOL(nft_set_parse_file);
571 
572 static int nft_set_snprintf_json(char *buf, size_t size, struct nft_set *s,
573  uint32_t type, uint32_t flags)
574 {
575  int len = size, offset = 0, ret;
576  struct nft_set_elem *elem;
577 
578  ret = snprintf(buf, len, "{\"set\":{");
579  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
580 
581  if (s->flags & (1 << NFT_SET_ATTR_NAME)) {
582  ret = snprintf(buf + offset, len, "\"name\":\"%s\"",
583  s->name);
584  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
585  }
586  if (s->flags & (1 << NFT_SET_ATTR_TABLE)) {
587  ret = snprintf(buf + offset, len, ",\"table\":\"%s\"",
588  s->table);
589  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
590  }
591  if (s->flags & (1 << NFT_SET_ATTR_FLAGS)) {
592  ret = snprintf(buf + offset, len, ",\"flags\":%u",
593  s->set_flags);
594  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
595  }
596  if (s->flags & (1 << NFT_SET_ATTR_FAMILY)) {
597  ret = snprintf(buf + offset, len, ",\"family\":\"%s\"",
598  nft_family2str(s->family));
599  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
600  }
601  if (s->flags & (1 << NFT_SET_ATTR_KEY_TYPE)) {
602  ret = snprintf(buf + offset, len, ",\"key_type\":%u",
603  s->key_type);
604  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
605  }
606  if (s->flags & (1 << NFT_SET_ATTR_KEY_LEN)) {
607  ret = snprintf(buf + offset, len, ",\"key_len\":%u",
608  s->key_len);
609  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
610  }
611  if(s->flags & (1 << NFT_SET_ATTR_DATA_TYPE)) {
612  ret = snprintf(buf + offset, len,
613  ",\"data_type\":%u", s->data_type);
614  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
615  }
616  if(s->flags & (1 << NFT_SET_ATTR_DATA_LEN)) {
617  ret = snprintf(buf + offset, len, ",\"data_len\":%u", s->data_len);
618  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
619  }
620  /* Empty set? Skip printinf of elements */
621  if (list_empty(&s->element_list)){
622  ret = snprintf(buf + offset, len, "}}");
623  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
624  return offset;
625  }
626 
627  ret = snprintf(buf + offset, len, ",\"set_elem\":[");
628  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
629 
630  list_for_each_entry(elem, &s->element_list, head) {
631  ret = snprintf(buf + offset, len, "{");
632  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
633 
634  ret = nft_set_elem_snprintf(buf + offset, len, elem, type,
635  flags);
636  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
637 
638  ret = snprintf(buf + offset, len, "},");
639  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
640  }
641  /* Overwrite trailing ", " from last set element */
642  offset --;
643 
644  ret = snprintf(buf + offset, len, "]}}");
645  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
646 
647  return offset;
648 }
649 
650 static int nft_set_snprintf_default(char *buf, size_t size, struct nft_set *s,
651  uint32_t type, uint32_t flags)
652 {
653  int ret;
654  int len = size, offset = 0;
655  struct nft_set_elem *elem;
656 
657  ret = snprintf(buf, len, "%s %s %x",
658  s->name, s->table, s->set_flags);
659  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
660 
661  /* Empty set? Skip printinf of elements */
662  if (list_empty(&s->element_list))
663  return offset;
664 
665  ret = snprintf(buf+offset, len, "\n");
666  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
667 
668  list_for_each_entry(elem, &s->element_list, head) {
669  ret = snprintf(buf+offset, len, "\t");
670  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
671 
672  ret = nft_set_elem_snprintf(buf+offset, len, elem, type, flags);
673  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
674  }
675 
676  return offset;
677 }
678 
679 static int nft_set_snprintf_xml(char *buf, size_t size, struct nft_set *s,
680  uint32_t flags)
681 {
682  int ret;
683  int len = size, offset = 0;
684  struct nft_set_elem *elem;
685 
686  ret = snprintf(buf, len, "<set>");
687  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
688 
689  if (s->flags & (1 << NFT_SET_ATTR_FAMILY)) {
690  ret = snprintf(buf + offset, len, "<family>%s</family>",
691  nft_family2str(s->family));
692  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
693  }
694 
695  if (s->flags & (1 << NFT_SET_ATTR_TABLE)) {
696  ret = snprintf(buf + offset, len, "<table>%s</table>",
697  s->table);
698  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
699  }
700 
701  if (s->flags & (1 << NFT_SET_ATTR_NAME)) {
702  ret = snprintf(buf + offset, len, "<name>%s</name>",
703  s->name);
704  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
705  }
706 
707  if (s->flags & (1 << NFT_SET_ATTR_FLAGS)) {
708  ret = snprintf(buf + offset, len, "<flags>%u</flags>",
709  s->set_flags);
710  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
711  }
712  if (s->flags & (1 << NFT_SET_ATTR_KEY_TYPE)) {
713  ret = snprintf(buf + offset, len, "<key_type>%u</key_type>",
714  s->key_type);
715  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
716  }
717  if (s->flags & (1 << NFT_SET_ATTR_KEY_LEN)) {
718  ret = snprintf(buf + offset, len, "<key_len>%u</key_len>",
719  s->key_len);
720  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
721  }
722 
723  if (s->flags & (1 << NFT_SET_ATTR_DATA_TYPE)) {
724  ret = snprintf(buf + offset, len, "<data_type>%u</data_type>",
725  s->data_type);
726  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
727  }
728  if (s->flags & (1 << NFT_SET_ATTR_DATA_LEN)) {
729  ret = snprintf(buf + offset, len, "<data_len>%u</data_len>",
730  s->data_len);
731  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
732  }
733 
734  if (!list_empty(&s->element_list)) {
735  list_for_each_entry(elem, &s->element_list, head) {
736  ret = nft_set_elem_snprintf(buf + offset, len, elem,
737  NFT_OUTPUT_XML, flags);
738  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
739  }
740  }
741 
742  ret = snprintf(buf + offset, len, "</set>");
743  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
744 
745  return offset;
746 }
747 
748 int nft_set_snprintf(char *buf, size_t size, struct nft_set *s,
749  uint32_t type, uint32_t flags)
750 {
751  int ret, len = size, offset = 0;
752  uint32_t inner_flags = flags;
753 
754  /* prevent set_elems to print as events */
755  inner_flags &= ~NFT_OF_EVENT_ANY;
756 
757  ret = nft_event_header_snprintf(buf+offset, len, type, flags);
758  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
759 
760  switch(type) {
761  case NFT_OUTPUT_DEFAULT:
762  ret = nft_set_snprintf_default(buf+offset, len, s, type,
763  inner_flags);
764  break;
765  case NFT_OUTPUT_XML:
766  ret = nft_set_snprintf_xml(buf+offset, len, s, inner_flags);
767  break;
768  case NFT_OUTPUT_JSON:
769  ret = nft_set_snprintf_json(buf+offset, len, s, type,
770  inner_flags);
771  break;
772  default:
773  return -1;
774  }
775 
776  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
777 
778  ret = nft_event_footer_snprintf(buf+offset, len, type, flags);
779  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
780 
781  return offset;
782 }
783 EXPORT_SYMBOL(nft_set_snprintf);
784 
785 static inline int nft_set_do_snprintf(char *buf, size_t size, void *s,
786  uint32_t type, uint32_t flags)
787 {
788  return nft_set_snprintf(buf, size, s, type, flags);
789 }
790 
791 int nft_set_fprintf(FILE *fp, struct nft_set *s, uint32_t type,
792  uint32_t flags)
793 {
794  return nft_fprintf(fp, s, type, flags, nft_set_do_snprintf);
795 }
796 EXPORT_SYMBOL(nft_set_fprintf);
797 
798 void nft_set_elem_add(struct nft_set *s, struct nft_set_elem *elem)
799 {
800  list_add_tail(&elem->head, &s->element_list);
801 }
802 EXPORT_SYMBOL(nft_set_elem_add);
803 
804 struct nft_set_list {
805  struct list_head list;
806 };
807 
808 struct nft_set_list *nft_set_list_alloc(void)
809 {
810  struct nft_set_list *list;
811 
812  list = calloc(1, sizeof(struct nft_set_list));
813  if (list == NULL)
814  return NULL;
815 
816  INIT_LIST_HEAD(&list->list);
817 
818  return list;
819 }
820 EXPORT_SYMBOL(nft_set_list_alloc);
821 
822 void nft_set_list_free(struct nft_set_list *list)
823 {
824  struct nft_set *s, *tmp;
825 
826  list_for_each_entry_safe(s, tmp, &list->list, head) {
827  list_del(&s->head);
828  nft_set_free(s);
829  }
830  xfree(list);
831 }
832 EXPORT_SYMBOL(nft_set_list_free);
833 
834 int nft_set_list_is_empty(struct nft_set_list *list)
835 {
836  return list_empty(&list->list);
837 }
838 EXPORT_SYMBOL(nft_set_list_is_empty);
839 
840 void nft_set_list_add(struct nft_set *s, struct nft_set_list *list)
841 {
842  list_add(&s->head, &list->list);
843 }
844 EXPORT_SYMBOL(nft_set_list_add);
845 
846 void nft_set_list_add_tail(struct nft_set *s, struct nft_set_list *list)
847 {
848  list_add_tail(&s->head, &list->list);
849 }
850 EXPORT_SYMBOL(nft_set_list_add_tail);
851 
852 void nft_set_list_del(struct nft_set *s)
853 {
854  list_del(&s->head);
855 }
856 EXPORT_SYMBOL(nft_set_list_del);
857 
858 int nft_set_list_foreach(struct nft_set_list *set_list,
859  int (*cb)(struct nft_set *t, void *data), void *data)
860 {
861  struct nft_set *cur, *tmp;
862  int ret;
863 
864  list_for_each_entry_safe(cur, tmp, &set_list->list, head) {
865  ret = cb(cur, data);
866  if (ret < 0)
867  return ret;
868  }
869  return 0;
870 }
871 EXPORT_SYMBOL(nft_set_list_foreach);
872 
874  struct nft_set_list *list;
875  struct nft_set *cur;
876 };
877 
878 struct nft_set_list_iter *nft_set_list_iter_create(struct nft_set_list *l)
879 {
880  struct nft_set_list_iter *iter;
881 
882  iter = calloc(1, sizeof(struct nft_set_list_iter));
883  if (iter == NULL)
884  return NULL;
885 
886  iter->list = l;
887  iter->cur = list_entry(l->list.next, struct nft_set, head);
888 
889  return iter;
890 }
891 EXPORT_SYMBOL(nft_set_list_iter_create);
892 
893 struct nft_set *nft_set_list_iter_cur(struct nft_set_list_iter *iter)
894 {
895  return iter->cur;
896 }
897 EXPORT_SYMBOL(nft_set_list_iter_cur);
898 
899 struct nft_set *nft_set_list_iter_next(struct nft_set_list_iter *iter)
900 {
901  struct nft_set *s = iter->cur;
902 
903  /* get next rule, if any */
904  iter->cur = list_entry(iter->cur->head.next, struct nft_set, head);
905  if (&iter->cur->head == iter->list->list.next)
906  return NULL;
907 
908  return s;
909 }
910 EXPORT_SYMBOL(nft_set_list_iter_next);
911 
912 void nft_set_list_iter_destroy(struct nft_set_list_iter *iter)
913 {
914  xfree(iter);
915 }
916 EXPORT_SYMBOL(nft_set_list_iter_destroy);