libnftnl 1.2.6
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
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
55EXPORT_SYMBOL(nftnl_trace_alloc);
56struct nftnl_trace *nftnl_trace_alloc(void)
57{
58 return calloc(1, sizeof(struct nftnl_trace));
59}
60
61EXPORT_SYMBOL(nftnl_trace_free);
62void 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
73EXPORT_SYMBOL(nftnl_trace_is_set);
74bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr)
75{
76 return t->flags & (1 << attr);
77}
78
79static 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
133EXPORT_SYMBOL(nftnl_trace_get_data);
134const 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
204EXPORT_SYMBOL(nftnl_trace_get_str);
205const 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
219EXPORT_SYMBOL(nftnl_trace_get_u16);
220uint16_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
232EXPORT_SYMBOL(nftnl_trace_get_u32);
233uint32_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
245EXPORT_SYMBOL(nftnl_trace_get_u64);
246uint64_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
258static 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
278static 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
299static 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
328EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
329int 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}