All of lore.kernel.org
 help / color / mirror / Atom feed
From: Florian Westphal <fw@strlen.de>
To: <netfilter-devel@vger.kernel.org>
Cc: Florian Westphal <fw@strlen.de>
Subject: [PATCH libnftnl 5/6] src: add trace infrastructure support
Date: Tue, 24 Nov 2015 11:02:10 +0100	[thread overview]
Message-ID: <1448359331-12692-6-git-send-email-fw@strlen.de> (raw)
In-Reply-To: <1448359331-12692-1-git-send-email-fw@strlen.de>

parses trace monitor netlink messages from the kernel and
supports printing most of the 'important' header data such as
ether/ip/ip6 src/dst addresses and udp/tcp port numbers.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/libnftnl/Makefile.am        |   1 +
 include/libnftnl/trace.h            |  56 +++
 include/linux/netfilter/nf_tables.h |  32 ++
 src/Makefile.am                     |   1 +
 src/libnftnl.map                    |  17 +
 src/trace.c                         | 725 ++++++++++++++++++++++++++++++++++++
 src/utils.c                         |   4 +
 7 files changed, 836 insertions(+)
 create mode 100644 include/libnftnl/trace.h
 create mode 100644 src/trace.c

diff --git a/include/libnftnl/Makefile.am b/include/libnftnl/Makefile.am
index a20aaee..84f01b6 100644
--- a/include/libnftnl/Makefile.am
+++ b/include/libnftnl/Makefile.am
@@ -1,5 +1,6 @@
 pkginclude_HEADERS = batch.h		\
 		     table.h		\
+		     trace.h		\
 		     chain.h		\
 		     rule.h		\
 		     expr.h		\
diff --git a/include/libnftnl/trace.h b/include/libnftnl/trace.h
new file mode 100644
index 0000000..a570194
--- /dev/null
+++ b/include/libnftnl/trace.h
@@ -0,0 +1,56 @@
+#ifndef _LIBNFTNL_TRACE_H_
+#define _LIBNFTNL_TRACE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum nftnl_trace_attr {
+	NFTNL_TRACE_CHAIN = 0,
+	NFTNL_TRACE_DEV_TYPE,
+	NFTNL_TRACE_FAMILY,
+	NFTNL_TRACE_ID,
+	NFTNL_TRACE_IIF,
+	NFTNL_TRACE_OIF,
+	NFTNL_TRACE_LL_HEADER,
+	NFTNL_TRACE_MARK,
+	NFTNL_TRACE_NETWORK_HEADER,
+	NFTNL_TRACE_TABLE,
+	NFTNL_TRACE_TRANSPORT_HEADER,
+	NFTNL_TRACE_TRANSPORT_PROTO,
+	NFTNL_TRACE_TYPE,
+	NFTNL_TRACE_RULE_HANDLE,
+	NFTNL_TRACE_VERDICT,
+	NFTNL_TRACE_VLAN_TAG,
+};
+#define NFTNL_TRACE_MAX NFTNL_TRACE_VLAN_TAG
+
+struct nftnl_trace;
+
+struct nftnl_trace *nftnl_trace_alloc(void);
+void nftnl_trace_free(struct nftnl_trace *trace);
+
+bool nftnl_trace_is_set(const struct nftnl_trace *trace, uint16_t type);
+
+const void *nftnl_trace_get_data(const struct nftnl_trace *trace,
+				 uint16_t type, uint32_t *data_len);
+
+uint8_t nftnl_trace_get_u8(const struct nftnl_trace *trace, uint16_t type);
+uint16_t nftnl_trace_get_u16(const struct nftnl_trace *trace, uint16_t type);
+uint32_t nftnl_trace_get_u32(const struct nftnl_trace *trace, uint16_t type);
+uint64_t nftnl_trace_get_u64(const struct nftnl_trace *trace, uint16_t type);
+const char *nftnl_trace_get_str(const struct nftnl_trace *trace, uint16_t type);
+
+int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t);
+int nftnl_trace_snprintf(char *buf, size_t size, const struct nftnl_trace *t, uint32_t type);
+int nftnl_trace_fprintf(FILE *fh, const struct nftnl_trace *t, uint32_t type);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _LIBNFTNL_TRACE_H_ */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 9796d82..09ede2b 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -83,6 +83,7 @@ enum nft_verdicts {
  * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
  * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes)
  * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes)
