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