libnftnl  1.1.2
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  struct {
29  const char *name;
30  uint32_t id;
31  } map;
32 };
33 
34 static int
35 nftnl_expr_ng_set(struct nftnl_expr *e, uint16_t type,
36  const void *data, uint32_t data_len)
37 {
38  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
39 
40  switch (type) {
41  case NFTNL_EXPR_NG_DREG:
42  memcpy(&ng->dreg, data, sizeof(ng->dreg));
43  break;
44  case NFTNL_EXPR_NG_MODULUS:
45  memcpy(&ng->modulus, data, sizeof(ng->modulus));
46  break;
47  case NFTNL_EXPR_NG_TYPE:
48  memcpy(&ng->type, data, sizeof(ng->type));
49  break;
50  case NFTNL_EXPR_NG_OFFSET:
51  memcpy(&ng->offset, data, sizeof(ng->offset));
52  break;
53  case NFTNL_EXPR_NG_SET_NAME:
54  ng->map.name = strdup(data);
55  if (!ng->map.name)
56  return -1;
57  break;
58  case NFTNL_EXPR_NG_SET_ID:
59  memcpy(&ng->map.id, data, sizeof(ng->map.id));
60  break;
61  default:
62  return -1;
63  }
64  return 0;
65 }
66 
67 static const void *
68 nftnl_expr_ng_get(const struct nftnl_expr *e, uint16_t type,
69  uint32_t *data_len)
70 {
71  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
72 
73  switch (type) {
74  case NFTNL_EXPR_NG_DREG:
75  *data_len = sizeof(ng->dreg);
76  return &ng->dreg;
77  case NFTNL_EXPR_NG_MODULUS:
78  *data_len = sizeof(ng->modulus);
79  return &ng->modulus;
80  case NFTNL_EXPR_NG_TYPE:
81  *data_len = sizeof(ng->type);
82  return &ng->type;
83  case NFTNL_EXPR_NG_OFFSET:
84  *data_len = sizeof(ng->offset);
85  return &ng->offset;
86  case NFTNL_EXPR_NG_SET_NAME:
87  *data_len = strlen(ng->map.name) + 1;
88  return ng->map.name;
89  case NFTNL_EXPR_NG_SET_ID:
90  *data_len = sizeof(ng->map.id);
91  return &ng->map.id;
92  }
93  return NULL;
94 }
95 
96 static int nftnl_expr_ng_cb(const struct nlattr *attr, void *data)
97 {
98  const struct nlattr **tb = data;
99  int type = mnl_attr_get_type(attr);
100 
101  if (mnl_attr_type_valid(attr, NFTA_NG_MAX) < 0)
102  return MNL_CB_OK;
103 
104  switch (type) {
105  case NFTA_NG_DREG:
106  case NFTA_NG_MODULUS:
107  case NFTA_NG_TYPE:
108  case NFTA_NG_OFFSET:
109  case NFTA_NG_SET_ID:
110  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
111  abi_breakage();
112  break;
113  case NFTA_NG_SET_NAME:
114  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 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_ng_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
125 {
126  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
127 
128  if (e->flags & (1 << NFTNL_EXPR_NG_DREG))
129  mnl_attr_put_u32(nlh, NFTA_NG_DREG, htonl(ng->dreg));
130  if (e->flags & (1 << NFTNL_EXPR_NG_MODULUS))
131  mnl_attr_put_u32(nlh, NFTA_NG_MODULUS, htonl(ng->modulus));
132  if (e->flags & (1 << NFTNL_EXPR_NG_TYPE))
133  mnl_attr_put_u32(nlh, NFTA_NG_TYPE, htonl(ng->type));
134  if (e->flags & (1 << NFTNL_EXPR_NG_OFFSET))
135  mnl_attr_put_u32(nlh, NFTA_NG_OFFSET, htonl(ng->offset));
136  if (e->flags & (1 << NFTNL_EXPR_NG_SET_NAME))
137  mnl_attr_put_str(nlh, NFTA_NG_SET_NAME, ng->map.name);
138  if (e->flags & (1 << NFTNL_EXPR_NG_SET_ID))
139  mnl_attr_put_u32(nlh, NFTA_NG_SET_ID, htonl(ng->map.id));
140 }
141 
142 static int
143 nftnl_expr_ng_parse(struct nftnl_expr *e, struct nlattr *attr)
144 {
145  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
146  struct nlattr *tb[NFTA_NG_MAX+1] = {};
147  int ret = 0;
148 
149  if (mnl_attr_parse_nested(attr, nftnl_expr_ng_cb, tb) < 0)
150  return -1;
151 
152  if (tb[NFTA_NG_DREG]) {
153  ng->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_NG_DREG]));
154  e->flags |= (1 << NFTNL_EXPR_NG_DREG);
155  }
156  if (tb[NFTA_NG_MODULUS]) {
157  ng->modulus = ntohl(mnl_attr_get_u32(tb[NFTA_NG_MODULUS]));
158  e->flags |= (1 << NFTNL_EXPR_NG_MODULUS);
159  }
160  if (tb[NFTA_NG_TYPE]) {
161  ng->type = ntohl(mnl_attr_get_u32(tb[NFTA_NG_TYPE]));
162  e->flags |= (1 << NFTNL_EXPR_NG_TYPE);
163  }
164  if (tb[NFTA_NG_OFFSET]) {
165  ng->offset = ntohl(mnl_attr_get_u32(tb[NFTA_NG_OFFSET]));
166  e->flags |= (1 << NFTNL_EXPR_NG_OFFSET);
167  }
168  if (tb[NFTA_NG_SET_NAME]) {
169  ng->map.name =
170  strdup(mnl_attr_get_str(tb[NFTA_NG_SET_NAME]));
171  e->flags |= (1 << NFTNL_EXPR_NG_SET_NAME);
172  }
173  if (tb[NFTA_NG_SET_ID]) {
174  ng->map.id =
175  ntohl(mnl_attr_get_u32(tb[NFTA_NG_SET_ID]));
176  e->flags |= (1 << NFTNL_EXPR_NG_SET_ID);
177  }
178 
179  return ret;
180 }
181 
182 static int
183 nftnl_expr_ng_snprintf_default(char *buf, size_t size,
184  const struct nftnl_expr *e)
185 {
186  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
187  int remain = size, offset = 0, ret;
188 
189  switch (ng->type) {
190  case NFT_NG_INCREMENTAL:
191  ret = snprintf(buf, remain, "reg %u = inc mod %u ",
192  ng->dreg, ng->modulus);
193  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
194  break;
195  case NFT_NG_RANDOM:
196  ret = snprintf(buf, remain, "reg %u = random mod %u ",
197  ng->dreg, ng->modulus);
198  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
199  break;
200  default:
201  return 0;
202  }
203 
204  if (ng->offset) {
205  ret = snprintf(buf + offset, remain, "offset %u ", ng->offset);
206  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
207  }
208 
209  if (ng->map.id) {
210  ret = snprintf(buf + offset, remain, "set %s id %u ",
211  ng->map.name, ng->map.id);
212  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
213  }
214 
215  return offset;
216 }
217 
218 static int
219 nftnl_expr_ng_snprintf(char *buf, size_t len, uint32_t type,
220  uint32_t flags, const struct nftnl_expr *e)
221 {
222  switch (type) {
223  case NFTNL_OUTPUT_DEFAULT:
224  return nftnl_expr_ng_snprintf_default(buf, len, e);
225  case NFTNL_OUTPUT_XML:
226  case NFTNL_OUTPUT_JSON:
227  default:
228  break;
229  }
230  return -1;
231 }
232 
233 struct expr_ops expr_ops_ng = {
234  .name = "numgen",
235  .alloc_len = sizeof(struct nftnl_expr_ng),
236  .max_attr = NFTA_NG_MAX,
237  .set = nftnl_expr_ng_set,
238  .get = nftnl_expr_ng_get,
239  .parse = nftnl_expr_ng_parse,
240  .build = nftnl_expr_ng_build,
241  .snprintf = nftnl_expr_ng_snprintf,
242 };