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