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
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
51EXPORT_SYMBOL(nftnl_trace_alloc);
52struct nftnl_trace *nftnl_trace_alloc(void)
53{
54 return calloc(1, sizeof(struct nftnl_trace));
55}
56
57EXPORT_SYMBOL(nftnl_trace_free);
58void 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
69EXPORT_SYMBOL(nftnl_trace_is_set);
70bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr)
71{
72 return t->flags & (1 << attr);
73}
74
75static 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
129EXPORT_SYMBOL(nftnl_trace_get_data);
130const 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
200EXPORT_SYMBOL(nftnl_trace_get_str);
201const 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
215EXPORT_SYMBOL(nftnl_trace_get_u16);
216uint16_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
228EXPORT_SYMBOL(nftnl_trace_get_u32);
229uint32_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
241EXPORT_SYMBOL(nftnl_trace_get_u64);
242uint64_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
254static 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
274static 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
295static 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
324EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
325int 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}