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