All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] nft trace
@ 2015-06-17 20:07 Markus Koetter
  2015-06-17 20:07 ` [PATCH 1/5] parser: add trace command Markus Koetter
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Markus Koetter @ 2015-06-17 20:07 UTC (permalink / raw)
  To: netfilter-devel

This patch adds a new command to nft - the trace command.
The trace command reads NFLOG messages, parses TRACE: messages and prints the
rules in a human readable format.
To trace, you have to set the trace mark on a packet and run "nft trace".
Patch is split into 5 parts, 
 - adding the command, 
 - storing the chain policy during delinearize for later use
 - creating a rule cache to look up the rules
 - implementing the actual command
 - code to log a packet header 'similar' to ip/nftables LOG

Markus Koetter (5):
  parser: add trace command
  netlink: delinarize chain policy
  rule: make cache creation a function
  trace: implement commands action
  trace: add log for packets

 include/Makefile.am |   2 +
 include/log.h       |  17 ++
 include/rule.h      |  15 +
 include/trace.h     |   2 +
 src/Makefile.am     |   2 +
 src/evaluate.c      |   2 +
 src/log.c           | 779 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/netlink.c       |   4 +
 src/parser_bison.y  |  16 +-
 src/rule.c          | 121 ++++++--
 src/scanner.l       |   1 +
 src/trace.c         | 361 ++++++++++++++++++++++++
 12 files changed, 1291 insertions(+), 31 deletions(-)
 create mode 100644 include/log.h
 create mode 100644 include/trace.h
 create mode 100644 src/log.c
 create mode 100644 src/trace.c

-- 
1.9.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/5] parser: add trace command
  2015-06-17 20:07 [PATCH 0/5] nft trace Markus Koetter
@ 2015-06-17 20:07 ` Markus Koetter
  2015-06-17 20:07 ` [PATCH 2/5] netlink: delinarize chain policy Markus Koetter
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Markus Koetter @ 2015-06-17 20:07 UTC (permalink / raw)
  To: netfilter-devel

---
 include/rule.h     | 14 ++++++++++++++
 src/evaluate.c     |  2 ++
 src/parser_bison.y | 16 ++++++++++++++--
 src/rule.c         | 31 +++++++++++++++++++++++++++++++
 src/scanner.l      |  1 +
 5 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/include/rule.h b/include/rule.h
index 491411e..fbd327b 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -224,6 +224,7 @@ extern void set_print_plain(const struct set *s);
  * @CMD_EXPORT:		export the ruleset in a given format
  * @CMD_MONITOR:	event listener
  * @CMD_DESCRIBE:	describe an expression
+ * @CMD_TRACE:		print the packets trace
  */
 enum cmd_ops {
 	CMD_INVALID,
@@ -237,6 +238,7 @@ enum cmd_ops {
 	CMD_EXPORT,
 	CMD_MONITOR,
 	CMD_DESCRIBE,
+	CMD_TRACE,
 };
 
 /**
@@ -253,6 +255,7 @@ enum cmd_ops {
  * @CMD_OBJ_EXPR:	expression
  * @CMD_OBJ_MONITOR:	monitor
  * @CMD_OBJ_EXPORT:	export
+ * @CMD_OBJ_TRACE:	trace
  */
 enum cmd_obj {
 	CMD_OBJ_INVALID,
@@ -266,6 +269,7 @@ enum cmd_obj {
 	CMD_OBJ_EXPR,
 	CMD_OBJ_MONITOR,
 	CMD_OBJ_EXPORT,
+	CMD_OBJ_TRACE,
 };
 
 struct export {
@@ -296,6 +300,15 @@ struct monitor {
 struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event);
 void monitor_free(struct monitor *m);
 
+struct trace {
+	struct location	location;
+	int family;
+};
+
+struct trace *trace_alloc(int family);
+void trace_free(struct trace *m);
+
+
 /**
  * struct cmd - command statement
  *
@@ -325,6 +338,7 @@ struct cmd {
 		struct table	*table;
 		struct monitor	*monitor;
 		struct export	*export;
+		struct trace	*trace;
 	};
 	const void		*arg;
 };
diff --git a/src/evaluate.c b/src/evaluate.c
index a3484c6..cfbafcd 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1971,6 +1971,8 @@ int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
 		return 0;
 	case CMD_MONITOR:
 		return cmd_evaluate_monitor(ctx, cmd);
+	case CMD_TRACE:
+		return 0;
 	default:
 		BUG("invalid command operation %u\n", cmd->op);
 	};
diff --git a/src/parser_bison.y b/src/parser_bison.y
index fd2407c..6178502 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -190,6 +190,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token DESCRIBE			"describe"
 %token EXPORT			"export"
 %token MONITOR			"monitor"
+%token TRACE			"trace"
 
 %token ACCEPT			"accept"
 %token DROP			"drop"
@@ -402,8 +403,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <cmd>			line
 %destructor { cmd_free($$); }	line
 
-%type <cmd>			base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
-%destructor { cmd_free($$); }	base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
+%type <cmd>			base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd trace_cmd
+%destructor { cmd_free($$); }	base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd trace_cmd
 
 %type <handle>			table_spec tables_spec chain_spec chain_identifier ruleid_spec ruleset_spec
 %destructor { handle_free(&$$); } table_spec tables_spec chain_spec chain_identifier ruleid_spec ruleset_spec
@@ -640,6 +641,7 @@ base_cmd		:	/* empty */	add_cmd		{ $$ = $1; }
 			|	EXPORT		export_cmd	{ $$ = $2; }
 			|	MONITOR		monitor_cmd	{ $$ = $2; }
 			|	DESCRIBE	describe_cmd	{ $$ = $2; }
+			|	TRACE		trace_cmd	{ $$ = $2; }
 			;
 
 add_cmd			:	TABLE		table_spec
@@ -809,6 +811,16 @@ export_cmd		:	export_format
 			}
 			;
 
+trace_cmd	: family_spec
+			{
+				struct handle h = { .family = NFPROTO_UNSPEC };
+				struct trace *t = trace_alloc($1);
+				t->location = @-1;
+				$$ = cmd_alloc(CMD_TRACE, CMD_OBJ_TRACE, &h, &@$, t);
+			}
+			;
+
+
 monitor_cmd		:	monitor_event	monitor_object	monitor_format
 			{
 				struct handle h = { .family = NFPROTO_UNSPEC };
diff --git a/src/rule.c b/src/rule.c
index 8d76fd0..97c436e 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -573,6 +573,20 @@ void monitor_free(struct monitor *m)
 	xfree(m);
 }
 
+struct trace *trace_alloc(int family)
+{
+	struct trace *tr;
+
+	tr = xmalloc(sizeof(struct trace));
+	tr->family = family;
+	return tr;
+}
+
+void trace_free(struct trace *tr)
+{
+	xfree(tr);
+}
+
 void cmd_free(struct cmd *cmd)
 {
 	handle_free(&cmd->handle);
@@ -602,6 +616,9 @@ void cmd_free(struct cmd *cmd)
 		case CMD_OBJ_EXPORT:
 			export_free(cmd->export);
 			break;
+		case CMD_OBJ_TRACE:
+			trace_free(cmd->trace);
+			break;
 		default:
 			BUG("invalid command object type %u\n", cmd->obj);
 		}
@@ -953,6 +970,10 @@ static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
 	LIST_HEAD(msgs);
 	struct handle set_handle;
 	struct netlink_mon_handler monhandler;
+}
+
+}
+
 
 	/* cache only needed if monitoring:
 	 *  - new rules in default format
@@ -1000,6 +1021,14 @@ static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
 	return netlink_monitor(&monhandler);
 }
 
+static int do_command_trace(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+	struct handle h = { .family = NFPROTO_UNSPEC };
+	create_cache(ctx, &h, &cmd->location);
+
+	return nft_trace(0, cmd->trace->family);
+}
+
 static int do_command_describe(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	expr_describe(cmd->expr);
@@ -1029,6 +1058,8 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
 		return do_command_monitor(ctx, cmd);
 	case CMD_DESCRIBE:
 		return do_command_describe(ctx, cmd);
+	case CMD_TRACE:
+		return do_command_trace(ctx, cmd);
 	default:
 		BUG("invalid command object type %u\n", cmd->obj);
 	}
diff --git a/src/scanner.l b/src/scanner.l
index 73c4f8b..4f8ace4 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -263,6 +263,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "rename"		{ return RENAME; }
 "export"		{ return EXPORT; }
 "monitor"		{ return MONITOR; }
+"trace"			{ return TRACE; }
 
 "position"		{ return POSITION; }
 "comment"		{ return COMMENT; }
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/5] netlink: delinarize chain policy
  2015-06-17 20:07 [PATCH 0/5] nft trace Markus Koetter
  2015-06-17 20:07 ` [PATCH 1/5] parser: add trace command Markus Koetter
