libnftnl  1.1.7
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 EXPORT_SYMBOL(nftnl_rule_alloc);
33 struct nftnl_rule *nftnl_rule_alloc(void)
34 {
35  struct nftnl_rule *r;
36 
37  r = calloc(1, sizeof(struct nftnl_rule));
38  if (r == NULL)
39  return NULL;
40 
41  INIT_LIST_HEAD(&r->expr_list);
42 
43  return r;
44 }
45 
46 EXPORT_SYMBOL(nftnl_rule_free);
47 void nftnl_rule_free(const struct nftnl_rule *r)
48 {
49  struct nftnl_expr *e, *tmp;
50 
51  list_for_each_entry_safe(e, tmp, &r->expr_list, head)
52  nftnl_expr_free(e);
53 
54  if (r->flags & (1 << (NFTNL_RULE_TABLE)))
55  xfree(r->table);
56  if (r->flags & (1 << (NFTNL_RULE_CHAIN)))
57  xfree(r->chain);
58  if (r->flags & (1 << (NFTNL_RULE_USERDATA)))
59  xfree(r->user.data);
60 
61  xfree(r);
62 }
63 
64 EXPORT_SYMBOL(nftnl_rule_is_set);
65 bool nftnl_rule_is_set(const struct nftnl_rule *r, uint16_t attr)
66 {
67  return r->flags & (1 << attr);
68 }
69 
70 EXPORT_SYMBOL(nftnl_rule_unset);
71 void nftnl_rule_unset(struct nftnl_rule *r, uint16_t attr)
72 {
73  if (!(r->flags & (1 << attr)))
74  return;
75 
76  switch (attr) {
77  case NFTNL_RULE_TABLE:
78  xfree(r->table);
79  break;
80  case NFTNL_RULE_CHAIN:
81  xfree(r->chain);
82  break;
83  case NFTNL_RULE_HANDLE:
84  case NFTNL_RULE_COMPAT_PROTO:
85  case NFTNL_RULE_COMPAT_FLAGS:
86  case NFTNL_RULE_POSITION:
87  case NFTNL_RULE_FAMILY:
88  case NFTNL_RULE_ID:
89  case NFTNL_RULE_POSITION_ID:
90  break;
91  case NFTNL_RULE_USERDATA:
92  xfree(r->user.data);
93  break;
94  }
95 
96  r->flags &= ~(1 << attr);
97 }
98 
99 static uint32_t nftnl_rule_validate[NFTNL_RULE_MAX + 1] = {
100  [NFTNL_RULE_HANDLE] = sizeof(uint64_t),
101  [NFTNL_RULE_COMPAT_PROTO] = sizeof(uint32_t),
102  [NFTNL_RULE_COMPAT_FLAGS] = sizeof(uint32_t),
103  [NFTNL_RULE_FAMILY] = sizeof(uint32_t),
104  [NFTNL_RULE_POSITION] = sizeof(uint64_t),
105  [NFTNL_RULE_ID] = sizeof(uint32_t),
106  [NFTNL_RULE_POSITION_ID] = sizeof(uint32_t),
107 };
108 
109 EXPORT_SYMBOL(nftnl_rule_set_data);
110 int nftnl_rule_set_data(struct nftnl_rule *r, uint16_t attr,
111  const void *data, uint32_t data_len)
112 {
113  nftnl_assert_attr_exists(attr, NFTNL_RULE_MAX);
114  nftnl_assert_validate(data, nftnl_rule_validate, attr, data_len);
115 
116  switch(attr) {
117  case NFTNL_RULE_TABLE:
118  if (r->flags & (1 << NFTNL_RULE_TABLE))
119  xfree(r->table);
120 
121  r->table = strdup(data);
122  if (!r->table)
123  return -1;
124  break;
125  case NFTNL_RULE_CHAIN:
126  if (r->flags & (1 << NFTNL_RULE_CHAIN))
127  xfree(r->chain);
128 
129  r->chain = strdup(data);
130  if (!r->chain)
131  return -1;
132  break;
133  case NFTNL_RULE_HANDLE:
134  memcpy(&r->handle, data, sizeof(r->handle));
135  break;
136  case NFTNL_RULE_COMPAT_PROTO:
137  memcpy(&r->compat.proto, data, sizeof(r->compat.proto));
138  break;
139  case NFTNL_RULE_COMPAT_FLAGS:
140  memcpy(&r->compat.flags, data, sizeof(r->compat.flags));
141  break;
142  case NFTNL_RULE_FAMILY:
143  memcpy(&r->family, data, sizeof(r->family));
144  break;
145  case NFTNL_RULE_POSITION:
146  memcpy(&r->position, data, sizeof(r->position));
147  break;
148  case NFTNL_RULE_USERDATA:
149  if (r->flags & (1 << NFTNL_RULE_USERDATA))
150  xfree(r->user.data);
151 
152  r->user.data = malloc(data_len);
153  if (!r->user.data)
154  return -1;
155 
156  memcpy(r->user.data, data, data_len);
157  r->user.len = data_len;
158  break;
159  case NFTNL_RULE_ID:
160  memcpy(&r->id, data, sizeof(r->id));
161  break;
162  case NFTNL_RULE_POSITION_ID:
163  memcpy(&r->position_id, data, sizeof(r->position_id));
164  break;
165  }
166  r->flags |= (1 << attr);
167  return 0;
168 }
169 
170 int nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data) __visible;
171 int nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data)
172 {
173  return nftnl_rule_set_data(r, attr, data, nftnl_rule_validate[attr]);
174 }
175 
176 EXPORT_SYMBOL(nftnl_rule_set_u32);
177 void nftnl_rule_set_u32(struct nftnl_rule *r, uint16_t attr, uint32_t val)
178 {
179  nftnl_rule_set_data(r, attr, &val, sizeof(uint32_t));
180 }
181 
182 EXPORT_SYMBOL(nftnl_rule_set_u64);
183 void nftnl_rule_set_u64(struct nftnl_rule *r, uint16_t attr, uint64_t val)
184 {
185  nftnl_rule_set_data(r, attr, &val, sizeof(uint64_t));
186 }
187 
188 EXPORT_SYMBOL(nftnl_rule_set_str);
189 int nftnl_rule_set_str(struct nftnl_rule *r, uint16_t attr, const char *str)
190 {
191  return nftnl_rule_set_data(r, attr, str, strlen(str) + 1);
192 }
193 
194 EXPORT_SYMBOL(nftnl_rule_get_data);
195 const void *nftnl_rule_get_data(const struct nftnl_rule *r, uint16_t attr,
196  uint32_t *data_len)
197 {
198  if (!(r->flags & (1 << attr)))
199  return NULL;
200 
201  switch(attr) {
202  case NFTNL_RULE_FAMILY:
203  *data_len = sizeof(uint32_t);
204  return &r->family;
205  case NFTNL_RULE_TABLE:
206  *data_len = strlen(r->table) + 1;
207  return r->table;
208  case NFTNL_RULE_CHAIN:
209  *data_len = strlen(r->chain) + 1;
210  return r->chain;
211  case NFTNL_RULE_HANDLE:
212  *data_len = sizeof(uint64_t);
213  return &r->handle;
214  case NFTNL_RULE_COMPAT_PROTO:
215  *data_len = sizeof(uint32_t);
216  return &r->compat.proto;
217  case NFTNL_RULE_COMPAT_FLAGS:
218  *data_len = sizeof(uint32_t);
219  return &r->compat.flags;
220  case NFTNL_RULE_POSITION:
221  *data_len = sizeof(uint64_t);
222  return &r->position;
223  case NFTNL_RULE_USERDATA:
224  *data_len = r->user.len;
225  return r->user.data;
226  case NFTNL_RULE_ID:
227  *data_len = sizeof(uint32_t);
228  return &r->id;
229  case NFTNL_RULE_POSITION_ID:
230  *data_len = sizeof(uint32_t);
231  return &r->position_id;
232  }
233  return NULL;
234 }
235 
236 EXPORT_SYMBOL(nftnl_rule_get);
237 const void *nftnl_rule_get(const struct nftnl_rule *r, uint16_t attr)
238 {
239  uint32_t data_len;
240  return nftnl_rule_get_data(r, attr, &data_len);
241 }
242 
243 EXPORT_SYMBOL(nftnl_rule_get_str);
244 const char *nftnl_rule_get_str(const struct nftnl_rule *r, uint16_t attr)
245 {
246  return nftnl_rule_get(r, attr);
247 }
248 
249 EXPORT_SYMBOL(nftnl_rule_get_u32);
250 uint32_t nftnl_rule_get_u32(const struct nftnl_rule *r, uint16_t attr)
251 {
252  uint32_t data_len;
253  const uint32_t *val = nftnl_rule_get_data(r, attr, &data_len);
254 
255  nftnl_assert(val, attr, data_len == sizeof(uint32_t));
256 
257  return val ? *val : 0;
258 }
259 
260 EXPORT_SYMBOL(nftnl_rule_get_u64);
261 uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr)
262 {
263  uint32_t data_len;
264  const uint64_t *val = nftnl_rule_get_data(r, attr, &data_len);
265 
266  nftnl_assert(val, attr, data_len == sizeof(uint64_t));
267 
268  return val ? *val : 0;
269 }
270 
271 EXPORT_SYMBOL(nftnl_rule_get_u8);
272 uint8_t nftnl_rule_get_u8(const struct nftnl_rule *r, uint16_t attr)
273 {
274  uint32_t data_len;
275  const uint8_t *val = nftnl_rule_get_data(r, attr, &data_len);
276 
277  nftnl_assert(val, attr, data_len == sizeof(uint8_t));
278 
279  return val ? *val : 0;
280 }
281 
282 EXPORT_SYMBOL(nftnl_rule_nlmsg_build_payload);
283 void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *r)
284 {
285  struct nftnl_expr *expr;
286  struct nlattr *nest, *nest2;
287 
288  if (r->flags & (1 << NFTNL_RULE_TABLE))
289  mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, r->table);
290  if (r->flags & (1 << NFTNL_RULE_CHAIN))
291  mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, r->chain);
292  if (r->flags & (1 << NFTNL_RULE_HANDLE))
293  mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(r->handle));
294  if (r->flags & (1 << NFTNL_RULE_POSITION))
295  mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
296  if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
297  mnl_attr_put(nlh, NFTA_RULE_USERDATA, r->user.len,
298  r->user.data);
299  }
300 
301  if (!list_empty(&r->expr_list)) {
302  nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
303  list_for_each_entry(expr, &r->expr_list, head) {
304  nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
305  nftnl_expr_build_payload(nlh, expr);
306  mnl_attr_nest_end(nlh, nest2);
307  }
308  mnl_attr_nest_end(nlh, nest);
309  }
310 
311  if (r->flags & (1 << NFTNL_RULE_COMPAT_PROTO) &&
312  r->flags & (1 << NFTNL_RULE_COMPAT_FLAGS)) {
313 
314  nest = mnl_attr_nest_start(nlh, NFTA_RULE_COMPAT);
315  mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_PROTO,
316  htonl(r->compat.proto));
317  mnl_attr_put_u32(nlh, NFTA_RULE_COMPAT_FLAGS,
318  htonl(r->compat.flags));
319  mnl_attr_nest_end(nlh, nest);
320  }
321  if (r->flags & (1 << NFTNL_RULE_ID))
322  mnl_attr_put_u32(nlh, NFTA_RULE_ID, htonl(r->id));
323  if (r->flags & (1 << NFTNL_RULE_POSITION_ID))
324  mnl_attr_put_u32(nlh, NFTA_RULE_POSITION_ID, htonl(r->position_id));
325 }
326 
327 EXPORT_SYMBOL(nftnl_rule_add_expr);
328 void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr)
329 {
330  list_add_tail(&expr->head, &r->expr_list);
331 }
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  case NFTA_RULE_ID:
364  case NFTA_RULE_POSITION_ID:
365  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
366  abi_breakage();
367  break;
368  }
369 
370  tb[type] = attr;
371  return MNL_CB_OK;
372 }
373 
374 static int nftnl_rule_parse_expr(struct nlattr *nest, struct nftnl_rule *r)
375 {
376  struct nftnl_expr *expr;
377  struct nlattr *attr;
378 
379  mnl_attr_for_each_nested(attr, nest) {
380  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
381  return -1;
382 
383  expr = nftnl_expr_parse(attr);
384  if (expr == NULL)
385  return -1;
386 
387  list_add_tail(&expr->head, &r->expr_list);
388  }
389  return 0;
390 }
391 
392 static int nftnl_rule_parse_compat_cb(const struct nlattr *attr, void *data)
393 {
394  const struct nlattr **tb = data;
395  int type = mnl_attr_get_type(attr);
396 
397  if (mnl_attr_type_valid(attr, NFTA_RULE_COMPAT_MAX) < 0)
398  return MNL_CB_OK;
399 
400  switch(type) {
401  case NFTA_RULE_COMPAT_PROTO:
402  case NFTA_RULE_COMPAT_FLAGS:
403  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
404  abi_breakage();
405  break;
406  }
407 
408  tb[type] = attr;
409  return MNL_CB_OK;
410 }
411 
412 static int nftnl_rule_parse_compat(struct nlattr *nest, struct nftnl_rule *r)
413 {
414  struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1] = {};
415 
416  if (mnl_attr_parse_nested(nest, nftnl_rule_parse_compat_cb, tb) < 0)
417  return -1;
418 
419  if (tb[NFTA_RULE_COMPAT_PROTO]) {
420  r->compat.proto =
421  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_PROTO]));
422  r->flags |= (1 << NFTNL_RULE_COMPAT_PROTO);
423  }
424  if (tb[NFTA_RULE_COMPAT_FLAGS]) {
425  r->compat.flags =
426  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_FLAGS]));
427  r->flags |= (1 << NFTNL_RULE_COMPAT_FLAGS);
428  }
429  return 0;
430 }
431 
432 EXPORT_SYMBOL(nftnl_rule_nlmsg_parse);
433 int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_rule *r)
434 {
435  struct nlattr *tb[NFTA_RULE_MAX+1] = {};
436  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
437  int ret;
438 
439  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_rule_parse_attr_cb, tb) < 0)
440  return -1;
441 
442  if (tb[NFTA_RULE_TABLE]) {
443  if (r->flags & (1 << NFTNL_RULE_TABLE))
444  xfree(r->table);
445  r->table = strdup(mnl_attr_get_str(tb[NFTA_RULE_TABLE]));
446  if (!r->table)
447  return -1;
448  r->flags |= (1 << NFTNL_RULE_TABLE);
449  }
450  if (tb[NFTA_RULE_CHAIN]) {
451  if (r->flags & (1 << NFTNL_RULE_CHAIN))
452  xfree(r->chain);
453  r->chain = strdup(mnl_attr_get_str(tb[NFTA_RULE_CHAIN]));
454  if (!r->chain)
455  return -1;
456  r->flags |= (1 << NFTNL_RULE_CHAIN);
457  }
458  if (tb[NFTA_RULE_HANDLE]) {
459  r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
460  r->flags |= (1 << NFTNL_RULE_HANDLE);
461  }
462  if (tb[NFTA_RULE_EXPRESSIONS]) {
463  ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
464  if (ret < 0)
465  return ret;
466  }
467  if (tb[NFTA_RULE_COMPAT]) {
468  ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
469  if (ret < 0)
470  return ret;
471  }
472  if (tb[NFTA_RULE_POSITION]) {
473  r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
474  r->flags |= (1 << NFTNL_RULE_POSITION);
475  }
476  if (tb[NFTA_RULE_USERDATA]) {
477  const void *udata =
478  mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
479 
480  if (r->flags & (1 << NFTNL_RULE_USERDATA))
481  xfree(r->user.data);
482 
483  r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
484 
485  r->user.data = malloc(r->user.len);
486  if (r->user.data == NULL)
487  return -1;
488 
489  memcpy(r->user.data, udata, r->user.len);
490  r->flags |= (1 << NFTNL_RULE_USERDATA);
491  }
492  if (tb[NFTA_RULE_ID]) {
493  r->id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_ID]));
494  r->flags |= (1 << NFTNL_RULE_ID);
495  }
496  if (tb[NFTA_RULE_POSITION_ID]) {
497  r->position_id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_POSITION_ID]));
498  r->flags |= (1 << NFTNL_RULE_POSITION_ID);
499  }
500 
501  r->family = nfg->nfgen_family;
502  r->flags |= (1 << NFTNL_RULE_FAMILY);
503 
504  return 0;
505 }
506 
507 static int nftnl_rule_do_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
508  const void *data, struct nftnl_parse_err *err,
509  enum nftnl_parse_input input)
510 {
511  int ret;
512  struct nftnl_parse_err perr = {};
513 
514  switch (type) {
515  case NFTNL_PARSE_JSON:
516  case NFTNL_PARSE_XML:
517  default:
518  ret = -1;
519  errno = EOPNOTSUPP;
520  break;
521  }
522  if (err != NULL)
523  *err = perr;
524 
525  return ret;
526 }
527 
528 EXPORT_SYMBOL(nftnl_rule_parse);
529 int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
530  const char *data, struct nftnl_parse_err *err)
531 {
532  return nftnl_rule_do_parse(r, type, data, err, NFTNL_PARSE_BUFFER);
533 }
534 
535 EXPORT_SYMBOL(nftnl_rule_parse_file);
536 int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
537  FILE *fp, struct nftnl_parse_err *err)
538 {
539  return nftnl_rule_do_parse(r, type, fp, err, NFTNL_PARSE_FILE);
540 }
541 
542 static int nftnl_rule_snprintf_default(char *buf, size_t size,
543  const struct nftnl_rule *r,
544  uint32_t type, uint32_t flags)
545 {
546  struct nftnl_expr *expr;
547  int ret, remain = size, offset = 0, i;
548 
549  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
550  ret = snprintf(buf + offset, remain, "%s ",
551  nftnl_family2str(r->family));
552  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
553  }
554 
555  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
556  ret = snprintf(buf + offset, remain, "%s ",
557  r->table);
558  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
559  }
560 
561  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
562  ret = snprintf(buf + offset, remain, "%s ",
563  r->chain);
564  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
565  }
566  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
567  ret = snprintf(buf + offset, remain, "%llu ",
568  (unsigned long long)r->handle);
569  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
570  }
571 
572  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
573  ret = snprintf(buf + offset, remain, "%llu ",
574  (unsigned long long)r->position);
575  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
576  }
577 
578  if (r->flags & (1 << NFTNL_RULE_ID)) {
579  ret = snprintf(buf + offset, remain, "%u ", r->id);
580  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
581  }
582 
583  if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
584  ret = snprintf(buf + offset, remain, "%u ", r->position_id);
585  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
586  }
587 
588  ret = snprintf(buf + offset, remain, "\n");
589  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
590 
591  list_for_each_entry(expr, &r->expr_list, head) {
592  ret = snprintf(buf + offset, remain, " [ %s ", expr->ops->name);
593  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
594 
595  ret = nftnl_expr_snprintf(buf + offset, remain, expr,
596  type, flags);
597  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
598 
599  ret = snprintf(buf + offset, remain, "]\n");
600  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
601  }
602 
603  if (r->user.len) {
604  ret = snprintf(buf + offset, remain, " userdata = { ");
605  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
606 
607  for (i = 0; i < r->user.len; i++) {
608  char *c = r->user.data;
609 
610  ret = snprintf(buf + offset, remain, "%c",
611  isalnum(c[i]) ? c[i] : 0);
612  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
613  }
614 
615  ret = snprintf(buf + offset, remain, " }\n");
616  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
617 
618  }
619 
620  return offset;
621 }
622 
623 static int nftnl_rule_cmd_snprintf(char *buf, size_t size,
624  const struct nftnl_rule *r, uint32_t cmd,
625  uint32_t type, uint32_t flags)
626 {
627  int ret, remain = size, offset = 0;
628  uint32_t inner_flags = flags;
629 
630  inner_flags &= ~NFTNL_OF_EVENT_ANY;
631 
632  switch(type) {
633  case NFTNL_OUTPUT_DEFAULT:
634  ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
635  inner_flags);
636  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
637  break;
638  case NFTNL_OUTPUT_JSON:
639  case NFTNL_OUTPUT_XML:
640  default:
641  return -1;
642  }
643 
644  return offset;
645 }
646 
647 EXPORT_SYMBOL(nftnl_rule_snprintf);
648 int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
649  uint32_t type, uint32_t flags)
650 {
651  if (size)
652  buf[0] = '\0';
653 
654  return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
655  flags);
656 }
657 
658 static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
659  uint32_t cmd, uint32_t type, uint32_t flags)
660 {
661  return nftnl_rule_snprintf(buf, size, r, type, flags);
662 }
663 
664 EXPORT_SYMBOL(nftnl_rule_fprintf);
665 int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
666  uint32_t flags)
667 {
668  return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
669  nftnl_rule_do_snprintf);
670 }
671 
672 EXPORT_SYMBOL(nftnl_expr_foreach);
673 int nftnl_expr_foreach(struct nftnl_rule *r,
674  int (*cb)(struct nftnl_expr *e, void *data),
675  void *data)
676 {
677  struct nftnl_expr *cur, *tmp;
678  int ret;
679 
680  list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
681  ret = cb(cur, data);
682  if (ret < 0)
683  return ret;
684  }
685  return 0;
686 }
687 
689  const struct nftnl_rule *r;
690  struct nftnl_expr *cur;
691 };
692 
693 static void nftnl_expr_iter_init(const struct nftnl_rule *r,
694  struct nftnl_expr_iter *iter)
695 {
696  iter->r = r;
697  if (list_empty(&r->expr_list))
698  iter->cur = NULL;
699  else
700  iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
701  head);
702 }
703 
704 EXPORT_SYMBOL(nftnl_expr_iter_create);
705 struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
706 {
707  struct nftnl_expr_iter *iter;
708 
709  iter = calloc(1, sizeof(struct nftnl_expr_iter));
710  if (iter == NULL)
711  return NULL;
712 
713  nftnl_expr_iter_init(r, iter);
714 
715  return iter;
716 }
717 
718 EXPORT_SYMBOL(nftnl_expr_iter_next);
719 struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
720 {
721  struct nftnl_expr *expr = iter->cur;
722 
723  if (expr == NULL)
724  return NULL;
725 
726  /* get next expression, if any */
727  iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
728  if (&iter->cur->head == iter->r->expr_list.next)
729  return NULL;
730 
731  return expr;
732 }
733 
734 EXPORT_SYMBOL(nftnl_expr_iter_destroy);
735 void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
736 {
737  xfree(iter);
738 }
739 
741  struct list_head list;
742 };
743 
744 EXPORT_SYMBOL(nftnl_rule_list_alloc);
745 struct nftnl_rule_list *nftnl_rule_list_alloc(void)
746 {
747  struct nftnl_rule_list *list;
748 
749  list = calloc(1, sizeof(struct nftnl_rule_list));
750  if (list == NULL)
751  return NULL;
752 
753  INIT_LIST_HEAD(&list->list);
754 
755  return list;
756 }
757 
758 EXPORT_SYMBOL(nftnl_rule_list_free);
759 void nftnl_rule_list_free(struct nftnl_rule_list *list)
760 {
761  struct nftnl_rule *r, *tmp;
762 
763  list_for_each_entry_safe(r, tmp, &list->list, head) {
764  list_del(&r->head);
765  nftnl_rule_free(r);
766  }
767  xfree(list);
768 }
769 
770 EXPORT_SYMBOL(nftnl_rule_list_is_empty);
771 int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
772 {
773  return list_empty(&list->list);
774 }
775 
776 EXPORT_SYMBOL(nftnl_rule_list_add);
777 void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
778 {
779  list_add(&r->head, &list->list);
780 }
781 
782 EXPORT_SYMBOL(nftnl_rule_list_insert_at);
783 void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
784 {
785  list_add(&r->head, &pos->head);
786 }
787 
788 EXPORT_SYMBOL(nftnl_rule_list_add_tail);
789 void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
790 {
791  list_add_tail(&r->head, &list->list);
792 }
793 
794 EXPORT_SYMBOL(nftnl_rule_list_del);
795 void nftnl_rule_list_del(struct nftnl_rule *r)
796 {
797  list_del(&r->head);
798 }
799 
800 EXPORT_SYMBOL(nftnl_rule_list_foreach);
801 int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
802  int (*cb)(struct nftnl_rule *r, void *data),
803  void *data)
804 {
805  struct nftnl_rule *cur, *tmp;
806  int ret;
807 
808  list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
809  ret = cb(cur, data);
810  if (ret < 0)
811  return ret;
812  }
813  return 0;
814 }
815 
817  const struct nftnl_rule_list *list;
818  struct nftnl_rule *cur;
819 };
820 
821 EXPORT_SYMBOL(nftnl_rule_list_iter_create);
822 struct nftnl_rule_list_iter *
823 nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
824 {
825  struct nftnl_rule_list_iter *iter;
826 
827  iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
828  if (iter == NULL)
829  return NULL;
830 
831  iter->list = l;
832  if (nftnl_rule_list_is_empty(l))
833  iter->cur = NULL;
834  else
835  iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
836 
837  return iter;
838 }
839 
840 EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
841 struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
842 {
843  return iter->cur;
844 }
845 
846 EXPORT_SYMBOL(nftnl_rule_list_iter_next);
847 struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
848 {
849  struct nftnl_rule *r = iter->cur;
850 
851  if (r == NULL)
852  return NULL;
853 
854  /* get next rule, if any */
855  iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
856  if (&iter->cur->head == iter->list->list.next)
857  return NULL;
858 
859  return r;
860 }
861 
862 EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
863 void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
864 {
865  xfree(iter);
866 }