diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:04:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-09 13:04:34 +0000 |
commit | 371c8a8bca2b6862226bc79c13d143e07c1d8fc3 (patch) | |
tree | 06c7dc8826596690422e79d5bde2f46c90492de3 /src/trace.c | |
parent | Initial commit. (diff) | |
download | libnftnl-371c8a8bca2b6862226bc79c13d143e07c1d8fc3.tar.xz libnftnl-371c8a8bca2b6862226bc79c13d143e07c1d8fc3.zip |
Adding upstream version 1.2.6.upstream/1.2.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/trace.c')
-rw-r--r-- | src/trace.c | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/src/trace.c b/src/trace.c new file mode 100644 index 0000000..f426437 --- /dev/null +++ b/src/trace.c @@ -0,0 +1,427 @@ +/* + * (C) 2015 Red Hat GmbH + * Author: Florian Westphal <fw@strlen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include "internal.h" + +#include <time.h> +#include <endian.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <netinet/in.h> + +#include <libmnl/libmnl.h> +#include <linux/netfilter.h> +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nf_tables.h> + +#include <libnftnl/trace.h> + +struct nftnl_header_data { + char *data; + unsigned int len; +}; + +struct nftnl_trace { + char *table; + char *chain; + char *jump_target; + uint64_t rule_handle; + struct nftnl_header_data ll; + struct nftnl_header_data nh; + struct nftnl_header_data th; + uint32_t family; + uint32_t type; + uint32_t id; + uint32_t iif; + uint32_t oif; + uint32_t mark; + uint32_t verdict; + uint32_t nfproto; + uint32_t policy; + uint16_t iiftype; + uint16_t oiftype; + + uint32_t flags; +}; + +EXPORT_SYMBOL(nftnl_trace_alloc); +struct nftnl_trace *nftnl_trace_alloc(void) +{ + return calloc(1, sizeof(struct nftnl_trace)); +} + +EXPORT_SYMBOL(nftnl_trace_free); +void nftnl_trace_free(const struct nftnl_trace *t) +{ + xfree(t->chain); + xfree(t->table); + xfree(t->jump_target); + xfree(t->ll.data); + xfree(t->nh.data); + xfree(t->th.data); + xfree(t); +} + +EXPORT_SYMBOL(nftnl_trace_is_set); +bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr) +{ + return t->flags & (1 << attr); +} + +static int nftnl_trace_parse_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + enum nft_trace_attributes type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, NFTA_TRACE_MAX) < 0) + return MNL_CB_OK; + + switch (type) { + case NFTA_TRACE_UNSPEC: + case __NFTA_TRACE_MAX: + break; + case NFTA_TRACE_VERDICT: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) + abi_breakage(); + break; + case NFTA_TRACE_IIFTYPE: + case NFTA_TRACE_OIFTYPE: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + abi_breakage(); + break; + case NFTA_TRACE_ID: + case NFTA_TRACE_IIF: + case NFTA_TRACE_MARK: + case NFTA_TRACE_OIF: + case NFTA_TRACE_POLICY: + case NFTA_TRACE_NFPROTO: + case NFTA_TRACE_TYPE: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + abi_breakage(); + break; + case NFTA_TRACE_CHAIN: + case NFTA_TRACE_TABLE: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) + abi_breakage(); + break; + case NFTA_TRACE_RULE_HANDLE: + if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) + abi_breakage(); + break; + case NFTA_TRACE_LL_HEADER: /* fallthrough */ + case NFTA_TRACE_NETWORK_HEADER: + case NFTA_TRACE_TRANSPORT_HEADER: + if (mnl_attr_get_payload_len(attr) == 0) + abi_breakage(); + break; + default: + return MNL_CB_OK; + }; + + tb[type] = attr; + return MNL_CB_OK; +} + +EXPORT_SYMBOL(nftnl_trace_get_data); +const void *nftnl_trace_get_data(const struct nftnl_trace *trace, + uint16_t type, uint32_t *data_len) +{ + enum nftnl_trace_attr attr = type; + + if (!(trace->flags & (1 << type))) + return NULL; + + switch (attr) { + case NFTNL_TRACE_FAMILY: + *data_len = sizeof(uint32_t); + return &trace->family; + case NFTNL_TRACE_ID: + *data_len = sizeof(uint32_t); + return &trace->id; + case NFTNL_TRACE_IIF: + *data_len = sizeof(uint32_t); + return &trace->iif; + case NFTNL_TRACE_OIF: + *data_len = sizeof(uint32_t); + return &trace->oif; + case NFTNL_TRACE_LL_HEADER: + *data_len = trace->ll.len; + return trace->ll.data; + case NFTNL_TRACE_MARK: + *data_len = sizeof(uint32_t); + return &trace->mark; + case NFTNL_TRACE_NETWORK_HEADER: + *data_len = trace->nh.len; + return trace->nh.data; + case NFTNL_TRACE_TYPE: + *data_len = sizeof(uint32_t); + return &trace->type; + case NFTNL_TRACE_CHAIN: + *data_len = strlen(trace->chain) + 1; + return trace->chain; + case NFTNL_TRACE_TABLE: + *data_len = strlen(trace->table) + 1; + return trace->table; + case NFTNL_TRACE_JUMP_TARGET: + *data_len = strlen(trace->jump_target) + 1; + return trace->jump_target; + case NFTNL_TRACE_TRANSPORT_HEADER: + *data_len = trace->th.len; + return trace->th.data; + case NFTNL_TRACE_RULE_HANDLE: + *data_len = sizeof(uint64_t); + return &trace->rule_handle; + case NFTNL_TRACE_VERDICT: + *data_len = sizeof(uint32_t); + return &trace->verdict; + case NFTNL_TRACE_IIFTYPE: + *data_len = sizeof(uint16_t); + return &trace->iiftype; + case NFTNL_TRACE_OIFTYPE: + *data_len = sizeof(uint16_t); + return &trace->oiftype; + case NFTNL_TRACE_NFPROTO: + *data_len = sizeof(uint32_t); + return &trace->nfproto; + case NFTNL_TRACE_POLICY: + *data_len = sizeof(uint32_t); + return &trace->policy; + case __NFTNL_TRACE_MAX: + break; + } + + return NULL; +} + +EXPORT_SYMBOL(nftnl_trace_get_str); +const char *nftnl_trace_get_str(const struct nftnl_trace *trace, uint16_t type) +{ + if (!nftnl_trace_is_set(trace, type)) + return NULL; + + switch (type) { + case NFTNL_TRACE_CHAIN: return trace->chain; + case NFTNL_TRACE_TABLE: return trace->table; + case NFTNL_TRACE_JUMP_TARGET: return trace->jump_target; + default: break; + } + return NULL; +} + +EXPORT_SYMBOL(nftnl_trace_get_u16); +uint16_t nftnl_trace_get_u16(const struct nftnl_trace *trace, uint16_t type) +{ + const uint16_t *d; + uint32_t dlen; + + d = nftnl_trace_get_data(trace, type, &dlen); + if (d && dlen == sizeof(*d)) + return *d; + + return 0; +} + +EXPORT_SYMBOL(nftnl_trace_get_u32); +uint32_t nftnl_trace_get_u32(const struct nftnl_trace *trace, uint16_t type) +{ + const uint32_t *d; + uint32_t dlen; + + d = nftnl_trace_get_data(trace, type, &dlen); + if (d && dlen == sizeof(*d)) + return *d; + + return 0; +} + +EXPORT_SYMBOL(nftnl_trace_get_u64); +uint64_t nftnl_trace_get_u64(const struct nftnl_trace *trace, uint16_t type) +{ + const uint64_t *d; + uint32_t dlen; + + d = nftnl_trace_get_data(trace, type, &dlen); + if (d && dlen == sizeof(*d)) + return *d; + + return 0; +} + +static bool nftnl_trace_nlmsg_parse_hdrdata(struct nlattr *attr, + struct nftnl_header_data *header) +{ + uint32_t len; + + if (!attr) + return false; + + len = mnl_attr_get_payload_len(attr); + + header->data = malloc(len); + if (header->data) { + memcpy(header->data, mnl_attr_get_payload(attr), len); + header->len = len; + return true; + } + + return false; +} + +static int nftnl_trace_parse_verdict_cb(const struct nlattr *attr, void *data) +{ + int type = mnl_attr_get_type(attr); + const struct nlattr **tb = data; + + switch (type) { + case NFTA_VERDICT_CODE: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + abi_breakage(); + tb[type] = attr; + break; + case NFTA_VERDICT_CHAIN: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) + abi_breakage(); + tb[type] = attr; + break; + } + + return MNL_CB_OK; +} + +static int nftnl_trace_parse_verdict(const struct nlattr *attr, + struct nftnl_trace *t) +{ + struct nlattr *tb[NFTA_VERDICT_MAX+1]; + + if (mnl_attr_parse_nested(attr, nftnl_trace_parse_verdict_cb, tb) < 0) + return -1; + + if (!tb[NFTA_VERDICT_CODE]) + abi_breakage(); + + t->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE])); + t->flags |= (1 << NFTNL_TRACE_VERDICT); + + switch (t->verdict) { + case NFT_GOTO: /* fallthough */ + case NFT_JUMP: + if (!tb[NFTA_VERDICT_CHAIN]) + abi_breakage(); + t->jump_target = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN])); + if (!t->jump_target) + return -1; + + t->flags |= (1 << NFTNL_TRACE_JUMP_TARGET); + break; + } + return 0; +} + +EXPORT_SYMBOL(nftnl_trace_nlmsg_parse); +int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t) +{ + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + struct nlattr *tb[NFTA_TRACE_MAX+1] = {}; + + if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_trace_parse_attr_cb, tb) < 0) + return -1; + + if (!tb[NFTA_TRACE_ID]) + abi_breakage(); + + if (!tb[NFTA_TRACE_TYPE]) + abi_breakage(); + + t->family = nfg->nfgen_family; + t->flags |= (1 << NFTNL_TRACE_FAMILY); + + t->type = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_TYPE])); + t->flags |= (1 << NFTNL_TRACE_TYPE); + + t->id = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_ID])); + t->flags |= (1 << NFTNL_TRACE_ID); + + if (tb[NFTA_TRACE_TABLE]) { + t->table = strdup(mnl_attr_get_str(tb[NFTA_TRACE_TABLE])); + if (!t->table) + return -1; + + t->flags |= (1 << NFTNL_TRACE_TABLE); + } + + if (tb[NFTA_TRACE_CHAIN]) { + t->chain = strdup(mnl_attr_get_str(tb[NFTA_TRACE_CHAIN])); + if (!t->chain) + return -1; + + t->flags |= (1 << NFTNL_TRACE_CHAIN); + } + + if (tb[NFTA_TRACE_IIFTYPE]) { + t->iiftype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_IIFTYPE])); + t->flags |= (1 << NFTNL_TRACE_IIFTYPE); + } + + if (tb[NFTA_TRACE_IIF]) { + t->iif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_IIF])); + t->flags |= (1 << NFTNL_TRACE_IIF); + } + + if (tb[NFTA_TRACE_OIFTYPE]) { + t->oiftype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_OIFTYPE])); + t->flags |= (1 << NFTNL_TRACE_OIFTYPE); + } + + if (tb[NFTA_TRACE_OIF]) { + t->oif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_OIF])); + t->flags |= (1 << NFTNL_TRACE_OIF); + } + + if (tb[NFTA_TRACE_MARK]) { + t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK])); + t->flags |= (1 << NFTNL_TRACE_MARK); + } + + if (tb[NFTA_TRACE_RULE_HANDLE]) { + t->rule_handle = be64toh(mnl_attr_get_u64(tb[NFTA_TRACE_RULE_HANDLE])); + t->flags |= (1 << NFTNL_TRACE_RULE_HANDLE); + } + + if (tb[NFTA_TRACE_VERDICT] && + nftnl_trace_parse_verdict(tb[NFTA_TRACE_VERDICT], t) < 0) + return -1; + + if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_LL_HEADER], &t->ll)) + t->flags |= (1 << NFTNL_TRACE_LL_HEADER); + + if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_NETWORK_HEADER], &t->nh)) + t->flags |= (1 << NFTNL_TRACE_NETWORK_HEADER); + + if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_TRANSPORT_HEADER], &t->th)) + t->flags |= (1 << NFTNL_TRACE_TRANSPORT_HEADER); + + if (tb[NFTA_TRACE_NFPROTO]) { + t->nfproto = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_NFPROTO])); + t->flags |= (1 << NFTNL_TRACE_NFPROTO); + } + + if (tb[NFTA_TRACE_POLICY]) { + t->policy = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_POLICY])); + t->flags |= (1 << NFTNL_TRACE_POLICY); + } + + if (tb[NFTA_TRACE_MARK]) { + t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK])); + t->flags |= (1 << NFTNL_TRACE_MARK); + } + + return 0; +} |