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