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