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