libnftnl  1.0.2
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 #include "data_reg.h"
24 #include "expr_ops.h"
25 
27  enum nft_registers sreg;
28  enum nft_registers dreg;
29  enum nft_byteorder_ops op;
30  unsigned int len;
31  unsigned int size;
32 };
33 
34 static int
35 nft_rule_expr_byteorder_set(struct nft_rule_expr *e, uint16_t type,
36  const void *data, uint32_t data_len)
37 {
38  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
39 
40  switch(type) {
41  case NFT_EXPR_BYTEORDER_SREG:
42  byteorder->sreg = *((uint32_t *)data);
43  break;
44  case NFT_EXPR_BYTEORDER_DREG:
45  byteorder->dreg = *((uint32_t *)data);
46  break;
47  case NFT_EXPR_BYTEORDER_OP:
48  byteorder->op = *((uint32_t *)data);
49  break;
50  case NFT_EXPR_BYTEORDER_LEN:
51  byteorder->len = *((unsigned int *)data);
52  break;
53  case NFT_EXPR_BYTEORDER_SIZE:
54  byteorder->size = *((unsigned int *)data);
55  break;
56  default:
57  return -1;
58  }
59  return 0;
60 }
61 
62 static const void *
63 nft_rule_expr_byteorder_get(const struct nft_rule_expr *e, uint16_t type,
64  uint32_t *data_len)
65 {
66  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
67 
68  switch(type) {
69  case NFT_EXPR_BYTEORDER_SREG:
70  *data_len = sizeof(byteorder->sreg);
71  return &byteorder->sreg;
72  case NFT_EXPR_BYTEORDER_DREG:
73  *data_len = sizeof(byteorder->dreg);
74  return &byteorder->dreg;
75  case NFT_EXPR_BYTEORDER_OP:
76  *data_len = sizeof(byteorder->op);
77  return &byteorder->op;
78  case NFT_EXPR_BYTEORDER_LEN:
79  *data_len = sizeof(byteorder->len);
80  return &byteorder->len;
81  case NFT_EXPR_BYTEORDER_SIZE:
82  *data_len = sizeof(byteorder->size);
83  return &byteorder->size;
84  }
85  return NULL;
86 }
87 
88 static int nft_rule_expr_byteorder_cb(const struct nlattr *attr, void *data)
89 {
90  const struct nlattr **tb = data;
91  int type = mnl_attr_get_type(attr);
92 
93  if (mnl_attr_type_valid(attr, NFTA_BYTEORDER_MAX) < 0)
94  return MNL_CB_OK;
95 
96  switch(type) {
97  case NFTA_BYTEORDER_SREG:
98  case NFTA_BYTEORDER_DREG:
99  case NFTA_BYTEORDER_OP:
100  case NFTA_BYTEORDER_LEN:
101  case NFTA_BYTEORDER_SIZE:
102  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
103  perror("mnl_attr_validate");
104  return MNL_CB_ERROR;
105  }
106  break;
107  }
108 
109  tb[type] = attr;
110  return MNL_CB_OK;
111 }
112 
113 static void
114 nft_rule_expr_byteorder_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
115 {
116  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
117 
118  if (e->flags & (1 << NFT_EXPR_BYTEORDER_SREG)) {
119  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_SREG,
120  htonl(byteorder->sreg));
121  }
122  if (e->flags & (1 << NFT_EXPR_BYTEORDER_DREG)) {
123  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_DREG,
124  htonl(byteorder->dreg));
125  }
126  if (e->flags & (1 << NFT_EXPR_BYTEORDER_OP)) {
127  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_OP,
128  htonl(byteorder->op));
129  }
130  if (e->flags & (1 << NFT_EXPR_BYTEORDER_LEN)) {
131  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_LEN,
132  htonl(byteorder->len));
133  }
134  if (e->flags & (1 << NFT_EXPR_BYTEORDER_SIZE)) {
135  mnl_attr_put_u32(nlh, NFTA_BYTEORDER_SIZE,
136  htonl(byteorder->size));
137  }
138 }
139 
140 static int
141 nft_rule_expr_byteorder_parse(struct nft_rule_expr *e, struct nlattr *attr)
142 {
143  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
144  struct nlattr *tb[NFTA_BYTEORDER_MAX+1] = {};
145  int ret = 0;
146 
147  if (mnl_attr_parse_nested(attr, nft_rule_expr_byteorder_cb, tb) < 0)
148  return -1;
149 
150  if (tb[NFTA_BYTEORDER_SREG]) {
151  byteorder->sreg =
152  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_SREG]));
153  e->flags |= (1 << NFT_EXPR_BYTEORDER_SREG);
154  }
155  if (tb[NFTA_BYTEORDER_DREG]) {
156  byteorder->dreg =
157  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_DREG]));
158  e->flags |= (1 << NFT_EXPR_BYTEORDER_DREG);
159  }
160  if (tb[NFTA_BYTEORDER_OP]) {
161  byteorder->op =
162  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_OP]));
163  e->flags |= (1 << NFT_EXPR_BYTEORDER_OP);
164  }
165  if (tb[NFTA_BYTEORDER_LEN]) {
166  byteorder->len =
167  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_LEN]));
168  e->flags |= (1 << NFT_EXPR_BYTEORDER_LEN);
169  }
170  if (tb[NFTA_BYTEORDER_SIZE]) {
171  byteorder->size =
172  ntohl(mnl_attr_get_u32(tb[NFTA_BYTEORDER_SIZE]));
173  e->flags |= (1 << NFT_EXPR_BYTEORDER_SIZE);
174  }
175 
176  return ret;
177 }
178 
179 static char *expr_byteorder_str[] = {
180  [NFT_BYTEORDER_HTON] = "hton",
181  [NFT_BYTEORDER_NTOH] = "ntoh",
182 };
183 
184 static inline int nft_str2ntoh(const char *op)
185 {
186  if (strcmp(op, "ntoh") == 0)
187  return NFT_BYTEORDER_NTOH;
188  else if (strcmp(op, "hton") == 0)
189  return NFT_BYTEORDER_HTON;
190  else {
191  errno = EINVAL;
192  return -1;
193  }
194 }
195 
196 static int
197 nft_rule_expr_byteorder_json_parse(struct nft_rule_expr *e, json_t *root,
198  struct nft_parse_err *err)
199 {
200 #ifdef JSON_PARSING
201  const char *op;
202  uint32_t sreg, dreg, len, size;
203  int ntoh;
204 
205  if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &sreg, err) == 0)
206  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_SREG, sreg);
207 
208  if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &dreg, err) == 0)
209  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_DREG, dreg);
210 
211  op = nft_jansson_parse_str(root, "op", err);
212  if (op != NULL) {
213  ntoh = nft_str2ntoh(op);
214  if (ntoh < 0)
215  return -1;
216 
217  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_OP, ntoh);
218  }
219 
220  if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &len, err) == 0)
221  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_LEN, len);
222 
223  if (nft_jansson_parse_val(root, "size", NFT_TYPE_U32, &size, err) == 0)
224  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_SIZE, size);
225 
226  return 0;
227 #else
228  errno = EOPNOTSUPP;
229  return -1;
230 #endif
231 }
232 
233 static int
234 nft_rule_expr_byteorder_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
235  struct nft_parse_err *err)
236 {
237 #ifdef XML_PARSING
238  const char *op;
239  int32_t ntoh;
240  uint32_t sreg, dreg, len, size;
241 
242  if (nft_mxml_reg_parse(tree, "sreg", &sreg, MXML_DESCEND_FIRST,
243  NFT_XML_MAND, err) == 0)
244  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_SREG, sreg);
245 
246  if (nft_mxml_reg_parse(tree, "dreg", &dreg, MXML_DESCEND, NFT_XML_MAND,
247  err) == 0)
248  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_DREG, dreg);
249 
250  op = nft_mxml_str_parse(tree, "op", MXML_DESCEND_FIRST, NFT_XML_MAND,
251  err);
252  if (op != NULL) {
253  ntoh = nft_str2ntoh(op);
254  if (ntoh < 0)
255  return -1;
256 
257  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_OP, ntoh);
258  }
259 
260  if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
261  &len, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
262  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_LEN, len);
263 
264  if (nft_mxml_num_parse(tree, "size", MXML_DESCEND_FIRST, BASE_DEC,
265  &size, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
266  nft_rule_expr_set_u32(e, NFT_EXPR_BYTEORDER_SIZE, size);
267 
268  return 0;
269 #else
270  errno = EOPNOTSUPP;
271  return -1;
272 #endif
273 }
274 
275 static int nft_rule_expr_byteorder_snprintf_json(char *buf, size_t size,
276  struct nft_rule_expr *e)
277 {
278  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
279  int len = size, offset = 0, ret;
280 
281  if (e->flags & (1 << NFT_EXPR_BYTEORDER_SREG)) {
282  ret = snprintf(buf + offset, len, "\"sreg\":%u,",
283  byteorder->sreg);
284  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
285  }
286  if (e->flags & (1 << NFT_EXPR_BYTEORDER_DREG)) {
287  ret = snprintf(buf + offset, len, "\"dreg\":%u,",
288  byteorder->dreg);
289  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
290  }
291  if (e->flags & (1 << NFT_EXPR_BYTEORDER_OP)) {
292  ret = snprintf(buf + offset, len, "\"op\":\"%s\",",
293  expr_byteorder_str[byteorder->op]);
294  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
295  }
296  if (e->flags & (1 << NFT_EXPR_BYTEORDER_LEN)) {
297  ret = snprintf(buf + offset, len, "\"len\":%u,",
298  byteorder->len);
299  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
300  }
301  if (e->flags & (1 << NFT_EXPR_BYTEORDER_SIZE)) {
302  ret = snprintf(buf + offset, len, "\"size\":%u,",
303  byteorder->size);
304  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
305  }
306 
307  if (offset > 0)
308  offset--;
309 
310  return offset;
311 }
312 
313 static int nft_rule_expr_byteorder_snprintf_xml(char *buf, size_t size,
314  struct nft_rule_expr *e)
315 {
316  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
317  int len = size, offset = 0, ret;
318 
319  if (e->flags & (1 << NFT_EXPR_BYTEORDER_SREG)) {
320  ret = snprintf(buf + offset, len, "<sreg>%u</sreg>",
321  byteorder->sreg);
322  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
323  }
324  if (e->flags & (1 << NFT_EXPR_BYTEORDER_DREG)) {
325  ret = snprintf(buf + offset, len, "<dreg>%u</dreg>",
326  byteorder->dreg);
327  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
328  }
329  if (e->flags & (1 << NFT_EXPR_BYTEORDER_OP)) {
330  ret = snprintf(buf + offset, len, "<op>%s</op>",
331  expr_byteorder_str[byteorder->op]);
332  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
333  }
334  if (e->flags & (1 << NFT_EXPR_BYTEORDER_LEN)) {
335  ret = snprintf(buf + offset, len, "<len>%u</len>",
336  byteorder->len);
337  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
338  }
339  if (e->flags & (1 << NFT_EXPR_BYTEORDER_SIZE)) {
340  ret = snprintf(buf + offset, len, "<size>%u</size>",
341  byteorder->size);
342  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
343  }
344 
345  return offset;
346 }
347 
348 static int nft_rule_expr_byteorder_snprintf_default(char *buf, size_t size,
349  struct nft_rule_expr *e)
350 {
351  struct nft_expr_byteorder *byteorder = nft_expr_data(e);
352  int len = size, offset = 0, ret;
353 
354  ret = snprintf(buf, len, "reg %u = %s(reg %u, %u, %u) ",
355  byteorder->dreg, expr_byteorder_str[byteorder->op],
356  byteorder->sreg, byteorder->size, byteorder->len);
357  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
358 
359  return offset;
360 }
361 
362 static int
363 nft_rule_expr_byteorder_snprintf(char *buf, size_t size, uint32_t type,
364  uint32_t flags, struct nft_rule_expr *e)
365 {
366  switch(type) {
367  case NFT_OUTPUT_DEFAULT:
368  return nft_rule_expr_byteorder_snprintf_default(buf, size, e);
369  case NFT_OUTPUT_XML:
370  return nft_rule_expr_byteorder_snprintf_xml(buf, size, e);
371  case NFT_OUTPUT_JSON:
372  return nft_rule_expr_byteorder_snprintf_json(buf, size, e);
373  default:
374  break;
375  }
376  return -1;
377 }
378 
379 struct expr_ops expr_ops_byteorder = {
380  .name = "byteorder",
381  .alloc_len = sizeof(struct nft_expr_byteorder),
382  .max_attr = NFTA_BYTEORDER_MAX,
383  .set = nft_rule_expr_byteorder_set,
384  .get = nft_rule_expr_byteorder_get,
385  .parse = nft_rule_expr_byteorder_parse,
386  .build = nft_rule_expr_byteorder_build,
387  .snprintf = nft_rule_expr_byteorder_snprintf,
388  .xml_parse = nft_rule_expr_byteorder_xml_parse,
389  .json_parse = nft_rule_expr_byteorder_json_parse,
390 };
391 
392 static void __init expr_byteorder_init(void)
393 {
394  nft_expr_ops_register(&expr_ops_byteorder);
395 }