libnftnl  1.0.2
bitwise.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 "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  unsigned int len;
30  union nft_data_reg mask;
31  union nft_data_reg xor;
32 };
33 
34 static int
35 nft_rule_expr_bitwise_set(struct nft_rule_expr *e, uint16_t type,
36  const void *data, uint32_t data_len)
37 {
38  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
39 
40  switch(type) {
41  case NFT_EXPR_BITWISE_SREG:
42  bitwise->sreg = *((uint32_t *)data);
43  break;
44  case NFT_EXPR_BITWISE_DREG:
45  bitwise->dreg = *((uint32_t *)data);
46  break;
47  case NFT_EXPR_BITWISE_LEN:
48  bitwise->len = *((unsigned int *)data);
49  break;
50  case NFT_EXPR_BITWISE_MASK:
51  memcpy(&bitwise->mask.val, data, data_len);
52  bitwise->mask.len = data_len;
53  break;
54  case NFT_EXPR_BITWISE_XOR:
55  memcpy(&bitwise->xor.val, data, data_len);
56  bitwise->xor.len = data_len;
57  break;
58  default:
59  return -1;
60  }
61  return 0;
62 }
63 
64 static const void *
65 nft_rule_expr_bitwise_get(const struct nft_rule_expr *e, uint16_t type,
66  uint32_t *data_len)
67 {
68  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
69 
70  switch(type) {
71  case NFT_EXPR_BITWISE_SREG:
72  *data_len = sizeof(bitwise->sreg);
73  return &bitwise->sreg;
74  case NFT_EXPR_BITWISE_DREG:
75  *data_len = sizeof(bitwise->dreg);
76  return &bitwise->dreg;
77  case NFT_EXPR_BITWISE_LEN:
78  *data_len = sizeof(bitwise->len);
79  return &bitwise->len;
80  case NFT_EXPR_BITWISE_MASK:
81  *data_len = bitwise->mask.len;
82  return &bitwise->mask.val;
83  case NFT_EXPR_BITWISE_XOR:
84  *data_len = bitwise->xor.len;
85  return &bitwise->xor.val;
86  }
87  return NULL;
88 }
89 
90 static int nft_rule_expr_bitwise_cb(const struct nlattr *attr, void *data)
91 {
92  const struct nlattr **tb = data;
93  int type = mnl_attr_get_type(attr);
94 
95  if (mnl_attr_type_valid(attr, NFTA_BITWISE_MAX) < 0)
96  return MNL_CB_OK;
97 
98  switch(type) {
99  case NFTA_BITWISE_SREG:
100  case NFTA_BITWISE_DREG:
101  case NFTA_BITWISE_LEN:
102  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
103  perror("mnl_attr_validate");
104  return MNL_CB_ERROR;
105  }
106  break;
107  case NFTA_BITWISE_MASK:
108  case NFTA_BITWISE_XOR:
109  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) {
110  perror("mnl_attr_validate");
111  return MNL_CB_ERROR;
112  }
113  break;
114  }
115 
116  tb[type] = attr;
117  return MNL_CB_OK;
118 }
119 
120 static void
121 nft_rule_expr_bitwise_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
122 {
123  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
124 
125  if (e->flags & (1 << NFT_EXPR_BITWISE_SREG))
126  mnl_attr_put_u32(nlh, NFTA_BITWISE_SREG, htonl(bitwise->sreg));
127  if (e->flags & (1 << NFT_EXPR_BITWISE_DREG))
128  mnl_attr_put_u32(nlh, NFTA_BITWISE_DREG, htonl(bitwise->dreg));
129  if (e->flags & (1 << NFT_EXPR_BITWISE_LEN))
130  mnl_attr_put_u32(nlh, NFTA_BITWISE_LEN, htonl(bitwise->len));
131  if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) {
132  struct nlattr *nest;
133 
134  nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_MASK);
135  mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->mask.len,
136  bitwise->mask.val);
137  mnl_attr_nest_end(nlh, nest);
138  }
139  if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) {
140  struct nlattr *nest;
141 
142  nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_XOR);
143  mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->xor.len,
144  bitwise->xor.val);
145  mnl_attr_nest_end(nlh, nest);
146  }
147 }
148 
149 static int
150 nft_rule_expr_bitwise_parse(struct nft_rule_expr *e, struct nlattr *attr)
151 {
152  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
153  struct nlattr *tb[NFTA_BITWISE_MAX+1] = {};
154  int ret = 0;
155 
156  if (mnl_attr_parse_nested(attr, nft_rule_expr_bitwise_cb, tb) < 0)
157  return -1;
158 
159  if (tb[NFTA_BITWISE_SREG]) {
160  bitwise->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_SREG]));
161  e->flags |= (1 << NFT_EXPR_BITWISE_SREG);
162  }
163  if (tb[NFTA_BITWISE_DREG]) {
164  bitwise->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_DREG]));
165  e->flags |= (1 << NFT_EXPR_BITWISE_DREG);
166  }
167  if (tb[NFTA_BITWISE_LEN]) {
168  bitwise->len = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_LEN]));
169  e->flags |= (1 << NFT_EXPR_BITWISE_LEN);
170  }
171  if (tb[NFTA_BITWISE_MASK]) {
172  ret = nft_parse_data(&bitwise->mask, tb[NFTA_BITWISE_MASK], NULL);
173  e->flags |= (1 << NFTA_BITWISE_MASK);
174  }
175  if (tb[NFTA_BITWISE_XOR]) {
176  ret = nft_parse_data(&bitwise->xor, tb[NFTA_BITWISE_XOR], NULL);
177  e->flags |= (1 << NFTA_BITWISE_XOR);
178  }
179 
180  return ret;
181 }
182 
183 static int
184 nft_rule_expr_bitwise_json_parse(struct nft_rule_expr *e, json_t *root,
185  struct nft_parse_err *err)
186 {
187 #ifdef JSON_PARSING
188  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
189  uint32_t reg, len;
190 
191  if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &reg, err) == 0)
192  nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_SREG, reg);
193 
194  if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &reg, err) == 0)
195  nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_DREG, reg);
196 
197  if (nft_jansson_parse_val(root, "len", NFT_TYPE_U32, &len, err) == 0)
198  nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_LEN, len);
199 
200  if (nft_jansson_data_reg_parse(root, "mask", &bitwise->mask,
201  err) == DATA_VALUE)
202  e->flags |= (1 << NFT_EXPR_BITWISE_MASK);
203 
204  if (nft_jansson_data_reg_parse(root, "xor", &bitwise->xor,
205  err) == DATA_VALUE)
206  e->flags |= (1 << NFT_EXPR_BITWISE_XOR);
207 
208  if (bitwise->mask.len != bitwise->xor.len)
209  return -1;
210 
211  return 0;
212 #else
213  errno = EOPNOTSUPP;
214  return -1;
215 #endif
216 }
217 
218 static int
219 nft_rule_expr_bitwise_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
220  struct nft_parse_err *err)
221 {
222 #ifdef XML_PARSING
223  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
224  uint32_t sreg, dreg, len;
225 
226  if (nft_mxml_reg_parse(tree, "sreg", &sreg, MXML_DESCEND_FIRST,
227  NFT_XML_MAND, err) == 0)
228  nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_SREG, sreg);
229 
230  if (nft_mxml_reg_parse(tree, "dreg", &dreg, MXML_DESCEND_FIRST,
231  NFT_XML_MAND, err) == 0)
232  nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_DREG, dreg);
233 
234  if (nft_mxml_num_parse(tree, "len", MXML_DESCEND_FIRST, BASE_DEC,
235  &len, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
236  nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_LEN, len);
237 
238  if (nft_mxml_data_reg_parse(tree, "mask", &bitwise->mask, NFT_XML_MAND,
239  err) == DATA_VALUE)
240  e->flags |= (1 << NFT_EXPR_BITWISE_MASK);
241 
242  if (nft_mxml_data_reg_parse(tree, "xor", &bitwise->xor, NFT_XML_MAND,
243  err) == DATA_VALUE)
244  e->flags |= (1 << NFT_EXPR_BITWISE_XOR);
245 
246  /* Additional validation: mask and xor must use the same number of
247  * data registers.
248  */
249  if (bitwise->mask.len != bitwise->xor.len)
250  return -1;
251 
252  return 0;
253 #else
254  errno = EOPNOTSUPP;
255  return -1;
256 #endif
257 }
258 
259 static int nft_rule_expr_bitwise_snprintf_json(char *buf, size_t size,
260  struct nft_rule_expr *e)
261 {
262  int len = size, offset = 0, ret;
263  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
264 
265  if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) {
266  ret = snprintf(buf + offset, len, "\"sreg\":%u,",
267  bitwise->sreg);
268  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
269  }
270  if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) {
271  ret = snprintf(buf + offset, len, "\"dreg\":%u,",
272  bitwise->dreg);
273  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
274  }
275  if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) {
276  ret = snprintf(buf + offset, len, "\"len\":%u,",
277  bitwise->len);
278  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
279  }
280  if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) {
281  ret = snprintf(buf + offset, len, "\"mask\":{");
282  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
283 
284  ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->mask,
285  NFT_OUTPUT_JSON, 0, DATA_VALUE);
286  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
287 
288  ret = snprintf(buf + offset, len, "},");
289  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
290 
291  }
292  if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) {
293  ret = snprintf(buf+offset, len, "\"xor\":{");
294  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
295 
296  ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->xor,
297  NFT_OUTPUT_JSON, 0, DATA_VALUE);
298  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
299 
300  ret = snprintf(buf+offset, len, "},");
301  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
302  }
303 
304  if (offset > 0)
305  offset--;
306 
307  return offset;
308 }
309 
310 static int nft_rule_expr_bitwise_snprintf_xml(char *buf, size_t size,
311  struct nft_rule_expr *e)
312 {
313  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
314  int len = size, offset = 0, ret;
315 
316  if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) {
317  ret = snprintf(buf + offset, len, "<sreg>%u</sreg>",
318  bitwise->sreg);
319  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
320  }
321  if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) {
322  ret = snprintf(buf + offset, len, "<dreg>%u</dreg>",
323  bitwise->dreg);
324  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
325  }
326  if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) {
327  ret = snprintf(buf + offset, len, "<len>%u</len>",
328  bitwise->len);
329  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
330  }
331  if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) {
332  ret = snprintf(buf + offset, len, "<mask>");
333  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
334 
335  ret = nft_data_reg_snprintf(buf + offset, len, &bitwise->mask,
336  NFT_OUTPUT_XML, 0, DATA_VALUE);
337  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
338 
339  ret = snprintf(buf + offset, len, "</mask>");
340  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
341  }
342  if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) {
343  ret = snprintf(buf + offset, len, "<xor>");
344  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
345 
346  ret = nft_data_reg_snprintf(buf + offset, len, &bitwise->xor,
347  NFT_OUTPUT_XML, 0, DATA_VALUE);
348  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
349 
350  ret = snprintf(buf + offset, len, "</xor>");
351  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
352  }
353 
354  return offset;
355 }
356 
357 static int nft_rule_expr_bitwise_snprintf_default(char *buf, size_t size,
358  struct nft_rule_expr *e)
359 {
360  struct nft_expr_bitwise *bitwise = nft_expr_data(e);
361  int len = size, offset = 0, ret;
362 
363  ret = snprintf(buf, len, "reg %u = (reg=%u & ",
364  bitwise->dreg, bitwise->sreg);
365  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
366 
367  ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->mask,
368  NFT_OUTPUT_DEFAULT, 0, DATA_VALUE);
369  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
370 
371  ret = snprintf(buf+offset, len, ") ^ ");
372  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
373 
374  ret = nft_data_reg_snprintf(buf+offset, len, &bitwise->xor,
375  NFT_OUTPUT_DEFAULT, 0, DATA_VALUE);
376  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
377 
378  return offset;
379 }
380 
381 static int
382 nft_rule_expr_bitwise_snprintf(char *buf, size_t size, uint32_t type,
383  uint32_t flags, struct nft_rule_expr *e)
384 {
385  switch(type) {
386  case NFT_OUTPUT_DEFAULT:
387  return nft_rule_expr_bitwise_snprintf_default(buf, size, e);
388  case NFT_OUTPUT_XML:
389  return nft_rule_expr_bitwise_snprintf_xml(buf, size, e);
390  case NFT_OUTPUT_JSON:
391  return nft_rule_expr_bitwise_snprintf_json(buf, size, e);
392  default:
393  break;
394  }
395  return -1;
396 }
397 
398 struct expr_ops expr_ops_bitwise = {
399  .name = "bitwise",
400  .alloc_len = sizeof(struct nft_expr_bitwise),
401  .max_attr = NFTA_BITWISE_MAX,
402  .set = nft_rule_expr_bitwise_set,
403  .get = nft_rule_expr_bitwise_get,
404  .parse = nft_rule_expr_bitwise_parse,
405  .build = nft_rule_expr_bitwise_build,
406  .snprintf = nft_rule_expr_bitwise_snprintf,
407  .xml_parse = nft_rule_expr_bitwise_xml_parse,
408  .json_parse = nft_rule_expr_bitwise_json_parse,
409 };
410 
411 static void __init expr_bitwise(void)
412 {
413  nft_expr_ops_register(&expr_ops_bitwise);
414 }