/* * (C) 2015 Red Hat GmbH * Author: Florian Westphal * * 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 #include #include #include #include #include #include #include #include #include #include #include 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]; mnl_attr_parse_nested(attr, nftnl_trace_parse_verdict_cb, tb); 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; }