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