libnftnl  1.2.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 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_FLAGS:
78  case NFTNL_TABLE_HANDLE:
79  case NFTNL_TABLE_FAMILY:
80  case NFTNL_TABLE_USE:
81  case NFTNL_TABLE_OWNER:
82  break;
83  }
84  t->flags &= ~(1 << attr);
85 }
86 
87 static uint32_t nftnl_table_validate[NFTNL_TABLE_MAX + 1] = {
88  [NFTNL_TABLE_FLAGS] = sizeof(uint32_t),
89  [NFTNL_TABLE_FAMILY] = sizeof(uint32_t),
90  [NFTNL_TABLE_HANDLE] = sizeof(uint64_t),
91 };
92 
93 EXPORT_SYMBOL(nftnl_table_set_data);
94 int nftnl_table_set_data(struct nftnl_table *t, uint16_t attr,
95  const void *data, uint32_t data_len)
96 {
97  nftnl_assert_attr_exists(attr, NFTNL_TABLE_MAX);
98  nftnl_assert_validate(data, nftnl_table_validate, attr, data_len);
99 
100  switch (attr) {
101  case NFTNL_TABLE_NAME:
102  if (t->flags & (1 << NFTNL_TABLE_NAME))
103  xfree(t->name);
104 
105  t->name = strdup(data);
106  if (!t->name)
107  return -1;
108  break;
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 static int nftnl_table_do_parse(struct nftnl_table *t, enum nftnl_parse_type type,
331  const void *data, struct nftnl_parse_err *err,
332  enum nftnl_parse_input input)
333 {
334  int ret;
335 
336  switch (type) {
337  case NFTNL_PARSE_JSON:
338  case NFTNL_PARSE_XML:
339  default:
340  ret = -1;
341  errno = EOPNOTSUPP;
342  break;
343  }
344 
345  return ret;
346 }
347 
348 EXPORT_SYMBOL(nftnl_table_parse);
349 int nftnl_table_parse(struct nftnl_table *t, enum nftnl_parse_type type,
350  const char *data, struct nftnl_parse_err *err)
351 {
352  return nftnl_table_do_parse(t, type, data, err, NFTNL_PARSE_BUFFER);
353 }
354 
355 EXPORT_SYMBOL(nftnl_table_parse_file);
356 int nftnl_table_parse_file(struct nftnl_table *t, enum nftnl_parse_type type,
357  FILE *fp, struct nftnl_parse_err *err)
358 {
359  return nftnl_table_do_parse(t, type, fp, err, NFTNL_PARSE_FILE);
360 }
361 
362 static int nftnl_table_snprintf_default(char *buf, size_t size,
363  const struct nftnl_table *t)
364 {
365  return snprintf(buf, size, "table %s %s flags %x use %d handle %llu",
366  t->name, nftnl_family2str(t->family),
367  t->table_flags, t->use, (unsigned long long)t->handle);
368 }
369 
370 static int nftnl_table_cmd_snprintf(char *buf, size_t remain,
371  const struct nftnl_table *t, uint32_t cmd,
372  uint32_t type, uint32_t flags)
373 {
374  int ret, offset = 0;
375 
376  if (type != NFTNL_OUTPUT_DEFAULT)
377  return -1;
378 
379  ret = nftnl_table_snprintf_default(buf + offset, remain, t);
380  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
381  return offset;
382 }
383 
384 EXPORT_SYMBOL(nftnl_table_snprintf);
385 int nftnl_table_snprintf(char *buf, size_t size, const struct nftnl_table *t,
386  uint32_t type, uint32_t flags)
387 {
388  if (size)
389  buf[0] = '\0';
390 
391  return nftnl_table_cmd_snprintf(buf, size, t, nftnl_flag2cmd(flags), type,
392  flags);
393 }
394 
395 static int nftnl_table_do_snprintf(char *buf, size_t size, const void *t,
396  uint32_t cmd, uint32_t type, uint32_t flags)
397 {
398  return nftnl_table_snprintf(buf, size, t, type, flags);
399 }
400 
401 EXPORT_SYMBOL(nftnl_table_fprintf);
402 int nftnl_table_fprintf(FILE *fp, const struct nftnl_table *t, uint32_t type,
403  uint32_t flags)
404 {
405  return nftnl_fprintf(fp, t, NFTNL_CMD_UNSPEC, type, flags,
406  nftnl_table_do_snprintf);
407 }
408 
410  struct list_head list;
411 };
412 
413 EXPORT_SYMBOL(nftnl_table_list_alloc);
414 struct nftnl_table_list *nftnl_table_list_alloc(void)
415 {
416  struct nftnl_table_list *list;
417 
418  list = calloc(1, sizeof(struct nftnl_table_list));
419  if (list == NULL)
420  return NULL;
421 
422  INIT_LIST_HEAD(&list->list);
423 
424  return list;
425 }
426 
427 EXPORT_SYMBOL(nftnl_table_list_free);
428 void nftnl_table_list_free(struct nftnl_table_list *list)
429 {
430  struct nftnl_table *r, *tmp;
431 
432  list_for_each_entry_safe(r, tmp, &list->list, head) {
433  list_del(&r->head);
434  nftnl_table_free(r);
435  }
436  xfree(list);
437 }
438 
439 EXPORT_SYMBOL(nftnl_table_list_is_empty);
440 int nftnl_table_list_is_empty(const struct nftnl_table_list *list)
441 {
442  return list_empty(&list->list);
443 }
444 
445 EXPORT_SYMBOL(nftnl_table_list_add);
446 void nftnl_table_list_add(struct nftnl_table *r, struct nftnl_table_list *list)
447 {
448  list_add(&r->head, &list->list);
449 }
450 
451 EXPORT_SYMBOL(nftnl_table_list_add_tail);
452 void nftnl_table_list_add_tail(struct nftnl_table *r, struct nftnl_table_list *list)
453 {
454  list_add_tail(&r->head, &list->list);
455 }
456 
457 EXPORT_SYMBOL(nftnl_table_list_del);
458 void nftnl_table_list_del(struct nftnl_table *t)
459 {
460  list_del(&t->head);
461 }
462 
463 EXPORT_SYMBOL(nftnl_table_list_foreach);
464 int nftnl_table_list_foreach(struct nftnl_table_list *table_list,
465  int (*cb)(struct nftnl_table *t, void *data),
466  void *data)
467 {
468  struct nftnl_table *cur, *tmp;
469  int ret;
470 
471  list_for_each_entry_safe(cur, tmp, &table_list->list, head) {
472  ret = cb(cur, data);
473  if (ret < 0)
474  return ret;
475  }
476  return 0;
477 }
478 
480  const struct nftnl_table_list *list;
481  struct nftnl_table *cur;
482 };
483 
484 EXPORT_SYMBOL(nftnl_table_list_iter_create);
485 struct nftnl_table_list_iter *
486 nftnl_table_list_iter_create(const struct nftnl_table_list *l)
487 {
488  struct nftnl_table_list_iter *iter;
489 
490  iter = calloc(1, sizeof(struct nftnl_table_list_iter));
491  if (iter == NULL)
492  return NULL;
493 
494  iter->list = l;
495  if (nftnl_table_list_is_empty(l))
496  iter->cur = NULL;
497  else
498  iter->cur = list_entry(l->list.next, struct nftnl_table, head);
499 
500  return iter;
501 }
502 
503 EXPORT_SYMBOL(nftnl_table_list_iter_next);
504 struct nftnl_table *nftnl_table_list_iter_next(struct nftnl_table_list_iter *iter)
505 {
506  struct nftnl_table *r = iter->cur;
507 
508  if (r == NULL)
509  return NULL;
510 
511  /* get next table, if any */
512  iter->cur = list_entry(iter->cur->head.next, struct nftnl_table, head);
513  if (&iter->cur->head == iter->list->list.next)
514  return NULL;
515 
516  return r;
517 }
518 
519 EXPORT_SYMBOL(nftnl_table_list_iter_destroy);
520 void nftnl_table_list_iter_destroy(const struct nftnl_table_list_iter *iter)
521 {
522  xfree(iter);
523 }