libnftnl  1.1.8
expr.c
1 /*
2  * (C) 2012 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 #include "internal.h"
12 
13 #include <time.h>
14 #include <endian.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <netinet/in.h>
20 
21 #include <libmnl/libmnl.h>
22 #include <linux/netfilter/nfnetlink.h>
23 #include <linux/netfilter/nf_tables.h>
24 
25 #include <libnftnl/expr.h>
26 
27 EXPORT_SYMBOL(nftnl_expr_alloc);
28 struct nftnl_expr *nftnl_expr_alloc(const char *name)
29 {
30  struct nftnl_expr *expr;
31  struct expr_ops *ops;
32 
33  ops = nftnl_expr_ops_lookup(name);
34  if (ops == NULL)
35  return NULL;
36 
37  expr = calloc(1, sizeof(struct nftnl_expr) + ops->alloc_len);
38  if (expr == NULL)
39  return NULL;
40 
41  /* Manually set expression name attribute */
42  expr->flags |= (1 << NFTNL_EXPR_NAME);
43  expr->ops = ops;
44 
45  return expr;
46 }
47 
48 EXPORT_SYMBOL(nftnl_expr_free);
49 void nftnl_expr_free(const struct nftnl_expr *expr)
50 {
51  if (expr->ops->free)
52  expr->ops->free(expr);
53 
54  xfree(expr);
55 }
56 
57 EXPORT_SYMBOL(nftnl_expr_is_set);
58 bool nftnl_expr_is_set(const struct nftnl_expr *expr, uint16_t type)
59 {
60  return expr->flags & (1 << type);
61 }
62 
63 EXPORT_SYMBOL(nftnl_expr_set);
64 int nftnl_expr_set(struct nftnl_expr *expr, uint16_t type,
65  const void *data, uint32_t data_len)
66 {
67  switch(type) {
68  case NFTNL_EXPR_NAME: /* cannot be modified */
69  return 0;
70  default:
71  if (expr->ops->set(expr, type, data, data_len) < 0)
72  return -1;
73  }
74  expr->flags |= (1 << type);
75  return 0;
76 }
77 
78 EXPORT_SYMBOL(nftnl_expr_set_u8);
79 void
80 nftnl_expr_set_u8(struct nftnl_expr *expr, uint16_t type, uint8_t data)
81 {
82  nftnl_expr_set(expr, type, &data, sizeof(uint8_t));
83 }
84 
85 EXPORT_SYMBOL(nftnl_expr_set_u16);
86 void
87 nftnl_expr_set_u16(struct nftnl_expr *expr, uint16_t type, uint16_t data)
88 {
89  nftnl_expr_set(expr, type, &data, sizeof(uint16_t));
90 }
91 
92 EXPORT_SYMBOL(nftnl_expr_set_u32);
93 void
94 nftnl_expr_set_u32(struct nftnl_expr *expr, uint16_t type, uint32_t data)
95 {
96  nftnl_expr_set(expr, type, &data, sizeof(uint32_t));
97 }
98 
99 EXPORT_SYMBOL(nftnl_expr_set_u64);
100 void
101 nftnl_expr_set_u64(struct nftnl_expr *expr, uint16_t type, uint64_t data)
102 {
103  nftnl_expr_set(expr, type, &data, sizeof(uint64_t));
104 }
105 
106 EXPORT_SYMBOL(nftnl_expr_set_str);
107 int nftnl_expr_set_str(struct nftnl_expr *expr, uint16_t type, const char *str)
108 {
109  return nftnl_expr_set(expr, type, str, strlen(str) + 1);
110 }
111 
112 EXPORT_SYMBOL(nftnl_expr_get);
113 const void *nftnl_expr_get(const struct nftnl_expr *expr,
114  uint16_t type, uint32_t *data_len)
115 {
116  const void *ret;
117 
118  if (!(expr->flags & (1 << type)))
119  return NULL;
120 
121  switch(type) {
122  case NFTNL_EXPR_NAME:
123  *data_len = strlen(expr->ops->name) + 1;
124  ret = expr->ops->name;
125  break;
126  default:
127  ret = expr->ops->get(expr, type, data_len);
128  break;
129  }
130 
131  return ret;
132 }
133 
134 EXPORT_SYMBOL(nftnl_expr_get_u8);
135 uint8_t nftnl_expr_get_u8(const struct nftnl_expr *expr, uint16_t type)
136 {
137  const void *data;
138  uint32_t data_len;
139 
140  data = nftnl_expr_get(expr, type, &data_len);
141  if (data == NULL)
142  return 0;
143 
144  if (data_len != sizeof(uint8_t))
145  return 0;
146 
147  return *((uint8_t *)data);
148 }
149 
150 EXPORT_SYMBOL(nftnl_expr_get_u16);
151 uint16_t nftnl_expr_get_u16(const struct nftnl_expr *expr, uint16_t type)
152 {
153  const void *data;
154  uint32_t data_len;
155 
156  data = nftnl_expr_get(expr, type, &data_len);
157  if (data == NULL)
158  return 0;
159 
160  if (data_len != sizeof(uint16_t))
161  return 0;
162 
163  return *((uint16_t *)data);
164 }
165 
166 EXPORT_SYMBOL(nftnl_expr_get_u32);
167 uint32_t nftnl_expr_get_u32(const struct nftnl_expr *expr, uint16_t type)
168 {
169  const void *data;
170  uint32_t data_len;
171 
172  data = nftnl_expr_get(expr, type, &data_len);
173  if (data == NULL)
174  return 0;
175 
176  if (data_len != sizeof(uint32_t))
177  return 0;
178 
179  return *((uint32_t *)data);
180 }
181 
182 EXPORT_SYMBOL(nftnl_expr_get_u64);
183 uint64_t nftnl_expr_get_u64(const struct nftnl_expr *expr, uint16_t type)
184 {
185  const void *data;
186  uint32_t data_len;
187 
188  data = nftnl_expr_get(expr, type, &data_len);
189  if (data == NULL)
190  return 0;
191 
192  if (data_len != sizeof(uint64_t))
193  return 0;
194 
195  return *((uint64_t *)data);
196 }
197 
198 EXPORT_SYMBOL(nftnl_expr_get_str);
199 const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type)
200 {
201  uint32_t data_len;
202 
203  return (const char *)nftnl_expr_get(expr, type, &data_len);
204 }
205 
206 EXPORT_SYMBOL(nftnl_expr_build_payload);
207 void nftnl_expr_build_payload(struct nlmsghdr *nlh, struct nftnl_expr *expr)
208 {
209  struct nlattr *nest;
210 
211  mnl_attr_put_strz(nlh, NFTA_EXPR_NAME, expr->ops->name);
212 
213  if (!expr->ops->build)
214  return;
215 
216  nest = mnl_attr_nest_start(nlh, NFTA_EXPR_DATA);
217  expr->ops->build(nlh, expr);
218  mnl_attr_nest_end(nlh, nest);
219 }
220 
221 static int nftnl_rule_parse_expr_cb(const struct nlattr *attr, void *data)
222 {
223  const struct nlattr **tb = data;
224  int type = mnl_attr_get_type(attr);
225 
226  if (mnl_attr_type_valid(attr, NFTA_EXPR_MAX) < 0)
227  return MNL_CB_OK;
228 
229  switch (type) {
230  case NFTA_EXPR_NAME:
231  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
232  abi_breakage();
233  break;
234  case NFTA_EXPR_DATA:
235  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
236  abi_breakage();
237  break;
238  }
239 
240  tb[type] = attr;
241  return MNL_CB_OK;
242 }
243 
244 struct nftnl_expr *nftnl_expr_parse(struct nlattr *attr)
245 {
246  struct nlattr *tb[NFTA_EXPR_MAX+1] = {};
247  struct nftnl_expr *expr;
248 
249  if (mnl_attr_parse_nested(attr, nftnl_rule_parse_expr_cb, tb) < 0)
250  goto err1;
251 
252  expr = nftnl_expr_alloc(mnl_attr_get_str(tb[NFTA_EXPR_NAME]));
253  if (expr == NULL)
254  goto err1;
255 
256  if (tb[NFTA_EXPR_DATA] &&
257  expr->ops->parse &&
258  expr->ops->parse(expr, tb[NFTA_EXPR_DATA]) < 0)
259  goto err2;
260 
261  return expr;
262 
263 err2:
264  xfree(expr);
265 err1:
266  return NULL;
267 }
268 
269 EXPORT_SYMBOL(nftnl_expr_snprintf);
270 int nftnl_expr_snprintf(char *buf, size_t size, const struct nftnl_expr *expr,
271  uint32_t type, uint32_t flags)
272 {
273  int ret;
274  unsigned int offset = 0, remain = size;
275 
276  if (size)
277  buf[0] = '\0';
278 
279  if (!expr->ops->snprintf)
280  return 0;
281 
282  ret = expr->ops->snprintf(buf + offset, remain, type, flags, expr);
283  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
284 
285  return offset;
286 }
287 
288 static int nftnl_expr_do_snprintf(char *buf, size_t size, const void *e,
289  uint32_t cmd, uint32_t type, uint32_t flags)
290 {
291  return nftnl_expr_snprintf(buf, size, e, type, flags);
292 }
293 
294 EXPORT_SYMBOL(nftnl_expr_fprintf);
295 int nftnl_expr_fprintf(FILE *fp, const struct nftnl_expr *expr, uint32_t type,
296  uint32_t flags)
297 {
298  return nftnl_fprintf(fp, expr, NFTNL_CMD_UNSPEC, type, flags,
299  nftnl_expr_do_snprintf);
300 }