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