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