All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft v2] src: add level option to the log statement
@ 2014-07-25 16:20 Pablo Neira Ayuso
  0 siblings, 0 replies; only message in thread
From: Pablo Neira Ayuso @ 2014-07-25 16:20 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber

This patch is required if you use upcoming Linux kernels >= 3.17
which come with a complete logging support for nf_tables.

If you use 'log' without options, the kernel logging buffer is used:

nft> add rule filter input log

You can also specify the logging prefix string:

nft> add rule filter input log prefix "input: "

You may want to specify the log level:

nft> add rule filter input log prefix "input: " level notice

By default, if not specified, the default level is 'warn' (just like
in iptables).

If you specify the group, then nft uses the nfnetlink_log instead:

nft> add rule filter input log prefix "input: " group 10

You can also specify the snaplen and qthreshold for the nfnetlink_log.
But you cannot mix level and group at the same time, they are mutually
exclusive.

Default values for both snaplen and qthreshold are 0 (just like in
iptables).

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: use the scanner to identify the log level instead of strcmp.
    Suggested by Patrick.

 include/statement.h       |   10 +++++++++
 src/evaluate.c            |   15 ++++++++++++-
 src/netlink_delinearize.c |   28 ++++++++++++++++++-----
 src/netlink_linearize.c   |   18 +++++++--------
 src/parser.y              |   54 +++++++++++++++++++++++++++++++++++++++++++++
 src/scanner.l             |    9 ++++++++
 src/statement.c           |   31 ++++++++++++++++++++++----
 7 files changed, 146 insertions(+), 19 deletions(-)

diff --git a/include/statement.h b/include/statement.h
index 480b719..12336bc 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -28,11 +28,21 @@ extern struct stmt *meta_stmt_alloc(const struct location *loc,
 				    enum nft_meta_keys key,
 				    struct expr *expr);
 
+enum {
+	STMT_LOG_PREFIX		= (1 << 0),
+	STMT_LOG_SNAPLEN	= (1 << 1),
+	STMT_LOG_GROUP		= (1 << 2),
+	STMT_LOG_QTHRESHOLD	= (1 << 3),
+	STMT_LOG_LEVEL		= (1 << 4),
+};
+
 struct log_stmt {
 	const char		*prefix;
 	unsigned int		snaplen;
 	uint16_t		group;
 	uint16_t		qthreshold;
+	uint32_t		level;
+	uint32_t		flags;
 };
 
 extern struct stmt *log_stmt_alloc(const struct location *loc);
diff --git a/src/evaluate.c b/src/evaluate.c
index e05473a..f66a8ea 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1180,6 +1180,18 @@ static int stmt_evaluate_ct(struct eval_ctx *ctx, struct stmt *stmt)
 	return 0;
 }
 
+static int stmt_evaluate_log(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	if (stmt->log.flags & STMT_LOG_LEVEL &&
+	    (stmt->log.flags & STMT_LOG_GROUP	||
+	     stmt->log.flags & STMT_LOG_SNAPLEN	||
+	     stmt->log.flags & STMT_LOG_QTHRESHOLD)) {
+		return stmt_error(ctx, stmt,
+				  "level and group are mutually exclusive");
+	}
+	return 0;
+}
+
 static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 {
 #ifdef DEBUG
@@ -1193,7 +1205,6 @@ static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 	switch (stmt->ops->type) {
 	case STMT_COUNTER:
 	case STMT_LIMIT:
-	case STMT_LOG:
 		return 0;
 	case STMT_EXPRESSION:
 		return stmt_evaluate_expr(ctx, stmt);
@@ -1201,6 +1212,8 @@ static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 		return stmt_evaluate_verdict(ctx, stmt);
 	case STMT_META:
 		return stmt_evaluate_meta(ctx, stmt);
+	case STMT_LOG:
+		return stmt_evaluate_log(ctx, stmt);
 	case STMT_REJECT:
 		return stmt_evaluate_reject(ctx, stmt);
 	case STMT_NAT:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 5c6ca80..195d432 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -428,12 +428,30 @@ static void netlink_parse_log(struct netlink_parse_ctx *ctx,
 
 	stmt = log_stmt_alloc(loc);
 	prefix = nft_rule_expr_get_str(nle, NFT_EXPR_LOG_PREFIX);
-	if (prefix != NULL)
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_LOG_PREFIX)) {
 		stmt->log.prefix = xstrdup(prefix);
-	stmt->log.group = nft_rule_expr_get_u16(nle, NFT_EXPR_LOG_GROUP);
-	stmt->log.snaplen = nft_rule_expr_get_u32(nle, NFT_EXPR_LOG_SNAPLEN);
-	stmt->log.qthreshold =
-		nft_rule_expr_get_u16(nle, NFT_EXPR_LOG_QTHRESHOLD);
+		stmt->log.flags |= STMT_LOG_PREFIX;
+	}
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_LOG_GROUP)) {
+		stmt->log.group =
+			nft_rule_expr_get_u16(nle, NFT_EXPR_LOG_GROUP);
+		stmt->log.flags |= STMT_LOG_GROUP;
+	}
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_LOG_SNAPLEN)) {
+		stmt->log.snaplen =
+			nft_rule_expr_get_u32(nle, NFT_EXPR_LOG_SNAPLEN);
+		stmt->log.flags |= STMT_LOG_SNAPLEN;
+	}
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_LOG_QTHRESHOLD)) {
+		stmt->log.qthreshold =
+			nft_rule_expr_get_u16(nle, NFT_EXPR_LOG_QTHRESHOLD);
+		stmt->log.flags |= STMT_LOG_QTHRESHOLD;
+	}
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_LOG_LEVEL)) {
+		stmt->log.level =
+			nft_rule_expr_get_u32(nle, NFT_EXPR_LOG_LEVEL);
+		stmt->log.flags |= STMT_LOG_LEVEL;
+	}
 	list_add_tail(&stmt->list, &ctx->rule->stmts);
 }
 
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 5c1b46d..075e243 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -576,17 +576,17 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
 		nft_rule_expr_set_str(nle, NFT_EXPR_LOG_PREFIX,
 				      stmt->log.prefix);
 	}
