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