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