* [PATCH 0/2] ct_set: port CT target to nftables
@ 2014-01-02 9:12 Eric Leblond
2014-01-02 9:12 ` [PATCH 1/2] netfilter: CT: factorize reusable code Eric Leblond
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Eric Leblond @ 2014-01-02 9:12 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Hello,
Here's a patchset implementing CT features into a nftables modules
named ct_set. I've used same technique as my previous work by
factoring code in first patch and introducing the new module in
second one.
libnftables implementation is done and will be attached to this
thread.
I will work on nft support in the coming days.
Patchset statistics:
include/net/netfilter/nf_ct_set.h | 137 ++++++++++++++++
include/uapi/linux/netfilter/nf_tables.h | 36 +++++
net/netfilter/Kconfig | 5 +
net/netfilter/Makefile | 1 +
net/netfilter/nft_ct_set.c | 262 +++++++++++++++++++++++++++++++
net/netfilter/xt_CT.c | 143 +----------------
6 files changed, 449 insertions(+), 135 deletions(-)
BR,
--
Eric Leblond
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] netfilter: CT: factorize reusable code
2014-01-02 9:12 [PATCH 0/2] ct_set: port CT target to nftables Eric Leblond
@ 2014-01-02 9:12 ` Eric Leblond
2014-01-02 9:12 ` [PATCH 2/2] netfilter: nftables: introduce ct_set module Eric Leblond
2014-01-02 9:14 ` [libnftables PATCH] expr: add ct_set expression Eric Leblond
2 siblings, 0 replies; 8+ messages in thread
From: Eric Leblond @ 2014-01-02 9:12 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, Eric Leblond
Signed-off-by: Eric Leblond <eric@regit.org>
---
include/net/netfilter/nf_ct_set.h | 137 ++++++++++++++++++++++++++++++++++++
net/netfilter/xt_CT.c | 143 +++-----------------------------------
2 files changed, 145 insertions(+), 135 deletions(-)
create mode 100644 include/net/netfilter/nf_ct_set.h
diff --git a/include/net/netfilter/nf_ct_set.h b/include/net/netfilter/nf_ct_set.h
new file mode 100644
index 0000000..6f7d8cb
--- /dev/null
+++ b/include/net/netfilter/nf_ct_set.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014 Eric Leblond <eric@regit.org>
+ *
+ * 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 <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_timeout.h>
+#include <net/netfilter/nf_conntrack_zones.h>
+
+static int
+nf_ct_set_helper(struct nf_conn *ct, const char *helper_name, u8 proto,
+ u8 family)
+{
+ struct nf_conntrack_helper *helper;
+ struct nf_conn_help *help;
+
+ if (!proto) {
+ pr_info("You must specify a L4 protocol, and not use "
+ "inversions on it.\n");
+ return -ENOENT;
+ }
+
+ helper = nf_conntrack_helper_try_module_get(helper_name, family,
+ proto);
+ if (helper == NULL) {
+ pr_info("No such helper \"%s\"\n", helper_name);
+ return -ENOENT;
+ }
+
+ help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
+ if (help == NULL) {
+ module_put(helper->me);
+ return -ENOMEM;
+ }
+
+ help->helper = helper;
+ return 0;
+}
+
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+static void __nf_ct_tg_timeout_put(struct ctnl_timeout *timeout)
+{
+ typeof(nf_ct_timeout_put_hook) timeout_put;
+
+ timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
+ if (timeout_put)
+ timeout_put(timeout);
+}
+#endif
+
+static int
+nf_ct_set_timeout(struct nf_conn *ct, u8 proto, u8 family,
+ const char *timeout_name)
+{
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+ typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
+ struct ctnl_timeout *timeout;
+ struct nf_conn_timeout *timeout_ext;
+ struct nf_conntrack_l4proto *l4proto;
+ int ret = 0;
+
+ rcu_read_lock();
+ timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
+ if (timeout_find_get == NULL) {
+ ret = -ENOENT;
+ pr_info("Timeout policy base is empty\n");
+ goto out;
+ }
+
+ if (!proto) {
+ ret = -EINVAL;
+ pr_info("You must specify a L4 protocol, and not use "
+ "inversions on it.\n");
+ goto out;
+ }
+
+ timeout = timeout_find_get(timeout_name);
+ if (timeout == NULL) {
+ ret = -ENOENT;
+ pr_info("No such timeout policy \"%s\"\n", timeout_name);
+ goto out;
+ }
+
+ if (timeout->l3num != family) {
+ ret = -EINVAL;
+ pr_info("Timeout policy `%s' can only be used by L3 protocol "
+ "number %d\n", timeout_name, timeout->l3num);
+ goto err_put_timeout;
+ }
+ /* Make sure the timeout policy matches any existing protocol tracker,
+ * otherwise default to generic.
+ */
+ l4proto = __nf_ct_l4proto_find(family, proto);
+ if (timeout->l4proto->l4proto != l4proto->l4proto) {
+ ret = -EINVAL;
+ pr_info("Timeout policy `%s' can only be used by L4 protocol "
+ "number %d\n",
+ timeout_name, timeout->l4proto->l4proto);
+ goto err_put_timeout;
+ }
+ timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
+ if (timeout_ext == NULL)
+ ret = -ENOMEM;
+
+err_put_timeout:
+ __nf_ct_tg_timeout_put(timeout);
+out:
+ rcu_read_unlock();
+ return ret;
+#else
+ return -EOPNOTSUPP;
+#endif
+}
+
+static void nf_ct_destroy_timeout(struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+ struct nf_conn_timeout *timeout_ext;
+ typeof(nf_ct_timeout_put_hook) timeout_put;
+
+ rcu_read_lock();
+ timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
+
+ if (timeout_put) {
+ timeout_ext = nf_ct_timeout_find(ct);
+ if (timeout_ext)
+ timeout_put(timeout_ext->timeout);
+ }
+ rcu_read_unlock();
+#endif
+}
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 5929be6..e4190bc 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -14,11 +14,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_CT.h>
#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_l4proto.h>
-#include <net/netfilter/nf_conntrack_helper.h>
-#include <net/netfilter/nf_conntrack_ecache.h>
-#include <net/netfilter/nf_conntrack_timeout.h>
-#include <net/netfilter/nf_conntrack_zones.h>
+#include <net/netfilter/nf_ct_set.h>
static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
{
@@ -72,121 +68,13 @@ static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
return 0;
}
-static int
-xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
- const struct xt_tgchk_param *par)
-{
- struct nf_conntrack_helper *helper;
- struct nf_conn_help *help;
- u8 proto;
-
- proto = xt_ct_find_proto(par);
- if (!proto) {
- pr_info("You must specify a L4 protocol, and not use "
- "inversions on it.\n");
- return -ENOENT;
- }
-
- helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
- proto);
- if (helper == NULL) {
- pr_info("No such helper \"%s\"\n", helper_name);
- return -ENOENT;
- }
-
- help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
- if (help == NULL) {
- module_put(helper->me);
- return -ENOMEM;
- }
-
- help->helper = helper;
- return 0;
-}
-
-#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
-static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
-{
- typeof(nf_ct_timeout_put_hook) timeout_put;
-
- timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
- if (timeout_put)
- timeout_put(timeout);
-}
-#endif
-
-static int
-xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
- const char *timeout_name)
-{
-#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
- typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
- struct ctnl_timeout *timeout;
- struct nf_conn_timeout *timeout_ext;
- struct nf_conntrack_l4proto *l4proto;
- int ret = 0;
- u8 proto;
-
- rcu_read_lock();
- timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
- if (timeout_find_get == NULL) {
- ret = -ENOENT;
- pr_info("Timeout policy base is empty\n");
- goto out;
- }
-
- proto = xt_ct_find_proto(par);
- if (!proto) {
- ret = -EINVAL;
- pr_info("You must specify a L4 protocol, and not use "
- "inversions on it.\n");
- goto out;
- }
-
- timeout = timeout_find_get(timeout_name);
- if (timeout == NULL) {
- ret = -ENOENT;
- pr_info("No such timeout policy \"%s\"\n", timeout_name);
- goto out;
- }
-
- if (timeout->l3num != par->family) {
- ret = -EINVAL;
- pr_info("Timeout policy `%s' can only be used by L3 protocol "
- "number %d\n", timeout_name, timeout->l3num);
- goto err_put_timeout;
- }
- /* Make sure the timeout policy matches any existing protocol tracker,
- * otherwise default to generic.
- */
- l4proto = __nf_ct_l4proto_find(par->family, proto);
- if (timeout->l4proto->l4proto != l4proto->l4proto) {
- ret = -EINVAL;
- pr_info("Timeout policy `%s' can only be used by L4 protocol "
- "number %d\n",
- timeout_name, timeout->l4proto->l4proto);
- goto err_put_timeout;
- }
- timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
- if (timeout_ext == NULL)
- ret = -ENOMEM;
-
-err_put_timeout:
- __xt_ct_tg_timeout_put(timeout);
-out:
- rcu_read_unlock();
- return ret;
-#else
- return -EOPNOTSUPP;
-#endif
-}
-
static int xt_ct_tg_check(const struct xt_tgchk_param *par,
struct xt_ct_target_info_v1 *info)
{
struct nf_conntrack_tuple t;
struct nf_conn *ct;
int ret = -EOPNOTSUPP;
+ u8 proto = 0;
if (info->flags & XT_CT_NOTRACK) {
ct = NULL;
@@ -217,13 +105,16 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
}
if (info->helper[0]) {
- ret = xt_ct_set_helper(ct, info->helper, par);
+ proto = xt_ct_find_proto(par);
+ ret = nf_ct_set_helper(ct, info->helper, proto, par->family);
if (ret < 0)
goto err3;
}
if (info->timeout[0]) {
- ret = xt_ct_set_timeout(ct, par, info->timeout);
+ if (!proto)
+ proto = xt_ct_find_proto(par);
+ ret = nf_ct_set_timeout(ct, proto, par->family, info->timeout);
if (ret < 0)
goto err3;
}
@@ -291,24 +182,6 @@ static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
return xt_ct_tg_check(par, par->targinfo);
}
-static void xt_ct_destroy_timeout(struct nf_conn *ct)
-{
-#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
- struct nf_conn_timeout *timeout_ext;
- typeof(nf_ct_timeout_put_hook) timeout_put;
-
- rcu_read_lock();
- timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
-
- if (timeout_put) {
- timeout_ext = nf_ct_timeout_find(ct);
- if (timeout_ext)
- timeout_put(timeout_ext->timeout);
- }
- rcu_read_unlock();
-#endif
-}
-
static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
struct xt_ct_target_info_v1 *info)
{
@@ -322,7 +195,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
nf_ct_l3proto_module_put(par->family);
- xt_ct_destroy_timeout(ct);
+ nf_ct_destroy_timeout(ct);
nf_ct_put(info->ct);
}
}
--
1.8.5.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] netfilter: nftables: introduce ct_set module
2014-01-02 9:12 [PATCH 0/2] ct_set: port CT target to nftables Eric Leblond
2014-01-02 9:12 ` [PATCH 1/2] netfilter: CT: factorize reusable code Eric Leblond
@ 2014-01-02 9:12 ` Eric Leblond
2014-01-02 14:05 ` Pablo Neira Ayuso
2014-01-02 9:14 ` [libnftables PATCH] expr: add ct_set expression Eric Leblond
2 siblings, 1 reply; 8+ messages in thread
From: Eric Leblond @ 2014-01-02 9:12 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, Eric Leblond
This module is a port of iptables CT target. It allows
user to setup connection tracking for selected packets.
The context is not containing information about layer 4
so it is necessary to ask to userspace explicitely for
which layer 4 protocol the connection template has to be
created. This is the reason why the NFTA_CT_SET_PROTO
field has been introduced.
Signed-off-by: Eric Leblond <eric@regit.org>
---
include/uapi/linux/netfilter/nf_tables.h | 36 +++++
net/netfilter/Kconfig | 5 +
net/netfilter/Makefile | 1 +
net/netfilter/nft_ct_set.c | 262 +++++++++++++++++++++++++++++++
4 files changed, 304 insertions(+)
create mode 100644 net/netfilter/nft_ct_set.c
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index aa86a152..96bde79 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -707,6 +707,42 @@ enum nft_reject_attributes {
#define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1)
/**
+ * enum nft_ct_set_attributes - nf_tables ct_set expression netlink attributes
+ *
+ * @NFTA_CT_SET_PROTO: layer 4 protocol
+ * @NFTA_CT_SET_FLAGS: flags for connection as NOTRACK for example
+ * @NFTA_CT_SET_HELPER: protocol helper to link with matching connections
+ * @NFTA_CT_SET_CTEVENTS: only generate the specified conntrack events
+ * @NFTA_CT_SET_EXPEVENTS: only generate the specified expectation events
+ * @NFTA_CT_SET_ZONEID: assign packet to sone id
+ * @NFTA_CT_SET_TIMEOUT: use timeout policy for the connection
+ *
+ */
+enum nft_ct_set_attributes {
+ NFTA_CT_SET_UNSPEC,
+ NFTA_CT_SET_PROTO,
+ NFTA_CT_SET_FLAGS,
+ NFTA_CT_SET_HELPER,
+ NFTA_CT_SET_CTEVENTS,
+ NFTA_CT_SET_EXPEVENTS,
+ NFTA_CT_SET_ZONEID,
+ NFTA_CT_SET_TIMEOUT,
+ __NFTA_CT_SET_MAX
+};
+#define NFTA_CT_SET_MAX (__NFTA_CT_SET_MAX - 1)
+
+/**
+ * enum nft_ct_set_flags - nf_tables ct_set flags
+ *
+ * @NFT_CT_SET_F_NOTRACK: do not track this connection
+ */
+enum nft_ct_set_flags {
+
+enum nft_ct_set_flags {
+ NFT_CT_SET_F_NOTRACK = 0x1,
+};
+
+/**
* enum nft_nat_types - nf_tables nat expression NAT types
*
* @NFT_NAT_SNAT: source NAT
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index a1dec61..448c389 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -430,6 +430,11 @@ config NFT_CT
depends on NF_CONNTRACK
tristate "Netfilter nf_tables conntrack module"
+config NFT_CT_SET
+ depends on NF_TABLES
+ depends on NF_CONNTRACK
+ tristate "Netfilter nf_tables conntrack setup module"
+
config NFT_RBTREE
depends on NF_TABLES
tristate "Netfilter nf_tables rbtree set module"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 39e4a7b..f50c501 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
obj-$(CONFIG_NFT_META) += nft_meta.o
obj-$(CONFIG_NFT_CT) += nft_ct.o
+obj-$(CONFIG_NFT_CT_SET) += nft_ct_set.o
obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
obj-$(CONFIG_NFT_NAT) += nft_nat.o
obj-$(CONFIG_NFT_QUEUE) += nft_queue.o
diff --git a/net/netfilter/nft_ct_set.c b/net/netfilter/nft_ct_set.c
new file mode 100644
index 0000000..93e862d
--- /dev/null
+++ b/net/netfilter/nft_ct_set.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2014 Eric Leblond <eric@regit.org>
+ *
+ * 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/rculist_nulls.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_ct_set.h>
+
+struct nft_ct_set {
+ __u16 flags;
+ __u16 zoneid;
+ __u32 ct_events;
+ __u32 exp_events;
+ char *helper;
+ char *timeout;
+
+ /* Used internally by the kernel */
+ struct nf_conn *ct __attribute__((aligned(8)));
+ __u16 proto;
+};
+
+static void nft_ct_set_eval(const struct nft_expr *expr,
+ struct nft_data data[NFT_REG_MAX + 1],
+ const struct nft_pktinfo *pkt)
+{
+ struct nft_ct_set *priv = nft_expr_priv(expr);
+ struct nf_conn *ct;
+
+ if (pkt->skb->nfct != NULL)
+ return;
+
+ if (priv->flags & NFT_CT_SET_F_NOTRACK)
+ ct = nf_ct_untracked_get();
+ else
+ ct = priv->ct;
+
+ atomic_inc(&ct->ct_general.use);
+ pkt->skb->nfct = &ct->ct_general;
+ pkt->skb->nfctinfo = IP_CT_NEW;
+}
+
+static const struct nla_policy nft_ct_set_policy[NFTA_CT_SET_MAX + 1] = {
+ [NFTA_CT_SET_FLAGS] = { .type = NLA_U16 },
+ [NFTA_CT_SET_HELPER] = { .type = NLA_STRING },
+ [NFTA_CT_SET_CTEVENTS] = { .type = NLA_U32 },
+ [NFTA_CT_SET_EXPEVENTS] = { .type = NLA_U32 },
+ [NFTA_CT_SET_ZONEID] = { .type = NLA_U16 },
+ [NFTA_CT_SET_TIMEOUT] = { .type = NLA_STRING },
+};
+
+static int nft_ct_set_init(const struct nft_ctx *ctx,
+ const struct nft_expr *expr,
+ const struct nlattr * const tb[])
+{
+ struct nft_ct_set *priv = nft_expr_priv(expr);
+ const struct nlattr *nla;
+ struct nf_conntrack_tuple t;
+ struct nf_conn *ct;
+ int ret = -EOPNOTSUPP;
+
+
+ if (tb[NFTA_CT_SET_PROTO] != NULL)
+ priv->proto = ntohs(nla_get_be16(tb[NFTA_CT_SET_PROTO]));
+ else
+ return -EINVAL;
+
+ if (tb[NFTA_CT_SET_FLAGS] != NULL)
+ priv->flags = ntohs(nla_get_be16(tb[NFTA_CT_SET_FLAGS]));
+
+ if (priv->flags & NFT_CT_SET_F_NOTRACK) {
+ ct = NULL;
+ goto out;
+ }
+
+ if (tb[NFTA_CT_SET_HELPER] != NULL) {
+ nla = tb[NFTA_CT_SET_HELPER];
+ priv->helper = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
+ if (priv->helper == NULL)
+ return -ENOMEM;
+ nla_strlcpy(priv->helper, nla, nla_len(nla) + 1);
+ }
+
+ if (tb[NFTA_CT_SET_CTEVENTS] != NULL)
+ priv->ct_events = ntohl(nla_get_be32(tb[NFTA_CT_SET_CTEVENTS]));
+
+ if (tb[NFTA_CT_SET_EXPEVENTS] != NULL)
+ priv->exp_events =
+ ntohl(nla_get_be32(tb[NFTA_CT_SET_EXPEVENTS]));
+
+ if (tb[NFTA_CT_SET_ZONEID] != NULL) {
+#ifndef CONFIG_NF_CONNTRACK_ZONES
+ goto err1;
+#endif
+ priv->zoneid = ntohs(nla_get_be16(tb[NFTA_CT_SET_ZONEID]));
+ }
+
+ if (tb[NFTA_CT_SET_TIMEOUT] != NULL) {
+#ifndef CONFIG_NF_CONNTRACK_TIMEOUT
+ goto err1;
+#endif
+ nla = tb[NFTA_CT_SET_TIMEOUT];
+ priv->timeout = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
+ if (priv->timeout == NULL) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+ nla_strlcpy(priv->timeout, nla, nla_len(nla) + 1);
+ }
+
+ ret = nf_ct_l3proto_try_module_get(ctx->afi->family);
+ if (ret < 0)
+ goto err1;
+
+ memset(&t, 0, sizeof(t));
+ ct = nf_conntrack_alloc(ctx->net, priv->zoneid, &t, &t, GFP_KERNEL);
+ ret = PTR_ERR(ct);
+ if (IS_ERR(ct))
+ goto err2;
+
+ ret = 0;
+ if ((priv->ct_events || priv->exp_events) &&
+ !nf_ct_ecache_ext_add(ct, priv->ct_events, priv->exp_events,
+ GFP_KERNEL)) {
+ ret = -EINVAL;
+ goto err3;
+ }
+
+ if (priv->helper) {
+ ret = nf_ct_set_helper(ct, priv->helper, priv->proto,
+ ctx->afi->family);
+ if (ret < 0)
+ goto err3;
+ }
+
+ if (priv->timeout) {
+ ret = nf_ct_set_timeout(ct, priv->proto, ctx->afi->family,
+ priv->timeout);
+ if (ret < 0)
+ goto err3;
+ }
+
+ __set_bit(IPS_TEMPLATE_BIT, &ct->status);
+ __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+
+ /* Overload tuple linked list to put us in template list. */
+ hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+ &ctx->net->ct.tmpl);
+
+out:
+ priv->ct = ct;
+ return 0;
+
+err3:
+ nf_conntrack_free(ct);
+err2:
+ nf_ct_l3proto_module_put(ctx->afi->family);
+
+err1:
+ if (priv->helper)
+ kfree(priv->helper);
+ if (priv->timeout)
+ kfree(priv->timeout);
+ return ret;
+}
+
+static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+ const struct nft_ct_set *priv = nft_expr_priv(expr);
+
+ if (nla_put_be16(skb, NFTA_CT_SET_FLAGS, htons(priv->flags)) ||
+ nla_put_be16(skb, NFTA_CT_SET_ZONEID, htons(priv->zoneid)) ||
+ nla_put_be16(skb, NFTA_CT_SET_PROTO, htons(priv->proto)) ||
+ nla_put_be32(skb, NFTA_CT_SET_CTEVENTS, htons(priv->ct_events)) ||
+ nla_put_be32(skb, NFTA_CT_SET_EXPEVENTS, htons(priv->exp_events)))
+ goto nla_put_failure;
+ if (priv->helper)
+ if (nla_put_string(skb, NFTA_CT_SET_HELPER, priv->helper))
+ goto nla_put_failure;
+ if (priv->timeout)
+ if (nla_put_string(skb, NFTA_CT_SET_TIMEOUT, priv->timeout))
+ goto nla_put_failure;
+
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+
+static void nft_ct_set_destroy(const struct nft_expr *expr) {
+ struct nft_ct_set *priv = nft_expr_priv(expr);
+ struct nf_conn_help *help;
+ struct nf_conn *ct = NULL;
+
+ if (priv->helper)
+ kfree(priv->helper);
+
+ if (priv->timeout)
+ kfree(priv->timeout);
+
+ ct = priv->ct;
+ if (ct) {
+ help = nfct_help(ct);
+ if (help)
+ module_put(help->helper->me);
+
+ /* FIXME */
+#if 0
+ nf_ct_l3proto_module_put(par->family);
+#endif
+
+ nf_ct_destroy_timeout(ct);
+ nf_ct_put(priv->ct);
+ }
+}
+
+static struct nft_expr_type nft_ct_set_type;
+static const struct nft_expr_ops nft_ct_set_ops = {
+ .type = &nft_ct_set_type,
+ .size = NFT_EXPR_SIZE(sizeof(struct nft_ct_set)),
+ .eval = nft_ct_set_eval,
+ .init = nft_ct_set_init,
+ .dump = nft_ct_set_dump,
+ .destroy = nft_ct_set_destroy,
+};
+
+static struct nft_expr_type nft_ct_set_type __read_mostly = {
+ .name = "ct_set",
+ .ops = &nft_ct_set_ops,
+ .policy = nft_ct_set_policy,
+ .maxattr = NFTA_CT_SET_MAX,
+ .owner = THIS_MODULE,
+};
+
+static int __init nft_ct_set_module_init(void)
+{
+ return nft_register_expr(&nft_ct_set_type);
+}
+
+static void __exit nft_ct_set_module_exit(void)
+{
+ nft_unregister_expr(&nft_ct_set_type);
+}
+
+module_init(nft_ct_set_module_init);
+module_exit(nft_ct_set_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Leblond <eric@regit.org>");
+MODULE_ALIAS_NFT_EXPR("ct_set");
--
1.8.5.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [libnftables PATCH] expr: add ct_set expression
2014-01-02 9:12 [PATCH 0/2] ct_set: port CT target to nftables Eric Leblond
2014-01-02 9:12 ` [PATCH 1/2] netfilter: CT: factorize reusable code Eric Leblond
2014-01-02 9:12 ` [PATCH 2/2] netfilter: nftables: introduce ct_set module Eric Leblond
@ 2014-01-02 9:14 ` Eric Leblond
2014-01-02 9:52 ` Arturo Borrero Gonzalez
2 siblings, 1 reply; 8+ messages in thread
From: Eric Leblond @ 2014-01-02 9:14 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, Eric Leblond
This patch adds support for 'ct_set' expression which is a port
of iptables CT target.
Signed-off-by: Eric Leblond <eric@regit.org>
---
include/libnftables/expr.h | 11 ++
include/linux/netfilter/nf_tables.h | 35 ++++
src/Makefile.am | 1 +
src/expr/ct_set.c | 373 ++++++++++++++++++++++++++++++++++++
4 files changed, 420 insertions(+)
create mode 100644 src/expr/ct_set.c
diff --git a/include/libnftables/expr.h b/include/libnftables/expr.h
index 25455e4..71c66ae 100644
--- a/include/libnftables/expr.h
+++ b/include/libnftables/expr.h
@@ -149,6 +149,17 @@ enum {
NFT_EXPR_QUEUE_TOTAL,
NFT_EXPR_QUEUE_FLAGS,
};
+
+enum {
+ NFT_EXPR_CT_SET_FLAGS = NFT_RULE_EXPR_ATTR_BASE,
+ NFT_EXPR_CT_SET_PROTO,
+ NFT_EXPR_CT_SET_ZONEID,
+ NFT_EXPR_CT_SET_CTEVENTS,
+ NFT_EXPR_CT_SET_EXPEVENTS,
+ NFT_EXPR_CT_SET_HELPER,
+ NFT_EXPR_CT_SET_TIMEOUT,
+};
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index e08f80e..7c0c15b 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -628,6 +628,41 @@ enum nft_reject_attributes {
#define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1)
/**
+ * enum nft_ct_set_attributes - nf_tables ct_set expression netlink attributes
+ *
+ * @NFTA_CT_SET_PROTO: layer 4 protocol
+ * @NFTA_CT_SET_FLAGS: flags for connection as NOTRACK for example
+ * @NFTA_CT_SET_HELPER: protocol helper to link with matching connections
+ * @NFTA_CT_SET_CTEVENTS: only generate the specified conntrack events
+ * @NFTA_CT_SET_EXPEVENTS: only generate the specified expectation events
+ * @NFTA_CT_SET_ZONEID: assign packet to sone id
+ * @NFTA_CT_SET_TIMEOUT: use timeout policy for the connection
+ *
+ */
+enum nft_ct_set_attributes {
+ NFTA_CT_SET_UNSPEC,
+ NFTA_CT_SET_PROTO,
+ NFTA_CT_SET_FLAGS,
+ NFTA_CT_SET_HELPER,
+ NFTA_CT_SET_CTEVENTS,
+ NFTA_CT_SET_EXPEVENTS,
+ NFTA_CT_SET_ZONEID,
+ NFTA_CT_SET_TIMEOUT,
+ __NFTA_CT_SET_MAX
+};
+#define NFTA_CT_SET_MAX (__NFTA_CT_SET_MAX - 1)
+
+/**
+ * enum nft_ct_set_flags - nf_tables ct_set flags
+ *
+ * @NFT_CT_SET_F_NOTRACK: do not track this connection
+ */
+enum nft_ct_set_flags {
+ NFT_CT_SET_F_NOTRACK = 0x1,
+};
+
+
+/**
* enum nft_nat_types - nf_tables nat expression NAT types
*
* @NFT_NAT_SNAT: source NAT
diff --git a/src/Makefile.am b/src/Makefile.am
index 441e96e..e39ba25 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,7 @@ libnftables_la_SOURCES = utils.c \
expr/cmp.c \
expr/counter.c \
expr/ct.c \
+ expr/ct_set.c \
expr/data_reg.c \
expr/exthdr.c \
expr/limit.c \
diff --git a/src/expr/ct_set.c b/src/expr/ct_set.c
new file mode 100644
index 0000000..8449c5a
--- /dev/null
+++ b/src/expr/ct_set.c
@@ -0,0 +1,373 @@
+/*
+ * (C) 2014 by Eric Leblond <eric@regit.or>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include "internal.h"
+#include <libmnl/libmnl.h>
+#include <libnftables/expr.h>
+#include <libnftables/rule.h>
+#include "expr_ops.h"
+
+struct nft_expr_ct_set {
+ uint16_t flags;
+ uint16_t proto;
+ uint16_t zoneid;
+ uint32_t ct_events;
+ uint32_t exp_events;
+ char *helper;
+ char *timeout;
+};
+
+static int nft_rule_expr_ct_set_set(struct nft_rule_expr *e, uint16_t type,
+ const void *data, uint32_t data_len)
+{
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+
+ switch(type) {
+ case NFT_EXPR_CT_SET_FLAGS:
+ ct_set->flags = *((uint16_t *)data);
+ break;
+ case NFT_EXPR_CT_SET_PROTO:
+ ct_set->proto = *((uint16_t *)data);
+ break;
+ case NFT_EXPR_CT_SET_ZONEID:
+ ct_set->zoneid = *((uint16_t *)data);
+ break;
+ case NFT_EXPR_CT_SET_CTEVENTS:
+ ct_set->ct_events = *((uint32_t *)data);
+ break;
+ case NFT_EXPR_CT_SET_EXPEVENTS:
+ ct_set->exp_events = *((uint32_t *)data);
+ break;
+ case NFT_EXPR_CT_SET_HELPER:
+ if (ct_set->helper)
+ xfree(ct_set->helper);
+
+ ct_set->helper = strdup(data);
+ break;
+ case NFT_EXPR_CT_SET_TIMEOUT:
+ if (ct_set->timeout)
+ xfree(ct_set->timeout);
+
+ ct_set->timeout = strdup(data);
+ break;
+
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static const void *
+nft_rule_expr_ct_set_get(const struct nft_rule_expr *e, uint16_t type,
+ uint32_t *data_len)
+{
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+
+ switch(type) {
+ case NFT_EXPR_CT_SET_FLAGS:
+ *data_len = sizeof(ct_set->flags);
+ return &ct_set->flags;
+ case NFT_EXPR_CT_SET_PROTO:
+ *data_len = sizeof(ct_set->proto);
+ return &ct_set->proto;
+ case NFT_EXPR_CT_SET_ZONEID:
+ *data_len = sizeof(ct_set->zoneid);
+ return &ct_set->zoneid;
+ case NFT_EXPR_CT_SET_CTEVENTS:
+ *data_len = sizeof(ct_set->ct_events);
+ return &ct_set->ct_events;
+ case NFT_EXPR_CT_SET_EXPEVENTS:
+ *data_len = sizeof(ct_set->exp_events);
+ return &ct_set->exp_events;
+ case NFT_EXPR_CT_SET_HELPER:
+ *data_len = strlen(ct_set->helper)+1;
+ return ct_set->helper;
+ case NFT_EXPR_CT_SET_TIMEOUT:
+ *data_len = strlen(ct_set->timeout)+1;
+ return ct_set->timeout;
+ }
+ return NULL;
+}
+
+static int nft_rule_expr_ct_set_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, NFTA_CT_SET_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFTA_CT_SET_FLAGS:
+ case NFTA_CT_SET_PROTO:
+ case NFTA_CT_SET_ZONEID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case NFTA_CT_SET_CTEVENTS:
+ case NFTA_CT_SET_EXPEVENTS:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case NFTA_CT_SET_HELPER:
+ case NFTA_CT_SET_TIMEOUT:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void
+nft_rule_expr_ct_set_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
+{
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+
+ if (e->flags & (1 << NFT_EXPR_CT_SET_FLAGS))
+ mnl_attr_put_u16(nlh, NFTA_CT_SET_FLAGS, htons(ct_set->flags));
+ if (e->flags & (1 << NFT_EXPR_CT_SET_PROTO))
+ mnl_attr_put_u16(nlh, NFTA_CT_SET_PROTO, htons(ct_set->proto));
+ if (e->flags & (1 << NFT_EXPR_CT_SET_ZONEID))
+ mnl_attr_put_u16(nlh, NFTA_CT_SET_ZONEID, htons(ct_set->zoneid));
+ if (e->flags & (1 << NFT_EXPR_CT_SET_CTEVENTS))
+ mnl_attr_put_u32(nlh, NFTA_CT_SET_CTEVENTS, htonl(ct_set->ct_events));
+ if (e->flags & (1 << NFT_EXPR_CT_SET_EXPEVENTS))
+ mnl_attr_put_u32(nlh, NFTA_CT_SET_EXPEVENTS, htonl(ct_set->exp_events));
+ if (e->flags & (1 << NFT_EXPR_CT_SET_HELPER))
+ mnl_attr_put_strz(nlh, NFTA_CT_SET_HELPER, ct_set->helper);
+ if (e->flags & (1 << NFT_EXPR_CT_SET_TIMEOUT))
+ mnl_attr_put_strz(nlh, NFTA_CT_SET_TIMEOUT, ct_set->timeout);
+}
+
+static int
+nft_rule_expr_ct_set_parse(struct nft_rule_expr *e, struct nlattr *attr)
+{
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+ struct nlattr *tb[NFTA_CT_SET_MAX+1] = {};
+
+ if (mnl_attr_parse_nested(attr, nft_rule_expr_ct_set_cb, tb) < 0)
+ return -1;
+
+ if (tb[NFTA_CT_SET_FLAGS]) {
+ ct_set->flags = ntohs(mnl_attr_get_u16(tb[NFTA_CT_SET_FLAGS]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_FLAGS);
+ }
+ if (tb[NFTA_CT_SET_PROTO]) {
+ ct_set->proto = ntohs(mnl_attr_get_u16(tb[NFTA_CT_SET_PROTO]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_PROTO);
+ }
+ if (tb[NFTA_CT_SET_ZONEID]) {
+ ct_set->zoneid = ntohs(mnl_attr_get_u16(tb[NFTA_CT_SET_ZONEID]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_ZONEID);
+ }
+ if (tb[NFTA_CT_SET_CTEVENTS]) {
+ ct_set->ct_events = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SET_CTEVENTS]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_CTEVENTS);
+ }
+ if (tb[NFTA_CT_SET_EXPEVENTS]) {
+ ct_set->exp_events = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SET_EXPEVENTS]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_EXPEVENTS);
+ }
+ if (tb[NFTA_CT_SET_HELPER]) {
+ if (ct_set->helper)
+ xfree(ct_set->helper);
+
+ ct_set->helper = strdup(mnl_attr_get_str(tb[NFTA_CT_SET_HELPER]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_HELPER);
+ }
+ if (tb[NFTA_CT_SET_TIMEOUT]) {
+ if (ct_set->timeout)
+ xfree(ct_set->timeout);
+
+ ct_set->helper = strdup(mnl_attr_get_str(tb[NFTA_CT_SET_TIMEOUT]));
+ e->flags |= (1 << NFT_EXPR_CT_SET_TIMEOUT);
+ }
+ return 0;
+}
+
+static int nft_rule_expr_ct_set_json_parse(struct nft_rule_expr *e, json_t *root)
+{
+#ifdef JSON_PARSING
+ const char *uvalstr;
+ uint32_t uval32;
+ uint16_t uval16;
+
+ if (nft_jansson_parse_val(root, "flags", NFT_TYPE_U16, &uval16) < 0)
+ return -1;
+ nft_rule_expr_set_u16(e, NFT_EXPR_CT_SET_FLAGS, uval16);
+
+ if (nft_jansson_parse_val(root, "proto", NFT_TYPE_U16, &uval16) < 0)
+ return -1;
+ nft_rule_expr_set_u16(e, NFT_EXPR_CT_SET_PROTO, uval16);
+
+ if (nft_jansson_parse_val(root, "zoneid", NFT_TYPE_U16, &uval16) < 0)
+ return -1;
+ nft_rule_expr_set_u16(e, NFT_EXPR_CT_SET_ZONEID, uval16);
+
+ if (nft_jansson_parse_val(root, "ctevents", NFT_TYPE_U32, &uval32) < 0)
+ return -1;
+ nft_rule_expr_set_u32(e, NFT_EXPR_CT_SET_CTEVENTS, uval32);
+
+ if (nft_jansson_parse_val(root, "expevents", NFT_TYPE_U32, &uval32) < 0)
+ return -1;
+ nft_rule_expr_set_u32(e, NFT_EXPR_CT_SET_EXPEVENTS, uval32);
+
+ uvalstr = nft_jansson_parse_str(root, "helper");
+ if (uvalstr == NULL)
+ return -1;
+ nft_rule_expr_set_str(e, NFT_EXPR_CT_SET_HELPER, uvalstr);
+
+ uvalstr = nft_jansson_parse_str(root, "timeout");
+ if (uvalstr == NULL)
+ return -1;
+ nft_rule_expr_set_str(e, NFT_EXPR_CT_SET_TIMEOUT, uvalstr);
+
+ return 0;
+#else
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
+}
+
+static int nft_rule_expr_ct_set_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
+{
+#ifdef XML_PARSING
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+ const char *uvalstr;
+
+ if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
+ &ct_set->flags, NFT_TYPE_U16, NFT_XML_MAND) != 0)
+ return -1;
+ e->flags |= (1 << NFT_EXPR_CT_SET_FLAGS);
+
+ if (nft_mxml_num_parse(tree, "proto", MXML_DESCEND_FIRST, BASE_DEC,
+ &ct_set->proto, NFT_TYPE_U16, NFT_XML_MAND) != 0)
+ return -1;
+ e->flags |= (1 << NFT_EXPR_CT_SET_PROTO);
+
+ if (nft_mxml_num_parse(tree, "zoneid", MXML_DESCEND_FIRST, BASE_DEC,
+ &ct_set->flags, NFT_TYPE_U16, NFT_XML_MAND) != 0)
+ return -1;
+ e->flags |= (1 << NFT_EXPR_CT_SET_ZONEID);
+
+ if (nft_mxml_num_parse(tree, "ctevents", MXML_DESCEND_FIRST, BASE_DEC,
+ &ct_set->ct_events, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+ return -1;
+ e->flags |= (1 << NFT_EXPR_CT_SET_CTEVENTS);
+
+ if (nft_mxml_num_parse(tree, "expevents", MXML_DESCEND_FIRST, BASE_DEC,
+ &ct_set->exp_events, NFT_TYPE_U32, NFT_XML_MAND) != 0)
+ return -1;
+ e->flags |= (1 << NFT_EXPR_CT_SET_EXPEVENTS);
+
+ uvalstr = nft_mxml_str_parse(tree, "helper", MXML_DESCEND_FIRST,
+ NFT_XML_MAND);
+ if (uvalstr == NULL)
+ return -1;
+ ct_set->helper = strdup(uvalstr);
+ e->flags |= (1 << NFT_EXPR_CT_SET_HELPER);
+
+ uvalstr = nft_mxml_str_parse(tree, "timeout", MXML_DESCEND_FIRST,
+ NFT_XML_MAND);
+ if (uvalstr == NULL)
+ return -1;
+ ct_set->timeout = strdup(uvalstr);
+ e->flags |= (1 << NFT_EXPR_CT_SET_TIMEOUT);
+
+ return 0;
+#else
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
+}
+
+static int
+nft_rule_expr_ct_set_snprintf(char *buf, size_t len, uint32_t type,
+ uint32_t flags, struct nft_rule_expr *e)
+{
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+
+ switch(type) {
+ case NFT_OUTPUT_DEFAULT:
+ return snprintf(buf, len, "flags %u proto %u zoneid %u "
+ "ctevents %u expevents %u "
+ "helper %s timeout %s",
+ ct_set->flags, ct_set->proto, ct_set->zoneid,
+ ct_set->ct_events, ct_set->exp_events,
+ ct_set->helper, ct_set->timeout);
+ case NFT_OUTPUT_XML:
+ return snprintf(buf, len, "<flags>%u</flags>"
+ "<proto>%u</proto>"
+ "<zoneid>%u</zoneid>"
+ "<ctevents>%u</ctevents>"
+ "<expevents>%u</expevents>"
+ "<helper>%s</helper>"
+ "<timeout>%s</timeout>",
+ ct_set->flags, ct_set->proto, ct_set->zoneid,
+ ct_set->ct_events, ct_set->exp_events,
+ ct_set->helper, ct_set->timeout);
+ case NFT_OUTPUT_JSON:
+ return snprintf(buf, len, "\"flags\":%u,"
+ "\"proto\":%u,"
+ "\"zoneid\":%u,"
+ "\"ctevents\":%u,"
+ "\"expevents\":%u,"
+ "\"helper\":\"%s\","
+ "\"timeout\":\"%s\"",
+ ct_set->flags, ct_set->proto, ct_set->zoneid,
+ ct_set->ct_events, ct_set->exp_events,
+ ct_set->helper, ct_set->timeout);
+ default:
+ break;
+ }
+ return -1;
+}
+
+static void nft_rule_expr_ct_set_free(struct nft_rule_expr *e)
+{
+ struct nft_expr_ct_set *ct_set = nft_expr_data(e);
+
+ xfree(ct_set->helper);
+ xfree(ct_set->timeout);
+}
+
+struct expr_ops expr_ops_ct_set = {
+ .name = "ct_set",
+ .alloc_len = sizeof(struct nft_expr_ct_set),
+ .max_attr = NFTA_LOG_MAX,
+ .free = nft_rule_expr_ct_set_free,
+ .set = nft_rule_expr_ct_set_set,
+ .get = nft_rule_expr_ct_set_get,
+ .parse = nft_rule_expr_ct_set_parse,
+ .build = nft_rule_expr_ct_set_build,
+ .snprintf = nft_rule_expr_ct_set_snprintf,
+ .xml_parse = nft_rule_expr_ct_set_xml_parse,
+ .json_parse = nft_rule_expr_ct_set_json_parse,
+};
+
+static void __init expr_ct_set_init(void)
+{
+ nft_expr_ops_register(&expr_ops_ct_set);
+}
--
1.8.5.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [libnftables PATCH] expr: add ct_set expression
2014-01-02 9:14 ` [libnftables PATCH] expr: add ct_set expression Eric Leblond
@ 2014-01-02 9:52 ` Arturo Borrero Gonzalez
2014-01-02 10:15 ` Eric Leblond
0 siblings, 1 reply; 8+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-01-02 9:52 UTC (permalink / raw)
To: Eric Leblond; +Cc: Pablo Neira Ayuso, Netfilter Development Mailing list
On 2 January 2014 10:14, Eric Leblond <eric@regit.org> wrote:
> This patch adds support for 'ct_set' expression which is a port
> of iptables CT target.
>
> Signed-off-by: Eric Leblond <eric@regit.org>
Hi Eric, this patch looks good. Some comments below:
> +static const void *
> +nft_rule_expr_ct_set_get(const struct nft_rule_expr *e, uint16_t type,
> + uint32_t *data_len)
> +{
> + struct nft_expr_ct_set *ct_set = nft_expr_data(e);
> +
> + switch(type) {
> + case NFT_EXPR_CT_SET_FLAGS:
> + *data_len = sizeof(ct_set->flags);
> + return &ct_set->flags;
> + case NFT_EXPR_CT_SET_PROTO:
> + *data_len = sizeof(ct_set->proto);
> + return &ct_set->proto;
> + case NFT_EXPR_CT_SET_ZONEID:
> + *data_len = sizeof(ct_set->zoneid);
> + return &ct_set->zoneid;
> + case NFT_EXPR_CT_SET_CTEVENTS:
> + *data_len = sizeof(ct_set->ct_events);
> + return &ct_set->ct_events;
> + case NFT_EXPR_CT_SET_EXPEVENTS:
> + *data_len = sizeof(ct_set->exp_events);
> + return &ct_set->exp_events;
> + case NFT_EXPR_CT_SET_HELPER:
> + *data_len = strlen(ct_set->helper)+1;
> + return ct_set->helper;
> + case NFT_EXPR_CT_SET_TIMEOUT:
> + *data_len = strlen(ct_set->timeout)+1;
Why +1 here?
Others expressions, like 'log' or 'lookup' simply sets data_len with strlen().
I guess either this or the others aren't good, don't you?
> +
> +static int nft_rule_expr_ct_set_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
> +{
> +#ifdef XML_PARSING
> + struct nft_expr_ct_set *ct_set = nft_expr_data(e);
> + const char *uvalstr;
> +
> + if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
> + &ct_set->flags, NFT_TYPE_U16, NFT_XML_MAND) != 0)
> + return -1;
I see now that errno is not set anywhere in the error path of XML/JSON
expression parsing code.
I will patch nft_mxml_expr_parse() and nft_jansson_expr_parse().
regards
--
Arturo Borrero González
--
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
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [libnftables PATCH] expr: add ct_set expression
2014-01-02 9:52 ` Arturo Borrero Gonzalez
@ 2014-01-02 10:15 ` Eric Leblond
2014-01-02 11:20 ` Arturo Borrero Gonzalez
0 siblings, 1 reply; 8+ messages in thread
From: Eric Leblond @ 2014-01-02 10:15 UTC (permalink / raw)
To: Arturo Borrero Gonzalez
Cc: Pablo Neira Ayuso, Netfilter Development Mailing list
Hello,
On Thu, 2014-01-02 at 10:52 +0100, Arturo Borrero Gonzalez wrote:
> On 2 January 2014 10:14, Eric Leblond <eric@regit.org> wrote:
> > This patch adds support for 'ct_set' expression which is a port
> > of iptables CT target.
> >
> > Signed-off-by: Eric Leblond <eric@regit.org>
>
> Hi Eric, this patch looks good. Some comments below:
>
> > +static const void *
> > +nft_rule_expr_ct_set_get(const struct nft_rule_expr *e, uint16_t type,
> > + uint32_t *data_len)
> > +{
> > + struct nft_expr_ct_set *ct_set = nft_expr_data(e);
> > +
> > + switch(type) {
> > + case NFT_EXPR_CT_SET_FLAGS:
> > + *data_len = sizeof(ct_set->flags);
> > + return &ct_set->flags;
> > + case NFT_EXPR_CT_SET_PROTO:
> > + *data_len = sizeof(ct_set->proto);
> > + return &ct_set->proto;
> > + case NFT_EXPR_CT_SET_ZONEID:
> > + *data_len = sizeof(ct_set->zoneid);
> > + return &ct_set->zoneid;
> > + case NFT_EXPR_CT_SET_CTEVENTS:
> > + *data_len = sizeof(ct_set->ct_events);
> > + return &ct_set->ct_events;
> > + case NFT_EXPR_CT_SET_EXPEVENTS:
> > + *data_len = sizeof(ct_set->exp_events);
> > + return &ct_set->exp_events;
> > + case NFT_EXPR_CT_SET_HELPER:
> > + *data_len = strlen(ct_set->helper)+1;
> > + return ct_set->helper;
> > + case NFT_EXPR_CT_SET_TIMEOUT:
> > + *data_len = strlen(ct_set->timeout)+1;
>
> Why +1 here?
> Others expressions, like 'log' or 'lookup' simply sets data_len with strlen().
'log' is is using a char * and in length computation it is using +1 to
get the terminal 0 at the end of the string:
*data_len = strlen(log->prefix)+1;
return log->prefix;
and 'lookup' is using a direct access. I think it is because we have:
char set_name[IFNAMSIZ];
and in setter function:
memcpy(lookup->set_name, data, IFNAMSIZ);
lookup->set_name[IFNAMSIZ-1] = '\0';
So doing the following is ok in the getter function. We are sure we will
have a terminal 0 and we know the size of data:
case NFT_EXPR_LOOKUP_SET:
return lookup->set_name;
> I guess either this or the others aren't good, don't you?
No ;)
>
> > +
> > +static int nft_rule_expr_ct_set_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree)
> > +{
> > +#ifdef XML_PARSING
> > + struct nft_expr_ct_set *ct_set = nft_expr_data(e);
> > + const char *uvalstr;
> > +
> > + if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
> > + &ct_set->flags, NFT_TYPE_U16, NFT_XML_MAND) != 0)
> > + return -1;
>
> I see now that errno is not set anywhere in the error path of XML/JSON
> expression parsing code.
>
> I will patch nft_mxml_expr_parse() and nft_jansson_expr_parse().
Good catch!
BR,
--
Eric Leblond <eric@regit.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [libnftables PATCH] expr: add ct_set expression
2014-01-02 10:15 ` Eric Leblond
@ 2014-01-02 11:20 ` Arturo Borrero Gonzalez
0 siblings, 0 replies; 8+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-01-02 11:20 UTC (permalink / raw)
To: Eric Leblond; +Cc: Pablo Neira Ayuso, Netfilter Development Mailing list
On 2 January 2014 11:15, Eric Leblond <eric@regit.org> wrote:
>> I guess either this or the others aren't good, don't you?
>
> No ;)
>
Ok!
>>
>> I will patch nft_mxml_expr_parse() and nft_jansson_expr_parse().
>
> Good catch!
>
False-positive, they do set errno through concrete helpers, like
nft_xx_reg_parse() etc..
--
Arturo Borrero González
--
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
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] netfilter: nftables: introduce ct_set module
2014-01-02 9:12 ` [PATCH 2/2] netfilter: nftables: introduce ct_set module Eric Leblond
@ 2014-01-02 14:05 ` Pablo Neira Ayuso
0 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2014-01-02 14:05 UTC (permalink / raw)
To: Eric Leblond; +Cc: netfilter-devel
Hi Eric,
On Thu, Jan 02, 2014 at 10:12:56AM +0100, Eric Leblond wrote:
> This module is a port of iptables CT target. It allows
> user to setup connection tracking for selected packets.
>
> The context is not containing information about layer 4
> so it is necessary to ask to userspace explicitely for
> which layer 4 protocol the connection template has to be
> created. This is the reason why the NFTA_CT_SET_PROTO
> field has been introduced.
>
> Signed-off-by: Eric Leblond <eric@regit.org>
> ---
> include/uapi/linux/netfilter/nf_tables.h | 36 +++++
> net/netfilter/Kconfig | 5 +
> net/netfilter/Makefile | 1 +
> net/netfilter/nft_ct_set.c | 262 +++++++++++++++++++++++++++++++
> 4 files changed, 304 insertions(+)
> create mode 100644 net/netfilter/nft_ct_set.c
>
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index aa86a152..96bde79 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -707,6 +707,42 @@ enum nft_reject_attributes {
> #define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1)
>
> /**
> + * enum nft_ct_set_attributes - nf_tables ct_set expression netlink attributes
> + *
> + * @NFTA_CT_SET_PROTO: layer 4 protocol
> + * @NFTA_CT_SET_FLAGS: flags for connection as NOTRACK for example
> + * @NFTA_CT_SET_HELPER: protocol helper to link with matching connections
> + * @NFTA_CT_SET_CTEVENTS: only generate the specified conntrack events
> + * @NFTA_CT_SET_EXPEVENTS: only generate the specified expectation events
> + * @NFTA_CT_SET_ZONEID: assign packet to sone id
> + * @NFTA_CT_SET_TIMEOUT: use timeout policy for the connection
> + *
> + */
> +enum nft_ct_set_attributes {
> + NFTA_CT_SET_UNSPEC,
> + NFTA_CT_SET_PROTO,
> + NFTA_CT_SET_FLAGS,
> + NFTA_CT_SET_HELPER,
> + NFTA_CT_SET_CTEVENTS,
> + NFTA_CT_SET_EXPEVENTS,
> + NFTA_CT_SET_ZONEID,
> + NFTA_CT_SET_TIMEOUT,
> + __NFTA_CT_SET_MAX
> +};
> +#define NFTA_CT_SET_MAX (__NFTA_CT_SET_MAX - 1)
> +
> +/**
> + * enum nft_ct_set_flags - nf_tables ct_set flags
> + *
> + * @NFT_CT_SET_F_NOTRACK: do not track this connection
> + */
> +enum nft_ct_set_flags {
> +
> +enum nft_ct_set_flags {
> + NFT_CT_SET_F_NOTRACK = 0x1,
> +};
> +
> +/**
> * enum nft_nat_types - nf_tables nat expression NAT types
> *
> * @NFT_NAT_SNAT: source NAT
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index a1dec61..448c389 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -430,6 +430,11 @@ config NFT_CT
> depends on NF_CONNTRACK
> tristate "Netfilter nf_tables conntrack module"
>
> +config NFT_CT_SET
> + depends on NF_TABLES
> + depends on NF_CONNTRACK
> + tristate "Netfilter nf_tables conntrack setup module"
> +
> config NFT_RBTREE
> depends on NF_TABLES
> tristate "Netfilter nf_tables rbtree set module"
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index 39e4a7b..f50c501 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -74,6 +74,7 @@ obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
> obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
> obj-$(CONFIG_NFT_META) += nft_meta.o
> obj-$(CONFIG_NFT_CT) += nft_ct.o
> +obj-$(CONFIG_NFT_CT_SET) += nft_ct_set.o
> obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
> obj-$(CONFIG_NFT_NAT) += nft_nat.o
> obj-$(CONFIG_NFT_QUEUE) += nft_queue.o
> diff --git a/net/netfilter/nft_ct_set.c b/net/netfilter/nft_ct_set.c
> new file mode 100644
> index 0000000..93e862d
> --- /dev/null
> +++ b/net/netfilter/nft_ct_set.c
This has to be integrated into the existing nft_ct using the
select_ops(...) infrastructure. Depending on SREG or DREG if
interprets the rule as set or get operation. Some attributes will turn
noop depending on the flavour.
Please, see recent Arturo's work to enable meta set operation for
reference. Let me know if you have any question, thanks for working on
this.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-01-02 14:05 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-02 9:12 [PATCH 0/2] ct_set: port CT target to nftables Eric Leblond
2014-01-02 9:12 ` [PATCH 1/2] netfilter: CT: factorize reusable code Eric Leblond
2014-01-02 9:12 ` [PATCH 2/2] netfilter: nftables: introduce ct_set module Eric Leblond
2014-01-02 14:05 ` Pablo Neira Ayuso
2014-01-02 9:14 ` [libnftables PATCH] expr: add ct_set expression Eric Leblond
2014-01-02 9:52 ` Arturo Borrero Gonzalez
2014-01-02 10:15 ` Eric Leblond
2014-01-02 11:20 ` Arturo Borrero Gonzalez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).