]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add level option to the log statement
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 23 Jun 2014 00:49:38 +0000 (02:49 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 25 Jul 2014 16:18:40 +0000 (18:18 +0200)
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>
include/statement.h
src/evaluate.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser.y
src/scanner.l
src/statement.c

index 480b7190d536066dc2a7fbb38b8205d498c7b0fb..12336bc09b36ab68999508eef8c81e3fd3cfeb5c 100644 (file)
@@ -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);
index e05473a982092d0403f3c2f1049f6e530b4187b7..f66a8ea329910e3da8f560da266e182c04fd6168 100644 (file)
@@ -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:
index 5c6ca8008e45783790028d064ec0fde9978b5f9f..195d43291a45c1e3179d217460fbbe50f03618b4 100644 (file)
@@ -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);
 }
 
index 5c1b46dd19f89b47f09db1341ffa372b55af5e0d..075e24360dcb07d76df81a00f8e22cceeaa6a6e0 100644 (file)
@@ -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);
 }
index 3e08e21ea1fcad547430b44327b3124861cd2472..26d28793bd7681d446f1c05e8fdc8d3d6a6050da 100644 (file)
@@ -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;
                        }
                        ;
 
index 73a1a3f1f16beccf1ca89fed84f10ad80d264dba..4eec92f5f7db10e09b76503cf501db9bd30d6011 100644 (file)
@@ -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;}
index 2dd3f1873c21dde0ca7e02ba1e61655c2555338f..4be6625165027921e04c31c95b834fa4dc9c9c88 100644 (file)
@@ -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)