libnftnl  1.0.2
lookup.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
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  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #include "internal.h"
13 
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h> /* for memcpy */
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <libmnl/libmnl.h>
20 #include <linux/netfilter/nf_tables.h>
21 #include <libnftnl/rule.h>
22 #include <libnftnl/expr.h>
23 #include "data_reg.h"
24 #include "expr_ops.h"
25 
26 #ifndef IFNAMSIZ
27 #define IFNAMSIZ 16
28 #endif
29 
31  enum nft_registers sreg;
32  enum nft_registers dreg;
33  char set_name[IFNAMSIZ];
34  uint32_t set_id;
35 };
36 
37 static int
38 nft_rule_expr_lookup_set(struct nft_rule_expr *e, uint16_t type,
39  const void *data, uint32_t data_len)
40 {
41  struct nft_expr_lookup *lookup = nft_expr_data(e);
42 
43  switch(type) {
44  case NFT_EXPR_LOOKUP_SREG:
45  lookup->sreg = *((uint32_t *)data);
46  break;
47  case NFT_EXPR_LOOKUP_DREG:
48  lookup->dreg = *((uint32_t *)data);
49  break;
50  case NFT_EXPR_LOOKUP_SET:
51  snprintf(lookup->set_name, sizeof(lookup->set_name), "%s",
52  (const char *)data);
53  break;
54  case NFT_EXPR_LOOKUP_SET_ID:
55  lookup->set_id = *((uint32_t *)data);
56  break;
57  default:
58  return -1;
59  }
60  return 0;
61 }
62 
63 static const void *
64 nft_rule_expr_lookup_get(const struct nft_rule_expr *e, uint16_t type,
65  uint32_t *data_len)
66 {
67  struct nft_expr_lookup *lookup = nft_expr_data(e);
68 
69  switch(type) {
70  case NFT_EXPR_LOOKUP_SREG:
71  *data_len = sizeof(lookup->sreg);
72  return &lookup->sreg;
73  case NFT_EXPR_LOOKUP_DREG:
74  *data_len = sizeof(lookup->dreg);
75  return &lookup->dreg;
76  case NFT_EXPR_LOOKUP_SET:
77  return lookup->set_name;
78  case NFT_EXPR_LOOKUP_SET_ID:
79  return &lookup->set_id;
80  }
81  return NULL;
82 }
83 
84 static int nft_rule_expr_lookup_cb(const struct nlattr *attr, void *data)
85 {
86  const struct nlattr **tb = data;
87  int type = mnl_attr_get_type(attr);
88 
89  if (mnl_attr_type_valid(attr, NFTA_LOOKUP_MAX) < 0)
90  return MNL_CB_OK;
91 
92  switch(type) {
93  case NFTA_LOOKUP_SREG:
94  case NFTA_LOOKUP_DREG:
95  case NFTA_LOOKUP_SET_ID:
96  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
97  perror("mnl_attr_validate");
98  return MNL_CB_ERROR;
99  }
100  break;
101  case NFTA_LOOKUP_SET:
102  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
103  perror("mnl_attr_validate");
104  return MNL_CB_ERROR;
105  }
106  break;
107  }
108 
109  tb[type] = attr;
110  return MNL_CB_OK;
111 }
112 
113 static void
114 nft_rule_expr_lookup_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
115 {
116  struct nft_expr_lookup *lookup = nft_expr_data(e);
117 
118  if (e->flags & (1 << NFT_EXPR_LOOKUP_SREG))
119  mnl_attr_put_u32(nlh, NFTA_LOOKUP_SREG, htonl(lookup->sreg));
120  if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG))
121  mnl_attr_put_u32(nlh, NFTA_LOOKUP_DREG, htonl(lookup->dreg));
122  if (e->flags & (1 << NFT_EXPR_LOOKUP_SET))
123  mnl_attr_put_strz(nlh, NFTA_LOOKUP_SET, lookup->set_name);
124  if (e->flags & (1 << NFT_EXPR_LOOKUP_SET_ID)) {
125  mnl_attr_put_u32(nlh, NFTA_LOOKUP_SET_ID,
126  htonl(lookup->set_id));
127  }
128 }
129 
130 static int
131 nft_rule_expr_lookup_parse(struct nft_rule_expr *e, struct nlattr *attr)
132 {
133  struct nft_expr_lookup *lookup = nft_expr_data(e);
134  struct nlattr *tb[NFTA_LOOKUP_MAX+1] = {};
135  int ret = 0;
136 
137  if (mnl_attr_parse_nested(attr, nft_rule_expr_lookup_cb, tb) < 0)
138  return -1;
139 
140  if (tb[NFTA_LOOKUP_SREG]) {
141  lookup->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_LOOKUP_SREG]));
142  e->flags |= (1 << NFT_EXPR_LOOKUP_SREG);
143  }
144  if (tb[NFTA_LOOKUP_DREG]) {
145  lookup->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_LOOKUP_DREG]));
146  e->flags |= (1 << NFT_EXPR_LOOKUP_DREG);
147  }
148  if (tb[NFTA_LOOKUP_SET]) {
149  strcpy(lookup->set_name, mnl_attr_get_str(tb[NFTA_LOOKUP_SET]));
150  e->flags |= (1 << NFT_EXPR_LOOKUP_SET);
151  }
152  if (tb[NFTA_LOOKUP_SET_ID]) {
153  lookup->set_id =
154  ntohl(mnl_attr_get_u32(tb[NFTA_LOOKUP_SET_ID]));
155  e->flags |= (1 << NFT_EXPR_LOOKUP_SET_ID);
156  }
157 
158  return ret;
159 }
160 
161 static int
162 nft_rule_expr_lookup_json_parse(struct nft_rule_expr *e, json_t *root,
163  struct nft_parse_err *err)
164 {
165 #ifdef JSON_PARSING
166  const char *set_name;
167  uint32_t sreg, dreg;
168 
169  set_name = nft_jansson_parse_str(root, "set", err);
170  if (set_name != NULL)
171  nft_rule_expr_set_str(e, NFT_EXPR_LOOKUP_SET, set_name);
172 
173  if (nft_jansson_parse_reg(root, "sreg", NFT_TYPE_U32, &sreg, err) == 0)
174  nft_rule_expr_set_u32(e, NFT_EXPR_LOOKUP_SREG, sreg);
175 
176  if (nft_jansson_parse_reg(root, "dreg", NFT_TYPE_U32, &dreg, err) == 0)
177  nft_rule_expr_set_u32(e, NFT_EXPR_LOOKUP_DREG, dreg);
178 
179  return 0;
180 #else
181  errno = EOPNOTSUPP;
182  return -1;
183 #endif
184 }
185 
186 static int
187 nft_rule_expr_lookup_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
188  struct nft_parse_err *err)
189 {
190 #ifdef XML_PARSING
191  const char *set_name;
192  uint32_t sreg, dreg;
193 
194  set_name = nft_mxml_str_parse(tree, "set", MXML_DESCEND_FIRST,
195  NFT_XML_MAND, err);
196  if (set_name != NULL)
197  nft_rule_expr_set_str(e, NFT_EXPR_LOOKUP_SET, set_name);
198 
199  if (nft_mxml_reg_parse(tree, "sreg", &sreg, MXML_DESCEND, NFT_XML_MAND,
200  err) == 0)
201  nft_rule_expr_set_u32(e, NFT_EXPR_LOOKUP_SREG, sreg);
202 
203  if (nft_mxml_reg_parse(tree, "dreg", &dreg, MXML_DESCEND, NFT_XML_OPT,
204  err) == 0)
205  nft_rule_expr_set_u32(e, NFT_EXPR_LOOKUP_DREG, dreg);
206 
207  return 0;
208 #else
209  errno = EOPNOTSUPP;
210  return -1;
211 #endif
212 }
213 
214 static int
215 nft_rule_expr_lookup_snprintf_json(char *buf, size_t size,
216  struct nft_rule_expr *e)
217 {
218  int len = size, offset = 0, ret;
219  struct nft_expr_lookup *l = nft_expr_data(e);
220 
221  if (e->flags & (1 << NFT_EXPR_LOOKUP_SET)) {
222  ret = snprintf(buf, len, "\"set\":\"%s\",", l->set_name);
223  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
224  }
225  if (e->flags & (1 << NFT_EXPR_LOOKUP_SREG)) {
226  ret = snprintf(buf + offset, len, "\"sreg\":%u,", l->sreg);
227  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
228  }
229  if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG)) {
230  ret = snprintf(buf + offset, len, "\"dreg\":%u,", l->dreg);
231  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
232  }
233  /* Remove the last comma characther */
234  if (offset > 0)
235  offset--;
236 
237  return offset;
238 }
239 
240 static int
241 nft_rule_expr_lookup_snprintf_xml(char *buf, size_t size,
242  struct nft_rule_expr *e)
243 {
244  int len = size, offset = 0, ret;
245  struct nft_expr_lookup *l = nft_expr_data(e);
246 
247  if (e->flags & (1 << NFT_EXPR_LOOKUP_SET)) {
248  ret = snprintf(buf, len, "<set>%s</set>", l->set_name);
249  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
250  }
251  if (e->flags & (1 << NFT_EXPR_LOOKUP_SREG)) {
252  ret = snprintf(buf + offset, len, "<sreg>%u</sreg>", l->sreg);
253  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
254  }
255  if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG)) {
256  ret = snprintf(buf + offset, len, "<dreg>%u</dreg>", l->dreg);
257  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
258  }
259 
260  return offset;
261 }
262 
263 static int
264 nft_rule_expr_lookup_snprintf_default(char *buf, size_t size,
265  struct nft_rule_expr *e)
266 {
267  int len = size, offset = 0, ret;
268  struct nft_expr_lookup *l = nft_expr_data(e);
269 
270  ret = snprintf(buf, len, "reg %u set %s ", l->sreg, l->set_name);
271  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
272 
273 
274  if (e->flags & (1 << NFT_EXPR_LOOKUP_DREG)) {
275  ret = snprintf(buf+offset, len, "dreg %u ", l->dreg);
276  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
277  }
278 
279  return offset;
280 }
281 
282 static int
283 nft_rule_expr_lookup_snprintf(char *buf, size_t size, uint32_t type,
284  uint32_t flags, struct nft_rule_expr *e)
285 {
286 
287  switch(type) {
288  case NFT_OUTPUT_DEFAULT:
289  return nft_rule_expr_lookup_snprintf_default(buf, size, e);
290  case NFT_OUTPUT_XML:
291  return nft_rule_expr_lookup_snprintf_xml(buf, size, e);
292  case NFT_OUTPUT_JSON:
293  return nft_rule_expr_lookup_snprintf_json(buf, size, e);
294  default:
295  break;
296  }
297  return -1;
298 }
299 
300 struct expr_ops expr_ops_lookup = {
301  .name = "lookup",
302  .alloc_len = sizeof(struct nft_expr_lookup),
303  .max_attr = NFTA_LOOKUP_MAX,
304  .set = nft_rule_expr_lookup_set,
305  .get = nft_rule_expr_lookup_get,
306  .parse = nft_rule_expr_lookup_parse,
307  .build = nft_rule_expr_lookup_build,
308  .snprintf = nft_rule_expr_lookup_snprintf,
309  .xml_parse = nft_rule_expr_lookup_xml_parse,
310  .json_parse = nft_rule_expr_lookup_json_parse,
311 };
312 
313 static void __init expr_lookup_init(void)
314 {
315  nft_expr_ops_register(&expr_ops_lookup);
316 }