libnftnl  1.3.1
rule.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6  */
7 #include "internal.h"
8 
9 #include <time.h>
10 #include <endian.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <limits.h>
14 #include <string.h>
15 #include <netinet/in.h>
16 #include <errno.h>
17 #include <inttypes.h>
18 #include <ctype.h>
19 
20 #include <libmnl/libmnl.h>
21 #include <linux/netfilter/nfnetlink.h>
22 #include <linux/netfilter/nf_tables.h>
23 
24 #include <libnftnl/rule.h>
25 #include <libnftnl/set.h>
26 #include <libnftnl/expr.h>
27 
28 EXPORT_SYMBOL(nftnl_rule_alloc);
29 struct nftnl_rule *nftnl_rule_alloc(void)
30 {
31  struct nftnl_rule *r;
32 
33  r = calloc(1, sizeof(struct nftnl_rule));
34  if (r == NULL)
35  return NULL;
36 
37  INIT_LIST_HEAD(&r->expr_list);
38 
39  return r;
40 }
41 
42 EXPORT_SYMBOL(nftnl_rule_free);
43 void nftnl_rule_free(const struct nftnl_rule *r)
44 {
45  struct nftnl_expr *e, *tmp;
46 
47  list_for_each_entry_safe(e, tmp, &r->expr_list, head)
48  nftnl_expr_free(e);
49 
50  if (r->flags & (1 << (NFTNL_RULE_TABLE)))
51  xfree(r->table);
52  if (r->flags & (1 << (NFTNL_RULE_CHAIN)))
53  xfree(r->chain);
54  if (r->flags & (1 << (NFTNL_RULE_USERDATA)))
55  xfree(r->user.data);
56 
57  xfree(r);
58 }
59 
60 EXPORT_SYMBOL(nftnl_rule_is_set);
61 bool nftnl_rule_is_set(const struct nftnl_rule *r, uint16_t attr)
62 {
63  return r->flags & (1 << attr);
64 }
65 
66 EXPORT_SYMBOL(nftnl_rule_unset);
67 void nftnl_rule_unset(struct nftnl_rule *r, uint16_t attr)
68 {
69  if (!(r->flags & (1 << attr)))
70  return;
71 
72  switch (attr) {
73  case NFTNL_RULE_TABLE:
74  xfree(r->table);
75  break;
76  case NFTNL_RULE_CHAIN:
77  xfree(r->chain);
78  break;
79  case NFTNL_RULE_HANDLE:
80  case NFTNL_RULE_COMPAT_PROTO:
81  case NFTNL_RULE_COMPAT_FLAGS:
82  case NFTNL_RULE_POSITION:
83  case NFTNL_RULE_FAMILY:
84  case NFTNL_RULE_ID:
85  case NFTNL_RULE_POSITION_ID:
86  break;
87  case NFTNL_RULE_USERDATA:
88  xfree(r->user.data);
89  break;
90  }
91 
92  r->flags &= ~(1 << attr);
93 }
94 
95 static uint32_t nftnl_rule_validate[NFTNL_RULE_MAX + 1] = {
96  [NFTNL_RULE_HANDLE] = sizeof(uint64_t),
97  [NFTNL_RULE_COMPAT_PROTO] = sizeof(uint32_t),
98  [NFTNL_RULE_COMPAT_FLAGS] = sizeof(uint32_t),
99  [NFTNL_RULE_FAMILY] = sizeof(uint32_t),
100  [NFTNL_RULE_POSITION] = sizeof(uint64_t),
101  [NFTNL_RULE_ID] = sizeof(uint32_t),
102  [NFTNL_RULE_POSITION_ID] = sizeof(uint32_t),
103 };
104 
105 EXPORT_SYMBOL(nftnl_rule_set_data);
106 int nftnl_rule_set_data(struct nftnl_rule *r, uint16_t attr,
107  const void *data, uint32_t data_len)
108 {
109  nftnl_assert_attr_exists(attr, NFTNL_RULE_MAX);
110  nftnl_assert_validate(data, nftnl_rule_validate, attr, data_len);
111 
112  switch(attr) {
113  case NFTNL_RULE_TABLE:
114  return nftnl_set_str_attr(&r->table, &r->flags,
115  attr, data, data_len);
116  case NFTNL_RULE_CHAIN:
117  return nftnl_set_str_attr(&r->chain, &r->flags,
118  attr, data, data_len);
119  case NFTNL_RULE_HANDLE:
120  memcpy(&r->handle, data, sizeof(r->handle));
121  break;
122  case NFTNL_RULE_COMPAT_PROTO:
123  memcpy(&r->compat.proto, data, sizeof(r->compat.proto));
124  break;
125  case NFTNL_RULE_COMPAT_FLAGS:
126  memcpy(&r->compat.flags, data, sizeof(r->compat.flags));
127  break;
128  case NFTNL_RULE_FAMILY:
129  memcpy(&r->family, data, sizeof(r->family));
130  break;
131  case NFTNL_RULE_POSITION:
132  memcpy(&r->position, data, sizeof(r->position));
133  break;
134  case NFTNL_RULE_USERDATA:
135  if (r->flags & (1 << NFTNL_RULE_USERDATA))
136  xfree(r->user.data);
137 
138  r->user.data = malloc(data_len);
139  if (!r->user.data)
140  return -1;
141 
142  memcpy(r->user.data, data, data_len);
143  r->user.len = data_len;
144  break;
145  case NFTNL_RULE_ID:
146  memcpy(&r->id, data, sizeof(r->id));
147  break;
148  case NFTNL_RULE_POSITION_ID:
149  memcpy(&r->position_id, data, sizeof(r->position_id));
150  break;
151  }
152  r->flags |= (1 << attr);
153  return 0;
154 }
155 
156 int nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data) __visible;
157 int nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data)
158 {
159  return nftnl_rule_set_data(r, attr, data, nftnl_rule_validate[attr]);
160 }
161 
162 EXPORT_SYMBOL(nftnl_rule_set_u32);
163 void nftnl_rule_set_u32(struct nftnl_rule *r, uint16_t attr, uint32_t val)
164 {
165  nftnl_rule_set_data(r, attr, &val, sizeof(uint32_t));
166 }
167 
168 EXPORT_SYMBOL(nftnl_rule_set_u64);
169 void nftnl_rule_set_u64(struct nftnl_rule *r, uint16_t attr, uint64_t val)
170 {
171  nftnl_rule_set_data(r, attr, &val, sizeof(uint64_t));
172 }
173 
174 EXPORT_SYMBOL(nftnl_rule_set_str);
175 int nftnl_rule_set_str(struct nftnl_rule *r, uint16_t attr, const char *str)
176 {
177  return nftnl_rule_set_data(r, attr, str, strlen(str) + 1);
178 }
179 
180 EXPORT_SYMBOL(nftnl_rule_get_data);
181 const void *nftnl_rule_get_data(const struct nftnl_rule *r, uint16_t attr,
182  uint32_t *data_len)
183 {
184  if (!(r->flags & (1 << attr)))
185  return NULL;
186 
187  switch(attr) {
188  case NFTNL_RULE_FAMILY:
189  *data_len = sizeof(uint32_t);
190  return &r->family;
191  case NFTNL_RULE_TABLE:
192  *data_len = strlen(r->table) + 1;
193  return r->table;
194  case NFTNL_RULE_CHAIN:
195  *data_len = strlen(r->chain) + 1;
196  return r->chain;
197  case NFTNL_RULE_HANDLE:
198  *data_len = sizeof(uint64_t);
199  return &r->handle;
200  case NFTNL_RULE_COMPAT_PROTO:
201  *data_len = sizeof(uint32_t);
202  return &r->compat.proto;
203  case NFTNL_RULE_COMPAT_FLAGS:
204  *data_len = sizeof(uint32_t);
205  return &r->compat.flags;
206  case NFTNL_RULE_POSITION:
207  *data_len = sizeof(uint64_t);
208  return &r->position;
209  case NFTNL_RULE_USERDATA:
210  *data_len = r->user.len;
211  return r->user.data;
212  case NFTNL_RULE_ID:
213  *data_len = sizeof(uint32_t);
214  return &r->id;
215  case NFTNL_RULE_POSITION_ID:
216  *data_len = sizeof(uint32_t);
217  return &r->position_id;
218  }
219  return NULL;
220 }
221 
222 EXPORT_SYMBOL(nftnl_rule_get);
223 const void *nftnl_rule_get(const struct nftnl_rule *r, uint16_t attr)
224 {
225  uint32_t data_len;
226  return nftnl_rule_get_data(r, attr, &data_len);
227 }
228 
229 EXPORT_SYMBOL(nftnl_rule_get_str);
230 const char *nftnl_rule_get_str(const struct nftnl_rule *r, uint16_t attr)
231 {
232  return nftnl_rule_get(r, attr);
233 }
234 
235 EXPORT_SYMBOL(nftnl_rule_get_u32);
236 uint32_t nftnl_rule_get_u32(const struct nftnl_rule *r, uint16_t attr)
237 {
238  uint32_t data_len;
239  const uint32_t *val = nftnl_rule_get_data(r, attr, &data_len);
240 
241  nftnl_assert(val, attr, data_len == sizeof(uint32_t));
242 
243  return val ? *val : 0;
244 }
245 
246 EXPORT_SYMBOL(nftnl_rule_get_u64);
247 uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr)
248 {
249  uint32_t data_len;
250  const uint64_t *val = nftnl_rule_get_data(r, attr, &data_len);
251 
252  nftnl_assert(val, attr, data_len == sizeof(uint64_t));
253 
254  return val ? *val : 0;
255 }
256 
257 EXPORT_SYMBOL(nftnl_rule_get_u8);
258 uint8_t nftnl_rule_get_u8(const struct nftnl_rule *r, uint16_t attr)
259 {
260  uint32_t data_len;
261  const uint8_t *val = nftnl_rule_get_data(r, attr, &data_len);
262 
263  nftnl_assert(val, attr, data_len == sizeof(uint8_t));
264 
265  return val ? *val : 0;
266 }
267 
268 EXPORT_SYMBOL(nftnl_rule_nlmsg_build_payload);
269 void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *r)
270 {
271  struct nftnl_expr *expr;
272  struct nlattr *nest, *nest2;
273 
274  if (r->flags & (1 << NFTNL_RULE_TABLE))
275  mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, r->table);
276  if (r->flags & (1 << NFTNL_RULE_CHAIN))
277  mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, r->chain);
278  if (r->flags & (1 << NFTNL_RULE_HANDLE))
279  mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(r->handle));
280  if (r->flags & (1 << NFTNL_RULE_POSITION))
281  mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
282  if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
283  mnl_attr_put(nlh, NFTA_RULE_USERDATA, r->user.len,
284  r->user.data);
285  }
286 
287  if (!list_empty(&r->expr_list)) {
288  nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
289  list_for_each_entry(expr, &r->expr_list, head) {
290  nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
291  nftnl_expr_build_payload(nlh, expr);
292  mnl_attr_nest_end(nlh, nest2);
293  }
294  mnl_attr_nest_end(nlh, nest);
295  }
296 
297  if (r->flags & (1 << NFTNL_RULE_COMPAT_PROTO) &&
298  r->flags & (1 << NFTNL_RULE_COMPAT_FLAGS)) {
299 
300  nest = mnl_attr_nest_start(nlh, NFTA_RULE_COMPAT);
301  mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_PROTO,
302  htonl(r->compat.proto));
303  mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_FLAGS,
304  htonl(r->compat.flags));
305  mnl_attr_nest_end(nlh, nest);
306  }
307  if (r->flags & (1 << NFTNL_RULE_ID))
308  mnl_attr_put_u32(nlh, NFTA_RULE_ID, htonl(r->id));
309  if (r->flags & (1 << NFTNL_RULE_POSITION_ID))
310  mnl_attr_put_u32(nlh, NFTA_RULE_POSITION_ID, htonl(r->position_id));
311 }
312 
313 EXPORT_SYMBOL(nftnl_rule_add_expr);
314 void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr)
315 {
316  list_add_tail(&expr->head, &r->expr_list);
317 }
318 
319 EXPORT_SYMBOL(nftnl_rule_del_expr);
320 void nftnl_rule_del_expr(struct nftnl_expr *expr)
321 {
322  list_del(&expr->head);
323 }
324 
325 static int nftnl_rule_parse_attr_cb(const struct nlattr *attr, void *data)
326 {
327  const struct nlattr **tb = data;
328  int type = mnl_attr_get_type(attr);
329 
330  if (mnl_attr_type_valid(attr, NFTA_RULE_MAX) < 0)
331  return MNL_CB_OK;
332 
333  switch(type) {
334  case NFTA_RULE_TABLE:
335  case NFTA_RULE_CHAIN:
336  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
337  abi_breakage();
338  break;
339  case NFTA_RULE_HANDLE:
340  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
341  abi_breakage();
342  break;
343  case NFTA_RULE_COMPAT:
344  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
345  abi_breakage();
346  break;
347  case NFTA_RULE_POSITION:
348  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
349  abi_breakage();
350  break;
351  case NFTA_RULE_USERDATA:
352  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
353  abi_breakage();
354  break;
355  case NFTA_RULE_ID:
356  case NFTA_RULE_POSITION_ID:
357  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
358  abi_breakage();
359  break;
360  }
361 
362  tb[type] = attr;
363  return MNL_CB_OK;
364 }
365 
366 static int nftnl_rule_parse_expr(struct nlattr *nest, struct nftnl_rule *r)
367 {
368  struct nftnl_expr *expr;
369  struct nlattr *attr;
370 
371  mnl_attr_for_each_nested(attr, nest) {
372  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
373  return -1;
374 
375  expr = nftnl_expr_parse(attr);
376  if (expr == NULL)
377  return -1;
378 
379  list_add_tail(&expr->head, &r->expr_list);
380  }
381  return 0;
382 }
383 
384 static int nftnl_rule_parse_compat_cb(const struct nlattr *attr, void *data)
385 {
386  const struct nlattr **tb = data;
387  int type = mnl_attr_get_type(attr);
388 
389  if (mnl_attr_type_valid(attr, NFTA_RULE_COMPAT_MAX) < 0)
390  return MNL_CB_OK;
391 
392  switch(type) {
393  case NFTA_RULE_COMPAT_PROTO:
394  case NFTA_RULE_COMPAT_FLAGS:
395  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
396  abi_breakage();
397  break;
398  }
399 
400  tb[type] = attr;
401  return MNL_CB_OK;
402 }
403 
404 static int nftnl_rule_parse_compat(struct nlattr *nest, struct nftnl_rule *r)
405 {
406  struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1] = {};
407 
408  if (mnl_attr_parse_nested(nest, nftnl_rule_parse_compat_cb, tb) < 0)
409  return -1;
410 
411  if (tb[NFTA_RULE_COMPAT_PROTO]) {
412  r->compat.proto =
413  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_PROTO]));
414  r->flags |= (1 << NFTNL_RULE_COMPAT_PROTO);
415  }
416  if (tb[NFTA_RULE_COMPAT_FLAGS]) {
417  r->compat.flags =
418  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_FLAGS]));
419  r->flags |= (1 << NFTNL_RULE_COMPAT_FLAGS);
420  }
421  return 0;
422 }
423 
424 EXPORT_SYMBOL(nftnl_rule_nlmsg_parse);
425 int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_rule *r)
426 {
427  struct nlattr *tb[NFTA_RULE_MAX+1] = {};
428  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
429  int ret;
430 
431  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_rule_parse_attr_cb, tb) < 0)
432  return -1;
433 
434  if (nftnl_parse_str_attr(tb[NFTA_RULE_TABLE], NFTNL_RULE_TABLE,
435  &r->table, &r->flags) < 0)
436  return -1;
437  if (nftnl_parse_str_attr(tb[NFTA_RULE_CHAIN], NFTNL_RULE_CHAIN,
438  &r->chain, &r->flags) < 0)
439  return -1;
440  if (tb[NFTA_RULE_HANDLE]) {
441  r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
442  r->flags |= (1 << NFTNL_RULE_HANDLE);
443  }
444  if (tb[NFTA_RULE_EXPRESSIONS]) {
445  ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
446  if (ret < 0)
447  return ret;
448  }
449  if (tb[NFTA_RULE_COMPAT]) {
450  ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
451  if (ret < 0)
452  return ret;
453  }
454  if (tb[NFTA_RULE_POSITION]) {
455  r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
456  r->flags |= (1 << NFTNL_RULE_POSITION);
457  }
458  if (tb[NFTA_RULE_USERDATA]) {
459  const void *udata =
460  mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
461 
462  if (r->flags & (1 << NFTNL_RULE_USERDATA))
463  xfree(r->user.data);
464 
465  r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
466 
467  r->user.data = malloc(r->user.len);
468  if (r->user.data == NULL)
469  return -1;
470 
471  memcpy(r->user.data, udata, r->user.len);
472  r->flags |= (1 << NFTNL_RULE_USERDATA);
473  }
474  if (tb[NFTA_RULE_ID]) {
475  r->id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_ID]));
476  r->flags |= (1 << NFTNL_RULE_ID);
477  }
478  if (tb[NFTA_RULE_POSITION_ID]) {
479  r->position_id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_POSITION_ID]));
480  r->flags |= (1 << NFTNL_RULE_POSITION_ID);
481  }
482 
483  r->family = nfg->nfgen_family;
484  r->flags |= (1 << NFTNL_RULE_FAMILY);
485 
486  return 0;
487 }
488 
489 EXPORT_SYMBOL(nftnl_rule_parse);
490 int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
491  const char *data, struct nftnl_parse_err *err)
492 {
493  errno = EOPNOTSUPP;
494 
495  return -1;
496 }
497 
498 EXPORT_SYMBOL(nftnl_rule_parse_file);
499 int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
500  FILE *fp, struct nftnl_parse_err *err)
501 {
502  errno = EOPNOTSUPP;
503 
504  return -1;
505 }
506 
507 static int nftnl_rule_snprintf_default(char *buf, size_t remain,
508  const struct nftnl_rule *r,
509  uint32_t type, uint32_t flags)
510 {
511  struct nftnl_expr *expr;
512  int ret, offset = 0, i;
513  const char *sep = "";
514 
515  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
516  ret = snprintf(buf + offset, remain, "%s%s", sep,
517  nftnl_family2str(r->family));
518  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
519  sep = " ";
520  }
521 
522  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
523  ret = snprintf(buf + offset, remain, "%s%s", sep,
524  r->table);
525  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
526  sep = " ";
527  }
528 
529  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
530  ret = snprintf(buf + offset, remain, "%s%s", sep,
531  r->chain);
532  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
533  sep = " ";
534  }
535  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
536  ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
537  r->handle);
538  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
539  sep = " ";
540  }
541 
542  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
543  ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
544  r->position);
545  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
546  sep = " ";
547  }
548 
549  if (r->flags & (1 << NFTNL_RULE_ID)) {
550  ret = snprintf(buf + offset, remain, "%s%u", sep, r->id);
551  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
552  sep = " ";
553  }
554 
555  if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
556  ret = snprintf(buf + offset, remain, "%s%u", sep,
557  r->position_id);
558  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
559  sep = " ";
560  }
561 
562  list_for_each_entry(expr, &r->expr_list, head) {
563  ret = snprintf(buf + offset, remain,
564  "\n [ %s ", expr->ops->name);
565  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
566 
567  ret = nftnl_expr_snprintf(buf + offset, remain, expr,
568  type, flags);
569  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
570 
571  ret = snprintf(buf + offset, remain, "]");
572  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
573  }
574 
575  if (r->user.len) {
576  ret = snprintf(buf + offset, remain, "\n userdata = { ");
577  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
578 
579  for (i = 0; i < r->user.len; i++) {
580  char *c = r->user.data;
581 
582  ret = snprintf(buf + offset, remain,
583  isprint(c[i]) ? "%c" : "\\x%02hhx",
584  c[i]);
585  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
586  }
587 
588  ret = snprintf(buf + offset, remain, " }");
589  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
590 
591  }
592 
593  return offset;
594 }
595 
596 static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
597  const struct nftnl_rule *r, uint32_t cmd,
598  uint32_t type, uint32_t flags)
599 {
600  uint32_t inner_flags = flags;
601  int ret, offset = 0;
602 
603  inner_flags &= ~NFTNL_OF_EVENT_ANY;
604 
605  if (type != NFTNL_OUTPUT_DEFAULT)
606  return -1;
607 
608  ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
609  inner_flags);
610  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
611  return offset;
612 }
613 
614 EXPORT_SYMBOL(nftnl_rule_snprintf);
615 int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
616  uint32_t type, uint32_t flags)
617 {
618  if (size)
619  buf[0] = '\0';
620 
621  return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
622  flags);
623 }
624 
625 static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
626  uint32_t cmd, uint32_t type, uint32_t flags)
627 {
628  return nftnl_rule_snprintf(buf, size, r, type, flags);
629 }
630 
631 EXPORT_SYMBOL(nftnl_rule_fprintf);
632 int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
633  uint32_t flags)
634 {
635  return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
636  nftnl_rule_do_snprintf);
637 }
638 
639 EXPORT_SYMBOL(nftnl_expr_foreach);
640 int nftnl_expr_foreach(struct nftnl_rule *r,
641  int (*cb)(struct nftnl_expr *e, void *data),
642  void *data)
643 {
644  struct nftnl_expr *cur, *tmp;
645  int ret;
646 
647  list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
648  ret = cb(cur, data);
649  if (ret < 0)
650  return ret;
651  }
652  return 0;
653 }
654 
656  const struct nftnl_rule *r;
657  struct nftnl_expr *cur;
658 };
659 
660 static void nftnl_expr_iter_init(const struct nftnl_rule *r,
661  struct nftnl_expr_iter *iter)
662 {
663  iter->r = r;
664  if (list_empty(&r->expr_list))
665  iter->cur = NULL;
666  else
667  iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
668  head);
669 }
670 
671 EXPORT_SYMBOL(nftnl_expr_iter_create);
672 struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
673 {
674  struct nftnl_expr_iter *iter;
675 
676  iter = calloc(1, sizeof(struct nftnl_expr_iter));
677  if (iter == NULL)
678  return NULL;
679 
680  nftnl_expr_iter_init(r, iter);
681 
682  return iter;
683 }
684 
685 EXPORT_SYMBOL(nftnl_expr_iter_next);
686 struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
687 {
688  struct nftnl_expr *expr = iter->cur;
689 
690  if (expr == NULL)
691  return NULL;
692 
693  /* get next expression, if any */
694  iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
695  if (&iter->cur->head == iter->r->expr_list.next)
696  return NULL;
697 
698  return expr;
699 }
700 
701 EXPORT_SYMBOL(nftnl_expr_iter_destroy);
702 void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
703 {
704  xfree(iter);
705 }
706 
708  struct list_head list;
709 };
710 
711 EXPORT_SYMBOL(nftnl_rule_list_alloc);
712 struct nftnl_rule_list *nftnl_rule_list_alloc(void)
713 {
714  struct nftnl_rule_list *list;
715 
716  list = calloc(1, sizeof(struct nftnl_rule_list));
717  if (list == NULL)
718  return NULL;
719 
720  INIT_LIST_HEAD(&list->list);
721 
722  return list;
723 }
724 
725 EXPORT_SYMBOL(nftnl_rule_list_free);
726 void nftnl_rule_list_free(struct nftnl_rule_list *list)
727 {
728  struct nftnl_rule *r, *tmp;
729 
730  list_for_each_entry_safe(r, tmp, &list->list, head) {
731  list_del(&r->head);
732  nftnl_rule_free(r);
733  }
734  xfree(list);
735 }
736 
737 EXPORT_SYMBOL(nftnl_rule_list_is_empty);
738 int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
739 {
740  return list_empty(&list->list);
741 }
742 
743 EXPORT_SYMBOL(nftnl_rule_list_add);
744 void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
745 {
746  list_add(&r->head, &list->list);
747 }
748 
749 EXPORT_SYMBOL(nftnl_rule_list_insert_at);
750 void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
751 {
752  list_add(&r->head, &pos->head);
753 }
754 
755 EXPORT_SYMBOL(nftnl_rule_list_add_tail);
756 void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
757 {
758  list_add_tail(&r->head, &list->list);
759 }
760 
761 EXPORT_SYMBOL(nftnl_rule_list_del);
762 void nftnl_rule_list_del(struct nftnl_rule *r)
763 {
764  list_del(&r->head);
765 }
766 
767 EXPORT_SYMBOL(nftnl_rule_list_foreach);
768 int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
769  int (*cb)(struct nftnl_rule *r, void *data),
770  void *data)
771 {
772  struct nftnl_rule *cur, *tmp;
773  int ret;
774 
775  list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
776  ret = cb(cur, data);
777  if (ret < 0)
778  return ret;
779  }
780  return 0;
781 }
782 
784  const struct nftnl_rule_list *list;
785  struct nftnl_rule *cur;
786 };
787 
788 EXPORT_SYMBOL(nftnl_rule_list_iter_create);
789 struct nftnl_rule_list_iter *
790 nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
791 {
792  struct nftnl_rule_list_iter *iter;
793 
794  iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
795  if (iter == NULL)
796  return NULL;
797 
798  iter->list = l;
799  if (nftnl_rule_list_is_empty(l))
800  iter->cur = NULL;
801  else
802  iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
803 
804  return iter;
805 }
806 
807 EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
808 struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
809 {
810  return iter->cur;
811 }
812 
813 EXPORT_SYMBOL(nftnl_rule_list_iter_next);
814 struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
815 {
816  struct nftnl_rule *r = iter->cur;
817 
818  if (r == NULL)
819  return NULL;
820 
821  /* get next rule, if any */
822  iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
823  if (&iter->cur->head == iter->list->list.next)
824  return NULL;
825 
826  return r;
827 }
828 
829 EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
830 void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
831 {
832  xfree(iter);
833 }