@@ -28,6 +28,10 @@ enum nftnl_trace_attr {
NFTNL_TRACE_VERDICT,
NFTNL_TRACE_NFPROTO,
NFTNL_TRACE_POLICY,
+ NFTNL_TRACE_CT_DIRECTION,
+ NFTNL_TRACE_CT_ID,
+ NFTNL_TRACE_CT_STATE,
+ NFTNL_TRACE_CT_STATUS,
__NFTNL_TRACE_MAX,
};
#define NFTNL_TRACE_MAX (__NFTNL_TRACE_MAX - 1)
@@ -1837,6 +1837,7 @@ enum nft_xfrm_keys {
* @NFTA_TRACE_MARK: nfmark (NLA_U32)
* @NFTA_TRACE_NFPROTO: nf protocol processed (NLA_U32)
* @NFTA_TRACE_POLICY: policy that decided fate of packet (NLA_U32)
+ * @NFTA_TRACE_CT: connection tracking information (NLA_NESTED: nft_ct_keys)
*/
enum nft_trace_attributes {
NFTA_TRACE_UNSPEC,
@@ -1857,6 +1858,7 @@ enum nft_trace_attributes {
NFTA_TRACE_NFPROTO,
NFTA_TRACE_POLICY,
NFTA_TRACE_PAD,
+ NFTA_TRACE_CT,
__NFTA_TRACE_MAX
};
#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
@@ -44,6 +44,12 @@ struct nftnl_trace {
uint32_t policy;
uint16_t iiftype;
uint16_t oiftype;
+ struct {
+ uint16_t dir;
+ uint32_t id;
+ uint32_t state;
+ uint32_t status;
+ } ct;
uint32_t flags;
};
@@ -85,6 +91,7 @@ static int nftnl_trace_parse_attr_cb(const struct nlattr *attr, void *data)
case __NFTA_TRACE_MAX:
break;
case NFTA_TRACE_VERDICT:
+ case NFTA_TRACE_CT:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
abi_breakage();
break;
@@ -190,6 +197,18 @@ const void *nftnl_trace_get_data(const struct nftnl_trace *trace,
case NFTNL_TRACE_POLICY:
*data_len = sizeof(uint32_t);
return &trace->policy;
+ case NFTNL_TRACE_CT_DIRECTION:
+ *data_len = sizeof(uint16_t);
+ return &trace->ct.dir;
+ case NFTNL_TRACE_CT_ID:
+ *data_len = sizeof(uint32_t);
+ return &trace->ct.id;
+ case NFTNL_TRACE_CT_STATE:
+ *data_len = sizeof(uint32_t);
+ return &trace->ct.state;
+ case NFTNL_TRACE_CT_STATUS:
+ *data_len = sizeof(uint32_t);
+ return &trace->ct.status;
case __NFTNL_TRACE_MAX:
break;
}
@@ -321,6 +340,61 @@ static int nftnl_trace_parse_verdict(const struct nlattr *attr,
return 0;
}
+static int nftnl_trace_parse_ct_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ switch (type) {
+ case NFT_CT_DIRECTION:
+ if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+ abi_breakage();
+ tb[type] = attr;
+ break;
+ case NFT_CT_STATE:
+ case NFT_CT_STATUS:
+ case NFT_CT_ID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ abi_breakage();
+ tb[type] = attr;
+ break;
+ }
+
+ return MNL_CB_OK;
+}
+
+static int nftnl_trace_parse_ct(const struct nlattr *attr,
+ struct nftnl_trace *t)
+{
+ struct nlattr *tb[NFT_CT_MAX+1] = {};
+
+ if (mnl_attr_parse_nested(attr, nftnl_trace_parse_ct_cb, tb) < 0)
+ return -1;
+
+ if (tb[NFT_CT_DIRECTION]) {
+ t->ct.dir = mnl_attr_get_u8(tb[NFT_CT_DIRECTION]);
+ t->flags |= (1 << NFTNL_TRACE_CT_DIRECTION);
+ }
+
+ if (tb[NFT_CT_ID]) {
+ /* NFT_CT_ID is expected to be in big endian */
+ t->ct.id = mnl_attr_get_u32(tb[NFT_CT_ID]);
+ t->flags |= (1 << NFTNL_TRACE_CT_ID);
+ }
+
+ if (tb[NFT_CT_STATE]) {
+ t->ct.state = ntohl(mnl_attr_get_u32(tb[NFT_CT_STATE]));
+ t->flags |= (1 << NFTNL_TRACE_CT_STATE);
+ }
+
+ if (tb[NFT_CT_STATUS]) {
+ t->ct.status = ntohl(mnl_attr_get_u32(tb[NFT_CT_STATUS]));
+ t->flags |= (1 << NFTNL_TRACE_CT_STATUS);
+ }
+
+ return 0;
+}
+
EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t)
{
@@ -419,5 +493,9 @@ int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t)
t->flags |= (1 << NFTNL_TRACE_MARK);
}
+ if (tb[NFTA_TRACE_CT] &&
+ nftnl_trace_parse_ct(tb[NFTA_TRACE_CT], t) < 0)
+ return -1;
+
return 0;
}
Decode direction/id/state/status information. This will be used by 'nftables monitor trace' to print a packets conntrack state. Signed-off-by: Florian Westphal <fw@strlen.de> --- include/libnftnl/trace.h | 4 ++ include/linux/netfilter/nf_tables.h | 2 + src/trace.c | 78 +++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+)