@ 2015-06-17 20:07 ` Markus Koetter
  2015-06-26  8:09   ` Pablo Neira Ayuso
  2015-06-17 20:07 ` [PATCH 3/5] rule: make cache creation a function Markus Koetter
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Markus Koetter @ 2015-06-17 20:07 UTC (permalink / raw)
  To: netfilter-devel

---
 include/rule.h | 1 +
 src/netlink.c  | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/include/rule.h b/include/rule.h
index fbd327b..40cb98a 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -119,6 +119,7 @@ struct chain {
 	const char		*type;
 	struct scope		scope;
 	struct list_head	rules;
+	uint32_t		policy;
 };
 
 extern const char *chain_type_name_lookup(const char *name);
diff --git a/src/netlink.c b/src/netlink.c
index 84d9d27..17aabd4 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -675,6 +675,10 @@ static struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
 		chain->flags        |= CHAIN_F_BASECHAIN;
 	}
 
+	if (nft_chain_attr_is_set(nlc, NFT_CHAIN_ATTR_TYPE))
+		chain->policy =
+		nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_POLICY);
+
 	return chain;
 }
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/5] rule: make cache creation a function
  2015-06-17 20:07 [PATCH 0/5] nft trace Markus Koetter
  2015-06-17 20:07 ` [PATCH 1/5] parser: add trace command Markus Koetter
  2015-06-17 20:07 ` [PATCH 2/5] netlink: delinarize chain policy Markus Koetter
@ 2015-06-17 20:07 ` Markus Koetter
  2015-06-17 20:07 ` [PATCH 4/5] trace: implement commands action Markus Koetter
  2015-06-17 20:07 ` [PATCH 5/5] trace: add log for packets Markus Koetter
  4 siblings, 0 replies; 9+ messages in thread
From: Markus Koetter @ 2015-06-17 20:07 UTC (permalink / raw)
  To: netfilter-devel

---
 src/rule.c | 93 +++++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 62 insertions(+), 31 deletions(-)

diff --git a/src/rule.c b/src/rule.c
index 97c436e..dc65452 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -962,18 +962,73 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
 	return 0;
 }
 
-static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
+static int create_cache(struct netlink_ctx *ctx, struct handle *h, struct location *loc)
 {
 	struct table *t, *nt;
 	struct set *s, *ns;
-	struct netlink_ctx set_ctx;
+	struct chain *c, *nc;
+	struct rule *r, *rc;
+	struct netlink_ctx tmpctx;
 	LIST_HEAD(msgs);
-	struct handle set_handle;
-	struct netlink_mon_handler monhandler;
-}
+	struct handle filter;
+
+	/* create cache */
+	memset(&tmpctx, 0, sizeof(tmpctx));
+	init_list_head(&msgs);
+	tmpctx.msgs = &msgs;
+
+	if (netlink_list_tables(ctx, h, loc) < 0)
+		return -1;
+
+	list_for_each_entry_safe(t, nt, &ctx->list, list) {
+		table_add_hash(t);
+
+		filter.family = t->handle.family;
+		filter.table = t->handle.table;
+		filter.chain = NULL;
+
+		init_list_head(&tmpctx.list);
+
+		if (netlink_list_sets(&tmpctx, &filter, loc) < 0)
+			return -1;
+
+		list_for_each_entry_safe(s, ns, &tmpctx.list, list) {
+			if (netlink_get_setelems(&tmpctx, &s->handle, loc, s) < 0)
+				return -1;
+			list_move_tail(&s->list, &t->sets);
+			set_add_hash(s, t);
+		}
+
+		init_list_head(&tmpctx.list);
+
+		if (netlink_list_chains(&tmpctx, &filter, loc) < 0)
+			return -1;
+
+		list_for_each_entry_safe(c, nc, &tmpctx.list, list) {
+			chain_add_hash(c, t);
+		}
+
+		init_list_head(&tmpctx.list);
 
+		if (netlink_list_table(&tmpctx, &filter, loc) < 0)
+			return -1;
+
+		list_for_each_entry_safe(r, rc, &tmpctx.list, list) {
+			c = chain_lookup(t, &r->handle);
+			if (c == NULL) {
+				c = chain_alloc(r->handle.chain);
+				chain_add_hash(c, t);
+			}
+			list_move_tail(&r->list, &c->rules);
+		}
+		init_list_head(&tmpctx.list);
+	}
+	return 0;
 }
 
