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