libnftnl  1.1.7
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 void nftnl_expr_build_payload(struct nlmsghdr *nlh, struct nftnl_expr *expr)
207 {
208  struct nlattr *nest;
209 
210  mnl_attr_put_strz(nlh, NFTA_EXPR_NAME, expr->ops->name);
211 
212  if (!expr->ops->build)
213  return;
214 
215  nest = mnl_attr_nest_start(nlh, NFTA_EXPR_DATA);
216  expr->ops->build(nlh, expr);
217  mnl_attr_nest_end(nlh, nest);
218 }
219 
220 static int nftnl_rule_parse_expr_cb(const struct nlattr *attr, void *data)
221 {
222  const struct nlattr **tb = data;
223  int type = mnl_attr_get_type(attr);
224 
225  if (mnl_attr_type_valid(attr, NFTA_EXPR_MAX) < 0)
226  return MNL_CB_OK;
227 
228  switch (type) {
229  case NFTA_EXPR_NAME:
230  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
231  abi_breakage();
232  break;
233  case NFTA_EXPR_DATA:
234  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
235  abi_breakage();
236  break;
237  }
238 
239  tb[type] = attr;
240  return MNL_CB_OK;
241 }
242 
243 struct nftnl_expr *nftnl_expr_parse(struct nlattr *attr)
244 {
245  struct nlattr *tb[NFTA_EXPR_MAX+1] = {};
246  struct nftnl_expr *expr;
247 
248  if (mnl_attr_parse_nested(attr, nftnl_rule_parse_expr_cb, tb) < 0)
249  goto err1;
250 
251  expr = nftnl_expr_alloc(mnl_attr_get_str(tb[NFTA_EXPR_NAME]));
252  if (expr == NULL)
253  goto err1;
254 
255  if (tb[NFTA_EXPR_DATA] &&
256  expr->ops->parse &&
257  expr->ops->parse(expr, tb[NFTA_EXPR_DATA]) < 0)
258  goto err2;
259 
260  return expr;
261 
262 err2:
263  xfree(expr);
264 err1:
265  return NULL;
266 }
267 
268 EXPORT_SYMBOL(nftnl_expr_snprintf);
269 int nftnl_expr_snprintf(char *buf, size_t size, const struct nftnl_expr *expr,
270  uint32_t type, uint32_t flags)
271 {
272  int ret;
273  unsigned int offset = 0, remain = size;
274 
275  if (size)
276  buf[0] = '\0';
277 
278  if (!expr->ops->snprintf)
279  return 0;
280 
281  ret = expr->ops->snprintf(buf + offset, remain, type, flags, expr);
282  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
283 
284  return offset;
285 }
286 
287 static int nftnl_expr_do_snprintf(char *buf, size_t size, const void *e,
288  uint32_t cmd, uint32_t type, uint32_t flags)
289 {
290  return nftnl_expr_snprintf(buf, size, e, type, flags);
291 }
292 
293 EXPORT_SYMBOL(nftnl_expr_fprintf);
294 int nftnl_expr_fprintf(FILE *fp, const struct nftnl_expr *expr, uint32_t type,
295  uint32_t flags)
296 {
297  return nftnl_fprintf(fp, expr, NFTNL_CMD_UNSPEC, type, flags,
298  nftnl_expr_do_snprintf);
299 }