+static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+	struct netlink_mon_handler monhandler;
 
 	/* cache only needed if monitoring:
 	 *  - new rules in default format
@@ -986,32 +1041,8 @@ static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
 	else
 		monhandler.cache_needed = false;
 
-	if (monhandler.cache_needed) {
-		memset(&set_ctx, 0, sizeof(set_ctx));
-		init_list_head(&msgs);
-		set_ctx.msgs = &msgs;
-
-		if (netlink_list_tables(ctx, &cmd->handle, &cmd->location) < 0)
-			return -1;
-
-		list_for_each_entry_safe(t, nt, &ctx->list, list) {
-			set_handle.family = t->handle.family;
-			set_handle.table = t->handle.table;
-
-			init_list_head(&set_ctx.list);
-
-			if (netlink_list_sets(&set_ctx, &set_handle,
-					      &cmd->location) < 0)
-				return -1;
-
-			list_for_each_entry_safe(s, ns, &set_ctx.list, list) {
-				s->init = set_expr_alloc(&cmd->location);
-				set_add_hash(s, t);
-			}
-
-			table_add_hash(t);
-		}
-	}
+	if (monhandler.cache_needed)
+		create_cache(ctx, &cmd->handle, &cmd->location);
 
 	monhandler.monitor_flags = cmd->monitor->flags;
 	monhandler.format = cmd->monitor->format;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/5] trace: implement commands action
  2015-06-17 20:07 [PATCH 0/5] nft trace Markus Koetter
                   ` (2 preceding siblings ...)
  2015-06-17 20:07 ` [PATCH 3/5] rule: make cache creation a function Markus Koetter
@ 2015-06-17 20:07 ` Markus Koetter
  2015-06-25 14:11   ` Pablo Neira Ayuso
  2015-06-17 20:07 ` [PATCH 5/5] trace: add log for packets Markus Koetter
  4 siblings, 1 reply; 9+ messages in thread
From: Markus Koetter @ 2015-06-17 20:07 UTC (permalink / raw)
  To: netfilter-devel


trace.c is based upon https://git.netfilter.org/libmnl/tree/examples/netfilter/nf-log.c

---
 include/Makefile.am |   1 +
 include/trace.h     |   2 +
 src/Makefile.am     |   1 +
 src/rule.c          |   1 +
 src/trace.c         | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 366 insertions(+)
 create mode 100644 include/trace.h
 create mode 100644 src/trace.c

diff --git a/include/Makefile.am b/include/Makefile.am
index f22561b..c351b55 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -19,4 +19,5 @@ noinst_HEADERS = 	cli.h		\
 			parser.h	\
 			proto.h		\
 			rule.h		\
+			trace.h		\
 			utils.h
diff --git a/include/trace.h b/include/trace.h
new file mode 100644
index 0000000..8c43c86
--- /dev/null
+++ b/include/trace.h
@@ -0,0 +1,2 @@
+int nft_trace(int qnum, int family);
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 2410fd3..db77e8e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,6 +45,7 @@ nft_SOURCES =	main.c				\
 		erec.c				\
 		mnl.c				\
 		scanner.l			\
+		trace.c				\
 		parser_bison.y
 
 if BUILD_CLI
diff --git a/src/rule.c b/src/rule.c
index dc65452..cd21de0 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -18,6 +18,7 @@
 
 #include <statement.h>
 #include <rule.h>
+#include <trace.h>
 #include <utils.h>
 #include <netlink.h>
 
diff --git a/src/trace.c b/src/trace.c
new file mode 100644
index 0000000..a9c9b5f
--- /dev/null
+++ b/src/trace.c
@@ -0,0 +1,361 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include <net/ethernet.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+
+#ifndef aligned_be64
+#define aligned_be64 u_int64_t __attribute__((aligned(8)))
+#endif
+
+#include <linux/netfilter/nfnetlink_log.h>
+#include <libmnl/libmnl.h>
+
+#include "trace.h"
+#include "rule.h"
+#include "statement.h"
+#include "log.h"
+
+struct prefix
+{
+	char *table;
+	char *chain;
+	char *action;
+	char *num;
+};
+
+static int parse_prefix(char *prefix, struct prefix *td)
+{
+	static const char *TRACE = "TRACE: ";
+	char *pos;
+	char *cur = NULL;
+	char *end = prefix + strlen(prefix);
+	pos = prefix;
+
+	/* "TRACE: filter:input:rule:2 " */
+	if (strncmp(prefix, TRACE, strlen(TRACE)) != 0)
+		return -1;
+
+	pos += strlen(TRACE);
+
+	if (pos >= end)
+		goto invalid_format_error;
+
+	/* "filter:input:rule:2 " */
+	/* TABLE:CHAIN:ACTION:NUM */
+	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
+		goto invalid_format_error;
+	*cur = '\0';
+	td->table = pos;
+	pos = cur+1;
+
+	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
+		goto invalid_format_error;
+	*cur = '\0';
+	td->chain = pos;
+	pos = cur+1;
+
+	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
+		goto invalid_format_error;
+	*cur = '\0';
+	td->action = pos;
+
+	td->num = cur+1;
+	return 0;
+
+invalid_format_error:
+	return -1;
+}
+
+
+static int parse_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	/* skip unsupported attribute in user-space */
+	if (mnl_attr_type_valid(attr, NFULA_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch(type) {
+	case NFULA_MARK:
+	case NFULA_IFINDEX_INDEV:
+	case NFULA_IFINDEX_OUTDEV:
+	case NFULA_IFINDEX_PHYSINDEV:
+	case NFULA_IFINDEX_PHYSOUTDEV:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+			perror("mnl_attr_validate");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_TIMESTAMP:
+		if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
+		    sizeof(struct nfulnl_msg_packet_timestamp)) < 0) {
+			perror("mnl_attr_validate2");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_HWADDR:
+		if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
+		    sizeof(struct nfulnl_msg_packet_hw)) < 0) {
+			perror("mnl_attr_validate2");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_PREFIX:
+		if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
+			perror("mnl_attr_validate");
+			return MNL_CB_ERROR;
+		}
+		break;
+	case NFULA_PAYLOAD:
+		break;
+	}
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+struct log_ctx
+{
+	int family;
+};
+
+static int log_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct log_ctx *ctx = data;
+	struct nlattr *tb[NFULA_MAX+1] = {};
+	struct nfulnl_msg_packet_hdr *ph = NULL;
+	struct prefix td;
+	char prefix[65];
+
+	struct handle h;
+	struct table *table;
+	struct chain *chain;
+	struct rule *rule = NULL;
+	const struct stmt *stmt;
+	int i;
+	uint32_t mark = 0;
+
+	mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
+
+	if (!tb[NFULA_PACKET_HDR])
+		return 0;
+
+	ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
+
+	if (ntohs(ph->hw_protocol) == ETHERTYPE_IP && (ctx->family != NFPROTO_IPV4 && ctx->family != NFPROTO_INET))
+		return 0;
+	if (ntohs(ph->hw_protocol) == ETHERTYPE_IPV6 && (ctx->family != NFPROTO_IPV6 && ctx->family != NFPROTO_INET))
+		return 0;
+
+
+	if (tb[NFULA_PREFIX])
+		strncpy(prefix, mnl_attr_get_str(tb[NFULA_PREFIX]), sizeof(prefix)-1);
+	else
+		goto invalid_format_error;
+
+	prefix[sizeof(prefix)-1] = '\0';
+
+	if( parse_prefix(prefix, &td) != 0)
+		return 0;
+
+	if (tb[NFULA_MARK])
+		mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK]));
+
+	h.family = ctx->family;
+	h.table = td.table;
+
+	if ( (table = table_lookup(&h)) == NULL)
+		return 0;
+
+	h.chain = td.chain;
+	if ( (chain = chain_lookup(table, &h)) ==  NULL)
+		return 0;
+
+	if (strcmp(td.action, "rule") == 0) {
+		i = atoi(td.num);
+		list_for_each_entry(rule, &chain->rules, list) {
+			if (--i != 0)
+				continue;
+			break;
+		}
+		if (rule == NULL)
+			return 0;
+		list_for_each_entry(stmt, &rule->stmts, list) {
+			if (stmt->ops->type == STMT_META &&
+				stmt->meta.key == NFT_META_NFTRACE)
+			{
+				nf_log_packet(tb);
+				break;
+			}
+		}
+	}
+
+
+	if (strcmp(td.action, "policy") == 0) {
+		char *policies[NF_MAX_VERDICT] = {
+			[NF_DROP] = "DROP",
+			[NF_ACCEPT] = "ACCEPT",
+			[NF_QUEUE] = "QUEUE",
+		};
+		printf("\t%s %s NFMARK=0x%x\n", td.table, td.chain, mark);
+		printf("\t\t%s\n", policies[chain->policy]);
+	} else
+	if (strcmp(td.action, "rule") == 0) {
+		printf("\t%s %s (#%i) NFMARK=0x%x\n", td.table, td.chain, atoi(td.num), mark);
+		printf("\t\t");
+		rule_print(rule);
+		printf("\n");
+	} else
+	if (strcmp(td.action, "return") == 0) {
+		printf("\t%s %s NFMARK=0x%x\n", td.table, td.chain, mark);
+		printf("\t\t => RETURN\n");
+	}
+
+invalid_format_error:
+	return MNL_CB_OK;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_pf_request(char *buf, uint8_t command)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+	struct nfulnl_msg_config_cmd cmd;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+
+	cmd.command = command,
+
+	mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
+
+	return nlh;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_request(char *buf, uint8_t command, int qnum)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+	struct nfulnl_msg_config_cmd cmd;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(qnum);
+
+	cmd.command = command,
+
+	mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
+
+	return nlh;
+}
+
+static struct nlmsghdr *
+nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+	struct nfulnl_msg_config_mode params;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type	= (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_UNSPEC;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = htons(qnum);
+
+	params.copy_range = htonl(range);
+	params.copy_mode = mode;
+
+	mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
+
+	return nlh;
+}
+
+int nft_trace(int qnum, int family)
+{
+	struct mnl_socket *nl;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	int ret;
+	int portid;
+	struct log_ctx lctx = { .family = family };
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL)
+		return -1;
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+		goto failed;
+
+	portid = mnl_socket_get_portid(nl);
+
+	nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto failed;
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	if (ret == -1)
+		goto failed;
+
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, 0, portid, log_cb, &lctx);
+		if (ret < 0){
+			perror("mnl_cb_run");
+			exit(EXIT_FAILURE);
+		}
+
+		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+		if (ret == -1) {
+			perror("mnl_socket_recvfrom");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	mnl_socket_close(nl);
+
+	return 0;
+
+
+failed:
+	mnl_socket_close(nl);
+	return -1;
+}
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/5] trace: add log for packets
  2015-06-17 20:07 [PATCH 0/5] nft trace Markus Koetter
                   ` (3 preceding siblings ...)
  2015-06-17 20:07 ` [PATCH 4/5] trace: implement commands action Markus Koetter