-	if (stmt->log.group) {
+	if (stmt->log.flags & STMT_LOG_GROUP) {
 		nft_rule_expr_set_u16(nle, NFT_EXPR_LOG_GROUP,
 				      stmt->log.group);
-	}
-	if (stmt->log.snaplen) {
-		nft_rule_expr_set_u32(nle, NFT_EXPR_LOG_SNAPLEN,
-				      stmt->log.snaplen);
-	}
-	if (stmt->log.qthreshold) {
-		nft_rule_expr_set_u16(nle, NFT_EXPR_LOG_QTHRESHOLD,
-				      stmt->log.qthreshold);
+		if (stmt->log.flags & STMT_LOG_SNAPLEN)
+			nft_rule_expr_set_u32(nle, NFT_EXPR_LOG_SNAPLEN,
+					      stmt->log.snaplen);
+		if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
+			nft_rule_expr_set_u16(nle, NFT_EXPR_LOG_QTHRESHOLD,
+					      stmt->log.qthreshold);
+	} else {
+		nft_rule_expr_set_u32(nle, NFT_EXPR_LOG_LEVEL, stmt->log.level);
 	}
 	nft_rule_add_expr(ctx->nlr, nle);
 }
diff --git a/src/parser.y b/src/parser.y
index 3e08e21..26d2879 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -13,6 +13,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <inttypes.h>
+#include <syslog.h>
 #include <netinet/ip.h>
 #include <netinet/if_ether.h>
 #include <linux/netfilter.h>
@@ -345,6 +346,15 @@ static int monitor_lookup_event(const char *event)
 %token GROUP			"group"
 %token SNAPLEN			"snaplen"
 %token QUEUE_THRESHOLD		"queue-threshold"
+%token LEVEL			"level"
+%token LEVEL_EMERG		"emerg"
+%token LEVEL_ALERT		"alert"
+%token LEVEL_CRIT		"crit"
+%token LEVEL_ERR		"err"
+%token LEVEL_WARN		"warn"
+%token LEVEL_NOTICE		"notice"
+%token LEVEL_INFO		"info"
+%token LEVEL_DEBUG		"debug"
 
 %token LIMIT			"limit"
 %token RATE			"rate"
@@ -416,6 +426,7 @@ static int monitor_lookup_event(const char *event)
 %destructor { stmt_free($$); }	meta_stmt
 %type <stmt>			log_stmt log_stmt_alloc
 %destructor { stmt_free($$); }	log_stmt log_stmt_alloc
+%type <val>			level_type
 %type <stmt>			limit_stmt
 %destructor { stmt_free($$); }	limit_stmt
 %type <val>			time_unit
