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