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