libnftnl  1.0.6
data_reg.c
1 /*
2  * (C) 2012 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 
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <limits.h>
16 #include <arpa/inet.h>
17 #include <errno.h>
18 #include <netinet/in.h>
19 
20 #include <libmnl/libmnl.h>
21 #include <linux/netfilter.h>
22 #include <linux/netfilter/nf_tables.h>
23 #include <libnftnl/expr.h>
24 #include <libnftnl/rule.h>
25 #include "internal.h"
26 
27 #ifdef JSON_PARSING
28 static int nftnl_data_reg_verdict_json_parse(union nftnl_data_reg *reg, json_t *data,
29  struct nftnl_parse_err *err)
30 {
31  int verdict;
32  const char *verdict_str;
33  const char *chain;
34 
35  verdict_str = nftnl_jansson_parse_str(data, "verdict", err);
36  if (verdict_str == NULL)
37  return DATA_NONE;
38 
39  if (nftnl_str2verdict(verdict_str, &verdict) != 0) {
40  err->node_name = "verdict";
41  err->error = NFTNL_PARSE_EBADTYPE;
42  errno = EINVAL;
43  return -1;
44  }
45 
46  reg->verdict = (uint32_t)verdict;
47 
48  if (nftnl_jansson_node_exist(data, "chain")) {
49  chain = nftnl_jansson_parse_str(data, "chain", err);
50  if (chain == NULL)
51  return DATA_NONE;
52 
53  reg->chain = strdup(chain);
54  }
55 
56  return DATA_VERDICT;
57 }
58 
59 static int nftnl_data_reg_value_json_parse(union nftnl_data_reg *reg, json_t *data,
60  struct nftnl_parse_err *err)
61 {
62  int i;
63  char node_name[6];
64 
65  if (nftnl_jansson_parse_val(data, "len", NFTNL_TYPE_U8, &reg->len, err) < 0)
66  return DATA_NONE;
67 
68  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
69  sprintf(node_name, "data%d", i);
70 
71  if (nftnl_jansson_str2num(data, node_name, BASE_HEX,
72  &reg->val[i], NFTNL_TYPE_U32, err) != 0)
73  return DATA_NONE;
74  }
75 
76  return DATA_VALUE;
77 }
78 
79 int nftnl_data_reg_json_parse(union nftnl_data_reg *reg, json_t *data,
80  struct nftnl_parse_err *err)
81 {
82 
83  const char *type;
84 
85  type = nftnl_jansson_parse_str(data, "type", err);
86  if (type == NULL)
87  return -1;
88 
89  /* Select what type of parsing is needed */
90  if (strcmp(type, "value") == 0)
91  return nftnl_data_reg_value_json_parse(reg, data, err);
92  else if (strcmp(type, "verdict") == 0)
93  return nftnl_data_reg_verdict_json_parse(reg, data, err);
94 
95  return DATA_NONE;
96 }
97 #endif
98 
99 #ifdef XML_PARSING
100 static int nftnl_data_reg_verdict_xml_parse(union nftnl_data_reg *reg,
101  mxml_node_t *tree,
102  struct nftnl_parse_err *err)
103 {
104  int verdict;
105  const char *verdict_str;
106  const char *chain;
107 
108  verdict_str = nftnl_mxml_str_parse(tree, "verdict", MXML_DESCEND_FIRST,
109  NFTNL_XML_MAND, err);
110  if (verdict_str == NULL)
111  return DATA_NONE;
112 
113  if (nftnl_str2verdict(verdict_str, &verdict) != 0) {
114  err->node_name = "verdict";
115  err->error = NFTNL_PARSE_EBADTYPE;
116  errno = EINVAL;
117  return DATA_NONE;
118  }
119 
120  reg->verdict = (uint32_t)verdict;
121 
122  chain = nftnl_mxml_str_parse(tree, "chain", MXML_DESCEND_FIRST,
123  NFTNL_XML_OPT, err);
124  if (chain != NULL) {
125  if (reg->chain)
126  xfree(reg->chain);
127 
128  reg->chain = strdup(chain);
129  }
130 
131  return DATA_VERDICT;
132 }
133 
134 static int nftnl_data_reg_value_xml_parse(union nftnl_data_reg *reg,
135  mxml_node_t *tree,
136  struct nftnl_parse_err *err)
137 {
138  int i;
139  char node_name[6];
140 
141  if (nftnl_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
142  &reg->len, NFTNL_TYPE_U8, NFTNL_XML_MAND, err) != 0)
143  return DATA_NONE;
144 
145  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
146  sprintf(node_name, "data%d", i);
147 
148  if (nftnl_mxml_num_parse(tree, node_name, MXML_DESCEND_FIRST,
149  BASE_HEX, &reg->val[i], NFTNL_TYPE_U32,
150  NFTNL_XML_MAND, err) != 0)
151  return DATA_NONE;
152  }
153 
154  return DATA_VALUE;
155 }
156 
157 int nftnl_data_reg_xml_parse(union nftnl_data_reg *reg, mxml_node_t *tree,
158  struct nftnl_parse_err *err)
159 {
160  const char *type;
161  mxml_node_t *node;
162 
163  node = mxmlFindElement(tree, tree, "reg", "type", NULL,
164  MXML_DESCEND_FIRST);
165  if (node == NULL)
166  goto err;
167 
168  type = mxmlElementGetAttr(node, "type");
169 
170  if (type == NULL)
171  goto err;
172 
173  if (strcmp(type, "value") == 0)
174  return nftnl_data_reg_value_xml_parse(reg, node, err);
175  else if (strcmp(type, "verdict") == 0)
176  return nftnl_data_reg_verdict_xml_parse(reg, node, err);
177 
178  return DATA_NONE;
179 err:
180  errno = EINVAL;
181  err->node_name = "reg";
182  err->error = NFTNL_PARSE_EMISSINGNODE;
183  return DATA_NONE;
184 }
185 #endif
186 
187 static int
188 nftnl_data_reg_value_snprintf_json(char *buf, size_t size,
189  const union nftnl_data_reg *reg,
190  uint32_t flags)
191 {
192  int len = size, offset = 0, ret, i, j;
193  uint32_t utemp;
194  uint8_t *tmp;
195 
196  ret = snprintf(buf, len, "\"reg\":{\"type\":\"value\",");
197  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
198 
199  ret = snprintf(buf+offset, len, "\"len\":%u,", reg->len);
200  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
201 
202  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
203  ret = snprintf(buf+offset, len, "\"data%d\":\"0x", i);
204  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
205 
206  utemp = htonl(reg->val[i]);
207  tmp = (uint8_t *)&utemp;
208 
209  for (j = 0; j<sizeof(uint32_t); j++) {
210  ret = snprintf(buf+offset, len, "%.02x", tmp[j]);
211  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
212  }
213 
214  ret = snprintf(buf+offset, len, "\",");
215  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
216  }
217  offset--;
218  ret = snprintf(buf+offset, len, "}");
219  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
220 
221  return offset;
222 }
223 
224 static
225 int nftnl_data_reg_value_snprintf_xml(char *buf, size_t size,
226  const union nftnl_data_reg *reg,
227  uint32_t flags)
228 {
229  int len = size, offset = 0, ret, i, j;
230  uint32_t be;
231  uint8_t *tmp;
232 
233  ret = snprintf(buf, len, "<reg type=\"value\">");
234  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
235 
236  ret = snprintf(buf+offset, len, "<len>%u</len>", reg->len);
237  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
238 
239  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
240  ret = snprintf(buf+offset, len, "<data%d>0x", i);
241  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
242 
243  be = htonl(reg->val[i]);
244  tmp = (uint8_t *)&be;
245 
246  for (j = 0; j < sizeof(uint32_t); j++) {
247  ret = snprintf(buf+offset, len, "%.02x", tmp[j]);
248  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
249  }
250 
251  ret = snprintf(buf+offset, len, "</data%d>", i);
252  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
253  }
254 
255  ret = snprintf(buf+offset, len, "</reg>");
256  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
257 
258  return offset;
259 }
260 
261 static int
262 nftnl_data_reg_value_snprintf_default(char *buf, size_t size,
263  const union nftnl_data_reg *reg,
264  uint32_t flags)
265 {
266  int len = size, offset = 0, ret, i;
267 
268  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
269  ret = snprintf(buf+offset, len, "0x%.8x ", reg->val[i]);
270  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
271  }
272 
273  return offset;
274 }
275 
276 static int
277 nftnl_data_reg_verdict_snprintf_def(char *buf, size_t size,
278  const union nftnl_data_reg *reg,
279  uint32_t flags)
280 {
281  int len = size, offset = 0, ret = 0;
282 
283  ret = snprintf(buf, size, "%s ", nftnl_verdict2str(reg->verdict));
284  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
285 
286  if (reg->chain != NULL) {
287  ret = snprintf(buf+offset, len, "-> %s ", reg->chain);
288  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
289  }
290 
291  return offset;
292 }
293 
294 static int
295 nftnl_data_reg_verdict_snprintf_xml(char *buf, size_t size,
296  const union nftnl_data_reg *reg,
297  uint32_t flags)
298 {
299  int len = size, offset = 0, ret = 0;
300 
301  ret = snprintf(buf, size, "<reg type=\"verdict\">"
302  "<verdict>%s</verdict>", nftnl_verdict2str(reg->verdict));
303  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
304 
305  if (reg->chain != NULL) {
306  ret = snprintf(buf+offset, len, "<chain>%s</chain>",
307  reg->chain);
308  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
309  }
310 
311  ret = snprintf(buf+offset, len, "</reg>");
312  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
313 
314  return offset;
315 }
316 
317 static int
318 nftnl_data_reg_verdict_snprintf_json(char *buf, size_t size,
319  const union nftnl_data_reg *reg,
320  uint32_t flags)
321 {
322  int len = size, offset = 0, ret = 0;
323 
324  ret = snprintf(buf, size, "\"reg\":{\"type\":\"verdict\","
325  "\"verdict\":\"%s\"", nftnl_verdict2str(reg->verdict));
326  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
327 
328  if (reg->chain != NULL) {
329  ret = snprintf(buf+offset, len, ",\"chain\":\"%s\"",
330  reg->chain);
331  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
332  }
333 
334  ret = snprintf(buf+offset, len, "}");
335  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
336 
337  return offset;
338 }
339 
340 int nftnl_data_reg_snprintf(char *buf, size_t size,
341  const union nftnl_data_reg *reg,
342  uint32_t output_format, uint32_t flags,
343  int reg_type)
344 {
345  switch(reg_type) {
346  case DATA_VALUE:
347  switch(output_format) {
348  case NFTNL_OUTPUT_DEFAULT:
349  return nftnl_data_reg_value_snprintf_default(buf, size,
350  reg, flags);
351  case NFTNL_OUTPUT_XML:
352  return nftnl_data_reg_value_snprintf_xml(buf, size,
353  reg, flags);
354  case NFTNL_OUTPUT_JSON:
355  return nftnl_data_reg_value_snprintf_json(buf, size,
356  reg, flags);
357  default:
358  break;
359  }
360  case DATA_VERDICT:
361  case DATA_CHAIN:
362  switch(output_format) {
363  case NFTNL_OUTPUT_DEFAULT:
364  return nftnl_data_reg_verdict_snprintf_def(buf, size,
365  reg, flags);
366  case NFTNL_OUTPUT_XML:
367  return nftnl_data_reg_verdict_snprintf_xml(buf, size,
368  reg, flags);
369  case NFTNL_OUTPUT_JSON:
370  return nftnl_data_reg_verdict_snprintf_json(buf, size,
371  reg, flags);
372  default:
373  break;
374  }
375  default:
376  break;
377  }
378 
379  return -1;
380 }
381 
382 static int nftnl_data_parse_cb(const struct nlattr *attr, void *data)
383 {
384  const struct nlattr **tb = data;
385  int type = mnl_attr_get_type(attr);
386 
387  if (mnl_attr_type_valid(attr, NFTA_DATA_MAX) < 0)
388  return MNL_CB_OK;
389 
390  switch(type) {
391  case NFTA_DATA_VALUE:
392  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
393  abi_breakage();
394  break;
395  case NFTA_DATA_VERDICT:
396  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
397  abi_breakage();
398  break;
399  }
400  tb[type] = attr;
401  return MNL_CB_OK;
402 }
403 
404 static int nftnl_verdict_parse_cb(const struct nlattr *attr, void *data)
405 {
406  const struct nlattr **tb = data;
407  int type = mnl_attr_get_type(attr);
408 
409  if (mnl_attr_type_valid(attr, NFTA_VERDICT_MAX) < 0)
410  return MNL_CB_OK;
411 
412  switch(type) {
413  case NFTA_VERDICT_CODE:
414  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
415  abi_breakage();
416  break;
417  case NFTA_VERDICT_CHAIN:
418  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
419  abi_breakage();
420  break;
421  }
422  tb[type] = attr;
423  return MNL_CB_OK;
424 }
425 
426 static int
427 nftnl_parse_verdict(union nftnl_data_reg *data, const struct nlattr *attr, int *type)
428 {
429  struct nlattr *tb[NFTA_VERDICT_MAX+1];
430 
431  if (mnl_attr_parse_nested(attr, nftnl_verdict_parse_cb, tb) < 0) {
432  perror("mnl_attr_parse_nested");
433  return -1;
434  }
435 
436  if (!tb[NFTA_VERDICT_CODE])
437  return -1;
438 
439  data->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE]));
440 
441  switch(data->verdict) {
442  case NF_ACCEPT:
443  case NF_DROP:
444  case NF_QUEUE:
445  case NFT_CONTINUE:
446  case NFT_BREAK:
447  case NFT_RETURN:
448  if (type)
449  *type = DATA_VERDICT;
450  data->len = sizeof(data->verdict);
451  break;
452  case NFT_JUMP:
453  case NFT_GOTO:
454  if (!tb[NFTA_VERDICT_CHAIN])
455  return -1;
456 
457  data->chain = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN]));
458  if (type)
459  *type = DATA_CHAIN;
460  break;
461  default:
462  return -1;
463  }
464 
465  return 0;
466 }
467 
468 static int
469 __nftnl_parse_data(union nftnl_data_reg *data, const struct nlattr *attr)
470 {
471  void *orig = mnl_attr_get_payload(attr);
472  uint32_t data_len = mnl_attr_get_payload_len(attr);
473 
474  if (data_len == 0)
475  return -1;
476 
477  if (data_len > sizeof(data->val))
478  return -1;
479 
480  memcpy(data->val, orig, data_len);
481  data->len = data_len;
482 
483  return 0;
484 }
485 
486 int nftnl_parse_data(union nftnl_data_reg *data, struct nlattr *attr, int *type)
487 {
488  struct nlattr *tb[NFTA_DATA_MAX+1] = {};
489  int ret = 0;
490 
491  if (mnl_attr_parse_nested(attr, nftnl_data_parse_cb, tb) < 0) {
492  perror("mnl_attr_parse_nested");
493  return -1;
494  }
495  if (tb[NFTA_DATA_VALUE]) {
496  if (type)
497  *type = DATA_VALUE;
498 
499  ret = __nftnl_parse_data(data, tb[NFTA_DATA_VALUE]);
500  if (ret < 0)
501  return ret;
502  }
503  if (tb[NFTA_DATA_VERDICT])
504  ret = nftnl_parse_verdict(data, tb[NFTA_DATA_VERDICT], type);
505 
506  return ret;
507 }
508 
509 void nftnl_free_verdict(const union nftnl_data_reg *data)
510 {
511  switch(data->verdict) {
512  case NFT_JUMP:
513  case NFT_GOTO:
514  xfree(data->chain);
515  break;
516  default:
517  break;
518  }
519 }