netfilter-devel.vger.kernel.org archive mirror
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).