libnftnl  1.0.2
jansson.c
1 /*
2  * (C) 2013 by Álvaro Neira Ayuso <alvaroneay@gmail.com>
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 #include <stdlib.h>
12 #include <limits.h>
13 #include <stdint.h>
14 #include <stdbool.h>
15 #include <arpa/inet.h>
16 #include <errno.h>
17 #include <string.h>
18 #include "expr_ops.h"
19 #include <libnftnl/set.h>
20 
21 #include <libnftnl/expr.h>
22 #include <linux/netfilter/nf_tables.h>
23 
24 #ifdef JSON_PARSING
25 
26 static int nft_jansson_load_int_node(json_t *root, const char *node_name,
27  json_int_t *val, struct nft_parse_err *err)
28 {
29  json_t *node;
30 
31  node = json_object_get(root, node_name);
32  if (node == NULL) {
33  err->error = NFT_PARSE_EMISSINGNODE;
34  err->node_name = node_name;
35  errno = EINVAL;
36  return -1;
37  }
38 
39  if (!json_is_integer(node)) {
40  err->error = NFT_PARSE_EBADTYPE;
41  err->node_name = node_name;
42  errno = ERANGE;
43  return -1;
44  }
45  *val = json_integer_value(node);
46 
47  return 0;
48 }
49 
50 const char *nft_jansson_parse_str(json_t *root, const char *node_name,
51  struct nft_parse_err *err)
52 {
53  json_t *node;
54  const char *val;
55 
56  node = json_object_get(root, node_name);
57  if (node == NULL) {
58  err->error = NFT_PARSE_EMISSINGNODE;
59  err->node_name = node_name;
60  errno = EINVAL;
61  return NULL;
62  }
63 
64  val = json_string_value(node);
65  if (val == NULL) {
66  err->error = NFT_PARSE_EBADTYPE;
67  err->node_name = node_name;
68  }
69 
70  return val;
71 }
72 
73 int nft_jansson_parse_val(json_t *root, const char *node_name, int type,
74  void *out, struct nft_parse_err *err)
75 {
76  json_int_t val;
77 
78  if (nft_jansson_load_int_node(root, node_name, &val, err) == -1)
79  return -1;
80 
81  if (nft_get_value(type, &val, out) == -1)
82  return -1;
83 
84  return 0;
85 }
86 
87 bool nft_jansson_node_exist(json_t *root, const char *node_name)
88 {
89  return json_object_get(root, node_name) != NULL;
90 }
91 
92 json_t *nft_jansson_create_root(const void *json, json_error_t *error,
93  struct nft_parse_err *err, enum nft_parse_input input)
94 {
95  json_t *root;
96 
97  switch (input) {
98  case NFT_PARSE_BUFFER:
99  root = json_loadb(json, strlen(json), 0, error);
100  break;
101  case NFT_PARSE_FILE:
102  root = json_loadf((FILE *)json, 0, error);
103  break;
104  default:
105  goto err;
106  }
107 
108  if (root == NULL) {
109  err->error = NFT_PARSE_EBADINPUT;
110  err->line = error->line;
111  err->column = error->column;
112  err->node_name = error->source;
113  goto err;
114  }
115 
116  return root;
117 err:
118  errno = EINVAL;
119  return NULL;
120 }
121 
122 json_t *nft_jansson_get_node(json_t *root, const char *node_name,
123  struct nft_parse_err *err)
124 {
125  json_t *node;
126 
127  node = json_object_get(root, node_name);
128  if (node == NULL) {
129  err->error = NFT_PARSE_EMISSINGNODE;
130  err->node_name = node_name;
131  errno = EINVAL;
132  return NULL;
133  }
134 
135  return node;
136 }
137 
138 void nft_jansson_free_root(json_t *root)
139 {
140  json_decref(root);
141 }
142 
143 int nft_jansson_parse_family(json_t *root, void *out, struct nft_parse_err *err)
144 {
145  const char *str;
146  int family;
147 
148  str = nft_jansson_parse_str(root, "family", err);
149  if (str == NULL)
150  return -1;
151 
152  family = nft_str2family(str);
153  if (family < 0) {
154  err->node_name = "family";
155  errno = EINVAL;
156  return -1;
157  }
158 
159  memcpy(out, &family, sizeof(family));
160  return 0;
161 }
162 
163 int nft_jansson_parse_reg(json_t *root, const char *node_name, int type,
164  void *out, struct nft_parse_err *err)
165 {
166  if (nft_jansson_parse_val(root, node_name, type, out, err) < 0)
167  return -1;
168 
169  if (*((uint32_t *)out) > NFT_REG_MAX){
170  errno = ERANGE;
171  return -1;
172  }
173 
174  return 0;
175 }
176 
177 int nft_jansson_str2num(json_t *root, const char *node_name, int base,
178  void *out, enum nft_type type, struct nft_parse_err *err)
179 {
180  const char *str;
181 
182  str = nft_jansson_parse_str(root, node_name, err);
183  if (str == NULL)
184  return -1;
185 
186  return nft_strtoi(str, base, out, type);
187 }
188 
189 struct nft_rule_expr *nft_jansson_expr_parse(json_t *root,
190  struct nft_parse_err *err)
191 {
192  struct nft_rule_expr *e;
193  const char *type;
194  int ret;
195 
196  type = nft_jansson_parse_str(root, "type", err);
197  if (type == NULL)
198  return NULL;
199 
200  e = nft_rule_expr_alloc(type);
201  if (e == NULL) {
202  err->node_name = "type";
203  return NULL;
204  }
205 
206  ret = e->ops->json_parse(e, root, err);
207 
208  return ret < 0 ? NULL : e;
209 }
210 
211 int nft_jansson_data_reg_parse(json_t *root, const char *node_name,
212  union nft_data_reg *data_reg,
213  struct nft_parse_err *err)
214 {
215  json_t *data;
216  int ret;
217 
218  /* It is necessary for the compatibility with cmpdata label. */
219  data = json_object_get(root, node_name);
220  if (data == NULL)
221  data = root;
222 
223  data = json_object_get(data, "data_reg");
224  if (data == NULL) {
225  err->error = NFT_PARSE_EMISSINGNODE;
226  err->node_name = "data_reg";
227  errno = EINVAL;
228  return -1;
229  }
230 
231  ret = nft_data_reg_json_parse(data_reg, data, err);
232  if (ret == DATA_NONE) {
233  errno = EINVAL;
234  return -1;
235  }
236 
237  return ret;
238 }
239 
240 int nft_jansson_set_elem_parse(struct nft_set_elem *e, json_t *root,
241  struct nft_parse_err *err)
242 {
243  int set_elem_data;
244  uint32_t flags;
245 
246  if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U32, &flags, err) == 0)
247  nft_set_elem_attr_set_u32(e, NFT_SET_ELEM_ATTR_FLAGS, flags);
248 
249  if (nft_jansson_data_reg_parse(root, "key", &e->key, err) == DATA_VALUE)
250  e->flags |= (1 << NFT_SET_ELEM_ATTR_KEY);
251 
252  if (nft_jansson_node_exist(root, "data")) {
253  set_elem_data = nft_jansson_data_reg_parse(root, "data",
254  &e->data, err);
255  switch (set_elem_data) {
256  case DATA_VALUE:
257  e->flags |= (1 << NFT_SET_ELEM_ATTR_DATA);
258  break;
259  case DATA_VERDICT:
260  e->flags |= (1 << NFT_SET_ELEM_ATTR_VERDICT);
261  if (e->data.chain != NULL)
262  e->flags |= (1 << NFT_SET_ELEM_ATTR_CHAIN);
263  break;
264  case DATA_NONE:
265  default:
266  return -1;
267  }
268  }
269 
270  return 0;
271 }
272 #endif