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