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