libnftnl  1.0.2
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 
28 struct nft_table {
29  struct list_head head;
30 
31  const char *name;
32  uint32_t family;
33  uint32_t table_flags;
34  uint32_t use;
35  uint32_t flags;
36 };
37 
38 struct nft_table *nft_table_alloc(void)
39 {
40  return calloc(1, sizeof(struct nft_table));
41 }
42 EXPORT_SYMBOL(nft_table_alloc);
43 
44 void nft_table_free(struct nft_table *t)
45 {
46  if (t->flags & (1 << NFT_TABLE_ATTR_NAME))
47  xfree(t->name);
48 
49  xfree(t);
50 }
51 EXPORT_SYMBOL(nft_table_free);
52 
53 bool nft_table_attr_is_set(const struct nft_table *t, uint16_t attr)
54 {
55  return t->flags & (1 << attr);
56 }
57 EXPORT_SYMBOL(nft_table_attr_is_set);
58 
59 void nft_table_attr_unset(struct nft_table *t, uint16_t attr)
60 {
61  if (!(t->flags & (1 << attr)))
62  return;
63 
64  switch (attr) {
65  case NFT_TABLE_ATTR_NAME:
66  if (t->name) {
67  xfree(t->name);
68  t->name = NULL;
69  }
70  break;
71  case NFT_TABLE_ATTR_FLAGS:
72  case NFT_TABLE_ATTR_FAMILY:
73  break;
74  case NFT_TABLE_ATTR_USE:
75  /* Cannot be unset, ignoring it */
76  return;
77  }
78  t->flags &= ~(1 << attr);
79 }
80 EXPORT_SYMBOL(nft_table_attr_unset);
81 
82 static uint32_t nft_table_attr_validate[NFT_TABLE_ATTR_MAX + 1] = {
83  [NFT_TABLE_ATTR_FLAGS] = sizeof(uint32_t),
84  [NFT_TABLE_ATTR_FAMILY] = sizeof(uint32_t),
85 };
86 
87 void nft_table_attr_set_data(struct nft_table *t, uint16_t attr,
88  const void *data, uint32_t data_len)
89 {
90  if (attr > NFT_TABLE_ATTR_MAX)
91  return;
92 
93  nft_assert_validate(data, nft_table_attr_validate, attr, data_len);
94 
95  switch (attr) {
96  case NFT_TABLE_ATTR_NAME:
97  if (t->name)
98  xfree(t->name);
99 
100  t->name = strdup(data);
101  break;
102  case NFT_TABLE_ATTR_FLAGS:
103  t->table_flags = *((uint32_t *)data);
104  break;
105  case NFT_TABLE_ATTR_FAMILY:
106  t->family = *((uint32_t *)data);
107  break;
108  case NFT_TABLE_ATTR_USE:
109  /* Cannot be set, ignoring it */
110  return;
111  }
112  t->flags |= (1 << attr);
113 }
114 EXPORT_SYMBOL(nft_table_attr_set_data);
115 
116 void nft_table_attr_set(struct nft_table *t, uint16_t attr, const void *data)
117 {
118  nft_table_attr_set_data(t, attr, data, nft_table_attr_validate[attr]);
119 }
120 EXPORT_SYMBOL(nft_table_attr_set);
121 
122 void nft_table_attr_set_u32(struct nft_table *t, uint16_t attr, uint32_t val)
123 {
124  nft_table_attr_set_data(t, attr, &val, sizeof(uint32_t));
125 }
126 EXPORT_SYMBOL(nft_table_attr_set_u32);
127 
128 void nft_table_attr_set_u8(struct nft_table *t, uint16_t attr, uint8_t val)
129 {
130  nft_table_attr_set_data(t, attr, &val, sizeof(uint8_t));
131 }
132 EXPORT_SYMBOL(nft_table_attr_set_u8);
133 
134 void nft_table_attr_set_str(struct nft_table *t, uint16_t attr, const char *str)
135 {
136  nft_table_attr_set_data(t, attr, str, 0);
137 }
138 EXPORT_SYMBOL(nft_table_attr_set_str);
139 
140 const void *nft_table_attr_get_data(struct nft_table *t, uint16_t attr,
141  uint32_t *data_len)
142 {
143  if (!(t->flags & (1 << attr)))
144  return NULL;
145 
146  switch(attr) {
147  case NFT_TABLE_ATTR_NAME:
148  return t->name;
149  case NFT_TABLE_ATTR_FLAGS:
150  *data_len = sizeof(uint32_t);
151  return &t->table_flags;
152  case NFT_TABLE_ATTR_FAMILY:
153  *data_len = sizeof(uint32_t);
154  return &t->family;
155  case NFT_TABLE_ATTR_USE:
156  *data_len = sizeof(uint32_t);
157  return &t->use;
158  }
159  return NULL;
160 }
161 EXPORT_SYMBOL(nft_table_attr_get_data);
162 
163 const void *nft_table_attr_get(struct nft_table *t, uint16_t attr)
164 {
165  uint32_t data_len;
166  return nft_table_attr_get_data(t, attr, &data_len);
167 }
168 EXPORT_SYMBOL(nft_table_attr_get);
169 
170 uint32_t nft_table_attr_get_u32(struct nft_table *t, uint16_t attr)
171 {
172  const void *ret = nft_table_attr_get(t, attr);
173  return ret == NULL ? 0 : *((uint32_t *)ret);
174 }
175 EXPORT_SYMBOL(nft_table_attr_get_u32);
176 
177 uint8_t nft_table_attr_get_u8(struct nft_table *t, uint16_t attr)
178 {
179  const void *ret = nft_table_attr_get(t, attr);
180  return ret == NULL ? 0 : *((uint8_t *)ret);
181 }
182 EXPORT_SYMBOL(nft_table_attr_get_u8);
183 
184 const char *nft_table_attr_get_str(struct nft_table *t, uint16_t attr)
185 {
186  return nft_table_attr_get(t, attr);
187 }
188 EXPORT_SYMBOL(nft_table_attr_get_str);
189 
190 void nft_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nft_table *t)
191 {
192  if (t->flags & (1 << NFT_TABLE_ATTR_NAME))
193  mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, t->name);
194  if (t->flags & (1 << NFT_TABLE_ATTR_FLAGS))
195  mnl_attr_put_u32(nlh, NFTA_TABLE_FLAGS, htonl(t->table_flags));
196 }
197 EXPORT_SYMBOL(nft_table_nlmsg_build_payload);
198 
199 static int nft_table_parse_attr_cb(const struct nlattr *attr, void *data)
200 {
201  const struct nlattr **tb = data;
202  int type = mnl_attr_get_type(attr);
203 
204  if (mnl_attr_type_valid(attr, NFTA_TABLE_MAX) < 0)
205  return MNL_CB_OK;
206 
207  switch(type) {
208  case NFTA_TABLE_NAME:
209  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
210  perror("mnl_attr_validate");
211  return MNL_CB_ERROR;
212  }
213  break;
214  case NFTA_TABLE_FLAGS:
215  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
216  perror("mnl_attr_validate");
217  return MNL_CB_ERROR;
218  }
219  break;
220  case NFTA_TABLE_USE:
221  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
222  perror("mnl_attr_validate");
223  return MNL_CB_ERROR;
224  }
225  break;
226  }
227 
228  tb[type] = attr;
229  return MNL_CB_OK;
230 }
231 
232 int nft_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_table *t)
233 {
234  struct nlattr *tb[NFTA_TABLE_MAX+1] = {};
235  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
236 
237  if (mnl_attr_parse(nlh, sizeof(*nfg), nft_table_parse_attr_cb, tb) < 0)
238  return -1;
239 
240  if (tb[NFTA_TABLE_NAME]) {
241  t->name = strdup(mnl_attr_get_str(tb[NFTA_TABLE_NAME]));
242  t->flags |= (1 << NFT_TABLE_ATTR_NAME);
243  }
244  if (tb[NFTA_TABLE_FLAGS]) {
245  t->table_flags = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_FLAGS]));
246  t->flags |= (1 << NFT_TABLE_ATTR_FLAGS);
247  }
248  if (tb[NFTA_TABLE_USE]) {
249  t->use = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_USE]));
250  t->flags |= (1 << NFT_TABLE_ATTR_USE);
251  }
252 
253  t->family = nfg->nfgen_family;
254  t->flags |= (1 << NFT_TABLE_ATTR_FAMILY);
255 
256  return 0;
257 }
258 EXPORT_SYMBOL(nft_table_nlmsg_parse);
259 
260 #ifdef XML_PARSING
261 int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t,
262  struct nft_parse_err *err)
263 {
264  const char *name;
265  int family;
266 
267  name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
268  NFT_XML_MAND, err);
269  if (name == NULL)
270  return -1;
271 
272  if (t->name)
273  xfree(t->name);
274 
275  t->name = strdup(name);
276  t->flags |= (1 << NFT_TABLE_ATTR_NAME);
277 
278  family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
279  NFT_XML_MAND, err);
280  if (family < 0)
281  return -1;
282 
283  t->family = family;
284  t->flags |= (1 << NFT_TABLE_ATTR_FAMILY);
285 
286  if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND, BASE_DEC,
287  &t->table_flags, NFT_TYPE_U32,
288  NFT_XML_MAND, err) != 0)
289  return -1;
290 
291  t->flags |= (1 << NFT_TABLE_ATTR_FLAGS);
292 
293  return 0;
294 }
295 #endif
296 
297 static int nft_table_xml_parse(struct nft_table *t, const void *data,
298  struct nft_parse_err *err,
299  enum nft_parse_input input)
300 {
301 #ifdef XML_PARSING
302  int ret;
303  mxml_node_t *tree = nft_mxml_build_tree(data, "table", err, input);
304  if (tree == NULL)
305  return -1;
306 
307  ret = nft_mxml_table_parse(tree, t, err);
308  mxmlDelete(tree);
309  return ret;
310 #else
311  errno = EOPNOTSUPP;
312  return -1;
313 #endif
314 }
315 
316 #ifdef JSON_PARSING
317 int nft_jansson_parse_table(struct nft_table *t, json_t *tree,
318  struct nft_parse_err *err)
319 {
320  json_t *root;
321  uint32_t flags;
322  const char *str;
323  int family;
324 
325  root = nft_jansson_get_node(tree, "table", err);
326  if (root == NULL)
327  return -1;
328 
329  str = nft_jansson_parse_str(root, "name", err);
330  if (str == NULL)
331  goto err;
332 
333  nft_table_attr_set_str(t, NFT_TABLE_ATTR_NAME, str);
334 
335  if (nft_jansson_parse_family(root, &family, err) != 0)
336  goto err;
337 
338  nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FAMILY, family);
339 
340  if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &flags, err) < 0)
341  goto err;
342 
343  nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FLAGS, flags);
344 
345  nft_jansson_free_root(tree);
346  return 0;
347 err:
348  nft_jansson_free_root(tree);
349  return -1;
350 }
351 #endif
352 
353 static int nft_table_json_parse(struct nft_table *t, const void *json,
354  struct nft_parse_err *err,
355  enum nft_parse_input input)
356 {
357 #ifdef JSON_PARSING
358  json_t *tree;
359  json_error_t error;
360 
361  tree = nft_jansson_create_root(json, &error, err, input);
362  if (tree == NULL)
363  return -1;
364 
365  return nft_jansson_parse_table(t, tree, err);
366 #else
367  errno = EOPNOTSUPP;
368  return -1;
369 #endif
370 }
371 
372 static int nft_table_do_parse(struct nft_table *t, enum nft_parse_type type,
373  const void *data, struct nft_parse_err *err,
374  enum nft_parse_input input)
375 {
376  int ret;
377  struct nft_parse_err perr;
378 
379  switch (type) {
380  case NFT_PARSE_XML:
381  ret = nft_table_xml_parse(t, data, &perr, input);
382  break;
383  case NFT_PARSE_JSON:
384  ret = nft_table_json_parse(t, data, &perr, input);
385  break;
386  default:
387  ret = -1;
388  errno = EOPNOTSUPP;
389  break;
390  }
391 
392  if (err != NULL)
393  *err = perr;
394 
395  return ret;
396 }
397 
398 int nft_table_parse(struct nft_table *t, enum nft_parse_type type,
399  const char *data, struct nft_parse_err *err)
400 {
401  return nft_table_do_parse(t, type, data, err, NFT_PARSE_BUFFER);
402 }
403 EXPORT_SYMBOL(nft_table_parse);
404 
405 int nft_table_parse_file(struct nft_table *t, enum nft_parse_type type,
406  FILE *fp, struct nft_parse_err *err)
407 {
408  return nft_table_do_parse(t, type, fp, err, NFT_PARSE_FILE);
409 }
410 EXPORT_SYMBOL(nft_table_parse_file);
411 
412 static int nft_table_snprintf_json(char *buf, size_t size, struct nft_table *t)
413 {
414  return snprintf(buf, size,
415  "{\"table\":{"
416  "\"name\":\"%s\","
417  "\"family\":\"%s\","
418  "\"flags\":%d,"
419  "\"use\":%d"
420  "}"
421  "}" ,
422  t->name, nft_family2str(t->family),
423  t->table_flags, t->use);
424 }
425 
426 static int nft_table_snprintf_xml(char *buf, size_t size, struct nft_table *t)
427 {
428  return snprintf(buf, size, "<table><name>%s</name><family>%s</family>"
429  "<flags>%d</flags><use>%d</use></table>",
430  t->name, nft_family2str(t->family),
431  t->table_flags, t->use);
432 }
433 
434 static int nft_table_snprintf_default(char *buf, size_t size, struct nft_table *t)
435 {
436  return snprintf(buf, size, "table %s %s flags %x use %d",
437  t->name, nft_family2str(t->family),
438  t->table_flags, t->use);
439 }
440 
441 int nft_table_snprintf(char *buf, size_t size, struct nft_table *t,
442  uint32_t type, uint32_t flags)
443 {
444  int ret, len = size, offset = 0;
445 
446  ret = nft_event_header_snprintf(buf+offset, len, type, flags);
447  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
448 
449  switch(type) {
450  case NFT_OUTPUT_DEFAULT:
451  ret = nft_table_snprintf_default(buf+offset, len, t);
452  break;
453  case NFT_OUTPUT_XML:
454  ret = nft_table_snprintf_xml(buf+offset, len, t);
455  break;
456  case NFT_OUTPUT_JSON:
457  ret = nft_table_snprintf_json(buf+offset, len, t);
458  break;
459  default:
460  return -1;
461  }
462  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
463 
464  ret = nft_event_footer_snprintf(buf+offset, len, type, flags);
465  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
466 
467  return offset;
468 }
469 EXPORT_SYMBOL(nft_table_snprintf);
470 
471 static inline int nft_table_do_snprintf(char *buf, size_t size, void *t,
472  uint32_t type, uint32_t flags)
473 {
474  return nft_table_snprintf(buf, size, t, type, flags);
475 }
476 
477 int nft_table_fprintf(FILE *fp, struct nft_table *t, uint32_t type,
478  uint32_t flags)
479 {
480  return nft_fprintf(fp, t, type, flags, nft_table_do_snprintf);
481 }
482 EXPORT_SYMBOL(nft_table_fprintf);
483 
485  struct list_head list;
486 };
487 
488 struct nft_table_list *nft_table_list_alloc(void)
489 {
490  struct nft_table_list *list;
491 
492  list = calloc(1, sizeof(struct nft_table_list));
493  if (list == NULL)
494  return NULL;
495 
496  INIT_LIST_HEAD(&list->list);
497 
498  return list;
499 }
500 EXPORT_SYMBOL(nft_table_list_alloc);
501 
502 void nft_table_list_free(struct nft_table_list *list)
503 {
504  struct nft_table *r, *tmp;
505 
506  list_for_each_entry_safe(r, tmp, &list->list, head) {
507  list_del(&r->head);
508  nft_table_free(r);
509  }
510  xfree(list);
511 }
512 EXPORT_SYMBOL(nft_table_list_free);
513 
514 int nft_table_list_is_empty(struct nft_table_list *list)
515 {
516  return list_empty(&list->list);
517 }
518 EXPORT_SYMBOL(nft_table_list_is_empty);
519 
520 void nft_table_list_add(struct nft_table *r, struct nft_table_list *list)
521 {
522  list_add(&r->head, &list->list);
523 }
524 EXPORT_SYMBOL(nft_table_list_add);
525 
526 void nft_table_list_add_tail(struct nft_table *r, struct nft_table_list *list)
527 {
528  list_add_tail(&r->head, &list->list);
529 }
530 EXPORT_SYMBOL(nft_table_list_add_tail);
531 
532 void nft_table_list_del(struct nft_table *t)
533 {
534  list_del(&t->head);
535 }
536 EXPORT_SYMBOL(nft_table_list_del);
537 
538 int nft_table_list_foreach(struct nft_table_list *table_list,
539  int (*cb)(struct nft_table *t, void *data),
540  void *data)
541 {
542  struct nft_table *cur, *tmp;
543  int ret;
544 
545  list_for_each_entry_safe(cur, tmp, &table_list->list, head) {
546  ret = cb(cur, data);
547  if (ret < 0)
548  return ret;
549  }
550  return 0;
551 }
552 EXPORT_SYMBOL(nft_table_list_foreach);
553 
555  struct nft_table_list *list;
556  struct nft_table *cur;
557 };
558 
559 struct nft_table_list_iter *nft_table_list_iter_create(struct nft_table_list *l)
560 {
561  struct nft_table_list_iter *iter;
562 
563  iter = calloc(1, sizeof(struct nft_table_list_iter));
564  if (iter == NULL)
565  return NULL;
566 
567  iter->list = l;
568  iter->cur = list_entry(l->list.next, struct nft_table, head);
569 
570  return iter;
571 }
572 EXPORT_SYMBOL(nft_table_list_iter_create);
573 
574 struct nft_table *nft_table_list_iter_next(struct nft_table_list_iter *iter)
575 {
576  struct nft_table *r = iter->cur;
577 
578  /* get next table, if any */
579  iter->cur = list_entry(iter->cur->head.next, struct nft_table, head);
580  if (&iter->cur->head == iter->list->list.next)
581  return NULL;
582 
583  return r;
584 }
585 EXPORT_SYMBOL(nft_table_list_iter_next);
586 
587 void nft_table_list_iter_destroy(struct nft_table_list_iter *iter)
588 {
589  xfree(iter);
590 }
591 EXPORT_SYMBOL(nft_table_list_iter_destroy);