* [PATCH 1/3] netfilter: add connlabel conntrack extension
2012-11-15 15:55 [PATCH 0/3] netfilter: add connlabel conntrack extension Florian Westphal
@ 2012-11-15 15:55 ` Florian Westphal
0 siblings, 0 replies; 8+ messages in thread
From: Florian Westphal @ 2012-11-15 15:55 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
similar to connmarks, except labels are bit-based; i.e.
all labels may be attached to a flow at the same time.
Up to 128 labels are supported. Supporting more labels
is possible, but requires increasing the ct offset delta
from u8 to u16 type due to increased extension sizes.
Mapping of bit-identifier to label name is done in userspace.
The extension is enabled at run-time once "-m connlabel" netfilter
rules are added.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/net/netfilter/nf_conntrack_extend.h | 4 +
include/net/netfilter/nf_conntrack_labels.h | 54 +++++++++++++++
include/net/netns/conntrack.h | 4 +
include/uapi/linux/netfilter/xt_connlabel.h | 13 ++++
net/netfilter/Kconfig | 18 +++++
net/netfilter/Makefile | 2 +
net/netfilter/nf_conntrack_core.c | 12 ++++
net/netfilter/nf_conntrack_labels.c | 73 ++++++++++++++++++++
net/netfilter/nf_conntrack_netlink.c | 3 +
net/netfilter/xt_connlabel.c | 96 +++++++++++++++++++++++++++
10 files changed, 279 insertions(+), 0 deletions(-)
create mode 100644 include/net/netfilter/nf_conntrack_labels.h
create mode 100644 include/uapi/linux/netfilter/xt_connlabel.h
create mode 100644 net/netfilter/nf_conntrack_labels.c
create mode 100644 net/netfilter/xt_connlabel.c
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 8b4d1fc2..977bc8a 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -23,6 +23,9 @@ enum nf_ct_ext_id {
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
NF_CT_EXT_TIMEOUT,
#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ NF_CT_EXT_LABELS,
+#endif
NF_CT_EXT_NUM,
};
@@ -33,6 +36,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
#define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h
new file mode 100644
index 0000000..fdd88fb
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_labels.h
@@ -0,0 +1,54 @@
+#include <linux/types.h>
+#include <net/net_namespace.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+#include <uapi/linux/netfilter/xt_connlabel.h>
+
+struct nf_conn_labels {
+ u8 words;
+ unsigned long bits[];
+};
+
+static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ return nf_ct_ext_find(ct, NF_CT_EXT_LABELS);
+#else
+ return NULL;
+#endif
+}
+
+static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ struct nf_conn_labels *cl_ext;
+ struct net *net = nf_ct_net(ct);
+ u8 words;
+
+ words = ACCESS_ONCE(net->ct.label_words);
+ if (words == 0 || WARN_ON_ONCE(words > 8))
+ return NULL;
+
+ cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS, words * sizeof(long), GFP_ATOMIC);
+ if (cl_ext != NULL)
+ cl_ext->words = words;
+
+ return cl_ext;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+int nf_conntrack_labels_init(struct net *net);
+void nf_conntrack_labels_fini(struct net *net);
+#else
+static inline int nf_conntrack_labels_init(struct net *n) { return 0; }
+static inline void nf_conntrack_labels_fini(struct net *net) {}
+#endif
+
+bool nf_connlabel_match(const struct nf_conn *ct, u16 bit);
+int nf_connlabel_set(struct nf_conn *ct, u16 bit);
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index a1d83cc..8cc41f4 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -83,6 +83,10 @@ struct netns_ct {
int sysctl_auto_assign_helper;
bool auto_assign_helper_warned;
struct nf_ip_net nf_ct_proto;
+#if defined(CONFIG_NF_CONNTRACK_LABELS)
+ unsigned int labels_used;
+ u8 label_words;
+#endif
#ifdef CONFIG_NF_NAT_NEEDED
struct hlist_head *nat_bysource;
unsigned int nat_htable_size;
diff --git a/include/uapi/linux/netfilter/xt_connlabel.h b/include/uapi/linux/netfilter/xt_connlabel.h
new file mode 100644
index 0000000..a6ffd33
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_connlabel.h
@@ -0,0 +1,13 @@
+#include <linux/types.h>
+
+#define XT_CONNLABEL_MAXBIT 127
+enum xt_connlabel_mtopts {
+ XT_CONNLABEL_OP_INVERT = 1 << 0,
+ XT_CONNLABEL_OP_SET = 1 << 1,
+};
+
+struct xt_connlabel_mtinfo {
+ __u16 bit;
+ __u16 options;
+};
+
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index fefa514..acfed41 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -124,6 +124,12 @@ config NF_CONNTRACK_TIMESTAMP
If unsure, say `N'.
+config NF_CONNTRACK_LABELS
+ bool
+ help
+ This option enables support for assigning user-defined flag bits
+ to connection tracking entries. It selected by the connlabel match.
+
config NF_CT_PROTO_DCCP
tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)'
depends on EXPERIMENTAL
@@ -835,6 +841,18 @@ config NETFILTER_XT_MATCH_CONNBYTES
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_MATCH_CONNLABEL
+ tristate '"connlabel" match support'
+ select NF_CONNTRACK_LABELS
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This match allows you to test and assign userspace-defined labels names
+ to a connection. The kernel only stores bit values - mapping
+ names to bits is done by userspace.
+
+ Unlike connmark, more than 32 flag bits may be assigned to a
+ connection simultaneously.
+
config NETFILTER_XT_MATCH_CONNLIMIT
tristate '"connlimit" match support"'
depends on NF_CONNTRACK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 3259697..b3bbda6 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
+nf_conntrack-$(CONFIG_NF_CONNTRACK_LABELS) += nf_conntrack_labels.o
obj-$(CONFIG_NETFILTER) = netfilter.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ADDRTYPE) += xt_addrtype.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLABEL) += xt_connlabel.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 0f241be..35a2d47 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -45,6 +45,7 @@
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_timestamp.h>
#include <net/netfilter/nf_conntrack_timeout.h>
+#include <net/netfilter/nf_conntrack_labels.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
@@ -770,6 +771,7 @@ void nf_conntrack_free(struct nf_conn *ct)
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
+
/* Allocate a new conntrack: we return -ENOMEM if classification
failed due to stress. Otherwise it really is unclassifiable. */
static struct nf_conntrack_tuple_hash *
@@ -816,6 +818,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
+ nf_ct_labels_ext_add(ct);
ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL;
nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0,
@@ -1359,6 +1362,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
}
nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
+ nf_conntrack_labels_fini(net);
nf_conntrack_helper_fini(net);
nf_conntrack_timeout_fini(net);
nf_conntrack_ecache_fini(net);
@@ -1585,7 +1589,15 @@ static int nf_conntrack_init_net(struct net *net)
ret = nf_conntrack_helper_init(net);
if (ret < 0)
goto err_helper;
+
+ ret = nf_conntrack_labels_init(net);
+ if (ret < 0)
+ goto err_labels;
+
return 0;
+
+err_labels:
+ nf_conntrack_helper_fini(net);
err_helper:
nf_conntrack_timeout_fini(net);
err_timeout:
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c
new file mode 100644
index 0000000..22f4823
--- /dev/null
+++ b/net/netfilter/nf_conntrack_labels.c
@@ -0,0 +1,73 @@
+/*
+ * test/set flag bits stored in conntrack extension area.
+ *
+ * (C) 2012 Astaro GmbH & Co KG
+ *
+ * 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/ctype.h>
+#include <linux/export.h>
+#include <linux/jhash.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_labels.h>
+
+static unsigned int label_bits(const struct nf_conn_labels *l)
+{
+ unsigned int longs = l->words;
+ return longs * BITS_PER_LONG;
+}
+
+bool nf_connlabel_match(const struct nf_conn *ct, u16 bit)
+{
+ struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+ if (!labels)
+ return false;
+
+ return bit < label_bits(labels) && test_bit(bit, labels->bits);
+}
+EXPORT_SYMBOL_GPL(nf_connlabel_match);
+
+int nf_connlabel_set(struct nf_conn *ct, u16 bit)
+{
+ struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+ if (!labels || bit >= label_bits(labels))
+ return -ENOSPC;
+
+ if (test_bit(bit, labels->bits))
+ return 0;
+
+ if (test_and_set_bit(bit, labels->bits))
+ return 0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_connlabel_set);
+
+static struct nf_ct_ext_type labels_extend __read_mostly = {
+ .len = sizeof(struct nf_conn_labels),
+ .align = __alignof__(struct nf_conn_labels),
+ .id = NF_CT_EXT_LABELS,
+};
+
+int nf_conntrack_labels_init(struct net *net)
+{
+ if (net_eq(net, &init_net))
+ return nf_ct_extend_register(&labels_extend);
+ return 0;
+}
+
+void nf_conntrack_labels_fini(struct net *net)
+{
+ if (net_eq(net, &init_net))
+ nf_ct_extend_unregister(&labels_extend);
+}
+
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 7bbfb3d..cf22362 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -43,6 +43,7 @@
#include <net/netfilter/nf_conntrack_acct.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_timestamp.h>
+#include <net/netfilter/nf_conntrack_labels.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_l4proto.h>
@@ -1489,6 +1490,8 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
+ nf_ct_labels_ext_add(ct);
+
/* we must add conntrack extensions before confirmation. */
ct->status |= IPS_CONFIRMED;
diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c
new file mode 100644
index 0000000..6256dc3
--- /dev/null
+++ b/net/netfilter/xt_connlabel.c
@@ -0,0 +1,96 @@
+/*
+ * (C) 2012 Astaro GmbH & Co KG
+ *
+ * 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/module.h>
+#include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_labels.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Xtables: add/match connection trackling labels");
+
+static bool
+connlabel_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_connlabel_mtinfo *info = par->matchinfo;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct;
+ bool invert = info->options & XT_CONNLABEL_OP_INVERT;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct == NULL || nf_ct_is_untracked(ct))
+ return invert;
+
+ if (info->options & XT_CONNLABEL_OP_SET)
+ return (nf_connlabel_set(ct, info->bit) == 0) ^ invert;
+
+ return nf_connlabel_match(ct, info->bit) ^ invert;
+}
+
+static int connlabel_mt_check(const struct xt_mtchk_param *par)
+{
+ const int options = XT_CONNLABEL_OP_INVERT |
+ XT_CONNLABEL_OP_SET;
+ struct xt_connlabel_mtinfo *info = par->matchinfo;
+ int ret;
+ size_t words;
+
+ if (info->bit > XT_CONNLABEL_MAXBIT)
+ return -ERANGE;
+
+ if (info->options & ~options) {
+ pr_err("Unknown options in mask %x\n", info->options);
+ return -EINVAL;
+ }
+
+ ret = nf_ct_l3proto_try_module_get(par->family);
+ if (ret < 0) {
+ pr_info("cannot load conntrack support for proto=%u\n", par->family);
+ return ret;
+ }
+
+ par->net->ct.labels_used++;
+ words = BITS_TO_LONGS(info->bit+1);
+ if (words > par->net->ct.label_words)
+ par->net->ct.label_words = words;
+
+ return ret;
+}
+
+static void connlabel_mt_destroy(const struct xt_mtdtor_param *par)
+{
+ par->net->ct.labels_used--;
+ if (par->net->ct.labels_used == 0)
+ par->net->ct.label_words = 0;
+ nf_ct_l3proto_module_put(par->family);
+}
+
+static struct xt_match connlabels_mt_reg __read_mostly = {
+ .name = "connlabel",
+ .family = NFPROTO_UNSPEC,
+ .checkentry = connlabel_mt_check,
+ .match = connlabel_mt,
+ .matchsize = sizeof(struct xt_connlabel_mtinfo),
+ .destroy = connlabel_mt_destroy,
+ .me = THIS_MODULE,
+};
+
+static int __init connlabel_mt_init(void)
+{
+ return xt_register_match(&connlabels_mt_reg);
+}
+
+static void __exit connlabel_mt_exit(void)
+{
+ xt_unregister_match(&connlabels_mt_reg);
+}
+
+module_init(connlabel_mt_init);
+module_exit(connlabel_mt_exit);
--
1.7.8.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH next V2] netfilter connlabel extension
@ 2013-01-11 16:30 Florian Westphal
2013-01-11 16:30 ` [PATCH 1/3] netfilter: add connlabel conntrack extension Florian Westphal
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Florian Westphal @ 2013-01-11 16:30 UTC (permalink / raw)
To: netfilter-devel
The following three patches add the connlabel extension, plus
ctnetlink support to set/clear labels from userspace.
Connlabels are similar to connmarks, except labels are bit-based; i.e.
all labels may be attached to a flow at the same time.
Up to 128 labels are supported at this time.
This limit could be increased later, if the need arises.
To do this safely, one needs to check that the
conntrack extension array won't wrap when all conntrack extensions are in
use at the same time (offsets are stored in 'u8' array).
Mapping of bit-identifier to label name is done in userspace.
The extension is enabled at run-time once "-m connlabel" netfilter rules
are added. Existing conntracks will not be able to make use of the labels
added later.
Change since V1:
- add ctnetlink bitmask attribute (CTA_LABELS_MASK)
to allow userspace to only manipulate a subset of the bitmask.
- otherwise, cosmetic changes only.
Changes since RFCv2:
- make it a variable-size extension and remove dynamic
reallocation of the label array
- add ctnetlink support for receiving/setting labels
- limit to 128 instead of 1k labels due to limited extension
space (128 is more than enough for now, so this is no problem).
The following changes since commit 61c5e88aecd6fbf2480f39394bb495964e6d9984:
skbuff: make __kmalloc_reserve static (2012-12-28 20:32:36 -0800)
are available in the git repository at:
git://git.breakpoint.cc/fw/nf-next.git nfct_ext_clabel_19
Florian Westphal (3):
netfilter: add connlabel conntrack extension
netfilter: ctnetlink: deliver labels to userspace
netfilter: ctnetlink: allow userspace to modify labels
include/net/netfilter/nf_conntrack_extend.h | 4 +
include/net/netfilter/nf_conntrack_labels.h | 58 ++++++++++
include/net/netns/conntrack.h | 4 +
include/uapi/linux/netfilter/nf_conntrack_common.h | 1 +
include/uapi/linux/netfilter/nfnetlink_conntrack.h | 2 +
include/uapi/linux/netfilter/xt_connlabel.h | 12 ++
net/netfilter/Kconfig | 18 +++
net/netfilter/Makefile | 2 +
net/netfilter/nf_conntrack_core.c | 12 ++
net/netfilter/nf_conntrack_labels.c | 115 ++++++++++++++++++++
net/netfilter/nf_conntrack_netlink.c | 88 +++++++++++++++
net/netfilter/xt_connlabel.c | 99 +++++++++++++++++
12 files changed, 415 insertions(+), 0 deletions(-)
create mode 100644 include/net/netfilter/nf_conntrack_labels.h
create mode 100644 include/uapi/linux/netfilter/xt_connlabel.h
create mode 100644 net/netfilter/nf_conntrack_labels.c
create mode 100644 net/netfilter/xt_connlabel.c
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] netfilter: add connlabel conntrack extension
2013-01-11 16:30 [PATCH next V2] netfilter connlabel extension Florian Westphal
@ 2013-01-11 16:30 ` Florian Westphal
2013-01-17 23:37 ` Pablo Neira Ayuso
2013-01-11 16:30 ` [PATCH 2/3] netfilter: ctnetlink: deliver labels to userspace Florian Westphal
2013-01-11 16:30 ` [PATCH 3/3] netfilter: ctnetlink: allow userspace to modify labels Florian Westphal
2 siblings, 1 reply; 8+ messages in thread
From: Florian Westphal @ 2013-01-11 16:30 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
similar to connmarks, except labels are bit-based; i.e.
all labels may be attached to a flow at the same time.
Up to 128 labels are supported. Supporting more labels
is possible, but requires increasing the ct offset delta
from u8 to u16 type due to increased extension sizes.
Mapping of bit-identifier to label name is done in userspace.
The extension is enabled at run-time once "-m connlabel" netfilter
rules are added.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/net/netfilter/nf_conntrack_extend.h | 4 +
include/net/netfilter/nf_conntrack_labels.h | 55 +++++++++++++++
include/net/netns/conntrack.h | 4 +
include/uapi/linux/netfilter/xt_connlabel.h | 12 +++
net/netfilter/Kconfig | 18 +++++
net/netfilter/Makefile | 2 +
net/netfilter/nf_conntrack_core.c | 12 +++
net/netfilter/nf_conntrack_labels.c | 72 +++++++++++++++++++
net/netfilter/nf_conntrack_netlink.c | 3 +
net/netfilter/xt_connlabel.c | 99 +++++++++++++++++++++++++++
10 files changed, 281 insertions(+), 0 deletions(-)
create mode 100644 include/net/netfilter/nf_conntrack_labels.h
create mode 100644 include/uapi/linux/netfilter/xt_connlabel.h
create mode 100644 net/netfilter/nf_conntrack_labels.c
create mode 100644 net/netfilter/xt_connlabel.c
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 8b4d1fc2..977bc8a 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -23,6 +23,9 @@ enum nf_ct_ext_id {
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
NF_CT_EXT_TIMEOUT,
#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ NF_CT_EXT_LABELS,
+#endif
NF_CT_EXT_NUM,
};
@@ -33,6 +36,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
#define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h
new file mode 100644
index 0000000..b94fe31
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_labels.h
@@ -0,0 +1,55 @@
+#include <linux/types.h>
+#include <net/net_namespace.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+#include <uapi/linux/netfilter/xt_connlabel.h>
+
+struct nf_conn_labels {
+ u8 words;
+ unsigned long bits[];
+};
+
+static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ return nf_ct_ext_find(ct, NF_CT_EXT_LABELS);
+#else
+ return NULL;
+#endif
+}
+
+static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ struct nf_conn_labels *cl_ext;
+ struct net *net = nf_ct_net(ct);
+ u8 words;
+
+ words = ACCESS_ONCE(net->ct.label_words);
+ if (words == 0 || WARN_ON_ONCE(words > 8))
+ return NULL;
+
+ cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
+ words * sizeof(long), GFP_ATOMIC);
+ if (cl_ext != NULL)
+ cl_ext->words = words;
+
+ return cl_ext;
+#else
+ return NULL;
+#endif
+}
+
+bool nf_connlabel_match(const struct nf_conn *ct, u16 bit);
+int nf_connlabel_set(struct nf_conn *ct, u16 bit);
+
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+int nf_conntrack_labels_init(struct net *net);
+void nf_conntrack_labels_fini(struct net *net);
+#else
+static inline int nf_conntrack_labels_init(struct net *n) { return 0; }
+static inline void nf_conntrack_labels_fini(struct net *net) {}
+#endif
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index a1d83cc..8cc41f4 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -83,6 +83,10 @@ struct netns_ct {
int sysctl_auto_assign_helper;
bool auto_assign_helper_warned;
struct nf_ip_net nf_ct_proto;
+#if defined(CONFIG_NF_CONNTRACK_LABELS)
+ unsigned int labels_used;
+ u8 label_words;
+#endif
#ifdef CONFIG_NF_NAT_NEEDED
struct hlist_head *nat_bysource;
unsigned int nat_htable_size;
diff --git a/include/uapi/linux/netfilter/xt_connlabel.h b/include/uapi/linux/netfilter/xt_connlabel.h
new file mode 100644
index 0000000..c4bc9ee
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_connlabel.h
@@ -0,0 +1,12 @@
+#include <linux/types.h>
+
+#define XT_CONNLABEL_MAXBIT 127
+enum xt_connlabel_mtopts {
+ XT_CONNLABEL_OP_INVERT = 1 << 0,
+ XT_CONNLABEL_OP_SET = 1 << 1,
+};
+
+struct xt_connlabel_mtinfo {
+ __u16 bit;
+ __u16 options;
+};
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index fefa514..acfed41 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -124,6 +124,12 @@ config NF_CONNTRACK_TIMESTAMP
If unsure, say `N'.
+config NF_CONNTRACK_LABELS
+ bool
+ help
+ This option enables support for assigning user-defined flag bits
+ to connection tracking entries. It selected by the connlabel match.
+
config NF_CT_PROTO_DCCP
tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)'
depends on EXPERIMENTAL
@@ -835,6 +841,18 @@ config NETFILTER_XT_MATCH_CONNBYTES
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_MATCH_CONNLABEL
+ tristate '"connlabel" match support'
+ select NF_CONNTRACK_LABELS
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This match allows you to test and assign userspace-defined labels names
+ to a connection. The kernel only stores bit values - mapping
+ names to bits is done by userspace.
+
+ Unlike connmark, more than 32 flag bits may be assigned to a
+ connection simultaneously.
+
config NETFILTER_XT_MATCH_CONNLIMIT
tristate '"connlimit" match support"'
depends on NF_CONNTRACK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 3259697..b3bbda6 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
+nf_conntrack-$(CONFIG_NF_CONNTRACK_LABELS) += nf_conntrack_labels.o
obj-$(CONFIG_NETFILTER) = netfilter.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ADDRTYPE) += xt_addrtype.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLABEL) += xt_connlabel.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 08cdc71..2d898b1 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -45,6 +45,7 @@
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_timestamp.h>
#include <net/netfilter/nf_conntrack_timeout.h>
+#include <net/netfilter/nf_conntrack_labels.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
@@ -763,6 +764,7 @@ void nf_conntrack_free(struct nf_conn *ct)
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
+
/* Allocate a new conntrack: we return -ENOMEM if classification
failed due to stress. Otherwise it really is unclassifiable. */
static struct nf_conntrack_tuple_hash *
@@ -809,6 +811,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
+ nf_ct_labels_ext_add(ct);
ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL;
nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0,
@@ -1352,6 +1355,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
}
nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
+ nf_conntrack_labels_fini(net);
nf_conntrack_helper_fini(net);
nf_conntrack_timeout_fini(net);
nf_conntrack_ecache_fini(net);
@@ -1580,7 +1584,15 @@ static int nf_conntrack_init_net(struct net *net)
ret = nf_conntrack_helper_init(net);
if (ret < 0)
goto err_helper;
+
+ ret = nf_conntrack_labels_init(net);
+ if (ret < 0)
+ goto err_labels;
+
return 0;
+
+err_labels:
+ nf_conntrack_helper_fini(net);
err_helper:
nf_conntrack_timeout_fini(net);
err_timeout:
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c
new file mode 100644
index 0000000..9fcf470
--- /dev/null
+++ b/net/netfilter/nf_conntrack_labels.c
@@ -0,0 +1,72 @@
+/*
+ * test/set flag bits stored in conntrack extension area.
+ *
+ * (C) 2013 Astaro GmbH & Co KG
+ *
+ * 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/ctype.h>
+#include <linux/export.h>
+#include <linux/jhash.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_labels.h>
+
+static unsigned int label_bits(const struct nf_conn_labels *l)
+{
+ unsigned int longs = l->words;
+ return longs * BITS_PER_LONG;
+}
+
+bool nf_connlabel_match(const struct nf_conn *ct, u16 bit)
+{
+ struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+ if (!labels)
+ return false;
+
+ return bit < label_bits(labels) && test_bit(bit, labels->bits);
+}
+EXPORT_SYMBOL_GPL(nf_connlabel_match);
+
+int nf_connlabel_set(struct nf_conn *ct, u16 bit)
+{
+ struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+ if (!labels || bit >= label_bits(labels))
+ return -ENOSPC;
+
+ if (test_bit(bit, labels->bits))
+ return 0;
+
+ if (test_and_set_bit(bit, labels->bits))
+ return 0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_connlabel_set);
+
+static struct nf_ct_ext_type labels_extend __read_mostly = {
+ .len = sizeof(struct nf_conn_labels),
+ .align = __alignof__(struct nf_conn_labels),
+ .id = NF_CT_EXT_LABELS,
+};
+
+int nf_conntrack_labels_init(struct net *net)
+{
+ if (net_eq(net, &init_net))
+ return nf_ct_extend_register(&labels_extend);
+ return 0;
+}
+
+void nf_conntrack_labels_fini(struct net *net)
+{
+ if (net_eq(net, &init_net))
+ nf_ct_extend_unregister(&labels_extend);
+}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4e078cd..5bf95eb 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -43,6 +43,7 @@
#include <net/netfilter/nf_conntrack_acct.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_timestamp.h>
+#include <net/netfilter/nf_conntrack_labels.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_l4proto.h>
@@ -1598,6 +1599,8 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
+ nf_ct_labels_ext_add(ct);
+
/* we must add conntrack extensions before confirmation. */
ct->status |= IPS_CONFIRMED;
diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c
new file mode 100644
index 0000000..9f8719d
--- /dev/null
+++ b/net/netfilter/xt_connlabel.c
@@ -0,0 +1,99 @@
+/*
+ * (C) 2013 Astaro GmbH & Co KG
+ *
+ * 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/module.h>
+#include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_labels.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Xtables: add/match connection trackling labels");
+MODULE_ALIAS("ipt_connlabel");
+MODULE_ALIAS("ip6t_connlabel");
+
+static bool
+connlabel_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_connlabel_mtinfo *info = par->matchinfo;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct;
+ bool invert = info->options & XT_CONNLABEL_OP_INVERT;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct == NULL || nf_ct_is_untracked(ct))
+ return invert;
+
+ if (info->options & XT_CONNLABEL_OP_SET)
+ return (nf_connlabel_set(ct, info->bit) == 0) ^ invert;
+
+ return nf_connlabel_match(ct, info->bit) ^ invert;
+}
+
+static int connlabel_mt_check(const struct xt_mtchk_param *par)
+{
+ const int options = XT_CONNLABEL_OP_INVERT |
+ XT_CONNLABEL_OP_SET;
+ struct xt_connlabel_mtinfo *info = par->matchinfo;
+ int ret;
+ size_t words;
+
+ if (info->bit > XT_CONNLABEL_MAXBIT)
+ return -ERANGE;
+
+ if (info->options & ~options) {
+ pr_err("Unknown options in mask %x\n", info->options);
+ return -EINVAL;
+ }
+
+ ret = nf_ct_l3proto_try_module_get(par->family);
+ if (ret < 0) {
+ pr_info("cannot load conntrack support for proto=%u\n",
+ par->family);
+ return ret;
+ }
+
+ par->net->ct.labels_used++;
+ words = BITS_TO_LONGS(info->bit+1);
+ if (words > par->net->ct.label_words)
+ par->net->ct.label_words = words;
+
+ return ret;
+}
+
+static void connlabel_mt_destroy(const struct xt_mtdtor_param *par)
+{
+ par->net->ct.labels_used--;
+ if (par->net->ct.labels_used == 0)
+ par->net->ct.label_words = 0;
+ nf_ct_l3proto_module_put(par->family);
+}
+
+static struct xt_match connlabels_mt_reg __read_mostly = {
+ .name = "connlabel",
+ .family = NFPROTO_UNSPEC,
+ .checkentry = connlabel_mt_check,
+ .match = connlabel_mt,
+ .matchsize = sizeof(struct xt_connlabel_mtinfo),
+ .destroy = connlabel_mt_destroy,
+ .me = THIS_MODULE,
+};
+
+static int __init connlabel_mt_init(void)
+{
+ return xt_register_match(&connlabels_mt_reg);
+}
+
+static void __exit connlabel_mt_exit(void)
+{
+ xt_unregister_match(&connlabels_mt_reg);
+}
+
+module_init(connlabel_mt_init);
+module_exit(connlabel_mt_exit);
--
1.7.8.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] netfilter: ctnetlink: deliver labels to userspace
2013-01-11 16:30 [PATCH next V2] netfilter connlabel extension Florian Westphal
2013-01-11 16:30 ` [PATCH 1/3] netfilter: add connlabel conntrack extension Florian Westphal
@ 2013-01-11 16:30 ` Florian Westphal
2013-01-17 23:38 ` Pablo Neira Ayuso
2013-01-11 16:30 ` [PATCH 3/3] netfilter: ctnetlink: allow userspace to modify labels Florian Westphal
2 siblings, 1 reply; 8+ messages in thread
From: Florian Westphal @ 2013-01-11 16:30 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Introduce CTA_LABELS attribute to send a bit-vector of currently active labels
to userspace.
Future patch will permit userspace to also set/delete active labels.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/uapi/linux/netfilter/nf_conntrack_common.h | 1 +
include/uapi/linux/netfilter/nfnetlink_conntrack.h | 1 +
net/netfilter/nf_conntrack_labels.c | 2 +-
net/netfilter/nf_conntrack_netlink.c | 41 ++++++++++++++++++++
4 files changed, 44 insertions(+), 1 deletions(-)
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index 1644cdd..d69483f 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -101,6 +101,7 @@ enum ip_conntrack_events {
IPCT_MARK, /* new mark has been set */
IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
IPCT_SECMARK, /* new security mark has been set */
+ IPCT_LABEL, /* new connlabel has been set */
};
enum ip_conntrack_expect_events {
diff --git a/include/uapi/linux/netfilter/nfnetlink_conntrack.h b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
index 86e930c..9e71e0c 100644
--- a/include/uapi/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
@@ -49,6 +49,7 @@ enum ctattr_type {
CTA_SECCTX,
CTA_TIMESTAMP,
CTA_MARK_MASK,
+ CTA_LABELS,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c
index 9fcf470..2a82236 100644
--- a/net/netfilter/nf_conntrack_labels.c
+++ b/net/netfilter/nf_conntrack_labels.c
@@ -46,7 +46,7 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit)
return 0;
if (test_and_set_bit(bit, labels->bits))
- return 0;
+ nf_conntrack_event_cache(IPCT_LABEL, ct);
return 0;
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 5bf95eb..005ab7e 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -324,6 +324,40 @@ nla_put_failure:
#define ctnetlink_dump_secctx(a, b) (0)
#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+static int ctnetlink_label_size(const struct nf_conn *ct)
+{
+ struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+ if (!labels)
+ return 0;
+ return nla_total_size(labels->words * sizeof(long));
+}
+
+static int
+ctnetlink_dump_labels(struct sk_buff *skb, const struct nf_conn *ct)
+{
+ struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+ unsigned int len, i;
+
+ if (!labels)
+ return 0;
+
+ len = labels->words * sizeof(long);
+ i = 0;
+ do {
+ if (labels->bits[i] != 0)
+ return nla_put(skb, CTA_LABELS, len, labels->bits);
+ i++;
+ } while (i < labels->words);
+
+ return 0;
+}
+#else
+#define ctnetlink_dump_labels(a, b) (0)
+#define ctnetlink_label_size(a) (0)
+#endif
+
#define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
static inline int
@@ -464,6 +498,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
ctnetlink_dump_helpinfo(skb, ct) < 0 ||
ctnetlink_dump_mark(skb, ct) < 0 ||
ctnetlink_dump_secctx(skb, ct) < 0 ||
+ ctnetlink_dump_labels(skb, ct) < 0 ||
ctnetlink_dump_id(skb, ct) < 0 ||
ctnetlink_dump_use(skb, ct) < 0 ||
ctnetlink_dump_master(skb, ct) < 0 ||
@@ -562,6 +597,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
+ nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
#endif
+ ctnetlink_proto_size(ct)
+ + ctnetlink_label_size(ct)
;
}
@@ -663,6 +699,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
&& ctnetlink_dump_secctx(skb, ct) < 0)
goto nla_put_failure;
#endif
+ if (events & (1 << IPCT_LABEL) &&
+ ctnetlink_dump_labels(skb, ct) < 0)
+ goto nla_put_failure;
if (events & (1 << IPCT_RELATED) &&
ctnetlink_dump_master(skb, ct) < 0)
@@ -1986,6 +2025,8 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
goto nla_put_failure;
#endif
+ if (ctnetlink_dump_labels(skb, ct) < 0)
+ goto nla_put_failure;
rcu_read_unlock();
return 0;
--
1.7.8.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/3] netfilter: ctnetlink: allow userspace to modify labels
2013-01-11 16:30 [PATCH next V2] netfilter connlabel extension Florian Westphal
2013-01-11 16:30 ` [PATCH 1/3] netfilter: add connlabel conntrack extension Florian Westphal
2013-01-11 16:30 ` [PATCH 2/3] netfilter: ctnetlink: deliver labels to userspace Florian Westphal
@ 2013-01-11 16:30 ` Florian Westphal
2013-01-17 23:39 ` Pablo Neira Ayuso
2 siblings, 1 reply; 8+ messages in thread
From: Florian Westphal @ 2013-01-11 16:30 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Add the ability to set/clear labels assigned to a conntrack
via ctnetlink.
To allow userspace to only alter specific bits, Pablo suggested to add
a new CTA_LABELS_MASK attribute:
The new set of active labels is then determined via
active = (active & ~mask) ^ changeset
i.e., the mask selects those bits in the existing set that should be
changed.
This follows the same method already used by MARK and CONNMARK targets.
Omitting CTA_LABELS_MASK is the same as setting all bits in CTA_LABELS_MASK
to 1: The existing set is replaced by the one from userspace.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/net/netfilter/nf_conntrack_labels.h | 3 +
include/uapi/linux/netfilter/nfnetlink_conntrack.h | 1 +
net/netfilter/nf_conntrack_labels.c | 43 +++++++++++++++++++
net/netfilter/nf_conntrack_netlink.c | 44 ++++++++++++++++++++
4 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h
index b94fe31..a3ce5d0 100644
--- a/include/net/netfilter/nf_conntrack_labels.h
+++ b/include/net/netfilter/nf_conntrack_labels.h
@@ -46,6 +46,9 @@ static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
bool nf_connlabel_match(const struct nf_conn *ct, u16 bit);
int nf_connlabel_set(struct nf_conn *ct, u16 bit);
+int nf_connlabels_replace(struct nf_conn *ct,
+ const u32 *data, const u32 *mask, unsigned int words);
+
#ifdef CONFIG_NF_CONNTRACK_LABELS
int nf_conntrack_labels_init(struct net *net);
void nf_conntrack_labels_fini(struct net *net);
diff --git a/include/uapi/linux/netfilter/nfnetlink_conntrack.h b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
index 9e71e0c..08fabc6 100644
--- a/include/uapi/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
@@ -50,6 +50,7 @@ enum ctattr_type {
CTA_TIMESTAMP,
CTA_MARK_MASK,
CTA_LABELS,
+ CTA_LABELS_MASK,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c
index 2a82236..c99bd11 100644
--- a/net/netfilter/nf_conntrack_labels.c
+++ b/net/netfilter/nf_conntrack_labels.c
@@ -52,6 +52,49 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit)
}
EXPORT_SYMBOL_GPL(nf_connlabel_set);
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
+static void replace_u32(u32 *address, u32 mask, u32 new)
+{
+ u32 old, tmp;
+
+ do {
+ old = *address;
+ tmp = (old & mask) ^ new;
+ } while (cmpxchg(address, old, tmp) != old);
+}
+
+int nf_connlabels_replace(struct nf_conn *ct,
+ const u32 *data,
+ const u32 *mask, unsigned int words32)
+{
+ struct nf_conn_labels *labels;
+ unsigned int size, i;
+ u32 *dst;
+
+ labels = nf_ct_labels_find(ct);
+ if (!labels)
+ return -ENOSPC;
+
+ size = labels->words * sizeof(long);
+ if (size < (words32 * sizeof(u32)))
+ words32 = size / sizeof(u32);
+
+ dst = (u32 *) labels->bits;
+ if (words32) {
+ for (i = 0; i < words32; i++)
+ replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
+ }
+
+ size /= sizeof(u32);
+ for (i = words32; i < size; i++) /* pad */
+ replace_u32(&dst[i], 0, 0);
+
+ nf_conntrack_event_cache(IPCT_LABEL, ct);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_connlabels_replace);
+#endif
+
static struct nf_ct_ext_type labels_extend __read_mostly = {
.len = sizeof(struct nf_conn_labels),
.align = __alignof__(struct nf_conn_labels),
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 005ab7e..c957fe2 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -961,6 +961,7 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
return 0;
}
+#define __CTA_LABELS_MAX_LENGTH ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
[CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
[CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
@@ -977,6 +978,10 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
[CTA_NAT_SEQ_ADJ_REPLY] = { .type = NLA_NESTED },
[CTA_ZONE] = { .type = NLA_U16 },
[CTA_MARK_MASK] = { .type = NLA_U32 },
+ [CTA_LABELS] = { .type = NLA_BINARY,
+ .len = __CTA_LABELS_MAX_LENGTH },
+ [CTA_LABELS_MASK] = { .type = NLA_BINARY,
+ .len = __CTA_LABELS_MAX_LENGTH },
};
static int
@@ -1505,6 +1510,31 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct,
#endif
static int
+ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[])
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+ size_t len = nla_len(cda[CTA_LABELS]);
+ const void *mask = cda[CTA_LABELS_MASK];
+
+ if (len & (sizeof(u32)-1)) /* must be multiple of u32 */
+ return -EINVAL;
+
+ if (mask) {
+ if (nla_len(cda[CTA_LABELS_MASK]) == 0 ||
+ nla_len(cda[CTA_LABELS_MASK]) != len)
+ return -EINVAL;
+ mask = nla_data(cda[CTA_LABELS_MASK]);
+ }
+
+ len /= sizeof(u32);
+
+ return nf_connlabels_replace(ct, nla_data(cda[CTA_LABELS]), mask, len);
+#else
+ return -EOPNOTSUPP;
+#endif
+}
+
+static int
ctnetlink_change_conntrack(struct nf_conn *ct,
const struct nlattr * const cda[])
{
@@ -1550,6 +1580,11 @@ ctnetlink_change_conntrack(struct nf_conn *ct,
return err;
}
#endif
+ if (cda[CTA_LABELS]) {
+ err = ctnetlink_attach_labels(ct, cda);
+ if (err < 0)
+ return err;
+ }
return 0;
}
@@ -1758,6 +1793,10 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
else
events = IPCT_NEW;
+ if (cda[CTA_LABELS] &&
+ ctnetlink_attach_labels(ct, cda) == 0)
+ events |= (1 << IPCT_LABEL);
+
nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
(1 << IPCT_ASSURED) |
(1 << IPCT_HELPER) |
@@ -2055,6 +2094,11 @@ ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
if (err < 0)
return err;
}
+ if (cda[CTA_LABELS]) {
+ err = ctnetlink_attach_labels(ct, cda);
+ if (err < 0)
+ return err;
+ }
#if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK])
ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
--
1.7.8.6
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/3] netfilter: add connlabel conntrack extension
2013-01-11 16:30 ` [PATCH 1/3] netfilter: add connlabel conntrack extension Florian Westphal
@ 2013-01-17 23:37 ` Pablo Neira Ayuso
0 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2013-01-17 23:37 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Fri, Jan 11, 2013 at 05:30:44PM +0100, Florian Westphal wrote:
> similar to connmarks, except labels are bit-based; i.e.
> all labels may be attached to a flow at the same time.
>
> Up to 128 labels are supported. Supporting more labels
> is possible, but requires increasing the ct offset delta
> from u8 to u16 type due to increased extension sizes.
>
> Mapping of bit-identifier to label name is done in userspace.
>
> The extension is enabled at run-time once "-m connlabel" netfilter
> rules are added.
Applied, thanks.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] netfilter: ctnetlink: deliver labels to userspace
2013-01-11 16:30 ` [PATCH 2/3] netfilter: ctnetlink: deliver labels to userspace Florian Westphal
@ 2013-01-17 23:38 ` Pablo Neira Ayuso
0 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2013-01-17 23:38 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Fri, Jan 11, 2013 at 05:30:45PM +0100, Florian Westphal wrote:
> Introduce CTA_LABELS attribute to send a bit-vector of currently active labels
> to userspace.
>
> Future patch will permit userspace to also set/delete active labels.
Applied, thanks.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] netfilter: ctnetlink: allow userspace to modify labels
2013-01-11 16:30 ` [PATCH 3/3] netfilter: ctnetlink: allow userspace to modify labels Florian Westphal
@ 2013-01-17 23:39 ` Pablo Neira Ayuso
0 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2013-01-17 23:39 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Fri, Jan 11, 2013 at 05:30:46PM +0100, Florian Westphal wrote:
> Add the ability to set/clear labels assigned to a conntrack
> via ctnetlink.
>
> To allow userspace to only alter specific bits, Pablo suggested to add
> a new CTA_LABELS_MASK attribute:
>
> The new set of active labels is then determined via
>
> active = (active & ~mask) ^ changeset
>
> i.e., the mask selects those bits in the existing set that should be
> changed.
>
> This follows the same method already used by MARK and CONNMARK targets.
>
> Omitting CTA_LABELS_MASK is the same as setting all bits in CTA_LABELS_MASK
> to 1: The existing set is replaced by the one from userspace.
And this also applied, thanks Florian.
You can push the user-space changes for this into some new -next
branch of each tree. Then merge it to master by when 3.9-rc1 is
released.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2013-01-17 23:39 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-11 16:30 [PATCH next V2] netfilter connlabel extension Florian Westphal
2013-01-11 16:30 ` [PATCH 1/3] netfilter: add connlabel conntrack extension Florian Westphal
2013-01-17 23:37 ` Pablo Neira Ayuso
2013-01-11 16:30 ` [PATCH 2/3] netfilter: ctnetlink: deliver labels to userspace Florian Westphal
2013-01-17 23:38 ` Pablo Neira Ayuso
2013-01-11 16:30 ` [PATCH 3/3] netfilter: ctnetlink: allow userspace to modify labels Florian Westphal
2013-01-17 23:39 ` Pablo Neira Ayuso
-- strict thread matches above, loose matches on Subject: below --
2012-11-15 15:55 [PATCH 0/3] netfilter: add connlabel conntrack extension Florian Westphal
2012-11-15 15:55 ` [PATCH 1/3] " Florian Westphal
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).