libnftnl  1.1.2
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  struct {
32  const char *name;
33  uint32_t id;
34  } map;
35 };
36 
37 static int
38 nftnl_expr_hash_set(struct nftnl_expr *e, uint16_t type,
39  const void *data, uint32_t data_len)
40 {
41  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
42  switch (type) {
43  case NFTNL_EXPR_HASH_SREG:
44  memcpy(&hash->sreg, data, sizeof(hash->sreg));
45  break;
46  case NFTNL_EXPR_HASH_DREG:
47  memcpy(&hash->dreg, data, sizeof(hash->dreg));
48  break;
49  case NFTNL_EXPR_HASH_LEN:
50  memcpy(&hash->len, data, sizeof(hash->len));
51  break;
52  case NFTNL_EXPR_HASH_MODULUS:
53  memcpy(&hash->modulus, data, sizeof(hash->modulus));
54  break;
55  case NFTNL_EXPR_HASH_SEED:
56  memcpy(&hash->seed, data, sizeof(hash->seed));
57  break;
58  case NFTNL_EXPR_HASH_OFFSET:
59  memcpy(&hash->offset, data, sizeof(hash->offset));
60  break;
61  case NFTNL_EXPR_HASH_TYPE:
62  memcpy(&hash->type, data, sizeof(hash->type));
63  break;
64  case NFTNL_EXPR_HASH_SET_NAME:
65  hash->map.name = strdup(data);
66  if (!hash->map.name)
67  return -1;
68  break;
69  case NFTNL_EXPR_HASH_SET_ID:
70  memcpy(&hash->map.id, data, sizeof(hash->map.id));
71  break;
72  default:
73  return -1;
74  }
75  return 0;
76 }
77 
78 static const void *
79 nftnl_expr_hash_get(const struct nftnl_expr *e, uint16_t type,
80  uint32_t *data_len)
81 {
82  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
83 
84  switch (type) {
85  case NFTNL_EXPR_HASH_SREG:
86  *data_len = sizeof(hash->sreg);
87  return &hash->sreg;
88  case NFTNL_EXPR_HASH_DREG:
89  *data_len = sizeof(hash->dreg);
90  return &hash->dreg;
91  case NFTNL_EXPR_HASH_LEN:
92  *data_len = sizeof(hash->len);
93  return &hash->len;
94  case NFTNL_EXPR_HASH_MODULUS:
95  *data_len = sizeof(hash->modulus);
96  return &hash->modulus;
97  case NFTNL_EXPR_HASH_SEED:
98  *data_len = sizeof(hash->seed);
99  return &hash->seed;
100  case NFTNL_EXPR_HASH_OFFSET:
101  *data_len = sizeof(hash->offset);
102  return &hash->offset;
103  case NFTNL_EXPR_HASH_TYPE:
104  *data_len = sizeof(hash->type);
105  return &hash->type;
106  case NFTNL_EXPR_HASH_SET_NAME:
107  *data_len = strlen(hash->map.name) + 1;
108  return hash->map.name;
109  case NFTNL_EXPR_HASH_SET_ID:
110  *data_len = sizeof(hash->map.id);
111  return &hash->map.id;
112  }
113  return NULL;
114 }
115 
116 static int nftnl_expr_hash_cb(const struct nlattr *attr, void *data)
117 {
118  const struct nlattr **tb = data;
119  int type = mnl_attr_get_type(attr);
120 
121  if (mnl_attr_type_valid(attr, NFTA_HASH_MAX) < 0)
122  return MNL_CB_OK;
123 
124  switch (type) {
125  case NFTA_HASH_SREG:
126  case NFTA_HASH_DREG:
127  case NFTA_HASH_LEN:
128  case NFTA_HASH_MODULUS:
129  case NFTA_HASH_SEED:
130  case NFTA_HASH_OFFSET:
131  case NFTA_HASH_TYPE:
132  case NFTA_HASH_SET_ID:
133  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
134  abi_breakage();
135  break;
136  case NFTA_HASH_SET_NAME:
137  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
138  abi_breakage();
139  break;
140  }
141 
142  tb[type] = attr;
143  return MNL_CB_OK;
144 }
145 
146 static void
147 nftnl_expr_hash_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
148 {
149  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
150 
151  if (e->flags & (1 << NFTNL_EXPR_HASH_SREG))
152  mnl_attr_put_u32(nlh, NFTA_HASH_SREG, htonl(hash->sreg));
153  if (e->flags & (1 << NFTNL_EXPR_HASH_DREG))
154  mnl_attr_put_u32(nlh, NFTA_HASH_DREG, htonl(hash->dreg));
155  if (e->flags & (1 << NFTNL_EXPR_HASH_LEN))
156  mnl_attr_put_u32(nlh, NFTA_HASH_LEN, htonl(hash->len));
157  if (e->flags & (1 << NFTNL_EXPR_HASH_MODULUS))
158  mnl_attr_put_u32(nlh, NFTA_HASH_MODULUS, htonl(hash->modulus));
159  if (e->flags & (1 << NFTNL_EXPR_HASH_SEED))
160  mnl_attr_put_u32(nlh, NFTA_HASH_SEED, htonl(hash->seed));
161  if (e->flags & (1 << NFTNL_EXPR_HASH_OFFSET))
162  mnl_attr_put_u32(nlh, NFTA_HASH_OFFSET, htonl(hash->offset));
163  if (e->flags & (1 << NFTNL_EXPR_HASH_TYPE))
164  mnl_attr_put_u32(nlh, NFTA_HASH_TYPE, htonl(hash->type));
165  if (e->flags & (1 << NFTNL_EXPR_HASH_SET_NAME))
166  mnl_attr_put_str(nlh, NFTA_HASH_SET_NAME, hash->map.name);
167  if (e->flags & (1 << NFTNL_EXPR_HASH_SET_ID))
168  mnl_attr_put_u32(nlh, NFTA_HASH_SET_ID, htonl(hash->map.id));
169 }
170 
171 static int
172 nftnl_expr_hash_parse(struct nftnl_expr *e, struct nlattr *attr)
173 {
174  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
175  struct nlattr *tb[NFTA_HASH_MAX+1] = {};
176  int ret = 0;
177 
178  if (mnl_attr_parse_nested(attr, nftnl_expr_hash_cb, tb) < 0)
179  return -1;
180 
181  if (tb[NFTA_HASH_SREG]) {
182  hash->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SREG]));
183  e->flags |= (1 << NFTNL_EXPR_HASH_SREG);
184  }
185  if (tb[NFTA_HASH_DREG]) {
186  hash->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_DREG]));
187  e->flags |= (1 << NFTNL_EXPR_HASH_DREG);
188  }
189  if (tb[NFTA_HASH_LEN]) {
190  hash->len = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_LEN]));
191  e->flags |= (1 << NFTNL_EXPR_HASH_LEN);
192  }
193  if (tb[NFTA_HASH_MODULUS]) {
194  hash->modulus = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_MODULUS]));
195  e->flags |= (1 << NFTNL_EXPR_HASH_MODULUS);
196  }
197  if (tb[NFTA_HASH_SEED]) {
198  hash->seed = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SEED]));
199  e->flags |= (1 << NFTNL_EXPR_HASH_SEED);
200  }
201  if (tb[NFTA_HASH_OFFSET]) {
202  hash->offset = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_OFFSET]));
203  e->flags |= (1 << NFTNL_EXPR_HASH_OFFSET);
204  }
205  if (tb[NFTA_HASH_TYPE]) {
206  hash->type = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_TYPE]));
207  e->flags |= (1 << NFTNL_EXPR_HASH_TYPE);
208  }
209  if (tb[NFTA_HASH_SET_NAME]) {
210  hash->map.name =
211  strdup(mnl_attr_get_str(tb[NFTA_HASH_SET_NAME]));
212  e->flags |= (1 << NFTNL_EXPR_HASH_SET_NAME);
213  }
214  if (tb[NFTA_HASH_SET_ID]) {
215  hash->map.id =
216  ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SET_ID]));
217  e->flags |= (1 << NFTNL_EXPR_HASH_SET_ID);
218  }
219 
220  return ret;
221 }
222 
223 static int
224 nftnl_expr_hash_snprintf_default(char *buf, size_t size,
225  const struct nftnl_expr *e)
226 {
227  struct nftnl_expr_hash *hash = nftnl_expr_data(e);
228  int remain = size, offset = 0, ret;
229 
230  switch (hash->type) {
231  case NFT_HASH_SYM:
232  ret =
233  snprintf(buf, remain, "reg %u = symhash() %% mod %u ",
234  hash->dreg,
235  hash->modulus);
236  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
237  break;
238  case NFT_HASH_JENKINS:
239  default:
240  ret =
241  snprintf(buf, remain,
242  "reg %u = jhash(reg %u, %u, 0x%x) %% mod %u ",
243  hash->dreg, hash->sreg, hash->len, hash->seed,
244  hash->modulus);
245  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
246  break;
247  }
248 
249  if (hash->offset) {
250  ret = snprintf(buf + offset, remain, "offset %u ",
251  hash->offset);
252  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
253  }
254 
255  if (hash->map.id) {
256  ret = snprintf(buf + offset, remain, "set %s id %u ",
257  hash->map.name, hash->map.id);
258  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
259  }
260 
261  return offset;
262 }
263 
264 static int
265 nftnl_expr_hash_snprintf(char *buf, size_t len, uint32_t type,
266  uint32_t flags, const struct nftnl_expr *e)
267 {
268  switch (type) {
269  case NFTNL_OUTPUT_DEFAULT:
270  return nftnl_expr_hash_snprintf_default(buf, len, e);
271  case NFTNL_OUTPUT_XML:
272  case NFTNL_OUTPUT_JSON:
273  default:
274  break;
275  }
276  return -1;
277 }
278 
279 struct expr_ops expr_ops_hash = {
280  .name = "hash",
281  .alloc_len = sizeof(struct nftnl_expr_hash),
282  .max_attr = NFTA_HASH_MAX,
283  .set = nftnl_expr_hash_set,
284  .get = nftnl_expr_hash_get,
285  .parse = nftnl_expr_hash_parse,
286  .build = nftnl_expr_hash_build,
287  .snprintf = nftnl_expr_hash_snprintf,
288 };