libnftnl  1.2.8
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 
25  enum nft_registers sreg;
26  enum nft_registers dreg;
27  enum nft_bitwise_ops op;
28  unsigned int len;
29  union nftnl_data_reg mask;
30  union nftnl_data_reg xor;
31  union nftnl_data_reg data;
32 };
33 
34 static int
35 nftnl_expr_bitwise_set(struct nftnl_expr *e, uint16_t type,
36  const void *data, uint32_t data_len)
37 {
38  struct nftnl_expr_bitwise *bitwise = nftnl_expr_data(e);
39 
40  switch(type) {
41  case NFTNL_EXPR_BITWISE_SREG:
42  memcpy(&bitwise->sreg, data, data_len);
43  break;
44  case NFTNL_EXPR_BITWISE_DREG:
45  memcpy(&bitwise->dreg, data, data_len);
46  break;
47  case NFTNL_EXPR_BITWISE_OP:
48  memcpy(&bitwise->op, data, data_len);
49  break;
50  case NFTNL_EXPR_BITWISE_LEN:
51  memcpy(&bitwise->len, data, data_len);
52  break;
53  case NFTNL_EXPR_BITWISE_MASK:
54  return nftnl_data_cpy(&bitwise->mask, data, data_len);
55  case NFTNL_EXPR_BITWISE_XOR:
56  return nftnl_data_cpy(&bitwise->xor, data, data_len);
57  case NFTNL_EXPR_BITWISE_DATA:
58  return nftnl_data_cpy(&bitwise->data, data, data_len);
59  }
60  return 0;
61 }
62 
63 static const void *
64 nftnl_expr_bitwise_get(const struct nftnl_expr *e, uint16_t type,
65  uint32_t *data_len)
66 {
67  struct nftnl_expr_bitwise *bitwise = nftnl_expr_data(e);
68 
69  switch(type) {
70  case NFTNL_EXPR_BITWISE_SREG:
71  *data_len = sizeof(bitwise->sreg);
72  return &bitwise->sreg;
73  case NFTNL_EXPR_BITWISE_DREG:
74  *data_len = sizeof(bitwise->dreg);
75  return &bitwise->dreg;
76  case NFTNL_EXPR_BITWISE_OP:
77  *data_len = sizeof(bitwise->op);
78  return &bitwise->op;
79  case NFTNL_EXPR_BITWISE_LEN:
80  *data_len = sizeof(bitwise->len);
81  return &bitwise->len;
82  case NFTNL_EXPR_BITWISE_MASK:
83  *data_len = bitwise->mask.len;
84  return &bitwise->mask.val;
85  case NFTNL_EXPR_BITWISE_XOR:
86  *data_len = bitwise->xor.len;
87  return &bitwise->xor.val;
88  case NFTNL_EXPR_BITWISE_DATA:
89  *data_len = bitwise->data.len;
90  return &bitwise->data.val;
91  }
92  return NULL;
93 }
94 
95 static int nftnl_expr_bitwise_cb(const struct nlattr *attr, void *data)
96 {
97  const struct nlattr **tb = data;
98  int type = mnl_attr_get_type(attr);
99 
100  if (mnl_attr_type_valid(attr, NFTA_BITWISE_MAX) < 0)
101  return MNL_CB_OK;
102 
103  switch(type) {
104  case NFTA_BITWISE_SREG:
105  case NFTA_BITWISE_DREG:
106  case NFTA_BITWISE_OP:
107  case NFTA_BITWISE_LEN:
108  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
109  abi_breakage();
110  break;
111  case NFTA_BITWISE_MASK:
112  case NFTA_BITWISE_XOR:
113  case NFTA_BITWISE_DATA:
114  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
115  abi_breakage();
116  break;
117  }
118 
119  tb[type] = attr;
120  return MNL_CB_OK;
121 }
122 
123 static void
124 nftnl_expr_bitwise_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
125 {
126  struct nftnl_expr_bitwise *bitwise = nftnl_expr_data(e);
127 
128  if (e->flags & (1 << NFTNL_EXPR_BITWISE_SREG))
129  mnl_attr_put_u32(nlh, NFTA_BITWISE_SREG, htonl(bitwise->sreg));
130  if (e->flags & (1 << NFTNL_EXPR_BITWISE_DREG))
131  mnl_attr_put_u32(nlh, NFTA_BITWISE_DREG, htonl(bitwise->dreg));
132  if (e->flags & (1 << NFTNL_EXPR_BITWISE_OP))
133  mnl_attr_put_u32(nlh, NFTA_BITWISE_OP, htonl(bitwise->op));
134  if (e->flags & (1 << NFTNL_EXPR_BITWISE_LEN))
135  mnl_attr_put_u32(nlh, NFTA_BITWISE_LEN, htonl(bitwise->len));
136  if (e->flags & (1 << NFTNL_EXPR_BITWISE_MASK)) {
137  struct nlattr *nest;
138 
139  nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_MASK);
140  mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->mask.len,
141  bitwise->mask.val);
142  mnl_attr_nest_end(nlh, nest);
143  }
144  if (e->flags & (1 << NFTNL_EXPR_BITWISE_XOR)) {
145  struct nlattr *nest;
146 
147  nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_XOR);
148  mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->xor.len,
149  bitwise->xor.val);
150  mnl_attr_nest_end(nlh, nest);
151  }
152  if (e->flags & (1 << NFTNL_EXPR_BITWISE_DATA)) {
153  struct nlattr *nest;
154 
155  nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_DATA);
156  mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->data.len,
157  bitwise->data.val);
158  mnl_attr_nest_end(nlh, nest);
159  }
160 }
161 
162 static int
163 nftnl_expr_bitwise_parse(struct nftnl_expr *e, struct nlattr *attr)
164 {
165  struct nftnl_expr_bitwise *bitwise = nftnl_expr_data(e);
166  struct nlattr *tb[NFTA_BITWISE_MAX+1] = {};
167  int ret = 0;
168 
169  if (mnl_attr_parse_nested(attr, nftnl_expr_bitwise_cb, tb) < 0)
170  return -1;
171 
172  if (tb[NFTA_BITWISE_SREG]) {
173  bitwise->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_SREG]));
174  e->flags |= (1 << NFTNL_EXPR_BITWISE_SREG);
175  }
176  if (tb[NFTA_BITWISE_DREG]) {
177  bitwise->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_DREG]));
178  e->flags |= (1 << NFTNL_EXPR_BITWISE_DREG);
179  }
180  if (tb[NFTA_BITWISE_OP]) {
181  bitwise->op = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_OP]));
182  e->flags |= (1 << NFTNL_EXPR_BITWISE_OP);
183  }
184  if (tb[NFTA_BITWISE_LEN]) {
185  bitwise->len = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_LEN]));
186  e->flags |= (1 << NFTNL_EXPR_BITWISE_LEN);
187  }
188  if (tb[NFTA_BITWISE_MASK]) {
189  ret = nftnl_parse_data(&bitwise->mask, tb[NFTA_BITWISE_MASK], NULL);
190  e->flags |= (1 << NFTA_BITWISE_MASK);
191  }
192  if (tb[NFTA_BITWISE_XOR]) {
193  ret = nftnl_parse_data(&bitwise->xor, tb[NFTA_BITWISE_XOR], NULL);
194  e->flags |= (1 << NFTA_BITWISE_XOR);
195  }
196  if (tb[NFTA_BITWISE_DATA]) {
197  ret = nftnl_parse_data(&bitwise->data, tb[NFTA_BITWISE_DATA], NULL);
198  e->flags |= (1 << NFTNL_EXPR_BITWISE_DATA);
199  }
200 
201  return ret;
202 }
203 
204 static int
205 nftnl_expr_bitwise_snprintf_bool(char *buf, size_t remain,
206  const struct nftnl_expr_bitwise *bitwise)
207 {
208  int offset = 0, ret;
209 
210  ret = snprintf(buf, remain, "reg %u = ( reg %u & ",
211  bitwise->dreg, bitwise->sreg);
212  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
213 
214  ret = nftnl_data_reg_snprintf(buf + offset, remain, &bitwise->mask,
215  0, DATA_VALUE);
216  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
217 
218  ret = snprintf(buf + offset, remain, ") ^ ");
219  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
220 
221  ret = nftnl_data_reg_snprintf(buf + offset, remain, &bitwise->xor,
222  0, DATA_VALUE);
223  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
224 
225  return offset;
226 }
227 
228 static int
229 nftnl_expr_bitwise_snprintf_shift(char *buf, size_t remain, const char *op,
230  const struct nftnl_expr_bitwise *bitwise)
231 { int offset = 0, ret;
232 
233  ret = snprintf(buf, remain, "reg %u = ( reg %u %s ",
234  bitwise->dreg, bitwise->sreg, op);
235  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
236 
237  ret = nftnl_data_reg_snprintf(buf + offset, remain, &bitwise->data,
238  0, DATA_VALUE);
239  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
240 
241  ret = snprintf(buf + offset, remain, ") ");
242  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
243 
244  return offset;
245 }
246 
247 static int
248 nftnl_expr_bitwise_snprintf(char *buf, size_t size,
249  uint32_t flags, const struct nftnl_expr *e)
250 {
251  struct nftnl_expr_bitwise *bitwise = nftnl_expr_data(e);
252  int err = -1;
253 
254  switch (bitwise->op) {
255  case NFT_BITWISE_BOOL:
256  err = nftnl_expr_bitwise_snprintf_bool(buf, size, bitwise);
257  break;
258  case NFT_BITWISE_LSHIFT:
259  err = nftnl_expr_bitwise_snprintf_shift(buf, size, "<<", bitwise);
260  break;
261  case NFT_BITWISE_RSHIFT:
262  err = nftnl_expr_bitwise_snprintf_shift(buf, size, ">>", bitwise);
263  break;
264  }
265 
266  return err;
267 }
268 
269 static struct attr_policy bitwise_attr_policy[__NFTNL_EXPR_BITWISE_MAX] = {
270  [NFTNL_EXPR_BITWISE_SREG] = { .maxlen = sizeof(uint32_t) },
271  [NFTNL_EXPR_BITWISE_DREG] = { .maxlen = sizeof(uint32_t) },
272  [NFTNL_EXPR_BITWISE_LEN] = { .maxlen = sizeof(uint32_t) },
273  [NFTNL_EXPR_BITWISE_MASK] = { .maxlen = NFT_DATA_VALUE_MAXLEN },
274  [NFTNL_EXPR_BITWISE_XOR] = { .maxlen = NFT_DATA_VALUE_MAXLEN },
275  [NFTNL_EXPR_BITWISE_OP] = { .maxlen = sizeof(uint32_t) },
276  [NFTNL_EXPR_BITWISE_DATA] = { .maxlen = NFT_DATA_VALUE_MAXLEN },
277 };
278 
279 struct expr_ops expr_ops_bitwise = {
280  .name = "bitwise",
281  .alloc_len = sizeof(struct nftnl_expr_bitwise),
282  .nftnl_max_attr = __NFTNL_EXPR_BITWISE_MAX - 1,
283  .attr_policy = bitwise_attr_policy,
284  .set = nftnl_expr_bitwise_set,
285  .get = nftnl_expr_bitwise_get,
286  .parse = nftnl_expr_bitwise_parse,
287  .build = nftnl_expr_bitwise_build,
288  .output = nftnl_expr_bitwise_snprintf,
289 };