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