libnftnl  1.2.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 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 EXPORT_SYMBOL(nftnl_rule_del_expr);
334 void nftnl_rule_del_expr(struct nftnl_expr *expr)
335 {
336  list_del(&expr->head);
337 }
338 
339 static int nftnl_rule_parse_attr_cb(const struct nlattr *attr, void *data)
340 {
341  const struct nlattr **tb = data;
342  int type = mnl_attr_get_type(attr);
343 
344  if (mnl_attr_type_valid(attr, NFTA_RULE_MAX) < 0)
345  return MNL_CB_OK;
346 
347  switch(type) {
348  case NFTA_RULE_TABLE:
349  case NFTA_RULE_CHAIN:
350  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
351  abi_breakage();
352  break;
353  case NFTA_RULE_HANDLE:
354  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
355  abi_breakage();
356  break;
357  case NFTA_RULE_COMPAT:
358  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
359  abi_breakage();
360  break;
361  case NFTA_RULE_POSITION:
362  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
363  abi_breakage();
364  break;
365  case NFTA_RULE_USERDATA:
366  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
367  abi_breakage();
368  break;
369  case NFTA_RULE_ID:
370  case NFTA_RULE_POSITION_ID:
371  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
372  abi_breakage();
373  break;
374  }
375 
376  tb[type] = attr;
377  return MNL_CB_OK;
378 }
379 
380 static int nftnl_rule_parse_expr(struct nlattr *nest, struct nftnl_rule *r)
381 {
382  struct nftnl_expr *expr;
383  struct nlattr *attr;
384 
385  mnl_attr_for_each_nested(attr, nest) {
386  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
387  return -1;
388 
389  expr = nftnl_expr_parse(attr);
390  if (expr == NULL)
391  return -1;
392 
393  list_add_tail(&expr->head, &r->expr_list);
394  }
395  return 0;
396 }
397 
398 static int nftnl_rule_parse_compat_cb(const struct nlattr *attr, void *data)
399 {
400  const struct nlattr **tb = data;
401  int type = mnl_attr_get_type(attr);
402 
403  if (mnl_attr_type_valid(attr, NFTA_RULE_COMPAT_MAX) < 0)
404  return MNL_CB_OK;
405 
406  switch(type) {
407  case NFTA_RULE_COMPAT_PROTO:
408  case NFTA_RULE_COMPAT_FLAGS:
409  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
410  abi_breakage();
411  break;
412  }
413 
414  tb[type] = attr;
415  return MNL_CB_OK;
416 }
417 
418 static int nftnl_rule_parse_compat(struct nlattr *nest, struct nftnl_rule *r)
419 {
420  struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1] = {};
421 
422  if (mnl_attr_parse_nested(nest, nftnl_rule_parse_compat_cb, tb) < 0)
423  return -1;
424 
425  if (tb[NFTA_RULE_COMPAT_PROTO]) {
426  r->compat.proto =
427  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_PROTO]));
428  r->flags |= (1 << NFTNL_RULE_COMPAT_PROTO);
429  }
430  if (tb[NFTA_RULE_COMPAT_FLAGS]) {
431  r->compat.flags =
432  ntohl(mnl_attr_get_u32(tb[NFTA_RULE_COMPAT_FLAGS]));
433  r->flags |= (1 << NFTNL_RULE_COMPAT_FLAGS);
434  }
435  return 0;
436 }
437 
438 EXPORT_SYMBOL(nftnl_rule_nlmsg_parse);
439 int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_rule *r)
440 {
441  struct nlattr *tb[NFTA_RULE_MAX+1] = {};
442  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
443  int ret;
444 
445  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_rule_parse_attr_cb, tb) < 0)
446  return -1;
447 
448  if (tb[NFTA_RULE_TABLE]) {
449  if (r->flags & (1 << NFTNL_RULE_TABLE))
450  xfree(r->table);
451  r->table = strdup(mnl_attr_get_str(tb[NFTA_RULE_TABLE]));
452  if (!r->table)
453  return -1;
454  r->flags |= (1 << NFTNL_RULE_TABLE);
455  }
456  if (tb[NFTA_RULE_CHAIN]) {
457  if (r->flags & (1 << NFTNL_RULE_CHAIN))
458  xfree(r->chain);
459  r->chain = strdup(mnl_attr_get_str(tb[NFTA_RULE_CHAIN]));
460  if (!r->chain)
461  return -1;
462  r->flags |= (1 << NFTNL_RULE_CHAIN);
463  }
464  if (tb[NFTA_RULE_HANDLE]) {
465  r->handle = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_HANDLE]));
466  r->flags |= (1 << NFTNL_RULE_HANDLE);
467  }
468  if (tb[NFTA_RULE_EXPRESSIONS]) {
469  ret = nftnl_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
470  if (ret < 0)
471  return ret;
472  }
473  if (tb[NFTA_RULE_COMPAT]) {
474  ret = nftnl_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
475  if (ret < 0)
476  return ret;
477  }
478  if (tb[NFTA_RULE_POSITION]) {
479  r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
480  r->flags |= (1 << NFTNL_RULE_POSITION);
481  }
482  if (tb[NFTA_RULE_USERDATA]) {
483  const void *udata =
484  mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
485 
486  if (r->flags & (1 << NFTNL_RULE_USERDATA))
487  xfree(r->user.data);
488 
489  r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
490 
491  r->user.data = malloc(r->user.len);
492  if (r->user.data == NULL)
493  return -1;
494 
495  memcpy(r->user.data, udata, r->user.len);
496  r->flags |= (1 << NFTNL_RULE_USERDATA);
497  }
498  if (tb[NFTA_RULE_ID]) {
499  r->id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_ID]));
500  r->flags |= (1 << NFTNL_RULE_ID);
501  }
502  if (tb[NFTA_RULE_POSITION_ID]) {
503  r->position_id = ntohl(mnl_attr_get_u32(tb[NFTA_RULE_POSITION_ID]));
504  r->flags |= (1 << NFTNL_RULE_POSITION_ID);
505  }
506 
507  r->family = nfg->nfgen_family;
508  r->flags |= (1 << NFTNL_RULE_FAMILY);
509 
510  return 0;
511 }
512 
513 static int nftnl_rule_do_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
514  const void *data, struct nftnl_parse_err *err,
515  enum nftnl_parse_input input)
516 {
517  int ret;
518  struct nftnl_parse_err perr = {};
519 
520  switch (type) {
521  case NFTNL_PARSE_JSON:
522  case NFTNL_PARSE_XML:
523  default:
524  ret = -1;
525  errno = EOPNOTSUPP;
526  break;
527  }
528  if (err != NULL)
529  *err = perr;
530 
531  return ret;
532 }
533 
534 EXPORT_SYMBOL(nftnl_rule_parse);
535 int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
536  const char *data, struct nftnl_parse_err *err)
537 {
538  return nftnl_rule_do_parse(r, type, data, err, NFTNL_PARSE_BUFFER);
539 }
540 
541 EXPORT_SYMBOL(nftnl_rule_parse_file);
542 int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
543  FILE *fp, struct nftnl_parse_err *err)
544 {
545  return nftnl_rule_do_parse(r, type, fp, err, NFTNL_PARSE_FILE);
546 }
547 
548 static int nftnl_rule_snprintf_default(char *buf, size_t remain,
549  const struct nftnl_rule *r,
550  uint32_t type, uint32_t flags)
551 {
552  struct nftnl_expr *expr;
553  int ret, offset = 0, i;
554  const char *sep = "";
555 
556  if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
557  ret = snprintf(buf + offset, remain, "%s%s", sep,
558  nftnl_family2str(r->family));
559  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
560  sep = " ";
561  }
562 
563  if (r->flags & (1 << NFTNL_RULE_TABLE)) {
564  ret = snprintf(buf + offset, remain, "%s%s", sep,
565  r->table);
566  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
567  sep = " ";
568  }
569 
570  if (r->flags & (1 << NFTNL_RULE_CHAIN)) {
571  ret = snprintf(buf + offset, remain, "%s%s", sep,
572  r->chain);
573  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
574  sep = " ";
575  }
576  if (r->flags & (1 << NFTNL_RULE_HANDLE)) {
577  ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
578  r->handle);
579  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
580  sep = " ";
581  }
582 
583  if (r->flags & (1 << NFTNL_RULE_POSITION)) {
584  ret = snprintf(buf + offset, remain, "%s%" PRIu64, sep,
585  r->position);
586  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
587  sep = " ";
588  }
589 
590  if (r->flags & (1 << NFTNL_RULE_ID)) {
591  ret = snprintf(buf + offset, remain, "%s%u", sep, r->id);
592  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
593  sep = " ";
594  }
595 
596  if (r->flags & (1 << NFTNL_RULE_POSITION_ID)) {
597  ret = snprintf(buf + offset, remain, "%s%u", sep,
598  r->position_id);
599  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
600  sep = " ";
601  }
602 
603  ret = snprintf(buf + offset, remain, "\n");
604  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
605 
606  list_for_each_entry(expr, &r->expr_list, head) {
607  ret = snprintf(buf + offset, remain, " [ %s ", expr->ops->name);
608  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
609 
610  ret = nftnl_expr_snprintf(buf + offset, remain, expr,
611  type, flags);
612  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
613 
614  ret = snprintf(buf + offset, remain, "]\n");
615  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
616  }
617 
618  if (r->user.len) {
619  ret = snprintf(buf + offset, remain, " userdata = { ");
620  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
621 
622  for (i = 0; i < r->user.len; i++) {
623  char *c = r->user.data;
624 
625  ret = snprintf(buf + offset, remain,
626  isprint(c[i]) ? "%c" : "\\x%02hhx",
627  c[i]);
628  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
629  }
630 
631  ret = snprintf(buf + offset, remain, " }");
632  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
633 
634  }
635 
636  return offset;
637 }
638 
639 static int nftnl_rule_cmd_snprintf(char *buf, size_t remain,
640  const struct nftnl_rule *r, uint32_t cmd,
641  uint32_t type, uint32_t flags)
642 {
643  uint32_t inner_flags = flags;
644  int ret, offset = 0;
645 
646  inner_flags &= ~NFTNL_OF_EVENT_ANY;
647 
648  if (type != NFTNL_OUTPUT_DEFAULT)
649  return -1;
650 
651  ret = nftnl_rule_snprintf_default(buf + offset, remain, r, type,
652  inner_flags);
653  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
654  return offset;
655 }
656 
657 EXPORT_SYMBOL(nftnl_rule_snprintf);
658 int nftnl_rule_snprintf(char *buf, size_t size, const struct nftnl_rule *r,
659  uint32_t type, uint32_t flags)
660 {
661  if (size)
662  buf[0] = '\0';
663 
664  return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
665  flags);
666 }
667 
668 static int nftnl_rule_do_snprintf(char *buf, size_t size, const void *r,
669  uint32_t cmd, uint32_t type, uint32_t flags)
670 {
671  return nftnl_rule_snprintf(buf, size, r, type, flags);
672 }
673 
674 EXPORT_SYMBOL(nftnl_rule_fprintf);
675 int nftnl_rule_fprintf(FILE *fp, const struct nftnl_rule *r, uint32_t type,
676  uint32_t flags)
677 {
678  return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
679  nftnl_rule_do_snprintf);
680 }
681 
682 EXPORT_SYMBOL(nftnl_expr_foreach);
683 int nftnl_expr_foreach(struct nftnl_rule *r,
684  int (*cb)(struct nftnl_expr *e, void *data),
685  void *data)
686 {
687  struct nftnl_expr *cur, *tmp;
688  int ret;
689 
690  list_for_each_entry_safe(cur, tmp, &r->expr_list, head) {
691  ret = cb(cur, data);
692  if (ret < 0)
693  return ret;
694  }
695  return 0;
696 }
697 
699  const struct nftnl_rule *r;
700  struct nftnl_expr *cur;
701 };
702 
703 static void nftnl_expr_iter_init(const struct nftnl_rule *r,
704  struct nftnl_expr_iter *iter)
705 {
706  iter->r = r;
707  if (list_empty(&r->expr_list))
708  iter->cur = NULL;
709  else
710  iter->cur = list_entry(r->expr_list.next, struct nftnl_expr,
711  head);
712 }
713 
714 EXPORT_SYMBOL(nftnl_expr_iter_create);
715 struct nftnl_expr_iter *nftnl_expr_iter_create(const struct nftnl_rule *r)
716 {
717  struct nftnl_expr_iter *iter;
718 
719  iter = calloc(1, sizeof(struct nftnl_expr_iter));
720  if (iter == NULL)
721  return NULL;
722 
723  nftnl_expr_iter_init(r, iter);
724 
725  return iter;
726 }
727 
728 EXPORT_SYMBOL(nftnl_expr_iter_next);
729 struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
730 {
731  struct nftnl_expr *expr = iter->cur;
732 
733  if (expr == NULL)
734  return NULL;
735 
736  /* get next expression, if any */
737  iter->cur = list_entry(iter->cur->head.next, struct nftnl_expr, head);
738  if (&iter->cur->head == iter->r->expr_list.next)
739  return NULL;
740 
741  return expr;
742 }
743 
744 EXPORT_SYMBOL(nftnl_expr_iter_destroy);
745 void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
746 {
747  xfree(iter);
748 }
749 
751  struct list_head list;
752 };
753 
754 EXPORT_SYMBOL(nftnl_rule_list_alloc);
755 struct nftnl_rule_list *nftnl_rule_list_alloc(void)
756 {
757  struct nftnl_rule_list *list;
758 
759  list = calloc(1, sizeof(struct nftnl_rule_list));
760  if (list == NULL)
761  return NULL;
762 
763  INIT_LIST_HEAD(&list->list);
764 
765  return list;
766 }
767 
768 EXPORT_SYMBOL(nftnl_rule_list_free);
769 void nftnl_rule_list_free(struct nftnl_rule_list *list)
770 {
771  struct nftnl_rule *r, *tmp;
772 
773  list_for_each_entry_safe(r, tmp, &list->list, head) {
774  list_del(&r->head);
775  nftnl_rule_free(r);
776  }
777  xfree(list);
778 }
779 
780 EXPORT_SYMBOL(nftnl_rule_list_is_empty);
781 int nftnl_rule_list_is_empty(const struct nftnl_rule_list *list)
782 {
783  return list_empty(&list->list);
784 }
785 
786 EXPORT_SYMBOL(nftnl_rule_list_add);
787 void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
788 {
789  list_add(&r->head, &list->list);
790 }
791 
792 EXPORT_SYMBOL(nftnl_rule_list_insert_at);
793 void nftnl_rule_list_insert_at(struct nftnl_rule *r, struct nftnl_rule *pos)
794 {
795  list_add(&r->head, &pos->head);
796 }
797 
798 EXPORT_SYMBOL(nftnl_rule_list_add_tail);
799 void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
800 {
801  list_add_tail(&r->head, &list->list);
802 }
803 
804 EXPORT_SYMBOL(nftnl_rule_list_del);
805 void nftnl_rule_list_del(struct nftnl_rule *r)
806 {
807  list_del(&r->head);
808 }
809 
810 EXPORT_SYMBOL(nftnl_rule_list_foreach);
811 int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
812  int (*cb)(struct nftnl_rule *r, void *data),
813  void *data)
814 {
815  struct nftnl_rule *cur, *tmp;
816  int ret;
817 
818  list_for_each_entry_safe(cur, tmp, &rule_list->list, head) {
819  ret = cb(cur, data);
820  if (ret < 0)
821  return ret;
822  }
823  return 0;
824 }
825 
827  const struct nftnl_rule_list *list;
828  struct nftnl_rule *cur;
829 };
830 
831 EXPORT_SYMBOL(nftnl_rule_list_iter_create);
832 struct nftnl_rule_list_iter *
833 nftnl_rule_list_iter_create(const struct nftnl_rule_list *l)
834 {
835  struct nftnl_rule_list_iter *iter;
836 
837  iter = calloc(1, sizeof(struct nftnl_rule_list_iter));
838  if (iter == NULL)
839  return NULL;
840 
841  iter->list = l;
842  if (nftnl_rule_list_is_empty(l))
843  iter->cur = NULL;
844  else
845  iter->cur = list_entry(l->list.next, struct nftnl_rule, head);
846 
847  return iter;
848 }
849 
850 EXPORT_SYMBOL(nftnl_rule_list_iter_cur);
851 struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
852 {
853  return iter->cur;
854 }
855 
856 EXPORT_SYMBOL(nftnl_rule_list_iter_next);
857 struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
858 {
859  struct nftnl_rule *r = iter->cur;
860 
861  if (r == NULL)
862  return NULL;
863 
864  /* get next rule, if any */
865  iter->cur = list_entry(iter->cur->head.next, struct nftnl_rule, head);
866  if (&iter->cur->head == iter->list->list.next)
867  return NULL;
868 
869  return r;
870 }
871 
872 EXPORT_SYMBOL(nftnl_rule_list_iter_destroy);
873 void nftnl_rule_list_iter_destroy(const struct nftnl_rule_list_iter *iter)
874 {
875  xfree(iter);
876 }