@ 2015-06-17 20:07 ` Markus Koetter
  2015-06-25 13:38   ` Pablo Neira Ayuso
  4 siblings, 1 reply; 9+ messages in thread
From: Markus Koetter @ 2015-06-17 20:07 UTC (permalink / raw)
  To: netfilter-devel

use kernel packet logging code, just adding some compat skbuff/nf_log_buf
and disable some blocks using ifdefs.
---
 include/Makefile.am |   1 +
 include/log.h       |  17 ++
 src/Makefile.am     |   1 +
 src/log.c           | 779 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 798 insertions(+)
 create mode 100644 include/log.h
 create mode 100644 src/log.c

diff --git a/include/Makefile.am b/include/Makefile.am
index c351b55..7951587 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -20,4 +20,5 @@ noinst_HEADERS = 	cli.h		\
 			proto.h		\
 			rule.h		\
 			trace.h		\
+			log.h		\
 			utils.h
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..22545f4
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,17 @@
+#include <stdint.h>
+#include <inttypes.h>
+
+struct nf_log_buf;
+
+void nf_log_buf_init(struct nf_log_buf *);
+int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...);
+void nf_log_buf_exit(struct nf_log_buf *m);
+
+struct nlattr;
+void nf_log_packet(struct nlattr *tb[]);
+
+#define IP_CE           0x8000          /* Flag: "Congestion"           */
+#define IP_DF           0x4000          /* Flag: "Don't Fragment"       */
+#define IP_MF           0x2000          /* Flag: "More Fragments"       */
+#define IP_OFFSET       0x1FFF          /* "Fragment Offset" part       */
+
diff --git a/src/Makefile.am b/src/Makefile.am
index db77e8e..3fd07ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,6 +46,7 @@ nft_SOURCES =	main.c				\
 		mnl.c				\
 		scanner.l			\
 		trace.c				\
