libnftnl  1.0.6
byteorder.c
1 /*
2  * (C) 2012-2013 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 "internal.h"
13 
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h> /* for memcpy */
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <libmnl/libmnl.h>
20 #include <linux/netfilter/nf_tables.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
23 
25  enum nft_registers sreg;
26  enum nft_registers dreg;
27  enum nft_byteorder_ops op;
28  unsigned int len;
29  unsigned int size;
30 };
31 
32 static int
33 nftnl_expr_byteorder_set(struct nftnl_expr *e, uint16_t type,
34  const void *data, uint32_t data_len)
35 {
36  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
37 
38  switch(type) {
39  case NFTNL_EXPR_BYTEORDER_SREG:
40  byteorder->sreg = *((uint32_t *)data);
41  break;
42  case NFTNL_EXPR_BYTEORDER_DREG:
43  byteorder->dreg = *((uint32_t *)data);
44  break;
45  case NFTNL_EXPR_BYTEORDER_OP:
46  byteorder->op = *((uint32_t *)data);
47  break;
48  case NFTNL_EXPR_BYTEORDER_LEN:
49  byteorder->len = *((unsigned int *)data);
50  break;
51  case NFTNL_EXPR_BYTEORDER_SIZE:
52  byteorder->size = *((unsigned int *)data);
53  break;
54  default:
55  return -1;
56  }
57  return 0;
58 }
59 
60 static const void *
61 nftnl_expr_byteorder_get(const struct nftnl_expr *e, uint16_t type,
62  uint32_t *data_len)
63 {
64  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
65 
66  switch(type) {
67  case NFTNL_EXPR_BYTEORDER_SREG:
68  *data_len = sizeof(byteorder->sreg);
69  return &byteorder->sreg;
70  case NFTNL_EXPR_BYTEORDER_DREG:
71  *data_len = sizeof(byteorder->dreg);
72  return &byteorder->dreg;
73  case NFTNL_EXPR_BYTEORDER_OP:
74  *data_len = sizeof(byteorder->op);
75  return &byteorder->op;
76  case NFTNL_EXPR_BYTEORDER_LEN:
77  *data_len = sizeof(byteorder->len);
78  return &byteorder->len;
79  case NFTNL_EXPR_BYTEORDER_SIZE:
80  *data_len = sizeof(byteorder->size);
81  return &byteorder->size;
82  }
83  return NULL;
84 }
85 
86 static int nftnl_expr_byteorder_cb(const struct nlattr *attr, void *data)
87 {
88  const struct nlattr **tb = data;
89  int type = mnl_attr_get_type(attr);
90 
91  if (mnl_attr_type_valid(attr, NFTA_BYTEORDER_MAX) < 0)
92  return MNL_CB_OK;
93 
94  switch(type) {
95  case NFTA_BYTEORDER_SREG:
96  case NFTA_BYTEORDER_DREG:
97  case NFTA_BYTEORDER_OP:
98  case NFTA_BYTEORDER_LEN:
99  case NFTA_BYTEORDER_SIZE:
100  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
101  abi_breakage();
102  break;
103  }
104 
105  tb[type] = attr;
106  return MNL_CB_OK;
107 }
108 
109 static void
110 nftnl_expr_byteorder_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
111 {
112  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
113 
114  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SREG)) {
115  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_SREG,
116  htonl(byteorder->sreg));
117  }
118  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_DREG)) {
119  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_DREG,
120  htonl(byteorder->dreg));
121  }
122  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_OP)) {
123  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_OP,
124  htonl(byteorder->op));
125  }
126  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_LEN)) {
127  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_LEN,
128  htonl(byteorder->len));
129  }
130  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SIZE)) {
131  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_SIZE,
132  htonl(byteorder->size));
133  }
134 }
135 
136 static int
137 nftnl_expr_byteorder_parse(struct nftnl_expr *e, struct nlattr *attr)
138 {
139  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
140  struct nlattr *tb[NFTA_BYTEORDER_MAX+1] = {};
141  int ret = 0;
142 
143  if (mnl_attr_parse_nested(attr, nftnl_expr_byteorder_cb, tb) < 0)
144  return -1;
145 
146  if (tb[NFTA_BYTEORDER_SREG]) {
147  byteorder->sreg =
148  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_SREG]));
149  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_SREG);
150  }
151  if (tb[NFTA_BYTEORDER_DREG]) {
152  byteorder->dreg =
153  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_DREG]));
154  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_DREG);
155  }
156  if (tb[NFTA_BYTEORDER_OP]) {
157  byteorder->op =
158  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_OP]));
159  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_OP);
160  }
161  if (tb[NFTA_BYTEORDER_LEN]) {
162  byteorder->len =
163  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_LEN]));
164  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_LEN);
165  }
166  if (tb[NFTA_BYTEORDER_SIZE]) {
167  byteorder->size =
168  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_SIZE]));
169  e->flags |= (1 << NFTNL_EXPR_BYTEORDER_SIZE);
170  }
171 
172  return ret;
173 }
174 
175 static char *expr_byteorder_str[] = {
176  [NFT_BYTEORDER_HTON] = "hton",
177  [NFT_BYTEORDER_NTOH] = "ntoh",
178 };
179 
180 static const char *bo2str(uint32_t type)
181 {
182  if (type > NFT_BYTEORDER_HTON)
183  return "unknown";
184 
185  return expr_byteorder_str[type];
186 }
187 
188 static inline int nftnl_str2ntoh(const char *op)
189 {
190  if (strcmp(op, "ntoh") == 0)
191  return NFT_BYTEORDER_NTOH;
192  else if (strcmp(op, "hton") == 0)
193  return NFT_BYTEORDER_HTON;
194  else {
195  errno = EINVAL;
196  return -1;
197  }
198 }
199 
200 static int
201 nftnl_expr_byteorder_json_parse(struct nftnl_expr *e, json_t *root,
202  struct nftnl_parse_err *err)
203 {
204 #ifdef JSON_PARSING
205  const char *op;
206  uint32_t sreg, dreg, len, size;
207  int ntoh;
208 
209  if (nftnl_jansson_parse_reg(root, "sreg", NFTNL_TYPE_U32, &sreg, err) == 0)
210  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_SREG, sreg);
211 
212  if (nftnl_jansson_parse_reg(root, "dreg", NFTNL_TYPE_U32, &dreg, err) == 0)
213  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_DREG, dreg);
214 
215  op = nftnl_jansson_parse_str(root, "op", err);
216  if (op != NULL) {
217  ntoh = nftnl_str2ntoh(op);
218  if (ntoh < 0)
219  return -1;
220 
221  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_OP, ntoh);
222  }
223 
224  if (nftnl_jansson_parse_val(root, "len", NFTNL_TYPE_U32, &len, err) == 0)
225  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_LEN, len);
226 
227  if (nftnl_jansson_parse_val(root, "size", NFTNL_TYPE_U32, &size, err) == 0)
228  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_SIZE, size);
229 
230  return 0;
231 #else
232  errno = EOPNOTSUPP;
233  return -1;
234 #endif
235 }
236 
237 static int
238 nftnl_expr_byteorder_xml_parse(struct nftnl_expr *e, mxml_node_t *tree,
239  struct nftnl_parse_err *err)
240 {
241 #ifdef XML_PARSING
242  const char *op;
243  int32_t ntoh;
244  uint32_t sreg, dreg, len, size;
245 
246  if (nftnl_mxml_reg_parse(tree, "sreg", &sreg, MXML_DESCEND_FIRST,
247  NFTNL_XML_MAND, err) == 0)
248  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_SREG, sreg);
249 
250  if (nftnl_mxml_reg_parse(tree, "dreg", &dreg, MXML_DESCEND, NFTNL_XML_MAND,
251  err) == 0)
252  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_DREG, dreg);
253 
254  op = nftnl_mxml_str_parse(tree, "op", MXML_DESCEND_FIRST, NFTNL_XML_MAND,
255  err);
256  if (op != NULL) {
257  ntoh = nftnl_str2ntoh(op);
258  if (ntoh < 0)
259  return -1;
260 
261  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_OP, ntoh);
262  }
263 
264  if (nftnl_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
265  &len, NFTNL_TYPE_U32, NFTNL_XML_MAND, err) == 0)
266  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_LEN, len);
267 
268  if (nftnl_mxml_num_parse(tree, "size", MXML_DESCEND_FIRST, BASE_DEC,
269  &size, NFTNL_TYPE_U32, NFTNL_XML_MAND, err) == 0)
270  nftnl_expr_set_u32(e, NFTNL_EXPR_BYTEORDER_SIZE, size);
271 
272  return 0;
273 #else
274  errno = EOPNOTSUPP;
275  return -1;
276 #endif
277 }
278 
279 static int nftnl_expr_byteorder_export(char *buf, size_t size,
280  const struct nftnl_expr *e, int type)
281 {
282  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
283  NFTNL_BUF_INIT(b, buf, size);
284 
285  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SREG))
286  nftnl_buf_u32(&b, type, byteorder->sreg, SREG);
287  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_DREG))
288  nftnl_buf_u32(&b, type, byteorder->dreg, DREG);
289  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_OP))
290  nftnl_buf_str(&b, type, bo2str(byteorder->op), OP);
291  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_LEN))
292  nftnl_buf_u32(&b, type, byteorder->len, LEN);
293  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SIZE))
294  nftnl_buf_u32(&b, type, byteorder->size, SIZE);
295 
296  return nftnl_buf_done(&b);
297 }
298 
299 static int nftnl_expr_byteorder_snprintf_default(char *buf, size_t size,
300  const struct nftnl_expr *e)
301 {
302  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
303  int len = size, offset = 0, ret;
304 
305  ret = snprintf(buf, len, "reg %u = %s(reg %u, %u, %u) ",
306  byteorder->dreg, bo2str(byteorder->op),
307  byteorder->sreg, byteorder->size, byteorder->len);
308  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
309 
310  return offset;
311 }
312 
313 static int
314 nftnl_expr_byteorder_snprintf(char *buf, size_t size, uint32_t type,
315  uint32_t flags, const struct nftnl_expr *e)
316 {
317  switch (type) {
318  case NFTNL_OUTPUT_DEFAULT:
319  return nftnl_expr_byteorder_snprintf_default(buf, size, e);
320  case NFTNL_OUTPUT_XML:
321  case NFTNL_OUTPUT_JSON:
322  return nftnl_expr_byteorder_export(buf, size, e, type);
323  default:
324  break;
325  }
326  return -1;
327 }
328 
329 struct expr_ops expr_ops_byteorder = {
330  .name = "byteorder",
331  .alloc_len = sizeof(struct nftnl_expr_byteorder),
332  .max_attr = NFTA_BYTEORDER_MAX,
333  .set = nftnl_expr_byteorder_set,
334  .get = nftnl_expr_byteorder_get,
335  .parse = nftnl_expr_byteorder_parse,
336  .build = nftnl_expr_byteorder_build,
337  .snprintf = nftnl_expr_byteorder_snprintf,
338  .xml_parse = nftnl_expr_byteorder_xml_parse,
339  .json_parse = nftnl_expr_byteorder_json_parse,
340 };