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