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