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