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