libnftnl  1.0.8
object.c
1 /*
2  * (C) 2012-2016 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 #include "internal.h"
10 
11 #include <time.h>
12 #include <endian.h>
13 #include <stdint.h>
14 #include <limits.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <netinet/in.h>
18 #include <errno.h>
19 
20 #include <libmnl/libmnl.h>
21 #include <linux/netfilter/nfnetlink.h>
22 #include <linux/netfilter/nf_tables.h>
23 
24 #include <libnftnl/object.h>
25 #include <buffer.h>
26 #include "obj.h"
27 
28 static struct obj_ops *obj_ops[] = {
29  [NFT_OBJECT_COUNTER] = &obj_ops_counter,
30  [NFT_OBJECT_QUOTA] = &obj_ops_quota,
31  [NFT_OBJECT_CT_HELPER] = &obj_ops_ct_helper,
32  [NFT_OBJECT_LIMIT] = &obj_ops_limit,
33 };
34 
35 static struct obj_ops *nftnl_obj_ops_lookup(uint32_t type)
36 {
37  if (type > NFT_OBJECT_MAX)
38  return NULL;
39 
40  return obj_ops[type];
41 }
42 
43 struct nftnl_obj *nftnl_obj_alloc(void)
44 {
45  return calloc(1, sizeof(struct nftnl_obj));
46 }
47 EXPORT_SYMBOL(nftnl_obj_alloc);
48 
49 void nftnl_obj_free(const struct nftnl_obj *obj)
50 {
51  if (obj->flags & (1 << NFTNL_OBJ_TABLE))
52  xfree(obj->table);
53  if (obj->flags & (1 << NFTNL_OBJ_NAME))
54  xfree(obj->name);
55 
56  xfree(obj);
57 }
58 EXPORT_SYMBOL(nftnl_obj_free);
59 
60 bool nftnl_obj_is_set(const struct nftnl_obj *obj, uint16_t attr)
61 {
62  return obj->flags & (1 << attr);
63 }
64 EXPORT_SYMBOL(nftnl_obj_is_set);
65 
66 static uint32_t nftnl_obj_validate[NFTNL_OBJ_MAX + 1] = {
67  [NFTNL_OBJ_FAMILY] = sizeof(uint32_t),
68  [NFTNL_OBJ_USE] = sizeof(uint32_t),
69 };
70 
71 void nftnl_obj_set_data(struct nftnl_obj *obj, uint16_t attr,
72  const void *data, uint32_t data_len)
73 {
74  if (attr < NFTNL_OBJ_MAX)
75  nftnl_assert_validate(data, nftnl_obj_validate, attr, data_len);
76 
77  switch (attr) {
78  case NFTNL_OBJ_TABLE:
79  xfree(obj->table);
80  obj->table = strdup(data);
81  break;
82  case NFTNL_OBJ_NAME:
83  xfree(obj->name);
84  obj->name = strdup(data);
85  break;
86  case NFTNL_OBJ_TYPE:
87  obj->ops = nftnl_obj_ops_lookup(*((uint32_t *)data));
88  if (!obj->ops)
89  return;
90  break;
91  case NFTNL_OBJ_FAMILY:
92  obj->family = *((uint32_t *)data);
93  break;
94  case NFTNL_OBJ_USE:
95  obj->use = *((uint32_t *)data);
96  break;
97  default:
98  if (obj->ops)
99  obj->ops->set(obj, attr, data, data_len);
100  break;
101  }
102  obj->flags |= (1 << attr);
103 }
104 EXPORT_SYMBOL(nftnl_obj_set_data);
105 
106 void nftnl_obj_set(struct nftnl_obj *obj, uint16_t attr, const void *data)
107 {
108  nftnl_obj_set_data(obj, attr, data, nftnl_obj_validate[attr]);
109 }
110 EXPORT_SYMBOL(nftnl_obj_set);
111 
112 void nftnl_obj_set_u8(struct nftnl_obj *obj, uint16_t attr, uint8_t val)
113 {
114  nftnl_obj_set_data(obj, attr, &val, sizeof(uint8_t));
115 }
116 EXPORT_SYMBOL(nftnl_obj_set_u8);
117 
118 void nftnl_obj_set_u16(struct nftnl_obj *obj, uint16_t attr, uint16_t val)
119 {
120  nftnl_obj_set_data(obj, attr, &val, sizeof(uint16_t));
121 }
122 EXPORT_SYMBOL(nftnl_obj_set_u16);
123 
124 void nftnl_obj_set_u32(struct nftnl_obj *obj, uint16_t attr, uint32_t val)
125 {
126  nftnl_obj_set_data(obj, attr, &val, sizeof(uint32_t));
127 }
128 EXPORT_SYMBOL(nftnl_obj_set_u32);
129 
130 void nftnl_obj_set_u64(struct nftnl_obj *obj, uint16_t attr, uint64_t val)
131 {
132  nftnl_obj_set_data(obj, attr, &val, sizeof(uint64_t));
133 }
134 EXPORT_SYMBOL(nftnl_obj_set_u64);
135 
136 void nftnl_obj_set_str(struct nftnl_obj *obj, uint16_t attr, const char *str)
137 {
138  nftnl_obj_set_data(obj, attr, str, 0);
139 }
140 EXPORT_SYMBOL(nftnl_obj_set_str);
141 
142 const void *nftnl_obj_get_data(struct nftnl_obj *obj, uint16_t attr,
143  uint32_t *data_len)
144 {
145  if (!(obj->flags & (1 << attr)))
146  return NULL;
147 
148  switch(attr) {
149  case NFTNL_OBJ_TABLE:
150  return obj->table;
151  case NFTNL_OBJ_NAME:
152  return obj->name;
153  case NFTNL_OBJ_TYPE:
154  if (!obj->ops)
155  return NULL;
156 
157  *data_len = sizeof(uint32_t);
158  return &obj->ops->type;
159  case NFTNL_OBJ_FAMILY:
160  *data_len = sizeof(uint32_t);
161  return &obj->family;
162  case NFTNL_OBJ_USE:
163  *data_len = sizeof(uint32_t);
164  return &obj->use;
165  default:
166  if (obj->ops)
167  return obj->ops->get(obj, attr, data_len);
168  break;
169  }
170  return NULL;
171 }
172 EXPORT_SYMBOL(nftnl_obj_get_data);
173 
174 const void *nftnl_obj_get(struct nftnl_obj *obj, uint16_t attr)
175 {
176  uint32_t data_len;
177  return nftnl_obj_get_data(obj, attr, &data_len);
178 }
179 EXPORT_SYMBOL(nftnl_obj_get);
180 
181 uint8_t nftnl_obj_get_u8(struct nftnl_obj *obj, uint16_t attr)
182 {
183  const void *ret = nftnl_obj_get(obj, attr);
184  return ret == NULL ? 0 : *((uint8_t *)ret);
185 }
186 EXPORT_SYMBOL(nftnl_obj_get_u8);
187 
188 uint16_t nftnl_obj_get_u16(struct nftnl_obj *obj, uint16_t attr)
189 {
190  const void *ret = nftnl_obj_get(obj, attr);
191  return ret == NULL ? 0 : *((uint16_t *)ret);
192 }
193 EXPORT_SYMBOL(nftnl_obj_get_u16);
194 
195 uint32_t nftnl_obj_get_u32(struct nftnl_obj *obj, uint16_t attr)
196 {
197  const void *ret = nftnl_obj_get(obj, attr);
198  return ret == NULL ? 0 : *((uint32_t *)ret);
199 }
200 EXPORT_SYMBOL(nftnl_obj_get_u32);
201 
202 uint64_t nftnl_obj_get_u64(struct nftnl_obj *obj, uint16_t attr)
203 {
204  const void *ret = nftnl_obj_get(obj, attr);
205  return ret == NULL ? 0 : *((uint64_t *)ret);
206 }
207 EXPORT_SYMBOL(nftnl_obj_get_u64);
208 
209 const char *nftnl_obj_get_str(struct nftnl_obj *obj, uint16_t attr)
210 {
211  return nftnl_obj_get(obj, attr);
212 }
213 EXPORT_SYMBOL(nftnl_obj_get_str);
214 
215 void nftnl_obj_nlmsg_build_payload(struct nlmsghdr *nlh,
216  const struct nftnl_obj *obj)
217 {
218  if (obj->flags & (1 << NFTNL_OBJ_TABLE))
219  mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, obj->table);
220  if (obj->flags & (1 << NFTNL_OBJ_NAME))
221  mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, obj->name);
222  if (obj->flags & (1 << NFTNL_OBJ_TYPE))
223  mnl_attr_put_u32(nlh, NFTA_OBJ_TYPE, htonl(obj->ops->type));
224 
225  if (obj->ops) {
226  struct nlattr *nest = mnl_attr_nest_start(nlh, NFTA_OBJ_DATA);
227 
228  obj->ops->build(nlh, obj);
229  mnl_attr_nest_end(nlh, nest);
230  }
231 }
232 EXPORT_SYMBOL(nftnl_obj_nlmsg_build_payload);
233 
234 static int nftnl_obj_parse_attr_cb(const struct nlattr *attr, void *data)
235 {
236  const struct nlattr **tb = data;
237  int type = mnl_attr_get_type(attr);
238 
239  if (mnl_attr_type_valid(attr, NFTA_OBJ_MAX) < 0)
240  return MNL_CB_OK;
241 
242  switch(type) {
243  case NFTA_OBJ_TABLE:
244  case NFTA_OBJ_NAME:
245  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
246  abi_breakage();
247  break;
248  case NFTA_OBJ_DATA:
249  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
250  abi_breakage();
251  break;
252  case NFTA_OBJ_USE:
253  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
254  abi_breakage();
255  break;
256  }
257 
258  tb[type] = attr;
259  return MNL_CB_OK;
260 }
261 
262 int nftnl_obj_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_obj *obj)
263 {
264  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
265  struct nlattr *tb[NFTA_OBJ_MAX + 1] = {};
266  int err;
267 
268  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_obj_parse_attr_cb, tb) < 0)
269  return -1;
270 
271  if (tb[NFTA_OBJ_TABLE]) {
272  obj->table = strdup(mnl_attr_get_str(tb[NFTA_OBJ_TABLE]));
273  obj->flags |= (1 << NFTNL_OBJ_TABLE);
274  }
275  if (tb[NFTA_OBJ_NAME]) {
276  obj->name = strdup(mnl_attr_get_str(tb[NFTA_OBJ_NAME]));
277  obj->flags |= (1 << NFTNL_OBJ_NAME);
278  }
279  if (tb[NFTA_OBJ_TYPE]) {
280  uint32_t type = ntohl(mnl_attr_get_u32(tb[NFTA_OBJ_TYPE]));
281 
282  obj->ops = nftnl_obj_ops_lookup(type);
283  if (obj->ops)
284  obj->flags |= (1 << NFTNL_OBJ_TYPE);
285  }
286  if (tb[NFTA_OBJ_DATA]) {
287  if (obj->ops) {
288  err = obj->ops->parse(obj, tb[NFTA_OBJ_DATA]);
289  if (err < 0)
290  return err;
291  }
292  }
293  if (tb[NFTA_OBJ_USE]) {
294  obj->use = ntohl(mnl_attr_get_u32(tb[NFTA_OBJ_USE]));
295  obj->flags |= (1 << NFTNL_OBJ_USE);
296  }
297 
298  obj->family = nfg->nfgen_family;
299  obj->flags |= (1 << NFTNL_OBJ_FAMILY);
300 
301  return 0;
302 }
303 EXPORT_SYMBOL(nftnl_obj_nlmsg_parse);
304 
305 #ifdef JSON_PARSING
306 static int nftnl_jansson_parse_obj(struct nftnl_obj *t, json_t *tree,
307  struct nftnl_parse_err *err)
308 {
309  const char *str;
310  uint32_t type;
311  json_t *root;
312 
313  root = nftnl_jansson_get_node(tree, "obj", err);
314  if (root == NULL)
315  return -1;
316 
317  str = nftnl_jansson_parse_str(root, "table", err);
318  if (str != NULL)
319  nftnl_obj_set_str(t, NFTNL_OBJ_TABLE, str);
320 
321  str = nftnl_jansson_parse_str(root, "name", err);
322  if (str != NULL)
323  nftnl_obj_set_str(t, NFTNL_OBJ_NAME, str);
324 
325  if (nftnl_jansson_parse_val(root, "type", NFTNL_TYPE_U32, &type,
326  err) < 0)
327  nftnl_obj_set_u32(t, NFTNL_OBJ_TYPE, type);
328 
329  return 0;
330 }
331 #endif
332 
333 static int nftnl_obj_json_parse(struct nftnl_obj *t, const void *json,
334  struct nftnl_parse_err *err,
335  enum nftnl_parse_input input)
336 {
337 #ifdef JSON_PARSING
338  json_t *tree;
339  json_error_t error;
340  int ret;
341 
342  tree = nftnl_jansson_create_root(json, &error, err, input);
343  if (tree == NULL)
344  return -1;
345 
346  ret = nftnl_jansson_parse_obj(t, tree, err);
347 
348  nftnl_jansson_free_root(tree);
349 
350  return ret;
351 #else
352  errno = EOPNOTSUPP;
353  return -1;
354 #endif
355 }
356 
357 static int nftnl_obj_do_parse(struct nftnl_obj *obj, enum nftnl_parse_type type,
358  const void *data, struct nftnl_parse_err *err,
359  enum nftnl_parse_input input)
360 {
361  struct nftnl_parse_err perr;
362  int ret;
363 
364  switch (type) {
365  case NFTNL_PARSE_JSON:
366  ret = nftnl_obj_json_parse(obj, data, &perr, input);
367  break;
368  case NFTNL_PARSE_XML:
369  default:
370  ret = -1;
371  errno = EOPNOTSUPP;
372  break;
373  }
374 
375  if (err != NULL)
376  *err = perr;
377 
378  return ret;
379 }
380 
381 int nftnl_obj_parse(struct nftnl_obj *obj, enum nftnl_parse_type type,
382  const char *data, struct nftnl_parse_err *err)
383 {
384  return nftnl_obj_do_parse(obj, type, data, err, NFTNL_PARSE_BUFFER);
385 }
386 EXPORT_SYMBOL(nftnl_obj_parse);
387 
388 int nftnl_obj_parse_file(struct nftnl_obj *obj, enum nftnl_parse_type type,
389  FILE *fp, struct nftnl_parse_err *err)
390 {
391  return nftnl_obj_do_parse(obj, type, fp, err, NFTNL_PARSE_FILE);
392 }
393 EXPORT_SYMBOL(nftnl_obj_parse_file);
394 
395 static int nftnl_obj_export(char *buf, size_t size,
396  const struct nftnl_obj *obj,
397  uint32_t type, uint32_t flags)
398 {
399  int ret = 0;
400 
401  NFTNL_BUF_INIT(b, buf, size);
402 
403  nftnl_buf_open(&b, type, TABLE);
404  if (obj->flags & (1 << NFTNL_OBJ_TABLE))
405  nftnl_buf_str(&b, type, obj->name, NAME);
406  if (obj->flags & (1 << NFTNL_OBJ_NAME))
407  nftnl_buf_str(&b, type, obj->name, NAME);
408  if (obj->flags & (1 << NFTNL_OBJ_FAMILY))
409  nftnl_buf_str(&b, type, nftnl_family2str(obj->family), FAMILY);
410  if (obj->flags & (1 << NFTNL_OBJ_USE))
411  nftnl_buf_u32(&b, type, obj->use, USE);
412 
413  if (obj->ops)
414  ret = obj->ops->snprintf(buf + b.len, size - b.len, type,
415  flags, obj);
416 
417  b.len += ret;
418  nftnl_buf_close(&b, type, TABLE);
419 
420  return nftnl_buf_done(&b);
421 }
422 
423 static int nftnl_obj_snprintf_dflt(char *buf, size_t size,
424  const struct nftnl_obj *obj,
425  uint32_t type, uint32_t flags)
426 {
427  const char *name = obj->ops ? obj->ops->name : "(unknown)";
428  int ret, remain = size, offset = 0;
429 
430  ret = snprintf(buf, size, "table %s name %s use %u [ %s ",
431  obj->table, obj->name, obj->use, name);
432  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
433 
434  if (obj->ops) {
435  ret = obj->ops->snprintf(buf + offset, offset, type, flags,
436  obj);
437  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
438  }
439  ret = snprintf(buf + offset, offset, "]");
440  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
441 
442  return offset;
443 }
444 
445 static int nftnl_obj_cmd_snprintf(char *buf, size_t size,
446  const struct nftnl_obj *obj, uint32_t cmd,
447  uint32_t type, uint32_t flags)
448 {
449  int ret, remain = size, offset = 0;
450 
451  ret = nftnl_cmd_header_snprintf(buf + offset, remain, cmd, type, flags);
452  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
453 
454  switch (type) {
455  case NFTNL_OUTPUT_DEFAULT:
456  ret = nftnl_obj_snprintf_dflt(buf + offset, remain, obj, type,
457  flags);
458  break;
459  case NFTNL_OUTPUT_JSON:
460  ret = nftnl_obj_export(buf + offset, remain, obj, type, flags);
461  break;
462  case NFTNL_OUTPUT_XML:
463  default:
464  return -1;
465  }
466  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
467 
468  ret = nftnl_cmd_footer_snprintf(buf + offset, remain, cmd, type, flags);
469  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
470 
471  return offset;
472 }
473 
474 int nftnl_obj_snprintf(char *buf, size_t size, const struct nftnl_obj *obj,
475  uint32_t type, uint32_t flags)
476 {
477  if (size)
478  buf[0] = '\0';
479 
480  return nftnl_obj_cmd_snprintf(buf, size, obj, nftnl_flag2cmd(flags),
481  type, flags);
482 }
483 EXPORT_SYMBOL(nftnl_obj_snprintf);
484 
485 static int nftnl_obj_do_snprintf(char *buf, size_t size, const void *obj,
486  uint32_t cmd, uint32_t type, uint32_t flags)
487 {
488  return nftnl_obj_snprintf(buf, size, obj, type, flags);
489 }
490 
491 int nftnl_obj_fprintf(FILE *fp, const struct nftnl_obj *obj, uint32_t type,
492  uint32_t flags)
493 {
494  return nftnl_fprintf(fp, obj, NFTNL_CMD_UNSPEC, type, flags,
495  nftnl_obj_do_snprintf);
496 }
497 EXPORT_SYMBOL(nftnl_obj_fprintf);
498 
500  struct list_head list;
501 };
502 
503 struct nftnl_obj_list *nftnl_obj_list_alloc(void)
504 {
505  struct nftnl_obj_list *list;
506 
507  list = calloc(1, sizeof(struct nftnl_obj_list));
508  if (list == NULL)
509  return NULL;
510 
511  INIT_LIST_HEAD(&list->list);
512 
513  return list;
514 }
515 EXPORT_SYMBOL(nftnl_obj_list_alloc);
516 
517 void nftnl_obj_list_free(struct nftnl_obj_list *list)
518 {
519  struct nftnl_obj *r, *tmp;
520 
521  list_for_each_entry_safe(r, tmp, &list->list, head) {
522  list_del(&r->head);
523  nftnl_obj_free(r);
524  }
525  xfree(list);
526 }
527 EXPORT_SYMBOL(nftnl_obj_list_free);
528 
529 int nftnl_obj_list_is_empty(struct nftnl_obj_list *list)
530 {
531  return list_empty(&list->list);
532 }
533 EXPORT_SYMBOL(nftnl_obj_list_is_empty);
534 
535 void nftnl_obj_list_add(struct nftnl_obj *r, struct nftnl_obj_list *list)
536 {
537  list_add(&r->head, &list->list);
538 }
539 EXPORT_SYMBOL(nftnl_obj_list_add);
540 
541 void nftnl_obj_list_add_tail(struct nftnl_obj *r,
542  struct nftnl_obj_list *list)
543 {
544  list_add_tail(&r->head, &list->list);
545 }
546 EXPORT_SYMBOL(nftnl_obj_list_add_tail);
547 
548 void nftnl_obj_list_del(struct nftnl_obj *t)
549 {
550  list_del(&t->head);
551 }
552 EXPORT_SYMBOL(nftnl_obj_list_del);
553 
554 int nftnl_obj_list_foreach(struct nftnl_obj_list *table_list,
555  int (*cb)(struct nftnl_obj *t, void *data),
556  void *data)
557 {
558  struct nftnl_obj *cur, *tmp;
559  int ret;
560 
561  list_for_each_entry_safe(cur, tmp, &table_list->list, head) {
562  ret = cb(cur, data);
563  if (ret < 0)
564  return ret;
565  }
566  return 0;
567 }
568 EXPORT_SYMBOL(nftnl_obj_list_foreach);
569 
571  struct nftnl_obj_list *list;
572  struct nftnl_obj *cur;
573 };
574 
575 struct nftnl_obj_list_iter *
576 nftnl_obj_list_iter_create(struct nftnl_obj_list *l)
577 {
578  struct nftnl_obj_list_iter *iter;
579 
580  iter = calloc(1, sizeof(struct nftnl_obj_list_iter));
581  if (iter == NULL)
582  return NULL;
583 
584  iter->list = l;
585  if (nftnl_obj_list_is_empty(l))
586  iter->cur = NULL;
587  else
588  iter->cur = list_entry(l->list.next, struct nftnl_obj, head);
589 
590  return iter;
591 }
592 EXPORT_SYMBOL(nftnl_obj_list_iter_create);
593 
594 struct nftnl_obj *nftnl_obj_list_iter_next(struct nftnl_obj_list_iter *iter)
595 {
596  struct nftnl_obj *r = iter->cur;
597 
598  if (r == NULL)
599  return NULL;
600 
601  /* get next table, if any */
602  iter->cur = list_entry(iter->cur->head.next, struct nftnl_obj, head);
603  if (&iter->cur->head == iter->list->list.next)
604  return NULL;
605 
606  return r;
607 }
608 EXPORT_SYMBOL(nftnl_obj_list_iter_next);
609 
610 void nftnl_obj_list_iter_destroy(struct nftnl_obj_list_iter *iter)
611 {
612  xfree(iter);
613 }
614 EXPORT_SYMBOL(nftnl_obj_list_iter_destroy);