diff mbox

[netfilter:,nft] add connmark module

Message ID 1389011352-11449-1-git-send-email-kristian.evensen@gmail.com
State Changes Requested
Headers show

Commit Message

Kristian Evensen Jan. 6, 2014, 12:29 p.m. UTC
From: Kristian Evensen <kristian.evensen@gmail.com>

This patch adds a connmark module to nftables, which enables setting, storing
and restoring the connection mark (ctmark) of a tracked connection. It works in
the same way as xt_CONNMARK.

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
---
 include/uapi/linux/netfilter/nf_tables.h |  35 +++++++
 net/netfilter/Kconfig                    |  10 ++
 net/netfilter/Makefile                   |   1 +
 net/netfilter/nft_connmark.c             | 169 +++++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+)
 create mode 100644 net/netfilter/nft_connmark.c

Comments

Pablo Neira Ayuso Jan. 6, 2014, 12:42 p.m. UTC | #1
Hi,

On Mon, Jan 06, 2014 at 01:29:12PM +0100, Kristian Evensen wrote:
> From: Kristian Evensen <kristian.evensen@gmail.com>
> 
> This patch adds a connmark module to nftables, which enables setting, storing
> and restoring the connection mark (ctmark) of a tracked connection. It works in
> the same way as xt_CONNMARK.
> 
> Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
> ---
>  include/uapi/linux/netfilter/nf_tables.h |  35 +++++++
>  net/netfilter/Kconfig                    |  10 ++
>  net/netfilter/Makefile                   |   1 +
>  net/netfilter/nft_connmark.c             | 169 +++++++++++++++++++++++++++++++
>  4 files changed, 215 insertions(+)
>  create mode 100644 net/netfilter/nft_connmark.c
> 
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index aa86a152..ccf9f9f 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -682,6 +682,41 @@ enum nft_queue_attributes {
>  #define NFT_QUEUE_FLAG_MASK		0x03
>  
>  /**
> + * enum nft_connmark_types - nf_tables connmark expression types
> + *
> + * @NFT_CONNMARK_SAVE: save connmark
> + * @NFT_CONNMARK_RESTORE: restore connmark
> + * @NFT_CONNMARK_SET: set connmark (iptables set-xmark)
> + */
> +enum nft_connmark_types {
> +	NFT_CONNMARK_SAVE,
> +	NFT_CONNMARK_RESTORE,
> +	NFT_CONNMARK_SET
> +};
> +
> +/**
> + * enum nft_connmark_attributes - nf_tables connmark expression netlink
> + * attributes
> + *
> + * @NFTA_CONNMARK_MODE: conntrack action (save, set or restore) (NLA_U8)
> + * @NFTA_CONNMARK_CTMARK: conntrack ctmark (NLA_U32)
> + * @NFTA_CONNMARK_CTMASK: conntrack ctmask (NLA_U32)
> + * @NFTA_CONNMARK_NFMASK: conntrack nfmask (NLA_U32)
> + */
> +
> +enum nft_connmark_attributes {
> +	NFTA_CONNMARK_UNSPEC,
> +	NFTA_CONNMARK_MODE,
> +	NFTA_CONNMARK_CTMARK,
> +	NFTA_CONNMARK_CTMASK,
> +	NFTA_CONNMARK_NFMASK,
> +	__NFTA_CONNMARK_MAX,
> +};
> +#define NFTA_CONNMARK_MAX		(__NFTA_CONNMARK_MAX - 1)
> +
> +#define NFT_CONNMARK_DEFAULT_MASK	0xFFFFFFFF
> +
> +/**
>   * enum nft_reject_types - nf_tables reject expression reject types
>   *
>   * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index 0609514..d3ff630 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -471,6 +471,16 @@ config NFT_COUNTER
>  	  This option adds the "counter" expression that you can use to
>  	  include packet and byte counters in a rule.
>  
> +config NFT_CONNMARK
> +	depends on NF_TABLES
> +	depends on NF_CONNTRACK
> +	depends on NETFILTER_ADVANCED
> +	select NF_CONNTRACK_MARK
> +	tristate "Netfilter nf_tables conntrack module"
> +	help
> +		This option adds the "connmark" expression that can be used to
> +		set, save or restore a mark on a tracked connection.
> +
>  config NFT_LOG
>  	depends on NF_TABLES
>  	tristate "Netfilter nf_tables log module"
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index 39e4a7b..5097a2f 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -71,6 +71,7 @@ nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
>  
>  obj-$(CONFIG_NF_TABLES)		+= nf_tables.o
>  obj-$(CONFIG_NFT_COMPAT)	+= nft_compat.o
> +obj-$(CONFIG_NFT_CONNMARK)	+= nft_connmark.o
>  obj-$(CONFIG_NFT_EXTHDR)	+= nft_exthdr.o
>  obj-$(CONFIG_NFT_META)		+= nft_meta.o
>  obj-$(CONFIG_NFT_CT)		+= nft_ct.o
> diff --git a/net/netfilter/nft_connmark.c b/net/netfilter/nft_connmark.c
> new file mode 100644
> index 0000000..04d56d1
> --- /dev/null
> +++ b/net/netfilter/nft_connmark.c
> @@ -0,0 +1,169 @@
> +/* Copyright (c) 2013 Kristian Evensen <kristian.evensen@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/netlink.h>
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_conntrack.h>
> +#include <net/netfilter/nf_conntrack_ecache.h>
> +
> +struct nft_connmark {
> +	u32 ctmask;
> +	union{
> +		u32 ctmark;
> +		u32 nfmask;
> +	};
> +	u8  mode;
> +};
> +
> +static void nft_connmark_eval(const struct nft_expr *expr,
> +			   struct nft_data data[NFT_REG_MAX + 1],
> +			   const struct nft_pktinfo *pkt)
> +{
> +	struct nft_connmark *priv = nft_expr_priv(expr);
> +	enum ip_conntrack_info ctinfo;
> +	struct nf_conn *ct;
> +	u_int32_t newmark;
> +
> +	ct = nf_ct_get(pkt->skb, &ctinfo);
> +	if (ct == NULL)
> +		return;
> +
> +	switch (priv->mode) {
> +	case NFT_CONNMARK_SET:
> +		newmark = (ct->mark & ~priv->ctmask) ^ priv->ctmark;
> +		if (ct->mark != newmark) {
> +			ct->mark = newmark;
> +			nf_conntrack_event_cache(IPCT_MARK, ct);
> +		}
> +		break;
> +	case NFT_CONNMARK_SAVE:
> +		newmark = (ct->mark & ~priv->ctmask) ^
> +			  (pkt->skb->mark & priv->nfmask);
> +
> +		if (ct->mark != newmark) {
> +			ct->mark = newmark;
> +			nf_conntrack_event_cache(IPCT_MARK, ct);
> +		}
> +		break;
> +	case NFT_CONNMARK_RESTORE:
> +		newmark = (pkt->skb->mark & ~priv->nfmask) ^
> +			  (ct->mark & priv->ctmask);
> +		pkt->skb->mark = newmark;

We already have expressions for bitmask operations and to fetch the
packet mark into a register. These operations can be implemented in
the existing meta expressions as NFT_META_CONNMARK.

Note that we now have two meta flavours:

http://git.kernel.org/cgit/linux/kernel/git/pablo/nftables.git/commit/net/netfilter/nft_meta.c?id=e035b77ac7be430a5fef8c9c23f60b6b50ec81c5

So the idea is to make a patch that allows us to retrieve and to set
the connmark value.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kristian Evensen Jan. 6, 2014, 12:46 p.m. UTC | #2
Hi,

Thanks. I noticed the addition of the get/set operation while working
on the patch and was unsure about how to deal with setting the
connmark, but I decided to add it for completeness sake. Perhaps a
better idea would be to remove set from the module and only keep
save/restore? It would simplify the code as well.

-Kristian

On Mon, Jan 6, 2014 at 1:42 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> Hi,
>
> On Mon, Jan 06, 2014 at 01:29:12PM +0100, Kristian Evensen wrote:
>> From: Kristian Evensen <kristian.evensen@gmail.com>
>>
>> This patch adds a connmark module to nftables, which enables setting, storing
>> and restoring the connection mark (ctmark) of a tracked connection. It works in
>> the same way as xt_CONNMARK.
>>
>> Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
>> ---
>>  include/uapi/linux/netfilter/nf_tables.h |  35 +++++++
>>  net/netfilter/Kconfig                    |  10 ++
>>  net/netfilter/Makefile                   |   1 +
>>  net/netfilter/nft_connmark.c             | 169 +++++++++++++++++++++++++++++++
>>  4 files changed, 215 insertions(+)
>>  create mode 100644 net/netfilter/nft_connmark.c
>>
>> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
>> index aa86a152..ccf9f9f 100644
>> --- a/include/uapi/linux/netfilter/nf_tables.h
>> +++ b/include/uapi/linux/netfilter/nf_tables.h
>> @@ -682,6 +682,41 @@ enum nft_queue_attributes {
>>  #define NFT_QUEUE_FLAG_MASK          0x03
>>
>>  /**
>> + * enum nft_connmark_types - nf_tables connmark expression types
>> + *
>> + * @NFT_CONNMARK_SAVE: save connmark
>> + * @NFT_CONNMARK_RESTORE: restore connmark
>> + * @NFT_CONNMARK_SET: set connmark (iptables set-xmark)
>> + */
>> +enum nft_connmark_types {
>> +     NFT_CONNMARK_SAVE,
>> +     NFT_CONNMARK_RESTORE,
>> +     NFT_CONNMARK_SET
>> +};
>> +
>> +/**
>> + * enum nft_connmark_attributes - nf_tables connmark expression netlink
>> + * attributes
>> + *
>> + * @NFTA_CONNMARK_MODE: conntrack action (save, set or restore) (NLA_U8)
>> + * @NFTA_CONNMARK_CTMARK: conntrack ctmark (NLA_U32)
>> + * @NFTA_CONNMARK_CTMASK: conntrack ctmask (NLA_U32)
>> + * @NFTA_CONNMARK_NFMASK: conntrack nfmask (NLA_U32)
>> + */
>> +
>> +enum nft_connmark_attributes {
>> +     NFTA_CONNMARK_UNSPEC,
>> +     NFTA_CONNMARK_MODE,
>> +     NFTA_CONNMARK_CTMARK,
>> +     NFTA_CONNMARK_CTMASK,
>> +     NFTA_CONNMARK_NFMASK,
>> +     __NFTA_CONNMARK_MAX,
>> +};
>> +#define NFTA_CONNMARK_MAX            (__NFTA_CONNMARK_MAX - 1)
>> +
>> +#define NFT_CONNMARK_DEFAULT_MASK    0xFFFFFFFF
>> +
>> +/**
>>   * enum nft_reject_types - nf_tables reject expression reject types
>>   *
>>   * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
>> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
>> index 0609514..d3ff630 100644
>> --- a/net/netfilter/Kconfig
>> +++ b/net/netfilter/Kconfig
>> @@ -471,6 +471,16 @@ config NFT_COUNTER
>>         This option adds the "counter" expression that you can use to
>>         include packet and byte counters in a rule.
>>
>> +config NFT_CONNMARK
>> +     depends on NF_TABLES
>> +     depends on NF_CONNTRACK
>> +     depends on NETFILTER_ADVANCED
>> +     select NF_CONNTRACK_MARK
>> +     tristate "Netfilter nf_tables conntrack module"
>> +     help
>> +             This option adds the "connmark" expression that can be used to
>> +             set, save or restore a mark on a tracked connection.
>> +
>>  config NFT_LOG
>>       depends on NF_TABLES
>>       tristate "Netfilter nf_tables log module"
>> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
>> index 39e4a7b..5097a2f 100644
>> --- a/net/netfilter/Makefile
>> +++ b/net/netfilter/Makefile
>> @@ -71,6 +71,7 @@ nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
>>
>>  obj-$(CONFIG_NF_TABLES)              += nf_tables.o
>>  obj-$(CONFIG_NFT_COMPAT)     += nft_compat.o
>> +obj-$(CONFIG_NFT_CONNMARK)   += nft_connmark.o
>>  obj-$(CONFIG_NFT_EXTHDR)     += nft_exthdr.o
>>  obj-$(CONFIG_NFT_META)               += nft_meta.o
>>  obj-$(CONFIG_NFT_CT)         += nft_ct.o
>> diff --git a/net/netfilter/nft_connmark.c b/net/netfilter/nft_connmark.c
>> new file mode 100644
>> index 0000000..04d56d1
>> --- /dev/null
>> +++ b/net/netfilter/nft_connmark.c
>> @@ -0,0 +1,169 @@
>> +/* Copyright (c) 2013 Kristian Evensen <kristian.evensen@gmail.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/module.h>
>> +#include <linux/netlink.h>
>> +#include <linux/netfilter.h>
>> +#include <linux/netfilter/nf_tables.h>
>> +#include <net/netfilter/nf_tables.h>
>> +#include <net/netfilter/nf_conntrack.h>
>> +#include <net/netfilter/nf_conntrack_ecache.h>
>> +
>> +struct nft_connmark {
>> +     u32 ctmask;
>> +     union{
>> +             u32 ctmark;
>> +             u32 nfmask;
>> +     };
>> +     u8  mode;
>> +};
>> +
>> +static void nft_connmark_eval(const struct nft_expr *expr,
>> +                        struct nft_data data[NFT_REG_MAX + 1],
>> +                        const struct nft_pktinfo *pkt)
>> +{
>> +     struct nft_connmark *priv = nft_expr_priv(expr);
>> +     enum ip_conntrack_info ctinfo;
>> +     struct nf_conn *ct;
>> +     u_int32_t newmark;
>> +
>> +     ct = nf_ct_get(pkt->skb, &ctinfo);
>> +     if (ct == NULL)
>> +             return;
>> +
>> +     switch (priv->mode) {
>> +     case NFT_CONNMARK_SET:
>> +             newmark = (ct->mark & ~priv->ctmask) ^ priv->ctmark;
>> +             if (ct->mark != newmark) {
>> +                     ct->mark = newmark;
>> +                     nf_conntrack_event_cache(IPCT_MARK, ct);
>> +             }
>> +             break;
>> +     case NFT_CONNMARK_SAVE:
>> +             newmark = (ct->mark & ~priv->ctmask) ^
>> +                       (pkt->skb->mark & priv->nfmask);
>> +
>> +             if (ct->mark != newmark) {
>> +                     ct->mark = newmark;
>> +                     nf_conntrack_event_cache(IPCT_MARK, ct);
>> +             }
>> +             break;
>> +     case NFT_CONNMARK_RESTORE:
>> +             newmark = (pkt->skb->mark & ~priv->nfmask) ^
>> +                       (ct->mark & priv->ctmask);
>> +             pkt->skb->mark = newmark;
>
> We already have expressions for bitmask operations and to fetch the
> packet mark into a register. These operations can be implemented in
> the existing meta expressions as NFT_META_CONNMARK.
>
> Note that we now have two meta flavours:
>
> http://git.kernel.org/cgit/linux/kernel/git/pablo/nftables.git/commit/net/netfilter/nft_meta.c?id=e035b77ac7be430a5fef8c9c23f60b6b50ec81c5
>
> So the idea is to make a patch that allows us to retrieve and to set
> the connmark value.
>
> Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira Ayuso Jan. 6, 2014, 12:49 p.m. UTC | #3
On Mon, Jan 06, 2014 at 01:46:08PM +0100, Kristian Evensen wrote:
> Hi,
> 
> Thanks. I noticed the addition of the get/set operation while working
> on the patch and was unsure about how to deal with setting the
> connmark, but I decided to add it for completeness sake. Perhaps a
> better idea would be to remove set from the module and only keep
> save/restore? It would simplify the code as well.

I think one single NFT_META_CONNMARK with the get/set variants should
be enough to implement the save, restore and set operations that
xt_connmark provides.

* restore:
        reg1 = get(NFT_META_CONNMARK)
        set(NFT_META_MARK, reg1)

* save:
        reg1 = get(NFT_META_MARK)
        set(NFT_META_CONNMARK, reg1)

* set:
        reg1 = immediate(value)
        set(NFT_META_CONNMARK, reg1)
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kristian Evensen Jan. 6, 2014, 1:02 p.m. UTC | #4
Yes, that sounds like a better solution. I will get started on adding
this functionality. One question though, how should we deal with the
masks? Based on my limited understanding, it is only possible to store
one value per meta key.

Also, what would be the preferred syntax? When looking at the existing
meta set/get, I suggest something like the following:

... meta connmark set X
... meta connmark-restore
... meta connmark-save.

-Kristian

On Mon, Jan 6, 2014 at 1:49 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Mon, Jan 06, 2014 at 01:46:08PM +0100, Kristian Evensen wrote:
>> Hi,
>>
>> Thanks. I noticed the addition of the get/set operation while working
>> on the patch and was unsure about how to deal with setting the
>> connmark, but I decided to add it for completeness sake. Perhaps a
>> better idea would be to remove set from the module and only keep
>> save/restore? It would simplify the code as well.
>
> I think one single NFT_META_CONNMARK with the get/set variants should
> be enough to implement the save, restore and set operations that
> xt_connmark provides.
>
> * restore:
>         reg1 = get(NFT_META_CONNMARK)
>         set(NFT_META_MARK, reg1)
>
> * save:
>         reg1 = get(NFT_META_MARK)
>         set(NFT_META_CONNMARK, reg1)
>
> * set:
>         reg1 = immediate(value)
>         set(NFT_META_CONNMARK, reg1)
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira Ayuso Jan. 6, 2014, 1:09 p.m. UTC | #5
On Mon, Jan 06, 2014 at 02:02:55PM +0100, Kristian Evensen wrote:
> Yes, that sounds like a better solution. I will get started on adding
> this functionality. One question though, how should we deal with the
> masks? Based on my limited understanding, it is only possible to store
> one value per meta key.

Please, check the bitwise expression (net/netfilter/nft_bitwise.c), it
provides an instruction to perform bitwise operations.

> Also, what would be the preferred syntax? When looking at the existing
> meta set/get, I suggest something like the following:
> 
> ... meta connmark set X
> ... meta connmark-restore
> ... meta connmark-save.

Unless someone else come with a better syntax proposal, that's fine
with me.

P.S: Please, don't top post:
http://www.netfilter.org/mailinglists.html#list-rules
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kristian Evensen Jan. 6, 2014, 1:11 p.m. UTC | #6
On Mon, Jan 6, 2014 at 2:09 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> Please, check the bitwise expression (net/netfilter/nft_bitwise.c), it
> provides an instruction to perform bitwise operations.

Great, thanks for me letting me know.

> P.S: Please, don't top post:
> http://www.netfilter.org/mailinglists.html#list-rules

Sorry about that :)

-Kristian
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kristian Evensen Jan. 6, 2014, 3:19 p.m. UTC | #7
Hello again,

On Mon, Jan 6, 2014 at 1:49 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> I think one single NFT_META_CONNMARK with the get/set variants should
> be enough to implement the save, restore and set operations that
> xt_connmark provides.
>
> * restore:
>         reg1 = get(NFT_META_CONNMARK)
>         set(NFT_META_MARK, reg1)
>
> * save:
>         reg1 = get(NFT_META_MARK)
>         set(NFT_META_CONNMARK, reg1)
>
> * set:
>         reg1 = immediate(value)
>         set(NFT_META_CONNMARK, reg1)

I have spent some time trying to figure out how to implement this
(with only one NFT_META_CONNMARK), but I can't quite figure it out.
Implementing get and set of ctmark is straight forward and already
working, but restore and save are causing me some problems. They are
both set statements, but the current grammar requires a set statement
to contain an expression. We can use the already existing bitwise
operators instead of the mask provided as an argument to xt_CONNMARK,
so neither save nor restore needs an argument.

I was wondering if you could share your thoughts when you wrote the
pseudo-code? Would an OK solution be to for example add two more
meta_keys and hard-code something like the following statements:
META CONNMARK_SAVE
{
meta_stmt_alloc(&@$, $2, 0);
}
META CONNMARK_RESTORE
{
meta_stmt_alloc(&@$, $2, 0);
}?

-Kristian
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kristian Evensen Jan. 6, 2014, 4:05 p.m. UTC | #8
Hello again,

On Mon, Jan 6, 2014 at 4:19 PM, Kristian Evensen
<kristian.evensen@gmail.com> wrote:
> Hello again,
>
> On Mon, Jan 6, 2014 at 1:49 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>>
>> I think one single NFT_META_CONNMARK with the get/set variants should
>> be enough to implement the save, restore and set operations that
>> xt_connmark provides.
>>
>> * restore:
>>         reg1 = get(NFT_META_CONNMARK)
>>         set(NFT_META_MARK, reg1)
>>
>> * save:
>>         reg1 = get(NFT_META_MARK)
>>         set(NFT_META_CONNMARK, reg1)
>>
>> * set:
>>         reg1 = immediate(value)
>>         set(NFT_META_CONNMARK, reg1)

Please ignore my previous email. As often happens, the answer popped
up right after I clicked on send. I did not think properly through how
variables work and are used in nftables, and see now that the
functionality of restore/save can be implemented using only the
get/set operations.

Thank you very much for the help, the patch is coming soon.

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

Patch

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index aa86a152..ccf9f9f 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -682,6 +682,41 @@  enum nft_queue_attributes {
 #define NFT_QUEUE_FLAG_MASK		0x03
 
 /**
+ * enum nft_connmark_types - nf_tables connmark expression types
+ *
+ * @NFT_CONNMARK_SAVE: save connmark
+ * @NFT_CONNMARK_RESTORE: restore connmark
+ * @NFT_CONNMARK_SET: set connmark (iptables set-xmark)
+ */
+enum nft_connmark_types {
+	NFT_CONNMARK_SAVE,
+	NFT_CONNMARK_RESTORE,
+	NFT_CONNMARK_SET
+};
+
+/**
+ * enum nft_connmark_attributes - nf_tables connmark expression netlink
+ * attributes
+ *
+ * @NFTA_CONNMARK_MODE: conntrack action (save, set or restore) (NLA_U8)
+ * @NFTA_CONNMARK_CTMARK: conntrack ctmark (NLA_U32)
+ * @NFTA_CONNMARK_CTMASK: conntrack ctmask (NLA_U32)
+ * @NFTA_CONNMARK_NFMASK: conntrack nfmask (NLA_U32)
+ */
+
+enum nft_connmark_attributes {
+	NFTA_CONNMARK_UNSPEC,
+	NFTA_CONNMARK_MODE,
+	NFTA_CONNMARK_CTMARK,
+	NFTA_CONNMARK_CTMASK,
+	NFTA_CONNMARK_NFMASK,
+	__NFTA_CONNMARK_MAX,
+};
+#define NFTA_CONNMARK_MAX		(__NFTA_CONNMARK_MAX - 1)
+
+#define NFT_CONNMARK_DEFAULT_MASK	0xFFFFFFFF
+
+/**
  * enum nft_reject_types - nf_tables reject expression reject types
  *
  * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 0609514..d3ff630 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -471,6 +471,16 @@  config NFT_COUNTER
 	  This option adds the "counter" expression that you can use to
 	  include packet and byte counters in a rule.
 
+config NFT_CONNMARK
+	depends on NF_TABLES
+	depends on NF_CONNTRACK
+	depends on NETFILTER_ADVANCED
+	select NF_CONNTRACK_MARK
+	tristate "Netfilter nf_tables conntrack module"
+	help
+		This option adds the "connmark" expression that can be used to
+		set, save or restore a mark on a tracked connection.
+
 config NFT_LOG
 	depends on NF_TABLES
 	tristate "Netfilter nf_tables log module"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 39e4a7b..5097a2f 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -71,6 +71,7 @@  nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
 
 obj-$(CONFIG_NF_TABLES)		+= nf_tables.o
 obj-$(CONFIG_NFT_COMPAT)	+= nft_compat.o
+obj-$(CONFIG_NFT_CONNMARK)	+= nft_connmark.o
 obj-$(CONFIG_NFT_EXTHDR)	+= nft_exthdr.o
 obj-$(CONFIG_NFT_META)		+= nft_meta.o
 obj-$(CONFIG_NFT_CT)		+= nft_ct.o
diff --git a/net/netfilter/nft_connmark.c b/net/netfilter/nft_connmark.c
new file mode 100644
index 0000000..04d56d1
--- /dev/null
+++ b/net/netfilter/nft_connmark.c
@@ -0,0 +1,169 @@ 
+/* Copyright (c) 2013 Kristian Evensen <kristian.evensen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+
+struct nft_connmark {
+	u32 ctmask;
+	union{
+		u32 ctmark;
+		u32 nfmask;
+	};
+	u8  mode;
+};
+
+static void nft_connmark_eval(const struct nft_expr *expr,
+			   struct nft_data data[NFT_REG_MAX + 1],
+			   const struct nft_pktinfo *pkt)
+{
+	struct nft_connmark *priv = nft_expr_priv(expr);
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct;
+	u_int32_t newmark;
+
+	ct = nf_ct_get(pkt->skb, &ctinfo);
+	if (ct == NULL)
+		return;
+
+	switch (priv->mode) {
+	case NFT_CONNMARK_SET:
+		newmark = (ct->mark & ~priv->ctmask) ^ priv->ctmark;
+		if (ct->mark != newmark) {
+			ct->mark = newmark;
+			nf_conntrack_event_cache(IPCT_MARK, ct);
+		}
+		break;
+	case NFT_CONNMARK_SAVE:
+		newmark = (ct->mark & ~priv->ctmask) ^
+			  (pkt->skb->mark & priv->nfmask);
+
+		if (ct->mark != newmark) {
+			ct->mark = newmark;
+			nf_conntrack_event_cache(IPCT_MARK, ct);
+		}
+		break;
+	case NFT_CONNMARK_RESTORE:
+		newmark = (pkt->skb->mark & ~priv->nfmask) ^
+			  (ct->mark & priv->ctmask);
+		pkt->skb->mark = newmark;
+		break;
+	}
+}
+
+static const struct nla_policy nft_connmark_policy[NFTA_CONNMARK_MAX + 1] = {
+	[NFTA_CONNMARK_MODE]	= { .type = NLA_U8 },
+	[NFTA_CONNMARK_CTMARK]	= { .type = NLA_U32 },
+	[NFTA_CONNMARK_CTMASK]	= { .type = NLA_U32 },
+	[NFTA_CONNMARK_NFMASK]  = { .type = NLA_U32 },
+};
+
+static int nft_connmark_init(const struct nft_ctx *ctx,
+			   const struct nft_expr *expr,
+			   const struct nlattr * const tb[])
+{
+	struct nft_connmark *priv = nft_expr_priv(expr);
+
+	if (tb[NFTA_CONNMARK_MODE] == NULL || tb[NFTA_CONNMARK_CTMASK] == NULL)
+		return -EINVAL;
+
+	priv->mode = nla_get_u8(tb[NFTA_CONNMARK_MODE]);
+	priv->ctmask = ntohl(nla_get_be32(tb[NFTA_CONNMARK_CTMASK]));
+
+	switch (priv->mode) {
+	case NFT_CONNMARK_SAVE:
+	case NFT_CONNMARK_RESTORE:
+		if (tb[NFTA_CONNMARK_NFMASK] == NULL)
+			return -EINVAL;
+
+		priv->nfmask = ntohl(nla_get_be32(tb[NFTA_CONNMARK_NFMASK]));
+
+		if (priv->mode == NFT_CONNMARK_RESTORE &&
+		    priv->ctmask != priv->nfmask)
+			return -EINVAL;
+		break;
+	case NFT_CONNMARK_SET:
+		if (tb[NFTA_CONNMARK_CTMARK] == NULL)
+			return -EINVAL;
+
+		priv->ctmark = ntohl(nla_get_be32(tb[NFTA_CONNMARK_CTMARK]));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nft_connmark_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+	const struct nft_connmark *priv = nft_expr_priv(expr);
+
+	if (nla_put_u8(skb, NFTA_CONNMARK_MODE, priv->mode) ||
+	    nla_put_be32(skb, NFTA_CONNMARK_CTMASK, htonl(priv->ctmask)))
+		goto nla_put_failure;
+
+	switch (priv->mode) {
+	case NFT_CONNMARK_SAVE:
+	case NFT_CONNMARK_RESTORE:
+		if (nla_put_be32(skb, NFTA_CONNMARK_NFMASK,
+				 htonl(priv->nfmask)))
+			goto nla_put_failure;
+		break;
+	case NFT_CONNMARK_SET:
+		if (nla_put_be32(skb, NFTA_CONNMARK_CTMARK,
+				 htonl(priv->ctmark)))
+			goto nla_put_failure;
+		break;
+	}
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static struct nft_expr_type nft_connmark_type;
+static const struct nft_expr_ops nft_connmark_ops = {
+	.type		= &nft_connmark_type,
+	.size		= NFT_EXPR_SIZE(sizeof(struct nft_connmark)),
+	.eval		= nft_connmark_eval,
+	.init		= nft_connmark_init,
+	.dump		= nft_connmark_dump,
+};
+
+static struct nft_expr_type nft_connmark_type __read_mostly = {
+	.name		= "connmark",
+	.ops		= &nft_connmark_ops,
+	.policy		= nft_connmark_policy,
+	.maxattr	= NFTA_CONNMARK_MAX,
+	.owner		= THIS_MODULE,
+};
+
+static int __init nft_connmark_module_init(void)
+{
+	return nft_register_expr(&nft_connmark_type);
+}
+
+static void __exit nft_connmark_module_exit(void)
+{
+	nft_unregister_expr(&nft_connmark_type);
+}
+
+module_init(nft_connmark_module_init);
+module_exit(nft_connmark_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kristian Evensen <kristian.evensen@gmail.com>");
+MODULE_ALIAS_NFT_EXPR("connmark");