libnftnl  1.1.5
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 int nftnl_set_set(struct nftnl_set *s, uint16_t attr, const void *data) __visible;
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_data(s, attr, &val, sizeof(uint32_t));
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_data(s, attr, &val, sizeof(uint64_t));
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 
718 #define SET_NAME_HSIZE 512
719 
721  struct list_head list;
722  struct hlist_head name_hash[SET_NAME_HSIZE];
723 };
724 
725 EXPORT_SYMBOL(nftnl_set_list_alloc);
726 struct nftnl_set_list *nftnl_set_list_alloc(void)
727 {
728  struct nftnl_set_list *list;
729  int i;
730 
731  list = calloc(1, sizeof(struct nftnl_set_list));
732  if (list == NULL)
733  return NULL;
734 
735  INIT_LIST_HEAD(&list->list);
736  for (i = 0; i < SET_NAME_HSIZE; i++)
737  INIT_HLIST_HEAD(&list->name_hash[i]);
738 
739  return list;
740 }
741 
742 EXPORT_SYMBOL(nftnl_set_list_free);
743 void nftnl_set_list_free(struct nftnl_set_list *list)
744 {
745  struct nftnl_set *s, *tmp;
746 
747  list_for_each_entry_safe(s, tmp, &list->list, head) {
748  list_del(&s->head);
749  hlist_del(&s->hnode);
750  nftnl_set_free(s);
751  }
752  xfree(list);
753 }
754 
755 EXPORT_SYMBOL(nftnl_set_list_is_empty);
756 int nftnl_set_list_is_empty(const struct nftnl_set_list *list)
757 {
758  return list_empty(&list->list);
759 }
760 
761 static uint32_t djb_hash(const char *key)
762 {
763  uint32_t i, hash = 5381;
764 
765  for (i = 0; i < strlen(key); i++)
766  hash = ((hash << 5) + hash) + key[i];
767 
768  return hash;
769 }
770 
771 EXPORT_SYMBOL(nftnl_set_list_add);
772 void nftnl_set_list_add(struct nftnl_set *s, struct nftnl_set_list *list)
773 {
774  int key = djb_hash(s->name) % SET_NAME_HSIZE;
775 
776  hlist_add_head(&s->hnode, &list->name_hash[key]);
777  list_add(&s->head, &list->list);
778 }
779 
780 EXPORT_SYMBOL(nftnl_set_list_add_tail);
781 void nftnl_set_list_add_tail(struct nftnl_set *s, struct nftnl_set_list *list)
782 {
783  int key = djb_hash(s->name) % SET_NAME_HSIZE;
784 
785  hlist_add_head(&s->hnode, &list->name_hash[key]);
786  list_add_tail(&s->head, &list->list);
787 }
788 
789 EXPORT_SYMBOL(nftnl_set_list_del);
790 void nftnl_set_list_del(struct nftnl_set *s)
791 {
792  list_del(&s->head);
793  hlist_del(&s->hnode);
794 }
795 
796 EXPORT_SYMBOL(nftnl_set_list_foreach);
797 int nftnl_set_list_foreach(struct nftnl_set_list *set_list,
798  int (*cb)(struct nftnl_set *t, void *data), void *data)
799 {
800  struct nftnl_set *cur, *tmp;
801  int ret;
802 
803  list_for_each_entry_safe(cur, tmp, &set_list->list, head) {
804  ret = cb(cur, data);
805  if (ret < 0)
806  return ret;
807  }
808  return 0;
809 }
810 
812  const struct nftnl_set_list *list;
813  struct nftnl_set *cur;
814 };
815 
816 EXPORT_SYMBOL(nftnl_set_list_iter_create);
817 struct nftnl_set_list_iter *
818 nftnl_set_list_iter_create(const struct nftnl_set_list *l)
819 {
820  struct nftnl_set_list_iter *iter;
821 
822  iter = calloc(1, sizeof(struct nftnl_set_list_iter));
823  if (iter == NULL)
824  return NULL;
825 
826  iter->list = l;
827  if (nftnl_set_list_is_empty(l))
828  iter->cur = NULL;
829  else
830  iter->cur = list_entry(l->list.next, struct nftnl_set, head);
831 
832  return iter;
833 }
834 
835 EXPORT_SYMBOL(nftnl_set_list_iter_cur);
836 struct nftnl_set *
837 nftnl_set_list_iter_cur(const struct nftnl_set_list_iter *iter)
838 {
839  return iter->cur;
840 }
841 
842 EXPORT_SYMBOL(nftnl_set_list_iter_next);
843 struct nftnl_set *nftnl_set_list_iter_next(struct nftnl_set_list_iter *iter)
844 {
845  struct nftnl_set *s = iter->cur;
846 
847  if (s == NULL)
848  return NULL;
849 
850  /* get next rule, if any */
851  iter->cur = list_entry(iter->cur->head.next, struct nftnl_set, head);
852  if (&iter->cur->head == iter->list->list.next)
853  return NULL;
854 
855  return s;
856 }
857 
858 EXPORT_SYMBOL(nftnl_set_list_iter_destroy);
859 void nftnl_set_list_iter_destroy(const struct nftnl_set_list_iter *iter)
860 {
861  xfree(iter);
862 }
863 
864 EXPORT_SYMBOL(nftnl_set_list_lookup_byname);
865 struct nftnl_set *
866 nftnl_set_list_lookup_byname(struct nftnl_set_list *set_list, const char *set)
867 {
868  int key = djb_hash(set) % SET_NAME_HSIZE;
869  struct hlist_node *n;
870  struct nftnl_set *s;
871 
872  hlist_for_each_entry(s, n, &set_list->name_hash[key], hnode) {
873  if (!strcmp(set, s->name))
874  return s;
875  }
876  return NULL;
877 }
878 
879 int nftnl_set_lookup_id(struct nftnl_expr *e,
880  struct nftnl_set_list *set_list, uint32_t *set_id)
881 {
882  const char *set_name;
883  struct nftnl_set *s;
884 
885  set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
886  if (set_name == NULL)
887  return 0;
888 
889  s = nftnl_set_list_lookup_byname(set_list, set_name);
890  if (s == NULL)
891  return 0;
892 
893  *set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
894  return 1;
895 }