libnftnl  1.0.8
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 const 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 nftnl_expr_byteorder_export(char *buf, size_t size,
238  const struct nftnl_expr *e, int type)
239 {
240  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
241  NFTNL_BUF_INIT(b, buf, size);
242 
243  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SREG))
244  nftnl_buf_u32(&b, type, byteorder->sreg, SREG);
245  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_DREG))
246  nftnl_buf_u32(&b, type, byteorder->dreg, DREG);
247  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_OP))
248  nftnl_buf_str(&b, type, bo2str(byteorder->op), OP);
249  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_LEN))
250  nftnl_buf_u32(&b, type, byteorder->len, LEN);
251  if (e->flags & (1 << NFTNL_EXPR_BYTEORDER_SIZE))
252  nftnl_buf_u32(&b, type, byteorder->size, SIZE);
253 
254  return nftnl_buf_done(&b);
255 }
256 
257 static int nftnl_expr_byteorder_snprintf_default(char *buf, size_t size,
258  const struct nftnl_expr *e)
259 {
260  struct nftnl_expr_byteorder *byteorder = nftnl_expr_data(e);
261  int remain = size, offset = 0, ret;
262 
263  ret = snprintf(buf, remain, "reg %u = %s(reg %u, %u, %u) ",
264  byteorder->dreg, bo2str(byteorder->op),
265  byteorder->sreg, byteorder->size, byteorder->len);
266  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
267 
268  return offset;
269 }
270 
271 static int
272 nftnl_expr_byteorder_snprintf(char *buf, size_t size, uint32_t type,
273  uint32_t flags, const struct nftnl_expr *e)
274 {
275  switch (type) {
276  case NFTNL_OUTPUT_DEFAULT:
277  return nftnl_expr_byteorder_snprintf_default(buf, size, e);
278  case NFTNL_OUTPUT_XML:
279  case NFTNL_OUTPUT_JSON:
280  return nftnl_expr_byteorder_export(buf, size, e, type);
281  default:
282  break;
283  }
284  return -1;
285 }
286 
287 static bool nftnl_expr_byteorder_cmp(const struct nftnl_expr *e1,
288  const struct nftnl_expr *e2)
289 {
290  struct nftnl_expr_byteorder *b1 = nftnl_expr_data(e1);
291  struct nftnl_expr_byteorder *b2 = nftnl_expr_data(e2);
292  bool eq = true;
293 
294  if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_SREG))
295  eq &= (b1->sreg == b2->sreg);
296  if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_DREG))
297  eq &= (b1->dreg == b2->dreg);
298  if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_OP))
299  eq &= (b1->op == b2->op);
300  if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_LEN))
301  eq &= (b1->len == b2->len);
302  if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_SIZE))
303  eq &= (b1->size == b2->size);
304 
305  return eq;
306 }
307 
308 struct expr_ops expr_ops_byteorder = {
309  .name = "byteorder",
310  .alloc_len = sizeof(struct nftnl_expr_byteorder),
311  .max_attr = NFTA_BYTEORDER_MAX,
312  .cmp = nftnl_expr_byteorder_cmp,
313  .set = nftnl_expr_byteorder_set,
314  .get = nftnl_expr_byteorder_get,
315  .parse = nftnl_expr_byteorder_parse,
316  .build = nftnl_expr_byteorder_build,
317  .snprintf = nftnl_expr_byteorder_snprintf,
318  .json_parse = nftnl_expr_byteorder_json_parse,
319 };