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