libnftnl  1.0.8
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 static int
100 nftnl_data_reg_value_snprintf_json(char *buf, size_t size,
101  const union nftnl_data_reg *reg,
102  uint32_t flags)
103 {
104  int remain = size, offset = 0, ret, i, j;
105  uint32_t utemp;
106  uint8_t *tmp;
107 
108  ret = snprintf(buf, remain, "\"reg\":{\"type\":\"value\",");
109  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
110 
111  ret = snprintf(buf + offset, remain, "\"len\":%u,", reg->len);
112  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
113 
114  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
115  ret = snprintf(buf + offset, remain, "\"data%d\":\"0x", i);
116  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
117 
118  utemp = htonl(reg->val[i]);
119  tmp = (uint8_t *)&utemp;
120 
121  for (j = 0; j<sizeof(uint32_t); j++) {
122  ret = snprintf(buf + offset, remain, "%.02x", tmp[j]);
123  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
124  }
125 
126  ret = snprintf(buf + offset, remain, "\",");
127  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
128  }
129  offset--;
130  ret = snprintf(buf + offset, remain, "}");
131  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
132 
133  return offset;
134 }
135 
136 static int
137 nftnl_data_reg_value_snprintf_default(char *buf, size_t size,
138  const union nftnl_data_reg *reg,
139  uint32_t flags)
140 {
141  int remain = size, offset = 0, ret, i;
142 
143  for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) {
144  ret = snprintf(buf + offset, remain, "0x%.8x ", reg->val[i]);
145  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
146  }
147 
148  return offset;
149 }
150 
151 static int
152 nftnl_data_reg_verdict_snprintf_def(char *buf, size_t size,
153  const union nftnl_data_reg *reg,
154  uint32_t flags)
155 {
156  int remain = size, offset = 0, ret = 0;
157 
158  ret = snprintf(buf, size, "%s ", nftnl_verdict2str(reg->verdict));
159  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
160 
161  if (reg->chain != NULL) {
162  ret = snprintf(buf + offset, remain, "-> %s ", reg->chain);
163  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
164  }
165 
166  return offset;
167 }
168 
169 static int
170 nftnl_data_reg_verdict_snprintf_json(char *buf, size_t size,
171  const union nftnl_data_reg *reg,
172  uint32_t flags)
173 {
174  int remain = size, offset = 0, ret = 0;
175 
176  ret = snprintf(buf, size, "\"reg\":{\"type\":\"verdict\","
177  "\"verdict\":\"%s\"", nftnl_verdict2str(reg->verdict));
178  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
179 
180  if (reg->chain != NULL) {
181  ret = snprintf(buf + offset, remain, ",\"chain\":\"%s\"",
182  reg->chain);
183  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
184  }
185 
186  ret = snprintf(buf + offset, remain, "}");
187  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
188 
189  return offset;
190 }
191 
192 int nftnl_data_reg_snprintf(char *buf, size_t size,
193  const union nftnl_data_reg *reg,
194  uint32_t output_format, uint32_t flags,
195  int reg_type)
196 {
197  switch(reg_type) {
198  case DATA_VALUE:
199  switch(output_format) {
200  case NFTNL_OUTPUT_DEFAULT:
201  return nftnl_data_reg_value_snprintf_default(buf, size,
202  reg, flags);
203  case NFTNL_OUTPUT_JSON:
204  return nftnl_data_reg_value_snprintf_json(buf, size,
205  reg, flags);
206  case NFTNL_OUTPUT_XML:
207  default:
208  break;
209  }
210  case DATA_VERDICT:
211  case DATA_CHAIN:
212  switch(output_format) {
213  case NFTNL_OUTPUT_DEFAULT:
214  return nftnl_data_reg_verdict_snprintf_def(buf, size,
215  reg, flags);
216  case NFTNL_OUTPUT_JSON:
217  return nftnl_data_reg_verdict_snprintf_json(buf, size,
218  reg, flags);
219  case NFTNL_OUTPUT_XML:
220  default:
221  break;
222  }
223  default:
224  break;
225  }
226 
227  return -1;
228 }
229 
230 bool nftnl_data_reg_cmp(const union nftnl_data_reg *r1,
231  const union nftnl_data_reg *r2, int reg_type)
232 {
233  switch (reg_type) {
234  case DATA_VALUE:
235  return r1->len == r2->len &&
236  !memcmp(r1->val, r2->val, r1->len);
237  case DATA_VERDICT:
238  return r1->verdict == r2->verdict;
239  case DATA_CHAIN:
240  return r1->verdict == r2->verdict &&
241  !strcmp(r1->chain, r2->chain);
242  default:
243  return false;
244  }
245 }
246 
247 static int nftnl_data_parse_cb(const struct nlattr *attr, void *data)
248 {
249  const struct nlattr **tb = data;
250  int type = mnl_attr_get_type(attr);
251 
252  if (mnl_attr_type_valid(attr, NFTA_DATA_MAX) < 0)
253  return MNL_CB_OK;
254 
255  switch(type) {
256  case NFTA_DATA_VALUE:
257  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
258  abi_breakage();
259  break;
260  case NFTA_DATA_VERDICT:
261  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
262  abi_breakage();
263  break;
264  }
265  tb[type] = attr;
266  return MNL_CB_OK;
267 }
268 
269 static int nftnl_verdict_parse_cb(const struct nlattr *attr, void *data)
270 {
271  const struct nlattr **tb = data;
272  int type = mnl_attr_get_type(attr);
273 
274  if (mnl_attr_type_valid(attr, NFTA_VERDICT_MAX) < 0)
275  return MNL_CB_OK;
276 
277  switch(type) {
278  case NFTA_VERDICT_CODE:
279  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
280  abi_breakage();
281  break;
282  case NFTA_VERDICT_CHAIN:
283  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
284  abi_breakage();
285  break;
286  }
287  tb[type] = attr;
288  return MNL_CB_OK;
289 }
290 
291 static int
292 nftnl_parse_verdict(union nftnl_data_reg *data, const struct nlattr *attr, int *type)
293 {
294  struct nlattr *tb[NFTA_VERDICT_MAX+1];
295 
296  if (mnl_attr_parse_nested(attr, nftnl_verdict_parse_cb, tb) < 0)
297  return -1;
298 
299  if (!tb[NFTA_VERDICT_CODE])
300  return -1;
301 
302  data->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE]));
303 
304  switch(data->verdict) {
305  case NF_ACCEPT:
306  case NF_DROP:
307  case NF_QUEUE:
308  case NFT_CONTINUE:
309  case NFT_BREAK:
310  case NFT_RETURN:
311  if (type)
312  *type = DATA_VERDICT;
313  data->len = sizeof(data->verdict);
314  break;
315  case NFT_JUMP:
316  case NFT_GOTO:
317  if (!tb[NFTA_VERDICT_CHAIN])
318  return -1;
319 
320  data->chain = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN]));
321  if (!data->chain)
322  return -1;
323 
324  if (type)
325  *type = DATA_CHAIN;
326  break;
327  default:
328  return -1;
329  }
330 
331  return 0;
332 }
333 
334 static int
335 __nftnl_parse_data(union nftnl_data_reg *data, const struct nlattr *attr)
336 {
337  void *orig = mnl_attr_get_payload(attr);
338  uint32_t data_len = mnl_attr_get_payload_len(attr);
339 
340  if (data_len == 0)
341  return -1;
342 
343  if (data_len > sizeof(data->val))
344  return -1;
345 
346  memcpy(data->val, orig, data_len);
347  data->len = data_len;
348 
349  return 0;
350 }
351 
352 int nftnl_parse_data(union nftnl_data_reg *data, struct nlattr *attr, int *type)
353 {
354  struct nlattr *tb[NFTA_DATA_MAX+1] = {};
355  int ret = 0;
356 
357  if (mnl_attr_parse_nested(attr, nftnl_data_parse_cb, tb) < 0)
358  return -1;
359 
360  if (tb[NFTA_DATA_VALUE]) {
361  if (type)
362  *type = DATA_VALUE;
363 
364  ret = __nftnl_parse_data(data, tb[NFTA_DATA_VALUE]);
365  if (ret < 0)
366  return ret;
367  }
368  if (tb[NFTA_DATA_VERDICT])
369  ret = nftnl_parse_verdict(data, tb[NFTA_DATA_VERDICT], type);
370 
371  return ret;
372 }
373 
374 void nftnl_free_verdict(const union nftnl_data_reg *data)
375 {
376  switch(data->verdict) {
377  case NFT_JUMP:
378  case NFT_GOTO:
379  xfree(data->chain);
380  break;
381  default:
382  break;
383  }
384 }