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