libnftnl  1.0.5
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  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  union nftnl_data_reg *reg, uint32_t flags)
227 {
228  int len = size, offset = 0, ret, i, j;
229  uint32_t be;
230  uint8_t *tmp;
231 
232  ret = snprintf(buf, len, "<reg type=\"value\">");
233  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
234 
235  ret = snprintf(buf+offset, len, "<len>%u</len>", reg->len);
236  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
237 
238  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
239  ret = snprintf(buf+offset, len, "<data%d>0x", i);
240  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
241 
242  be = htonl(reg->val[i]);
243  tmp = (uint8_t *)&be;
244 
245  for (j = 0; j < sizeof(uint32_t); j++) {
246  ret = snprintf(buf+offset, len, "%.02x", tmp[j]);
247  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
248  }
249 
250  ret = snprintf(buf+offset, len, "</data%d>", i);
251  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
252  }
253 
254  ret = snprintf(buf+offset, len, "</reg>");
255  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
256 
257  return offset;
258 }
259 
260 static int
261 nftnl_data_reg_value_snprintf_default(char *buf, size_t size,
262  union nftnl_data_reg *reg, uint32_t flags)
263 {
264  int len = size, offset = 0, ret, i;
265 
266  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
267  ret = snprintf(buf+offset, len, "0x%.8x ", reg->val[i]);
268  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
269  }
270 
271  return offset;
272 }
273 
274 static int
275 nftnl_data_reg_verdict_snprintf_def(char *buf, size_t size,
276  union nftnl_data_reg *reg, uint32_t flags)
277 {
278  int len = size, offset = 0, ret = 0;
279 
280  ret = snprintf(buf, size, "%s ", nftnl_verdict2str(reg->verdict));
281  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
282 
283  if (reg->chain != NULL) {
284  ret = snprintf(buf+offset, len, "-> %s ", reg->chain);
285  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
286  }
287 
288  return offset;
289 }
290 
291 static int
292 nftnl_data_reg_verdict_snprintf_xml(char *buf, size_t size,
293  union nftnl_data_reg *reg, uint32_t flags)
294 {
295  int len = size, offset = 0, ret = 0;
296 
297  ret = snprintf(buf, size, "<reg type=\"verdict\">"
298  "<verdict>%s</verdict>", nftnl_verdict2str(reg->verdict));
299  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
300 
301  if (reg->chain != NULL) {
302  ret = snprintf(buf+offset, len, "<chain>%s</chain>",
303  reg->chain);
304  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
305  }
306 
307  ret = snprintf(buf+offset, len, "</reg>");
308  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
309 
310  return offset;
311 }
312 
313 static int
314 nftnl_data_reg_verdict_snprintf_json(char *buf, size_t size,
315  union nftnl_data_reg *reg, uint32_t flags)
316 {
317  int len = size, offset = 0, ret = 0;
318 
319  ret = snprintf(buf, size, "\"reg\":{\"type\":\"verdict\","
320  "\"verdict\":\"%s\"", nftnl_verdict2str(reg->verdict));
321  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
322 
323  if (reg->chain != NULL) {
324  ret = snprintf(buf+offset, len, ",\"chain\":\"%s\"",
325  reg->chain);
326  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
327  }
328 
329  ret = snprintf(buf+offset, len, "}");
330  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
331 
332  return offset;
333 }
334 
335 int nftnl_data_reg_snprintf(char *buf, size_t size, union nftnl_data_reg *reg,
336  uint32_t output_format, uint32_t flags, int reg_type)
337 {
338  switch(reg_type) {
339  case DATA_VALUE:
340  switch(output_format) {
341  case NFTNL_OUTPUT_DEFAULT:
342  return nftnl_data_reg_value_snprintf_default(buf, size,
343  reg, flags);
344  case NFTNL_OUTPUT_XML:
345  return nftnl_data_reg_value_snprintf_xml(buf, size,
346  reg, flags);
347  case NFTNL_OUTPUT_JSON:
348  return nftnl_data_reg_value_snprintf_json(buf, size,
349  reg, flags);
350  default:
351  break;
352  }
353  case DATA_VERDICT:
354  case DATA_CHAIN:
355  switch(output_format) {
356  case NFTNL_OUTPUT_DEFAULT:
357  return nftnl_data_reg_verdict_snprintf_def(buf, size,
358  reg, flags);
359  case NFTNL_OUTPUT_XML:
360  return nftnl_data_reg_verdict_snprintf_xml(buf, size,
361  reg, flags);
362  case NFTNL_OUTPUT_JSON:
363  return nftnl_data_reg_verdict_snprintf_json(buf, size,
364  reg, flags);
365  default:
366  break;
367  }
368  default:
369  break;
370  }
371 
372  return -1;
373 }
374 
375 static int nftnl_data_parse_cb(const struct nlattr *attr, void *data)
376 {
377  const struct nlattr **tb = data;
378  int type = mnl_attr_get_type(attr);
379 
380  if (mnl_attr_type_valid(attr, NFTA_DATA_MAX) < 0)
381  return MNL_CB_OK;
382 
383  switch(type) {
384  case NFTA_DATA_VALUE:
385  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
386  abi_breakage();
387  break;
388  case NFTA_DATA_VERDICT:
389  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
390  abi_breakage();
391  break;
392  }
393  tb[type] = attr;
394  return MNL_CB_OK;
395 }
396 
397 static int nftnl_verdict_parse_cb(const struct nlattr *attr, void *data)
398 {
399  const struct nlattr **tb = data;
400  int type = mnl_attr_get_type(attr);
401 
402  if (mnl_attr_type_valid(attr, NFTA_VERDICT_MAX) < 0)
403  return MNL_CB_OK;
404 
405  switch(type) {
406  case NFTA_VERDICT_CODE:
407  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
408  abi_breakage();
409  break;
410  case NFTA_VERDICT_CHAIN:
411  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
412  abi_breakage();
413  break;
414  }
415  tb[type] = attr;
416  return MNL_CB_OK;
417 }
418 
419 static int
420 nftnl_parse_verdict(union nftnl_data_reg *data, const struct nlattr *attr, int *type)
421 {
422  struct nlattr *tb[NFTA_VERDICT_MAX+1];
423 
424  if (mnl_attr_parse_nested(attr, nftnl_verdict_parse_cb, tb) < 0) {
425  perror("mnl_attr_parse_nested");
426  return -1;
427  }
428 
429  if (!tb[NFTA_VERDICT_CODE])
430  return -1;
431 
432  data->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE]));
433 
434  switch(data->verdict) {
435  case NF_ACCEPT:
436  case NF_DROP:
437  case NF_QUEUE:
438  case NFT_CONTINUE:
439  case NFT_BREAK:
440  case NFT_RETURN:
441  if (type)
442  *type = DATA_VERDICT;
443  data->len = sizeof(data->verdict);
444  break;
445  case NFT_JUMP:
446  case NFT_GOTO:
447  if (!tb[NFTA_VERDICT_CHAIN])
448  return -1;
449 
450  data->chain = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN]));
451  if (type)
452  *type = DATA_CHAIN;
453  break;
454  default:
455  return -1;
456  }
457 
458  return 0;
459 }
460 
461 static int
462 __nftnl_parse_data(union nftnl_data_reg *data, const struct nlattr *attr)
463 {
464  void *orig = mnl_attr_get_payload(attr);
465  uint32_t data_len = mnl_attr_get_payload_len(attr);
466 
467  if (data_len == 0)
468  return -1;
469 
470  if (data_len > sizeof(data->val))
471  return -1;
472 
473  memcpy(data->val, orig, data_len);
474  data->len = data_len;
475 
476  return 0;
477 }
478 
479 int nftnl_parse_data(union nftnl_data_reg *data, struct nlattr *attr, int *type)
480 {
481  struct nlattr *tb[NFTA_DATA_MAX+1] = {};
482  int ret = 0;
483 
484  if (mnl_attr_parse_nested(attr, nftnl_data_parse_cb, tb) < 0) {
485  perror("mnl_attr_parse_nested");
486  return -1;
487  }
488  if (tb[NFTA_DATA_VALUE]) {
489  if (type)
490  *type = DATA_VALUE;
491 
492  ret = __nftnl_parse_data(data, tb[NFTA_DATA_VALUE]);
493  if (ret < 0)
494  return ret;
495  }
496  if (tb[NFTA_DATA_VERDICT])
497  ret = nftnl_parse_verdict(data, tb[NFTA_DATA_VERDICT], type);
498 
499  return ret;
500 }
501 
502 void nftnl_free_verdict(union nftnl_data_reg *data)
503 {
504  switch(data->verdict) {
505  case NFT_JUMP:
506  case NFT_GOTO:
507  xfree(data->chain);
508  break;
509  default:
510  break;
511  }
512 }