libnftnl  1.2.9
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 
48  uint32_t flags;
49 };
50 
51 EXPORT_SYMBOL(nftnl_trace_alloc);
52 struct nftnl_trace *nftnl_trace_alloc(void)
53 {
54  return calloc(1, sizeof(struct nftnl_trace));
55 }
56 
57 EXPORT_SYMBOL(nftnl_trace_free);
58 void nftnl_trace_free(const struct nftnl_trace *t)
59 {
60  xfree(t->chain);
61  xfree(t->table);
62  xfree(t->jump_target);
63  xfree(t->ll.data);
64  xfree(t->nh.data);
65  xfree(t->th.data);
66  xfree(t);
67 }
68 
69 EXPORT_SYMBOL(nftnl_trace_is_set);
70 bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr)
71 {
72  return t->flags & (1 << attr);
73 }
74 
75 static int nftnl_trace_parse_attr_cb(const struct nlattr *attr, void *data)
76 {
77  const struct nlattr **tb = data;
78  enum nft_trace_attributes type = mnl_attr_get_type(attr);
79 
80  if (mnl_attr_type_valid(attr, NFTA_TRACE_MAX) < 0)
81  return MNL_CB_OK;
82 
83  switch (type) {
84  case NFTA_TRACE_UNSPEC:
85  case __NFTA_TRACE_MAX:
86  break;
87  case NFTA_TRACE_VERDICT:
88  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
89  abi_breakage();
90  break;
91  case NFTA_TRACE_IIFTYPE:
92  case NFTA_TRACE_OIFTYPE:
93  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
94  abi_breakage();
95  break;
96  case NFTA_TRACE_ID:
97  case NFTA_TRACE_IIF:
98  case NFTA_TRACE_MARK:
99  case NFTA_TRACE_OIF:
100  case NFTA_TRACE_POLICY:
101  case NFTA_TRACE_NFPROTO:
102  case NFTA_TRACE_TYPE:
103  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
104  abi_breakage();
105  break;
106  case NFTA_TRACE_CHAIN:
107  case NFTA_TRACE_TABLE:
108  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
109  abi_breakage();
110  break;
111  case NFTA_TRACE_RULE_HANDLE:
112  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
113  abi_breakage();
114  break;
115  case NFTA_TRACE_LL_HEADER: /* fallthrough */
116  case NFTA_TRACE_NETWORK_HEADER:
117  case NFTA_TRACE_TRANSPORT_HEADER:
118  if (mnl_attr_get_payload_len(attr) == 0)
119  abi_breakage();
120  break;
121  default:
122  return MNL_CB_OK;
123  };
124 
125  tb[type] = attr;
126  return MNL_CB_OK;
127 }
128 
129 EXPORT_SYMBOL(nftnl_trace_get_data);
130 const void *nftnl_trace_get_data(const struct nftnl_trace *trace,
131  uint16_t type, uint32_t *data_len)
132 {
133  enum nftnl_trace_attr attr = type;
134 
135  if (!(trace->flags & (1 << type)))
136  return NULL;
137 
138  switch (attr) {
139  case NFTNL_TRACE_FAMILY:
140  *data_len = sizeof(uint32_t);
141  return &trace->family;
142  case NFTNL_TRACE_ID:
143  *data_len = sizeof(uint32_t);
144  return &trace->id;
145  case NFTNL_TRACE_IIF:
146  *data_len = sizeof(uint32_t);
147  return &trace->iif;
148  case NFTNL_TRACE_OIF:
149  *data_len = sizeof(uint32_t);
150  return &trace->oif;
151  case NFTNL_TRACE_LL_HEADER:
152  *data_len = trace->ll.len;
153  return trace->ll.data;
154  case NFTNL_TRACE_MARK:
155  *data_len = sizeof(uint32_t);
156  return &trace->mark;
157  case NFTNL_TRACE_NETWORK_HEADER:
158  *data_len = trace->nh.len;
159  return trace->nh.data;
160  case NFTNL_TRACE_TYPE:
161  *data_len = sizeof(uint32_t);
162  return &trace->type;
163  case NFTNL_TRACE_CHAIN:
164  *data_len = strlen(trace->chain) + 1;
165  return trace->chain;
166  case NFTNL_TRACE_TABLE:
167  *data_len = strlen(trace->table) + 1;
168  return trace->table;
169  case NFTNL_TRACE_JUMP_TARGET:
170  *data_len = strlen(trace->jump_target) + 1;
171  return trace->jump_target;
172  case NFTNL_TRACE_TRANSPORT_HEADER:
173  *data_len = trace->th.len;
174  return trace->th.data;
175  case NFTNL_TRACE_RULE_HANDLE:
176  *data_len = sizeof(uint64_t);
177  return &trace->rule_handle;
178  case NFTNL_TRACE_VERDICT:
179  *data_len = sizeof(uint32_t);
180  return &trace->verdict;
181  case NFTNL_TRACE_IIFTYPE:
182  *data_len = sizeof(uint16_t);
183  return &trace->iiftype;
184  case NFTNL_TRACE_OIFTYPE:
185  *data_len = sizeof(uint16_t);
186  return &trace->oiftype;
187  case NFTNL_TRACE_NFPROTO:
188  *data_len = sizeof(uint32_t);
189  return &trace->nfproto;
190  case NFTNL_TRACE_POLICY:
191  *data_len = sizeof(uint32_t);
192  return &trace->policy;
193  case __NFTNL_TRACE_MAX:
194  break;
195  }
196 
197  return NULL;
198 }
199 
200 EXPORT_SYMBOL(nftnl_trace_get_str);
201 const char *nftnl_trace_get_str(const struct nftnl_trace *trace, uint16_t type)
202 {
203  if (!nftnl_trace_is_set(trace, type))
204  return NULL;
205 
206  switch (type) {
207  case NFTNL_TRACE_CHAIN: return trace->chain;
208  case NFTNL_TRACE_TABLE: return trace->table;
209  case NFTNL_TRACE_JUMP_TARGET: return trace->jump_target;
210  default: break;
211  }
212  return NULL;
213 }
214 
215 EXPORT_SYMBOL(nftnl_trace_get_u16);
216 uint16_t nftnl_trace_get_u16(const struct nftnl_trace *trace, uint16_t type)
217 {
218  const uint16_t *d;
219  uint32_t dlen;
220 
221  d = nftnl_trace_get_data(trace, type, &dlen);
222  if (d && dlen == sizeof(*d))
223  return *d;
224 
225  return 0;
226 }
227 
228 EXPORT_SYMBOL(nftnl_trace_get_u32);
229 uint32_t nftnl_trace_get_u32(const struct nftnl_trace *trace, uint16_t type)
230 {
231  const uint32_t *d;
232  uint32_t dlen;
233 
234  d = nftnl_trace_get_data(trace, type, &dlen);
235  if (d && dlen == sizeof(*d))
236  return *d;
237 
238  return 0;
239 }
240 
241 EXPORT_SYMBOL(nftnl_trace_get_u64);
242 uint64_t nftnl_trace_get_u64(const struct nftnl_trace *trace, uint16_t type)
243 {
244  const uint64_t *d;
245  uint32_t dlen;
246 
247  d = nftnl_trace_get_data(trace, type, &dlen);
248  if (d && dlen == sizeof(*d))
249  return *d;
250 
251  return 0;
252 }
253 
254 static bool nftnl_trace_nlmsg_parse_hdrdata(struct nlattr *attr,
255  struct nftnl_header_data *header)
256 {
257  uint32_t len;
258 
259  if (!attr)
260  return false;
261 
262  len = mnl_attr_get_payload_len(attr);
263 
264  header->data = malloc(len);
265  if (header->data) {
266  memcpy(header->data, mnl_attr_get_payload(attr), len);
267  header->len = len;
268  return true;
269  }
270 
271  return false;
272 }
273 
274 static int nftnl_trace_parse_verdict_cb(const struct nlattr *attr, void *data)
275 {
276  int type = mnl_attr_get_type(attr);
277  const struct nlattr **tb = data;
278 
279  switch (type) {
280  case NFTA_VERDICT_CODE:
281  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
282  abi_breakage();
283  tb[type] = attr;
284  break;
285  case NFTA_VERDICT_CHAIN:
286  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
287  abi_breakage();
288  tb[type] = attr;
289  break;
290  }
291 
292  return MNL_CB_OK;
293 }
294 
295 static int nftnl_trace_parse_verdict(const struct nlattr *attr,
296  struct nftnl_trace *t)
297 {
298  struct nlattr *tb[NFTA_VERDICT_MAX+1];
299 
300  if (mnl_attr_parse_nested(attr, nftnl_trace_parse_verdict_cb, tb) < 0)
301  return -1;
302 
303  if (!tb[NFTA_VERDICT_CODE])
304  abi_breakage();
305 
306  t->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE]));
307  t->flags |= (1 << NFTNL_TRACE_VERDICT);
308 
309  switch (t->verdict) {
310  case NFT_GOTO: /* fallthough */
311  case NFT_JUMP:
312  if (!tb[NFTA_VERDICT_CHAIN])
313  abi_breakage();
314  t->jump_target = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN]));
315  if (!t->jump_target)
316  return -1;
317 
318  t->flags |= (1 << NFTNL_TRACE_JUMP_TARGET);
319  break;
320  }
321  return 0;
322 }
323 
324 EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
325 int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t)
326 {
327  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
328  struct nlattr *tb[NFTA_TRACE_MAX+1] = {};
329 
330  if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_trace_parse_attr_cb, tb) < 0)
331  return -1;
332 
333  if (!tb[NFTA_TRACE_ID])
334  abi_breakage();
335 
336  if (!tb[NFTA_TRACE_TYPE])
337  abi_breakage();
338 
339  t->family = nfg->nfgen_family;
340  t->flags |= (1 << NFTNL_TRACE_FAMILY);
341 
342  t->type = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_TYPE]));
343  t->flags |= (1 << NFTNL_TRACE_TYPE);
344 
345  t->id = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_ID]));
346  t->flags |= (1 << NFTNL_TRACE_ID);
347 
348  if (tb[NFTA_TRACE_TABLE]) {
349  t->table = strdup(mnl_attr_get_str(tb[NFTA_TRACE_TABLE]));
350  if (!t->table)
351  return -1;
352 
353  t->flags |= (1 << NFTNL_TRACE_TABLE);
354  }
355 
356  if (tb[NFTA_TRACE_CHAIN]) {
357  t->chain = strdup(mnl_attr_get_str(tb[NFTA_TRACE_CHAIN]));
358  if (!t->chain)
359  return -1;
360 
361  t->flags |= (1 << NFTNL_TRACE_CHAIN);
362  }
363 
364  if (tb[NFTA_TRACE_IIFTYPE]) {
365  t->iiftype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_IIFTYPE]));
366  t->flags |= (1 << NFTNL_TRACE_IIFTYPE);
367  }
368 
369  if (tb[NFTA_TRACE_IIF]) {
370  t->iif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_IIF]));
371  t->flags |= (1 << NFTNL_TRACE_IIF);
372  }
373 
374  if (tb[NFTA_TRACE_OIFTYPE]) {
375  t->oiftype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_OIFTYPE]));
376  t->flags |= (1 << NFTNL_TRACE_OIFTYPE);
377  }
378 
379  if (tb[NFTA_TRACE_OIF]) {
380  t->oif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_OIF]));
381  t->flags |= (1 << NFTNL_TRACE_OIF);
382  }
383 
384  if (tb[NFTA_TRACE_MARK]) {
385  t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK]));
386  t->flags |= (1 << NFTNL_TRACE_MARK);
387  }
388 
389  if (tb[NFTA_TRACE_RULE_HANDLE]) {
390  t->rule_handle = be64toh(mnl_attr_get_u64(tb[NFTA_TRACE_RULE_HANDLE]));
391  t->flags |= (1 << NFTNL_TRACE_RULE_HANDLE);
392  }
393 
394  if (tb[NFTA_TRACE_VERDICT] &&
395  nftnl_trace_parse_verdict(tb[NFTA_TRACE_VERDICT], t) < 0)
396  return -1;
397 
398  if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_LL_HEADER], &t->ll))
399  t->flags |= (1 << NFTNL_TRACE_LL_HEADER);
400 
401  if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_NETWORK_HEADER], &t->nh))
402  t->flags |= (1 << NFTNL_TRACE_NETWORK_HEADER);
403 
404  if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_TRANSPORT_HEADER], &t->th))
405  t->flags |= (1 << NFTNL_TRACE_TRANSPORT_HEADER);
406 
407  if (tb[NFTA_TRACE_NFPROTO]) {
408  t->nfproto = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_NFPROTO]));
409  t->flags |= (1 << NFTNL_TRACE_NFPROTO);
410  }
411 
412  if (tb[NFTA_TRACE_POLICY]) {
413  t->policy = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_POLICY]));
414  t->flags |= (1 << NFTNL_TRACE_POLICY);
415  }
416 
417  if (tb[NFTA_TRACE_MARK]) {
418  t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK]));
419  t->flags |= (1 << NFTNL_TRACE_MARK);
420  }
421 
422  return 0;
423 }