libnftnl  1.1.5
dynset.c
1 /*
2  * Copyright (c) 2014, 2015 Patrick McHardy <kaber@trash.net>
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 #include "internal.h"
11 
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <inttypes.h>
15 #include <errno.h>
16 #include <arpa/inet.h>
17 #include <libmnl/libmnl.h>
18 #include <linux/netfilter/nf_tables.h>
19 #include <libnftnl/rule.h>
20 #include <libnftnl/expr.h>
21 #include "data_reg.h"
22 #include "expr_ops.h"
23 #include <buffer.h>
24 
26  enum nft_registers sreg_key;
27  enum nft_registers sreg_data;
28  enum nft_dynset_ops op;
29  uint64_t timeout;
30  struct nftnl_expr *expr;
31  char *set_name;
32  uint32_t set_id;
33 };
34 
35 static int
36 nftnl_expr_dynset_set(struct nftnl_expr *e, uint16_t type,
37  const void *data, uint32_t data_len)
38 {
39  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
40 
41  switch (type) {
42  case NFTNL_EXPR_DYNSET_SREG_KEY:
43  memcpy(&dynset->sreg_key, data, sizeof(dynset->sreg_key));
44  break;
45  case NFTNL_EXPR_DYNSET_SREG_DATA:
46  memcpy(&dynset->sreg_data, data, sizeof(dynset->sreg_data));
47  break;
48  case NFTNL_EXPR_DYNSET_OP:
49  memcpy(&dynset->op, data, sizeof(dynset->op));
50  break;
51  case NFTNL_EXPR_DYNSET_TIMEOUT:
52  memcpy(&dynset->timeout, data, sizeof(dynset->timeout));
53  break;
54  case NFTNL_EXPR_DYNSET_SET_NAME:
55  dynset->set_name = strdup((const char *)data);
56  if (!dynset->set_name)
57  return -1;
58  break;
59  case NFTNL_EXPR_DYNSET_SET_ID:
60  memcpy(&dynset->set_id, data, sizeof(dynset->set_id));
61  break;
62  case NFTNL_EXPR_DYNSET_EXPR:
63  dynset->expr = (void *)data;
64  break;
65  default:
66  return -1;
67  }
68  return 0;
69 }
70 
71 static const void *
72 nftnl_expr_dynset_get(const struct nftnl_expr *e, uint16_t type,
73  uint32_t *data_len)
74 {
75  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
76 
77  switch (type) {
78  case NFTNL_EXPR_DYNSET_SREG_KEY:
79  *data_len = sizeof(dynset->sreg_key);
80  return &dynset->sreg_key;
81  case NFTNL_EXPR_DYNSET_SREG_DATA:
82  *data_len = sizeof(dynset->sreg_data);
83  return &dynset->sreg_data;
84  case NFTNL_EXPR_DYNSET_OP:
85  *data_len = sizeof(dynset->op);
86  return &dynset->op;
87  case NFTNL_EXPR_DYNSET_TIMEOUT:
88  *data_len = sizeof(dynset->timeout);
89  return &dynset->timeout;
90  case NFTNL_EXPR_DYNSET_SET_NAME:
91  *data_len = strlen(dynset->set_name) + 1;
92  return dynset->set_name;
93  case NFTNL_EXPR_DYNSET_SET_ID:
94  *data_len = sizeof(dynset->set_id);
95  return &dynset->set_id;
96  case NFTNL_EXPR_DYNSET_EXPR:
97  return dynset->expr;
98  }
99  return NULL;
100 }
101 
102 static int nftnl_expr_dynset_cb(const struct nlattr *attr, void *data)
103 {
104  const struct nlattr **tb = data;
105  int type = mnl_attr_get_type(attr);
106 
107  if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
108  return MNL_CB_OK;
109 
110  switch (type) {
111  case NFTA_DYNSET_SREG_KEY:
112  case NFTA_DYNSET_SREG_DATA:
113  case NFTA_DYNSET_SET_ID:
114  case NFTA_DYNSET_OP:
115  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
116  abi_breakage();
117  break;
118  case NFTA_DYNSET_TIMEOUT:
119  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
120  abi_breakage();
121  break;
122  case NFTA_DYNSET_SET_NAME:
123  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
124  abi_breakage();
125  break;
126  case NFTA_DYNSET_EXPR:
127  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
128  abi_breakage();
129  break;
130  }
131 
132  tb[type] = attr;
133  return MNL_CB_OK;
134 }
135 
136 static void
137 nftnl_expr_dynset_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
138 {
139  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
140  struct nlattr *nest;
141 
142  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_KEY))
143  mnl_attr_put_u32(nlh, NFTA_DYNSET_SREG_KEY, htonl(dynset->sreg_key));
144  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_DATA))
145  mnl_attr_put_u32(nlh, NFTA_DYNSET_SREG_DATA, htonl(dynset->sreg_data));
146  if (e->flags & (1 << NFTNL_EXPR_DYNSET_OP))
147  mnl_attr_put_u32(nlh, NFTA_DYNSET_OP, htonl(dynset->op));
148  if (e->flags & (1 << NFTNL_EXPR_DYNSET_TIMEOUT))
149  mnl_attr_put_u64(nlh, NFTA_DYNSET_TIMEOUT, htobe64(dynset->timeout));
150  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_NAME))
151  mnl_attr_put_strz(nlh, NFTA_DYNSET_SET_NAME, dynset->set_name);
152  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_ID))
153  mnl_attr_put_u32(nlh, NFTA_DYNSET_SET_ID, htonl(dynset->set_id));
154  if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) {
155  nest = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPR);
156  nftnl_expr_build_payload(nlh, dynset->expr);
157  mnl_attr_nest_end(nlh, nest);
158  }
159 }
160 
161 static int
162 nftnl_expr_dynset_parse(struct nftnl_expr *e, struct nlattr *attr)
163 {
164  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
165  struct nlattr *tb[NFTA_SET_MAX+1] = {};
166  int ret = 0;
167 
168  if (mnl_attr_parse_nested(attr, nftnl_expr_dynset_cb, tb) < 0)
169  return -1;
170 
171  if (tb[NFTA_DYNSET_SREG_KEY]) {
172  dynset->sreg_key = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_SREG_KEY]));
173  e->flags |= (1 << NFTNL_EXPR_DYNSET_SREG_KEY);
174  }
175  if (tb[NFTA_DYNSET_SREG_DATA]) {
176  dynset->sreg_data = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_SREG_DATA]));
177  e->flags |= (1 << NFTNL_EXPR_DYNSET_SREG_DATA);
178  }
179  if (tb[NFTA_DYNSET_OP]) {
180  dynset->op = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_OP]));
181  e->flags |= (1 << NFTNL_EXPR_DYNSET_OP);
182  }
183  if (tb[NFTA_DYNSET_TIMEOUT]) {
184  dynset->timeout = be64toh(mnl_attr_get_u64(tb[NFTA_DYNSET_TIMEOUT]));
185  e->flags |= (1 << NFTNL_EXPR_DYNSET_TIMEOUT);
186  }
187  if (tb[NFTA_DYNSET_SET_NAME]) {
188  dynset->set_name =
189  strdup(mnl_attr_get_str(tb[NFTA_DYNSET_SET_NAME]));
190  if (!dynset->set_name)
191  return -1;
192  e->flags |= (1 << NFTNL_EXPR_DYNSET_SET_NAME);
193  }
194  if (tb[NFTA_DYNSET_SET_ID]) {
195  dynset->set_id = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_SET_ID]));
196  e->flags |= (1 << NFTNL_EXPR_DYNSET_SET_ID);
197  }
198  if (tb[NFTA_DYNSET_EXPR]) {
199  e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPR);
200  dynset->expr = nftnl_expr_parse(tb[NFTA_DYNSET_EXPR]);
201  if (dynset->expr == NULL)
202  return -1;
203  }
204 
205  return ret;
206 }
207 
208 static const char *op2str_array[] = {
209  [NFT_DYNSET_OP_ADD] = "add",
210  [NFT_DYNSET_OP_UPDATE] = "update",
211  [NFT_DYNSET_OP_DELETE] = "delete",
212 };
213 
214 static const char *op2str(enum nft_dynset_ops op)
215 {
216  if (op > NFT_DYNSET_OP_DELETE)
217  return "unknown";
218  return op2str_array[op];
219 }
220 
221 static int
222 nftnl_expr_dynset_snprintf_default(char *buf, size_t size,
223  const struct nftnl_expr *e)
224 {
225  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
226  struct nftnl_expr *expr;
227  int remain = size, offset = 0, ret;
228 
229  ret = snprintf(buf, remain, "%s reg_key %u set %s ",
230  op2str(dynset->op), dynset->sreg_key, dynset->set_name);
231  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
232 
233  if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_DATA)) {
234  ret = snprintf(buf + offset, remain, "sreg_data %u ",
235  dynset->sreg_data);
236  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
237  }
238  if (e->flags & (1 << NFTNL_EXPR_DYNSET_TIMEOUT)) {
239  ret = snprintf(buf + offset, remain, "timeout %"PRIu64"ms ",
240  dynset->timeout);
241  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
242  }
243  if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) {
244  expr = dynset->expr;
245  ret = snprintf(buf + offset, remain, "expr [ %s ",
246  expr->ops->name);
247  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
248 
249  ret = nftnl_expr_snprintf(buf + offset, remain, expr,
250  NFTNL_OUTPUT_DEFAULT,
251  NFTNL_OF_EVENT_ANY);
252  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
253 
254  ret = snprintf(buf + offset, remain, "] ");
255  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
256  }
257 
258  return offset;
259 }
260 
261 static int
262 nftnl_expr_dynset_snprintf(char *buf, size_t size, uint32_t type,
263  uint32_t flags, const struct nftnl_expr *e)
264 {
265  switch (type) {
266  case NFTNL_OUTPUT_DEFAULT:
267  return nftnl_expr_dynset_snprintf_default(buf, size, e);
268  case NFTNL_OUTPUT_XML:
269  case NFTNL_OUTPUT_JSON:
270  default:
271  break;
272  }
273  return -1;
274 }
275 
276 static void nftnl_expr_dynset_free(const struct nftnl_expr *e)
277 {
278  struct nftnl_expr_dynset *dynset = nftnl_expr_data(e);
279 
280  xfree(dynset->set_name);
281 }
282 
283 struct expr_ops expr_ops_dynset = {
284  .name = "dynset",
285  .alloc_len = sizeof(struct nftnl_expr_dynset),
286  .max_attr = NFTA_DYNSET_MAX,
287  .free = nftnl_expr_dynset_free,
288  .set = nftnl_expr_dynset_set,
289  .get = nftnl_expr_dynset_get,
290  .parse = nftnl_expr_dynset_parse,
291  .build = nftnl_expr_dynset_build,
292  .snprintf = nftnl_expr_dynset_snprintf,
293 };