+		log.c				\
 		parser_bison.y
 
 if BUILD_CLI
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..410c21e
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,779 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+
+#include <log.h>
+#include <linux/netfilter/nfnetlink_log.h>
+#include <libnfnetlink/libnfnetlink.h>
+
+
+#include <libmnl/libmnl.h>
+
+#define S_SIZE (1024 - (sizeof(unsigned int) + 1))
+
+struct nf_log_buf {
+	unsigned int	count;
+	char		buf[S_SIZE + 1];
+};
+
+int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
+{
+	va_list args;
+	int len;
+
+	if (m->count < S_SIZE) {
+		va_start(args, f);
+		len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
+		va_end(args);
+		if (m->count + len < S_SIZE) {
+			m->count += len;
+			return 0;
+		}
+	}
+	m->count = S_SIZE;
+	return -1;
+}
+
+void nf_log_buf_init(struct nf_log_buf *m)
+{
+	m->count = 0;
+}
+
+void nf_log_buf_exit(struct nf_log_buf *m)
+{
+	m->buf[m->count] = 0;
+}
+
+struct sk_buff
+{
+	void *data;
+	uint16_t len;
+	uint32_t mark;
+};
+
+static void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *dest)
+{
+	if (skb->len-offset < len)
+		return NULL;
+	memcpy(dest, &((unsigned char *)skb->data)[offset], len);
+	return dest;
+}
+
+struct nf_loginfo
+{
+	int type;
+};
+
+#define u8 uint8_t
+
+static int nf_log_dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb,
+			   u8 proto, int fragment, unsigned int offset)
+{
+	struct udphdr _udph;
+	const struct udphdr *uh;
+
+	if (proto == IPPROTO_UDP)
+		/* Max length: 10 "PROTO=UDP "     */
+		nf_log_buf_add(m, "PROTO=UDP ");
+	else	/* Max length: 14 "PROTO=UDPLITE " */
+		nf_log_buf_add(m, "PROTO=UDPLITE ");
+
+	if (fragment)
+		goto out;
+
+	/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+	uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+	if (uh == NULL) {
+		nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset);
+
+		return 1;
+	}
+
+	/* Max length: 20 "SPT=65535 DPT=65535 " */
+	nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ",
+		       ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len));
+
+out:
+	return 0;
+}
+
+static int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb,
+			   u8 proto, int fragment, unsigned int offset,
+			   unsigned int logflags)
+{
+	struct tcphdr _tcph;
+	const struct tcphdr *th;
+
+	/* Max length: 10 "PROTO=TCP " */
+	nf_log_buf_add(m, "PROTO=TCP ");
+
+	if (fragment)
+		return 0;
+
+	/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+	th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
+	if (th == NULL) {
+		nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset);
+		return 1;
+	}
+
+	/* Max length: 20 "SPT=65535 DPT=65535 " */
+	nf_log_buf_add(m, "SPT=%u DPT=%u ",
+		       ntohs(th->source), ntohs(th->dest));
+
+#ifdef XT_LOG_TCPSEQ
+	/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
+	if (logflags & XT_LOG_TCPSEQ) {
+		nf_log_buf_add(m, "SEQ=%u ACK=%u ",
+			       ntohl(th->seq), ntohl(th->ack_seq));
+	}
+#endif
+
+	/* Max length: 13 "WINDOW=65535 " */
+	nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window));
+	/* Max length: 9 "RES=0x3C " */
+	nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) &
+					    TCP_RESERVED_BITS) >> 22));
+	/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
+	if (th->cwr)
+		nf_log_buf_add(m, "CWR ");
+	if (th->ece)
+		nf_log_buf_add(m, "ECE ");
+	if (th->urg)
+		nf_log_buf_add(m, "URG ");
+	if (th->ack)
+		nf_log_buf_add(m, "ACK ");
+	if (th->psh)
+		nf_log_buf_add(m, "PSH ");
+	if (th->rst)
+		nf_log_buf_add(m, "RST ");
+	if (th->syn)
+		nf_log_buf_add(m, "SYN ");
+	if (th->fin)
+		nf_log_buf_add(m, "FIN ");
+	/* Max length: 11 "URGP=65535 " */
+	nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr));
+
+#ifdef XT_LOG_TCPOPT
+	if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) {
+		u_int8_t _opt[60 - sizeof(struct tcphdr)];
+		const u_int8_t *op;
+		unsigned int i;
+		unsigned int optsize = th->doff*4 - sizeof(struct tcphdr);
+
+		op = skb_header_pointer(skb, offset + sizeof(struct tcphdr),
+					optsize, _opt);
+		if (op == NULL) {
+			nf_log_buf_add(m, "OPT (TRUNCATED)");
+			return 1;
+		}
+
+		/* Max length: 127 "OPT (" 15*4*2chars ") " */
+		nf_log_buf_add(m, "OPT (");
+		for (i = 0; i < optsize; i++)
+			nf_log_buf_add(m, "%02X", op[i]);
+
+		nf_log_buf_add(m, ") ");
+	}
+#endif
+	return 0;
+}
+
+#define NEXTHDR_NONE            59
+static inline int
+ip6t_ext_hdr(u8 nexthdr)
+{       return (nexthdr == IPPROTO_HOPOPTS) ||
+			   (nexthdr == IPPROTO_ROUTING) ||
+			   (nexthdr == IPPROTO_FRAGMENT) ||
+			   (nexthdr == IPPROTO_ESP) ||
+			   (nexthdr == IPPROTO_AH) ||
+			   (nexthdr == IPPROTO_NONE) ||
+			   (nexthdr == IPPROTO_DSTOPTS);
+}
+
+/* One level of recursion won't kill us */
+static void dump_ipv6_packet(struct nf_log_buf *m,
+			     const struct nf_loginfo *info,
+			     const struct sk_buff *skb, unsigned int ip6hoff,
+			     int recurse)
+{
+	u_int8_t currenthdr;
+	int fragment;
+	struct ipv6hdr _ip6h;
+	const struct ipv6hdr *ih;
+	unsigned int ptr;
+	unsigned int hdrlen = 0;
+	unsigned int logflags;
+
+#ifdef NF_LOG_TYPE_LOG
+	if (info->type == NF_LOG_TYPE_LOG)
+		logflags = info->u.log.logflags;
+	else
+		logflags = NF_LOG_MASK;
+#endif
+
+	ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
+	if (ih == NULL) {
+		nf_log_buf_add(m, "TRUNCATED");
+		return;
+	}
+
+	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
+//	nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
+	{
+		char src[INET6_ADDRSTRLEN+1], dst[INET6_ADDRSTRLEN+1];
+		nf_log_buf_add(m, "SRC=%s DST=%s ",
+				 inet_ntop(AF_INET6, (void *)&ih->saddr, src, sizeof(src)),
+				 inet_ntop(AF_INET6, (void *)&ih->daddr, dst, sizeof(dst)));
+	}
+
+	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
+	nf_log_buf_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
+	       ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
+	       (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
+	       ih->hop_limit,
+	       (ntohl(*(__be32 *)ih) & 0x000fffff));
+
+	fragment = 0;
+	ptr = ip6hoff + sizeof(struct ipv6hdr);
+	currenthdr = ih->nexthdr;
+	while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
+		struct ipv6_opt_hdr _hdr;
+		const struct ipv6_opt_hdr *hp;
+
+		hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
+		if (hp == NULL) {
+			nf_log_buf_add(m, "TRUNCATED");
+			return;
+		}
+
+#ifdef XT_LOG_IPOPT
+		/* Max length: 48 "OPT (...) " */
+		if (logflags & XT_LOG_IPOPT)
+			nf_log_buf_add(m, "OPT ( ");
+
+		switch (currenthdr) {
+		case IPPROTO_FRAGMENT: {
+			struct frag_hdr _fhdr;
+			const struct frag_hdr *fh;
+
+			nf_log_buf_add(m, "FRAG:");
+			fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
+						&_fhdr);
+			if (fh == NULL) {
+				nf_log_buf_add(m, "TRUNCATED ");
+				return;
+			}
+
+			/* Max length: 6 "65535 " */
+			nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8);
+
+			/* Max length: 11 "INCOMPLETE " */
+			if (fh->frag_off & htons(0x0001))
+				nf_log_buf_add(m, "INCOMPLETE ");
+
+			nf_log_buf_add(m, "ID:%08x ",
+				       ntohl(fh->identification));
+
+			if (ntohs(fh->frag_off) & 0xFFF8)
+				fragment = 1;
+
+			hdrlen = 8;
+
+			break;
+		}
+		case IPPROTO_DSTOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_HOPOPTS:
+			if (fragment) {
+				if (logflags & XT_LOG_IPOPT)
+					nf_log_buf_add(m, ")");
+				return;
+			}
+			hdrlen = ipv6_optlen(hp);
+			break;
+		/* Max Length */
+		case IPPROTO_AH:
+			if (logflags & XT_LOG_IPOPT) {
+				struct ip_auth_hdr _ahdr;
+				const struct ip_auth_hdr *ah;
+
+				/* Max length: 3 "AH " */
+				nf_log_buf_add(m, "AH ");
+
+				if (fragment) {
+					nf_log_buf_add(m, ")");
+					return;
+				}
+
+				ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
+							&_ahdr);
+				if (ah == NULL) {
+					/*
+					 * Max length: 26 "INCOMPLETE [65535
+					 *  bytes] )"
+					 */
+					nf_log_buf_add(m, "INCOMPLETE [%u bytes] )",
+						       skb->len - ptr);
+					return;
+				}
+
+				/* Length: 15 "SPI=0xF1234567 */
+				nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi));
+
+			}
+
+			hdrlen = (hp->hdrlen+2)<<2;
+			break;
+		case IPPROTO_ESP:
+			if (logflags & XT_LOG_IPOPT) {
+				struct ip_esp_hdr _esph;
+				const struct ip_esp_hdr *eh;
+
+				/* Max length: 4 "ESP " */
+				nf_log_buf_add(m, "ESP ");
+
+				if (fragment) {
+					nf_log_buf_add(m, ")");
+					return;
+				}
+
+				/*
+				 * Max length: 26 "INCOMPLETE [65535 bytes] )"
+				 */
+				eh = skb_header_pointer(skb, ptr, sizeof(_esph),
+							&_esph);
+				if (eh == NULL) {
+					nf_log_buf_add(m, "INCOMPLETE [%u bytes] )",
+						       skb->len - ptr);
+					return;
+				}
+
+				/* Length: 16 "SPI=0xF1234567 )" */
+				nf_log_buf_add(m, "SPI=0x%x )",
+					       ntohl(eh->spi));
+			}
+			return;
+		default:
+			/* Max length: 20 "Unknown Ext Hdr 255" */
+			nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr);
+			return;
+		}
+		if (logflags & XT_LOG_IPOPT)
+			nf_log_buf_add(m, ") ");
+#endif
+
+		currenthdr = hp->nexthdr;
+		ptr += hdrlen;
+	}
+
+	switch (currenthdr) {
+	case IPPROTO_TCP:
+		if (nf_log_dump_tcp_header(m, skb, currenthdr, fragment,
+					   ptr, logflags))
+			return;
+		break;
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
+		if (nf_log_dump_udp_header(m, skb, currenthdr, fragment, ptr))
+			return;
+		break;
+	case IPPROTO_ICMPV6: {
+		struct icmp6hdr _icmp6h;
+		const struct icmp6hdr *ic;
+
+		/* Max length: 13 "PROTO=ICMPv6 " */
+		nf_log_buf_add(m, "PROTO=ICMPv6 ");
+
+		if (fragment)
+			break;
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
+		if (ic == NULL) {
+			nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
+				       skb->len - ptr);
+			return;
+		}
+
+		/* Max length: 18 "TYPE=255 CODE=255 " */
+		nf_log_buf_add(m, "TYPE=%u CODE=%u ",
+			       ic->icmp6_type, ic->icmp6_code);
+
+		switch (ic->icmp6_type) {
+		case ICMPV6_ECHO_REQUEST:
+		case ICMPV6_ECHO_REPLY:
+			/* Max length: 19 "ID=65535 SEQ=65535 " */
+			nf_log_buf_add(m, "ID=%u SEQ=%u ",
+				ntohs(ic->icmp6_identifier),
+				ntohs(ic->icmp6_sequence));
+			break;
+		case ICMPV6_MGM_QUERY:
+		case ICMPV6_MGM_REPORT:
+		case ICMPV6_MGM_REDUCTION:
+			break;
+
+		case ICMPV6_PARAMPROB:
+			/* Max length: 17 "POINTER=ffffffff " */
+			nf_log_buf_add(m, "POINTER=%08x ",
+				       ntohl(ic->icmp6_pointer));
+			/* Fall through */
+		case ICMPV6_DEST_UNREACH:
+		case ICMPV6_PKT_TOOBIG:
+		case ICMPV6_TIME_EXCEED:
+			/* Max length: 3+maxlen */
+			if (recurse) {
+				nf_log_buf_add(m, "[");
+				dump_ipv6_packet(m, info, skb,
+						 ptr + sizeof(_icmp6h), 0);
+				nf_log_buf_add(m, "] ");
+			}
+
+			/* Max length: 10 "MTU=65535 " */
+			if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) {
+				nf_log_buf_add(m, "MTU=%u ",
+					       ntohl(ic->icmp6_mtu));
+			}
+		}
+		break;
+	}
+	/* Max length: 10 "PROTO=255 " */
+	default:
+		nf_log_buf_add(m, "PROTO=%u ", currenthdr);
+	}
+
+#ifdef XT_LOG_UID
+	/* Max length: 15 "UID=4294967295 " */
+	if ((logflags & XT_LOG_UID) && recurse)
+		nf_log_dump_sk_uid_gid(m, skb->sk);
+#endif
+
+	/* Max length: 16 "MARK=0xFFFFFFFF " */
+	if (recurse && skb->mark)
+		nf_log_buf_add(m, "MARK=0x%x ", skb->mark);
+}
+
+/* One level of recursion won't kill us */
+static void dump_ipv4_packet(struct nf_log_buf *m,
+			     const struct nf_loginfo *info,
+			     const struct sk_buff *skb, unsigned int iphoff)
+{
+	struct iphdr _iph;
+	const struct iphdr *ih;
+	unsigned int logflags;
+
+#ifdef NF_LOG_TYPE_LOG
+	if (info->type == NF_LOG_TYPE_LOG)
+		logflags = info->u.log.logflags;
+	else
+		logflags = NF_LOG_MASK;
+#endif
+
+	ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
+	if (ih == NULL) {
+		nf_log_buf_add(m, "TRUNCATED");
+		return;
+	}
+
+	/* Important fields:
+	 * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
+	/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
+//	nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr);
+	{
+		char src[INET_ADDRSTRLEN+1], dst[INET_ADDRSTRLEN+1];
+		nf_log_buf_add(m, "SRC=%s DST=%s ",
+				 inet_ntop(AF_INET, (void *)&ih->saddr, src, sizeof(src)),
+				 inet_ntop(AF_INET, (void *)&ih->daddr, dst, sizeof(dst)));
+	}
+
+	/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
+	nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
+		       ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
+		       ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
+
+	/* Max length: 6 "CE DF MF " */
+	if (ntohs(ih->frag_off) & IP_CE)
+		nf_log_buf_add(m, "CE ");
+	if (ntohs(ih->frag_off) & IP_DF)
+		nf_log_buf_add(m, "DF ");
+	if (ntohs(ih->frag_off) & IP_MF)
+		nf_log_buf_add(m, "MF ");
+
+	/* Max length: 11 "FRAG:65535 " */
+	if (ntohs(ih->frag_off) & IP_OFFSET)
+		nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
+
+#ifdef XT_LOG_IPOPT
+	if ( (logflags & XT_LOG_IPOPT) && ih->ihl * 4 > sizeof(struct iphdr)) {
+		const unsigned char *op;
+		unsigned char _opt[4 * 15 - sizeof(struct iphdr)];
+		unsigned int i, optsize;
+
+		optsize = ih->ihl * 4 - sizeof(struct iphdr);
+		op = skb_header_pointer(skb, iphoff+sizeof(_iph),
+					optsize, _opt);
+		if (op == NULL) {
+			nf_log_buf_add(m, "TRUNCATED");
+			return;
+		}
+
+		/* Max length: 127 "OPT (" 15*4*2chars ") " */
+		nf_log_buf_add(m, "OPT (");
+		for (i = 0; i < optsize; i++)
+			nf_log_buf_add(m, "%02X", op[i]);
+		nf_log_buf_add(m, ") ");
+	}
+#endif
+
+	switch (ih->protocol) {
+	case IPPROTO_TCP:
+		if (nf_log_dump_tcp_header(m, skb, ih->protocol,
+					   ntohs(ih->frag_off) & IP_OFFSET,
+					   iphoff+ih->ihl*4, logflags))
+			return;
+		break;
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
+		if (nf_log_dump_udp_header(m, skb, ih->protocol,
+					   ntohs(ih->frag_off) & IP_OFFSET,
+					   iphoff+ih->ihl*4))
+			return;
+		break;
+	case IPPROTO_ICMP: {
+		struct icmphdr _icmph;
+		const struct icmphdr *ich;
+		static const size_t required_len[NR_ICMP_TYPES+1]
+			= { [ICMP_ECHOREPLY] = 4,
+			    [ICMP_DEST_UNREACH]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_SOURCE_QUENCH]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_REDIRECT]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_ECHO] = 4,
+			    [ICMP_TIME_EXCEEDED]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_PARAMETERPROB]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_TIMESTAMP] = 20,
+			    [ICMP_TIMESTAMPREPLY] = 20,
+			    [ICMP_ADDRESS] = 12,
+			    [ICMP_ADDRESSREPLY] = 12 };
+
+		/* Max length: 11 "PROTO=ICMP " */
+		nf_log_buf_add(m, "PROTO=ICMP ");
+
+		if (ntohs(ih->frag_off) & IP_OFFSET)
+			break;
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
+					 sizeof(_icmph), &_icmph);
+		if (ich == NULL) {
+			nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
+				       skb->len - iphoff - ih->ihl*4);
+			break;
+		}
+
+		/* Max length: 18 "TYPE=255 CODE=255 " */
+		nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (ich->type <= NR_ICMP_TYPES &&
+		    required_len[ich->type] &&
+		    skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
+			nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
+				       skb->len - iphoff - ih->ihl*4);
+			break;
+		}
+
+		switch (ich->type) {
+		case ICMP_ECHOREPLY:
+		case ICMP_ECHO:
+			/* Max length: 19 "ID=65535 SEQ=65535 " */
+			nf_log_buf_add(m, "ID=%u SEQ=%u ",
+				       ntohs(ich->un.echo.id),
+				       ntohs(ich->un.echo.sequence));
+			break;
+
+		case ICMP_PARAMETERPROB:
+			/* Max length: 14 "PARAMETER=255 " */
+			nf_log_buf_add(m, "PARAMETER=%u ",
+				       ntohl(ich->un.gateway) >> 24);
+			break;
+		case ICMP_REDIRECT:
+			/* Max length: 24 "GATEWAY=255.255.255.255 " */
+			nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
+			/* Fall through */
+		case ICMP_DEST_UNREACH:
+		case ICMP_SOURCE_QUENCH:
+		case ICMP_TIME_EXCEEDED:
+			/* Max length: 3+maxlen */
+			if (!iphoff) { /* Only recurse once. */
+				nf_log_buf_add(m, "[");
+				dump_ipv4_packet(m, info, skb,
+					    iphoff + ih->ihl*4+sizeof(_icmph));
+				nf_log_buf_add(m, "] ");
+			}
+
+			/* Max length: 10 "MTU=65535 " */
+			if (ich->type == ICMP_DEST_UNREACH &&
+			    ich->code == ICMP_FRAG_NEEDED) {
+				nf_log_buf_add(m, "MTU=%u ",
+					       ntohs(ich->un.frag.mtu));
+			}
+		}
+		break;
+	}
+	/* Max Length */
+	case IPPROTO_AH: {
+		struct ip_auth_hdr _ahdr;
+		const struct ip_auth_hdr *ah;
+
+		if (ntohs(ih->frag_off) & IP_OFFSET)
+			break;
+
+		/* Max length: 9 "PROTO=AH " */
+		nf_log_buf_add(m, "PROTO=AH ");
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
+					sizeof(_ahdr), &_ahdr);
+		if (ah == NULL) {
+			nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
+				       skb->len - iphoff - ih->ihl*4);
+			break;
+		}
+
+		/* Length: 15 "SPI=0xF1234567 " */
+		nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi));
+		break;
+	}
+	case IPPROTO_ESP: {
+		struct ip_esp_hdr _esph;
+		const struct ip_esp_hdr *eh;
+
+		/* Max length: 10 "PROTO=ESP " */
+		nf_log_buf_add(m, "PROTO=ESP ");
+
+		if (ntohs(ih->frag_off) & IP_OFFSET)
+			break;
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
+					sizeof(_esph), &_esph);
+		if (eh == NULL) {
+			nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
+				       skb->len - iphoff - ih->ihl*4);
+			break;
+		}
+
+		/* Length: 15 "SPI=0xF1234567 " */
+		nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi));
+		break;
+	}
+	/* Max length: 10 "PROTO 255 " */
+	default:
+		nf_log_buf_add(m, "PROTO=%u ", ih->protocol);
+	}
+
+#ifdef XT_LOG_UID
+	/* Max length: 15 "UID=4294967295 " */
+	if ((logflags & XT_LOG_UID) && !iphoff)
+		nf_log_dump_sk_uid_gid(m, skb->sk);
+#endif
+
+	/* Max length: 16 "MARK=0xFFFFFFFF " */
+	if (!iphoff && skb->mark)
+		nf_log_buf_add(m, "MARK=0x%x ", skb->mark);
+
+	/* Proto    Max log string length */
+	/* IP:	    40+46+6+11+127 = 230 */
+	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
+	/* UDP:     10+max(25,20) = 35 */
+	/* UDPLITE: 14+max(25,20) = 39 */
+	/* ICMP:    11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
+	/* ESP:     10+max(25)+15 = 50 */
+	/* AH:	    9+max(25)+15 = 49 */
+	/* unknown: 10 */
+
+	/* (ICMP allows recursion one level deep) */
+	/* maxlen =  IP + ICMP +  IP + max(TCP,UDP,ICMP,unknown) */
+	/* maxlen = 230+   91  + 230 + 252 = 803 */
+}
+
+void nf_log_packet(struct nlattr *tb[])
+{
+	struct nf_log_buf m;
+	struct nfulnl_msg_packet_hdr *ph = NULL;
+
+	nf_log_buf_init(&m);
+
+	if (tb[NFULA_IFINDEX_INDEV]) {
+		char ifname[IFNAMSIZ];
+		if_indextoname(ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_INDEV])), ifname);
+		nf_log_buf_add(&m, "IN=%s ", ifname);
+	}else
+		nf_log_buf_add(&m, "IN= ");
+
+	if (tb[NFULA_IFINDEX_OUTDEV]) {
+		char ifname[IFNAMSIZ];
+		if_indextoname(ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_OUTDEV])), ifname);
+		nf_log_buf_add(&m, "OUT=%s ", ifname);
+	}else
+		nf_log_buf_add(&m, "OUT= ");
+
+	/*
+	if (tb[NFULA_HWHEADER] && tb[NFULA_HWLEN])
+	{
+		uint16_t hwlen = ntohs(mnl_attr_get_u16(tb[NFULA_HWLEN]));
+		unsigned char *hwheader = mnl_attr_get_payload(tb[NFULA_HWHEADER]);
+	}
+	*/
+
+	if (tb[NFULA_PACKET_HDR])
+		ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
+
+	if(ph && tb[NFULA_PAYLOAD])
+	{
+		struct sk_buff skb =
+		{
+			.data = mnl_attr_get_payload(tb[NFULA_PAYLOAD]),
+			.len = NFA_PAYLOAD((struct nfattr *)tb[NFULA_PAYLOAD]),
+			.mark = 0,
+		};
+
+		switch (ntohs(ph->hw_protocol)) {
+		case ETHERTYPE_IP:
+			dump_ipv4_packet(&m, NULL, &skb, 0);
+			break;
+
+		case ETHERTYPE_IPV6:
+			dump_ipv6_packet(&m, NULL, &skb, 0, 1);
+			break;
+
+		default:
+			nf_log_buf_add(&m, "NOT IMPLEMENTED");
+		}
+
+	}
+
+	nf_log_buf_exit(&m);
+	printf("%s\n", m.buf);
+}
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 5/5] trace: add log for packets
  2015-06-17 20:07 ` [PATCH 5/5] trace: add log for packets Markus Koetter
@ 2015-06-25 13:38   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-25 13:38 UTC (permalink / raw)
  To: Markus Koetter; +Cc: netfilter-devel

Hi,

Sorry, it took me a while to look back to this because of the
Netfilter workshop.

On Wed, Jun 17, 2015 at 10:07:37PM +0200, Markus Koetter wrote:
> diff --git a/src/log.c b/src/log.c
> new file mode 100644
> index 0000000..410c21e
> --- /dev/null
> +++ b/src/log.c

This code has to go into libnetfilter_log, IIRC ulogd2 already has a
similar copy of this since it has a output plugin to display the logs
in the same way as the kernel does.

It would be great if both can use the same code. I'd basically like
not to see this code into nft.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 4/5] trace: implement commands action
  2015-06-17 20:07 ` [PATCH 4/5] trace: implement commands action Markus Koetter
