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