[PATCH nft] src: add level option to the log statement

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch is required if you use upcoming Linux kernels >= 3.17
which comes 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@xxxxxxxxxxxxx>
---
 include/statement.h       |   10 ++++++++++
 src/evaluate.c            |   15 ++++++++++++++-
 src/netlink_delinearize.c |   28 +++++++++++++++++++++++-----
 src/netlink_linearize.c   |   18 +++++++++---------
 src/parser.y              |   32 ++++++++++++++++++++++++++++++++
 src/scanner.l             |    1 +
 src/statement.c           |   31 +++++++++++++++++++++++++++----
 7 files changed, 116 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..50c35ae 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,7 @@ static int monitor_lookup_event(const char *event)
 %token GROUP			"group"
 %token SNAPLEN			"snaplen"
 %token QUEUE_THRESHOLD		"queue-threshold"
+%token LEVEL			"level"
 
 %token LIMIT			"limit"
 %token RATE			"rate"
@@ -1366,18 +1368,48 @@ 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		STRING
+			{
+				if (strcmp($2, "emerg") == 0) {
+					$<stmt>0->log.level = LOG_EMERG;
+				} else if (strcmp($2, "alert") == 0) {
+					$<stmt>0->log.level = LOG_ALERT;
+				} else if (strcmp($2, "crit") == 0) {
+					$<stmt>0->log.level = LOG_CRIT;
+				} else if (strcmp($2, "err") == 0) {
+					$<stmt>0->log.level = LOG_ERR;
+				} else if (strcmp($2, "warn") == 0) {
+					$<stmt>0->log.level = LOG_WARNING;
+				} else if (strcmp($2, "notice") == 0) {
+					$<stmt>0->log.level = LOG_NOTICE;
+				} else if (strcmp($2, "info") == 0) {
+					$<stmt>0->log.level = LOG_INFO;
+				} else if (strcmp($2, "debug") == 0) {
+					$<stmt>0->log.level = LOG_DEBUG;
+				} else {
+					erec_queue(error(&@2,
+							 "invalid syslog level %s",
+							 $2), state->msgs);
+					YYERROR;
+				}
+				$<stmt>0->log.flags |= STMT_LOG_LEVEL;
 			}
 			;
 
diff --git a/src/scanner.l b/src/scanner.l
index 73a1a3f..b0eecd3 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -276,6 +276,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "group"			{ return GROUP; }
 "snaplen"		{ return SNAPLEN; }
 "queue-threshold"	{ return QUEUE_THRESHOLD; }
+"level"			{ return LEVEL; }
 
 "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

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux