libnftnl  1.2.6
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  struct nlattr *nest = NULL;
490  int i;
491 
492  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
493  mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, c->table);
494  if (c->flags & (1 << NFTNL_CHAIN_NAME))
495  mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, c->name);
496 
497  if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) ||
498  (c->flags & (1 << NFTNL_CHAIN_PRIO)) ||
499  (c->flags & (1 << NFTNL_CHAIN_DEV)) ||
500  (c->flags & (1 << NFTNL_CHAIN_DEVICES)))
501  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
502 
503  if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)))
504  mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(c->hooknum));
505  if ((c->flags & (1 << NFTNL_CHAIN_PRIO)))
506  mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(c->prio));
507 
508  if (c->flags & (1 << NFTNL_CHAIN_DEV))
509  mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
510  else if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
511  struct nlattr *nest_dev;
512 
513  nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
514  for (i = 0; i < c->dev_array_len; i++)
515  mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
516  c->dev_array[i]);
517  mnl_attr_nest_end(nlh, nest_dev);
518  }
519 
520  if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) ||
521  (c->flags & (1 << NFTNL_CHAIN_PRIO)) ||
522  (c->flags & (1 << NFTNL_CHAIN_DEV)) ||
523  (c->flags & (1 << NFTNL_CHAIN_DEVICES)))
524  mnl_attr_nest_end(nlh, nest);
525 
526  if (c->flags & (1 << NFTNL_CHAIN_POLICY))
527  mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(c->policy));
528  if (c->flags & (1 << NFTNL_CHAIN_USE))
529  mnl_attr_put_u32(nlh, NFTA_CHAIN_USE, htonl(c->use));
530  if ((c->flags & (1 << NFTNL_CHAIN_PACKETS)) &&
531  (c->flags & (1 << NFTNL_CHAIN_BYTES))) {
532  nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_COUNTERS);
533  mnl_attr_put_u64(nlh, NFTA_COUNTER_PACKETS, be64toh(c->packets));
534  mnl_attr_put_u64(nlh, NFTA_COUNTER_BYTES, be64toh(c->bytes));
535  mnl_attr_nest_end(nlh, nest);
536  }
537  if (c->flags & (1 << NFTNL_CHAIN_HANDLE))
538  mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, be64toh(c->handle));
539  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
540  mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type);
541  if (c->flags & (1 << NFTNL_CHAIN_FLAGS))
542  mnl_attr_put_u32(nlh, NFTA_CHAIN_FLAGS, htonl(c->chain_flags));
543  if (c->flags & (1 << NFTNL_CHAIN_ID))
544  mnl_attr_put_u32(nlh, NFTA_CHAIN_ID, htonl(c->chain_id));
545  if (c->flags & (1 << NFTNL_CHAIN_USERDATA))
546  mnl_attr_put(nlh, NFTA_CHAIN_USERDATA, c->user.len, c->user.data);
547 }
548 
549 EXPORT_SYMBOL(nftnl_chain_rule_add);
550 void nftnl_chain_rule_add(struct nftnl_rule *rule, struct nftnl_chain *c)
551 {
552  list_add(&rule->head, &c->rule_list);
553 }
554 
555 EXPORT_SYMBOL(nftnl_chain_rule_del);
556 void nftnl_chain_rule_del(struct nftnl_rule *r)
557 {
558  list_del(&r->head);
559 }
560 
561 EXPORT_SYMBOL(nftnl_chain_rule_add_tail);
562 void nftnl_chain_rule_add_tail(struct nftnl_rule *rule, struct nftnl_chain *c)
563 {
564  list_add_tail(&rule->head, &c->rule_list);
565 }
566 
567 EXPORT_SYMBOL(nftnl_chain_rule_insert_at);
568 void nftnl_chain_rule_insert_at(struct nftnl_rule *rule, struct nftnl_rule *pos)
569 {
570  list_add_tail(&rule->head, &pos->head);
571 }
572 
573 EXPORT_SYMBOL(nftnl_chain_rule_append_at);
574 void nftnl_chain_rule_append_at(struct nftnl_rule *rule, struct nftnl_rule *pos)
575 {
576  list_add(&rule->head, &pos->head);
577 }
578 
579 static int nftnl_chain_parse_attr_cb(const struct nlattr *attr, void *data)
580 {
581  const struct nlattr **tb = data;
582  int type = mnl_attr_get_type(attr);
583 
584  if (mnl_attr_type_valid(attr, NFTA_CHAIN_MAX) < 0)
585  return MNL_CB_OK;
586 
587  switch(type) {
588  case NFTA_CHAIN_NAME:
589  case NFTA_CHAIN_TABLE:
590  case NFTA_CHAIN_TYPE:
591  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
592  abi_breakage();
593  break;
594  case NFTA_CHAIN_HOOK:
595  case NFTA_CHAIN_COUNTERS:
596  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
597  abi_breakage();
598  break;
599  case NFTA_CHAIN_POLICY:
600  case NFTA_CHAIN_USE:
601  case NFTA_CHAIN_FLAGS:
602  case NFTA_CHAIN_ID:
603  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
604  abi_breakage();
605  break;
606  case NFTA_CHAIN_HANDLE:
607  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
608  abi_breakage();
609  break;
610  case NFTA_CHAIN_USERDATA:
611  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
612  abi_breakage();
613  break;
614  }
615 
616  tb[type] = attr;
617  return MNL_CB_OK;
618 }
619 
620 static int nftnl_chain_parse_counters_cb(const struct nlattr *attr, void *data)
621 {
622  const struct nlattr **tb = data;
623  int type = mnl_attr_get_type(attr);
624 
625  if (mnl_attr_type_valid(attr, NFTA_COUNTER_MAX) < 0)
626  return MNL_CB_OK;
627 
628  switch(type) {
629  case NFTA_COUNTER_BYTES:
630  case NFTA_COUNTER_PACKETS:
631  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
632  abi_breakage();
633  break;
634  }
635 
636  tb[type] = attr;
637  return MNL_CB_OK;
638 }
639 
640 static int nftnl_chain_parse_counters(struct nlattr *attr, struct nftnl_chain *c)
641 {
642  struct nlattr *tb[NFTA_COUNTER_MAX+1] = {};
643 
644  if (mnl_attr_parse_nested(attr, nftnl_chain_parse_counters_cb, tb) < 0)
645  return -1;
646 
647  if (tb[NFTA_COUNTER_PACKETS]) {
648  c->packets = be64toh(mnl_attr_get_u64(tb[NFTA_COUNTER_PACKETS]));
649  c->flags |= (1 << NFTNL_CHAIN_PACKETS);
650  }
651  if (tb[NFTA_COUNTER_BYTES]) {
652  c->bytes = be64toh(mnl_attr_get_u64(tb[NFTA_COUNTER_BYTES]));
653  c->flags |= (1 << NFTNL_CHAIN_BYTES);
654  }
655 
656  return 0;
657 }
658 
659 static int nftnl_chain_parse_hook_cb(const struct nlattr *attr, void *data)
660 {
661  const struct nlattr **tb = data;
662  int type = mnl_attr_get_type(attr);
663 
664  if (mnl_attr_type_valid(attr, NFTA_HOOK_MAX) < 0)
665  return MNL_CB_OK;
666 
667  switch(type) {
668  case NFTA_HOOK_HOOKNUM:
669  case NFTA_HOOK_PRIORITY:
670  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
671  abi_breakage();
672  break;
673  case NFTA_HOOK_DEV:
674  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
675  abi_breakage();
676  break;
677  }
678 
679  tb[type] = attr;
680  return MNL_CB_OK;
681 }
682 
683 static int nftnl_chain_parse_devs(struct nlattr *nest, struct nftnl_chain *c)
684 {
685  const char **dev_array, **tmp;
686  int len = 0, size = 8;
687  struct nlattr *attr;
688 
689  dev_array = calloc(8, sizeof(char *));
690  if (!dev_array)
691  return -1;
692 
693  mnl_attr_for_each_nested(attr, nest) {
694  if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
695  goto err;
696  dev_array[len++] = strdup(mnl_attr_get_str(attr));
697  if (len >= size) {
698  tmp = realloc(dev_array, size * 2 * sizeof(char *));
699  if (!tmp)
700  goto err;
701 
702  size *= 2;
703  memset(&tmp[len], 0, (size - len) * sizeof(char *));
704  dev_array = tmp;
705  }
706  }
707 
708  c->dev_array = dev_array;
709  c->dev_array_len = len;
710 
711  return 0;
712 err:
713  while (len--)
714  xfree(dev_array[len]);
715  xfree(dev_array);
716  return -1;
717 }
718 
719 static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
720 {
721  struct nlattr *tb[NFTA_HOOK_MAX+1] = {};
722  int ret;
723 
724  if (mnl_attr_parse_nested(attr, nftnl_chain_parse_hook_cb, tb) < 0)
725  return -1;
726 
727  if (tb[NFTA_HOOK_HOOKNUM]) {
728  c->hooknum = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_HOOKNUM]));
729  c->flags |= (1 << NFTNL_CHAIN_HOOKNUM);
730  }
731  if (tb[NFTA_HOOK_PRIORITY]) {
732  c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_PRIORITY]));
733  c->flags |= (1 << NFTNL_CHAIN_PRIO);
734  }
735  if (tb[NFTA_HOOK_DEV]) {
736  c->dev = strdup(mnl_attr_get_str(tb[NFTA_HOOK_DEV]));
737  if (!c->dev)
738  return -1;
739  c->flags |= (1 << NFTNL_CHAIN_DEV);
740  }
741  if (tb[NFTA_HOOK_DEVS]) {
742  ret = nftnl_chain_parse_devs(tb[NFTA_HOOK_DEVS], c);
743  if (ret < 0)
744  return -1;
745  c->flags |= (1 << NFTNL_CHAIN_DEVICES);
746  }
747 
748  return 0;
749 }
750 
751 EXPORT_SYMBOL(nftnl_chain_nlmsg_parse);
752 int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c)
753 {
754  struct nlattr *tb[NFTA_CHAIN_MAX+1] = {};
755  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
756  int ret = 0;
757 
758  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_chain_parse_attr_cb, tb) < 0)
759  return -1;
760 
761  if (tb[NFTA_CHAIN_NAME]) {
762  if (c->flags & (1 << NFTNL_CHAIN_NAME))
763  xfree(c->name);
764  c->name = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_NAME]));
765  if (!c->name)
766  return -1;
767  c->flags |= (1 << NFTNL_CHAIN_NAME);
768  }
769  if (tb[NFTA_CHAIN_TABLE]) {
770  if (c->flags & (1 << NFTNL_CHAIN_TABLE))
771  xfree(c->table);
772  c->table = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TABLE]));
773  if (!c->table)
774  return -1;
775  c->flags |= (1 << NFTNL_CHAIN_TABLE);
776  }
777  if (tb[NFTA_CHAIN_HOOK]) {
778  ret = nftnl_chain_parse_hook(tb[NFTA_CHAIN_HOOK], c);
779  if (ret < 0)
780  return ret;
781  }
782  if (tb[NFTA_CHAIN_POLICY]) {
783  c->policy = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_POLICY]));
784  c->flags |= (1 << NFTNL_CHAIN_POLICY);
785  }
786  if (tb[NFTA_CHAIN_USE]) {
787  c->use = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_USE]));
788  c->flags |= (1 << NFTNL_CHAIN_USE);
789  }
790  if (tb[NFTA_CHAIN_COUNTERS]) {
791  ret = nftnl_chain_parse_counters(tb[NFTA_CHAIN_COUNTERS], c);
792  if (ret < 0)
793  return ret;
794  }
795  if (tb[NFTA_CHAIN_HANDLE]) {
796  c->handle = be64toh(mnl_attr_get_u64(tb[NFTA_CHAIN_HANDLE]));
797  c->flags |= (1 << NFTNL_CHAIN_HANDLE);
798  }
799  if (tb[NFTA_CHAIN_TYPE]) {
800  if (c->flags & (1 << NFTNL_CHAIN_TYPE))
801  xfree(c->type);
802  c->type = strdup(mnl_attr_get_str(tb[NFTA_CHAIN_TYPE]));
803  if (!c->type)
804  return -1;
805  c->flags |= (1 << NFTNL_CHAIN_TYPE);
806  }
807  if (tb[NFTA_CHAIN_FLAGS]) {
808  c->chain_flags = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_FLAGS]));
809  c->flags |= (1 << NFTNL_CHAIN_FLAGS);
810  }
811  if (tb[NFTA_CHAIN_ID]) {
812  c->chain_id = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_ID]));
813  c->flags |= (1 << NFTNL_CHAIN_ID);
814  }
815  if (tb[NFTA_CHAIN_USERDATA]) {
816  nftnl_chain_set_data(c, NFTNL_CHAIN_USERDATA,
817  mnl_attr_get_payload(tb[NFTA_CHAIN_USERDATA]),
818  mnl_attr_get_payload_len(tb[NFTA_CHAIN_USERDATA]));
819  }
820 
821  c->family = nfg->nfgen_family;
822  c->flags |= (1 << NFTNL_CHAIN_FAMILY);
823 
824  return ret;
825 }
826 
827 static inline int nftnl_str2hooknum(int family, const char *hook)
828 {
829  int hooknum;
830 
831  for (hooknum = 0; hooknum < NF_INET_NUMHOOKS; hooknum++) {
832  if (strcmp(hook, nftnl_hooknum2str(family, hooknum)) == 0)
833  return hooknum;
834  }
835  return -1;
836 }
837 
838 static int nftnl_chain_snprintf_default(char *buf, size_t remain,
839  const struct nftnl_chain *c)
840 {
841  int ret, offset = 0, i;
842 
843  ret = snprintf(buf, remain, "%s %s %s use %u",
844  nftnl_family2str(c->family), c->table, c->name, c->use);
845  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
846 
847  if (c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) {
848  ret = snprintf(buf + offset, remain, " type %s hook %s prio %d",
849  c->type, nftnl_hooknum2str(c->family, c->hooknum),
850  c->prio);
851  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
852 
853  if (c->flags & (1 << NFTNL_CHAIN_POLICY)) {
854  ret = snprintf(buf + offset, remain, " policy %s",
855  nftnl_verdict2str(c->policy));
856  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
857  }
858 
859  ret = snprintf(buf + offset, remain,
860  " packets %"PRIu64" bytes %"PRIu64"",
861  c->packets, c->bytes);
862  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
863 
864  if (c->flags & (1 << NFTNL_CHAIN_DEV)) {
865  ret = snprintf(buf + offset, remain, " dev %s ",
866  c->dev);
867  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
868  }
869  if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
870  ret = snprintf(buf + offset, remain, " dev { ");
871  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
872 
873  for (i = 0; i < c->dev_array_len; i++) {
874  ret = snprintf(buf + offset, remain, " %s ",
875  c->dev_array[i]);
876  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
877  }
878  ret = snprintf(buf + offset, remain, " } ");
879  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
880  }
881  if (c->flags & (1 << NFTNL_CHAIN_FLAGS)) {
882  ret = snprintf(buf + offset, remain, " flags %x",
883  c->chain_flags);
884  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
885  }
886  if (c->flags & (1 << NFTNL_CHAIN_ID)) {
887  ret = snprintf(buf + offset, remain, " id %x",
888  c->chain_id);
889  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
890  }
891  }
892 
893  return offset;
894 }
895 
896 static int nftnl_chain_cmd_snprintf(char *buf, size_t remain,
897  const struct nftnl_chain *c, uint32_t cmd,
898  uint32_t type, uint32_t flags)
899 {
900  int ret, offset = 0;
901 
902  if (type != NFTNL_OUTPUT_DEFAULT)
903  return -1;
904 
905  ret = nftnl_chain_snprintf_default(buf + offset, remain, c);
906  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
907  return offset;
908 }
909 
910 EXPORT_SYMBOL(nftnl_chain_snprintf);
911 int nftnl_chain_snprintf(char *buf, size_t size, const struct nftnl_chain *c,
912  uint32_t type, uint32_t flags)
913 {
914  if (size)
915  buf[0] = '\0';
916 
917  return nftnl_chain_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags),
918  type, flags);
919 }
920 
921 static int nftnl_chain_do_snprintf(char *buf, size_t size, const void *c,
922  uint32_t cmd, uint32_t type, uint32_t flags)
923 {
924  return nftnl_chain_snprintf(buf, size, c, type, flags);
925 }
926 
927 EXPORT_SYMBOL(nftnl_chain_fprintf);
928 int nftnl_chain_fprintf(FILE *fp, const struct nftnl_chain *c, uint32_t type,
929  uint32_t flags)
930 {
931  return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
932  nftnl_chain_do_snprintf);
933 }
934 
935 EXPORT_SYMBOL(nftnl_rule_foreach);
936 int nftnl_rule_foreach(struct nftnl_chain *c,
937  int (*cb)(struct nftnl_rule *r, void *data),
938  void *data)
939 {
940  struct nftnl_rule *cur, *tmp;
941  int ret;
942 
943  list_for_each_entry_safe(cur, tmp, &c->rule_list, head) {
944  ret = cb(cur, data);
945  if (ret < 0)
946  return ret;
947  }
948  return 0;
949 }
950 
951 EXPORT_SYMBOL(nftnl_rule_lookup_byindex);
952 struct nftnl_rule *
953 nftnl_rule_lookup_byindex(struct nftnl_chain *c, uint32_t index)
954 {
955  struct nftnl_rule *r;
956 
957  list_for_each_entry(r, &c->rule_list, head) {
958  if (!index)
959  return r;
960  index--;
961  }
962  return NULL;
963 }
964 
966  const struct nftnl_chain *c;
967  struct nftnl_rule *cur;
968 };
969 
970 static void nftnl_rule_iter_init(const struct nftnl_chain *c,
971  struct nftnl_rule_iter *iter)
972 {
973  iter->c = c;
974  if (list_empty(&c->rule_list))
975  iter->cur = NULL;
976  else
977  iter->cur = list_entry(c->rule_list.next, struct nftnl_rule,
978  head);
979 }
980 
981 EXPORT_SYMBOL(nftnl_rule_iter_create);
982 struct nftnl_rule_iter *nftnl_rule_iter_create(const struct nftnl_chain *c)
983 {
984  struct nftnl_rule_iter *iter;
985 
986  iter = calloc(1, sizeof(struct nftnl_rule_iter));
987  if (iter == NULL)
988  return NULL;
989 
990  nftnl_rule_iter_init(c, iter);
991 
992  return iter;
993 }
994 
995 EXPORT_SYMBOL(nftnl_rule_iter_next);
996 struct nftnl_rule *nftnl_rule_iter_next(struct nftnl_rule_iter *iter)
997 {
998  struct nftnl_rule *rule = iter->cur;
999 
1000  if (rule == NULL)
1001  return NULL;
1002 
1003  /* get next rule, if any */
1004  iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
1005  if (&iter->cur->head == iter->c->rule_list.next)
1006  return NULL;
1007 
1008  return rule;
1009 }
1010 
1011 EXPORT_SYMBOL(nftnl_rule_iter_destroy);
1012 void nftnl_rule_iter_destroy(struct nftnl_rule_iter *iter)
1013 {
1014  xfree(iter);
1015 }
1016 
1017 #define CHAIN_NAME_HSIZE 512
1018 
1020 
1021  struct list_head list;
1022  struct hlist_head name_hash[CHAIN_NAME_HSIZE];
1023 };
1024 
1025 EXPORT_SYMBOL(nftnl_chain_list_alloc);
1026 struct nftnl_chain_list *nftnl_chain_list_alloc(void)
1027 {
1028  struct nftnl_chain_list *list;
1029  int i;
1030 
1031  list = calloc(1, sizeof(struct nftnl_chain_list));
1032  if (list == NULL)
1033  return NULL;
1034 
1035  INIT_LIST_HEAD(&list->list);
1036  for (i = 0; i < CHAIN_NAME_HSIZE; i++)
1037  INIT_HLIST_HEAD(&list->name_hash[i]);
1038 
1039  return list;
1040 }
1041 
1042 EXPORT_SYMBOL(nftnl_chain_list_free);
1043 void nftnl_chain_list_free(struct nftnl_chain_list *list)
1044 {
1045  struct nftnl_chain *r, *tmp;
1046 
1047  list_for_each_entry_safe(r, tmp, &list->list, head) {
1048  list_del(&r->head);
1049  hlist_del(&r->hnode);
1050  nftnl_chain_free(r);
1051  }
1052  xfree(list);
1053 }
1054 
1055 EXPORT_SYMBOL(nftnl_chain_list_is_empty);
1056 int nftnl_chain_list_is_empty(const struct nftnl_chain_list *list)
1057 {
1058  return list_empty(&list->list);
1059 }
1060 
1061 static uint32_t djb_hash(const char *key)
1062 {
1063  uint32_t i, hash = 5381;
1064 
1065  for (i = 0; i < strlen(key); i++)
1066  hash = ((hash << 5) + hash) + key[i];
1067 
1068  return hash;
1069 }
1070 
1071 EXPORT_SYMBOL(nftnl_chain_list_add);
1072 void nftnl_chain_list_add(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(&r->head, &list->list);
1078 }
1079 
1080 EXPORT_SYMBOL(nftnl_chain_list_add_tail);
1081 void nftnl_chain_list_add_tail(struct nftnl_chain *r, struct nftnl_chain_list *list)
1082 {
1083  int key = djb_hash(r->name) % CHAIN_NAME_HSIZE;
1084 
1085  hlist_add_head(&r->hnode, &list->name_hash[key]);
1086  list_add_tail(&r->head, &list->list);
1087 }
1088 
1089 EXPORT_SYMBOL(nftnl_chain_list_del);
1090 void nftnl_chain_list_del(struct nftnl_chain *r)
1091 {
1092  list_del(&r->head);
1093  hlist_del(&r->hnode);
1094 }
1095 
1096 EXPORT_SYMBOL(nftnl_chain_list_foreach);
1097 int nftnl_chain_list_foreach(struct nftnl_chain_list *chain_list,
1098  int (*cb)(struct nftnl_chain *r, void *data),
1099  void *data)
1100 {
1101  struct nftnl_chain *cur, *tmp;
1102  int ret;
1103 
1104  list_for_each_entry_safe(cur, tmp, &chain_list->list, head) {
1105  ret = cb(cur, data);
1106  if (ret < 0)
1107  return ret;
1108  }
1109  return 0;
1110 }
1111 
1112 EXPORT_SYMBOL(nftnl_chain_list_lookup_byname);
1113 struct nftnl_chain *
1114 nftnl_chain_list_lookup_byname(struct nftnl_chain_list *chain_list,
1115  const char *chain)
1116 {
1117  int key = djb_hash(chain) % CHAIN_NAME_HSIZE;
1118  struct nftnl_chain *c;
1119  struct hlist_node *n;
1120 
1121  hlist_for_each_entry(c, n, &chain_list->name_hash[key], hnode) {
1122  if (!strcmp(chain, c->name))
1123  return c;
1124  }
1125  return NULL;
1126 }
1127 
1129  const struct nftnl_chain_list *list;
1130  struct nftnl_chain *cur;
1131 };
1132 
1133 EXPORT_SYMBOL(nftnl_chain_list_iter_create);
1134 struct nftnl_chain_list_iter *
1135 nftnl_chain_list_iter_create(const struct nftnl_chain_list *l)
1136 {
1137  struct nftnl_chain_list_iter *iter;
1138 
1139  iter = calloc(1, sizeof(struct nftnl_chain_list_iter));
1140  if (iter == NULL)
1141  return NULL;
1142 
1143  iter->list = l;
1144  if (nftnl_chain_list_is_empty(l))
1145  iter->cur = NULL;
1146  else
1147  iter->cur = list_entry(l->list.next, struct nftnl_chain, head);
1148 
1149  return iter;
1150 }
1151 
1152 EXPORT_SYMBOL(nftnl_chain_list_iter_next);
1153 struct nftnl_chain *nftnl_chain_list_iter_next(struct nftnl_chain_list_iter *iter)
1154 {
1155  struct nftnl_chain *r = iter->cur;
1156 
1157  if (r == NULL)
1158  return NULL;
1159 
1160  /* get next chain, if any */
1161  iter->cur = list_entry(iter->cur->head.next, struct nftnl_chain, head);
1162  if (&iter->cur->head == iter->list->list.next)
1163  return NULL;
1164 
1165  return r;
1166 }
1167 
1168 EXPORT_SYMBOL(nftnl_chain_list_iter_destroy);
1169 void nftnl_chain_list_iter_destroy(struct nftnl_chain_list_iter *iter)
1170 {
1171  xfree(iter);
1172 }