libnftnl  1.0.6
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 
25  enum nft_registers sreg;
26  enum nft_registers dreg;
27  char *set_name;
28  uint32_t set_id;
29 };
30 
31 static int
32 nftnl_expr_lookup_set(struct nftnl_expr *e, uint16_t type,
33  const void *data, uint32_t data_len)
34 {
35  struct nftnl_expr_lookup *lookup = nftnl_expr_data(e);
36 
37  switch(type) {
38  case NFTNL_EXPR_LOOKUP_SREG:
39  lookup->sreg = *((uint32_t *)data);
40  break;
41  case NFTNL_EXPR_LOOKUP_DREG:
42  lookup->dreg = *((uint32_t *)data);
43  break;
44  case NFTNL_EXPR_LOOKUP_SET:
45  lookup->set_name = strdup((const char *)data);
46  break;
47  case NFTNL_EXPR_LOOKUP_SET_ID:
48  lookup->set_id = *((uint32_t *)data);
49  break;
50  default:
51  return -1;
52  }
53  return 0;
54 }
55 
56 static const void *
57 nftnl_expr_lookup_get(const struct nftnl_expr *e, uint16_t type,
58  uint32_t *data_len)
59 {
60  struct nftnl_expr_lookup *lookup = nftnl_expr_data(e);
61 
62  switch(type) {
63  case NFTNL_EXPR_LOOKUP_SREG:
64  *data_len = sizeof(lookup->sreg);
65  return &lookup->sreg;
66  case NFTNL_EXPR_LOOKUP_DREG:
67  *data_len = sizeof(lookup->dreg);
68  return &lookup->dreg;
69  case NFTNL_EXPR_LOOKUP_SET:
70  return lookup->set_name;
71  case NFTNL_EXPR_LOOKUP_SET_ID:
72  return &lookup->set_id;
73  }
74  return NULL;
75 }
76 
77 static int nftnl_expr_lookup_cb(const struct nlattr *attr, void *data)
78 {
79  const struct nlattr **tb = data;
80  int type = mnl_attr_get_type(attr);
81 
82  if (mnl_attr_type_valid(attr, NFTA_LOOKUP_MAX) < 0)
83  return MNL_CB_OK;
84 
85  switch(type) {
86  case NFTA_LOOKUP_SREG:
87  case NFTA_LOOKUP_DREG:
88  case NFTA_LOOKUP_SET_ID:
89  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
90  abi_breakage();
91  break;
92  case NFTA_LOOKUP_SET:
93  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
94  abi_breakage();
95  break;
96  }
97 
98  tb[type] = attr;
99  return MNL_CB_OK;
100 }
101 
102 static void
103 nftnl_expr_lookup_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
104 {
105  struct nftnl_expr_lookup *lookup = nftnl_expr_data(e);
106 
107  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_SREG))
108  mnl_attr_put_u32(nlh, NFTA_LOOKUP_SREG, htonl(lookup->sreg));
109  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_DREG))
110  mnl_attr_put_u32(nlh, NFTA_LOOKUP_DREG, htonl(lookup->dreg));
111  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_SET))
112  mnl_attr_put_strz(nlh, NFTA_LOOKUP_SET, lookup->set_name);
113  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_SET_ID)) {
114  mnl_attr_put_u32(nlh, NFTA_LOOKUP_SET_ID,
115  htonl(lookup->set_id));
116  }
117 }
118 
119 static int
120 nftnl_expr_lookup_parse(struct nftnl_expr *e, struct nlattr *attr)
121 {
122  struct nftnl_expr_lookup *lookup = nftnl_expr_data(e);
123  struct nlattr *tb[NFTA_LOOKUP_MAX+1] = {};
124  int ret = 0;
125 
126  if (mnl_attr_parse_nested(attr, nftnl_expr_lookup_cb, tb) < 0)
127  return -1;
128 
129  if (tb[NFTA_LOOKUP_SREG]) {
130  lookup->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_LOOKUP_SREG]));
131  e->flags |= (1 << NFTNL_EXPR_LOOKUP_SREG);
132  }
133  if (tb[NFTA_LOOKUP_DREG]) {
134  lookup->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_LOOKUP_DREG]));
135  e->flags |= (1 << NFTNL_EXPR_LOOKUP_DREG);
136  }
137  if (tb[NFTA_LOOKUP_SET]) {
138  lookup->set_name =
139  strdup(mnl_attr_get_str(tb[NFTA_LOOKUP_SET]));
140  e->flags |= (1 << NFTNL_EXPR_LOOKUP_SET);
141  }
142  if (tb[NFTA_LOOKUP_SET_ID]) {
143  lookup->set_id =
144  ntohl(mnl_attr_get_u32(tb[NFTA_LOOKUP_SET_ID]));
145  e->flags |= (1 << NFTNL_EXPR_LOOKUP_SET_ID);
146  }
147 
148  return ret;
149 }
150 
151 static int
152 nftnl_expr_lookup_json_parse(struct nftnl_expr *e, json_t *root,
153  struct nftnl_parse_err *err)
154 {
155 #ifdef JSON_PARSING
156  const char *set_name;
157  uint32_t sreg, dreg;
158 
159  set_name = nftnl_jansson_parse_str(root, "set", err);
160  if (set_name != NULL)
161  nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
162 
163  if (nftnl_jansson_parse_reg(root, "sreg", NFTNL_TYPE_U32, &sreg, err) == 0)
164  nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
165 
166  if (nftnl_jansson_parse_reg(root, "dreg", NFTNL_TYPE_U32, &dreg, err) == 0)
167  nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_DREG, dreg);
168 
169  return 0;
170 #else
171  errno = EOPNOTSUPP;
172  return -1;
173 #endif
174 }
175 
176 static int
177 nftnl_expr_lookup_xml_parse(struct nftnl_expr *e, mxml_node_t *tree,
178  struct nftnl_parse_err *err)
179 {
180 #ifdef XML_PARSING
181  const char *set_name;
182  uint32_t sreg, dreg;
183 
184  set_name = nftnl_mxml_str_parse(tree, "set", MXML_DESCEND_FIRST,
185  NFTNL_XML_MAND, err);
186  if (set_name != NULL)
187  nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
188 
189  if (nftnl_mxml_reg_parse(tree, "sreg", &sreg, MXML_DESCEND, NFTNL_XML_MAND,
190  err) == 0)
191  nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
192 
193  if (nftnl_mxml_reg_parse(tree, "dreg", &dreg, MXML_DESCEND, NFTNL_XML_OPT,
194  err) == 0)
195  nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_DREG, dreg);
196 
197  return 0;
198 #else
199  errno = EOPNOTSUPP;
200  return -1;
201 #endif
202 }
203 
204 static int
205 nftnl_expr_lookup_export(char *buf, size_t size,
206  const struct nftnl_expr *e, int type)
207 {
208  struct nftnl_expr_lookup *l = nftnl_expr_data(e);
209  NFTNL_BUF_INIT(b, buf, size);
210 
211  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_SET))
212  nftnl_buf_str(&b, type, l->set_name, SET);
213  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_SREG))
214  nftnl_buf_u32(&b, type, l->sreg, SREG);
215  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_DREG))
216  nftnl_buf_u32(&b, type, l->dreg, DREG);
217 
218  return nftnl_buf_done(&b);
219 }
220 
221 static int
222 nftnl_expr_lookup_snprintf_default(char *buf, size_t size,
223  const struct nftnl_expr *e)
224 {
225  int len = size, offset = 0, ret;
226  struct nftnl_expr_lookup *l = nftnl_expr_data(e);
227 
228  ret = snprintf(buf, len, "reg %u set %s ", l->sreg, l->set_name);
229  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
230 
231 
232  if (e->flags & (1 << NFTNL_EXPR_LOOKUP_DREG)) {
233  ret = snprintf(buf+offset, len, "dreg %u ", l->dreg);
234  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
235  }
236 
237  return offset;
238 }
239 
240 static int
241 nftnl_expr_lookup_snprintf(char *buf, size_t size, uint32_t type,
242  uint32_t flags, const struct nftnl_expr *e)
243 {
244 
245  switch(type) {
246  case NFTNL_OUTPUT_DEFAULT:
247  return nftnl_expr_lookup_snprintf_default(buf, size, e);
248  case NFTNL_OUTPUT_XML:
249  case NFTNL_OUTPUT_JSON:
250  return nftnl_expr_lookup_export(buf, size, e, type);
251  default:
252  break;
253  }
254  return -1;
255 }
256 
257 static void nftnl_expr_lookup_free(const struct nftnl_expr *e)
258 {
259  struct nftnl_expr_lookup *lookup = nftnl_expr_data(e);
260 
261  xfree(lookup->set_name);
262 }
263 
264 struct expr_ops expr_ops_lookup = {
265  .name = "lookup",
266  .alloc_len = sizeof(struct nftnl_expr_lookup),
267  .max_attr = NFTA_LOOKUP_MAX,
268  .free = nftnl_expr_lookup_free,
269  .set = nftnl_expr_lookup_set,
270  .get = nftnl_expr_lookup_get,
271  .parse = nftnl_expr_lookup_parse,
272  .build = nftnl_expr_lookup_build,
273  .snprintf = nftnl_expr_lookup_snprintf,
274  .xml_parse = nftnl_expr_lookup_xml_parse,
275  .json_parse = nftnl_expr_lookup_json_parse,
276 };