libnftnl  1.3.1
trace.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2015 Red Hat GmbH
4  * Author: Florian Westphal <fw@strlen.de>
5  */
6 #include "internal.h"
7 
8 #include <time.h>
9 #include <endian.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <netinet/in.h>
15 
16 #include <libmnl/libmnl.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter/nfnetlink.h>
19 #include <linux/netfilter/nf_tables.h>
20 
21 #include <libnftnl/trace.h>
22 
24  char *data;
25  unsigned int len;
26 };
27 
28 struct nftnl_trace {
29  char *table;
30  char *chain;
31  char *jump_target;
32  uint64_t rule_handle;
33  struct nftnl_header_data ll;
34  struct nftnl_header_data nh;
35  struct nftnl_header_data th;
36  uint32_t family;
37  uint32_t type;
38  uint32_t id;
39  uint32_t iif;
40  uint32_t oif;
41  uint32_t mark;
42  uint32_t verdict;
43  uint32_t nfproto;
44  uint32_t policy;
45  uint16_t iiftype;
46  uint16_t oiftype;
47  struct {
48  uint16_t dir;
49  uint32_t id;
50  uint32_t state;
51  uint32_t status;
52  } ct;
53 
54  uint32_t flags;
55 };
56 
57 EXPORT_SYMBOL(nftnl_trace_alloc);
58 struct nftnl_trace *nftnl_trace_alloc(void)
59 {
60  return calloc(1, sizeof(struct nftnl_trace));
61 }
62 
63 EXPORT_SYMBOL(nftnl_trace_free);
64 void nftnl_trace_free(const struct nftnl_trace *t)
65 {
66  xfree(t->chain);
67  xfree(t->table);
68  xfree(t->jump_target);
69  xfree(t->ll.data);
70  xfree(t->nh.data);
71  xfree(t->th.data);
72  xfree(t);
73 }
74 
75 EXPORT_SYMBOL(nftnl_trace_is_set);
76 bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr)
77 {
78  return t->flags & (1 << attr);
79 }
80 
81 static int nftnl_trace_parse_attr_cb(const struct nlattr *attr, void *data)
82 {
83  const struct nlattr **tb = data;
84  enum nft_trace_attributes type = mnl_attr_get_type(attr);
85 
86  if (mnl_attr_type_valid(attr, NFTA_TRACE_MAX) < 0)
87  return MNL_CB_OK;
88 
89  switch (type) {
90  case NFTA_TRACE_UNSPEC:
91  case __NFTA_TRACE_MAX:
92  break;
93  case NFTA_TRACE_VERDICT:
94  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
95  abi_breakage();
96  break;
97  case NFTA_TRACE_CT_DIRECTION:
98  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
99  abi_breakage();
100  break;
101  case NFTA_TRACE_IIFTYPE:
102  case NFTA_TRACE_OIFTYPE:
103  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
104  abi_breakage();
105  break;
106  case NFTA_TRACE_ID:
107  case NFTA_TRACE_IIF:
108  case NFTA_TRACE_MARK:
109  case NFTA_TRACE_OIF:
110  case NFTA_TRACE_POLICY:
111  case NFTA_TRACE_NFPROTO:
112  case NFTA_TRACE_TYPE:
113  case NFTA_TRACE_CT_ID:
114  case NFTA_TRACE_CT_STATE:
115  case NFTA_TRACE_CT_STATUS:
116  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
117  abi_breakage();
118  break;
119  case NFTA_TRACE_CHAIN:
120  case NFTA_TRACE_TABLE:
121  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
122  abi_breakage();
123  break;
124  case NFTA_TRACE_RULE_HANDLE:
125  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
126  abi_breakage();
127  break;
128  case NFTA_TRACE_LL_HEADER: /* fallthrough */
129  case NFTA_TRACE_NETWORK_HEADER:
130  case NFTA_TRACE_TRANSPORT_HEADER:
131  if (mnl_attr_get_payload_len(attr) == 0)
132  abi_breakage();
133  break;
134  default:
135  return MNL_CB_OK;
136  };
137 
138  tb[type] = attr;
139  return MNL_CB_OK;
140 }
141 
142 EXPORT_SYMBOL(nftnl_trace_get_data);
143 const void *nftnl_trace_get_data(const struct nftnl_trace *trace,
144  uint16_t type, uint32_t *data_len)
145 {
146  enum nftnl_trace_attr attr = type;
147 
148  if (!(trace->flags & (1 << type)))
149  return NULL;
150 
151  switch (attr) {
152  case NFTNL_TRACE_FAMILY:
153  *data_len = sizeof(uint32_t);
154  return &trace->family;
155  case NFTNL_TRACE_ID:
156  *data_len = sizeof(uint32_t);
157  return &trace->id;
158  case NFTNL_TRACE_IIF:
159  *data_len = sizeof(uint32_t);
160  return &trace->iif;
161  case NFTNL_TRACE_OIF:
162  *data_len = sizeof(uint32_t);
163  return &trace->oif;
164  case NFTNL_TRACE_LL_HEADER:
165  *data_len = trace->ll.len;
166  return trace->ll.data;
167  case NFTNL_TRACE_MARK:
168  *data_len = sizeof(uint32_t);
169  return &trace->mark;
170  case NFTNL_TRACE_NETWORK_HEADER:
171  *data_len = trace->nh.len;
172  return trace->nh.data;
173  case NFTNL_TRACE_TYPE:
174  *data_len = sizeof(uint32_t);
175  return &trace->type;
176  case NFTNL_TRACE_CHAIN:
177  *data_len = strlen(trace->chain) + 1;
178  return trace->chain;
179  case NFTNL_TRACE_TABLE:
180  *data_len = strlen(trace->table) + 1;
181  return trace->table;
182  case NFTNL_TRACE_JUMP_TARGET:
183  *data_len = strlen(trace->jump_target) + 1;
184  return trace->jump_target;
185  case NFTNL_TRACE_TRANSPORT_HEADER:
186  *data_len = trace->th.len;
187  return trace->th.data;
188  case NFTNL_TRACE_RULE_HANDLE:
189  *data_len = sizeof(uint64_t);
190  return &trace->rule_handle;
191  case NFTNL_TRACE_VERDICT:
192  *data_len = sizeof(uint32_t);
193  return &trace->verdict;
194  case NFTNL_TRACE_IIFTYPE:
195  *data_len = sizeof(uint16_t);
196  return &trace->iiftype;
197  case NFTNL_TRACE_OIFTYPE:
198  *data_len = sizeof(uint16_t);
199  return &trace->oiftype;
200  case NFTNL_TRACE_NFPROTO:
201  *data_len = sizeof(uint32_t);
202  return &trace->nfproto;
203  case NFTNL_TRACE_POLICY:
204  *data_len = sizeof(uint32_t);
205  return &trace->policy;
206  case NFTNL_TRACE_CT_DIRECTION:
207  *data_len = sizeof(uint16_t);
208  return &trace->ct.dir;
209  case NFTNL_TRACE_CT_ID:
210  *data_len = sizeof(uint32_t);
211  return &trace->ct.id;
212  case NFTNL_TRACE_CT_STATE:
213  *data_len = sizeof(uint32_t);
214  return &trace->ct.state;
215  case NFTNL_TRACE_CT_STATUS:
216  *data_len = sizeof(uint32_t);
217  return &trace->ct.status;
218  case __NFTNL_TRACE_MAX:
219  break;
220  }
221 
222  return NULL;
223 }
224 
225 EXPORT_SYMBOL(nftnl_trace_get_str);
226 const char *nftnl_trace_get_str(const struct nftnl_trace *trace, uint16_t type)
227 {
228  if (!nftnl_trace_is_set(trace, type))
229  return NULL;
230 
231  switch (type) {
232  case NFTNL_TRACE_CHAIN: return trace->chain;
233  case NFTNL_TRACE_TABLE: return trace->table;
234  case NFTNL_TRACE_JUMP_TARGET: return trace->jump_target;
235  default: break;
236  }
237  return NULL;
238 }
239 
240 EXPORT_SYMBOL(nftnl_trace_get_u16);
241 uint16_t nftnl_trace_get_u16(const struct nftnl_trace *trace, uint16_t type)
242 {
243  const uint16_t *d;
244  uint32_t dlen;
245 
246  d = nftnl_trace_get_data(trace, type, &dlen);
247  if (d && dlen == sizeof(*d))
248  return *d;
249 
250  return 0;
251 }
252 
253 EXPORT_SYMBOL(nftnl_trace_get_u32);
254 uint32_t nftnl_trace_get_u32(const struct nftnl_trace *trace, uint16_t type)
255 {
256  const uint32_t *d;
257  uint32_t dlen;
258 
259  d = nftnl_trace_get_data(trace, type, &dlen);
260  if (d && dlen == sizeof(*d))
261  return *d;
262 
263  return 0;
264 }
265 
266 EXPORT_SYMBOL(nftnl_trace_get_u64);
267 uint64_t nftnl_trace_get_u64(const struct nftnl_trace *trace, uint16_t type)
268 {
269  const uint64_t *d;
270  uint32_t dlen;
271 
272  d = nftnl_trace_get_data(trace, type, &dlen);
273  if (d && dlen == sizeof(*d))
274  return *d;
275 
276  return 0;
277 }
278 
279 static bool nftnl_trace_nlmsg_parse_hdrdata(struct nlattr *attr,
280  struct nftnl_header_data *header)
281 {
282  uint32_t len;
283 
284  if (!attr)
285  return false;
286 
287  len = mnl_attr_get_payload_len(attr);
288 
289  header->data = malloc(len);
290  if (header->data) {
291  memcpy(header->data, mnl_attr_get_payload(attr), len);
292  header->len = len;
293  return true;
294  }
295 
296  return false;
297 }
298 
299 static int nftnl_trace_parse_verdict_cb(const struct nlattr *attr, void *data)
300 {
301  int type = mnl_attr_get_type(attr);
302  const struct nlattr **tb = data;
303 
304  switch (type) {
305  case NFTA_VERDICT_CODE:
306  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
307  abi_breakage();
308  tb[type] = attr;
309  break;
310  case NFTA_VERDICT_CHAIN:
311  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
312  abi_breakage();
313  tb[type] = attr;
314  break;
315  }
316 
317  return MNL_CB_OK;
318 }
319 
320 static int nftnl_trace_parse_verdict(const struct nlattr *attr,
321  struct nftnl_trace *t)
322 {
323  struct nlattr *tb[NFTA_VERDICT_MAX+1];
324 
325  if (mnl_attr_parse_nested(attr, nftnl_trace_parse_verdict_cb, tb) < 0)
326  return -1;
327 
328  if (!tb[NFTA_VERDICT_CODE])
329  abi_breakage();
330 
331  t->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE]));
332  t->flags |= (1 << NFTNL_TRACE_VERDICT);
333 
334  switch (t->verdict) {
335  case NFT_GOTO: /* fallthough */
336  case NFT_JUMP:
337  if (!tb[NFTA_VERDICT_CHAIN])
338  abi_breakage();
339  if (nftnl_parse_str_attr(tb[NFTA_VERDICT_CHAIN],
340  NFTNL_TRACE_JUMP_TARGET,
341  (const char **)&t->jump_target,
342  &t->flags) < 0)
343  return -1;
344  break;
345  }
346  return 0;
347 }
348 
349 EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
350 int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t)
351 {
352  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
353  struct nlattr *tb[NFTA_TRACE_MAX+1] = {};
354 
355  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_trace_parse_attr_cb, tb) < 0)
356  return -1;
357 
358  if (!tb[NFTA_TRACE_ID])
359  abi_breakage();
360 
361  if (!tb[NFTA_TRACE_TYPE])
362  abi_breakage();
363 
364  t->family = nfg->nfgen_family;
365  t->flags |= (1 << NFTNL_TRACE_FAMILY);
366 
367  t->type = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_TYPE]));
368  t->flags |= (1 << NFTNL_TRACE_TYPE);
369 
370  t->id = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_ID]));
371  t->flags |= (1 << NFTNL_TRACE_ID);
372 
373  if (nftnl_parse_str_attr(tb[NFTA_TRACE_TABLE], NFTNL_TRACE_TABLE,
374  (const char **)&t->table, &t->flags) < 0)
375  return -1;
376 
377  if (nftnl_parse_str_attr(tb[NFTA_TRACE_CHAIN], NFTNL_TRACE_CHAIN,
378  (const char **)&t->chain, &t->flags) < 0)
379  return -1;
380 
381  if (tb[NFTA_TRACE_IIFTYPE]) {
382  t->iiftype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_IIFTYPE]));
383  t->flags |= (1 << NFTNL_TRACE_IIFTYPE);
384  }
385 
386  if (tb[NFTA_TRACE_IIF]) {
387  t->iif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_IIF]));
388  t->flags |= (1 << NFTNL_TRACE_IIF);
389  }
390 
391  if (tb[NFTA_TRACE_OIFTYPE]) {
392  t->oiftype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_OIFTYPE]));
393  t->flags |= (1 << NFTNL_TRACE_OIFTYPE);
394  }
395 
396  if (tb[NFTA_TRACE_OIF]) {
397  t->oif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_OIF]));
398  t->flags |= (1 << NFTNL_TRACE_OIF);
399  }
400 
401  if (tb[NFTA_TRACE_MARK]) {
402  t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK]));
403  t->flags |= (1 << NFTNL_TRACE_MARK);
404  }
405 
406  if (tb[NFTA_TRACE_RULE_HANDLE]) {
407  t->rule_handle = be64toh(mnl_attr_get_u64(tb[NFTA_TRACE_RULE_HANDLE]));
408  t->flags |= (1 << NFTNL_TRACE_RULE_HANDLE);
409  }
410 
411  if (tb[NFTA_TRACE_VERDICT] &&
412  nftnl_trace_parse_verdict(tb[NFTA_TRACE_VERDICT], t) < 0)
413  return -1;
414 
415  if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_LL_HEADER], &t->ll))
416  t->flags |= (1 << NFTNL_TRACE_LL_HEADER);
417 
418  if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_NETWORK_HEADER], &t->nh))
419  t->flags |= (1 << NFTNL_TRACE_NETWORK_HEADER);
420 
421  if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_TRANSPORT_HEADER], &t->th))
422  t->flags |= (1 << NFTNL_TRACE_TRANSPORT_HEADER);
423 
424  if (tb[NFTA_TRACE_NFPROTO]) {
425  t->nfproto = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_NFPROTO]));
426  t->flags |= (1 << NFTNL_TRACE_NFPROTO);
427  }
428 
429  if (tb[NFTA_TRACE_POLICY]) {
430  t->policy = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_POLICY]));
431  t->flags |= (1 << NFTNL_TRACE_POLICY);
432  }
433 
434  if (tb[NFTA_TRACE_MARK]) {
435  t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK]));
436  t->flags |= (1 << NFTNL_TRACE_MARK);
437  }
438 
439  if (tb[NFTA_TRACE_CT_DIRECTION]) {
440  t->ct.dir = mnl_attr_get_u8(tb[NFTA_TRACE_CT_DIRECTION]);
441  t->flags |= (1 << NFTNL_TRACE_CT_DIRECTION);
442  }
443 
444  if (tb[NFTA_TRACE_CT_ID]) {
445  /* NFT_CT_ID is expected to be in big endian */
446  t->ct.id = mnl_attr_get_u32(tb[NFTA_TRACE_CT_ID]);
447  t->flags |= (1 << NFTNL_TRACE_CT_ID);
448  }
449 
450  if (tb[NFTA_TRACE_CT_STATE]) {
451  t->ct.state = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_CT_STATE]));
452  t->flags |= (1 << NFTNL_TRACE_CT_STATE);
453  }
454 
455  if (tb[NFTA_TRACE_CT_STATUS]) {
456  t->ct.status = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_CT_STATUS]));
457  t->flags |= (1 << NFTNL_TRACE_CT_STATUS);
458  }
459 
460  return 0;
461 }