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
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
57EXPORT_SYMBOL(nftnl_trace_alloc);
58struct nftnl_trace *nftnl_trace_alloc(void)
59{
60 return calloc(1, sizeof(struct nftnl_trace));
61}
62
63EXPORT_SYMBOL(nftnl_trace_free);
64void 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
75EXPORT_SYMBOL(nftnl_trace_is_set);
76bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr)
77{
78 return t->flags & (1 << attr);
79}
80
81static 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
142EXPORT_SYMBOL(nftnl_trace_get_data);
143const 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
225EXPORT_SYMBOL(nftnl_trace_get_str);
226const 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
240EXPORT_SYMBOL(nftnl_trace_get_u16);
241uint16_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
253EXPORT_SYMBOL(nftnl_trace_get_u32);
254uint32_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
266EXPORT_SYMBOL(nftnl_trace_get_u64);
267uint64_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
279static 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
299static 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
320static 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
349EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
350int 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}