@ 2015-06-25 14:11   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-25 14:11 UTC (permalink / raw)
  To: Markus Koetter; +Cc: netfilter-devel

On Wed, Jun 17, 2015 at 10:07:36PM +0200, Markus Koetter wrote:
> 
> trace.c is based upon https://git.netfilter.org/libmnl/tree/examples/netfilter/nf-log.c
> 
> ---
>  include/Makefile.am |   1 +
>  include/trace.h     |   2 +
>  src/Makefile.am     |   1 +
>  src/rule.c          |   1 +
>  src/trace.c         | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 366 insertions(+)
>  create mode 100644 include/trace.h
>  create mode 100644 src/trace.c
> 
> diff --git a/include/Makefile.am b/include/Makefile.am
> index f22561b..c351b55 100644
> --- a/include/Makefile.am
> +++ b/include/Makefile.am
> @@ -19,4 +19,5 @@ noinst_HEADERS = 	cli.h		\
>  			parser.h	\
>  			proto.h		\
>  			rule.h		\
> +			trace.h		\
>  			utils.h
> diff --git a/include/trace.h b/include/trace.h
> new file mode 100644
> index 0000000..8c43c86
> --- /dev/null
> +++ b/include/trace.h
> @@ -0,0 +1,2 @@
> +int nft_trace(int qnum, int family);
> +
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 2410fd3..db77e8e 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -45,6 +45,7 @@ nft_SOURCES =	main.c				\
>  		erec.c				\
>  		mnl.c				\
>  		scanner.l			\
> +		trace.c				\
>  		parser_bison.y
>  
>  if BUILD_CLI
> diff --git a/src/rule.c b/src/rule.c
> index dc65452..cd21de0 100644
> --- a/src/rule.c
> +++ b/src/rule.c
> @@ -18,6 +18,7 @@
>  
>  #include <statement.h>
>  #include <rule.h>
> +#include <trace.h>
>  #include <utils.h>
>  #include <netlink.h>
>  
> diff --git a/src/trace.c b/src/trace.c
> new file mode 100644
> index 0000000..a9c9b5f
> --- /dev/null
> +++ b/src/trace.c
> @@ -0,0 +1,361 @@
> +#include <stddef.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <time.h>
> +#include <arpa/inet.h>
> +
> +#include <net/ethernet.h>
> +
> +#include <libmnl/libmnl.h>
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/nfnetlink.h>
> +
> +#ifndef aligned_be64
> +#define aligned_be64 u_int64_t __attribute__((aligned(8)))
> +#endif
> +
> +#include <linux/netfilter/nfnetlink_log.h>
> +#include <libmnl/libmnl.h>
> +
> +#include "trace.h"
> +#include "rule.h"
> +#include "statement.h"
> +#include "log.h"
> +
> +struct prefix
> +{
> +	char *table;
> +	char *chain;
> +	char *action;
> +	char *num;
> +};
> +
> +static int parse_prefix(char *prefix, struct prefix *td)
> +{
> +	static const char *TRACE = "TRACE: ";
> +	char *pos;
> +	char *cur = NULL;
> +	char *end = prefix + strlen(prefix);
> +	pos = prefix;
> +
> +	/* "TRACE: filter:input:rule:2 " */
> +	if (strncmp(prefix, TRACE, strlen(TRACE)) != 0)
> +		return -1;
> +
> +	pos += strlen(TRACE);
> +
> +	if (pos >= end)
> +		goto invalid_format_error;
> +
> +	/* "filter:input:rule:2 " */
> +	/* TABLE:CHAIN:ACTION:NUM */
> +	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
> +		goto invalid_format_error;
> +	*cur = '\0';
> +	td->table = pos;
> +	pos = cur+1;
> +
> +	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
> +		goto invalid_format_error;
> +	*cur = '\0';
> +	td->chain = pos;
> +	pos = cur+1;
> +
> +	if ( (cur=strchr(pos, ':')) == NULL || cur+1 >= end)
> +		goto invalid_format_error;
> +	*cur = '\0';
> +	td->action = pos;
> +
> +	td->num = cur+1;

We have to pass this information to nfnetlink_log to express it as
netlink attributes. This requires some changes in the kernel side.
This string parsing is not a good idea.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/5] netlink: delinarize chain policy
  2015-06-17 20:07 ` [PATCH 2/5] netlink: delinarize chain policy Markus Koetter
@ 2015-06-26  8:09   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-26  8:09 UTC (permalink / raw)
  To: Markus Koetter; +Cc: netfilter-devel

On Wed, Jun 17, 2015 at 10:07:34PM +0200, Markus Koetter wrote:
> ---
>  include/rule.h | 1 +
>  src/netlink.c  | 4 ++++
>  2 files changed, 5 insertions(+)
> 
> diff --git a/include/rule.h b/include/rule.h
> index fbd327b..40cb98a 100644
> --- a/include/rule.h
> +++ b/include/rule.h
> @@ -119,6 +119,7 @@ struct chain {
>  	const char		*type;
>  	struct scope		scope;
>  	struct list_head	rules;
> +	uint32_t		policy;
>  };
>  
>  extern const char *chain_type_name_lookup(const char *name);
> diff --git a/src/netlink.c b/src/netlink.c
> index 84d9d27..17aabd4 100644
> --- a/src/netlink.c
> +++ b/src/netlink.c
> @@ -675,6 +675,10 @@ static struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
>  		chain->flags        |= CHAIN_F_BASECHAIN;
>  	}
>  
> +	if (nft_chain_attr_is_set(nlc, NFT_CHAIN_ATTR_TYPE))
> +		chain->policy =
> +		nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_POLICY);
> +

Are you using a working copy from git?

This patch seems to apply to an old version of nftables.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-06-26  8:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-17 20:07 [PATCH 0/5] nft trace Markus Koetter
2015-06-17 20:07 ` [PATCH 1/5] parser: add trace command Markus Koetter
2015-06-17 20:07 ` [PATCH 2/5] netlink: delinarize chain policy Markus Koetter
2015-06-26  8:09   ` Pablo Neira Ayuso
2015-06-17 20:07 ` [PATCH 3/5] rule: make cache creation a function Markus Koetter
2015-06-17 20:07 ` [PATCH 4/5] trace: implement commands action Markus Koetter
2015-06-25 14:11   ` Pablo Neira Ayuso
2015-06-17 20:07 ` [PATCH 5/5] trace: add log for packets Markus Koetter
2015-06-25 13:38   ` Pablo Neira Ayuso

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.