libnftnl  1.1.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 #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 EXPORT_SYMBOL(nftnl_chain_alloc);
91 struct nftnl_chain *nftnl_chain_alloc(void)
92 {
93  return calloc(1, sizeof(struct nftnl_chain));
94 }
95 
96 EXPORT_SYMBOL(nftnl_chain_free);
97 void nftnl_chain_free(const struct nftnl_chain *c)
98 {
99  if (c->flags & (1 << NFTNL_CHAIN_NAME))
100  xfree(c->name);
101  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
102  xfree(c->table);
103  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
104  xfree(c->type);
105  if (c->flags & (1 << NFTNL_CHAIN_DEV))
106  xfree(c->dev);
107  xfree(c);
108 }
109 
110 EXPORT_SYMBOL(nftnl_chain_is_set);
111 bool nftnl_chain_is_set(const struct nftnl_chain *c, uint16_t attr)
112 {
113  return c->flags & (1 << attr);
114 }
115 
116 EXPORT_SYMBOL(nftnl_chain_unset);
117 void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
118 {
119  if (!(c->flags & (1 << attr)))
120  return;
121 
122  switch (attr) {
123  case NFTNL_CHAIN_NAME:
124  xfree(c->name);
125  break;
126  case NFTNL_CHAIN_TABLE:
127  xfree(c->table);
128  break;
129  case NFTNL_CHAIN_USE:
130  break;
131  case NFTNL_CHAIN_TYPE:
132  xfree(c->type);
133  break;
134  case NFTNL_CHAIN_HOOKNUM:
135  case NFTNL_CHAIN_PRIO:
136  case NFTNL_CHAIN_POLICY:
137  case NFTNL_CHAIN_BYTES:
138  case NFTNL_CHAIN_PACKETS:
139  case NFTNL_CHAIN_HANDLE:
140  case NFTNL_CHAIN_FAMILY:
141  break;
142  case NFTNL_CHAIN_DEV:
143  xfree(c->dev);
144  break;
145  default:
146  return;
147  }
148 
149  c->flags &= ~(1 << attr);
150 }
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 EXPORT_SYMBOL(nftnl_chain_set_data);
163 int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
164  const void *data, uint32_t data_len)
165 {
166  nftnl_assert_attr_exists(attr, NFTNL_CHAIN_MAX);
167  nftnl_assert_validate(data, nftnl_chain_validate, attr, data_len);
168 
169  switch(attr) {
170  case NFTNL_CHAIN_NAME:
171  if (c->flags & (1 << NFTNL_CHAIN_NAME))
172  xfree(c->name);
173 
174  c->name = strdup(data);
175  if (!c->name)
176  return -1;
177  break;
178  case NFTNL_CHAIN_TABLE:
179  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
180  xfree(c->table);
181 
182  c->table = strdup(data);
183  if (!c->table)
184  return -1;
185  break;
186  case NFTNL_CHAIN_HOOKNUM:
187  memcpy(&c->hooknum, data, sizeof(c->hooknum));
188  break;
189  case NFTNL_CHAIN_PRIO:
190  memcpy(&c->prio, data, sizeof(c->prio));
191  break;
192  case NFTNL_CHAIN_POLICY:
193  memcpy(&c->policy, data, sizeof(c->policy));
194  break;
195  case NFTNL_CHAIN_USE:
196  memcpy(&c->use, data, sizeof(c->use));
197  break;
198  case NFTNL_CHAIN_BYTES:
199  memcpy(&c->bytes, data, sizeof(c->bytes));
200  break;
201  case NFTNL_CHAIN_PACKETS:
202  memcpy(&c->packets, data, sizeof(c->packets));
203  break;
204  case NFTNL_CHAIN_HANDLE:
205  memcpy(&c->handle, data, sizeof(c->handle));
206  break;
207  case NFTNL_CHAIN_FAMILY:
208  memcpy(&c->family, data, sizeof(c->family));
209  break;
210  case NFTNL_CHAIN_TYPE:
211  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
212  xfree(c->type);
213 
214  c->type = strdup(data);
215  if (!c->type)
216  return -1;
217  break;
218  case NFTNL_CHAIN_DEV:
219  if (c->flags & (1 << NFTNL_CHAIN_DEV))
220  xfree(c->dev);
221 
222  c->dev = strdup(data);
223  if (!c->dev)
224  return -1;
225  break;
226  }
227  c->flags |= (1 << attr);
228  return 0;
229 }
230 
231 EXPORT_SYMBOL(nftnl_chain_set);
232 void nftnl_chain_set(struct nftnl_chain *c, uint16_t attr, const void *data)
233 {
234  nftnl_chain_set_data(c, attr, data, nftnl_chain_validate[attr]);
235 }
236 
237 EXPORT_SYMBOL(nftnl_chain_set_u32);
238 void nftnl_chain_set_u32(struct nftnl_chain *c, uint16_t attr, uint32_t data)
239 {
240  nftnl_chain_set_data(c, attr, &data, sizeof(uint32_t));
241 }
242 
243 EXPORT_SYMBOL(nftnl_chain_set_s32);
244 void nftnl_chain_set_s32(struct nftnl_chain *c, uint16_t attr, int32_t data)
245 {
246  nftnl_chain_set_data(c, attr, &data, sizeof(int32_t));
247 }
248 
249 EXPORT_SYMBOL(nftnl_chain_set_u64);
250 void nftnl_chain_set_u64(struct nftnl_chain *c, uint16_t attr, uint64_t data)
251 {
252  nftnl_chain_set_data(c, attr, &data, sizeof(uint64_t));
253 }
254 
255 EXPORT_SYMBOL(nftnl_chain_set_u8);
256 void nftnl_chain_set_u8(struct nftnl_chain *c, uint16_t attr, uint8_t data)
257 {
258  nftnl_chain_set_data(c, attr, &data, sizeof(uint8_t));
259 }
260 
261 EXPORT_SYMBOL(nftnl_chain_set_str);
262 int nftnl_chain_set_str(struct nftnl_chain *c, uint16_t attr, const char *str)
263 {
264  return nftnl_chain_set_data(c, attr, str, strlen(str) + 1);
265 }
266 
267 EXPORT_SYMBOL(nftnl_chain_get_data);
268 const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
269  uint32_t *data_len)
270 {
271  if (!(c->flags & (1 << attr)))
272  return NULL;
273 
274  switch(attr) {
275  case NFTNL_CHAIN_NAME:
276  *data_len = strlen(c->name) + 1;
277  return c->name;
278  case NFTNL_CHAIN_TABLE:
279  *data_len = strlen(c->table) + 1;
280  return c->table;
281  case NFTNL_CHAIN_HOOKNUM:
282  *data_len = sizeof(uint32_t);
283  return &c->hooknum;
284  case NFTNL_CHAIN_PRIO:
285  *data_len = sizeof(int32_t);
286  return &c->prio;
287  case NFTNL_CHAIN_POLICY:
288  *data_len = sizeof(uint32_t);
289  return &c->policy;
290  case NFTNL_CHAIN_USE:
291  *data_len = sizeof(uint32_t);
292  return &c->use;
293  case NFTNL_CHAIN_BYTES:
294  *data_len = sizeof(uint64_t);
295  return &c->bytes;
296  case NFTNL_CHAIN_PACKETS:
297  *data_len = sizeof(uint64_t);
298  return &c->packets;
299  case NFTNL_CHAIN_HANDLE:
300  *data_len = sizeof(uint64_t);
301  return &c->handle;
302  case NFTNL_CHAIN_FAMILY:
303  *data_len = sizeof(uint32_t);
304  return &c->family;
305  case NFTNL_CHAIN_TYPE:
306  *data_len = sizeof(uint32_t);
307  return c->type;
308  case NFTNL_CHAIN_DEV:
309  *data_len = strlen(c->dev) + 1;
310  return c->dev;
311  }
312  return NULL;
313 }
314 
315 EXPORT_SYMBOL(nftnl_chain_get);
316 const void *nftnl_chain_get(const struct nftnl_chain *c, uint16_t attr)
317 {
318  uint32_t data_len;
319  return nftnl_chain_get_data(c, attr, &data_len);
320 }
321 
322 EXPORT_SYMBOL(nftnl_chain_get_str);
323 const char *nftnl_chain_get_str(const struct nftnl_chain *c, uint16_t attr)
324 {
325  return nftnl_chain_get(c, attr);
326 }
327 
328 EXPORT_SYMBOL(nftnl_chain_get_u32);
329 uint32_t nftnl_chain_get_u32(const struct nftnl_chain *c, uint16_t attr)
330 {
331  uint32_t data_len;
332  const uint32_t *val = nftnl_chain_get_data(c, attr, &data_len);
333 
334  nftnl_assert(val, attr, data_len == sizeof(uint32_t));
335 
336  return val ? *val : 0;
337 }
338 
339 EXPORT_SYMBOL(nftnl_chain_get_s32);
340 int32_t nftnl_chain_get_s32(const struct nftnl_chain *c, uint16_t attr)
341 {
342  uint32_t data_len;
343  const int32_t *val = nftnl_chain_get_data(c, attr, &data_len);
344 
345  nftnl_assert(val, attr, data_len == sizeof(int32_t));
346 
347  return val ? *val : 0;
348 }
349 
350 EXPORT_SYMBOL(nftnl_chain_get_u64);
351 uint64_t nftnl_chain_get_u64(const struct nftnl_chain *c, uint16_t attr)
352 {
353  uint32_t data_len;
354  const uint64_t *val = nftnl_chain_get_data(c, attr, &data_len);
355 
356  nftnl_assert(val, attr, data_len == sizeof(int64_t));
357 
358  return val ? *val : 0;
359 }
360 
361 EXPORT_SYMBOL(nftnl_chain_get_u8);
362 uint8_t nftnl_chain_get_u8(const struct nftnl_chain *c, uint16_t attr)
363 {
364  uint32_t data_len;
365  const uint8_t *val = nftnl_chain_get_data(c, attr, &data_len);
366 
367  nftnl_assert(val, attr, data_len == sizeof(int8_t));
368 
369  return val ? *val : 0;
370 }
371 
372 EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload);
373 void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_chain *c)
374 {
375  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
376  mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, c->table);
377  if (c->flags & (1 << NFTNL_CHAIN_NAME))
378  mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, c->name);
379  if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) &&
380  (c->flags & (1 << NFTNL_CHAIN_PRIO))) {
381  struct nlattr *nest;
382 
383  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
384  mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(c->hooknum));
385  mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(c->prio));
386  if (c->flags & (1 << NFTNL_CHAIN_DEV))
387  mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
388  mnl_attr_nest_end(nlh, nest);
389  }
390  if (c->flags & (1 << NFTNL_CHAIN_POLICY))
391  mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(c->policy));
392  if (c->flags & (1 << NFTNL_CHAIN_USE))
393  mnl_attr_put_u32(nlh, NFTA_CHAIN_USE, htonl(c->use));
394  if ((c->flags & (1 << NFTNL_CHAIN_PACKETS)) &&
395  (c->flags & (1 << NFTNL_CHAIN_BYTES))) {
396  struct nlattr *nest;
397 
398  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_COUNTERS);
399  mnl_attr_put_u64(nlh, NFTA_COUNTER_PACKETS, be64toh(c->packets));
400  mnl_attr_put_u64(nlh, NFTA_COUNTER_BYTES, be64toh(c->bytes));
401  mnl_attr_nest_end(nlh, nest);
402  }
403  if (c->flags & (1 << NFTNL_CHAIN_HANDLE))
404  mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, be64toh(c->handle));
405  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
406  mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type);
407 }
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 EXPORT_SYMBOL(nftnl_chain_nlmsg_parse);
533 int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c)
534 {
535  struct nlattr *tb[NFTA_CHAIN_MAX+1] = {};
536  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
537  int ret = 0;
538 
539  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_chain_parse_attr_cb, tb) < 0)
540  return -1;
541 
542  if (tb[NFTA_CHAIN_NAME]) {
543  if (c->flags & (1 << NFTNL_CHAIN_NAME))
544  xfree(c->name);
545  c->name = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_NAME]));
546  if (!c->name)
547  return -1;
548  c->flags |= (1 << NFTNL_CHAIN_NAME);
549  }
550  if (tb[NFTA_CHAIN_TABLE]) {
551  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
552  xfree(c->table);
553  c->table = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TABLE]));
554  if (!c->table)
555  return -1;
556  c->flags |= (1 << NFTNL_CHAIN_TABLE);
557  }
558  if (tb[NFTA_CHAIN_HOOK]) {
559  ret = nftnl_chain_parse_hook(tb[NFTA_CHAIN_HOOK], c);
560  if (ret < 0)
561  return ret;
562  }
563  if (tb[NFTA_CHAIN_POLICY]) {
564  c->policy = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_POLICY]));
565  c->flags |= (1 << NFTNL_CHAIN_POLICY);
566  }
567  if (tb[NFTA_CHAIN_USE]) {
568  c->use = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_USE]));
569  c->flags |= (1 << NFTNL_CHAIN_USE);
570  }
571  if (tb[NFTA_CHAIN_COUNTERS]) {
572  ret = nftnl_chain_parse_counters(tb[NFTA_CHAIN_COUNTERS], c);
573  if (ret < 0)
574  return ret;
575  }
576  if (tb[NFTA_CHAIN_HANDLE]) {
577  c->handle = be64toh(mnl_attr_get_u64(tb[NFTA_CHAIN_HANDLE]));
578  c->flags |= (1 << NFTNL_CHAIN_HANDLE);
579  }
580  if (tb[NFTA_CHAIN_TYPE]) {
581  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
582  xfree(c->type);
583  c->type = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TYPE]));
584  if (!c->type)
585  return -1;
586  c->flags |= (1 << NFTNL_CHAIN_TYPE);
587  }
588 
589  c->family = nfg->nfgen_family;
590  c->flags |= (1 << NFTNL_CHAIN_FAMILY);
591 
592  return ret;
593 }
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 static int nftnl_chain_snprintf_default(char *buf, size_t size,
607  const struct nftnl_chain *c)
608 {
609  int ret, remain = size, offset = 0;
610 
611  ret = snprintf(buf, remain, "%s %s %s use %u",
612  nftnl_family2str(c->family), c->table, c->name, c->use);
613  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
614 
615  if (c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) {
616  ret = snprintf(buf + offset, remain, " type %s hook %s prio %d",
617  c->type, nftnl_hooknum2str(c->family, c->hooknum),
618  c->prio);
619  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
620 
621  if (c->flags & (1 << NFTNL_CHAIN_POLICY)) {
622  ret = snprintf(buf + offset, remain, " policy %s",
623  nftnl_verdict2str(c->policy));
624  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
625  }
626 
627  ret = snprintf(buf + offset, remain,
628  " packets %"PRIu64" bytes %"PRIu64"",
629  c->packets, c->bytes);
630  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
631 
632  if (c->flags & (1 << NFTNL_CHAIN_DEV)) {
633  ret = snprintf(buf + offset, remain, " dev %s ",
634  c->dev);
635  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
636  }
637  }
638 
639  return offset;
640 }
641 
642 static int nftnl_chain_cmd_snprintf(char *buf, size_t size,
643  const struct nftnl_chain *c, uint32_t cmd,
644  uint32_t type, uint32_t flags)
645 {
646  int ret, remain = size, offset = 0;
647 
648  switch (type) {
649  case NFTNL_OUTPUT_DEFAULT:
650  ret = nftnl_chain_snprintf_default(buf + offset, remain, c);
651  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
652  break;
653  case NFTNL_OUTPUT_XML:
654  case NFTNL_OUTPUT_JSON:
655  default:
656  return -1;
657  }
658 
659  return offset;
660 }
661 
662 EXPORT_SYMBOL(nftnl_chain_snprintf);
663 int nftnl_chain_snprintf(char *buf, size_t size, const struct nftnl_chain *c,
664  uint32_t type, uint32_t flags)
665 {
666  if (size)
667  buf[0] = '\0';
668 
669  return nftnl_chain_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
670  type, flags);
671 }
672 
673 static int nftnl_chain_do_snprintf(char *buf, size_t size, const void *c,
674  uint32_t cmd, uint32_t type, uint32_t flags)
675 {
676  return nftnl_chain_snprintf(buf, size, c, type, flags);
677 }
678 
679 EXPORT_SYMBOL(nftnl_chain_fprintf);
680 int nftnl_chain_fprintf(FILE *fp, const struct nftnl_chain *c, uint32_t type,
681  uint32_t flags)
682 {
683  return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
684  nftnl_chain_do_snprintf);
685 }
686 
688  struct list_head list;
689 };
690 
691 EXPORT_SYMBOL(nftnl_chain_list_alloc);
692 struct nftnl_chain_list *nftnl_chain_list_alloc(void)
693 {
694  struct nftnl_chain_list *list;
695 
696  list = calloc(1, sizeof(struct nftnl_chain_list));
697  if (list == NULL)
698  return NULL;
699 
700  INIT_LIST_HEAD(&list->list);
701 
702  return list;
703 }
704 
705 EXPORT_SYMBOL(nftnl_chain_list_free);
706 void nftnl_chain_list_free(struct nftnl_chain_list *list)
707 {
708  struct nftnl_chain *r, *tmp;
709 
710  list_for_each_entry_safe(r, tmp, &list->list, head) {
711  list_del(&r->head);
712  nftnl_chain_free(r);
713  }
714  xfree(list);
715 }
716 
717 EXPORT_SYMBOL(nftnl_chain_list_is_empty);
718 int nftnl_chain_list_is_empty(const struct nftnl_chain_list *list)
719 {
720  return list_empty(&list->list);
721 }
722 
723 EXPORT_SYMBOL(nftnl_chain_list_add);
724 void nftnl_chain_list_add(struct nftnl_chain *r, struct nftnl_chain_list *list)
725 {
726  list_add(&r->head, &list->list);
727 }
728 
729 EXPORT_SYMBOL(nftnl_chain_list_add_tail);
730 void nftnl_chain_list_add_tail(struct nftnl_chain *r, struct nftnl_chain_list *list)
731 {
732  list_add_tail(&r->head, &list->list);
733 }
734 
735 EXPORT_SYMBOL(nftnl_chain_list_del);
736 void nftnl_chain_list_del(struct nftnl_chain *r)
737 {
738  list_del(&r->head);
739 }
740 
741 EXPORT_SYMBOL(nftnl_chain_list_foreach);
742 int nftnl_chain_list_foreach(struct nftnl_chain_list *chain_list,
743  int (*cb)(struct nftnl_chain *r, void *data),
744  void *data)
745 {
746  struct nftnl_chain *cur, *tmp;
747  int ret;
748 
749  list_for_each_entry_safe(cur, tmp, &chain_list->list, head) {
750  ret = cb(cur, data);
751  if (ret < 0)
752  return ret;
753  }
754  return 0;
755 }
756 
758  const struct nftnl_chain_list *list;
759  struct nftnl_chain *cur;
760 };
761 
762 EXPORT_SYMBOL(nftnl_chain_list_iter_create);
763 struct nftnl_chain_list_iter *
764 nftnl_chain_list_iter_create(const struct nftnl_chain_list *l)
765 {
766  struct nftnl_chain_list_iter *iter;
767 
768  iter = calloc(1, sizeof(struct nftnl_chain_list_iter));
769  if (iter == NULL)
770  return NULL;
771 
772  iter->list = l;
773  if (nftnl_chain_list_is_empty(l))
774  iter->cur = NULL;
775  else
776  iter->cur = list_entry(l->list.next, struct nftnl_chain, head);
777 
778  return iter;
779 }
780 
781 EXPORT_SYMBOL(nftnl_chain_list_iter_next);
782 struct nftnl_chain *nftnl_chain_list_iter_next(struct nftnl_chain_list_iter *iter)
783 {
784  struct nftnl_chain *r = iter->cur;
785 
786  if (r == NULL)
787  return NULL;
788 
789  /* get next chain, if any */
790  iter->cur = list_entry(iter->cur->head.next, struct nftnl_chain, head);
791  if (&iter->cur->head == iter->list->list.next)
792  return NULL;
793 
794  return r;
795 }
796 
797 EXPORT_SYMBOL(nftnl_chain_list_iter_destroy);
798 void nftnl_chain_list_iter_destroy(struct nftnl_chain_list_iter *iter)
799 {
800  xfree(iter);
801 }