+ * @NFT_MSG_TRACE: trace event (enum nft_trace_attributes)
  */
 enum nf_tables_msg_types {
 	NFT_MSG_NEWTABLE,
@@ -102,6 +103,7 @@ enum nf_tables_msg_types {
 	NFT_MSG_DELSETELEM,
 	NFT_MSG_NEWGEN,
 	NFT_MSG_GETGEN,
+	NFT_MSG_TRACE,
 	NFT_MSG_MAX,
 };
 
@@ -970,4 +972,34 @@ enum nft_gen_attributes {
 };
 #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
 
+enum nft_trace_attibutes {
+	NFTA_TRACE_UNSPEC,
+	NFTA_TRACE_CHAIN,
+	NFTA_TRACE_DEV_TYPE,
+	NFTA_TRACE_ID,
+	NFTA_TRACE_IIF,
+	NFTA_TRACE_OIF,
+	NFTA_TRACE_LL_HEADER,
+	NFTA_TRACE_MARK,
+	NFTA_TRACE_NETWORK_HEADER,
+	NFTA_TRACE_TABLE,
+	NFTA_TRACE_TRANSPORT_HEADER,
+	NFTA_TRACE_TRANSPORT_PROTO,
+	NFTA_TRACE_TYPE,
+	NFTA_TRACE_RULE_HANDLE,
+	NFTA_TRACE_VERDICT,
+	NFTA_TRACE_VLAN_TAG,
+	__NFTA_TRACE_MAX
+};
+#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
+
+enum nft_trace_types {
+	NFT_TRACETYPE_UNSPEC,
+	NFT_TRACETYPE_PACKET,
+	NFT_TRACETYPE_POLICY,
+	NFT_TRACETYPE_RETURN,
+	NFT_TRACETYPE_RULE,
+	__NFT_TRACETYPE_MAX
+};
+#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1)
 #endif /* _LINUX_NF_TABLES_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 107cae5..795307d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,7 @@ libnftnl_la_SOURCES = utils.c		\
 		      common.c		\
 		      gen.c		\
 		      table.c		\
+		      trace.c		\
 		      chain.c		\
 		      rule.c		\
 		      set.c		\
diff --git a/src/libnftnl.map b/src/libnftnl.map
index a52b54e..7fc2eb9 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -498,3 +498,20 @@ global:
 
 local: *;
 };
