libnftnl  1.2.9
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 (tb[NFTA_RULE_TABLE]) {
435  if (r->flags & (1 << NFTNL_RULE_TABLE))
436  xfree(r->table);
437  r->table = strdup(mnl_attr_get_str(tb[NFTA_RULE_TABLE]));
438  if (!r->table)
439  return -1;
440  r->flags |= (1 << NFTNL_RULE_TABLE);
441  }
442  if (tb[NFTA_RULE_CHAIN]) {
443  if (r->flags & (1 << NFTNL_RULE_CHAIN))
444  xfree(r->chain);
445  r->chain = strdup(mnl_attr_get_str(tb[NFTA_RULE_CHAIN]));
446  if (!r->chain)
447  return -1;
448  r->flags |= (1 << NFTNL_RULE_CHAIN);
449  }
450  if (tb[NFTA_RULE_HANDLE]) {
451  r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
452  r->flags |= (1 << NFTNL_RULE_HANDLE);
453  }
454  if (tb[NFTA_RULE_EXPRESSIONS]) {
455  ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
456  if (ret < 0)
457  return ret;
458  }
459  if (tb[NFTA_RULE_COMPAT]) {
460  ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
461  if (ret < 0)
462  return ret;
463  }
464  if (tb[NFTA_RULE_POSITION]) {
465  r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
466  r->flags |= (1 << NFTNL_RULE_POSITION);
467  }
468  if (tb[NFTA_RULE_USERDATA]) {
469  const void *udata =
470  mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
471 
472  if (r->flags & (1 << NFTNL_RULE_USERDATA))
473  xfree(r->user.data);
474 
475  r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
476 
477  r->user.data = malloc(r->user.len);
478  if (r->user.data == NULL)
479  return -1;
480 
481  memcpy(r->user.data, udata, r->user.len);
482  r->flags |= (1 << NFTNL_RULE_USERDATA);
483  }
484  if (tb[NFTA_RULE_ID]) {
485  r->id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_ID]));
486  r->flags |= (1 << NFTNL_RULE_ID);
487  }
488  if (tb[NFTA_RULE_POSITION_ID]) {
489  r->position_id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_POSITION_ID]));
490  r->flags |= (1 << NFTNL_RULE_POSITION_ID);
491  }
492 
493  r->family = nfg->nfgen_family;
494  r->flags |= (1 << NFTNL_RULE_FAMILY);
495 
496  return 0;
497 }
498 
499 EXPORT_SYMBOL(nftnl_rule_parse);
500 int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
501  const char *data, struct nftnl_parse_err *err)
502 {
503  errno = EOPNOTSUPP;
504 
505  return -1;
506 }
507 
508 EXPORT_SYMBOL(nftnl_rule_parse_file);
509 int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
510  FILE *fp, struct nftnl_parse_err *err)
511 {
512  errno = EOPNOTSUPP;
513 
514  return -1;
515 }
516 
517 static int nftnl_rule_snprintf_default(char *buf, size_t remain,
518  const struct nftnl_rule *r,
519  uint32_t type, uint32_t flags)
520 {
521  struct nftnl_expr *expr;
522  int ret, offset = 0, i;
523  const char *sep = "";
524 
525  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
526  ret = snprintf(buf + offset, remain, "%s%s", sep,
527  nftnl_family2str(r->family));
528  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
529  sep = " ";
530  }
531 
532  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
533  ret = snprintf(buf + offset, remain, "%s%s", sep,
534  r->table);
535  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
536  sep = " ";
537  }
538 
539  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
540  ret = snprintf(buf + offset, remain, "%s%s", sep,
541  r->chain);
542  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
543  sep = " ";
544  }
545  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
546  ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
547  r->handle);
548  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
549  sep = " ";
550  }
551 
552  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
553  ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
554  r->position);
555  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
556  sep = " ";
557  }
558 
559  if (r->flags & (1 << NFTNL_RULE_ID)) {
560  ret = snprintf(buf + offset, remain, "%s%u", sep, r->id);
561  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
562  sep = " ";
563  }
564 
565  if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
566  ret = snprintf(buf + offset, remain, "%s%u", sep,
567  r->position_id);
568  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
569  sep = " ";
570  }
571 
572  list_for_each_entry(expr, &r->expr_list, head) {
573  ret = snprintf(buf + offset, remain,
574  "\n [ %s ", expr->ops->name);
575  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
576 
577  ret = nftnl_expr_snprintf(buf + offset, remain, expr,
578  type, flags);
579  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
580 
581  ret = snprintf(buf + offset, remain, "]");
582  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
583  }
584 
585  if (r->user.len) {
586  ret = snprintf(buf + offset, remain, "\n userdata = { ");
587  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
588 
589  for (i = 0; i < r->user.len; i++) {
590  char *c = r->user.data;
591 
592  ret = snprintf(buf + offset, remain,
593  isprint(c[i]) ? "%c" : "\\x%02hhx",
594  c[i]);
595  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
596  }
597 
598  ret = snprintf(buf + offset, remain, " }");
599  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
600 
601  }
602 
603  return offset;
604 }
605 
606 static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
607  const struct nftnl_rule *r, uint32_t cmd,
608  uint32_t type, uint32_t flags)
609 {
610  uint32_t inner_flags = flags;
611  int ret, offset = 0;
612 
613  inner_flags &= ~NFTNL_OF_EVENT_ANY;
614 
615  if (type != NFTNL_OUTPUT_DEFAULT)
616  return -1;
617 
618  ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
619  inner_flags);
620  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
621  return offset;
622 }
623 
624 EXPORT_SYMBOL(nftnl_rule_snprintf);
625 int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
626  uint32_t type, uint32_t flags)
627 {
628  if (size)
629  buf[0] = '\0';
630 
631  return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
632  flags);
633 }
634 
635 static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
636  uint32_t cmd, uint32_t type, uint32_t flags)
637 {
638  return nftnl_rule_snprintf(buf, size, r, type, flags);
639 }
640 
641 EXPORT_SYMBOL(nftnl_rule_fprintf);
642 int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
643  uint32_t flags)
644 {
645  return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
646  nftnl_rule_do_snprintf);
647 }
648 
649 EXPORT_SYMBOL(nftnl_expr_foreach);
650 int nftnl_expr_foreach(struct nftnl_rule *r,
651  int (*cb)(struct nftnl_expr *e, void *data),
652  void *data)
653 {
654  struct nftnl_expr *cur, *tmp;
655  int ret;
656 
657  list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
658  ret = cb(cur, data);
659  if (ret < 0)
660  return ret;
661  }
662  return 0;
663 }
664 
666  const struct nftnl_rule *r;
667  struct nftnl_expr *cur;
668 };
669 
670 static void nftnl_expr_iter_init(const struct nftnl_rule *r,
671  struct nftnl_expr_iter *iter)
672 {
673  iter->r = r;
674  if (list_empty(&r->expr_list))
675  iter->cur = NULL;
676  else
677  iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
678  head);
679 }
680 
681 EXPORT_SYMBOL(nftnl_expr_iter_create);
682 struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
683 {
684  struct nftnl_expr_iter *iter;
685 
686  iter = calloc(1, sizeof(struct nftnl_expr_iter));
687  if (iter == NULL)
688  return NULL;
689 
690  nftnl_expr_iter_init(r, iter);
691 
692  return iter;
693 }
694 
695 EXPORT_SYMBOL(nftnl_expr_iter_next);
696 struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
697 {
698  struct nftnl_expr *expr = iter->cur;
699 
700  if (expr == NULL)
701  return NULL;
702 
703  /* get next expression, if any */
704  iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
705  if (&iter->cur->head == iter->r->expr_list.next)
706  return NULL;
707 
708  return expr;
709 }
710 
711 EXPORT_SYMBOL(nftnl_expr_iter_destroy);
712 void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
713 {
714  xfree(iter);
715 }
716 
718  struct list_head list;
719 };
720 
721 EXPORT_SYMBOL(nftnl_rule_list_alloc);
722 struct nftnl_rule_list *nftnl_rule_list_alloc(void)
723 {
724  struct nftnl_rule_list *list;
725 
726  list = calloc(1, sizeof(struct nftnl_rule_list));
727  if (list == NULL)
728  return NULL;
729 
730  INIT_LIST_HEAD(&list->list);
731 
732  return list;
733 }
734 
735 EXPORT_SYMBOL(nftnl_rule_list_free);
736 void nftnl_rule_list_free(struct nftnl_rule_list *list)
737 {
738  struct nftnl_rule *r, *tmp;
739 
740  list_for_each_entry_safe(r, tmp, &list->list, head) {
741  list_del(&r->head);
742  nftnl_rule_free(r);
743  }
744  xfree(list);
745 }
746 
747 EXPORT_SYMBOL(nftnl_rule_list_is_empty);
748 int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
749 {
750  return list_empty(&list->list);
751 }
752 
753 EXPORT_SYMBOL(nftnl_rule_list_add);
754 void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
755 {
756  list_add(&r->head, &list->list);
757 }
758 
759 EXPORT_SYMBOL(nftnl_rule_list_insert_at);
760 void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
761 {
762  list_add(&r->head, &pos->head);
763 }
764 
765 EXPORT_SYMBOL(nftnl_rule_list_add_tail);
766 void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
767 {
768  list_add_tail(&r->head, &list->list);
769 }
770 
771 EXPORT_SYMBOL(nftnl_rule_list_del);
772 void nftnl_rule_list_del(struct nftnl_rule *r)
773 {
774  list_del(&r->head);
775 }
776 
777 EXPORT_SYMBOL(nftnl_rule_list_foreach);
778 int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
779  int (*cb)(struct nftnl_rule *r, void *data),
780  void *data)
781 {
782  struct nftnl_rule *cur, *tmp;
783  int ret;
784 
785  list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
786  ret = cb(cur, data);
787  if (ret < 0)
788  return ret;
789  }
790  return 0;
791 }
792 
794  const struct nftnl_rule_list *list;
795  struct nftnl_rule *cur;
796 };
797 
798 EXPORT_SYMBOL(nftnl_rule_list_iter_create);
799 struct nftnl_rule_list_iter *
800 nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
801 {
802  struct nftnl_rule_list_iter *iter;
803 
804  iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
805  if (iter == NULL)
806  return NULL;
807 
808  iter->list = l;
809  if (nftnl_rule_list_is_empty(l))
810  iter->cur = NULL;
811  else
812  iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
813 
814  return iter;
815 }
816 
817 EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
818 struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
819 {
820  return iter->cur;
821 }
822 
823 EXPORT_SYMBOL(nftnl_rule_list_iter_next);
824 struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
825 {
826  struct nftnl_rule *r = iter->cur;
827 
828  if (r == NULL)
829  return NULL;
830 
831  /* get next rule, if any */
832  iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
833  if (&iter->cur->head == iter->list->list.next)
834  return NULL;
835 
836  return r;
837 }
838 
839 EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
840 void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
841 {
842  xfree(iter);
843 }