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