libnftnl  1.0.5
rule.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 #include <ctype.h>
23 
24 #include <libmnl/libmnl.h>
25 #include <linux/netfilter/nfnetlink.h>
26 #include <linux/netfilter/nf_tables.h>
27 
28 #include <libnftnl/rule.h>
29 #include <libnftnl/set.h>
30 #include <libnftnl/expr.h>
31 
32 struct nftnl_rule {
33  struct list_head head;
34 
35  uint32_t flags;
36  uint32_t family;
37  const char *table;
38  const char *chain;
39  uint64_t handle;
40  uint64_t position;
41  struct {
42  void *data;
43  uint32_t len;
44  } user;
45  struct {
46  uint32_t flags;
47  uint32_t proto;
48  } compat;
49 
50  struct list_head expr_list;
51 };
52 
53 struct nftnl_rule *nftnl_rule_alloc(void)
54 {
55  struct nftnl_rule *r;
56 
57  r = calloc(1, sizeof(struct nftnl_rule));
58  if (r == NULL)
59  return NULL;
60 
61  INIT_LIST_HEAD(&r->expr_list);
62 
63  return r;
64 }
65 EXPORT_SYMBOL(nftnl_rule_alloc, nft_rule_alloc);
66 
67 void nftnl_rule_free(struct nftnl_rule *r)
68 {
69  struct nftnl_expr *e, *tmp;
70 
71  list_for_each_entry_safe(e, tmp, &r->expr_list, head)
72  nftnl_expr_free(e);
73 
74  if (r->table != NULL)
75  xfree(r->table);
76  if (r->chain != NULL)
77  xfree(r->chain);
78 
79  xfree(r);
80 }
81 EXPORT_SYMBOL(nftnl_rule_free, nft_rule_free);
82 
83 bool nftnl_rule_is_set(const struct nftnl_rule *r, uint16_t attr)
84 {
85  return r->flags & (1 << attr);
86 }
87 EXPORT_SYMBOL(nftnl_rule_is_set, nft_rule_attr_is_set);
88 
89 void nftnl_rule_unset(struct nftnl_rule *r, uint16_t attr)
90 {
91  if (!(r->flags & (1 << attr)))
92  return;
93 
94  switch (attr) {
95  case NFTNL_RULE_TABLE:
96  if (r->table) {
97  xfree(r->table);
98  r->table = NULL;
99  }
100  break;
101  case NFTNL_RULE_CHAIN:
102  if (r->chain) {
103  xfree(r->chain);
104  r->chain = NULL;
105  }
106  break;
107  case NFTNL_RULE_HANDLE:
108  case NFTNL_RULE_COMPAT_PROTO:
109  case NFTNL_RULE_COMPAT_FLAGS:
110  case NFTNL_RULE_POSITION:
111  case NFTNL_RULE_FAMILY:
112  case NFTNL_RULE_USERDATA:
113  break;
114  }
115 
116  r->flags &= ~(1 << attr);
117 }
118 EXPORT_SYMBOL(nftnl_rule_unset, nft_rule_attr_unset);
119 
120 static uint32_t nftnl_rule_validate[NFTNL_RULE_MAX + 1] = {
121  [NFTNL_RULE_HANDLE] = sizeof(uint64_t),
122  [NFTNL_RULE_COMPAT_PROTO] = sizeof(uint32_t),
123  [NFTNL_RULE_COMPAT_FLAGS] = sizeof(uint32_t),
124  [NFTNL_RULE_FAMILY] = sizeof(uint32_t),
125  [NFTNL_RULE_POSITION] = sizeof(uint64_t),
126 };
127 
128 void nftnl_rule_set_data(struct nftnl_rule *r, uint16_t attr,
129  const void *data, uint32_t data_len)
130 {
131  if (attr > NFTNL_RULE_MAX)
132  return;
133 
134  nftnl_assert_validate(data, nftnl_rule_validate, attr, data_len);
135 
136  switch(attr) {
137  case NFTNL_RULE_TABLE:
138  if (r->table)
139  xfree(r->table);
140 
141  r->table = strdup(data);
142  break;
143  case NFTNL_RULE_CHAIN:
144  if (r->chain)
145  xfree(r->chain);
146 
147  r->chain = strdup(data);
148  break;
149  case NFTNL_RULE_HANDLE:
150  r->handle = *((uint64_t *)data);
151  break;
152  case NFTNL_RULE_COMPAT_PROTO:
153  r->compat.proto = *((uint32_t *)data);
154  break;
155  case NFTNL_RULE_COMPAT_FLAGS:
156  r->compat.flags = *((uint32_t *)data);
157  break;
158  case NFTNL_RULE_FAMILY:
159  r->family = *((uint32_t *)data);
160  break;
161  case NFTNL_RULE_POSITION:
162  r->position = *((uint64_t *)data);
163  break;
164  case NFTNL_RULE_USERDATA:
165  r->user.data = (void *)data;
166  r->user.len = data_len;
167  break;
168  }
169  r->flags |= (1 << attr);
170 }
171 EXPORT_SYMBOL(nftnl_rule_set_data, nft_rule_attr_set_data);
172 
173 void nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data)
174 {
175  nftnl_rule_set_data(r, attr, data, nftnl_rule_validate[attr]);
176 }
177 EXPORT_SYMBOL(nftnl_rule_set, nft_rule_attr_set);
178 
179 void nftnl_rule_set_u32(struct nftnl_rule *r, uint16_t attr, uint32_t val)
180 {
181  nftnl_rule_set_data(r, attr, &val, sizeof(uint32_t));
182 }
183 EXPORT_SYMBOL(nftnl_rule_set_u32, nft_rule_attr_set_u32);
184 
185 void nftnl_rule_set_u64(struct nftnl_rule *r, uint16_t attr, uint64_t val)
186 {
187  nftnl_rule_set_data(r, attr, &val, sizeof(uint64_t));
188 }
189 EXPORT_SYMBOL(nftnl_rule_set_u64, nft_rule_attr_set_u64);
190 
191 void nftnl_rule_set_str(struct nftnl_rule *r, uint16_t attr, const char *str)
192 {
193  nftnl_rule_set_data(r, attr, str, strlen(str));
194 }
195 EXPORT_SYMBOL(nftnl_rule_set_str, nft_rule_attr_set_str);
196 
197 const void *nftnl_rule_get_data(const struct nftnl_rule *r, uint16_t attr,
198  uint32_t *data_len)
199 {
200  if (!(r->flags & (1 << attr)))
201  return NULL;
202 
203  switch(attr) {
204  case NFTNL_RULE_FAMILY:
205  *data_len = sizeof(uint32_t);
206  return &r->family;
207  case NFTNL_RULE_TABLE:
208  return r->table;
209  case NFTNL_RULE_CHAIN:
210  return r->chain;
211  case NFTNL_RULE_HANDLE:
212  *data_len = sizeof(uint64_t);
213  return &r->handle;
214  case NFTNL_RULE_COMPAT_PROTO:
215  *data_len = sizeof(uint32_t);
216  return &r->compat.proto;
217  case NFTNL_RULE_COMPAT_FLAGS:
218  *data_len = sizeof(uint32_t);
219  return &r->compat.flags;
220  case NFTNL_RULE_POSITION:
221  *data_len = sizeof(uint64_t);
222  return &r->position;
223  case NFTNL_RULE_USERDATA:
224  *data_len = r->user.len;
225  return r->user.data;
226  }
227  return NULL;
228 }
229 EXPORT_SYMBOL(nftnl_rule_get_data, nft_rule_attr_get_data);
230 
231 const void *nftnl_rule_get(const struct nftnl_rule *r, uint16_t attr)
232 {
233  uint32_t data_len;
234  return nftnl_rule_get_data(r, attr, &data_len);
235 }
236 EXPORT_SYMBOL(nftnl_rule_get, nft_rule_attr_get);
237 
238 const char *nftnl_rule_get_str(const struct nftnl_rule *r, uint16_t attr)
239 {
240  return nftnl_rule_get(r, attr);
241 }
242 EXPORT_SYMBOL(nftnl_rule_get_str, nft_rule_attr_get_str);
243 
244 uint32_t nftnl_rule_get_u32(const struct nftnl_rule *r, uint16_t attr)
245 {
246  uint32_t data_len;
247  const uint32_t *val = nftnl_rule_get_data(r, attr, &data_len);
248 
249  nftnl_assert(val, attr, data_len == sizeof(uint32_t));
250 
251  return val ? *val : 0;
252 }
253 EXPORT_SYMBOL(nftnl_rule_get_u32, nft_rule_attr_get_u32);
254 
255 uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr)
256 {
257  uint32_t data_len;
258  const uint64_t *val = nftnl_rule_get_data(r, attr, &data_len);
259 
260  nftnl_assert(val, attr, data_len == sizeof(uint64_t));
261 
262  return val ? *val : 0;
263 }
264 EXPORT_SYMBOL(nftnl_rule_get_u64, nft_rule_attr_get_u64);
265 
266 uint8_t nftnl_rule_get_u8(const struct nftnl_rule *r, uint16_t attr)
267 {
268  uint32_t data_len;
269  const uint8_t *val = nftnl_rule_get_data(r, attr, &data_len);
270 
271  nftnl_assert(val, attr, data_len == sizeof(uint8_t));
272 
273  return val ? *val : 0;
274 }
275 EXPORT_SYMBOL(nftnl_rule_get_u8, nft_rule_attr_get_u8);
276 
277 void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *r)
278 {
279  struct nftnl_expr *expr;
280  struct nlattr *nest, *nest2;
281 
282  if (r->flags & (1 << NFTNL_RULE_TABLE))
283  mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, r->table);
284  if (r->flags & (1 << NFTNL_RULE_CHAIN))
285  mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, r->chain);
286  if (r->flags & (1 << NFTNL_RULE_HANDLE))
287  mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(r->handle));
288  if (r->flags & (1 << NFTNL_RULE_POSITION))
289  mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
290  if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
291  mnl_attr_put(nlh, NFTA_RULE_USERDATA, r->user.len,
292  r->user.data);
293  }
294 
295  if (!list_empty(&r->expr_list)) {
296  nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
297  list_for_each_entry(expr, &r->expr_list, head) {
298  nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
299  nftnl_expr_build_payload(nlh, expr);
300  mnl_attr_nest_end(nlh, nest2);
301  }
302  mnl_attr_nest_end(nlh, nest);
303  }
304 
305  if (r->flags & (1 << NFTNL_RULE_COMPAT_PROTO) &&
306  r->flags & (1 << NFTNL_RULE_COMPAT_FLAGS)) {
307 
308  nest = mnl_attr_nest_start(nlh, NFTA_RULE_COMPAT);
309  mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_PROTO,
310  htonl(r->compat.proto));
311  mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_FLAGS,
312  htonl(r->compat.flags));
313  mnl_attr_nest_end(nlh, nest);
314  }
315 }
316 EXPORT_SYMBOL(nftnl_rule_nlmsg_build_payload, nft_rule_nlmsg_build_payload);
317 
318 void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr)
319 {
320  list_add_tail(&expr->head, &r->expr_list);
321 }
322 EXPORT_SYMBOL(nftnl_rule_add_expr, nft_rule_add_expr);
323 
324 static int nftnl_rule_parse_attr_cb(const struct nlattr *attr, void *data)
325 {
326  const struct nlattr **tb = data;
327  int type = mnl_attr_get_type(attr);
328 
329  if (mnl_attr_type_valid(attr, NFTA_RULE_MAX) < 0)
330  return MNL_CB_OK;
331 
332  switch(type) {
333  case NFTA_RULE_TABLE:
334  case NFTA_RULE_CHAIN:
335  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
336  abi_breakage();
337  break;
338  case NFTA_RULE_HANDLE:
339  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
340  abi_breakage();
341  break;
342  case NFTA_RULE_COMPAT:
343  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
344  abi_breakage();
345  break;
346  case NFTA_RULE_POSITION:
347  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
348  abi_breakage();
349  break;
350  case NFTA_RULE_USERDATA:
351  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
352  abi_breakage();
353  break;
354  }
355 
356  tb[type] = attr;
357  return MNL_CB_OK;
358 }
359 
360 static int nftnl_rule_parse_expr(struct nlattr *nest, struct nftnl_rule *r)
361 {
362  struct nftnl_expr *expr;
363  struct nlattr *attr;
364 
365  mnl_attr_for_each_nested(attr, nest) {
366  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
367  return -1;
368 
369  expr = nftnl_expr_parse(attr);
370  if (expr == NULL)
371  return -1;
372 
373  list_add_tail(&expr->head, &r->expr_list);
374  }
375  return 0;
376 }
377 
378 static int nftnl_rule_parse_compat_cb(const struct nlattr *attr, void *data)
379 {
380  const struct nlattr **tb = data;
381  int type = mnl_attr_get_type(attr);
382 
383  if (mnl_attr_type_valid(attr, NFTA_RULE_COMPAT_MAX) < 0)
384  return MNL_CB_OK;
385 
386  switch(type) {
387  case NFTA_RULE_COMPAT_PROTO:
388  case NFTA_RULE_COMPAT_FLAGS:
389  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
390  abi_breakage();
391  break;
392  }
393 
394  tb[type] = attr;
395  return MNL_CB_OK;
396 }
397 
398 static int nftnl_rule_parse_compat(struct nlattr *nest, struct nftnl_rule *r)
399 {
400  struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1] = {};
401 
402  if (mnl_attr_parse_nested(nest, nftnl_rule_parse_compat_cb, tb) < 0)
403  return -1;
404 
405  if (tb[NFTA_RULE_COMPAT_PROTO]) {
406  r->compat.proto =
407  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_PROTO]));
408  r->flags |= (1 << NFTNL_RULE_COMPAT_PROTO);
409  }
410  if (tb[NFTA_RULE_COMPAT_FLAGS]) {
411  r->compat.flags =
412  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_FLAGS]));
413  r->flags |= (1 << NFTNL_RULE_COMPAT_FLAGS);
414  }
415  return 0;
416 }
417 
418 int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_rule *r)
419 {
420  struct nlattr *tb[NFTA_RULE_MAX+1] = {};
421  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
422  int ret = 0;
423 
424  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_rule_parse_attr_cb, tb) < 0)
425  return -1;
426 
427  if (tb[NFTA_RULE_TABLE]) {
428  xfree(r->table);
429  r->table = strdup(mnl_attr_get_str(tb[NFTA_RULE_TABLE]));
430  r->flags |= (1 << NFTNL_RULE_TABLE);
431  }
432  if (tb[NFTA_RULE_CHAIN]) {
433  xfree(r->chain);
434  r->chain = strdup(mnl_attr_get_str(tb[NFTA_RULE_CHAIN]));
435  r->flags |= (1 << NFTNL_RULE_CHAIN);
436  }
437  if (tb[NFTA_RULE_HANDLE]) {
438  r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
439  r->flags |= (1 << NFTNL_RULE_HANDLE);
440  }
441  if (tb[NFTA_RULE_EXPRESSIONS])
442  ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
443  if (tb[NFTA_RULE_COMPAT])
444  ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
445  if (tb[NFTA_RULE_POSITION]) {
446  r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
447  r->flags |= (1 << NFTNL_RULE_POSITION);
448  }
449  if (tb[NFTA_RULE_USERDATA]) {
450  const void *udata =
451  mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
452 
453  if (r->user.data)
454  xfree(r->user.data);
455 
456  r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
457 
458  r->user.data = malloc(r->user.len);
459  if (r->user.data == NULL)
460  return -1;
461 
462  memcpy(r->user.data, udata, r->user.len);
463  r->flags |= (1 << NFTNL_RULE_USERDATA);
464  }
465 
466  r->family = nfg->nfgen_family;
467  r->flags |= (1 << NFTNL_RULE_FAMILY);
468 
469  return ret;
470 }
471 EXPORT_SYMBOL(nftnl_rule_nlmsg_parse, nft_rule_nlmsg_parse);
472 
473 #ifdef JSON_PARSING
474 int nftnl_jansson_parse_rule(struct nftnl_rule *r, json_t *tree,
475  struct nftnl_parse_err *err,
476  struct nftnl_set_list *set_list)
477 {
478  json_t *root, *array;
479  struct nftnl_expr *e;
480  const char *str = NULL;
481  uint64_t uval64;
482  uint32_t uval32;
483  int i, family;
484 
485  root = nftnl_jansson_get_node(tree, "rule", err);
486  if (root == NULL)
487  return -1;
488 
489  if (nftnl_jansson_node_exist(root, "family")) {
490  if (nftnl_jansson_parse_family(root, &family, err) != 0)
491  goto err;
492 
493  nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
494  }
495 
496  if (nftnl_jansson_node_exist(root, "table")) {
497  str = nftnl_jansson_parse_str(root, "table", err);
498  if (str == NULL)
499  goto err;
500 
501  nftnl_rule_set_str(r, NFTNL_RULE_TABLE, str);
502  }
503 
504  if (nftnl_jansson_node_exist(root, "chain")) {
505  str = nftnl_jansson_parse_str(root, "chain", err);
506  if (str == NULL)
507  goto err;
508 
509  nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, str);
510  }
511 
512  if (nftnl_jansson_node_exist(root, "handle")) {
513  if (nftnl_jansson_parse_val(root, "handle", NFTNL_TYPE_U64, &uval64,
514  err) < 0)
515  goto err;
516 
517  nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, uval64);
518  }
519 
520  if (nftnl_jansson_node_exist(root, "compat_proto") ||
521  nftnl_jansson_node_exist(root, "compat_flags")) {
522  if (nftnl_jansson_parse_val(root, "compat_proto", NFTNL_TYPE_U32,
523  &uval32, err) < 0)
524  goto err;
525 
526  nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, uval32);
527 
528  if (nftnl_jansson_parse_val(root, "compat_flags", NFTNL_TYPE_U32,
529  &uval32, err) < 0)
530  goto err;
531 
532  nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS, uval32);
533  }
534 
535  if (nftnl_jansson_node_exist(root, "position")) {
536  if (nftnl_jansson_parse_val(root, "position", NFTNL_TYPE_U64,
537  &uval64, err) < 0)
538  goto err;
539 
540  nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, uval64);
541  }
542 
543  array = json_object_get(root, "expr");
544  if (array == NULL) {
545  err->error = NFTNL_PARSE_EMISSINGNODE;
546  err->node_name = "expr";
547  goto err;
548  }
549 
550  for (i = 0; i < json_array_size(array); ++i) {
551 
552  e = nftnl_jansson_expr_parse(json_array_get(array, i), err,
553  set_list);
554  if (e == NULL)
555  goto err;
556 
557  nftnl_rule_add_expr(r, e);
558  }
559 
560  return 0;
561 err:
562  return -1;
563 }
564 #endif
565 
566 static int nftnl_rule_json_parse(struct nftnl_rule *r, const void *json,
567  struct nftnl_parse_err *err,
568  enum nftnl_parse_input input,
569  struct nftnl_set_list *set_list)
570 {
571 #ifdef JSON_PARSING
572  json_t *tree;
573  json_error_t error;
574  int ret;
575 
576  tree = nftnl_jansson_create_root(json, &error, err, input);
577  if (tree == NULL)
578  return -1;
579 
580  ret = nftnl_jansson_parse_rule(r, tree, err, set_list);
581 
582  nftnl_jansson_free_root(tree);
583  return ret;
584 #else
585  errno = EOPNOTSUPP;
586  return -1;
587 #endif
588 }
589 
590 #ifdef XML_PARSING
591 int nftnl_mxml_rule_parse(mxml_node_t *tree, struct nftnl_rule *r,
592  struct nftnl_parse_err *err,
593  struct nftnl_set_list *set_list)
594 {
595  mxml_node_t *node;
596  struct nftnl_expr *e;
597  const char *table, *chain;
598  int family;
599 
600  family = nftnl_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
601  NFTNL_XML_MAND, err);
602  if (family >= 0)
603  nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
604 
605  table = nftnl_mxml_str_parse(tree, "table", MXML_DESCEND_FIRST,
606  NFTNL_XML_MAND, err);
607  if (table != NULL)
608  nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
609 
610  chain = nftnl_mxml_str_parse(tree, "chain", MXML_DESCEND_FIRST,
611  NFTNL_XML_MAND, err);
612  if (chain != NULL)
613  nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
614 
615  if (nftnl_mxml_num_parse(tree, "handle", MXML_DESCEND_FIRST, BASE_DEC,
616  &r->handle, NFTNL_TYPE_U64, NFTNL_XML_MAND, err) >= 0)
617  r->flags |= (1 << NFTNL_RULE_HANDLE);
618 
619  if (nftnl_mxml_num_parse(tree, "compat_proto", MXML_DESCEND_FIRST,
620  BASE_DEC, &r->compat.proto, NFTNL_TYPE_U32,
621  NFTNL_XML_OPT, err) >= 0)
622  r->flags |= (1 << NFTNL_RULE_COMPAT_PROTO);
623 
624  if (nftnl_mxml_num_parse(tree, "compat_flags", MXML_DESCEND_FIRST,
625  BASE_DEC, &r->compat.flags, NFTNL_TYPE_U32,
626  NFTNL_XML_OPT, err) >= 0)
627  r->flags |= (1 << NFTNL_RULE_COMPAT_FLAGS);
628 
629  if (nftnl_rule_is_set(r, NFTNL_RULE_COMPAT_PROTO) !=
630  nftnl_rule_is_set(r, NFTNL_RULE_COMPAT_FLAGS)) {
631  errno = EINVAL;
632  }
633 
634  if (nftnl_mxml_num_parse(tree, "position", MXML_DESCEND_FIRST,
635  BASE_DEC, &r->position, NFTNL_TYPE_U64,
636  NFTNL_XML_OPT, err) >= 0)
637  r->flags |= (1 << NFTNL_RULE_POSITION);
638 
639  /* Iterating over <expr> */
640  for (node = mxmlFindElement(tree, tree, "expr", "type",
641  NULL, MXML_DESCEND);
642  node != NULL;
643  node = mxmlFindElement(node, tree, "expr", "type",
644  NULL, MXML_DESCEND)) {
645  e = nftnl_mxml_expr_parse(node, err, set_list);
646  if (e == NULL)
647  return -1;
648 
649  nftnl_rule_add_expr(r, e);
650  }
651 
652  return 0;
653 }
654 #endif
655 
656 static int nftnl_rule_xml_parse(struct nftnl_rule *r, const void *xml,
657  struct nftnl_parse_err *err,
658  enum nftnl_parse_input input,
659  struct nftnl_set_list *set_list)
660 {
661 #ifdef XML_PARSING
662  int ret;
663  mxml_node_t *tree = nftnl_mxml_build_tree(xml, "rule", err, input);
664  if (tree == NULL)
665  return -1;
666 
667  ret = nftnl_mxml_rule_parse(tree, r, err, set_list);
668  mxmlDelete(tree);
669  return ret;
670 #else
671  errno = EOPNOTSUPP;
672  return -1;
673 #endif
674 }
675 
676 static int nftnl_rule_do_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
677  const void *data, struct nftnl_parse_err *err,
678  enum nftnl_parse_input input)
679 {
680  int ret;
681  struct nftnl_parse_err perr;
682 
683  switch (type) {
684  case NFTNL_PARSE_XML:
685  ret = nftnl_rule_xml_parse(r, data, &perr, input, NULL);
686  break;
687  case NFTNL_PARSE_JSON:
688  ret = nftnl_rule_json_parse(r, data, &perr, input, NULL);
689  break;
690  default:
691  ret = -1;
692  errno = EOPNOTSUPP;
693  break;
694  }
695  if (err != NULL)
696  *err = perr;
697 
698  return ret;
699 }
700 int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
701  const char *data, struct nftnl_parse_err *err)
702 {
703  return nftnl_rule_do_parse(r, type, data, err, NFTNL_PARSE_BUFFER);
704 }
705 EXPORT_SYMBOL(nftnl_rule_parse, nft_rule_parse);
706 
707 int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
708  FILE *fp, struct nftnl_parse_err *err)
709 {
710  return nftnl_rule_do_parse(r, type, fp, err, NFTNL_PARSE_FILE);
711 }
712 EXPORT_SYMBOL(nftnl_rule_parse_file, nft_rule_parse_file);
713 
714 static int nftnl_rule_snprintf_json(char *buf, size_t size, struct nftnl_rule *r,
715  uint32_t type, uint32_t flags)
716 {
717  int ret, len = size, offset = 0;
718  struct nftnl_expr *expr;
719 
720  ret = snprintf(buf, len, "{\"rule\":{");
721  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
722 
723  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
724  ret = snprintf(buf+offset, len, "\"family\":\"%s\",",
725  nftnl_family2str(r->family));
726  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
727  }
728 
729  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
730  ret = snprintf(buf+offset, len, "\"table\":\"%s\",",
731  r->table);
732  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
733  }
734 
735  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
736  ret = snprintf(buf+offset, len, "\"chain\":\"%s\",",
737  r->chain);
738  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
739  }
740  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
741  ret = snprintf(buf+offset, len, "\"handle\":%llu,",
742  (unsigned long long)r->handle);
743  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
744  }
745 
746  if (r->flags & (1 << NFTNL_RULE_COMPAT_PROTO) ||
747  r->flags & (1 << NFTNL_RULE_COMPAT_FLAGS)) {
748  ret = snprintf(buf+offset, len, "\"compat_flags\":%u,"
749  "\"compat_proto\":%u,",
750  r->compat.flags, r->compat.proto);
751  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
752  }
753 
754  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
755  ret = snprintf(buf+offset, len, "\"position\":%"PRIu64",",
756  r->position);
757  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
758  }
759 
760  ret = snprintf(buf+offset, len, "\"expr\":[");
761  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
762 
763  list_for_each_entry(expr, &r->expr_list, head) {
764  ret = snprintf(buf+offset, len,
765  "{\"type\":\"%s\",", expr->ops->name);
766  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
767 
768  ret = expr->ops->snprintf(buf+offset, len, type, flags, expr);
769  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
770 
771  /*
772  * Remove comma from the first element if there is type
773  * key-value pair only. Example: "expr":[{"type":"log"}]
774  */
775  if (ret == 0) {
776  offset--;
777  len--;
778  }
779 
780  ret = snprintf(buf+offset, len, "},");
781  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
782 
783  }
784  /* Remove comma from last element */
785  offset--;
786  ret = snprintf(buf+offset, len, "]}}");
787  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
788 
789  return offset;
790 }
791 
792 static int nftnl_rule_snprintf_xml(char *buf, size_t size, struct nftnl_rule *r,
793  uint32_t type, uint32_t flags)
794 {
795  int ret, len = size, offset = 0;
796  struct nftnl_expr *expr;
797 
798  ret = snprintf(buf, len, "<rule>");
799  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
800 
801  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
802  ret = snprintf(buf+offset, len, "<family>%s</family>",
803  nftnl_family2str(r->family));
804  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
805  }
806 
807  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
808  ret = snprintf(buf+offset, len, "<table>%s</table>",
809  r->table);
810  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
811  }
812 
813  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
814  ret = snprintf(buf+offset, len, "<chain>%s</chain>",
815  r->chain);
816  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
817  }
818  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
819  ret = snprintf(buf+offset, len, "<handle>%llu</handle>",
820  (unsigned long long)r->handle);
821  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
822  }
823 
824  if (r->compat.flags != 0 || r->compat.proto != 0) {
825  ret = snprintf(buf+offset, len,
826  "<compat_flags>%u</compat_flags>"
827  "<compat_proto>%u</compat_proto>",
828  r->compat.flags, r->compat.proto);
829  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
830  }
831 
832  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
833  ret = snprintf(buf+offset, len,
834  "<position>%"PRIu64"</position>",
835  r->position);
836  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
837  }
838 
839  list_for_each_entry(expr, &r->expr_list, head) {
840  ret = snprintf(buf+offset, len,
841  "<expr type=\"%s\">", expr->ops->name);
842  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
843 
844  ret = nftnl_expr_snprintf(buf+offset, len, expr,
845  type, flags);
846  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
847 
848  ret = snprintf(buf+offset, len, "</expr>");
849  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
850 
851  }
852  ret = snprintf(buf+offset, len, "</rule>");
853  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
854 
855  return offset;
856 }
857 
858 static int nftnl_rule_snprintf_default(char *buf, size_t size, struct nftnl_rule *r,
859  uint32_t type, uint32_t flags)
860 {
861  struct nftnl_expr *expr;
862  int ret, len = size, offset = 0, i;
863 
864  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
865  ret = snprintf(buf+offset, len, "%s ",
866  nftnl_family2str(r->family));
867  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
868  }
869 
870  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
871  ret = snprintf(buf+offset, len, "%s ",
872  r->table);
873  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
874  }
875 
876  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
877  ret = snprintf(buf+offset, len, "%s ",
878  r->chain);
879  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
880  }
881  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
882  ret = snprintf(buf+offset, len, "%llu ",
883  (unsigned long long)r->handle);
884  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
885  }
886 
887  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
888  ret = snprintf(buf+offset, len, "%llu ",
889  (unsigned long long)r->position);
890  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
891  }
892 
893  ret = snprintf(buf+offset, len, "\n");
894  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
895 
896  list_for_each_entry(expr, &r->expr_list, head) {
897  ret = snprintf(buf+offset, len, " [ %s ", expr->ops->name);
898  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
899 
900  ret = nftnl_expr_snprintf(buf+offset, len, expr,
901  type, flags);
902  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
903 
904  ret = snprintf(buf+offset, len, "]\n");
905  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
906  }
907 
908  if (r->user.len) {
909  ret = snprintf(buf+offset, len, " userdata = { ");
910  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
911 
912  for (i = 0; i < r->user.len; i++) {
913  char *c = r->user.data;
914 
915  ret = snprintf(buf+offset, len, "%c",
916  isalnum(c[i]) ? c[i] : 0);
917  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
918  }
919 
920  ret = snprintf(buf+offset, len, " }\n");
921  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
922 
923  }
924 
925  return offset;
926 }
927 
928 static int nftnl_rule_cmd_snprintf(char *buf, size_t size, struct nftnl_rule *r,
929  uint32_t cmd, uint32_t type, uint32_t flags)
930 {
931  int ret, len = size, offset = 0;
932  uint32_t inner_flags = flags;
933 
934  inner_flags &= ~NFTNL_OF_EVENT_ANY;
935 
936  ret = nftnl_cmd_header_snprintf(buf + offset, len, cmd, type, flags);
937  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
938 
939  switch(type) {
940  case NFTNL_OUTPUT_DEFAULT:
941  ret = nftnl_rule_snprintf_default(buf+offset, len, r, type,
942  inner_flags);
943  break;
944  case NFTNL_OUTPUT_XML:
945  ret = nftnl_rule_snprintf_xml(buf+offset, len, r, type,
946  inner_flags);
947  break;
948  case NFTNL_OUTPUT_JSON:
949  ret = nftnl_rule_snprintf_json(buf+offset, len, r, type,
950  inner_flags);
951  break;
952  default:
953  return -1;
954  }
955 
956  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
957 
958  ret = nftnl_cmd_footer_snprintf(buf + offset, len, cmd, type, flags);
959  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
960 
961  return offset;
962 }
963 
964 int nftnl_rule_snprintf(char *buf, size_t size, struct nftnl_rule *r,
965  uint32_t type, uint32_t flags)
966 {
967  return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
968  flags);
969 }
970 EXPORT_SYMBOL(nftnl_rule_snprintf, nft_rule_snprintf);
971 
972 static inline int nftnl_rule_do_snprintf(char *buf, size_t size, void *r,
973  uint32_t cmd, uint32_t type,
974  uint32_t flags)
975 {
976  return nftnl_rule_snprintf(buf, size, r, type, flags);
977 }
978 
979 int nftnl_rule_fprintf(FILE *fp, struct nftnl_rule *r, uint32_t type,
980  uint32_t flags)
981 {
982  return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
983  nftnl_rule_do_snprintf);
984 }
985 EXPORT_SYMBOL(nftnl_rule_fprintf, nft_rule_fprintf);
986 
987 int nftnl_expr_foreach(struct nftnl_rule *r,
988  int (*cb)(struct nftnl_expr *e, void *data),
989  void *data)
990 {
991  struct nftnl_expr *cur, *tmp;
992  int ret;
993 
994  list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
995  ret = cb(cur, data);
996  if (ret < 0)
997  return ret;
998  }
999  return 0;
1000 }
1001 EXPORT_SYMBOL(nftnl_expr_foreach, nft_rule_expr_foreach);
1002 
1004  struct nftnl_rule *r;
1005  struct nftnl_expr *cur;
1006 };
1007 
1008 struct nftnl_expr_iter *nftnl_expr_iter_create(struct nftnl_rule *r)
1009 {
1010  struct nftnl_expr_iter *iter;
1011 
1012  iter = calloc(1, sizeof(struct nftnl_expr_iter));
1013  if (iter == NULL)
1014  return NULL;
1015 
1016  iter->r = r;
1017  if (list_empty(&r->expr_list))
1018  iter->cur = NULL;
1019  else
1020  iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
1021  head);
1022 
1023  return iter;
1024 }
1025 EXPORT_SYMBOL(nftnl_expr_iter_create, nft_rule_expr_iter_create);
1026 
1027 struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
1028 {
1029  struct nftnl_expr *expr = iter->cur;
1030 
1031  if (expr == NULL)
1032  return NULL;
1033 
1034  /* get next expression, if any */
1035  iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
1036  if (&iter->cur->head == iter->r->expr_list.next)
1037  return NULL;
1038 
1039  return expr;
1040 }
1041 EXPORT_SYMBOL(nftnl_expr_iter_next, nft_rule_expr_iter_next);
1042 
1043 void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
1044 {
1045  xfree(iter);
1046 }
1047 EXPORT_SYMBOL(nftnl_expr_iter_destroy, nft_rule_expr_iter_destroy);
1048 
1050  struct list_head list;
1051 };
1052 
1053 struct nftnl_rule_list *nftnl_rule_list_alloc(void)
1054 {
1055  struct nftnl_rule_list *list;
1056 
1057  list = calloc(1, sizeof(struct nftnl_rule_list));
1058  if (list == NULL)
1059  return NULL;
1060 
1061  INIT_LIST_HEAD(&list->list);
1062 
1063  return list;
1064 }
1065 EXPORT_SYMBOL(nftnl_rule_list_alloc, nft_rule_list_alloc);
1066 
1067 void nftnl_rule_list_free(struct nftnl_rule_list *list)
1068 {
1069  struct nftnl_rule *r, *tmp;
1070 
1071  list_for_each_entry_safe(r, tmp, &list->list, head) {
1072  list_del(&r->head);
1073  nftnl_rule_free(r);
1074  }
1075  xfree(list);
1076 }
1077 EXPORT_SYMBOL(nftnl_rule_list_free, nft_rule_list_free);
1078 
1079 int nftnl_rule_list_is_empty(struct nftnl_rule_list *list)
1080 {
1081  return list_empty(&list->list);
1082 }
1083 EXPORT_SYMBOL(nftnl_rule_list_is_empty, nft_rule_list_is_empty);
1084 
1085 void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
1086 {
1087  list_add(&r->head, &list->list);
1088 }
1089 EXPORT_SYMBOL(nftnl_rule_list_add, nft_rule_list_add);
1090 
1091 void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
1092 {
1093  list_add_tail(&r->head, &list->list);
1094 }
1095 EXPORT_SYMBOL(nftnl_rule_list_add_tail, nft_rule_list_add_tail);
1096 
1097 void nftnl_rule_list_del(struct nftnl_rule *r)
1098 {
1099  list_del(&r->head);
1100 }
1101 EXPORT_SYMBOL(nftnl_rule_list_del, nft_rule_list_del);
1102 
1103 int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
1104  int (*cb)(struct nftnl_rule *r, void *data),
1105  void *data)
1106 {
1107  struct nftnl_rule *cur, *tmp;
1108  int ret;
1109 
1110  list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
1111  ret = cb(cur, data);
1112  if (ret < 0)
1113  return ret;
1114  }
1115  return 0;
1116 }
1117 EXPORT_SYMBOL(nftnl_rule_list_foreach, nft_rule_list_foreach);
1118 
1120  struct nftnl_rule_list *list;
1121  struct nftnl_rule *cur;
1122 };
1123 
1124 struct nftnl_rule_list_iter *nftnl_rule_list_iter_create(struct nftnl_rule_list *l)
1125 {
1126  struct nftnl_rule_list_iter *iter;
1127 
1128  iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
1129  if (iter == NULL)
1130  return NULL;
1131 
1132  iter->list = l;
1133  if (nftnl_rule_list_is_empty(l))
1134  iter->cur = NULL;
1135  else
1136  iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
1137 
1138  return iter;
1139 }
1140 EXPORT_SYMBOL(nftnl_rule_list_iter_create, nft_rule_list_iter_create);
1141 
1142 struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
1143 {
1144  return iter->cur;
1145 }
1146 EXPORT_SYMBOL(nftnl_rule_list_iter_cur, nft_rule_list_iter_cur);
1147 
1148 struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
1149 {
1150  struct nftnl_rule *r = iter->cur;
1151 
1152  if (r == NULL)
1153  return NULL;
1154 
1155  /* get next rule, if any */
1156  iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
1157  if (&iter->cur->head == iter->list->list.next)
1158  return NULL;
1159 
1160  return r;
1161 }
1162 EXPORT_SYMBOL(nftnl_rule_list_iter_next, nft_rule_list_iter_next);
1163 
1164 void nftnl_rule_list_iter_destroy(struct nftnl_rule_list_iter *iter)
1165 {
1166  xfree(iter);
1167 }
1168 EXPORT_SYMBOL(nftnl_rule_list_iter_destroy, nft_rule_list_iter_destroy);