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
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
62static 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
102EXPORT_SYMBOL(nftnl_chain_alloc);
103struct 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
116EXPORT_SYMBOL(nftnl_chain_free);
117void 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
144EXPORT_SYMBOL(nftnl_chain_is_set);
145bool nftnl_chain_is_set(const struct nftnl_chain *c, uint16_t attr)
146{
147 return c->flags & (1 << attr);
148}
149
150EXPORT_SYMBOL(nftnl_chain_unset);
151void 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
198static 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
211EXPORT_SYMBOL(nftnl_chain_set_data);
212int 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
299void nftnl_chain_set(struct nftnl_chain *c, uint16_t attr, const void *data) __visible;
300void 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
305EXPORT_SYMBOL(nftnl_chain_set_u32);
306void 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
311EXPORT_SYMBOL(nftnl_chain_set_s32);
312void 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
317EXPORT_SYMBOL(nftnl_chain_set_u64);
318void 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
323EXPORT_SYMBOL(nftnl_chain_set_u8);
324void 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
329EXPORT_SYMBOL(nftnl_chain_set_str);
330int 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
335EXPORT_SYMBOL(nftnl_chain_set_array);
336int 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
342EXPORT_SYMBOL(nftnl_chain_get_data);
343const 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
402EXPORT_SYMBOL(nftnl_chain_get);
403const 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
409EXPORT_SYMBOL(nftnl_chain_get_str);
410const char *nftnl_chain_get_str(const struct nftnl_chain *c, uint16_t attr)
411{
412 return nftnl_chain_get(c, attr);
413}
414
415EXPORT_SYMBOL(nftnl_chain_get_u32);
416uint32_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
426EXPORT_SYMBOL(nftnl_chain_get_s32);
427int32_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
437EXPORT_SYMBOL(nftnl_chain_get_u64);
438uint64_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
448EXPORT_SYMBOL(nftnl_chain_get_u8);
449uint8_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
459EXPORT_SYMBOL(nftnl_chain_get_array);
460const 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
470EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload);
471void 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
533EXPORT_SYMBOL(nftnl_chain_rule_add);
534void nftnl_chain_rule_add(struct nftnl_rule *rule, struct nftnl_chain *c)
535{
536 list_add(&rule->head, &c->rule_list);
537}
538
539EXPORT_SYMBOL(nftnl_chain_rule_del);
540void nftnl_chain_rule_del(struct nftnl_rule *r)
541{
542 list_del(&r->head);
543}
544
545EXPORT_SYMBOL(nftnl_chain_rule_add_tail);
546void 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
551EXPORT_SYMBOL(nftnl_chain_rule_insert_at);
552void nftnl_chain_rule_insert_at(struct nftnl_rule *rule, struct nftnl_rule *pos)
553{
554 list_add_tail(&rule->head, &pos->head);
555}
556
557EXPORT_SYMBOL(nftnl_chain_rule_append_at);
558void nftnl_chain_rule_append_at(struct nftnl_rule *rule, struct nftnl_rule *pos)
559{
560 list_add(&rule->head, &pos->head);
561}
562
563static 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
604static 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
624static 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
643static 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
667static 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;
696err:
697 while (len--)
698 xfree(dev_array[len]);
699 xfree(dev_array);
700 return -1;
701}
702
703static 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
735EXPORT_SYMBOL(nftnl_chain_nlmsg_parse);
736int 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
811static 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
822static 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
880static 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
894EXPORT_SYMBOL(nftnl_chain_snprintf);
895int 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
905static 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
911EXPORT_SYMBOL(nftnl_chain_fprintf);
912int 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
919EXPORT_SYMBOL(nftnl_rule_foreach);
920int 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
935EXPORT_SYMBOL(nftnl_rule_lookup_byindex);
936struct nftnl_rule *
937nftnl_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
954static 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
965EXPORT_SYMBOL(nftnl_rule_iter_create);
966struct 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
979EXPORT_SYMBOL(nftnl_rule_iter_next);
980struct 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
995EXPORT_SYMBOL(nftnl_rule_iter_destroy);
996void 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
1009EXPORT_SYMBOL(nftnl_chain_list_alloc);
1010struct 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
1026EXPORT_SYMBOL(nftnl_chain_list_free);
1027void 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
1039EXPORT_SYMBOL(nftnl_chain_list_is_empty);
1040int nftnl_chain_list_is_empty(const struct nftnl_chain_list *list)
1041{
1042 return list_empty(&list->list);
1043}
1044
1045static 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
1055EXPORT_SYMBOL(nftnl_chain_list_add);
1056void 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
1064EXPORT_SYMBOL(nftnl_chain_list_add_tail);
1065void 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
1073EXPORT_SYMBOL(nftnl_chain_list_del);
1074void nftnl_chain_list_del(struct nftnl_chain *r)
1075{
1076 list_del(&r->head);
1077 hlist_del(&r->hnode);
1078}
1079
1080EXPORT_SYMBOL(nftnl_chain_list_foreach);
1081int 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
1096EXPORT_SYMBOL(nftnl_chain_list_lookup_byname);
1097struct nftnl_chain *
1098nftnl_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
1117EXPORT_SYMBOL(nftnl_chain_list_iter_create);
1118struct nftnl_chain_list_iter *
1119nftnl_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
1136EXPORT_SYMBOL(nftnl_chain_list_iter_next);
1137struct 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
1152EXPORT_SYMBOL(nftnl_chain_list_iter_destroy);
1153void nftnl_chain_list_iter_destroy(struct nftnl_chain_list_iter *iter)
1154{
1155 xfree(iter);
1156}