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