+
+LIBNFTNL_4.1 {
+	nftnl_trace_alloc;
+	nftnl_trace_free;
+
+	nftnl_trace_is_set;
+
+	nftnl_trace_get_u8;
+	nftnl_trace_get_u16;
+	nftnl_trace_get_u32;
+	nftnl_trace_get_u64;
+	nftnl_trace_get_str;
+
+	nftnl_trace_nlmsg_parse;
+	nftnl_trace_snprintf;
+	nftnl_trace_fprintf;
+} LIBNFTNL_4;
diff --git a/src/trace.c b/src/trace.c
new file mode 100644
index 0000000..0b95d02
--- /dev/null
+++ b/src/trace.c
@@ -0,0 +1,725 @@
+/*
+ * (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>
+
+/* header snprintf */
+#include <inttypes.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+
+struct nftnl_header_data {
+	char *data;
+	unsigned int len;
+};
+
+struct nftnl_trace {
+	char *chain;
+	char *table;
+	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;
+	uint16_t vlan_tag;
+	uint16_t devtype;
+	uint8_t  th_prot;
+
+	uint32_t flags;
+};
+
+static const char *type2str(int type)
+{
+	enum nft_trace_types t = type;
+
+	switch (t) {
+	case NFT_TRACETYPE_PACKET:
+		return "packet"; /* trace start */
+	case NFT_TRACETYPE_POLICY:
+		return "policy";
+	case NFT_TRACETYPE_RETURN:
+		return "return";
+	case NFT_TRACETYPE_RULE:
+		return "rule";
+	case NFT_TRACETYPE_UNSPEC: /* fallthrough */
+	case __NFT_TRACETYPE_MAX:
+		break;
+	}
+
+	return "";
+}
+
+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(struct nftnl_trace *t)
+{
+	xfree(t->chain);
+	xfree(t->table);
+	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_attibutes 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_TRANSPORT_PROTO:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_DEV_TYPE:
+	case NFTA_TRACE_VLAN_TAG:
+		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_ID:
+	case NFTA_TRACE_IIF:
+	case NFTA_TRACE_OIF:
+	case NFTA_TRACE_MARK:
+	case NFTA_TRACE_TYPE:
+	case NFTA_TRACE_VERDICT:
+		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:
+		if (mnl_attr_get_payload_len(attr) == 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_NETWORK_HEADER:
+		if (mnl_attr_get_payload_len(attr) < sizeof(struct iphdr))
+			abi_breakage();
+		break;
+	case NFTA_TRACE_TRANSPORT_HEADER:
+		if (mnl_attr_get_payload_len(attr) < sizeof(uint32_t))
+			abi_breakage();
+		break;
+	};
+
+	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);
+		return trace->chain;
+	case NFTNL_TRACE_TABLE:
+		*data_len = strlen(trace->table);
+		return trace->table;
+	case NFTNL_TRACE_TRANSPORT_HEADER:
+		*data_len = trace->th.len;
+		return trace->th.data;
+	case NFTNL_TRACE_TRANSPORT_PROTO:
+		*data_len = sizeof(uint8_t);
+		return &trace->th_prot;
+	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_VLAN_TAG:
+		*data_len = sizeof(uint16_t);
+		return &trace->vlan_tag;
+	case NFTNL_TRACE_DEV_TYPE:
+		*data_len = sizeof(uint16_t);
+		return &trace->devtype;
+	}
+
+	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;
+	default: break;
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_u8);
+uint8_t nftnl_trace_get_u8(const struct nftnl_trace *trace, uint16_t type)
+{
+	const uint8_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_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;
+}
+
+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();
+
+	if (tb[NFTA_TRACE_TABLE])
+		t->table = strdup(mnl_attr_get_str(tb[NFTA_TRACE_TABLE]));
+	if (tb[NFTA_TRACE_CHAIN])
+		t->chain = strdup(mnl_attr_get_str(tb[NFTA_TRACE_CHAIN]));
+
+	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_IIF]) {
+		t->iif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_IIF]));
+		t->flags |= (1 << NFTNL_TRACE_IIF);
+	}
+
+	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]) {
+		t->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_VERDICT]));
+		t->flags |= (1 << NFTNL_TRACE_VERDICT);
+	}
+
+	if (tb[NFTA_TRACE_VLAN_TAG]) {
+		t->vlan_tag = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_VLAN_TAG]));
+		t->flags |= (1 << NFTNL_TRACE_VLAN_TAG);
+	}
+
+	if (tb[NFTA_TRACE_DEV_TYPE]) {
+		t->devtype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_DEV_TYPE]));
+		t->flags |= (1 << NFTNL_TRACE_DEV_TYPE);
+	}
+
+	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_TRANSPORT_PROTO]) {
+		t->th_prot = mnl_attr_get_u8(tb[NFTA_TRACE_TRANSPORT_PROTO]);
+		t->flags |= (1 << NFTNL_TRACE_TRANSPORT_PROTO);
+	}
+
+	if (t->chain)
+		t->flags |= (1 << NFTNL_TRACE_CHAIN);
+	if (t->table)
+		t->flags |= (1 << NFTNL_TRACE_TABLE);
+
+	return 0;
+}
+
+static int print_ether_addr(char *buf, size_t size, const void *addr)
+{
+	const uint8_t *mac = addr;
+
+	return snprintf(buf, size, "%02x:%02x:%02x:%02x:%02x:%02x",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int print_ip4(char *buf, size_t size, uint32_t addr)
+{
+	char addrs[INET_ADDRSTRLEN];
+
+	inet_ntop(AF_INET, &addr, addrs, sizeof(addrs));
+	return snprintf(buf, size, "%s", addrs);
+}
+
+static int print_ip6(char *buf, size_t size, const void *addr)
+{
+	char addrs[INET6_ADDRSTRLEN];
+
+	inet_ntop(AF_INET6, addr, addrs, sizeof(addrs));
+	return snprintf(buf, size, "%s", addrs);
+}
+
+static int
+print_th(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	uint8_t proto = nftnl_trace_get_u8(t, NFTNL_TRACE_TRANSPORT_PROTO);
+	int ret, len = size, offset = 0;
+	const struct udphdr *uh;
+	uint32_t plen;
+
+	ret = snprintf(buf+offset, len, " protocol %u", proto);
+
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	switch (proto) {
+	case IPPROTO_DCCP:
+	case IPPROTO_SCTP:
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
+		break;
+	default:
+		return 0;
+	}
+
+	/* warning: only sport/dport are valid */
+	uh = nftnl_trace_get_data(t, NFTNL_TRACE_TRANSPORT_HEADER, &plen);
+	if (!uh)
+		return 0;
+
+	ret = snprintf(buf+offset, len, " sport %"PRIu16 " dport %"PRIu16,
+			ntohs(uh->uh_sport), ntohs(uh->uh_dport));
+
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	return offset;
+}
+
+static int log_packet6(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	const struct ip6_hdr *iph;
+	uint32_t plen;
+
+	iph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!iph || plen < sizeof(iph))
+		return 0;
+
+	ret = snprintf(buf+offset, len, " src ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip6(buf+offset, len, &iph->ip6_src);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " dst ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip6(buf+offset, len, &iph->ip6_dst);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " len %u hoplimit %u",
+		       ntohs(iph->ip6_plen), iph->ip6_hlim);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_th(t, buf+offset, len);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int log_packet4(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	const struct iphdr *iph;
+	uint32_t plen;
+
+	iph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!iph || plen < sizeof(iph))
+		return 0;
+
+	ret = snprintf(buf+offset, len, " src ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip4(buf+offset, len, iph->saddr);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " dst ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip4(buf+offset, len, iph->daddr);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " len %u ttl %u id %u",
+			ntohs(iph->tot_len), iph->ttl, ntohs(iph->id));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (iph->frag_off & htons(IP_OFFMASK)) {
+		ret = snprintf(buf+offset, len, " frag %u protocol %u",
+				ntohs(iph->frag_off) & IP_OFFMASK, iph->protocol);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	} else {
+		ret = print_th(t, buf+offset, len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	return offset;
+}
+
+static bool log_packet_inet(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	const struct iphdr *iph;
+	uint32_t plen;
+
+	iph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!iph)
+		return 0;
+
+	switch (iph->version) {
+	case 4: return log_packet4(t, buf, size);
+	case 6: return log_packet6(t, buf, size);
+	default: break;
+	}
+	return true;
+}
+
+static bool log_packet_arp(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	const struct arphdr *arph;
+	uint32_t plen;
+
+	arph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!arph || plen < sizeof(arph))
+		return 0;
+
+	ret = snprintf(buf+offset, len, " arpop 0x%x", ntohs(arph->ar_op));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return ret;
+}
+
+static int log_packet_bridge(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	const struct ether_header *ethh;
+	int ret, len = size, offset = 0;
+	uint32_t hlen;
+
+	ethh = nftnl_trace_get_data(t, NFTNL_TRACE_LL_HEADER, &hlen);
+	if (!ethh || hlen < sizeof(ethh))
+		return log_packet_inet(t, buf+offset, len);
+
+	ret = snprintf(buf+offset, len, " src ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ether_addr(buf+offset, len, ethh->ether_shost);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " dst ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ether_addr(buf+offset, len, ethh->ether_dhost);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	switch (ntohs(ethh->ether_type)) {
+	case ETHERTYPE_ARP:
+		return log_packet_arp(t, buf+offset, len);
+	case ETHERTYPE_IP:
+		return log_packet4(t, buf+offset, len);
+	case ETHERTYPE_IPV6:
+		return log_packet6(t, buf+offset, len);
+	default:
+		ret = snprintf(buf+offset, len, " ethertype 0x%x", ntohs(ethh->ether_type));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		break;
+	}
+
+	return offset;
+
+}
+
+static int log_packet_netdev(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+
+	switch (t->devtype) {
+	case ARPHRD_ETHER:
+		return log_packet_bridge(t, buf+offset, len);
+	default:
+		ret = snprintf(buf+offset, len, "devtype 0x%04x", t->devtype);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		return log_packet_inet(t, buf+offset, len);
+	}
+
+	return 0;
+}
+
+static int log_packet(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	switch (t->family) {
+	case NFPROTO_IPV4:
+		ret = log_packet4(t, buf+offset, len);
+		break;
+	case NFPROTO_IPV6:
+		ret = log_packet6(t, buf+offset, len);
+		break;
+	case NFPROTO_INET:
+		ret = log_packet_inet(t, buf+offset, len);
+		break;
+	case NFPROTO_ARP: /* fallthrough */
+	case NFPROTO_BRIDGE:
+		ret = log_packet_bridge(t, buf+offset, len);
+		break;
+	case NFPROTO_NETDEV:
+		ret = log_packet_netdev(t, buf+offset, len);
+		break;
+	default:
+		ret = snprintf(buf+offset, len, " family %d", t->family);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		break;
+	}
+
+	return offset;
+}
+
+static int nftnl_trace_snprintf_default(char *buf, size_t size,
+				        const struct nftnl_trace *t)
+{
+	int ret, len = size, offset = 0;
+
+	ret = snprintf(buf+offset, len, "id %08x", nftnl_trace_get_u32(t, NFTNL_TRACE_ID));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " %s", nftnl_family2str(t->family));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_TABLE)) {
+		ret = snprintf(buf+offset, len, " %s", t->table);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_CHAIN)) {
+		ret = snprintf(buf+offset, len, " %s", t->chain);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	ret = snprintf(buf+offset, len, " %s", type2str(t->type));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_VERDICT)) {
+		ret = snprintf(buf+offset, len, " verdict %s",
+				nftnl_verdict2str(nftnl_trace_get_u32(t, NFTNL_TRACE_VERDICT)));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_MARK)) {
+		ret = snprintf(buf+offset, len,
+			       " mark 0x%x", nftnl_trace_get_u32(t, NFTNL_TRACE_MARK));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_VLAN_TAG)) {
+		ret = snprintf(buf+offset, len,
+			       " vlan id %d", nftnl_trace_get_u16(t, NFTNL_TRACE_VLAN_TAG));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_LL_HEADER) ||
+	    nftnl_trace_is_set(t, NFTNL_TRACE_NETWORK_HEADER)) {
+		ret = log_packet(t, buf+offset, len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	return offset;
+}
+
+
+EXPORT_SYMBOL(nftnl_trace_snprintf);
+int nftnl_trace_snprintf(char *buf, size_t size, const struct nftnl_trace *t, uint32_t type)
+{
+	int ret = 0;
+
+	switch (type) {
+	case NFTNL_OUTPUT_DEFAULT:
+		ret = nftnl_trace_snprintf_default(buf, size, t);
+		break;
+	default:
+		return -1;
+	}
+
+	return ret;
+}
+
+static int nftnl_trace_do_snprintf(char *buf, size_t size, void *r,
+				   uint32_t cmd, uint32_t type,
+				   uint32_t flags)
+{
+	return nftnl_trace_snprintf(buf, size, r, type);
+}
+
+
+EXPORT_SYMBOL(nftnl_trace_fprintf);
+int nftnl_trace_fprintf(FILE *fp, const struct nftnl_trace *t, uint32_t type)
+{
+	return nftnl_fprintf(fp, (void *) t, NFTNL_CMD_UNSPEC, type, 0,
+			   nftnl_trace_do_snprintf);
+}
diff --git a/src/utils.c b/src/utils.c
index 84fbe94..fb68b1a 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -152,6 +152,10 @@ const char *nftnl_verdict2str(uint32_t verdict)
 		return "jump";
 	case NFT_GOTO:
 		return "goto";
+	case NFT_CONTINUE:
+		return "continue";
+	case NFT_BREAK:
+		return "break";
 	default:
 		return "unknown";
 	}
