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