@@ -1366,18 +1377,61 @@ log_args		:	log_arg
 log_arg			:	PREFIX			string
 			{
 				$<stmt>0->log.prefix	 = $2;
+				$<stmt>0->log.flags 	|= STMT_LOG_PREFIX;
 			}
 			|	GROUP			NUM
 			{
 				$<stmt>0->log.group	 = $2;
+				$<stmt>0->log.flags 	|= STMT_LOG_GROUP;
 			}
 			|	SNAPLEN			NUM
 			{
 				$<stmt>0->log.snaplen	 = $2;
+				$<stmt>0->log.flags 	|= STMT_LOG_SNAPLEN;
 			}
 			|	QUEUE_THRESHOLD		NUM
 			{
 				$<stmt>0->log.qthreshold = $2;
+				$<stmt>0->log.flags 	|= STMT_LOG_QTHRESHOLD;
+			}
+			|	LEVEL			level_type
+			{
+				$<stmt>0->log.level	= $2;
+				$<stmt>0->log.flags 	|= STMT_LOG_LEVEL;
+			}
+			;
+
+level_type		:	LEVEL_EMERG
+			{
+				$$ = LOG_EMERG;
+			}
+			|	LEVEL_ALERT
+			{
+				$$ = LOG_ALERT;
+			}
+			|	LEVEL_CRIT
+			{
+				$$ = LOG_CRIT;
+			}
+			|	LEVEL_ERR
+			{
+				$$ = LOG_ERR;
+			}
+			|	LEVEL_WARN
+			{
+				$$ = LOG_WARNING;
+			}
+			|	LEVEL_NOTICE
+			{
+				$$ = LOG_NOTICE;
+			}
+			|	LEVEL_INFO
+			{
+				$$ = LOG_INFO;
+			}
+			|	LEVEL_DEBUG
+			{
+				$$ = LOG_DEBUG;
 			}
 			;
 
diff --git a/src/scanner.l b/src/scanner.l
index 73a1a3f..4eec92f 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -276,6 +276,15 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "group"			{ return GROUP; }
 "snaplen"		{ return SNAPLEN; }
 "queue-threshold"	{ return QUEUE_THRESHOLD; }
+"level"			{ return LEVEL; }
+"emerg"			{ return LEVEL_EMERG; }
+"alert"			{ return LEVEL_ALERT; }
+"crit"			{ return LEVEL_CRIT; }
+"err"			{ return LEVEL_ERR; }
+"warn"			{ return LEVEL_WARN; }
+"notice"		{ return LEVEL_NOTICE; }
+"info"			{ return LEVEL_INFO; }
+"debug"			{ return LEVEL_DEBUG; }
 
 "queue"			{ return QUEUE;}
 "num"			{ return QUEUENUM;}
diff --git a/src/statement.c b/src/statement.c
index 2dd3f18..4be6625 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -14,6 +14,7 @@
 #include <stdint.h>
 #include <inttypes.h>
 #include <string.h>
+#include <syslog.h>
 
 #include <statement.h>
 #include <utils.h>
@@ -112,17 +113,39 @@ struct stmt *counter_stmt_alloc(const struct location *loc)
 	return stmt_alloc(loc, &counter_stmt_ops);
 }
 
+static const char *syslog_level[LOG_DEBUG + 1] = {
+	[LOG_EMERG]	= "emerg",
+	[LOG_ALERT]	= "alert",
+	[LOG_CRIT]	= "crit",
+	[LOG_ERR]       = "err",
+	[LOG_WARNING]	= "warn",
+	[LOG_NOTICE]	= "notice",
+	[LOG_INFO]	= "info",
+	[LOG_DEBUG]	= "debug",
+};
+
+static const char *log_level(uint32_t level)
+{
+	if (level > LOG_DEBUG)
+		return "unknown";
+
+	return syslog_level[level];
+}
+
 static void log_stmt_print(const struct stmt *stmt)
 {
 	printf("log");
-	if (stmt->log.prefix != NULL)
+	if (stmt->log.flags & STMT_LOG_PREFIX)
 		printf(" prefix \"%s\"", stmt->log.prefix);
-	if (stmt->log.group)
+	if (stmt->log.flags & STMT_LOG_GROUP)
 		printf(" group %u", stmt->log.group);
-	if (stmt->log.snaplen)
+	if (stmt->log.flags & STMT_LOG_SNAPLEN)
 		printf(" snaplen %u", stmt->log.snaplen);
-	if (stmt->log.qthreshold)
+	if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
 		printf(" queue-threshold %u", stmt->log.qthreshold);
+	if ((stmt->log.flags & STMT_LOG_LEVEL) &&
+	    stmt->log.level != LOG_WARNING)
+		printf(" level %s", log_level(stmt->log.level));
 }
 
 static void log_stmt_destroy(struct stmt *stmt)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2014-07-25 16:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-25 16:20 [PATCH nft v2] src: add level option to the log statement 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.