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