libnftnl  1.0.8
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 #include <buffer.h>
31 
32 struct nftnl_chain {
33  struct list_head head;
34 
35  const char *name;
36  const char *type;
37  const char *table;
38  const char *dev;
39  uint32_t family;
40  uint32_t policy;
41  uint32_t hooknum;
42  int32_t prio;
43  uint32_t use;
44  uint64_t packets;
45  uint64_t bytes;
46  uint64_t handle;
47  uint32_t flags;
48 };
49 
50 static const char *nftnl_hooknum2str(int family, int hooknum)
51 {
52  switch (family) {
53  case NFPROTO_IPV4:
54  case NFPROTO_IPV6:
55  case NFPROTO_INET:
56  case NFPROTO_BRIDGE:
57  switch (hooknum) {
58  case NF_INET_PRE_ROUTING:
59  return "prerouting";
60  case NF_INET_LOCAL_IN:
61  return "input";
62  case NF_INET_FORWARD:
63  return "forward";
64  case NF_INET_LOCAL_OUT:
65  return "output";
66  case NF_INET_POST_ROUTING:
67  return "postrouting";
68  }
69  break;
70  case NFPROTO_ARP:
71  switch (hooknum) {
72  case NF_ARP_IN:
73  return "input";
74  case NF_ARP_OUT:
75  return "output";
76  case NF_ARP_FORWARD:
77  return "forward";
78  }
79  break;
80  case NFPROTO_NETDEV:
81  switch (hooknum) {
82  case NF_NETDEV_INGRESS:
83  return "ingress";
84  }
85  break;
86  }
87  return "unknown";
88 }
89 
90 struct nftnl_chain *nftnl_chain_alloc(void)
91 {
92  return calloc(1, sizeof(struct nftnl_chain));
93 }
94 EXPORT_SYMBOL(nftnl_chain_alloc);
95 
96 void nftnl_chain_free(const struct nftnl_chain *c)
97 {
98  if (c->flags & (1 << NFTNL_CHAIN_NAME))
99  xfree(c->name);
100  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
101  xfree(c->table);
102  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
103  xfree(c->type);
104  if (c->flags & (1 << NFTNL_CHAIN_DEV))
105  xfree(c->dev);
106  xfree(c);
107 }
108 EXPORT_SYMBOL(nftnl_chain_free);
109 
110 bool nftnl_chain_is_set(const struct nftnl_chain *c, uint16_t attr)
111 {
112  return c->flags & (1 << attr);
113 }
114 EXPORT_SYMBOL(nftnl_chain_is_set);
115 
116 void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
117 {
118  if (!(c->flags & (1 << attr)))
119  return;
120 
121  switch (attr) {
122  case NFTNL_CHAIN_NAME:
123  xfree(c->name);
124  break;
125  case NFTNL_CHAIN_TABLE:
126  xfree(c->table);
127  break;
128  case NFTNL_CHAIN_USE:
129  break;
130  case NFTNL_CHAIN_TYPE:
131  xfree(c->type);
132  break;
133  case NFTNL_CHAIN_HOOKNUM:
134  case NFTNL_CHAIN_PRIO:
135  case NFTNL_CHAIN_POLICY:
136  case NFTNL_CHAIN_BYTES:
137  case NFTNL_CHAIN_PACKETS:
138  case NFTNL_CHAIN_HANDLE:
139  case NFTNL_CHAIN_FAMILY:
140  break;
141  case NFTNL_CHAIN_DEV:
142  xfree(c->dev);
143  break;
144  default:
145  return;
146  }
147 
148  c->flags &= ~(1 << attr);
149 }
150 EXPORT_SYMBOL(nftnl_chain_unset);
151 
152 static uint32_t nftnl_chain_validate[NFTNL_CHAIN_MAX + 1] = {
153  [NFTNL_CHAIN_HOOKNUM] = sizeof(uint32_t),
154  [NFTNL_CHAIN_PRIO] = sizeof(int32_t),
155  [NFTNL_CHAIN_POLICY] = sizeof(uint32_t),
156  [NFTNL_CHAIN_BYTES] = sizeof(uint64_t),
157  [NFTNL_CHAIN_PACKETS] = sizeof(uint64_t),
158  [NFTNL_CHAIN_HANDLE] = sizeof(uint64_t),
159  [NFTNL_CHAIN_FAMILY] = sizeof(uint32_t),
160 };
161 
162 int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
163  const void *data, uint32_t data_len)
164 {
165  nftnl_assert_attr_exists(attr, NFTNL_CHAIN_MAX);
166  nftnl_assert_validate(data, nftnl_chain_validate, attr, data_len);
167 
168  switch(attr) {
169  case NFTNL_CHAIN_NAME:
170  if (c->flags & (1 << NFTNL_CHAIN_NAME))
171  xfree(c->name);
172 
173  c->name = strdup(data);
174  if (!c->name)
175  return -1;
176  break;
177  case NFTNL_CHAIN_TABLE:
178  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
179  xfree(c->table);
180 
181  c->table = strdup(data);
182  if (!c->table)
183  return -1;
184  break;
185  case NFTNL_CHAIN_HOOKNUM:
186  memcpy(&c->hooknum, data, sizeof(c->hooknum));
187  break;
188  case NFTNL_CHAIN_PRIO:
189  memcpy(&c->prio, data, sizeof(c->prio));
190  break;
191  case NFTNL_CHAIN_POLICY:
192  c->policy = *((uint32_t *)data);
193  break;
194  case NFTNL_CHAIN_USE:
195  c->use = *((uint32_t *)data);
196  break;
197  case NFTNL_CHAIN_BYTES:
198  c->bytes = *((uint64_t *)data);
199  break;
200  case NFTNL_CHAIN_PACKETS:
201  c->packets = *((uint64_t *)data);
202  break;
203  case NFTNL_CHAIN_HANDLE:
204  c->handle = *((uint64_t *)data);
205  break;
206  case NFTNL_CHAIN_FAMILY:
207  c->family = *((uint32_t *)data);
208  break;
209  case NFTNL_CHAIN_TYPE:
210  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
211  xfree(c->type);
212 
213  c->type = strdup(data);
214  if (!c->type)
215  return -1;
216  break;
217  case NFTNL_CHAIN_DEV:
218  if (c->flags & (1 << NFTNL_CHAIN_DEV))
219  xfree(c->dev);
220 
221  c->dev = strdup(data);
222  if (!c->dev)
223  return -1;
224  break;
225  }
226  c->flags |= (1 << attr);
227  return 0;
228 }
229 EXPORT_SYMBOL(nftnl_chain_set_data);
230 
231 void nftnl_chain_set(struct nftnl_chain *c, uint16_t attr, const void *data)
232 {
233  nftnl_chain_set_data(c, attr, data, nftnl_chain_validate[attr]);
234 }
235 EXPORT_SYMBOL(nftnl_chain_set);
236 
237 void nftnl_chain_set_u32(struct nftnl_chain *c, uint16_t attr, uint32_t data)
238 {
239  nftnl_chain_set_data(c, attr, &data, sizeof(uint32_t));
240 }
241 EXPORT_SYMBOL(nftnl_chain_set_u32);
242 
243 void nftnl_chain_set_s32(struct nftnl_chain *c, uint16_t attr, int32_t data)
244 {
245  nftnl_chain_set_data(c, attr, &data, sizeof(int32_t));
246 }
247 EXPORT_SYMBOL(nftnl_chain_set_s32);
248 
249 void nftnl_chain_set_u64(struct nftnl_chain *c, uint16_t attr, uint64_t data)
250 {
251  nftnl_chain_set_data(c, attr, &data, sizeof(uint64_t));
252 }
253 EXPORT_SYMBOL(nftnl_chain_set_u64);
254 
255 void nftnl_chain_set_u8(struct nftnl_chain *c, uint16_t attr, uint8_t data)
256 {
257  nftnl_chain_set_data(c, attr, &data, sizeof(uint8_t));
258 }
259 EXPORT_SYMBOL(nftnl_chain_set_u8);
260 
261 int nftnl_chain_set_str(struct nftnl_chain *c, uint16_t attr, const char *str)
262 {
263  return nftnl_chain_set_data(c, attr, str, strlen(str) + 1);
264 }
265 EXPORT_SYMBOL(nftnl_chain_set_str);
266 
267 const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
268  uint32_t *data_len)
269 {
270  if (!(c->flags & (1 << attr)))
271  return NULL;
272 
273  switch(attr) {
274  case NFTNL_CHAIN_NAME:
275  *data_len = strlen(c->name) + 1;
276  return c->name;
277  case NFTNL_CHAIN_TABLE:
278  *data_len = strlen(c->table) + 1;
279  return c->table;
280  case NFTNL_CHAIN_HOOKNUM:
281  *data_len = sizeof(uint32_t);
282  return &c->hooknum;
283  case NFTNL_CHAIN_PRIO:
284  *data_len = sizeof(int32_t);
285  return &c->prio;
286  case NFTNL_CHAIN_POLICY:
287  *data_len = sizeof(uint32_t);
288  return &c->policy;
289  case NFTNL_CHAIN_USE:
290  *data_len = sizeof(uint32_t);
291  return &c->use;
292  case NFTNL_CHAIN_BYTES:
293  *data_len = sizeof(uint64_t);
294  return &c->bytes;
295  case NFTNL_CHAIN_PACKETS:
296  *data_len = sizeof(uint64_t);
297  return &c->packets;
298  case NFTNL_CHAIN_HANDLE:
299  *data_len = sizeof(uint64_t);
300  return &c->handle;
301  case NFTNL_CHAIN_FAMILY:
302  *data_len = sizeof(uint32_t);
303  return &c->family;
304  case NFTNL_CHAIN_TYPE:
305  *data_len = sizeof(uint32_t);
306  return c->type;
307  case NFTNL_CHAIN_DEV:
308  *data_len = strlen(c->dev) + 1;
309  return c->dev;
310  }
311  return NULL;
312 }
313 EXPORT_SYMBOL(nftnl_chain_get_data);
314 
315 const void *nftnl_chain_get(const struct nftnl_chain *c, uint16_t attr)
316 {
317  uint32_t data_len;
318  return nftnl_chain_get_data(c, attr, &data_len);
319 }
320 EXPORT_SYMBOL(nftnl_chain_get);
321 
322 const char *nftnl_chain_get_str(const struct nftnl_chain *c, uint16_t attr)
323 {
324  return nftnl_chain_get(c, attr);
325 }
326 EXPORT_SYMBOL(nftnl_chain_get_str);
327 
328 uint32_t nftnl_chain_get_u32(const struct nftnl_chain *c, uint16_t attr)
329 {
330  uint32_t data_len;
331  const uint32_t *val = nftnl_chain_get_data(c, attr, &data_len);
332 
333  nftnl_assert(val, attr, data_len == sizeof(uint32_t));
334 
335  return val ? *val : 0;
336 }
337 EXPORT_SYMBOL(nftnl_chain_get_u32);
338 
339 int32_t nftnl_chain_get_s32(const struct nftnl_chain *c, uint16_t attr)
340 {
341  uint32_t data_len;
342  const int32_t *val = nftnl_chain_get_data(c, attr, &data_len);
343 
344  nftnl_assert(val, attr, data_len == sizeof(int32_t));
345 
346  return val ? *val : 0;
347 }
348 EXPORT_SYMBOL(nftnl_chain_get_s32);
349 
350 uint64_t nftnl_chain_get_u64(const struct nftnl_chain *c, uint16_t attr)
351 {
352  uint32_t data_len;
353  const uint64_t *val = nftnl_chain_get_data(c, attr, &data_len);
354 
355  nftnl_assert(val, attr, data_len == sizeof(int64_t));
356 
357  return val ? *val : 0;
358 }
359 EXPORT_SYMBOL(nftnl_chain_get_u64);
360 
361 uint8_t nftnl_chain_get_u8(const struct nftnl_chain *c, uint16_t attr)
362 {
363  uint32_t data_len;
364  const uint8_t *val = nftnl_chain_get_data(c, attr, &data_len);
365 
366  nftnl_assert(val, attr, data_len == sizeof(int8_t));
367 
368  return val ? *val : 0;
369 }
370 EXPORT_SYMBOL(nftnl_chain_get_u8);
371 
372 void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_chain *c)
373 {
374  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
375  mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, c->table);
376  if (c->flags & (1 << NFTNL_CHAIN_NAME))
377  mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, c->name);
378  if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) &&
379  (c->flags & (1 << NFTNL_CHAIN_PRIO))) {
380  struct nlattr *nest;
381 
382  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
383  mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(c->hooknum));
384  mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(c->prio));
385  if (c->flags & (1 << NFTNL_CHAIN_DEV))
386  mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
387  mnl_attr_nest_end(nlh, nest);
388  }
389  if (c->flags & (1 << NFTNL_CHAIN_POLICY))
390  mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(c->policy));
391  if (c->flags & (1 << NFTNL_CHAIN_USE))
392  mnl_attr_put_u32(nlh, NFTA_CHAIN_USE, htonl(c->use));
393  if ((c->flags & (1 << NFTNL_CHAIN_PACKETS)) &&
394  (c->flags & (1 << NFTNL_CHAIN_BYTES))) {
395  struct nlattr *nest;
396 
397  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_COUNTERS);
398  mnl_attr_put_u64(nlh, NFTA_COUNTER_PACKETS, be64toh(c->packets));
399  mnl_attr_put_u64(nlh, NFTA_COUNTER_BYTES, be64toh(c->bytes));
400  mnl_attr_nest_end(nlh, nest);
401  }
402  if (c->flags & (1 << NFTNL_CHAIN_HANDLE))
403  mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, be64toh(c->handle));
404  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
405  mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type);
406 }
407 EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload);
408 
409 static int nftnl_chain_parse_attr_cb(const struct nlattr *attr, void *data)
410 {
411  const struct nlattr **tb = data;
412  int type = mnl_attr_get_type(attr);
413 
414  if (mnl_attr_type_valid(attr, NFTA_CHAIN_MAX) < 0)
415  return MNL_CB_OK;
416 
417  switch(type) {
418  case NFTA_CHAIN_NAME:
419  case NFTA_CHAIN_TABLE:
420  case NFTA_CHAIN_TYPE:
421  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
422  abi_breakage();
423  break;
424  case NFTA_CHAIN_HOOK:
425  case NFTA_CHAIN_COUNTERS:
426  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
427  abi_breakage();
428  break;
429  case NFTA_CHAIN_POLICY:
430  case NFTA_CHAIN_USE:
431  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
432  abi_breakage();
433  break;
434  case NFTA_CHAIN_HANDLE:
435  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
436  abi_breakage();
437  break;
438  }
439 
440  tb[type] = attr;
441  return MNL_CB_OK;
442 }
443 
444 static int nftnl_chain_parse_counters_cb(const struct nlattr *attr, void *data)
445 {
446  const struct nlattr **tb = data;
447  int type = mnl_attr_get_type(attr);
448 
449  if (mnl_attr_type_valid(attr, NFTA_COUNTER_MAX) < 0)
450  return MNL_CB_OK;
451 
452  switch(type) {
453  case NFTA_COUNTER_BYTES:
454  case NFTA_COUNTER_PACKETS:
455  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
456  abi_breakage();
457  break;
458  }
459 
460  tb[type] = attr;
461  return MNL_CB_OK;
462 }
463 
464 static int nftnl_chain_parse_counters(struct nlattr *attr, struct nftnl_chain *c)
465 {
466  struct nlattr *tb[NFTA_COUNTER_MAX+1] = {};
467 
468  if (mnl_attr_parse_nested(attr, nftnl_chain_parse_counters_cb, tb) < 0)
469  return -1;
470 
471  if (tb[NFTA_COUNTER_PACKETS]) {
472  c->packets = be64toh(mnl_attr_get_u64(tb[NFTA_COUNTER_PACKETS]));
473  c->flags |= (1 << NFTNL_CHAIN_PACKETS);
474  }
475  if (tb[NFTA_COUNTER_BYTES]) {
476  c->bytes = be64toh(mnl_attr_get_u64(tb[NFTA_COUNTER_BYTES]));
477  c->flags |= (1 << NFTNL_CHAIN_BYTES);
478  }
479 
480  return 0;
481 }
482 
483 static int nftnl_chain_parse_hook_cb(const struct nlattr *attr, void *data)
484 {
485  const struct nlattr **tb = data;
486  int type = mnl_attr_get_type(attr);
487 
488  if (mnl_attr_type_valid(attr, NFTA_HOOK_MAX) < 0)
489  return MNL_CB_OK;
490 
491  switch(type) {
492  case NFTA_HOOK_HOOKNUM:
493  case NFTA_HOOK_PRIORITY:
494  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
495  abi_breakage();
496  break;
497  case NFTA_HOOK_DEV:
498  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
499  abi_breakage();
500  break;
501  }
502 
503  tb[type] = attr;
504  return MNL_CB_OK;
505 }
506 
507 static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
508 {
509  struct nlattr *tb[NFTA_HOOK_MAX+1] = {};
510 
511  if (mnl_attr_parse_nested(attr, nftnl_chain_parse_hook_cb, tb) < 0)
512  return -1;
513 
514  if (tb[NFTA_HOOK_HOOKNUM]) {
515  c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_HOOKNUM]));
516  c->flags |= (1 << NFTNL_CHAIN_HOOKNUM);
517  }
518  if (tb[NFTA_HOOK_PRIORITY]) {
519  c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_PRIORITY]));
520  c->flags |= (1 << NFTNL_CHAIN_PRIO);
521  }
522  if (tb[NFTA_HOOK_DEV]) {
523  c->dev = strdup(mnl_attr_get_str(tb[NFTA_HOOK_DEV]));
524  if (!c->dev)
525  return -1;
526  c->flags |= (1 << NFTNL_CHAIN_DEV);
527  }
528 
529  return 0;
530 }
531 
532 int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c)
533 {
534  struct nlattr *tb[NFTA_CHAIN_MAX+1] = {};
535  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
536  int ret = 0;
537 
538  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_chain_parse_attr_cb, tb) < 0)
539  return -1;
540 
541  if (tb[NFTA_CHAIN_NAME]) {
542  if (c->flags & (1 << NFTNL_CHAIN_NAME))
543  xfree(c->name);
544  c->name = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_NAME]));
545  if (!c->name)
546  return -1;
547  c->flags |= (1 << NFTNL_CHAIN_NAME);
548  }
549  if (tb[NFTA_CHAIN_TABLE]) {
550  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
551  xfree(c->table);
552  c->table = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TABLE]));
553  if (!c->table)
554  return -1;
555  c->flags |= (1 << NFTNL_CHAIN_TABLE);
556  }
557  if (tb[NFTA_CHAIN_HOOK]) {
558  ret = nftnl_chain_parse_hook(tb[NFTA_CHAIN_HOOK], c);
559  if (ret < 0)
560  return ret;
561  }
562  if (tb[NFTA_CHAIN_POLICY]) {
563  c->policy = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_POLICY]));
564  c->flags |= (1 << NFTNL_CHAIN_POLICY);
565  }
566  if (tb[NFTA_CHAIN_USE]) {
567  c->use = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_USE]));
568  c->flags |= (1 << NFTNL_CHAIN_USE);
569  }
570  if (tb[NFTA_CHAIN_COUNTERS]) {
571  ret = nftnl_chain_parse_counters(tb[NFTA_CHAIN_COUNTERS], c);
572  if (ret < 0)
573  return ret;
574  }
575  if (tb[NFTA_CHAIN_HANDLE]) {
576  c->handle = be64toh(mnl_attr_get_u64(tb[NFTA_CHAIN_HANDLE]));
577  c->flags |= (1 << NFTNL_CHAIN_HANDLE);
578  }
579  if (tb[NFTA_CHAIN_TYPE]) {
580  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
581  xfree(c->type);
582  c->type = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TYPE]));
583  if (!c->type)
584  return -1;
585  c->flags |= (1 << NFTNL_CHAIN_TYPE);
586  }
587 
588  c->family = nfg->nfgen_family;
589  c->flags |= (1 << NFTNL_CHAIN_FAMILY);
590 
591  return ret;
592 }
593 EXPORT_SYMBOL(nftnl_chain_nlmsg_parse);
594 
595 static inline int nftnl_str2hooknum(int family, const char *hook)
596 {
597  int hooknum;
598 
599  for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
600  if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
601  return hooknum;
602  }
603  return -1;
604 }
605 
606 #ifdef JSON_PARSING
607 int nftnl_jansson_parse_chain(struct nftnl_chain *c, json_t *tree,
608  struct nftnl_parse_err *err)
609 {
610  json_t *root;
611  uint64_t handle, bytes, packets;
612  int policy_num;
613  int32_t family, prio, hooknum, use;
614  const char *name, *table, *type, *hooknum_str, *policy, *dev;
615 
616  root = nftnl_jansson_get_node(tree, "chain", err);
617  if (root == NULL)
618  return -1;
619 
620  name = nftnl_jansson_parse_str(root, "name", err);
621  if (name != NULL)
622  nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, name);
623 
624  if (nftnl_jansson_parse_val(root, "handle", NFTNL_TYPE_U64, &handle,
625  err) == 0)
626  nftnl_chain_set_u64(c,NFTNL_CHAIN_HANDLE, handle);
627 
628  if (nftnl_jansson_parse_val(root, "bytes", NFTNL_TYPE_U64, &bytes,
629  err) == 0)
630  nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, bytes);
631 
632  if (nftnl_jansson_parse_val(root, "packets", NFTNL_TYPE_U64, &packets,
633  err) == 0)
634  nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, packets);
635 
636  if (nftnl_jansson_parse_family(root, &family, err) == 0)
637  nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, family);
638 
639  table = nftnl_jansson_parse_str(root, "table", err);
640 
641  if (table != NULL)
642  nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
643 
644  if (nftnl_jansson_parse_val(root, "use", NFTNL_TYPE_U32, &use, err) == 0)
645  nftnl_chain_set_u32(c, NFTNL_CHAIN_USE, use);
646 
647  if (nftnl_jansson_node_exist(root, "hooknum")) {
648  type = nftnl_jansson_parse_str(root, "type", err);
649 
650  if (type != NULL)
651  nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, type);
652 
653  if (nftnl_jansson_parse_val(root, "prio", NFTNL_TYPE_S32,
654  &prio, err) == 0)
655  nftnl_chain_set_s32(c, NFTNL_CHAIN_PRIO, prio);
656 
657  hooknum_str = nftnl_jansson_parse_str(root, "hooknum", err);
658  if (hooknum_str != NULL) {
659  hooknum = nftnl_str2hooknum(c->family, hooknum_str);
660  if (hooknum == -1)
661  return -1;
662  nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM,
663  hooknum);
664  }
665 
666  policy = nftnl_jansson_parse_str(root, "policy", err);
667  if (policy != NULL) {
668  if (nftnl_str2verdict(policy, &policy_num) != 0) {
669  errno = EINVAL;
670  err->node_name = "policy";
671  err->error = NFTNL_PARSE_EBADTYPE;
672  return -1;
673  }
674  nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY,
675  policy_num);
676  }
677 
678  dev = nftnl_jansson_parse_str(root, "device", err);
679  if (dev != NULL)
680  nftnl_chain_set_str(c, NFTNL_CHAIN_DEV, dev);
681  }
682 
683  return 0;
684 }
685 #endif
686 
687 static int nftnl_chain_json_parse(struct nftnl_chain *c, const void *json,
688  struct nftnl_parse_err *err,
689  enum nftnl_parse_input input)
690 {
691 #ifdef JSON_PARSING
692  json_t *tree;
693  json_error_t error;
694  int ret;
695 
696  tree = nftnl_jansson_create_root(json, &error, err, input);
697  if (tree == NULL)
698  return -1;
699 
700  ret = nftnl_jansson_parse_chain(c, tree, err);
701 
702  nftnl_jansson_free_root(tree);
703 
704  return ret;
705 #else
706  errno = EOPNOTSUPP;
707  return -1;
708 #endif
709 }
710 
711 static int nftnl_chain_do_parse(struct nftnl_chain *c, enum nftnl_parse_type type,
712  const void *data, struct nftnl_parse_err *err,
713  enum nftnl_parse_input input)
714 {
715  int ret;
716  struct nftnl_parse_err perr = {};
717 
718  switch (type) {
719  case NFTNL_PARSE_JSON:
720  ret = nftnl_chain_json_parse(c, data, &perr, input);
721  break;
722  case NFTNL_PARSE_XML:
723  default:
724  ret = -1;
725  errno = EOPNOTSUPP;
726  break;
727  }
728 
729  if (err != NULL)
730  *err = perr;
731 
732  return ret;
733 }
734 
735 int nftnl_chain_parse(struct nftnl_chain *c, enum nftnl_parse_type type,
736  const char *data, struct nftnl_parse_err *err)
737 {
738  return nftnl_chain_do_parse(c, type, data, err, NFTNL_PARSE_BUFFER);
739 }
740 EXPORT_SYMBOL(nftnl_chain_parse);
741 
742 int nftnl_chain_parse_file(struct nftnl_chain *c, enum nftnl_parse_type type,
743  FILE *fp, struct nftnl_parse_err *err)
744 {
745  return nftnl_chain_do_parse(c, type, fp, err, NFTNL_PARSE_FILE);
746 }
747 EXPORT_SYMBOL(nftnl_chain_parse_file);
748 
749 static int nftnl_chain_export(char *buf, size_t size,
750  const struct nftnl_chain *c, int type)
751 {
752  NFTNL_BUF_INIT(b, buf, size);
753 
754  nftnl_buf_open(&b, type, CHAIN);
755  if (c->flags & (1 << NFTNL_CHAIN_NAME))
756  nftnl_buf_str(&b, type, c->name, NAME);
757  if (c->flags & (1 << NFTNL_CHAIN_HANDLE))
758  nftnl_buf_u64(&b, type, c->handle, HANDLE);
759  if (c->flags & (1 << NFTNL_CHAIN_BYTES))
760  nftnl_buf_u64(&b, type, c->bytes, BYTES);
761  if (c->flags & (1 << NFTNL_CHAIN_PACKETS))
762  nftnl_buf_u64(&b, type, c->packets, PACKETS);
763  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
764  nftnl_buf_str(&b, type, c->table, TABLE);
765  if (c->flags & (1 << NFTNL_CHAIN_FAMILY))
766  nftnl_buf_str(&b, type, nftnl_family2str(c->family), FAMILY);
767  if (c->flags & (1 << NFTNL_CHAIN_USE))
768  nftnl_buf_u32(&b, type, c->use, USE);
769  if (c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) {
770  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
771  nftnl_buf_str(&b, type, c->type, TYPE);
772  if (c->flags & (1 << NFTNL_CHAIN_HOOKNUM))
773  nftnl_buf_str(&b, type, nftnl_hooknum2str(c->family,
774  c->hooknum), HOOKNUM);
775  if (c->flags & (1 << NFTNL_CHAIN_PRIO))
776  nftnl_buf_s32(&b, type, c->prio, PRIO);
777  if (c->flags & (1 << NFTNL_CHAIN_POLICY))
778  nftnl_buf_str(&b, type, nftnl_verdict2str(c->policy), POLICY);
779  if (c->flags & (1 << NFTNL_CHAIN_DEV))
780  nftnl_buf_str(&b, type, c->dev, DEVICE);
781  }
782 
783  nftnl_buf_close(&b, type, CHAIN);
784 
785  return nftnl_buf_done(&b);
786 }
787 
788 static int nftnl_chain_snprintf_default(char *buf, size_t size,
789  const struct nftnl_chain *c)
790 {
791  int ret, remain = size, offset = 0;
792 
793  ret = snprintf(buf, remain, "%s %s %s use %u",
794  nftnl_family2str(c->family), c->table, c->name, c->use);
795  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
796 
797  if (c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) {
798  ret = snprintf(buf + offset, remain, " type %s hook %s prio %d",
799  c->type, nftnl_hooknum2str(c->family, c->hooknum),
800  c->prio);
801  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
802 
803  if (c->flags & (1 << NFTNL_CHAIN_POLICY)) {
804  ret = snprintf(buf + offset, remain, " policy %s",
805  nftnl_verdict2str(c->policy));
806  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
807  }
808 
809  ret = snprintf(buf + offset, remain,
810  " packets %"PRIu64" bytes %"PRIu64"",
811  c->packets, c->bytes);
812  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
813 
814  if (c->flags & (1 << NFTNL_CHAIN_DEV)) {
815  ret = snprintf(buf + offset, remain, " dev %s ",
816  c->dev);
817  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
818  }
819  }
820 
821  return offset;
822 }
823 
824 static int nftnl_chain_cmd_snprintf(char *buf, size_t size,
825  const struct nftnl_chain *c, uint32_t cmd,
826  uint32_t type, uint32_t flags)
827 {
828  int ret, remain = size, offset = 0;
829 
830  ret = nftnl_cmd_header_snprintf(buf + offset, remain, cmd, type, flags);
831  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
832 
833  switch (type) {
834  case NFTNL_OUTPUT_DEFAULT:
835  ret = nftnl_chain_snprintf_default(buf + offset, remain, c);
836  break;
837  case NFTNL_OUTPUT_XML:
838  case NFTNL_OUTPUT_JSON:
839  ret = nftnl_chain_export(buf + offset, remain, c, type);
840  break;
841  default:
842  return -1;
843  }
844 
845  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
846 
847  ret = nftnl_cmd_footer_snprintf(buf + offset, remain, cmd, type, flags);
848  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
849 
850  return offset;
851 }
852 
853 int nftnl_chain_snprintf(char *buf, size_t size, const struct nftnl_chain *c,
854  uint32_t type, uint32_t flags)
855 {
856  if (size)
857  buf[0] = '\0';
858 
859  return nftnl_chain_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
860  type, flags);
861 }
862 EXPORT_SYMBOL(nftnl_chain_snprintf);
863 
864 static int nftnl_chain_do_snprintf(char *buf, size_t size, const void *c,
865  uint32_t cmd, uint32_t type, uint32_t flags)
866 {
867  return nftnl_chain_snprintf(buf, size, c, type, flags);
868 }
869 
870 int nftnl_chain_fprintf(FILE *fp, const struct nftnl_chain *c, uint32_t type,
871  uint32_t flags)
872 {
873  return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
874  nftnl_chain_do_snprintf);
875 }
876 EXPORT_SYMBOL(nftnl_chain_fprintf);
877 
879  struct list_head list;
880 };
881 
882 struct nftnl_chain_list *nftnl_chain_list_alloc(void)
883 {
884  struct nftnl_chain_list *list;
885 
886  list = calloc(1, sizeof(struct nftnl_chain_list));
887  if (list == NULL)
888  return NULL;
889 
890  INIT_LIST_HEAD(&list->list);
891 
892  return list;
893 }
894 EXPORT_SYMBOL(nftnl_chain_list_alloc);
895 
896 void nftnl_chain_list_free(struct nftnl_chain_list *list)
897 {
898  struct nftnl_chain *r, *tmp;
899 
900  list_for_each_entry_safe(r, tmp, &list->list, head) {
901  list_del(&r->head);
902  nftnl_chain_free(r);
903  }
904  xfree(list);
905 }
906 EXPORT_SYMBOL(nftnl_chain_list_free);
907 
908 int nftnl_chain_list_is_empty(const struct nftnl_chain_list *list)
909 {
910  return list_empty(&list->list);
911 }
912 EXPORT_SYMBOL(nftnl_chain_list_is_empty);
913 
914 void nftnl_chain_list_add(struct nftnl_chain *r, struct nftnl_chain_list *list)
915 {
916  list_add(&r->head, &list->list);
917 }
918 EXPORT_SYMBOL(nftnl_chain_list_add);
919 
920 void nftnl_chain_list_add_tail(struct nftnl_chain *r, struct nftnl_chain_list *list)
921 {
922  list_add_tail(&r->head, &list->list);
923 }
924 EXPORT_SYMBOL(nftnl_chain_list_add_tail);
925 
926 void nftnl_chain_list_del(struct nftnl_chain *r)
927 {
928  list_del(&r->head);
929 }
930 EXPORT_SYMBOL(nftnl_chain_list_del);
931 
932 int nftnl_chain_list_foreach(struct nftnl_chain_list *chain_list,
933  int (*cb)(struct nftnl_chain *r, void *data),
934  void *data)
935 {
936  struct nftnl_chain *cur, *tmp;
937  int ret;
938 
939  list_for_each_entry_safe(cur, tmp, &chain_list->list, head) {
940  ret = cb(cur, data);
941  if (ret < 0)
942  return ret;
943  }
944  return 0;
945 }
946 EXPORT_SYMBOL(nftnl_chain_list_foreach);
947 
949  const struct nftnl_chain_list *list;
950  struct nftnl_chain *cur;
951 };
952 
953 struct nftnl_chain_list_iter *
954 nftnl_chain_list_iter_create(const struct nftnl_chain_list *l)
955 {
956  struct nftnl_chain_list_iter *iter;
957 
958  iter = calloc(1, sizeof(struct nftnl_chain_list_iter));
959  if (iter == NULL)
960  return NULL;
961 
962  iter->list = l;
963  if (nftnl_chain_list_is_empty(l))
964  iter->cur = NULL;
965  else
966  iter->cur = list_entry(l->list.next, struct nftnl_chain, head);
967 
968  return iter;
969 }
970 EXPORT_SYMBOL(nftnl_chain_list_iter_create);
971 
972 struct nftnl_chain *nftnl_chain_list_iter_next(struct nftnl_chain_list_iter *iter)
973 {
974  struct nftnl_chain *r = iter->cur;
975 
976  if (r == NULL)
977  return NULL;
978 
979  /* get next chain, if any */
980  iter->cur = list_entry(iter->cur->head.next, struct nftnl_chain, head);
981  if (&iter->cur->head == iter->list->list.next)
982  return NULL;
983 
984  return r;
985 }
986 EXPORT_SYMBOL(nftnl_chain_list_iter_next);
987 
988 void nftnl_chain_list_iter_destroy(struct nftnl_chain_list_iter *iter)
989 {
990  xfree(iter);
991 }
992 EXPORT_SYMBOL(nftnl_chain_list_iter_destroy);