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