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