libnftnl  1.0.2
chain.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 <stdlib.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <netinet/in.h>
20 #include <errno.h>
21 #include <inttypes.h>
22 
23 #include <libmnl/libmnl.h>
24 #include <linux/netfilter/nfnetlink.h>
25 #include <linux/netfilter/nf_tables.h>
26 #include <linux/netfilter.h>
27 #include <linux/netfilter_arp.h>
28 
29 #include <libnftnl/chain.h>
30 
31 struct nft_chain {
32  struct list_head head;
33 
34  char name[NFT_CHAIN_MAXNAMELEN];
35  const char *type;
36  const char *table;
37  uint32_t family;
38  uint32_t policy;
39  uint32_t hooknum;
40  int32_t prio;
41  uint32_t use;
42  uint64_t packets;
43  uint64_t bytes;
44  uint64_t handle;
45  uint32_t flags;
46 };
47 
48 static const char *nft_hooknum2str(int family, int hooknum)
49 {
50  switch (family) {
51  case NFPROTO_IPV4:
52  case NFPROTO_IPV6:
53  case NFPROTO_INET:
54  case NFPROTO_BRIDGE:
55  switch (hooknum) {
56  case NF_INET_PRE_ROUTING:
57  return "prerouting";
58  case NF_INET_LOCAL_IN:
59  return "input";
60  case NF_INET_FORWARD:
61  return "forward";
62  case NF_INET_LOCAL_OUT:
63  return "output";
64  case NF_INET_POST_ROUTING:
65  return "postrouting";
66  }
67  break;
68  case NFPROTO_ARP:
69  switch (hooknum) {
70  case NF_ARP_IN:
71  return "input";
72  case NF_ARP_OUT:
73  return "output";
74  case NF_ARP_FORWARD:
75  return "forward";
76  }
77  break;
78  }
79  return "unknown";
80 }
81 
82 struct nft_chain *nft_chain_alloc(void)
83 {
84  return calloc(1, sizeof(struct nft_chain));
85 }
86 EXPORT_SYMBOL(nft_chain_alloc);
87 
88 void nft_chain_free(struct nft_chain *c)
89 {
90  if (c->table != NULL)
91  xfree(c->table);
92  if (c->type != NULL)
93  xfree(c->type);
94 
95  xfree(c);
96 }
97 EXPORT_SYMBOL(nft_chain_free);
98 
99 bool nft_chain_attr_is_set(const struct nft_chain *c, uint16_t attr)
100 {
101  return c->flags & (1 << attr);
102 }
103 EXPORT_SYMBOL(nft_chain_attr_is_set);
104 
105 void nft_chain_attr_unset(struct nft_chain *c, uint16_t attr)
106 {
107  if (!(c->flags & (1 << attr)))
108  return;
109 
110  switch (attr) {
111  case NFT_CHAIN_ATTR_TABLE:
112  if (c->table) {
113  xfree(c->table);
114  c->table = NULL;
115  }
116  break;
117  case NFT_CHAIN_ATTR_USE:
118  /* cannot be unset?, ignore it */
119  return;
120  case NFT_CHAIN_ATTR_TYPE:
121  if (c->type) {
122  xfree(c->type);
123  c->type = NULL;
124  }
125  break;
126  case NFT_CHAIN_ATTR_NAME:
127  case NFT_CHAIN_ATTR_HOOKNUM:
128  case NFT_CHAIN_ATTR_PRIO:
129  case NFT_CHAIN_ATTR_POLICY:
130  case NFT_CHAIN_ATTR_BYTES:
131  case NFT_CHAIN_ATTR_PACKETS:
132  case NFT_CHAIN_ATTR_HANDLE:
133  case NFT_CHAIN_ATTR_FAMILY:
134  break;
135  default:
136  return;
137  }
138 
139  c->flags &= ~(1 << attr);
140 }
141 EXPORT_SYMBOL(nft_chain_attr_unset);
142 
143 static uint32_t nft_chain_attr_validate[NFT_CHAIN_ATTR_MAX + 1] = {
144  [NFT_CHAIN_ATTR_HOOKNUM] = sizeof(uint32_t),
145  [NFT_CHAIN_ATTR_PRIO] = sizeof(int32_t),
146  [NFT_CHAIN_ATTR_POLICY] = sizeof(uint32_t),
147  [NFT_CHAIN_ATTR_BYTES] = sizeof(uint64_t),
148  [NFT_CHAIN_ATTR_PACKETS] = sizeof(uint64_t),
149  [NFT_CHAIN_ATTR_HANDLE] = sizeof(uint64_t),
150  [NFT_CHAIN_ATTR_FAMILY] = sizeof(uint32_t),
151 };
152 
153 void nft_chain_attr_set_data(struct nft_chain *c, uint16_t attr,
154  const void *data, uint32_t data_len)
155 {
156  if (attr > NFT_CHAIN_ATTR_MAX)
157  return;
158 
159  nft_assert_validate(data, nft_chain_attr_validate, attr, data_len);
160 
161  switch(attr) {
162  case NFT_CHAIN_ATTR_NAME:
163  strncpy(c->name, data, NFT_CHAIN_MAXNAMELEN);
164  break;
165  case NFT_CHAIN_ATTR_TABLE:
166  if (c->table)
167  xfree(c->table);
168 
169  c->table = strdup(data);
170  break;
171  case NFT_CHAIN_ATTR_HOOKNUM:
172  memcpy(&c->hooknum, data, sizeof(c->hooknum));
173  break;
174  case NFT_CHAIN_ATTR_PRIO:
175  memcpy(&c->prio, data, sizeof(c->prio));
176  break;
177  case NFT_CHAIN_ATTR_POLICY:
178  c->policy = *((uint32_t *)data);
179  break;
180  case NFT_CHAIN_ATTR_USE:
181  /* cannot be set, ignore it */
182  return;
183  case NFT_CHAIN_ATTR_BYTES:
184  c->bytes = *((uint64_t *)data);
185  break;
186  case NFT_CHAIN_ATTR_PACKETS:
187  c->packets = *((uint64_t *)data);
188  break;
189  case NFT_CHAIN_ATTR_HANDLE:
190  c->handle = *((uint64_t *)data);
191  break;
192  case NFT_CHAIN_ATTR_FAMILY:
193  c->family = *((uint32_t *)data);
194  break;
195  case NFT_CHAIN_ATTR_TYPE:
196  if (c->type)
197  xfree(c->type);
198 
199  c->type = strdup(data);
200  break;
201  }
202  c->flags |= (1 << attr);
203 }
204 EXPORT_SYMBOL(nft_chain_attr_set_data);
205 
206 void nft_chain_attr_set(struct nft_chain *c, uint16_t attr, const void *data)
207 {
208  nft_chain_attr_set_data(c, attr, data, nft_chain_attr_validate[attr]);
209 }
210 EXPORT_SYMBOL(nft_chain_attr_set);
211 
212 void nft_chain_attr_set_u32(struct nft_chain *c, uint16_t attr, uint32_t data)
213 {
214  nft_chain_attr_set_data(c, attr, &data, sizeof(uint32_t));
215 }
216 EXPORT_SYMBOL(nft_chain_attr_set_u32);
217 
218 void nft_chain_attr_set_s32(struct nft_chain *c, uint16_t attr, int32_t data)
219 {
220  nft_chain_attr_set_data(c, attr, &data, sizeof(int32_t));
221 }
222 EXPORT_SYMBOL(nft_chain_attr_set_s32);
223 
224 void nft_chain_attr_set_u64(struct nft_chain *c, uint16_t attr, uint64_t data)
225 {
226  nft_chain_attr_set_data(c, attr, &data, sizeof(uint64_t));
227 }
228 EXPORT_SYMBOL(nft_chain_attr_set_u64);
229 
230 void nft_chain_attr_set_u8(struct nft_chain *c, uint16_t attr, uint8_t data)
231 {
232  nft_chain_attr_set_data(c, attr, &data, sizeof(uint8_t));
233 }
234 EXPORT_SYMBOL(nft_chain_attr_set_u8);
235 
236 void nft_chain_attr_set_str(struct nft_chain *c, uint16_t attr, const char *str)
237 {
238  nft_chain_attr_set_data(c, attr, str, strlen(str));
239 }
240 EXPORT_SYMBOL(nft_chain_attr_set_str);
241 
242 const void *nft_chain_attr_get_data(struct nft_chain *c, uint16_t attr,
243  uint32_t *data_len)
244 {
245  if (!(c->flags & (1 << attr)))
246  return NULL;
247 
248  switch(attr) {
249  case NFT_CHAIN_ATTR_NAME:
250  return c->name;
251  case NFT_CHAIN_ATTR_TABLE:
252  return c->table;
253  case NFT_CHAIN_ATTR_HOOKNUM:
254  *data_len = sizeof(uint32_t);
255  return &c->hooknum;
256  case NFT_CHAIN_ATTR_PRIO:
257  *data_len = sizeof(int32_t);
258  return &c->prio;
259  case NFT_CHAIN_ATTR_POLICY:
260  *data_len = sizeof(uint32_t);
261  return &c->policy;
262  case NFT_CHAIN_ATTR_USE:
263  *data_len = sizeof(uint32_t);
264  return &c->use;
265  case NFT_CHAIN_ATTR_BYTES:
266  *data_len = sizeof(uint64_t);
267  return &c->bytes;
268  case NFT_CHAIN_ATTR_PACKETS:
269  *data_len = sizeof(uint64_t);
270  return &c->packets;
271  case NFT_CHAIN_ATTR_HANDLE:
272  *data_len = sizeof(uint64_t);
273  return &c->handle;
274  case NFT_CHAIN_ATTR_FAMILY:
275  *data_len = sizeof(uint32_t);
276  return &c->family;
277  case NFT_CHAIN_ATTR_TYPE:
278  *data_len = sizeof(uint32_t);
279  return c->type;
280  }
281  return NULL;
282 }
283 EXPORT_SYMBOL(nft_chain_attr_get_data);
284 
285 const void *nft_chain_attr_get(struct nft_chain *c, uint16_t attr)
286 {
287  uint32_t data_len;
288  return nft_chain_attr_get_data(c, attr, &data_len);
289 }
290 EXPORT_SYMBOL(nft_chain_attr_get);
291 
292 const char *nft_chain_attr_get_str(struct nft_chain *c, uint16_t attr)
293 {
294  return nft_chain_attr_get(c, attr);
295 }
296 EXPORT_SYMBOL(nft_chain_attr_get_str);
297 
298 uint32_t nft_chain_attr_get_u32(struct nft_chain *c, uint16_t attr)
299 {
300  uint32_t data_len;
301  const uint32_t *val = nft_chain_attr_get_data(c, attr, &data_len);
302 
303  nft_assert(val, attr, data_len == sizeof(uint32_t));
304 
305  return val ? *val : 0;
306 }
307 EXPORT_SYMBOL(nft_chain_attr_get_u32);
308 
309 int32_t nft_chain_attr_get_s32(struct nft_chain *c, uint16_t attr)
310 {
311  uint32_t data_len;
312  const int32_t *val = nft_chain_attr_get_data(c, attr, &data_len);
313 
314  nft_assert(val, attr, data_len == sizeof(int32_t));
315 
316  return val ? *val : 0;
317 }
318 EXPORT_SYMBOL(nft_chain_attr_get_s32);
319 
320 uint64_t nft_chain_attr_get_u64(struct nft_chain *c, uint16_t attr)
321 {
322  uint32_t data_len;
323  const uint64_t *val = nft_chain_attr_get_data(c, attr, &data_len);
324 
325  nft_assert(val, attr, data_len == sizeof(int64_t));
326 
327  return val ? *val : 0;
328 }
329 EXPORT_SYMBOL(nft_chain_attr_get_u64);
330 
331 uint8_t nft_chain_attr_get_u8(struct nft_chain *c, uint16_t attr)
332 {
333  uint32_t data_len;
334  const uint8_t *val = nft_chain_attr_get_data(c, attr, &data_len);
335 
336  nft_assert(val, attr, data_len == sizeof(int8_t));
337 
338  return val ? *val : 0;
339 }
340 EXPORT_SYMBOL(nft_chain_attr_get_u8);
341 
342 void nft_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nft_chain *c)
343 {
344  if (c->flags & (1 << NFT_CHAIN_ATTR_TABLE))
345  mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, c->table);
346  if (c->flags & (1 << NFT_CHAIN_ATTR_NAME))
347  mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, c->name);
348  if ((c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM)) &&
349  (c->flags & (1 << NFT_CHAIN_ATTR_PRIO))) {
350  struct nlattr *nest;
351 
352  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
353  mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(c->hooknum));
354  mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(c->prio));
355  mnl_attr_nest_end(nlh, nest);
356  }
357  if (c->flags & (1 << NFT_CHAIN_ATTR_POLICY))
358  mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(c->policy));
359  if ((c->flags & (1 << NFT_CHAIN_ATTR_PACKETS)) &&
360  (c->flags & (1 << NFT_CHAIN_ATTR_BYTES))) {
361  struct nlattr *nest;
362 
363  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_COUNTERS);
364  mnl_attr_put_u64(nlh, NFTA_COUNTER_PACKETS, be64toh(c->packets));
365  mnl_attr_put_u64(nlh, NFTA_COUNTER_BYTES, be64toh(c->bytes));
366  mnl_attr_nest_end(nlh, nest);
367  }
368  if (c->flags & (1 << NFT_CHAIN_ATTR_HANDLE))
369  mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, be64toh(c->handle));
370  if (c->flags & (1 << NFT_CHAIN_ATTR_TYPE))
371  mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type);
372 }
373 EXPORT_SYMBOL(nft_chain_nlmsg_build_payload);
374 
375 static int nft_chain_parse_attr_cb(const struct nlattr *attr, void *data)
376 {
377  const struct nlattr **tb = data;
378  int type = mnl_attr_get_type(attr);
379 
380  if (mnl_attr_type_valid(attr, NFTA_CHAIN_MAX) < 0)
381  return MNL_CB_OK;
382 
383  switch(type) {
384  case NFTA_CHAIN_NAME:
385  case NFTA_CHAIN_TABLE:
386  case NFTA_CHAIN_TYPE:
387  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
388  perror("mnl_attr_validate");
389  return MNL_CB_ERROR;
390  }
391  break;
392  case NFTA_CHAIN_HOOK:
393  case NFTA_CHAIN_COUNTERS:
394  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
395  perror("mnl_attr_validate");
396  return MNL_CB_ERROR;
397  }
398  break;
399  case NFTA_CHAIN_POLICY:
400  case NFTA_CHAIN_USE:
401  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
402  perror("mnl_attr_validate");
403  return MNL_CB_ERROR;
404  }
405  break;
406  case NFTA_CHAIN_HANDLE:
407  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
408  perror("mnl_attr_validate");
409  return MNL_CB_ERROR;
410  }
411  break;
412  }
413 
414  tb[type] = attr;
415  return MNL_CB_OK;
416 }
417 
418 static int nft_chain_parse_counters_cb(const struct nlattr *attr, void *data)
419 {
420  const struct nlattr **tb = data;
421  int type = mnl_attr_get_type(attr);
422 
423  if (mnl_attr_type_valid(attr, NFTA_COUNTER_MAX) < 0)
424  return MNL_CB_OK;
425 
426  switch(type) {
427  case NFTA_COUNTER_BYTES:
428  case NFTA_COUNTER_PACKETS:
429  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
430  perror("mnl_attr_validate");
431  return MNL_CB_ERROR;
432  }
433  break;
434  }
435 
436  tb[type] = attr;
437  return MNL_CB_OK;
438 }
439 
440 static int nft_chain_parse_counters(struct nlattr *attr, struct nft_chain *c)
441 {
442  struct nlattr *tb[NFTA_COUNTER_MAX+1] = {};
443 
444  if (mnl_attr_parse_nested(attr, nft_chain_parse_counters_cb, tb) < 0)
445  return -1;
446 
447  if (tb[NFTA_COUNTER_PACKETS]) {
448  c->packets = be64toh(mnl_attr_get_u64(tb[NFTA_COUNTER_PACKETS]));
449  c->flags |= (1 << NFT_CHAIN_ATTR_PACKETS);
450  }
451  if (tb[NFTA_COUNTER_BYTES]) {
452  c->bytes = be64toh(mnl_attr_get_u64(tb[NFTA_COUNTER_BYTES]));
453  c->flags |= (1 << NFT_CHAIN_ATTR_BYTES);
454  }
455 
456  return 0;
457 }
458 static int nft_chain_parse_hook_cb(const struct nlattr *attr, void *data)
459 {
460  const struct nlattr **tb = data;
461  int type = mnl_attr_get_type(attr);
462 
463  if (mnl_attr_type_valid(attr, NFTA_HOOK_MAX) < 0)
464  return MNL_CB_OK;
465 
466  switch(type) {
467  case NFTA_HOOK_HOOKNUM:
468  case NFTA_HOOK_PRIORITY:
469  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
470  perror("mnl_attr_validate");
471  return MNL_CB_ERROR;
472  }
473  break;
474  }
475 
476  tb[type] = attr;
477  return MNL_CB_OK;
478 }
479 
480 static int nft_chain_parse_hook(struct nlattr *attr, struct nft_chain *c)
481 {
482  struct nlattr *tb[NFTA_HOOK_MAX+1] = {};
483 
484  if (mnl_attr_parse_nested(attr, nft_chain_parse_hook_cb, tb) < 0)
485  return -1;
486 
487  if (tb[NFTA_HOOK_HOOKNUM]) {
488  c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_HOOKNUM]));
489  c->flags |= (1 << NFT_CHAIN_ATTR_HOOKNUM);
490  }
491  if (tb[NFTA_HOOK_PRIORITY]) {
492  c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_PRIORITY]));
493  c->flags |= (1 << NFT_CHAIN_ATTR_PRIO);
494  }
495 
496  return 0;
497 }
498 
499 int nft_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_chain *c)
500 {
501  struct nlattr *tb[NFTA_CHAIN_MAX+1] = {};
502  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
503  int ret = 0;
504 
505  if (mnl_attr_parse(nlh, sizeof(*nfg), nft_chain_parse_attr_cb, tb) < 0)
506  return -1;
507 
508  if (tb[NFTA_CHAIN_NAME]) {
509  strncpy(c->name, mnl_attr_get_str(tb[NFTA_CHAIN_NAME]),
510  NFT_CHAIN_MAXNAMELEN);
511  c->flags |= (1 << NFT_CHAIN_ATTR_NAME);
512  }
513  if (tb[NFTA_CHAIN_TABLE]) {
514  c->table = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TABLE]));
515  c->flags |= (1 << NFT_CHAIN_ATTR_TABLE);
516  }
517  if (tb[NFTA_CHAIN_HOOK]) {
518  ret = nft_chain_parse_hook(tb[NFTA_CHAIN_HOOK], c);
519  if (ret < 0)
520  return ret;
521  }
522  if (tb[NFTA_CHAIN_POLICY]) {
523  c->policy = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_POLICY]));
524  c->flags |= (1 << NFT_CHAIN_ATTR_POLICY);
525  }
526  if (tb[NFTA_CHAIN_USE]) {
527  c->use = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_USE]));
528  c->flags |= (1 << NFT_CHAIN_ATTR_USE);
529  }
530  if (tb[NFTA_CHAIN_COUNTERS]) {
531  ret = nft_chain_parse_counters(tb[NFTA_CHAIN_COUNTERS], c);
532  if (ret < 0)
533  return ret;
534  }
535  if (tb[NFTA_CHAIN_HANDLE]) {
536  c->handle = be64toh(mnl_attr_get_u64(tb[NFTA_CHAIN_HANDLE]));
537  c->flags |= (1 << NFT_CHAIN_ATTR_HANDLE);
538  }
539  if (tb[NFTA_CHAIN_TYPE]) {
540  c->type = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TYPE]));
541  c->flags |= (1 << NFT_CHAIN_ATTR_TYPE);
542  }
543 
544  c->family = nfg->nfgen_family;
545  c->flags |= (1 << NFT_CHAIN_ATTR_FAMILY);
546 
547  return ret;
548 }
549 EXPORT_SYMBOL(nft_chain_nlmsg_parse);
550 
551 static inline int nft_str2hooknum(int family, const char *hook)
552 {
553  int hooknum;
554 
555  for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
556  if (strcmp(hook, nft_hooknum2str(family, hooknum)) == 0)
557  return hooknum;
558  }
559  return -1;
560 }
561 
562 #ifdef JSON_PARSING
563 int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree,
564  struct nft_parse_err *err)
565 {
566  json_t *root;
567  uint64_t uval64;
568  int policy;
569  int32_t val32;
570  const char *valstr;
571 
572  root = nft_jansson_get_node(tree, "chain", err);
573  if (root == NULL)
574  return -1;
575 
576  valstr = nft_jansson_parse_str(root, "name", err);
577  if (valstr == NULL)
578  goto err;
579 
580  nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_NAME, valstr);
581 
582  if (nft_jansson_parse_val(root, "handle", NFT_TYPE_U64, &uval64,
583  err) < 0)
584  goto err;
585 
586  nft_chain_attr_set_u64(c,NFT_CHAIN_ATTR_HANDLE, uval64);
587 
588  if (nft_jansson_parse_val(root, "bytes", NFT_TYPE_U64, &uval64,
589  err) < 0)
590  goto err;
591 
592  nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_BYTES, uval64);
593 
594  if (nft_jansson_parse_val(root, "packets", NFT_TYPE_U64, &uval64,
595  err) < 0)
596  goto err;
597 
598  nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_PACKETS, uval64);
599 
600  if (nft_jansson_parse_family(root, &val32, err) != 0)
601  goto err;
602 
603  nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_FAMILY, val32);
604 
605  valstr = nft_jansson_parse_str(root, "table", err);
606 
607  if (valstr == NULL)
608  goto err;
609 
610  nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_TABLE, valstr);
611 
612  if (nft_jansson_node_exist(root, "hooknum")) {
613  valstr = nft_jansson_parse_str(root, "type", err);
614 
615  if (valstr == NULL)
616  goto err;
617 
618  nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_TYPE, valstr);
619 
620  if (nft_jansson_parse_val(root, "prio", NFT_TYPE_S32,
621  &val32, err) < 0)
622  goto err;
623 
624  nft_chain_attr_set_s32(c, NFT_CHAIN_ATTR_PRIO, val32);
625 
626  valstr = nft_jansson_parse_str(root, "hooknum", err);
627  if (valstr == NULL)
628  goto err;
629 
630  val32 = nft_str2hooknum(c->family, valstr);
631  if (val32 == -1)
632  goto err;
633 
634  nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_HOOKNUM, val32);
635 
636  valstr = nft_jansson_parse_str(root, "policy", err);
637  if (valstr == NULL)
638  goto err;
639 
640  if (nft_str2verdict(valstr, &policy) != 0) {
641  errno = EINVAL;
642  err->node_name = "policy";
643  err->error = NFT_PARSE_EBADTYPE;
644  goto err;
645  }
646 
647  nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_POLICY, policy);
648  }
649 
650  nft_jansson_free_root(tree);
651  return 0;
652 
653 err:
654  nft_jansson_free_root(tree);
655  return -1;
656 }
657 #endif
658 
659 static int nft_chain_json_parse(struct nft_chain *c, const void *json,
660  struct nft_parse_err *err,
661  enum nft_parse_input input)
662 {
663 #ifdef JSON_PARSING
664  json_t *tree;
665  json_error_t error;
666 
667  tree = nft_jansson_create_root(json, &error, err, input);
668  if (tree == NULL)
669  return -1;
670 
671  return nft_jansson_parse_chain(c, tree, err);
672 #else
673  errno = EOPNOTSUPP;
674  return -1;
675 #endif
676 }
677 
678 #ifdef XML_PARSING
679 int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c,
680  struct nft_parse_err *err)
681 {
682  const char *table, *name, *hooknum_str, *policy_str, *type;
683  int family, hooknum, policy;
684 
685  name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
686  NFT_XML_MAND, err);
687  if (name == NULL)
688  return -1;
689 
690  strncpy(c->name, name, NFT_CHAIN_MAXNAMELEN);
691  c->flags |= (1 << NFT_CHAIN_ATTR_NAME);
692 
693  if (nft_mxml_num_parse(tree, "handle", MXML_DESCEND_FIRST, BASE_DEC,
694  &c->handle, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
695  return -1;
696 
697  c->flags |= (1 << NFT_CHAIN_ATTR_HANDLE);
698 
699  if (nft_mxml_num_parse(tree, "bytes", MXML_DESCEND_FIRST, BASE_DEC,
700  &c->bytes, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
701  return -1;
702 
703  c->flags |= (1 << NFT_CHAIN_ATTR_BYTES);
704 
705  if (nft_mxml_num_parse(tree, "packets", MXML_DESCEND_FIRST, BASE_DEC,
706  &c->packets, NFT_TYPE_U64, NFT_XML_MAND, err) != 0)
707  return -1;
708 
709  c->flags |= (1 << NFT_CHAIN_ATTR_PACKETS);
710 
711  table = nft_mxml_str_parse(tree, "table", MXML_DESCEND_FIRST,
712  NFT_XML_MAND, err);
713  if (table == NULL)
714  return -1;
715 
716  if (c->table)
717  xfree(c->table);
718 
719  c->table = strdup(table);
720  c->flags |= (1 << NFT_CHAIN_ATTR_TABLE);
721 
722  family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
723  NFT_XML_MAND, err);
724  if (family < 0)
725  return -1;
726 
727  c->family = family;
728  c->flags |= (1 << NFT_CHAIN_ATTR_FAMILY);
729 
730  hooknum_str = nft_mxml_str_parse(tree, "hooknum", MXML_DESCEND_FIRST,
731  NFT_XML_OPT, err);
732  if (hooknum_str != NULL) {
733  hooknum = nft_str2hooknum(c->family, hooknum_str);
734  if (hooknum < 0)
735  return -1;
736 
737  c->hooknum = hooknum;
738  c->flags |= (1 << NFT_CHAIN_ATTR_HOOKNUM);
739 
740  type = nft_mxml_str_parse(tree, "type", MXML_DESCEND_FIRST,
741  NFT_XML_MAND, err);
742  if (type == NULL)
743  return -1;
744 
745  if (c->type)
746  xfree(c->type);
747 
748  c->type = strdup(type);
749  c->flags |= (1 << NFT_CHAIN_ATTR_TYPE);
750 
751 
752  if (nft_mxml_num_parse(tree, "prio", MXML_DESCEND, BASE_DEC,
753  &c->prio, NFT_TYPE_S32,
754  NFT_XML_MAND, err) != 0)
755  return -1;
756 
757  c->flags |= (1 << NFT_CHAIN_ATTR_PRIO);
758 
759  policy_str = nft_mxml_str_parse(tree, "policy",
760  MXML_DESCEND_FIRST,
761  NFT_XML_MAND, err);
762  if (policy_str == NULL)
763  return -1;
764 
765  if (nft_str2verdict(policy_str, &policy) != 0) {
766  errno = EINVAL;
767  err->node_name = "policy";
768  err->error = NFT_PARSE_EBADTYPE;
769  return -1;
770  }
771 
772  c->policy = policy;
773  c->flags |= (1 << NFT_CHAIN_ATTR_POLICY);
774  }
775 
776  return 0;
777 }
778 #endif
779 
780 static int nft_chain_xml_parse(struct nft_chain *c, const void *xml,
781  struct nft_parse_err *err,
782  enum nft_parse_input input)
783 {
784 #ifdef XML_PARSING
785  int ret;
786  mxml_node_t *tree = nft_mxml_build_tree(xml, "chain", err, input);
787  if (tree == NULL)
788  return -1;
789 
790  ret = nft_mxml_chain_parse(tree, c, err);
791  mxmlDelete(tree);
792  return ret;
793 #else
794  errno = EOPNOTSUPP;
795  return -1;
796 #endif
797 }
798 
799 static int nft_chain_do_parse(struct nft_chain *c, enum nft_parse_type type,
800  const void *data, struct nft_parse_err *err,
801  enum nft_parse_input input)
802 {
803  int ret;
804  struct nft_parse_err perr;
805 
806  switch (type) {
807  case NFT_PARSE_XML:
808  ret = nft_chain_xml_parse(c, data, &perr, input);
809  break;
810  case NFT_PARSE_JSON:
811  ret = nft_chain_json_parse(c, data, &perr, input);
812  break;
813  default:
814  ret = -1;
815  errno = EOPNOTSUPP;
816  break;
817  }
818 
819  if (err != NULL)
820  *err = perr;
821 
822  return ret;
823 }
824 
825 int nft_chain_parse(struct nft_chain *c, enum nft_parse_type type,
826  const char *data, struct nft_parse_err *err)
827 {
828  return nft_chain_do_parse(c, type, data, err, NFT_PARSE_BUFFER);
829 }
830 EXPORT_SYMBOL(nft_chain_parse);
831 
832 int nft_chain_parse_file(struct nft_chain *c, enum nft_parse_type type,
833  FILE *fp, struct nft_parse_err *err)
834 {
835  return nft_chain_do_parse(c, type, fp, err, NFT_PARSE_FILE);
836 }
837 EXPORT_SYMBOL(nft_chain_parse_file);
838 
839 static int nft_chain_snprintf_json(char *buf, size_t size, struct nft_chain *c)
840 {
841  int ret, len = size, offset = 0;
842 
843  ret = snprintf(buf, len,
844  "{\"chain\":{"
845  "\"name\":\"%s\","
846  "\"handle\":%"PRIu64","
847  "\"bytes\":%"PRIu64","
848  "\"packets\":%"PRIu64","
849  "\"family\":\"%s\","
850  "\"table\":\"%s\","
851  "\"use\":%d",
852  c->name, c->handle, c->bytes, c->packets,
853  nft_family2str(c->family),
854  c->table, c->use);
855  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
856 
857  if (c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM)) {
858  ret = snprintf(buf+offset, len,
859  ",\"type\":\"%s\","
860  "\"hooknum\":\"%s\","
861  "\"prio\":%d,"
862  "\"policy\":\"%s\"",
863  c->type, nft_hooknum2str(c->family, c->hooknum),
864  c->prio, nft_verdict2str(c->policy));
865  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
866  }
867 
868  ret = snprintf(buf+offset, len, "}}");
869  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
870 
871  return offset;
872 }
873 
874 static int nft_chain_snprintf_xml(char *buf, size_t size, struct nft_chain *c)
875 {
876  int ret, len = size, offset = 0;
877 
878  ret = snprintf(buf, len, "<chain><name>%s</name>"
879  "<handle>%"PRIu64"</handle><bytes>%"PRIu64"</bytes>"
880  "<packets>%"PRIu64"</packets><table>%s</table>",
881  c->name, c->handle, c->bytes, c->packets, c->table);
882  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
883 
884  if (c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM)) {
885  ret = snprintf(buf+offset, len,
886  "<type>%s</type>"
887  "<hooknum>%s</hooknum>"
888  "<prio>%d</prio>"
889  "<policy>%s</policy>",
890  c->type, nft_hooknum2str(c->family, c->hooknum),
891  c->prio, nft_verdict2str(c->policy));
892  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
893  }
894 
895  ret = snprintf(buf+offset, len, "<family>%s</family></chain>",
896  nft_family2str(c->family));
897  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
898 
899  return offset;
900 }
901 
902 static int nft_chain_snprintf_default(char *buf, size_t size,
903  struct nft_chain *c)
904 {
905  int ret, len = size, offset = 0;
906 
907  ret = snprintf(buf, len, "%s %s %s use %u",
908  nft_family2str(c->family), c->table, c->name, c->use);
909  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
910 
911  if (c->flags & (1 << NFT_CHAIN_ATTR_HOOKNUM)) {
912  ret = snprintf(buf+offset, len,
913  " type %s hook %s prio %d policy %s "
914  "packets %"PRIu64" bytes %"PRIu64"",
915  c->type, nft_hooknum2str(c->family, c->hooknum),
916  c->prio, nft_verdict2str(c->policy),
917  c->packets, c->bytes);
918  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
919  }
920 
921  return offset;
922 }
923 
924 int nft_chain_snprintf(char *buf, size_t size, struct nft_chain *c,
925  uint32_t type, uint32_t flags)
926 {
927  int ret, len = size, offset = 0;
928 
929  ret = nft_event_header_snprintf(buf+offset, len, type, flags);
930  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
931 
932  switch(type) {
933  case NFT_OUTPUT_DEFAULT:
934  ret = nft_chain_snprintf_default(buf+offset, len, c);
935  break;
936  case NFT_OUTPUT_XML:
937  ret = nft_chain_snprintf_xml(buf+offset, len, c);
938  break;
939  case NFT_OUTPUT_JSON:
940  ret = nft_chain_snprintf_json(buf+offset, len, c);
941  break;
942  default:
943  return -1;
944  }
945 
946  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
947 
948  ret = nft_event_footer_snprintf(buf+offset, len, type, flags);
949  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
950 
951  return offset;
952 }
953 EXPORT_SYMBOL(nft_chain_snprintf);
954 
955 static inline int nft_chain_do_snprintf(char *buf, size_t size, void *c,
956  uint32_t type, uint32_t flags)
957 {
958  return nft_chain_snprintf(buf, size, c, type, flags);
959 }
960 
961 int nft_chain_fprintf(FILE *fp, struct nft_chain *c, uint32_t type,
962  uint32_t flags)
963 {
964  return nft_fprintf(fp, c, type, flags, nft_chain_do_snprintf);
965 }
966 EXPORT_SYMBOL(nft_chain_fprintf);
967 
969  struct list_head list;
970 };
971 
972 struct nft_chain_list *nft_chain_list_alloc(void)
973 {
974  struct nft_chain_list *list;
975 
976  list = calloc(1, sizeof(struct nft_chain_list));
977  if (list == NULL)
978  return NULL;
979 
980  INIT_LIST_HEAD(&list->list);
981 
982  return list;
983 }
984 EXPORT_SYMBOL(nft_chain_list_alloc);
985 
986 void nft_chain_list_free(struct nft_chain_list *list)
987 {
988  struct nft_chain *r, *tmp;
989 
990  list_for_each_entry_safe(r, tmp, &list->list, head) {
991  list_del(&r->head);
992  nft_chain_free(r);
993  }
994  xfree(list);
995 }
996 EXPORT_SYMBOL(nft_chain_list_free);
997 
998 int nft_chain_list_is_empty(struct nft_chain_list *list)
999 {
1000  return list_empty(&list->list);
1001 }
1002 EXPORT_SYMBOL(nft_chain_list_is_empty);
1003 
1004 void nft_chain_list_add(struct nft_chain *r, struct nft_chain_list *list)
1005 {
1006  list_add(&r->head, &list->list);
1007 }
1008 EXPORT_SYMBOL(nft_chain_list_add);
1009 
1010 void nft_chain_list_add_tail(struct nft_chain *r, struct nft_chain_list *list)
1011 {
1012  list_add_tail(&r->head, &list->list);
1013 }
1014 EXPORT_SYMBOL(nft_chain_list_add_tail);
1015 
1016 void nft_chain_list_del(struct nft_chain *r)
1017 {
1018  list_del(&r->head);
1019 }
1020 EXPORT_SYMBOL(nft_chain_list_del);
1021 
1022 int nft_chain_list_foreach(struct nft_chain_list *chain_list,
1023  int (*cb)(struct nft_chain *r, void *data),
1024  void *data)
1025 {
1026  struct nft_chain *cur, *tmp;
1027  int ret;
1028 
1029  list_for_each_entry_safe(cur, tmp, &chain_list->list, head) {
1030  ret = cb(cur, data);
1031  if (ret < 0)
1032  return ret;
1033  }
1034  return 0;
1035 }
1036 EXPORT_SYMBOL(nft_chain_list_foreach);
1037 
1039  struct nft_chain_list *list;
1040  struct nft_chain *cur;
1041 };
1042 
1043 struct nft_chain_list_iter *nft_chain_list_iter_create(struct nft_chain_list *l)
1044 {
1045  struct nft_chain_list_iter *iter;
1046 
1047  iter = calloc(1, sizeof(struct nft_chain_list_iter));
1048  if (iter == NULL)
1049  return NULL;
1050 
1051  iter->list = l;
1052  iter->cur = list_entry(l->list.next, struct nft_chain, head);
1053 
1054  return iter;
1055 }
1056 EXPORT_SYMBOL(nft_chain_list_iter_create);
1057 
1058 struct nft_chain *nft_chain_list_iter_next(struct nft_chain_list_iter *iter)
1059 {
1060  struct nft_chain *r = iter->cur;
1061 
1062  /* get next chain, if any */
1063  iter->cur = list_entry(iter->cur->head.next, struct nft_chain, head);
1064  if (&iter->cur->head == iter->list->list.next)
1065  return NULL;
1066 
1067  return r;
1068 }
1069 EXPORT_SYMBOL(nft_chain_list_iter_next);
1070 
1071 void nft_chain_list_iter_destroy(struct nft_chain_list_iter *iter)
1072 {
1073  xfree(iter);
1074 }
1075 EXPORT_SYMBOL(nft_chain_list_iter_destroy);