Re: [netfilter-core] [PATCH] netfilter: xt_NFLOG: allow 128 character log prefixes

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

 



[CC trimmed since this is all about Netfilter userspace.]

On 2021-08-01, at 15:14:42 +0100, Jeremy Sowden wrote:
> On 2021-07-30, at 13:27:49 -0500, Kyle Bowman wrote:
> > On Wed, Jul 28, 2021 at 03:43:47AM +0200, Phil Sutter wrote:
> > > You might want to check iptables commit ccf154d7420c0 ("xtables:
> > > Don't use native nftables comments") for reference, it does the
> > > opposite of what you want to do.
> >
> > I went ahead and looked through this commit and also found found the
> > code that initially added this functionality; commit d64ef34a9961
> > ("iptables-compat: use nft built-in comments support ").
> >
> > Additionally I found some other commits that moved code to nft
> > native implementations of the xtables counterpart so that proved
> > helpful.
> >
> > After a couple days of research I did end up figuring out what to do
> > and have added a (mostly complete) native nft log support in
> > iptables-nft. It all seems to work without any kernel changes
> > required. The only problem I'm now faced with is that since we want
> > to take the string passed into the iptables-nft command and add it
> > to the nftnl expression (`NFTNL_EXPR_LOG_PREFIX`) I'm not entirely
> > sure where to get the original sized string from aside from `argv`
> > in the `struct iptables_command_state`. I would get it from the
> > `struct xt_nflog_info`, but that's going to store the truncated
> > version and we would like to be able to store 128 characters of the
> > string as opposed to 64.
> >
> > Any recommendations about how I might do this safely?
>
> The xtables_target struct has a `udata` member which I think would be
> suitable.  libxt_RATEEST does something similar.

Actually, if we embed struct xf_nflog_info in another structure along
with the longer prefix, we can get iptables-nft to print it untruncated.
I've attached a patch.

J.

> > From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
> > From: Kbowman <kbowman@xxxxxxxxxxxxxx>
> > Date: Thu, 29 Jul 2021 15:12:28 -0500
> > Subject: [PATCH] iptables-nft: use nft built-in logging instead of xt_NFLOG
> >
> > Replaces the use of xt_NFLOG with the nft built-in log statement.
> >
> > This additionally adds support for using longer log prefixes of 128
> > characters in size. A caveat to this is that the string will be
> > truncated when the rule is printed via iptables-nft but will remain
> > untruncated in nftables.
> >
> > Some changes have also been made to nft_is_expr_compatible() since
> > xt_NFLOG does not support log level or log flags. With the new
> > changes this means that when a log is used and sets either
> > NFTNL_EXPR_LOG_LEVEL or NFTNL_LOG_FLAGS to a value aside from their
> > default (log level defaults to 4, log flags will not be set) this
> > will produce a compatibility error.
> > ---
> >  iptables/nft-shared.c | 45 +++++++++++++++++++++++++++++++++++++++++++
> >  iptables/nft.c        | 38 ++++++++++++++++++++++++++++++++++++
> >  iptables/nft.h        |  1 +
> >  3 files changed, 84 insertions(+)
>
> One note about formatting: you've used four spaces for indentation,
> but Netfilter uses tabs.
>
> > diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
> > index 4253b081..b5259db0 100644
> > --- a/iptables/nft-shared.c
> > +++ b/iptables/nft-shared.c
> > @@ -22,6 +22,7 @@
> >
> >  #include <linux/netfilter/xt_comment.h>
> >  #include <linux/netfilter/xt_limit.h>
> > +#include <linux/netfilter/xt_NFLOG.h>
> >
> >  #include <libmnl/libmnl.h>
> >  #include <libnftnl/rule.h>
> > @@ -595,6 +596,48 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
> >  		ctx->h->ops->parse_match(match, ctx->cs);
> >  }
> >
> > +static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
> > +{
> > +    __u16 group =  nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP);
> > +    __u16 qthreshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD);
> > +    __u32 snaplen = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN);
> > +    const char *prefix = nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX);
> > +    struct xtables_target *target;
> > +    struct xt_entry_target *t;
> > +    size_t target_size;
> > +
> > +    void *data = ctx->cs;
> > +
> > +    target = xtables_find_target("NFLOG", XTF_TRY_LOAD);
> > +    if (target == NULL)
> > +        return;
> > +
> > +    target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
> > +
> > +    t = xtables_calloc(1, target_size);
> > +    t->u.target_size = target_size;
> > +    strcpy(t->u.user.name, target->name);
> > +    t->u.user.revision = target->revision;
> > +
> > +    target->t = t;
> > +
> > +    struct xt_nflog_info *info = xtables_malloc(sizeof(struct xt_nflog_info));
> > +    info->group = group;
> > +    info->len = snaplen;
> > +    info->threshold = qthreshold;
> > +
> > +    /* Here, because we allow 128 characters in nftables but only 64
> > +     * characters in xtables (in xt_nflog_info specifically), we may
> > +     * end up truncating the string when parsing it.
> > +     */
> > +    strncpy(info->prefix, prefix, sizeof(info->prefix));
> > +    info->prefix[sizeof(info->prefix) - 1] = '\0';
> > +
> > +    memcpy(&target->t->data, info, target->size);
> > +
> > +    ctx->h->ops->parse_target(target, data);
> > +}
> > +
> >  static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
> >  			     struct nftnl_expr *e)
> >  {
> > @@ -644,6 +687,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h,
> >  			nft_parse_limit(&ctx, expr);
> >  		else if (strcmp(name, "lookup") == 0)
> >  			nft_parse_lookup(&ctx, h, expr);
> > +		else if (strcmp(name, "log") == 0)
> > +		    nft_parse_log(&ctx, expr);
> >
> >  		expr = nftnl_expr_iter_next(iter);
> >  	}
> > diff --git a/iptables/nft.c b/iptables/nft.c
> > index f1deb82f..dce8fe0b 100644
> > --- a/iptables/nft.c
> > +++ b/iptables/nft.c
> > @@ -39,6 +39,7 @@
> >  #include <linux/netfilter/nf_tables_compat.h>
> >
> >  #include <linux/netfilter/xt_limit.h>
> > +#include <linux/netfilter/xt_NFLOG.h>
> >
> >  #include <libmnl/libmnl.h>
> >  #include <libnftnl/gen.h>
> > @@ -1340,6 +1341,8 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
> >  		       ret = add_verdict(r, NF_DROP);
> >  	       else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
> >  		       ret = add_verdict(r, NFT_RETURN);
> > +	       else if (strcmp(cs->jumpto, "NFLOG") == 0)
> > +	           ret = add_log(r, cs);
> >  	       else
> >  		       ret = add_target(r, cs->target->t);
> >         } else if (strlen(cs->jumpto) > 0) {
> > @@ -1352,6 +1355,36 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
> >         return ret;
> >  }
> >
> > +int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
> > +{
> > +    struct nftnl_expr *expr;
> > +    struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
> > +
> > +    expr = nftnl_expr_alloc("log");
> > +    if (!expr)
> > +        return -ENOMEM;
> > +
> > +    if (info->prefix != NULL) {
> > +        //char prefix[NF_LOG_PREFIXLEN] = {};
> > +
> > +        // get prefix here from somewhere...
> > +        // maybe in cs->argv?
> > +        nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX, "iff the value at the end is 12 then this string is truncated 123");
> > +    }
> > +    if (info->group) {
> > +        nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_GROUP, info->group);
> > +        if (info->flags & XT_NFLOG_F_COPY_LEN)
> > +            nftnl_expr_set_u32(expr, NFTNL_EXPR_LOG_SNAPLEN,
> > +                               info->len);
> > +        if (info->threshold)
> > +            nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_QTHRESHOLD,
> > +                               info->threshold);
> > +    }
> > +
> > +    nftnl_rule_add_expr(r, expr);
> > +    return 0;
> > +}
> > +
> >  static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
> >  {
> >  #ifdef NLDEBUG
> > @@ -3487,6 +3520,11 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
> >  	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
> >  		return 0;
> >
> > +	if (!strcmp(name, "log") &&
> > +	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LOG_LEVEL) == 4 &&
> > +	    !nftnl_expr_is_set(expr, NFTNL_EXPR_LOG_FLAGS))
> > +	    return 0;
> > +
> >  	return -1;
> >  }
> >
> > diff --git a/iptables/nft.h b/iptables/nft.h
> > index 4ac7e009..28dc81b7 100644
> > --- a/iptables/nft.h
> > +++ b/iptables/nft.h
> > @@ -193,6 +193,7 @@ int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match
> >  int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
> >  int add_jumpto(struct nftnl_rule *r, const char *name, int verdict);
> >  int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set);
> > +int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
> >  char *get_comment(const void *data, uint32_t data_len);
> >
> >  enum nft_rule_print {
> > --
> > 2.32.0
From 3c18555c6356e03731812688d7e6956a04ce820e Mon Sep 17 00:00:00 2001
From: Jeremy Sowden <jeremy@xxxxxxxxxx>
Date: Sun, 1 Aug 2021 14:47:52 +0100
Subject: [PATCH] extensions: libxt_NFLOG: embed struct xt_nflog_info in
 another structure to store longer prefixes suitable for the nft log
 statement.

NFLOG truncates the log-prefix to 64 characters which is the limit
supported by iptables-legacy.  We now store the longer 128-character
prefix in a new structure, struct xt_nflog_state, alongside the struct
xt_nflog_info for use by iptables-nft.

Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx>
---
 extensions/libxt_NFLOG.c | 38 ++++++++++++++++++++++++++++----------
 extensions/libxt_NFLOG.h | 12 ++++++++++++
 iptables/nft-shared.c    | 17 +++++++++++------
 iptables/nft.c           | 10 ++++------
 4 files changed, 55 insertions(+), 22 deletions(-)
 create mode 100644 extensions/libxt_NFLOG.h

diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c
index 02a1b4aa35a3..6e1482122f11 100644
--- a/extensions/libxt_NFLOG.c
+++ b/extensions/libxt_NFLOG.c
@@ -8,6 +8,8 @@
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_NFLOG.h>
 
+#include "libxt_NFLOG.h"
+
 enum {
 	O_GROUP = 0,
 	O_PREFIX,
@@ -53,12 +55,17 @@ static void NFLOG_init(struct xt_entry_target *t)
 
 static void NFLOG_parse(struct xt_option_call *cb)
 {
+	struct xt_nflog_state *state = (struct xt_nflog_state *)cb->data;
+
 	xtables_option_parse(cb);
 	switch (cb->entry->id) {
 	case O_PREFIX:
 		if (strchr(cb->arg, '\n') != NULL)
 			xtables_error(PARAMETER_PROBLEM,
 				   "Newlines not allowed in --log-prefix");
+
+		snprintf(state->nf_log_prefix, sizeof(state->nf_log_prefix),
+			 "%s", cb->arg);
 		break;
 	}
 }
@@ -75,11 +82,26 @@ static void NFLOG_check(struct xt_fcheck_call *cb)
 		info->flags |= XT_NFLOG_F_COPY_LEN;
 }
 
-static void nflog_print(const struct xt_nflog_info *info, char *prefix)
+static void nflog_print(const void *data, size_t target_size,
+			const char *prefix)
 {
+	size_t data_size = target_size - offsetof(struct xt_entry_target, data);
+	const struct xt_nflog_info *info;
+	const char *nf_log_prefix;
+
+	if (data_size == XT_ALIGN(sizeof(struct xt_nflog_state))) {
+		const struct xt_nflog_state *state = data;
+
+		info = &state->info;
+		nf_log_prefix = state->nf_log_prefix;
+	} else {
+		info = data;
+		nf_log_prefix = NULL;
+	}
+
 	if (info->prefix[0] != '\0') {
 		printf(" %snflog-prefix ", prefix);
-		xtables_save_string(info->prefix);
+		xtables_save_string(nf_log_prefix ? : info->prefix);
 	}
 	if (info->group)
 		printf(" %snflog-group %u", prefix, info->group);
@@ -94,16 +116,12 @@ static void nflog_print(const struct xt_nflog_info *info, char *prefix)
 static void NFLOG_print(const void *ip, const struct xt_entry_target *target,
 			int numeric)
 {
-	const struct xt_nflog_info *info = (struct xt_nflog_info *)target->data;
-
-	nflog_print(info, "");
+	nflog_print(target->data, target->u.target_size, "");
 }
 
 static void NFLOG_save(const void *ip, const struct xt_entry_target *target)
 {
-	const struct xt_nflog_info *info = (struct xt_nflog_info *)target->data;
-
-	nflog_print(info, "--");
+	nflog_print(target->data, target->u.target_size, "--");
 }
 
 static void nflog_print_xlate(const struct xt_nflog_info *info,
@@ -139,8 +157,8 @@ static struct xtables_target nflog_target = {
 	.family		= NFPROTO_UNSPEC,
 	.name		= "NFLOG",
 	.version	= XTABLES_VERSION,
-	.size		= XT_ALIGN(sizeof(struct xt_nflog_info)),
-	.userspacesize	= XT_ALIGN(sizeof(struct xt_nflog_info)),
+	.size		= XT_ALIGN(sizeof(struct xt_nflog_state)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_nflog_state)),
 	.help		= NFLOG_help,
 	.init		= NFLOG_init,
 	.x6_fcheck	= NFLOG_check,
diff --git a/extensions/libxt_NFLOG.h b/extensions/libxt_NFLOG.h
new file mode 100644
index 000000000000..f3599a77ef2e
--- /dev/null
+++ b/extensions/libxt_NFLOG.h
@@ -0,0 +1,12 @@
+#ifndef LIBXT_NFLOG_H_INCLUDED
+#define LIBXT_NFLOG_H_INCLUDED
+
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/xt_NFLOG.h>
+
+struct xt_nflog_state {
+	struct xt_nflog_info info;
+	char nf_log_prefix[NF_LOG_PREFIXLEN];
+};
+
+#endif /* !defined(LIBXT_NFLOG_H_INCLUDED) */
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index b5259db07723..0a9c4de034be 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -32,6 +32,7 @@
 #include "nft-bridge.h"
 #include "xshared.h"
 #include "nft.h"
+#include "extensions/libxt_NFLOG.h"
 
 extern struct nft_family_ops nft_family_ops_ipv4;
 extern struct nft_family_ops nft_family_ops_ipv6;
@@ -621,19 +622,23 @@ static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
 
     target->t = t;
 
-    struct xt_nflog_info *info = xtables_malloc(sizeof(struct xt_nflog_info));
+    struct xt_nflog_state state = { 0 };
+
+    struct xt_nflog_info *info = &state.info;
     info->group = group;
     info->len = snaplen;
     info->threshold = qthreshold;
 
     /* Here, because we allow 128 characters in nftables but only 64
-     * characters in xtables (in xt_nflog_info specifically), we may
-     * end up truncating the string when parsing it.
+     * characters in xtables (in xt_nflog_info specifically), we may end up
+     * truncating the string when parsing it.  The longer prefix will be
+     * available in state.nf_log_prefix.
      */
-    strncpy(info->prefix, prefix, sizeof(info->prefix));
-    info->prefix[sizeof(info->prefix) - 1] = '\0';
+    snprintf(info->prefix, sizeof(info->prefix), "%s", prefix);
+
+    snprintf(state.nf_log_prefix, sizeof(state.nf_log_prefix), "%s", prefix);
 
-    memcpy(&target->t->data, info, target->size);
+    memcpy(&target->t->data, &state, sizeof(state));
 
     ctx->h->ops->parse_target(target, data);
 }
diff --git a/iptables/nft.c b/iptables/nft.c
index dce8fe0b4a18..addcfffdd0cc 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -59,6 +59,7 @@
 #include "nft-cache.h"
 #include "nft-shared.h"
 #include "nft-bridge.h" /* EBT_NOPROTO */
+#include "extensions/libxt_NFLOG.h"
 
 static void *nft_fn;
 
@@ -1358,18 +1359,15 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
 int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
 {
     struct nftnl_expr *expr;
-    struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
+    struct xt_nflog_state *state = (struct xt_nflog_state *)cs->target->t->data;
+    struct xt_nflog_info *info = &state->info;
 
     expr = nftnl_expr_alloc("log");
     if (!expr)
         return -ENOMEM;
 
     if (info->prefix != NULL) {
-        //char prefix[NF_LOG_PREFIXLEN] = {};
-
-        // get prefix here from somewhere...
-        // maybe in cs->argv?
-        nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX, "iff the value at the end is 12 then this string is truncated 123");
+        nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX, state->nf_log_prefix);
     }
     if (info->group) {
         nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_GROUP, info->group);
-- 
2.30.2

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux