libnftnl  1.0.8
table.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 <limits.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <netinet/in.h>
20 #include <errno.h>
21 
22 #include <libmnl/libmnl.h>
23 #include <linux/netfilter/nfnetlink.h>
24 #include <linux/netfilter/nf_tables.h>
25 
26 #include <libnftnl/table.h>
27 #include <buffer.h>
28 
29 struct nftnl_table {
30  struct list_head head;
31 
32  const char *name;
33  uint32_t family;
34  uint32_t table_flags;
35  uint32_t use;
36  uint32_t flags;
37 };
38 
39 struct nftnl_table *nftnl_table_alloc(void)
40 {
41  return calloc(1, sizeof(struct nftnl_table));
42 }
43 EXPORT_SYMBOL(nftnl_table_alloc);
44 
45 void nftnl_table_free(const struct nftnl_table *t)
46 {
47  if (t->flags & (1 << NFTNL_TABLE_NAME))
48  xfree(t->name);
49 
50  xfree(t);
51 }
52 EXPORT_SYMBOL(nftnl_table_free);
53 
54 bool nftnl_table_is_set(const struct nftnl_table *t, uint16_t attr)
55 {
56  return t->flags & (1 << attr);
57 }
58 EXPORT_SYMBOL(nftnl_table_is_set);
59 
60 void nftnl_table_unset(struct nftnl_table *t, uint16_t attr)
61 {
62  if (!(t->flags & (1 << attr)))
63  return;
64 
65  switch (attr) {
66  case NFTNL_TABLE_NAME:
67  xfree(t->name);
68  break;
69  case NFTNL_TABLE_FLAGS:
70  case NFTNL_TABLE_FAMILY:
71  break;
72  case NFTNL_TABLE_USE:
73  break;
74  }
75  t->flags &= ~(1 << attr);
76 }
77 EXPORT_SYMBOL(nftnl_table_unset);
78 
79 static uint32_t nftnl_table_validate[NFTNL_TABLE_MAX + 1] = {
80  [NFTNL_TABLE_FLAGS] = sizeof(uint32_t),
81  [NFTNL_TABLE_FAMILY] = sizeof(uint32_t),
82 };
83 
84 int nftnl_table_set_data(struct nftnl_table *t, uint16_t attr,
85  const void *data, uint32_t data_len)
86 {
87  nftnl_assert_attr_exists(attr, NFTNL_TABLE_MAX);
88  nftnl_assert_validate(data, nftnl_table_validate, attr, data_len);
89 
90  switch (attr) {
91  case NFTNL_TABLE_NAME:
92  if (t->flags & (1 << NFTNL_TABLE_NAME))
93  xfree(t->name);
94 
95  t->name = strdup(data);
96  if (!t->name)
97  return -1;
98  break;
99  case NFTNL_TABLE_FLAGS:
100  t->table_flags = *((uint32_t *)data);
101  break;
102  case NFTNL_TABLE_FAMILY:
103  t->family = *((uint32_t *)data);
104  break;
105  case NFTNL_TABLE_USE:
106  t->use = *((uint32_t *)data);
107  break;
108  }
109  t->flags |= (1 << attr);
110  return 0;
111 }
112 EXPORT_SYMBOL(nftnl_table_set_data);
113 
114 void nftnl_table_set(struct nftnl_table *t, uint16_t attr, const void *data)
115 {
116  nftnl_table_set_data(t, attr, data, nftnl_table_validate[attr]);
117 }
118 EXPORT_SYMBOL(nftnl_table_set);
119 
120 void nftnl_table_set_u32(struct nftnl_table *t, uint16_t attr, uint32_t val)
121 {
122  nftnl_table_set_data(t, attr, &val, sizeof(uint32_t));
123 }
124 EXPORT_SYMBOL(nftnl_table_set_u32);
125 
126 void nftnl_table_set_u8(struct nftnl_table *t, uint16_t attr, uint8_t val)
127 {
128  nftnl_table_set_data(t, attr, &val, sizeof(uint8_t));
129 }
130 EXPORT_SYMBOL(nftnl_table_set_u8);
131 
132 int nftnl_table_set_str(struct nftnl_table *t, uint16_t attr, const char *str)
133 {
134  return nftnl_table_set_data(t, attr, str, strlen(str) + 1);
135 }
136 EXPORT_SYMBOL(nftnl_table_set_str);
137 
138 const void *nftnl_table_get_data(const struct nftnl_table *t, uint16_t attr,
139  uint32_t *data_len)
140 {
141  if (!(t->flags & (1 << attr)))
142  return NULL;
143 
144  switch(attr) {
145  case NFTNL_TABLE_NAME:
146  *data_len = strlen(t->name) + 1;
147  return t->name;
148  case NFTNL_TABLE_FLAGS:
149  *data_len = sizeof(uint32_t);
150  return &t->table_flags;
151  case NFTNL_TABLE_FAMILY:
152  *data_len = sizeof(uint32_t);
153  return &t->family;
154  case NFTNL_TABLE_USE:
155  *data_len = sizeof(uint32_t);
156  return &t->use;
157  }
158  return NULL;
159 }
160 EXPORT_SYMBOL(nftnl_table_get_data);
161 
162 const void *nftnl_table_get(const struct nftnl_table *t, uint16_t attr)
163 {
164  uint32_t data_len;
165  return nftnl_table_get_data(t, attr, &data_len);
166 }
167 EXPORT_SYMBOL(nftnl_table_get);
168 
169 uint32_t nftnl_table_get_u32(const struct nftnl_table *t, uint16_t attr)
170 {
171  const void *ret = nftnl_table_get(t, attr);
172  return ret == NULL ? 0 : *((uint32_t *)ret);
173 }
174 EXPORT_SYMBOL(nftnl_table_get_u32);
175 
176 uint8_t nftnl_table_get_u8(const struct nftnl_table *t, uint16_t attr)
177 {
178  const void *ret = nftnl_table_get(t, attr);
179  return ret == NULL ? 0 : *((uint8_t *)ret);
180 }
181 EXPORT_SYMBOL(nftnl_table_get_u8);
182 
183 const char *nftnl_table_get_str(const struct nftnl_table *t, uint16_t attr)
184 {
185  return nftnl_table_get(t, attr);
186 }
187 EXPORT_SYMBOL(nftnl_table_get_str);
188 
189 void nftnl_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_table *t)
190 {
191  if (t->flags & (1 << NFTNL_TABLE_NAME))
192  mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, t->name);
193  if (t->flags & (1 << NFTNL_TABLE_FLAGS))
194  mnl_attr_put_u32(nlh, NFTA_TABLE_FLAGS, htonl(t->table_flags));
195 }
196 EXPORT_SYMBOL(nftnl_table_nlmsg_build_payload);
197 
198 static int nftnl_table_parse_attr_cb(const struct nlattr *attr, void *data)
199 {
200  const struct nlattr **tb = data;
201  int type = mnl_attr_get_type(attr);
202 
203  if (mnl_attr_type_valid(attr, NFTA_TABLE_MAX) < 0)
204  return MNL_CB_OK;
205 
206  switch(type) {
207  case NFTA_TABLE_NAME:
208  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
209  abi_breakage();
210  break;
211  case NFTA_TABLE_FLAGS:
212  case NFTA_TABLE_USE:
213  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
214  abi_breakage();
215  break;
216  }
217 
218  tb[type] = attr;
219  return MNL_CB_OK;
220 }
221 
222 int nftnl_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_table *t)
223 {
224  struct nlattr *tb[NFTA_TABLE_MAX+1] = {};
225  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
226 
227  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_table_parse_attr_cb, tb) < 0)
228  return -1;
229 
230  if (tb[NFTA_TABLE_NAME]) {
231  if (t->flags & (1 << NFTNL_TABLE_NAME))
232  xfree(t->name);
233  t->name = strdup(mnl_attr_get_str(tb[NFTA_TABLE_NAME]));
234  if (!t->name)
235  return -1;
236  t->flags |= (1 << NFTNL_TABLE_NAME);
237  }
238  if (tb[NFTA_TABLE_FLAGS]) {
239  t->table_flags = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_FLAGS]));
240  t->flags |= (1 << NFTNL_TABLE_FLAGS);
241  }
242  if (tb[NFTA_TABLE_USE]) {
243  t->use = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_USE]));
244  t->flags |= (1 << NFTNL_TABLE_USE);
245  }
246 
247  t->family = nfg->nfgen_family;
248  t->flags |= (1 << NFTNL_TABLE_FAMILY);
249 
250  return 0;
251 }
252 EXPORT_SYMBOL(nftnl_table_nlmsg_parse);
253 
254 #ifdef JSON_PARSING
255 int nftnl_jansson_parse_table(struct nftnl_table *t, json_t *tree,
256  struct nftnl_parse_err *err)
257 {
258  json_t *root;
259  uint32_t flags, use;
260  const char *str;
261  int family;
262 
263  root = nftnl_jansson_get_node(tree, "table", err);
264  if (root == NULL)
265  return -1;
266 
267  str = nftnl_jansson_parse_str(root, "name", err);
268  if (str != NULL)
269  nftnl_table_set_str(t, NFTNL_TABLE_NAME, str);
270 
271  if (nftnl_jansson_parse_family(root, &family, err) == 0)
272  nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, family);
273 
274  if (nftnl_jansson_parse_val(root, "flags", NFTNL_TYPE_U32, &flags,
275  err) == 0)
276  nftnl_table_set_u32(t, NFTNL_TABLE_FLAGS, flags);
277 
278  if (nftnl_jansson_parse_val(root, "use", NFTNL_TYPE_U32, &use, err) == 0)
279  nftnl_table_set_u32(t, NFTNL_TABLE_USE, use);
280 
281  return 0;
282 }
283 #endif
284 
285 static int nftnl_table_json_parse(struct nftnl_table *t, const void *json,
286  struct nftnl_parse_err *err,
287  enum nftnl_parse_input input)
288 {
289 #ifdef JSON_PARSING
290  json_t *tree;
291  json_error_t error;
292  int ret;
293 
294  tree = nftnl_jansson_create_root(json, &error, err, input);
295  if (tree == NULL)
296  return -1;
297 
298  ret = nftnl_jansson_parse_table(t, tree, err);
299 
300  nftnl_jansson_free_root(tree);
301 
302  return ret;
303 #else
304  errno = EOPNOTSUPP;
305  return -1;
306 #endif
307 }
308 
309 static int nftnl_table_do_parse(struct nftnl_table *t, enum nftnl_parse_type type,
310  const void *data, struct nftnl_parse_err *err,
311  enum nftnl_parse_input input)
312 {
313  int ret;
314  struct nftnl_parse_err perr = {};
315 
316  switch (type) {
317  case NFTNL_PARSE_JSON:
318  ret = nftnl_table_json_parse(t, data, &perr, input);
319  break;
320  case NFTNL_PARSE_XML:
321  default:
322  ret = -1;
323  errno = EOPNOTSUPP;
324  break;
325  }
326 
327  if (err != NULL)
328  *err = perr;
329 
330  return ret;
331 }
332 
333 int nftnl_table_parse(struct nftnl_table *t, enum nftnl_parse_type type,
334  const char *data, struct nftnl_parse_err *err)
335 {
336  return nftnl_table_do_parse(t, type, data, err, NFTNL_PARSE_BUFFER);
337 }
338 EXPORT_SYMBOL(nftnl_table_parse);
339 
340 int nftnl_table_parse_file(struct nftnl_table *t, enum nftnl_parse_type type,
341  FILE *fp, struct nftnl_parse_err *err)
342 {
343  return nftnl_table_do_parse(t, type, fp, err, NFTNL_PARSE_FILE);
344 }
345 EXPORT_SYMBOL(nftnl_table_parse_file);
346 
347 static int nftnl_table_export(char *buf, size_t size,
348  const struct nftnl_table *t, int type)
349 {
350  NFTNL_BUF_INIT(b, buf, size);
351 
352  nftnl_buf_open(&b, type, TABLE);
353  if (t->flags & (1 << NFTNL_TABLE_NAME))
354  nftnl_buf_str(&b, type, t->name, NAME);
355  if (t->flags & (1 << NFTNL_TABLE_FAMILY))
356  nftnl_buf_str(&b, type, nftnl_family2str(t->family), FAMILY);
357  if (t->flags & (1 << NFTNL_TABLE_FLAGS))
358  nftnl_buf_u32(&b, type, t->table_flags, FLAGS);
359  if (t->flags & (1 << NFTNL_TABLE_USE))
360  nftnl_buf_u32(&b, type, t->use, USE);
361 
362  nftnl_buf_close(&b, type, TABLE);
363 
364  return nftnl_buf_done(&b);
365 }
366 
367 static int nftnl_table_snprintf_default(char *buf, size_t size,
368  const struct nftnl_table *t)
369 {
370  return snprintf(buf, size, "table %s %s flags %x use %d",
371  t->name, nftnl_family2str(t->family),
372  t->table_flags, t->use);
373 }
374 
375 static int nftnl_table_cmd_snprintf(char *buf, size_t size,
376  const struct nftnl_table *t, uint32_t cmd,
377  uint32_t type, uint32_t flags)
378 {
379  int ret, remain = size, offset = 0;
380 
381  ret = nftnl_cmd_header_snprintf(buf + offset, remain, cmd, type, flags);
382  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
383 
384  switch (type) {
385  case NFTNL_OUTPUT_DEFAULT:
386  ret = nftnl_table_snprintf_default(buf + offset, remain, t);
387  break;
388  case NFTNL_OUTPUT_XML:
389  case NFTNL_OUTPUT_JSON:
390  ret = nftnl_table_export(buf + offset, remain, t, type);
391  break;
392  default:
393  return -1;
394  }
395  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
396 
397  ret = nftnl_cmd_footer_snprintf(buf + offset, remain, cmd, type, flags);
398  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
399 
400  return offset;
401 }
402 
403 int nftnl_table_snprintf(char *buf, size_t size, const struct nftnl_table *t,
404  uint32_t type, uint32_t flags)
405 {
406  if (size)
407  buf[0] = '\0';
408 
409  return nftnl_table_cmd_snprintf(buf, size, t, nftnl_flag2cmd(flags), type,
410  flags);
411 }
412 EXPORT_SYMBOL(nftnl_table_snprintf);
413 
414 static int nftnl_table_do_snprintf(char *buf, size_t size, const void *t,
415  uint32_t cmd, uint32_t type, uint32_t flags)
416 {
417  return nftnl_table_snprintf(buf, size, t, type, flags);
418 }
419 
420 int nftnl_table_fprintf(FILE *fp, const struct nftnl_table *t, uint32_t type,
421  uint32_t flags)
422 {
423  return nftnl_fprintf(fp, t, NFTNL_CMD_UNSPEC, type, flags,
424  nftnl_table_do_snprintf);
425 }
426 EXPORT_SYMBOL(nftnl_table_fprintf);
427 
429  struct list_head list;
430 };
431 
432 struct nftnl_table_list *nftnl_table_list_alloc(void)
433 {
434  struct nftnl_table_list *list;
435 
436  list = calloc(1, sizeof(struct nftnl_table_list));
437  if (list == NULL)
438  return NULL;
439 
440  INIT_LIST_HEAD(&list->list);
441 
442  return list;
443 }
444 EXPORT_SYMBOL(nftnl_table_list_alloc);
445 
446 void nftnl_table_list_free(struct nftnl_table_list *list)
447 {
448  struct nftnl_table *r, *tmp;
449 
450  list_for_each_entry_safe(r, tmp, &list->list, head) {
451  list_del(&r->head);
452  nftnl_table_free(r);
453  }
454  xfree(list);
455 }
456 EXPORT_SYMBOL(nftnl_table_list_free);
457 
458 int nftnl_table_list_is_empty(const struct nftnl_table_list *list)
459 {
460  return list_empty(&list->list);
461 }
462 EXPORT_SYMBOL(nftnl_table_list_is_empty);
463 
464 void nftnl_table_list_add(struct nftnl_table *r, struct nftnl_table_list *list)
465 {
466  list_add(&r->head, &list->list);
467 }
468 EXPORT_SYMBOL(nftnl_table_list_add);
469 
470 void nftnl_table_list_add_tail(struct nftnl_table *r, struct nftnl_table_list *list)
471 {
472  list_add_tail(&r->head, &list->list);
473 }
474 EXPORT_SYMBOL(nftnl_table_list_add_tail);
475 
476 void nftnl_table_list_del(struct nftnl_table *t)
477 {
478  list_del(&t->head);
479 }
480 EXPORT_SYMBOL(nftnl_table_list_del);
481 
482 int nftnl_table_list_foreach(struct nftnl_table_list *table_list,
483  int (*cb)(struct nftnl_table *t, void *data),
484  void *data)
485 {
486  struct nftnl_table *cur, *tmp;
487  int ret;
488 
489  list_for_each_entry_safe(cur, tmp, &table_list->list, head) {
490  ret = cb(cur, data);
491  if (ret < 0)
492  return ret;
493  }
494  return 0;
495 }
496 EXPORT_SYMBOL(nftnl_table_list_foreach);
497 
499  const struct nftnl_table_list *list;
500  struct nftnl_table *cur;
501 };
502 
503 struct nftnl_table_list_iter *
504 nftnl_table_list_iter_create(const struct nftnl_table_list *l)
505 {
506  struct nftnl_table_list_iter *iter;
507 
508  iter = calloc(1, sizeof(struct nftnl_table_list_iter));
509  if (iter == NULL)
510  return NULL;
511 
512  iter->list = l;
513  if (nftnl_table_list_is_empty(l))
514  iter->cur = NULL;
515  else
516  iter->cur = list_entry(l->list.next, struct nftnl_table, head);
517 
518  return iter;
519 }
520 EXPORT_SYMBOL(nftnl_table_list_iter_create);
521 
522 struct nftnl_table *nftnl_table_list_iter_next(struct nftnl_table_list_iter *iter)
523 {
524  struct nftnl_table *r = iter->cur;
525 
526  if (r == NULL)
527  return NULL;
528 
529  /* get next table, if any */
530  iter->cur = list_entry(iter->cur->head.next, struct nftnl_table, head);
531  if (&iter->cur->head == iter->list->list.next)
532  return NULL;
533 
534  return r;
535 }
536 EXPORT_SYMBOL(nftnl_table_list_iter_next);
537 
538 void nftnl_table_list_iter_destroy(const struct nftnl_table_list_iter *iter)
539 {
540  xfree(iter);
541 }
542 EXPORT_SYMBOL(nftnl_table_list_iter_destroy);