libnftnl  1.2.9
set_elem.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 <netinet/in.h>
15 #include <errno.h>
16 #include <ctype.h>
17 
18 #include <libmnl/libmnl.h>
19 #include <linux/netfilter/nfnetlink.h>
20 #include <linux/netfilter/nf_tables.h>
21 
22 #include <libnftnl/set.h>
23 #include <libnftnl/rule.h>
24 #include <libnftnl/expr.h>
25 
26 EXPORT_SYMBOL(nftnl_set_elem_alloc);
27 struct nftnl_set_elem *nftnl_set_elem_alloc(void)
28 {
29  struct nftnl_set_elem *s;
30 
31  s = calloc(1, sizeof(struct nftnl_set_elem));
32  if (s == NULL)
33  return NULL;
34 
35  INIT_LIST_HEAD(&s->expr_list);
36 
37  return s;
38 }
39 
40 EXPORT_SYMBOL(nftnl_set_elem_free);
41 void nftnl_set_elem_free(struct nftnl_set_elem *s)
42 {
43  struct nftnl_expr *e, *tmp;
44 
45  if (s->flags & (1 << NFTNL_SET_ELEM_CHAIN))
46  xfree(s->data.chain);
47 
48  list_for_each_entry_safe(e, tmp, &s->expr_list, head)
49  nftnl_expr_free(e);
50 
51  if (s->flags & (1 << NFTNL_SET_ELEM_USERDATA))
52  xfree(s->user.data);
53 
54  if (s->flags & (1 << NFTNL_SET_ELEM_OBJREF))
55  xfree(s->objref);
56 
57  xfree(s);
58 }
59 
60 EXPORT_SYMBOL(nftnl_set_elem_is_set);
61 bool nftnl_set_elem_is_set(const struct nftnl_set_elem *s, uint16_t attr)
62 {
63  return s->flags & (1 << attr);
64 }
65 
66 EXPORT_SYMBOL(nftnl_set_elem_unset);
67 void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
68 {
69  struct nftnl_expr *expr, *tmp;
70 
71  if (!(s->flags & (1 << attr)))
72  return;
73 
74  switch (attr) {
75  case NFTNL_SET_ELEM_CHAIN:
76  xfree(s->data.chain);
77  break;
78  case NFTNL_SET_ELEM_FLAGS:
79  case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
80  case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
81  case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
82  case NFTNL_SET_ELEM_DATA: /* NFTA_SET_ELEM_DATA */
83  case NFTNL_SET_ELEM_TIMEOUT: /* NFTA_SET_ELEM_TIMEOUT */
84  case NFTNL_SET_ELEM_EXPIRATION: /* NFTA_SET_ELEM_EXPIRATION */
85  break;
86  case NFTNL_SET_ELEM_USERDATA: /* NFTA_SET_ELEM_USERDATA */
87  xfree(s->user.data);
88  break;
89  case NFTNL_SET_ELEM_EXPR:
90  case NFTNL_SET_ELEM_EXPRESSIONS:
91  list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
92  nftnl_expr_free(expr);
93  break;
94  case NFTNL_SET_ELEM_OBJREF:
95  xfree(s->objref);
96  break;
97  default:
98  return;
99  }
100 
101  s->flags &= ~(1 << attr);
102 }
103 
104 static uint32_t nftnl_set_elem_validate[NFTNL_SET_ELEM_MAX + 1] = {
105  [NFTNL_SET_ELEM_FLAGS] = sizeof(uint32_t),
106  [NFTNL_SET_ELEM_VERDICT] = sizeof(uint32_t),
107  [NFTNL_SET_ELEM_TIMEOUT] = sizeof(uint64_t),
108  [NFTNL_SET_ELEM_EXPIRATION] = sizeof(uint64_t),
109 };
110 
111 EXPORT_SYMBOL(nftnl_set_elem_set);
112 int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
113  const void *data, uint32_t data_len)
114 {
115  struct nftnl_expr *expr, *tmp;
116 
117  nftnl_assert_attr_exists(attr, NFTNL_SET_ELEM_MAX);
118  nftnl_assert_validate(data, nftnl_set_elem_validate, attr, data_len);
119 
120  switch(attr) {
121  case NFTNL_SET_ELEM_FLAGS:
122  memcpy(&s->set_elem_flags, data, sizeof(s->set_elem_flags));
123  break;
124  case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
125  if (nftnl_data_cpy(&s->key, data, data_len) < 0)
126  return -1;
127  break;
128  case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
129  if (nftnl_data_cpy(&s->key_end, data, data_len) < 0)
130  return -1;
131  break;
132  case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
133  memcpy(&s->data.verdict, data, sizeof(s->data.verdict));
134  break;
135  case NFTNL_SET_ELEM_CHAIN: /* NFTA_SET_ELEM_DATA */
136  if (s->flags & (1 << NFTNL_SET_ELEM_CHAIN))
137  xfree(s->data.chain);
138 
139  s->data.chain = strdup(data);
140  if (!s->data.chain)
141  return -1;
142  break;
143  case NFTNL_SET_ELEM_DATA: /* NFTA_SET_ELEM_DATA */
144  if (nftnl_data_cpy(&s->data, data, data_len) < 0)
145  return -1;
146  break;
147  case NFTNL_SET_ELEM_TIMEOUT: /* NFTA_SET_ELEM_TIMEOUT */
148  memcpy(&s->timeout, data, sizeof(s->timeout));
149  break;
150  case NFTNL_SET_ELEM_EXPIRATION: /* NFTA_SET_ELEM_EXPIRATION */
151  memcpy(&s->expiration, data, sizeof(s->expiration));
152  break;
153  case NFTNL_SET_ELEM_USERDATA: /* NFTA_SET_ELEM_USERDATA */
154  if (s->flags & (1 << NFTNL_SET_ELEM_USERDATA))
155  xfree(s->user.data);
156 
157  s->user.data = malloc(data_len);
158  if (!s->user.data)
159  return -1;
160  memcpy(s->user.data, data, data_len);
161  s->user.len = data_len;
162  break;
163  case NFTNL_SET_ELEM_OBJREF:
164  if (s->flags & (1 << NFTNL_SET_ELEM_OBJREF))
165  xfree(s->objref);
166 
167  s->objref = strdup(data);
168  if (!s->objref)
169  return -1;
170  break;
171  case NFTNL_SET_ELEM_EXPR:
172  list_for_each_entry_safe(expr, tmp, &s->expr_list, head)
173  nftnl_expr_free(expr);
174 
175  expr = (void *)data;
176  list_add(&expr->head, &s->expr_list);
177  break;
178  }
179  s->flags |= (1 << attr);
180  return 0;
181 }
182 
183 EXPORT_SYMBOL(nftnl_set_elem_set_u32);
184 void nftnl_set_elem_set_u32(struct nftnl_set_elem *s, uint16_t attr, uint32_t val)
185 {
186  nftnl_set_elem_set(s, attr, &val, sizeof(uint32_t));
187 }
188 
189 EXPORT_SYMBOL(nftnl_set_elem_set_u64);
190 void nftnl_set_elem_set_u64(struct nftnl_set_elem *s, uint16_t attr, uint64_t val)
191 {
192  nftnl_set_elem_set(s, attr, &val, sizeof(uint64_t));
193 }
194 
195 EXPORT_SYMBOL(nftnl_set_elem_set_str);
196 int nftnl_set_elem_set_str(struct nftnl_set_elem *s, uint16_t attr, const char *str)
197 {
198  return nftnl_set_elem_set(s, attr, str, strlen(str) + 1);
199 }
200 
201 EXPORT_SYMBOL(nftnl_set_elem_get);
202 const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t *data_len)
203 {
204  struct nftnl_expr *expr;
205 
206  if (!(s->flags & (1 << attr)))
207  return NULL;
208 
209  switch(attr) {
210  case NFTNL_SET_ELEM_FLAGS:
211  *data_len = sizeof(s->set_elem_flags);
212  return &s->set_elem_flags;
213  case NFTNL_SET_ELEM_KEY: /* NFTA_SET_ELEM_KEY */
214  *data_len = s->key.len;
215  return &s->key.val;
216  case NFTNL_SET_ELEM_KEY_END: /* NFTA_SET_ELEM_KEY_END */
217  *data_len = s->key_end.len;
218  return &s->key_end.val;
219  case NFTNL_SET_ELEM_VERDICT: /* NFTA_SET_ELEM_DATA */
220  *data_len = sizeof(s->data.verdict);
221  return &s->data.verdict;
222  case NFTNL_SET_ELEM_CHAIN: /* NFTA_SET_ELEM_DATA */
223  *data_len = strlen(s->data.chain) + 1;
224  return s->data.chain;
225  case NFTNL_SET_ELEM_DATA: /* NFTA_SET_ELEM_DATA */
226  *data_len = s->data.len;
227  return &s->data.val;
228  case NFTNL_SET_ELEM_TIMEOUT: /* NFTA_SET_ELEM_TIMEOUT */
229  *data_len = sizeof(s->timeout);
230  return &s->timeout;
231  case NFTNL_SET_ELEM_EXPIRATION: /* NFTA_SET_ELEM_EXPIRATION */
232  *data_len = sizeof(s->expiration);
233  return &s->expiration;
234  case NFTNL_SET_ELEM_USERDATA:
235  *data_len = s->user.len;
236  return s->user.data;
237  case NFTNL_SET_ELEM_EXPR:
238  list_for_each_entry(expr, &s->expr_list, head)
239  break;
240  return expr;
241  case NFTNL_SET_ELEM_OBJREF:
242  *data_len = strlen(s->objref) + 1;
243  return s->objref;
244  }
245  return NULL;
246 }
247 
248 EXPORT_SYMBOL(nftnl_set_elem_get_str);
249 const char *nftnl_set_elem_get_str(struct nftnl_set_elem *s, uint16_t attr)
250 {
251  uint32_t size;
252 
253  return nftnl_set_elem_get(s, attr, &size);
254 }
255 
256 EXPORT_SYMBOL(nftnl_set_elem_get_u32);
257 uint32_t nftnl_set_elem_get_u32(struct nftnl_set_elem *s, uint16_t attr)
258 {
259  uint32_t size, val;
260 
261  memcpy(&val, nftnl_set_elem_get(s, attr, &size), sizeof(val));
262 
263  return val;
264 }
265 
266 EXPORT_SYMBOL(nftnl_set_elem_get_u64);
267 uint64_t nftnl_set_elem_get_u64(struct nftnl_set_elem *s, uint16_t attr)
268 {
269  uint32_t size;
270  uint64_t val;
271 
272  memcpy(&val, nftnl_set_elem_get(s, attr, &size), sizeof(val));
273 
274  return val;
275 }
276 
277 struct nftnl_set_elem *nftnl_set_elem_clone(struct nftnl_set_elem *elem)
278 {
279  struct nftnl_set_elem *newelem;
280 
281  newelem = nftnl_set_elem_alloc();
282  if (newelem == NULL)
283  return NULL;
284 
285  memcpy(newelem, elem, sizeof(*elem));
286 
287  if (elem->flags & (1 << NFTNL_SET_ELEM_CHAIN)) {
288  newelem->data.chain = strdup(elem->data.chain);
289  if (!newelem->data.chain)
290  goto err;
291  }
292 
293  return newelem;
294 err:
295  nftnl_set_elem_free(newelem);
296  return NULL;
297 }
298 
299 EXPORT_SYMBOL(nftnl_set_elem_nlmsg_build_payload);
300 void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
301  struct nftnl_set_elem *e)
302 {
303  struct nftnl_expr *expr;
304  int num_exprs = 0;
305 
306  if (e->flags & (1 << NFTNL_SET_ELEM_FLAGS))
307  mnl_attr_put_u32(nlh, NFTA_SET_ELEM_FLAGS, htonl(e->set_elem_flags));
308  if (e->flags & (1 << NFTNL_SET_ELEM_TIMEOUT))
309  mnl_attr_put_u64(nlh, NFTA_SET_ELEM_TIMEOUT, htobe64(e->timeout));
310  if (e->flags & (1 << NFTNL_SET_ELEM_EXPIRATION))
311  mnl_attr_put_u64(nlh, NFTA_SET_ELEM_EXPIRATION, htobe64(e->expiration));
312  if (e->flags & (1 << NFTNL_SET_ELEM_KEY)) {
313  struct nlattr *nest1;
314 
315  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_KEY);
316  mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key.len, e->key.val);
317  mnl_attr_nest_end(nlh, nest1);
318  }
319  if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) {
320  struct nlattr *nest1;
321 
322  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_KEY_END);
323  mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key_end.len,
324  e->key_end.val);
325  mnl_attr_nest_end(nlh, nest1);
326  }
327  if (e->flags & (1 << NFTNL_SET_ELEM_VERDICT)) {
328  struct nlattr *nest1, *nest2;
329 
330  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_DATA);
331  nest2 = mnl_attr_nest_start(nlh, NFTA_DATA_VERDICT);
332  mnl_attr_put_u32(nlh, NFTA_VERDICT_CODE, htonl(e->data.verdict));
333  if (e->flags & (1 << NFTNL_SET_ELEM_CHAIN))
334  mnl_attr_put_strz(nlh, NFTA_VERDICT_CHAIN, e->data.chain);
335 
336  mnl_attr_nest_end(nlh, nest1);
337  mnl_attr_nest_end(nlh, nest2);
338  }
339  if (e->flags & (1 << NFTNL_SET_ELEM_DATA)) {
340  struct nlattr *nest1;
341 
342  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_DATA);
343  mnl_attr_put(nlh, NFTA_DATA_VALUE, e->data.len, e->data.val);
344  mnl_attr_nest_end(nlh, nest1);
345  }
346  if (e->flags & (1 << NFTNL_SET_ELEM_USERDATA))
347  mnl_attr_put(nlh, NFTA_SET_ELEM_USERDATA, e->user.len, e->user.data);
348  if (e->flags & (1 << NFTNL_SET_ELEM_OBJREF))
349  mnl_attr_put_strz(nlh, NFTA_SET_ELEM_OBJREF, e->objref);
350 
351  if (!list_empty(&e->expr_list)) {
352  list_for_each_entry(expr, &e->expr_list, head)
353  num_exprs++;
354 
355  if (num_exprs == 1) {
356  struct nlattr *nest1;
357 
358  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPR);
359  list_for_each_entry(expr, &e->expr_list, head)
360  nftnl_expr_build_payload(nlh, expr);
361 
362  mnl_attr_nest_end(nlh, nest1);
363  } else if (num_exprs > 1) {
364  struct nlattr *nest1, *nest2;
365 
366  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPRESSIONS);
367  list_for_each_entry(expr, &e->expr_list, head) {
368  nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
369  nftnl_expr_build_payload(nlh, expr);
370  mnl_attr_nest_end(nlh, nest2);
371  }
372  mnl_attr_nest_end(nlh, nest1);
373  }
374  }
375 }
376 
377 static void nftnl_set_elem_nlmsg_build_def(struct nlmsghdr *nlh,
378  const struct nftnl_set *s)
379 {
380  if (s->flags & (1 << NFTNL_SET_NAME))
381  mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_SET, s->name);
382  if (s->flags & (1 << NFTNL_SET_ID))
383  mnl_attr_put_u32(nlh, NFTA_SET_ELEM_LIST_SET_ID, htonl(s->id));
384  if (s->flags & (1 << NFTNL_SET_TABLE))
385  mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE, s->table);
386 }
387 
388 EXPORT_SYMBOL(nftnl_set_elem_nlmsg_build);
389 struct nlattr *nftnl_set_elem_nlmsg_build(struct nlmsghdr *nlh,
390  struct nftnl_set_elem *elem, int i)
391 {
392  struct nlattr *nest2;
393 
394  nest2 = mnl_attr_nest_start(nlh, i);
395  nftnl_set_elem_nlmsg_build_payload(nlh, elem);
396  mnl_attr_nest_end(nlh, nest2);
397 
398  return nest2;
399 }
400 
401 EXPORT_SYMBOL(nftnl_set_elems_nlmsg_build_payload);
402 void nftnl_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
403 {
404  struct nftnl_set_elem *elem;
405  struct nlattr *nest1;
406  int i = 0;
407 
408  nftnl_set_elem_nlmsg_build_def(nlh, s);
409 
410  if (list_empty(&s->element_list))
411  return;
412 
413  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
414  list_for_each_entry(elem, &s->element_list, head)
415  nftnl_set_elem_nlmsg_build(nlh, elem, ++i);
416 
417  mnl_attr_nest_end(nlh, nest1);
418 }
419 
420 EXPORT_SYMBOL(nftnl_set_elem_add_expr);
421 void nftnl_set_elem_add_expr(struct nftnl_set_elem *e, struct nftnl_expr *expr)
422 {
423  list_add_tail(&expr->head, &e->expr_list);
424 }
425 
426 EXPORT_SYMBOL(nftnl_set_elem_expr_foreach);
427 int nftnl_set_elem_expr_foreach(struct nftnl_set_elem *e,
428  int (*cb)(struct nftnl_expr *e, void *data),
429  void *data)
430 {
431  struct nftnl_expr *cur, *tmp;
432  int ret;
433 
434  list_for_each_entry_safe(cur, tmp, &e->expr_list, head) {
435  ret = cb(cur, data);
436  if (ret < 0)
437  return ret;
438  }
439  return 0;
440 }
441 
442 static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
443 {
444  const struct nlattr **tb = data;
445  int type = mnl_attr_get_type(attr);
446 
447  if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
448  return MNL_CB_OK;
449 
450  switch(type) {
451  case NFTA_SET_ELEM_FLAGS:
452  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
453  abi_breakage();
454  break;
455  case NFTA_SET_ELEM_TIMEOUT:
456  case NFTA_SET_ELEM_EXPIRATION:
457  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
458  abi_breakage();
459  break;
460  case NFTA_SET_ELEM_KEY:
461  case NFTA_SET_ELEM_KEY_END:
462  case NFTA_SET_ELEM_DATA:
463  case NFTA_SET_ELEM_EXPR:
464  case NFTA_SET_ELEM_EXPRESSIONS:
465  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
466  abi_breakage();
467  break;
468  case NFTA_SET_ELEM_USERDATA:
469  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
470  abi_breakage();
471  break;
472  }
473 
474  tb[type] = attr;
475  return MNL_CB_OK;
476 }
477 
478 static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest)
479 {
480  struct nlattr *tb[NFTA_SET_ELEM_MAX+1] = {};
481  struct nftnl_set_elem *e;
482  int ret, type;
483 
484  e = nftnl_set_elem_alloc();
485  if (e == NULL)
486  return -1;
487 
488  ret = mnl_attr_parse_nested(nest, nftnl_set_elem_parse_attr_cb, tb);
489  if (ret < 0)
490  goto out_set_elem;
491 
492  if (tb[NFTA_SET_ELEM_FLAGS]) {
493  e->set_elem_flags =
494  ntohl(mnl_attr_get_u32(tb[NFTA_SET_ELEM_FLAGS]));
495  e->flags |= (1 << NFTNL_SET_ELEM_FLAGS);
496  }
497  if (tb[NFTA_SET_ELEM_TIMEOUT]) {
498  e->timeout = be64toh(mnl_attr_get_u64(tb[NFTA_SET_ELEM_TIMEOUT]));
499  e->flags |= (1 << NFTNL_SET_ELEM_TIMEOUT);
500  }
501  if (tb[NFTA_SET_ELEM_EXPIRATION]) {
502  e->expiration = be64toh(mnl_attr_get_u64(tb[NFTA_SET_ELEM_EXPIRATION]));
503  e->flags |= (1 << NFTNL_SET_ELEM_EXPIRATION);
504  }
505  if (tb[NFTA_SET_ELEM_KEY]) {
506  ret = nftnl_parse_data(&e->key, tb[NFTA_SET_ELEM_KEY], &type);
507  if (ret < 0)
508  goto out_set_elem;
509  e->flags |= (1 << NFTNL_SET_ELEM_KEY);
510  }
511  if (tb[NFTA_SET_ELEM_KEY_END]) {
512  ret = nftnl_parse_data(&e->key_end, tb[NFTA_SET_ELEM_KEY_END],
513  &type);
514  if (ret < 0)
515  goto out_set_elem;
516  e->flags |= (1 << NFTNL_SET_ELEM_KEY_END);
517  }
518  if (tb[NFTA_SET_ELEM_DATA]) {
519  ret = nftnl_parse_data(&e->data, tb[NFTA_SET_ELEM_DATA], &type);
520  if (ret < 0)
521  goto out_set_elem;
522  switch(type) {
523  case DATA_VERDICT:
524  e->flags |= (1 << NFTNL_SET_ELEM_VERDICT);
525  break;
526  case DATA_CHAIN:
527  e->flags |= (1 << NFTNL_SET_ELEM_VERDICT) |
528  (1 << NFTNL_SET_ELEM_CHAIN);
529  break;
530  case DATA_VALUE:
531  e->flags |= (1 << NFTNL_SET_ELEM_DATA);
532  break;
533  }
534  }
535  if (tb[NFTA_SET_ELEM_EXPR]) {
536  struct nftnl_expr *expr;
537 
538  expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]);
539  if (expr == NULL) {
540  ret = -1;
541  goto out_set_elem;
542  }
543  list_add_tail(&expr->head, &e->expr_list);
544  e->flags |= (1 << NFTNL_SET_ELEM_EXPR);
545  } else if (tb[NFTA_SET_ELEM_EXPRESSIONS]) {
546  struct nftnl_expr *expr;
547  struct nlattr *attr;
548 
549  mnl_attr_for_each_nested(attr, tb[NFTA_SET_ELEM_EXPRESSIONS]) {
550  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM) {
551  ret = -1;
552  goto out_set_elem;
553  }
554  expr = nftnl_expr_parse(attr);
555  if (expr == NULL) {
556  ret = -1;
557  goto out_set_elem;
558  }
559  list_add_tail(&expr->head, &e->expr_list);
560  }
561  e->flags |= (1 << NFTNL_SET_ELEM_EXPRESSIONS);
562  }
563  if (tb[NFTA_SET_ELEM_USERDATA]) {
564  const void *udata =
565  mnl_attr_get_payload(tb[NFTA_SET_ELEM_USERDATA]);
566 
567  if (e->flags & (1 << NFTNL_RULE_USERDATA))
568  xfree(e->user.data);
569 
570  e->user.len = mnl_attr_get_payload_len(tb[NFTA_SET_ELEM_USERDATA]);
571  e->user.data = malloc(e->user.len);
572  if (e->user.data == NULL) {
573  ret = -1;
574  goto out_set_elem;
575  }
576  memcpy(e->user.data, udata, e->user.len);
577  e->flags |= (1 << NFTNL_RULE_USERDATA);
578  }
579  if (tb[NFTA_SET_ELEM_OBJREF]) {
580  e->objref = strdup(mnl_attr_get_str(tb[NFTA_SET_ELEM_OBJREF]));
581  if (e->objref == NULL) {
582  ret = -1;
583  goto out_set_elem;
584  }
585  e->flags |= (1 << NFTNL_SET_ELEM_OBJREF);
586  }
587 
588  /* Add this new element to this set */
589  list_add_tail(&e->head, &s->element_list);
590 
591  return 0;
592 out_set_elem:
593  nftnl_set_elem_free(e);
594  return ret;
595 }
596 
597 static int
598 nftnl_set_elem_list_parse_attr_cb(const struct nlattr *attr, void *data)
599 {
600  const struct nlattr **tb = data;
601  int type = mnl_attr_get_type(attr);
602 
603  if (mnl_attr_type_valid(attr, NFTA_SET_ELEM_LIST_MAX) < 0)
604  return MNL_CB_OK;
605 
606  switch(type) {
607  case NFTA_SET_ELEM_LIST_TABLE:
608  case NFTA_SET_ELEM_LIST_SET:
609  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
610  abi_breakage();
611  break;
612  case NFTA_SET_ELEM_LIST_ELEMENTS:
613  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
614  abi_breakage();
615  break;
616  }
617 
618  tb[type] = attr;
619  return MNL_CB_OK;
620 }
621 
622 static int nftnl_set_elems_parse(struct nftnl_set *s, const struct nlattr *nest)
623 {
624  struct nlattr *attr;
625  int ret = 0;
626 
627  mnl_attr_for_each_nested(attr, nest) {
628  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
629  return -1;
630 
631  ret = nftnl_set_elems_parse2(s, attr);
632  if (ret < 0)
633  return ret;
634  }
635  return ret;
636 }
637 
638 EXPORT_SYMBOL(nftnl_set_elems_nlmsg_parse);
639 int nftnl_set_elems_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
640 {
641  struct nlattr *tb[NFTA_SET_ELEM_LIST_MAX+1] = {};
642  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
643  int ret;
644 
645  if (mnl_attr_parse(nlh, sizeof(*nfg),
646  nftnl_set_elem_list_parse_attr_cb, tb) < 0)
647  return -1;
648 
649  if (tb[NFTA_SET_ELEM_LIST_TABLE]) {
650  if (s->flags & (1 << NFTNL_SET_TABLE))
651  xfree(s->table);
652  s->table =
653  strdup(mnl_attr_get_str(tb[NFTA_SET_ELEM_LIST_TABLE]));
654  if (!s->table)
655  return -1;
656  s->flags |= (1 << NFTNL_SET_TABLE);
657  }
658  if (tb[NFTA_SET_ELEM_LIST_SET]) {
659  if (s->flags & (1 << NFTNL_SET_NAME))
660  xfree(s->name);
661  s->name =
662  strdup(mnl_attr_get_str(tb[NFTA_SET_ELEM_LIST_SET]));
663  if (!s->name)
664  return -1;
665  s->flags |= (1 << NFTNL_SET_NAME);
666  }
667  if (tb[NFTA_SET_ELEM_LIST_SET_ID]) {
668  s->id = ntohl(mnl_attr_get_u32(tb[NFTA_SET_ELEM_LIST_SET_ID]));
669  s->flags |= (1 << NFTNL_SET_ID);
670  }
671  if (tb[NFTA_SET_ELEM_LIST_ELEMENTS]) {
672  ret = nftnl_set_elems_parse(s, tb[NFTA_SET_ELEM_LIST_ELEMENTS]);
673  if (ret < 0)
674  return ret;
675  }
676 
677  s->family = nfg->nfgen_family;
678  s->flags |= (1 << NFTNL_SET_FAMILY);
679 
680  return 0;
681 }
682 
683 EXPORT_SYMBOL(nftnl_set_elem_parse);
684 int nftnl_set_elem_parse(struct nftnl_set_elem *e, enum nftnl_parse_type type,
685  const char *data, struct nftnl_parse_err *err)
686 {
687  errno = EOPNOTSUPP;
688  return -1;
689 }
690 
691 EXPORT_SYMBOL(nftnl_set_elem_parse_file);
692 int nftnl_set_elem_parse_file(struct nftnl_set_elem *e, enum nftnl_parse_type type,
693  FILE *fp, struct nftnl_parse_err *err)
694 {
695  errno = EOPNOTSUPP;
696  return -1;
697 }
698 
699 int nftnl_set_elem_snprintf_default(char *buf, size_t remain,
700  const struct nftnl_set_elem *e)
701 {
702  int ret, dregtype = DATA_VALUE, offset = 0, i;
703 
704  ret = snprintf(buf, remain, "element ");
705  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
706 
707  ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key,
708  DATA_F_NOPFX, DATA_VALUE);
709  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
710 
711  if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) {
712  ret = snprintf(buf + offset, remain, " - ");
713  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
714 
715  ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key_end,
716  DATA_F_NOPFX, DATA_VALUE);
717  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
718  }
719 
720  ret = snprintf(buf + offset, remain, " : ");
721  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
722 
723  if (e->flags & (1 << NFTNL_SET_ELEM_VERDICT))
724  dregtype = DATA_VERDICT;
725 
726  ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->data,
727  DATA_F_NOPFX, dregtype);
728  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
729 
730  ret = snprintf(buf + offset, remain, "%u [end]", e->set_elem_flags);
731  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
732 
733  if (e->user.len) {
734  ret = snprintf(buf + offset, remain, " userdata = { ");
735  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
736 
737  for (i = 0; i < e->user.len; i++) {
738  char *c = e->user.data;
739 
740  ret = snprintf(buf + offset, remain,
741  isprint(c[i]) ? "%c" : "\\x%02hhx",
742  c[i]);
743  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
744  }
745 
746  ret = snprintf(buf + offset, remain, " }");
747  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
748  }
749 
750  return offset;
751 }
752 
753 static int nftnl_set_elem_cmd_snprintf(char *buf, size_t remain,
754  const struct nftnl_set_elem *e,
755  uint32_t cmd, uint32_t type,
756  uint32_t flags)
757 {
758  int ret, offset = 0;
759 
760  if (type != NFTNL_OUTPUT_DEFAULT)
761  return -1;
762 
763  ret = nftnl_set_elem_snprintf_default(buf + offset, remain, e);
764  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
765 
766  return offset;
767 }
768 
769 EXPORT_SYMBOL(nftnl_set_elem_snprintf);
770 int nftnl_set_elem_snprintf(char *buf, size_t size,
771  const struct nftnl_set_elem *e,
772  uint32_t type, uint32_t flags)
773 {
774  if (size)
775  buf[0] = '\0';
776 
777  return nftnl_set_elem_cmd_snprintf(buf, size, e, nftnl_flag2cmd(flags),
778  type, flags);
779 }
780 
781 static int nftnl_set_elem_do_snprintf(char *buf, size_t size, const void *e,
782  uint32_t cmd, uint32_t type,
783  uint32_t flags)
784 {
785  return nftnl_set_elem_snprintf(buf, size, e, type, flags);
786 }
787 
788 EXPORT_SYMBOL(nftnl_set_elem_fprintf);
789 int nftnl_set_elem_fprintf(FILE *fp, const struct nftnl_set_elem *se, uint32_t type,
790  uint32_t flags)
791 {
792  return nftnl_fprintf(fp, se, NFTNL_CMD_UNSPEC, type, flags,
793  nftnl_set_elem_do_snprintf);
794 }
795 
796 EXPORT_SYMBOL(nftnl_set_elem_foreach);
797 int nftnl_set_elem_foreach(struct nftnl_set *s,
798  int (*cb)(struct nftnl_set_elem *e, void *data),
799  void *data)
800 {
801  struct nftnl_set_elem *elem;
802  int ret;
803 
804  list_for_each_entry(elem, &s->element_list, head) {
805  ret = cb(elem, data);
806  if (ret < 0)
807  return ret;
808  }
809  return 0;
810 }
811 
813  const struct nftnl_set *set;
814  const struct list_head *list;
815  struct nftnl_set_elem *cur;
816 };
817 
818 EXPORT_SYMBOL(nftnl_set_elems_iter_create);
819 struct nftnl_set_elems_iter *
820 nftnl_set_elems_iter_create(const struct nftnl_set *s)
821 {
822  struct nftnl_set_elems_iter *iter;
823 
824  iter = calloc(1, sizeof(struct nftnl_set_elems_iter));
825  if (iter == NULL)
826  return NULL;
827 
828  iter->set = s;
829  iter->list = &s->element_list;
830  if (list_empty(&s->element_list))
831  iter->cur = NULL;
832  else
833  iter->cur = list_entry(s->element_list.next,
834  struct nftnl_set_elem, head);
835 
836  return iter;
837 }
838 
839 EXPORT_SYMBOL(nftnl_set_elems_iter_cur);
840 struct nftnl_set_elem *
841 nftnl_set_elems_iter_cur(const struct nftnl_set_elems_iter *iter)
842 {
843  return iter->cur;
844 }
845 
846 EXPORT_SYMBOL(nftnl_set_elems_iter_next);
847 struct nftnl_set_elem *nftnl_set_elems_iter_next(struct nftnl_set_elems_iter *iter)
848 {
849  struct nftnl_set_elem *s = iter->cur;
850 
851  if (s == NULL)
852  return NULL;
853 
854  iter->cur = list_entry(iter->cur->head.next, struct nftnl_set_elem, head);
855  if (&iter->cur->head == iter->list->next)
856  return NULL;
857 
858  return s;
859 }
860 
861 EXPORT_SYMBOL(nftnl_set_elems_iter_destroy);
862 void nftnl_set_elems_iter_destroy(struct nftnl_set_elems_iter *iter)
863 {
864  xfree(iter);
865 }
866 
867 static bool nftnl_attr_nest_overflow(struct nlmsghdr *nlh,
868  const struct nlattr *from,
869  const struct nlattr *to)
870 {
871  int len = (void *)to + to->nla_len - (void *)from;
872 
873  /* The attribute length field is 16 bits long, thus the maximum payload
874  * that an attribute can convey is UINT16_MAX. In case of overflow,
875  * discard the last that did not fit into the attribute.
876  */
877  if (len > UINT16_MAX) {
878  nlh->nlmsg_len -= to->nla_len;
879  return true;
880  }
881  return false;
882 }
883 
884 EXPORT_SYMBOL(nftnl_set_elems_nlmsg_build_payload_iter);
885 int nftnl_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh,
886  struct nftnl_set_elems_iter *iter)
887 {
888  struct nftnl_set_elem *elem;
889  struct nlattr *nest1, *nest2;
890  int i = 0, ret = 0;
891 
892  nftnl_set_elem_nlmsg_build_def(nlh, iter->set);
893 
894  /* This set is empty, don't add an empty list element nest. */
895  if (list_empty(&iter->set->element_list))
896  return ret;
897 
898  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
899  elem = nftnl_set_elems_iter_next(iter);
900  while (elem != NULL) {
901  nest2 = nftnl_set_elem_nlmsg_build(nlh, elem, ++i);
902  if (nftnl_attr_nest_overflow(nlh, nest1, nest2)) {
903  /* Go back to previous not to miss this element */
904  iter->cur = list_entry(iter->cur->head.prev,
905  struct nftnl_set_elem, head);
906  ret = 1;
907  break;
908  }
909  elem = nftnl_set_elems_iter_next(iter);
910  }
911  mnl_attr_nest_end(nlh, nest1);
912 
913  return ret;
914 }