libnftnl  1.2.9
table.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6  */
7 #include "internal.h"
8 
9 #include <time.h>
10 #include <endian.h>
11 #include <stdint.h>
12 #include <limits.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <netinet/in.h>
16 #include <errno.h>
17 
18 #include <libmnl/libmnl.h>
19 #include <linux/netfilter/nfnetlink.h>
20 #include <linux/netfilter/nf_tables.h>
21 
22 #include <libnftnl/table.h>
23 
24 struct nftnl_table {
25  struct list_head head;
26 
27  const char *name;
28  uint32_t family;
29  uint32_t table_flags;
30  uint64_t handle;
31  uint32_t use;
32  uint32_t flags;
33  uint32_t owner;
34  struct {
35  void *data;
36  uint32_t len;
37  } user;
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  if (t->flags & (1 << NFTNL_TABLE_USERDATA))
52  xfree(t->user.data);
53 
54  xfree(t);
55 }
56 
57 EXPORT_SYMBOL(nftnl_table_is_set);
58 bool nftnl_table_is_set(const struct nftnl_table *t, uint16_t attr)
59 {
60  return t->flags & (1 << attr);
61 }
62 
63 EXPORT_SYMBOL(nftnl_table_unset);
64 void nftnl_table_unset(struct nftnl_table *t, uint16_t attr)
65 {
66  if (!(t->flags & (1 << attr)))
67  return;
68 
69  switch (attr) {
70  case NFTNL_TABLE_NAME:
71  xfree(t->name);
72  break;
73  case NFTNL_TABLE_USERDATA:
74  xfree(t->user.data);
75  break;
76  case NFTNL_TABLE_FLAGS:
77  case NFTNL_TABLE_HANDLE:
78  case NFTNL_TABLE_FAMILY:
79  case NFTNL_TABLE_USE:
80  case NFTNL_TABLE_OWNER:
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  [NFTNL_TABLE_USE] = sizeof(uint32_t),
91  [NFTNL_TABLE_OWNER] = sizeof(uint32_t),
92 };
93 
94 EXPORT_SYMBOL(nftnl_table_set_data);
95 int nftnl_table_set_data(struct nftnl_table *t, uint16_t attr,
96  const void *data, uint32_t data_len)
97 {
98  nftnl_assert_attr_exists(attr, NFTNL_TABLE_MAX);
99  nftnl_assert_validate(data, nftnl_table_validate, attr, data_len);
100 
101  switch (attr) {
102  case NFTNL_TABLE_NAME:
103  return nftnl_set_str_attr(&t->name, &t->flags,
104  attr, data, data_len);
105  case NFTNL_TABLE_HANDLE:
106  memcpy(&t->handle, data, sizeof(t->handle));
107  break;
108  case NFTNL_TABLE_FLAGS:
109  memcpy(&t->table_flags, data, sizeof(t->table_flags));
110  break;
111  case NFTNL_TABLE_FAMILY:
112  memcpy(&t->family, data, sizeof(t->family));
113  break;
114  case NFTNL_TABLE_USE:
115  memcpy(&t->use, data, sizeof(t->use));
116  break;
117  case NFTNL_TABLE_USERDATA:
118  if (t->flags & (1 << NFTNL_TABLE_USERDATA))
119  xfree(t->user.data);
120 
121  t->user.data = malloc(data_len);
122  if (!t->user.data)
123  return -1;
124  memcpy(t->user.data, data, data_len);
125  t->user.len = data_len;
126  break;
127  case NFTNL_TABLE_OWNER:
128  memcpy(&t->owner, data, sizeof(t->owner));
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  case NFTNL_TABLE_OWNER:
192  *data_len = sizeof(uint32_t);
193  return &t->owner;
194  }
195  return NULL;
196 }
197 
198 EXPORT_SYMBOL(nftnl_table_get);
199 const void *nftnl_table_get(const struct nftnl_table *t, uint16_t attr)
200 {
201  uint32_t data_len;
202  return nftnl_table_get_data(t, attr, &data_len);
203 }
204 
205 EXPORT_SYMBOL(nftnl_table_get_u32);
206 uint32_t nftnl_table_get_u32(const struct nftnl_table *t, uint16_t attr)
207 {
208  const void *ret = nftnl_table_get(t, attr);
209  return ret == NULL ? 0 : *((uint32_t *)ret);
210 }
211 
212 EXPORT_SYMBOL(nftnl_table_get_u64);
213 uint64_t nftnl_table_get_u64(const struct nftnl_table *t, uint16_t attr)
214 {
215  const void *ret = nftnl_table_get(t, attr);
216  return ret == NULL ? 0 : *((uint64_t *)ret);
217 }
218 
219 EXPORT_SYMBOL(nftnl_table_get_u8);
220 uint8_t nftnl_table_get_u8(const struct nftnl_table *t, uint16_t attr)
221 {
222  const void *ret = nftnl_table_get(t, attr);
223  return ret == NULL ? 0 : *((uint8_t *)ret);
224 }
225 
226 EXPORT_SYMBOL(nftnl_table_get_str);
227 const char *nftnl_table_get_str(const struct nftnl_table *t, uint16_t attr)
228 {
229  return nftnl_table_get(t, attr);
230 }
231 
232 EXPORT_SYMBOL(nftnl_table_nlmsg_build_payload);
233 void nftnl_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_table *t)
234 {
235  if (t->flags & (1 << NFTNL_TABLE_NAME))
236  mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, t->name);
237  if (t->flags & (1 << NFTNL_TABLE_HANDLE))
238  mnl_attr_put_u64(nlh, NFTA_TABLE_HANDLE, htobe64(t->handle));
239  if (t->flags & (1 << NFTNL_TABLE_FLAGS))
240  mnl_attr_put_u32(nlh, NFTA_TABLE_FLAGS, htonl(t->table_flags));
241  if (t->flags & (1 << NFTNL_TABLE_USERDATA))
242  mnl_attr_put(nlh, NFTA_TABLE_USERDATA, t->user.len, t->user.data);
243 }
244 
245 static int nftnl_table_parse_attr_cb(const struct nlattr *attr, void *data)
246 {
247  const struct nlattr **tb = data;
248  int type = mnl_attr_get_type(attr);
249 
250  if (mnl_attr_type_valid(attr, NFTA_TABLE_MAX) < 0)
251  return MNL_CB_OK;
252 
253  switch(type) {
254  case NFTA_TABLE_NAME:
255  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
256  abi_breakage();
257  break;
258  case NFTA_TABLE_HANDLE:
259  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
260  abi_breakage();
261  break;
262  case NFTA_TABLE_FLAGS:
263  case NFTA_TABLE_USE:
264  case NFTA_TABLE_OWNER:
265  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
266  abi_breakage();
267  break;
268  case NFTA_TABLE_USERDATA:
269  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
270  abi_breakage();
271  break;
272  }
273 
274  tb[type] = attr;
275  return MNL_CB_OK;
276 }
277 
278 EXPORT_SYMBOL(nftnl_table_nlmsg_parse);
279 int nftnl_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_table *t)
280 {
281  struct nlattr *tb[NFTA_TABLE_MAX+1] = {};
282  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
283  int ret;
284 
285  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_table_parse_attr_cb, tb) < 0)
286  return -1;
287 
288  if (tb[NFTA_TABLE_NAME]) {
289  if (t->flags & (1 << NFTNL_TABLE_NAME))
290  xfree(t->name);
291  t->name = strdup(mnl_attr_get_str(tb[NFTA_TABLE_NAME]));
292  if (!t->name)
293  return -1;
294  t->flags |= (1 << NFTNL_TABLE_NAME);
295  }
296  if (tb[NFTA_TABLE_FLAGS]) {
297  t->table_flags = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_FLAGS]));
298  t->flags |= (1 << NFTNL_TABLE_FLAGS);
299  }
300  if (tb[NFTA_TABLE_USE]) {
301  t->use = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_USE]));
302  t->flags |= (1 << NFTNL_TABLE_USE);
303  }
304  if (tb[NFTA_TABLE_HANDLE]) {
305  t->handle = be64toh(mnl_attr_get_u64(tb[NFTA_TABLE_HANDLE]));
306  t->flags |= (1 << NFTNL_TABLE_HANDLE);
307  }
308  if (tb[NFTA_TABLE_USERDATA]) {
309  ret = nftnl_table_set_data(t, NFTNL_TABLE_USERDATA,
310  mnl_attr_get_payload(tb[NFTA_TABLE_USERDATA]),
311  mnl_attr_get_payload_len(tb[NFTA_TABLE_USERDATA]));
312  if (ret < 0)
313  return ret;
314  }
315  if (tb[NFTA_TABLE_OWNER]) {
316  t->owner = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_OWNER]));
317  t->flags |= (1 << NFTNL_TABLE_OWNER);
318  }
319 
320  t->family = nfg->nfgen_family;
321  t->flags |= (1 << NFTNL_TABLE_FAMILY);
322 
323  return 0;
324 }
325 
326 EXPORT_SYMBOL(nftnl_table_parse);
327 int nftnl_table_parse(struct nftnl_table *t, enum nftnl_parse_type type,
328  const char *data, struct nftnl_parse_err *err)
329 {
330  errno = EOPNOTSUPP;
331 
332  return -1;
333 }
334 
335 EXPORT_SYMBOL(nftnl_table_parse_file);
336 int nftnl_table_parse_file(struct nftnl_table *t, enum nftnl_parse_type type,
337  FILE *fp, struct nftnl_parse_err *err)
338 {
339  errno = EOPNOTSUPP;
340 
341  return -1;
342 }
343 
344 static int nftnl_table_snprintf_default(char *buf, size_t size,
345  const struct nftnl_table *t)
346 {
347  return snprintf(buf, size, "table %s %s flags %x use %d handle %llu",
348  t->name, nftnl_family2str(t->family),
349  t->table_flags, t->use, (unsigned long long)t->handle);
350 }
351 
352 static int nftnl_table_cmd_snprintf(char *buf, size_t remain,
353  const struct nftnl_table *t, uint32_t cmd,
354  uint32_t type, uint32_t flags)
355 {
356  int ret, offset = 0;
357 
358  if (type != NFTNL_OUTPUT_DEFAULT)
359  return -1;
360 
361  ret = nftnl_table_snprintf_default(buf + offset, remain, t);
362  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
363  return offset;
364 }
365 
366 EXPORT_SYMBOL(nftnl_table_snprintf);
367 int nftnl_table_snprintf(char *buf, size_t size, const struct nftnl_table *t,
368  uint32_t type, uint32_t flags)
369 {
370  if (size)
371  buf[0] = '\0';
372 
373  return nftnl_table_cmd_snprintf(buf, size, t, nftnl_flag2cmd(flags), type,
374  flags);
375 }
376 
377 static int nftnl_table_do_snprintf(char *buf, size_t size, const void *t,
378  uint32_t cmd, uint32_t type, uint32_t flags)
379 {
380  return nftnl_table_snprintf(buf, size, t, type, flags);
381 }
382 
383 EXPORT_SYMBOL(nftnl_table_fprintf);
384 int nftnl_table_fprintf(FILE *fp, const struct nftnl_table *t, uint32_t type,
385  uint32_t flags)
386 {
387  return nftnl_fprintf(fp, t, NFTNL_CMD_UNSPEC, type, flags,
388  nftnl_table_do_snprintf);
389 }
390 
392  struct list_head list;
393 };
394 
395 EXPORT_SYMBOL(nftnl_table_list_alloc);
396 struct nftnl_table_list *nftnl_table_list_alloc(void)
397 {
398  struct nftnl_table_list *list;
399 
400  list = calloc(1, sizeof(struct nftnl_table_list));
401  if (list == NULL)
402  return NULL;
403 
404  INIT_LIST_HEAD(&list->list);
405 
406  return list;
407 }
408 
409 EXPORT_SYMBOL(nftnl_table_list_free);
410 void nftnl_table_list_free(struct nftnl_table_list *list)
411 {
412  struct nftnl_table *r, *tmp;
413 
414  list_for_each_entry_safe(r, tmp, &list->list, head) {
415  list_del(&r->head);
416  nftnl_table_free(r);
417  }
418  xfree(list);
419 }
420 
421 EXPORT_SYMBOL(nftnl_table_list_is_empty);
422 int nftnl_table_list_is_empty(const struct nftnl_table_list *list)
423 {
424  return list_empty(&list->list);
425 }
426 
427 EXPORT_SYMBOL(nftnl_table_list_add);
428 void nftnl_table_list_add(struct nftnl_table *r, struct nftnl_table_list *list)
429 {
430  list_add(&r->head, &list->list);
431 }
432 
433 EXPORT_SYMBOL(nftnl_table_list_add_tail);
434 void nftnl_table_list_add_tail(struct nftnl_table *r, struct nftnl_table_list *list)
435 {
436  list_add_tail(&r->head, &list->list);
437 }
438 
439 EXPORT_SYMBOL(nftnl_table_list_del);
440 void nftnl_table_list_del(struct nftnl_table *t)
441 {
442  list_del(&t->head);
443 }
444 
445 EXPORT_SYMBOL(nftnl_table_list_foreach);
446 int nftnl_table_list_foreach(struct nftnl_table_list *table_list,
447  int (*cb)(struct nftnl_table *t, void *data),
448  void *data)
449 {
450  struct nftnl_table *cur, *tmp;
451  int ret;
452 
453  list_for_each_entry_safe(cur, tmp, &table_list->list, head) {
454  ret = cb(cur, data);
455  if (ret < 0)
456  return ret;
457  }
458  return 0;
459 }
460 
462  const struct nftnl_table_list *list;
463  struct nftnl_table *cur;
464 };
465 
466 EXPORT_SYMBOL(nftnl_table_list_iter_create);
467 struct nftnl_table_list_iter *
468 nftnl_table_list_iter_create(const struct nftnl_table_list *l)
469 {
470  struct nftnl_table_list_iter *iter;
471 
472  iter = calloc(1, sizeof(struct nftnl_table_list_iter));
473  if (iter == NULL)
474  return NULL;
475 
476  iter->list = l;
477  if (nftnl_table_list_is_empty(l))
478  iter->cur = NULL;
479  else
480  iter->cur = list_entry(l->list.next, struct nftnl_table, head);
481 
482  return iter;
483 }
484 
485 EXPORT_SYMBOL(nftnl_table_list_iter_next);
486 struct nftnl_table *nftnl_table_list_iter_next(struct nftnl_table_list_iter *iter)
487 {
488  struct nftnl_table *r = iter->cur;
489 
490  if (r == NULL)
491  return NULL;
492 
493  /* get next table, if any */
494  iter->cur = list_entry(iter->cur->head.next, struct nftnl_table, head);
495  if (&iter->cur->head == iter->list->list.next)
496  return NULL;
497 
498  return r;
499 }
500 
501 EXPORT_SYMBOL(nftnl_table_list_iter_destroy);
502 void nftnl_table_list_iter_destroy(const struct nftnl_table_list_iter *iter)
503 {
504  xfree(iter);
505 }