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