-- 
2.4.10


  parent reply	other threads:[~2015-11-24 10:02 UTC|newest]

Thread overview: 80+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
2015-11-24 10:17   ` Pablo Neira Ayuso
2015-11-24 10:27     ` Florian Westphal
2015-11-24 10:30       ` Pablo Neira Ayuso
2015-11-24 10:35         ` Patrick McHardy
2015-11-24 11:11         ` Florian Westphal
2015-11-24 10:22   ` Pablo Neira Ayuso
2015-11-24 10:28     ` Florian Westphal
2015-11-24 10:33       ` Patrick McHardy
2015-11-24 10:44         ` Pablo Neira Ayuso
2015-11-24 10:45           ` Pablo Neira Ayuso
2015-11-24 10:47             ` Patrick McHardy
2015-11-24 10:36       ` Pablo Neira Ayuso
2015-11-24 10:44   ` Patrick McHardy
2015-11-25  0:55   ` Patrick McHardy
2015-11-25  8:39     ` Florian Westphal
2015-11-25  8:48       ` Florian Westphal
2015-11-25  9:35       ` Patrick McHardy
2015-11-25 10:13         ` Florian Westphal
2015-11-25 11:51           ` Patrick McHardy
2015-11-25 12:20             ` Florian Westphal
2015-11-24 10:02 ` [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key Florian Westphal
2015-11-24 10:13   ` Patrick McHardy
2015-11-24 10:21     ` Florian Westphal
2015-11-24 10:28       ` Patrick McHardy
2015-11-24 10:19   ` Pablo Neira Ayuso
2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
2015-11-24 10:16   ` Patrick McHardy
2015-11-24 10:24   ` Pablo Neira Ayuso
2015-11-24 10:31     ` Florian Westphal
2015-11-24 10:39       ` Pablo Neira Ayuso
2015-11-24 10:53         ` Patrick McHardy
2015-11-24 11:10           ` Florian Westphal
2015-11-24 11:33             ` Patrick McHardy
2015-11-24 15:15               ` Florian Westphal
2015-11-24 15:26                 ` Patrick McHardy
2015-11-24 15:35                   ` Florian Westphal
2015-11-24 15:42                     ` Patrick McHardy
2015-11-25 15:06                       ` Patrick McHardy
2015-11-25 16:23                         ` Pablo Neira Ayuso
2015-11-25 16:34                           ` Patrick McHardy
2015-11-25 16:24                         ` Florian Westphal
2015-11-25 16:46                           ` Patrick McHardy
2015-11-25 17:32                             ` Patrick McHardy
2015-11-25 22:27                               ` Florian Westphal
2015-11-25 23:04                                 ` Patrick McHardy
2015-11-25 23:16                                   ` Florian Westphal
2015-11-25 23:30                                     ` Patrick McHardy
2015-11-25 23:42                                 ` Patrick McHardy
2015-11-25 23:56                                   ` Florian Westphal
2015-11-25 22:52                             ` Florian Westphal
2015-11-25 23:15                               ` Patrick McHardy
2015-11-25 23:19                                 ` Florian Westphal
2015-11-26 10:50                             ` Patrick McHardy
2015-11-26 11:03                               ` Florian Westphal
2015-11-26 11:42                                 ` Patrick McHardy
2015-11-25 16:49                         ` Jan Engelhardt
2015-11-25 16:53                           ` Patrick McHardy
2015-11-25 17:14                             ` Jan Engelhardt
2015-11-25 17:24                               ` Patrick McHardy
2015-11-25  0:57   ` Patrick McHardy
2015-11-24 10:02 ` [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS Florian Westphal
2015-11-24 10:11   ` Pablo Neira Ayuso
2015-11-24 10:02 ` Florian Westphal [this message]
2015-11-24 12:16   ` [PATCH libnftnl 5/6] src: add trace infrastructure support Patrick McHardy
2015-11-24 14:53     ` Patrick McHardy
2015-11-24 10:02 ` [PATCH nftables 6/6] src: add trace support to nft monitor mode Florian Westphal
2015-11-24 10:25   ` Patrick McHardy
2015-11-24 10:48     ` Florian Westphal
2015-11-24 10:58       ` Patrick McHardy
2015-11-24 11:01         ` Pablo Neira Ayuso
2015-11-24 11:07           ` Patrick McHardy
2015-11-24 11:14             ` Pablo Neira Ayuso
2015-11-24 11:14         ` Florian Westphal
2015-11-24 11:41           ` Patrick McHardy
2015-11-24 10:53     ` Pablo Neira Ayuso
2015-11-24 11:04       ` Patrick McHardy
2015-11-24 11:12         ` Pablo Neira Ayuso
2015-11-24 11:36           ` Patrick McHardy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1448359331-12692-6-git-send-email-fw@strlen.de \
    --to=fw@strlen.de \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.