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