libnftnl  1.0.8
hash.c
1 /*
2  * (C) 2016 by Laura Garcia <nevola@gmail.com>
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  */
10 
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <arpa/inet.h>
15 #include <errno.h>
16 #include <linux/netfilter/nf_tables.h>
17 
18 #include "internal.h"
19 #include <libmnl/libmnl.h>
20 #include <libnftnl/expr.h>
21 #include <libnftnl/rule.h>
22 
24  enum nft_hash_types type;
25  enum nft_registers sreg;
26  enum nft_registers dreg;
27  unsigned int len;
28  unsigned int modulus;
29  unsigned int seed;
30  unsigned int offset;
31 };
32 
33 static int
34 nftnl_expr_hash_set(struct nftnl_expr *e, uint16_t type,
35  const void *data, uint32_t data_len)
36 {
37  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
38  switch (type) {
39  case NFTNL_EXPR_HASH_SREG:
40  hash->sreg = *((uint32_t *)data);
41  break;
42  case NFTNL_EXPR_HASH_DREG:
43  hash->dreg = *((uint32_t *)data);
44  break;
45  case NFTNL_EXPR_HASH_LEN:
46  hash->len = *((uint32_t *)data);
47  break;
48  case NFTNL_EXPR_HASH_MODULUS:
49  hash->modulus = *((uint32_t *)data);
50  break;
51  case NFTNL_EXPR_HASH_SEED:
52  hash->seed = *((uint32_t *)data);
53  break;
54  case NFTNL_EXPR_HASH_OFFSET:
55  hash->offset = *((uint32_t *)data);
56  break;
57  case NFTNL_EXPR_HASH_TYPE:
58  hash->type = *((uint32_t *)data);
59  break;
60  default:
61  return -1;
62  }
63  return 0;
64 }
65 
66 static const void *
67 nftnl_expr_hash_get(const struct nftnl_expr *e, uint16_t type,
68  uint32_t *data_len)
69 {
70  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
71 
72  switch (type) {
73  case NFTNL_EXPR_HASH_SREG:
74  *data_len = sizeof(hash->sreg);
75  return &hash->sreg;
76  case NFTNL_EXPR_HASH_DREG:
77  *data_len = sizeof(hash->dreg);
78  return &hash->dreg;
79  case NFTNL_EXPR_HASH_LEN:
80  *data_len = sizeof(hash->len);
81  return &hash->len;
82  case NFTNL_EXPR_HASH_MODULUS:
83  *data_len = sizeof(hash->modulus);
84  return &hash->modulus;
85  case NFTNL_EXPR_HASH_SEED:
86  *data_len = sizeof(hash->seed);
87  return &hash->seed;
88  case NFTNL_EXPR_HASH_OFFSET:
89  *data_len = sizeof(hash->offset);
90  return &hash->offset;
91  case NFTNL_EXPR_HASH_TYPE:
92  *data_len = sizeof(hash->type);
93  return &hash->type;
94  }
95  return NULL;
96 }
97 
98 static int nftnl_expr_hash_cb(const struct nlattr *attr, void *data)
99 {
100  const struct nlattr **tb = data;
101  int type = mnl_attr_get_type(attr);
102 
103  if (mnl_attr_type_valid(attr, NFTA_HASH_MAX) < 0)
104  return MNL_CB_OK;
105 
106  switch (type) {
107  case NFTA_HASH_SREG:
108  case NFTA_HASH_DREG:
109  case NFTA_HASH_LEN:
110  case NFTA_HASH_MODULUS:
111  case NFTA_HASH_SEED:
112  case NFTA_HASH_OFFSET:
113  case NFTA_HASH_TYPE:
114  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 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_hash_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
125 {
126  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
127 
128  if (e->flags & (1 << NFTNL_EXPR_HASH_SREG))
129  mnl_attr_put_u32(nlh, NFTA_HASH_SREG, htonl(hash->sreg));
130  if (e->flags & (1 << NFTNL_EXPR_HASH_DREG))
131  mnl_attr_put_u32(nlh, NFTA_HASH_DREG, htonl(hash->dreg));
132  if (e->flags & (1 << NFTNL_EXPR_HASH_LEN))
133  mnl_attr_put_u32(nlh, NFTA_HASH_LEN, htonl(hash->len));
134  if (e->flags & (1 << NFTNL_EXPR_HASH_MODULUS))
135  mnl_attr_put_u32(nlh, NFTA_HASH_MODULUS, htonl(hash->modulus));
136  if (e->flags & (1 << NFTNL_EXPR_HASH_SEED))
137  mnl_attr_put_u32(nlh, NFTA_HASH_SEED, htonl(hash->seed));
138  if (e->flags & (1 << NFTNL_EXPR_HASH_OFFSET))
139  mnl_attr_put_u32(nlh, NFTA_HASH_OFFSET, htonl(hash->offset));
140  if (e->flags & (1 << NFTNL_EXPR_HASH_TYPE))
141  mnl_attr_put_u32(nlh, NFTA_HASH_TYPE, htonl(hash->type));
142 }
143 
144 static int
145 nftnl_expr_hash_parse(struct nftnl_expr *e, struct nlattr *attr)
146 {
147  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
148  struct nlattr *tb[NFTA_HASH_MAX+1] = {};
149  int ret = 0;
150 
151  if (mnl_attr_parse_nested(attr, nftnl_expr_hash_cb, tb) < 0)
152  return -1;
153 
154  if (tb[NFTA_HASH_SREG]) {
155  hash->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SREG]));
156  e->flags |= (1 << NFTNL_EXPR_HASH_SREG);
157  }
158  if (tb[NFTA_HASH_DREG]) {
159  hash->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_DREG]));
160  e->flags |= (1 << NFTNL_EXPR_HASH_DREG);
161  }
162  if (tb[NFTA_HASH_LEN]) {
163  hash->len = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_LEN]));
164  e->flags |= (1 << NFTNL_EXPR_HASH_LEN);
165  }
166  if (tb[NFTA_HASH_MODULUS]) {
167  hash->modulus = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_MODULUS]));
168  e->flags |= (1 << NFTNL_EXPR_HASH_MODULUS);
169  }
170  if (tb[NFTA_HASH_SEED]) {
171  hash->seed = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SEED]));
172  e->flags |= (1 << NFTNL_EXPR_HASH_SEED);
173  }
174  if (tb[NFTA_HASH_OFFSET]) {
175  hash->offset = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_OFFSET]));
176  e->flags |= (1 << NFTNL_EXPR_HASH_OFFSET);
177  }
178  if (tb[NFTA_HASH_TYPE]) {
179  hash->type = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_TYPE]));
180  e->flags |= (1 << NFTNL_EXPR_HASH_TYPE);
181  }
182 
183  return ret;
184 }
185 
186 static int nftnl_expr_hash_json_parse(struct nftnl_expr *e, json_t *root,
187  struct nftnl_parse_err *err)
188 {
189 #ifdef JSON_PARSING
190  uint32_t sreg, dreg, len, modulus, seed, offset, type;
191 
192  if (nftnl_jansson_parse_reg(root, "sreg", NFTNL_TYPE_U32,
193  &sreg, err) == 0)
194  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_SREG, sreg);
195 
196  if (nftnl_jansson_parse_reg(root, "dreg", NFTNL_TYPE_U32,
197  &dreg, err) == 0)
198  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_DREG, dreg);
199 
200  if (nftnl_jansson_parse_val(root, "len", NFTNL_TYPE_U32,
201  &len, err) == 0)
202  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_LEN, len);
203 
204  if (nftnl_jansson_parse_val(root, "modulus", NFTNL_TYPE_U32,
205  &modulus, err) == 0)
206  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_MODULUS, modulus);
207 
208  if (nftnl_jansson_parse_val(root, "seed", NFTNL_TYPE_U32,
209  &seed, err) == 0)
210  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_SEED, seed);
211 
212  if (nftnl_jansson_parse_val(root, "offset", NFTNL_TYPE_U32,
213  &offset, err) == 0)
214  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_OFFSET, offset);
215 
216  if (nftnl_jansson_parse_val(root, "type", NFTNL_TYPE_U32,
217  &type, err) == 0)
218  nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_TYPE, type);
219 
220  return 0;
221 #else
222  errno = EOPNOTSUPP;
223  return -1;
224 #endif
225 }
226 
227 static int
228 nftnl_expr_hash_snprintf_default(char *buf, size_t size,
229  const struct nftnl_expr *e)
230 {
231  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
232  int remain = size, offset = 0, ret;
233 
234  switch (hash->type) {
235  case NFT_HASH_SYM:
236  ret =
237  snprintf(buf, remain, "reg %u = symhash() %% mod %u ",
238  hash->dreg,
239  hash->modulus);
240  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
241  break;
242  case NFT_HASH_JENKINS:
243  default:
244  ret =
245  snprintf(buf, remain,
246  "reg %u = jhash(reg %u, %u, 0x%x) %% mod %u ",
247  hash->dreg, hash->sreg, hash->len, hash->seed,
248  hash->modulus);
249  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
250  break;
251  }
252 
253  if (hash->offset) {
254  ret = snprintf(buf + offset, remain, "offset %u ",
255  hash->offset);
256  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
257  }
258 
259  return offset;
260 }
261 
262 static int nftnl_expr_hash_export(char *buf, size_t size,
263  const struct nftnl_expr *e, int type)
264 {
265  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
266 
267  NFTNL_BUF_INIT(b, buf, size);
268 
269  if (e->flags & (1 << NFTNL_EXPR_HASH_SREG))
270  nftnl_buf_u32(&b, type, hash->sreg, SREG);
271  if (e->flags & (1 << NFTNL_EXPR_HASH_DREG))
272  nftnl_buf_u32(&b, type, hash->dreg, DREG);
273  if (e->flags & (1 << NFTNL_EXPR_HASH_LEN))
274  nftnl_buf_u32(&b, type, hash->len, LEN);
275  if (e->flags & (1 << NFTNL_EXPR_HASH_MODULUS))
276  nftnl_buf_u32(&b, type, hash->modulus, MODULUS);
277  if (e->flags & (1 << NFTNL_EXPR_HASH_SEED))
278  nftnl_buf_u32(&b, type, hash->seed, SEED);
279  if (e->flags & (1 << NFTNL_EXPR_HASH_OFFSET))
280  nftnl_buf_u32(&b, type, hash->offset, OFFSET);
281  if (e->flags & (1 << NFTNL_EXPR_HASH_TYPE))
282  nftnl_buf_u32(&b, type, hash->type, TYPE);
283 
284  return nftnl_buf_done(&b);
285 }
286 
287 static int
288 nftnl_expr_hash_snprintf(char *buf, size_t len, uint32_t type,
289  uint32_t flags, const struct nftnl_expr *e)
290 {
291  switch (type) {
292  case NFTNL_OUTPUT_DEFAULT:
293  return nftnl_expr_hash_snprintf_default(buf, len, e);
294  case NFTNL_OUTPUT_XML:
295  case NFTNL_OUTPUT_JSON:
296  return nftnl_expr_hash_export(buf, len, e, type);
297  default:
298  break;
299  }
300  return -1;
301 }
302 
303 static bool nftnl_expr_hash_cmp(const struct nftnl_expr *e1,
304  const struct nftnl_expr *e2)
305 {
306  struct nftnl_expr_hash *h1 = nftnl_expr_data(e1);
307  struct nftnl_expr_hash *h2 = nftnl_expr_data(e2);
308  bool eq = true;
309 
310  if (e1->flags & (1 << NFTNL_EXPR_HASH_SREG))
311  eq &= (h1->sreg == h2->sreg);
312  if (e1->flags & (1 << NFTNL_EXPR_HASH_DREG))
313  eq &= (h1->dreg == h2->dreg);
314  if (e1->flags & (1 << NFTNL_EXPR_HASH_LEN))
315  eq &= (h1->len == h2->len);
316  if (e1->flags & (1 << NFTNL_EXPR_HASH_MODULUS))
317  eq &= (h1->modulus == h2->modulus);
318  if (e1->flags & (1 << NFTNL_EXPR_HASH_SEED))
319  eq &= (h1->seed == h2->seed);
320  if (e1->flags & (1 << NFTNL_EXPR_HASH_OFFSET))
321  eq &= (h1->offset == h2->offset);
322  if (e1->flags & (1 << NFTNL_EXPR_HASH_TYPE))
323  eq &= (h1->type == h2->type);
324 
325  return eq;
326 }
327 
328 struct expr_ops expr_ops_hash = {
329  .name = "hash",
330  .alloc_len = sizeof(struct nftnl_expr_hash),
331  .max_attr = NFTA_HASH_MAX,
332  .cmp = nftnl_expr_hash_cmp,
333  .set = nftnl_expr_hash_set,
334  .get = nftnl_expr_hash_get,
335  .parse = nftnl_expr_hash_parse,
336  .build = nftnl_expr_hash_build,
337  .snprintf = nftnl_expr_hash_snprintf,
338  .json_parse = nftnl_expr_hash_json_parse,
339 };