libnftnl  1.0.6
dynset.c
1 /*
2  * Copyright (c) 2014, 2015 Patrick McHardy <kaber@trash.net>
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 
10 #include "internal.h"
11 
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <inttypes.h>
15 #include <errno.h>
16 #include <arpa/inet.h>
17 #include <libmnl/libmnl.h>
18 #include <linux/netfilter/nf_tables.h>
19 #include <libnftnl/rule.h>
20 #include <libnftnl/expr.h>
21 #include "data_reg.h"
22 #include "expr_ops.h"
23 #include <buffer.h>
24 
26  enum nft_registers sreg_key;
27  enum nft_registers sreg_data;
28  enum nft_dynset_ops op;
29  uint64_t timeout;
30  struct nftnl_expr *expr;
31  char *set_name;
32  uint32_t set_id;
33 };
34 
35 static int
36 nftnl_expr_dynset_set(struct nftnl_expr *e, uint16_t type,
37  const void *data, uint32_t data_len)
38 {
39  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
40 
41  switch (type) {
42  case NFTNL_EXPR_DYNSET_SREG_KEY:
43  dynset->sreg_key = *((uint32_t *)data);
44  break;
45  case NFTNL_EXPR_DYNSET_SREG_DATA:
46  dynset->sreg_data = *((uint32_t *)data);
47  break;
48  case NFTNL_EXPR_DYNSET_OP:
49  dynset->op = *((uint32_t *)data);
50  break;
51  case NFTNL_EXPR_DYNSET_TIMEOUT:
52  dynset->timeout = *((uint64_t *)data);
53  break;
54  case NFTNL_EXPR_DYNSET_SET_NAME:
55  dynset->set_name = strdup((const char *)data);
56  break;
57  case NFTNL_EXPR_DYNSET_SET_ID:
58  dynset->set_id = *((uint32_t *)data);
59  break;
60  case NFTNL_EXPR_DYNSET_EXPR:
61  dynset->expr = (void *)data;
62  break;
63  default:
64  return -1;
65  }
66  return 0;
67 }
68 
69 static const void *
70 nftnl_expr_dynset_get(const struct nftnl_expr *e, uint16_t type,
71  uint32_t *data_len)
72 {
73  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
74 
75  switch (type) {
76  case NFTNL_EXPR_DYNSET_SREG_KEY:
77  *data_len = sizeof(dynset->sreg_key);
78  return &dynset->sreg_key;
79  case NFTNL_EXPR_DYNSET_SREG_DATA:
80  *data_len = sizeof(dynset->sreg_data);
81  return &dynset->sreg_data;
82  case NFTNL_EXPR_DYNSET_OP:
83  *data_len = sizeof(dynset->op);
84  return &dynset->op;
85  case NFTNL_EXPR_DYNSET_TIMEOUT:
86  *data_len = sizeof(dynset->timeout);
87  return &dynset->timeout;
88  case NFTNL_EXPR_DYNSET_SET_NAME:
89  return dynset->set_name;
90  case NFTNL_EXPR_DYNSET_SET_ID:
91  return &dynset->set_id;
92  case NFTNL_EXPR_DYNSET_EXPR:
93  return dynset->expr;
94  }
95  return NULL;
96 }
97 
98 static int nftnl_expr_dynset_cb(const struct nlattr *attr, void *data)
99 {
100  const struct nlattr **tb = data;
101  int type = mnl_attr_get_type(attr);
102 
103  if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
104  return MNL_CB_OK;
105 
106  switch (type) {
107  case NFTA_DYNSET_SREG_KEY:
108  case NFTA_DYNSET_SREG_DATA:
109  case NFTA_DYNSET_SET_ID:
110  case NFTA_DYNSET_OP:
111  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
112  abi_breakage();
113  break;
114  case NFTA_DYNSET_TIMEOUT:
115  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
116  abi_breakage();
117  break;
118  case NFTA_DYNSET_SET_NAME:
119  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
120  abi_breakage();
121  break;
122  case NFTA_DYNSET_EXPR:
123  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
124  abi_breakage();
125  break;
126  }
127 
128  tb[type] = attr;
129  return MNL_CB_OK;
130 }
131 
132 static void
133 nftnl_expr_dynset_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
134 {
135  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
136  struct nlattr *nest;
137 
138  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_KEY))
139  mnl_attr_put_u32(nlh, NFTA_DYNSET_SREG_KEY, htonl(dynset->sreg_key));
140  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_DATA))
141  mnl_attr_put_u32(nlh, NFTA_DYNSET_SREG_DATA, htonl(dynset->sreg_data));
142  if (e->flags & (1 << NFTNL_EXPR_DYNSET_OP))
143  mnl_attr_put_u32(nlh, NFTA_DYNSET_OP, htonl(dynset->op));
144  if (e->flags & (1 << NFTNL_EXPR_DYNSET_TIMEOUT))
145  mnl_attr_put_u64(nlh, NFTA_DYNSET_TIMEOUT, htobe64(dynset->timeout));
146  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_NAME))
147  mnl_attr_put_strz(nlh, NFTA_DYNSET_SET_NAME, dynset->set_name);
148  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_ID))
149  mnl_attr_put_u32(nlh, NFTA_DYNSET_SET_ID, htonl(dynset->set_id));
150  if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) {
151  nest = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPR);
152  nftnl_expr_build_payload(nlh, dynset->expr);
153  mnl_attr_nest_end(nlh, nest);
154  }
155 }
156 
157 static int
158 nftnl_expr_dynset_parse(struct nftnl_expr *e, struct nlattr *attr)
159 {
160  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
161  struct nlattr *tb[NFTA_SET_MAX+1] = {};
162  int ret = 0;
163 
164  if (mnl_attr_parse_nested(attr, nftnl_expr_dynset_cb, tb) < 0)
165  return -1;
166 
167  if (tb[NFTA_DYNSET_SREG_KEY]) {
168  dynset->sreg_key = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_SREG_KEY]));
169  e->flags |= (1 << NFTNL_EXPR_DYNSET_SREG_KEY);
170  }
171  if (tb[NFTA_DYNSET_SREG_DATA]) {
172  dynset->sreg_data = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_SREG_DATA]));
173  e->flags |= (1 << NFTNL_EXPR_DYNSET_SREG_DATA);
174  }
175  if (tb[NFTA_DYNSET_OP]) {
176  dynset->op = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_OP]));
177  e->flags |= (1 << NFTNL_EXPR_DYNSET_OP);
178  }
179  if (tb[NFTA_DYNSET_TIMEOUT]) {
180  dynset->timeout = be64toh(mnl_attr_get_u64(tb[NFTA_DYNSET_TIMEOUT]));
181  e->flags |= (1 << NFTNL_EXPR_DYNSET_TIMEOUT);
182  }
183  if (tb[NFTA_DYNSET_SET_NAME]) {
184  dynset->set_name =
185  strdup(mnl_attr_get_str(tb[NFTA_DYNSET_SET_NAME]));
186  e->flags |= (1 << NFTNL_EXPR_DYNSET_SET_NAME);
187  }
188  if (tb[NFTA_DYNSET_SET_ID]) {
189  dynset->set_id = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_SET_ID]));
190  e->flags |= (1 << NFTNL_EXPR_DYNSET_SET_ID);
191  }
192  if (tb[NFTA_DYNSET_EXPR]) {
193  e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPR);
194  dynset->expr = nftnl_expr_parse(tb[NFTA_DYNSET_EXPR]);
195  if (dynset->expr == NULL)
196  return -1;
197  }
198 
199  return ret;
200 }
201 
202 static int
203 nftnl_expr_dynset_json_parse(struct nftnl_expr *e, json_t *root,
204  struct nftnl_parse_err *err)
205 {
206 #ifdef JSON_PARSING
207  const char *set_name;
208  uint32_t uval32;
209  uint64_t uval64;
210 
211  set_name = nftnl_jansson_parse_str(root, "set", err);
212  if (set_name != NULL)
213  nftnl_expr_set_str(e, NFTNL_EXPR_DYNSET_SET_NAME, set_name);
214 
215  if (nftnl_jansson_parse_reg(root, "sreg_key",
216  NFTNL_TYPE_U32, &uval32, err) == 0)
217  nftnl_expr_set_u32(e, NFTNL_EXPR_DYNSET_SREG_KEY, uval32);
218 
219  if (nftnl_jansson_parse_reg(root, "sreg_data",
220  NFTNL_TYPE_U32, &uval32, err) == 0)
221  nftnl_expr_set_u32(e, NFTNL_EXPR_DYNSET_SREG_DATA, uval32);
222 
223  if (nftnl_jansson_parse_val(root, "op", NFTNL_TYPE_U32, &uval32,
224  err) == 0)
225  nftnl_expr_set_u32(e, NFTNL_EXPR_DYNSET_OP, uval32);
226 
227  if (nftnl_jansson_parse_val(root, "timeout", NFTNL_TYPE_U64, &uval64,
228  err) == 0)
229  nftnl_expr_set_u64(e, NFTNL_EXPR_DYNSET_TIMEOUT, uval64);
230 
231  return 0;
232 #else
233  errno = EOPNOTSUPP;
234  return -1;
235 #endif
236 }
237 
238 static int
239 nftnl_expr_dynset_xml_parse(struct nftnl_expr *e, mxml_node_t *tree,
240  struct nftnl_parse_err *err)
241 {
242 #ifdef XML_PARSING
243  const char *set_name;
244  uint32_t uval32;
245  uint64_t uval64;
246 
247  set_name = nftnl_mxml_str_parse(tree, "set", MXML_DESCEND_FIRST,
248  NFTNL_XML_MAND, err);
249  if (set_name != NULL)
250  nftnl_expr_set_str(e, NFTNL_EXPR_DYNSET_SET_NAME, set_name);
251 
252  if (nftnl_mxml_reg_parse(tree, "sreg_key", &uval32, MXML_DESCEND,
253  NFTNL_XML_MAND, err) == 0)
254  nftnl_expr_set_u32(e, NFTNL_EXPR_DYNSET_SREG_KEY, uval32);
255 
256  if (nftnl_mxml_reg_parse(tree, "sreg_data", &uval32, MXML_DESCEND,
257  NFTNL_XML_MAND, err) == 0)
258  nftnl_expr_set_u32(e, NFTNL_EXPR_DYNSET_SREG_DATA, uval32);
259 
260  if (nftnl_mxml_num_parse(tree, "op", MXML_DESCEND_FIRST, BASE_DEC,
261  &uval32, NFTNL_TYPE_U32, NFTNL_XML_MAND, err) == 0)
262  nftnl_expr_set_u32(e, NFTNL_EXPR_DYNSET_OP, uval32);
263 
264  if (nftnl_mxml_num_parse(tree, "timeout", MXML_DESCEND_FIRST, BASE_DEC,
265  &uval64, NFTNL_TYPE_U64, NFTNL_XML_MAND, err) == 0)
266  nftnl_expr_set_u64(e, NFTNL_EXPR_DYNSET_TIMEOUT, uval64);
267 
268  return 0;
269 #else
270  errno = EOPNOTSUPP;
271  return -1;
272 #endif
273 }
274 
275 static int
276 nftnl_expr_dynset_export(char *buf, size_t size,
277  const struct nftnl_expr *e, int type)
278 {
279  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
280  NFTNL_BUF_INIT(b, buf, size);
281 
282  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_NAME))
283  nftnl_buf_str(&b, type, dynset->set_name, SET_NAME);
284  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_KEY))
285  nftnl_buf_u32(&b, type, dynset->sreg_key, SREG_KEY);
286  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_DATA))
287  nftnl_buf_u32(&b, type, dynset->sreg_data, SREG_DATA);
288 
289  return nftnl_buf_done(&b);
290 }
291 
292 static char *op2str_array[] = {
293  [NFT_DYNSET_OP_ADD] = "add",
294  [NFT_DYNSET_OP_UPDATE] = "update",
295 };
296 
297 static const char *op2str(enum nft_dynset_ops op)
298 {
299  if (op > NFT_DYNSET_OP_UPDATE)
300  return "unknown";
301  return op2str_array[op];
302 }
303 
304 static int
305 nftnl_expr_dynset_snprintf_default(char *buf, size_t size,
306  const struct nftnl_expr *e)
307 {
308  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
309  struct nftnl_expr *expr;
310  int len = size, offset = 0, ret;
311 
312  ret = snprintf(buf, len, "%s reg_key %u set %s ",
313  op2str(dynset->op), dynset->sreg_key, dynset->set_name);
314  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
315 
316  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_DATA)) {
317  ret = snprintf(buf+offset, len, "sreg_data %u ", dynset->sreg_data);
318  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
319  }
320  if (e->flags & (1 << NFTNL_EXPR_DYNSET_TIMEOUT)) {
321  ret = snprintf(buf+offset, len, "timeout %"PRIu64"ms ",
322  dynset->timeout);
323  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
324  }
325  if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) {
326  expr = dynset->expr;
327  ret = snprintf(buf+offset, len, "expr [ %s ",
328  expr->ops->name);
329  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
330 
331  ret = nftnl_expr_snprintf(buf+offset, len, expr,
332  NFTNL_OUTPUT_DEFAULT,
333  NFTNL_OF_EVENT_ANY);
334  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
335 
336  ret = snprintf(buf+offset, len, "] ");
337  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
338  }
339 
340  return offset;
341 }
342 
343 static int
344 nftnl_expr_dynset_snprintf(char *buf, size_t size, uint32_t type,
345  uint32_t flags, const struct nftnl_expr *e)
346 {
347 
348  switch (type) {
349  case NFTNL_OUTPUT_DEFAULT:
350  return nftnl_expr_dynset_snprintf_default(buf, size, e);
351  case NFTNL_OUTPUT_XML:
352  case NFTNL_OUTPUT_JSON:
353  return nftnl_expr_dynset_export(buf, size, e, type);
354  default:
355  break;
356  }
357  return -1;
358 }
359 
360 static void nftnl_expr_dynset_free(const struct nftnl_expr *e)
361 {
362  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
363 
364  xfree(dynset->set_name);
365 }
366 
367 struct expr_ops expr_ops_dynset = {
368  .name = "dynset",
369  .alloc_len = sizeof(struct nftnl_expr_dynset),
370  .max_attr = NFTA_DYNSET_MAX,
371  .free = nftnl_expr_dynset_free,
372  .set = nftnl_expr_dynset_set,
373  .get = nftnl_expr_dynset_get,
374  .parse = nftnl_expr_dynset_parse,
375  .build = nftnl_expr_dynset_build,
376  .snprintf = nftnl_expr_dynset_snprintf,
377  .xml_parse = nftnl_expr_dynset_xml_parse,
378  .json_parse = nftnl_expr_dynset_json_parse,
379 };