libnftnl  1.0.8
numgen.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 
23 struct nftnl_expr_ng {
24  enum nft_registers dreg;
25  unsigned int modulus;
26  enum nft_ng_types type;
27  unsigned int offset;
28 };
29 
30 static int
31 nftnl_expr_ng_set(struct nftnl_expr *e, uint16_t type,
32  const void *data, uint32_t data_len)
33 {
34  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
35 
36  switch (type) {
37  case NFTNL_EXPR_NG_DREG:
38  ng->dreg = *((uint32_t *)data);
39  break;
40  case NFTNL_EXPR_NG_MODULUS:
41  ng->modulus = *((uint32_t *)data);
42  break;
43  case NFTNL_EXPR_NG_TYPE:
44  ng->type = *((uint32_t *)data);
45  break;
46  case NFTNL_EXPR_NG_OFFSET:
47  ng->offset = *((uint32_t *)data);
48  break;
49  default:
50  return -1;
51  }
52  return 0;
53 }
54 
55 static const void *
56 nftnl_expr_ng_get(const struct nftnl_expr *e, uint16_t type,
57  uint32_t *data_len)
58 {
59  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
60 
61  switch (type) {
62  case NFTNL_EXPR_NG_DREG:
63  *data_len = sizeof(ng->dreg);
64  return &ng->dreg;
65  case NFTNL_EXPR_NG_MODULUS:
66  *data_len = sizeof(ng->modulus);
67  return &ng->modulus;
68  case NFTNL_EXPR_NG_TYPE:
69  *data_len = sizeof(ng->type);
70  return &ng->type;
71  case NFTNL_EXPR_NG_OFFSET:
72  *data_len = sizeof(ng->offset);
73  return &ng->offset;
74  }
75  return NULL;
76 }
77 
78 static int nftnl_expr_ng_cb(const struct nlattr *attr, void *data)
79 {
80  const struct nlattr **tb = data;
81  int type = mnl_attr_get_type(attr);
82 
83  if (mnl_attr_type_valid(attr, NFTA_NG_MAX) < 0)
84  return MNL_CB_OK;
85 
86  switch (type) {
87  case NFTA_NG_DREG:
88  case NFTA_NG_MODULUS:
89  case NFTA_NG_TYPE:
90  case NFTA_NG_OFFSET:
91  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
92  abi_breakage();
93  break;
94  }
95 
96  tb[type] = attr;
97  return MNL_CB_OK;
98 }
99 
100 static void
101 nftnl_expr_ng_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
102 {
103  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
104 
105  if (e->flags & (1 << NFTNL_EXPR_NG_DREG))
106  mnl_attr_put_u32(nlh, NFTA_NG_DREG, htonl(ng->dreg));
107  if (e->flags & (1 << NFTNL_EXPR_NG_MODULUS))
108  mnl_attr_put_u32(nlh, NFTA_NG_MODULUS, htonl(ng->modulus));
109  if (e->flags & (1 << NFTNL_EXPR_NG_TYPE))
110  mnl_attr_put_u32(nlh, NFTA_NG_TYPE, htonl(ng->type));
111  if (e->flags & (1 << NFTNL_EXPR_NG_OFFSET))
112  mnl_attr_put_u32(nlh, NFTA_NG_OFFSET, htonl(ng->offset));
113 }
114 
115 static int
116 nftnl_expr_ng_parse(struct nftnl_expr *e, struct nlattr *attr)
117 {
118  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
119  struct nlattr *tb[NFTA_NG_MAX+1] = {};
120  int ret = 0;
121 
122  if (mnl_attr_parse_nested(attr, nftnl_expr_ng_cb, tb) < 0)
123  return -1;
124 
125  if (tb[NFTA_NG_DREG]) {
126  ng->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_NG_DREG]));
127  e->flags |= (1 << NFTNL_EXPR_NG_DREG);
128  }
129  if (tb[NFTA_NG_MODULUS]) {
130  ng->modulus = ntohl(mnl_attr_get_u32(tb[NFTA_NG_MODULUS]));
131  e->flags |= (1 << NFTNL_EXPR_NG_MODULUS);
132  }
133  if (tb[NFTA_NG_TYPE]) {
134  ng->type = ntohl(mnl_attr_get_u32(tb[NFTA_NG_TYPE]));
135  e->flags |= (1 << NFTNL_EXPR_NG_TYPE);
136  }
137  if (tb[NFTA_NG_OFFSET]) {
138  ng->offset = ntohl(mnl_attr_get_u32(tb[NFTA_NG_OFFSET]));
139  e->flags |= (1 << NFTNL_EXPR_NG_OFFSET);
140  }
141 
142  return ret;
143 }
144 
145 static int nftnl_expr_ng_json_parse(struct nftnl_expr *e, json_t *root,
146  struct nftnl_parse_err *err)
147 {
148 #ifdef JSON_PARSING
149  uint32_t dreg, modulus, type, offset;
150 
151  if (nftnl_jansson_parse_reg(root, "dreg", NFTNL_TYPE_U32,
152  &dreg, err) == 0)
153  nftnl_expr_set_u32(e, NFTNL_EXPR_NG_DREG, dreg);
154 
155  if (nftnl_jansson_parse_val(root, "modulus", NFTNL_TYPE_U32,
156  &modulus, err) == 0)
157  nftnl_expr_set_u32(e, NFTNL_EXPR_NG_MODULUS, modulus);
158 
159  if (nftnl_jansson_parse_val(root, "type", NFTNL_TYPE_U32,
160  &type, err) == 0)
161  nftnl_expr_set_u32(e, NFTNL_EXPR_NG_TYPE, type);
162 
163  if (nftnl_jansson_parse_val(root, "offset", NFTNL_TYPE_U32,
164  &offset, err) == 0)
165  nftnl_expr_set_u32(e, NFTNL_EXPR_NG_OFFSET, offset);
166 
167  return 0;
168 #else
169  errno = EOPNOTSUPP;
170  return -1;
171 #endif
172 }
173 
174 static int
175 nftnl_expr_ng_snprintf_default(char *buf, size_t size,
176  const struct nftnl_expr *e)
177 {
178  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
179  int remain = size, offset = 0, ret;
180 
181  switch (ng->type) {
182  case NFT_NG_INCREMENTAL:
183  ret = snprintf(buf, remain, "reg %u = inc mod %u ",
184  ng->dreg, ng->modulus);
185  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
186  break;
187  case NFT_NG_RANDOM:
188  ret = snprintf(buf, remain, "reg %u = random mod %u ",
189  ng->dreg, ng->modulus);
190  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
191  break;
192  default:
193  return 0;
194  }
195 
196  if (ng->offset) {
197  ret = snprintf(buf + offset, remain, "offset %u ", ng->offset);
198  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
199  }
200 
201  return offset;
202 }
203 
204 static int nftnl_expr_ng_export(char *buf, size_t size,
205  const struct nftnl_expr *e, int type)
206 {
207  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
208 
209  NFTNL_BUF_INIT(b, buf, size);
210 
211  if (e->flags & (1 << NFTNL_EXPR_NG_DREG))
212  nftnl_buf_u32(&b, type, ng->dreg, DREG);
213  if (e->flags & (1 << NFTNL_EXPR_NG_MODULUS))
214  nftnl_buf_u32(&b, type, ng->modulus, MODULUS);
215  if (e->flags & (1 << NFTNL_EXPR_NG_TYPE))
216  nftnl_buf_u32(&b, type, ng->type, TYPE);
217  if (e->flags & (1 << NFTNL_EXPR_NG_OFFSET))
218  nftnl_buf_u32(&b, type, ng->type, OFFSET);
219 
220  return nftnl_buf_done(&b);
221 }
222 
223 static int
224 nftnl_expr_ng_snprintf(char *buf, size_t len, uint32_t type,
225  uint32_t flags, const struct nftnl_expr *e)
226 {
227  switch (type) {
228  case NFTNL_OUTPUT_DEFAULT:
229  return nftnl_expr_ng_snprintf_default(buf, len, e);
230  case NFTNL_OUTPUT_XML:
231  case NFTNL_OUTPUT_JSON:
232  return nftnl_expr_ng_export(buf, len, e, type);
233  default:
234  break;
235  }
236  return -1;
237 }
238 
239 static bool nftnl_expr_ng_cmp(const struct nftnl_expr *e1,
240  const struct nftnl_expr *e2)
241 {
242  struct nftnl_expr_ng *n1 = nftnl_expr_data(e1);
243  struct nftnl_expr_ng *n2 = nftnl_expr_data(e2);
244  bool eq = true;
245 
246  if (e1->flags & (1 << NFTNL_EXPR_NG_DREG))
247  eq &= (n1->dreg == n2->dreg);
248  if (e1->flags & (1 << NFTNL_EXPR_NG_MODULUS))
249  eq &= (n1->modulus == n2->modulus);
250  if (e1->flags & (1 << NFTNL_EXPR_NG_TYPE))
251  eq &= (n1->type == n2->type);
252  if (e1->flags & (1 << NFTNL_EXPR_NG_OFFSET))
253  eq &= (n1->offset == n2->offset);
254 
255  return eq;
256 }
257 
258 struct expr_ops expr_ops_ng = {
259  .name = "numgen",
260  .alloc_len = sizeof(struct nftnl_expr_ng),
261  .max_attr = NFTA_NG_MAX,
262  .cmp = nftnl_expr_ng_cmp,
263  .set = nftnl_expr_ng_set,
264  .get = nftnl_expr_ng_get,
265  .parse = nftnl_expr_ng_parse,
266  .build = nftnl_expr_ng_build,
267  .snprintf = nftnl_expr_ng_snprintf,
268  .json_parse = nftnl_expr_ng_json_parse,
269 };