All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] libnetfilter_conntrack: add connlabel support
@ 2012-11-15 15:50 Florian Westphal
  2012-11-15 15:50 ` [PATCH 1/3] api: add nfct_bitmask object Florian Westphal
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Florian Westphal @ 2012-11-15 15:50 UTC (permalink / raw)
  To: netfilter-devel

The following three patches add support for the planned
connlabel extension to libnetfilter_conntrack.

I've tried to add Pablos feedback/ideas, thus:
- a new nfct_bitmask object is added, plus
  interfaces to test/set such bits
- 2nd patch adds functions to create/inspect a
  name <-> bit mapping table
- setting/retrieving the connlabels is done
  with the existing nfct_get/set_attr interface, so
  no new interface for that.

Caveats:
- I only wired CTA_LABELS up with the libmnl-based API
- I only made a very brief test of this code (using
  the example programs).

Please let me know if there are any remaining issues
with the chosen approach.

summary of changes:
examples/Makefile.am                                       |   10 
examples/nfct-mnl-dump-labels.c                            |  103 +++++
examples/nfct-mnl-set-label.c                              |  170 +++++++++
include/internal/bitops.h                                  |    2 
include/internal/object.h                                  |   12 
include/internal/prototypes.h                              |    9 
include/libnetfilter_conntrack/libnetfilter_conntrack.h    |   20 +
include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h |    1 
src/conntrack/Makefile.am                                  |    1 
src/conntrack/api.c                                        |  164 ++++++++
src/conntrack/build_mnl.c                                  |   12 
src/conntrack/getter.c                                     |    6 
src/conntrack/labels.c                                     |  239 +++++++++++++
src/conntrack/parse.c                                      |    1 
src/conntrack/parse_mnl.c                                  |   25 +
src/conntrack/setter.c                                     |   12 
16 files changed, 787 insertions(+)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] api: add nfct_bitmask object
  2012-11-15 15:50 [PATCH 0/3] libnetfilter_conntrack: add connlabel support Florian Westphal
@ 2012-11-15 15:50 ` Florian Westphal
  2012-11-15 15:50 ` [PATCH 2/3] api: add connlabel api and attribute Florian Westphal
  2012-11-15 15:50 ` [PATCH 3/3] examples: add connlabel dump/set/clear demo programs Florian Westphal
  2 siblings, 0 replies; 5+ messages in thread
From: Florian Westphal @ 2012-11-15 15:50 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

In order to use generic getter/setter API with upcoming
conntrack label extension, add  helper functions to set/test/unset
bits in a vector of arbitrary size.

Conntrack labels will then be encoded via nfct_bitmask object.

Original idea from Pablo Neira Ayuso.
---
 include/internal/bitops.h                          |    2 +
 include/internal/object.h                          |    8 ++
 .../libnetfilter_conntrack.h                       |   11 ++
 src/conntrack/api.c                                |   99 ++++++++++++++++++++
 4 files changed, 120 insertions(+), 0 deletions(-)

diff --git a/include/internal/bitops.h b/include/internal/bitops.h
index 7ae566b..aefff0e 100644
--- a/include/internal/bitops.h
+++ b/include/internal/bitops.h
@@ -73,4 +73,6 @@ test_bitmask_u32_or(const uint32_t *buf1, const uint32_t *buf2, int len)
 	return 0;
 }
 
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
 #endif
diff --git a/include/internal/object.h b/include/internal/object.h
index 443e800..609265d 100644
--- a/include/internal/object.h
+++ b/include/internal/object.h
@@ -297,4 +297,12 @@ struct nf_expect {
 	u_int32_t 		set[1];
 };
 
+/*
+ * bitmask object
+ */
+struct nfct_bitmask {
+	unsigned int words;
+	uint32_t bits[];
+};
+
 #endif
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
index 12f61d1..97e2dd7 100644
--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
@@ -273,6 +273,17 @@ enum {
 	NFCT_CB_STOLEN = 2,     /* like continue, but ct is not freed */
 };
 
+/* bitmask setter/getter */
+struct nfct_bitmask;
+
+struct nfct_bitmask *nfct_bitmask_new(unsigned int maxbit);
+unsigned int nfct_bitmask_maxbit(const struct nfct_bitmask *);
+
+void nfct_bitmask_set_bit(struct nfct_bitmask *, unsigned int bit);
+int nfct_bitmask_test_bit(const struct nfct_bitmask *, unsigned int bit);
+void nfct_bitmask_unset_bit(struct nfct_bitmask *, unsigned int bit);
+void nfct_bitmask_destroy(struct nfct_bitmask *);
+
 /* setter */
 extern void nfct_set_attr(struct nf_conntrack *ct,
 			  const enum nf_conntrack_attr type,
diff --git a/src/conntrack/api.c b/src/conntrack/api.c
index 000571f..f1fcdc4 100644
--- a/src/conntrack/api.c
+++ b/src/conntrack/api.c
@@ -1483,3 +1483,102 @@ void nfct_filter_dump_set_attr_u8(struct nfct_filter_dump *filter_dump,
 /**
  * @}
  */
+
+/**
+ * \defgroup bitmask bitmask object
+ *
+ * @{
+ */
+
+/**
+ * nfct_bitmask_new - allocate a new bitmask
+ *
+ * \param max highest valid bit that can be set/unset.
+ *
+ * In case of success, this function returns a valid pointer to a memory blob,
+ * otherwise NULL is returned and errno is set appropiately.
+ */
+struct nfct_bitmask *nfct_bitmask_new(unsigned int max)
+{
+	struct nfct_bitmask *b;
+	unsigned int bytes, words;
+
+	if (max > 0xffff)
+		return NULL;
+
+	words = DIV_ROUND_UP(max+1, 32);
+	bytes = words * sizeof(b->bits[0]);
+
+	b = malloc(sizeof(struct nfct_bitmask) + bytes);
+	if (b) {
+		memset(b->bits, 0, bytes);
+		b->words = words;
+	}
+	return b;
+}
+
+/*
+ * nfct_bitmask_set_bit - set bit in the bitmask
+ *
+ * \param b pointer to the bitmask object
+ * \param bit the bit to set
+ */
+void nfct_bitmask_set_bit(struct nfct_bitmask *b, unsigned int bit)
+{
+	unsigned int bits = b->words * 32;
+	if (bit < bits)
+		set_bit(bit, b->bits);
+}
+
+/*
+ * nfct_bitmask_test_bit - test if a bit in the bitmask is set
+ *
+ * \param b pointer to the bitmask object
+ * \param bit the bit to test
+ *
+ * returns 0 if the bit is not set.
+ */
+int nfct_bitmask_test_bit(const struct nfct_bitmask *b, unsigned int bit)
+{
+	unsigned int bits = b->words * 32;
+	return bit < bits && test_bit(bit, b->bits);
+}
+
+/*
+ * nfct_bitmask_unset_bit - unset bit in the bitmask
+ *
+ * \param b pointer to the bitmask object
+ * \param bit the bit to clear
+ */
+void nfct_bitmask_unset_bit(struct nfct_bitmask *b, unsigned int bit)
+{
+	unsigned int bits = b->words * 32;
+	if (bit < bits)
+		unset_bit(bit, b->bits);
+}
+
+/*
+ * nfct_bitmask_maxbit - return highest bit that may be set/unset
+ *
+ * \param b pointer to the bitmask object
+ */
+unsigned int nfct_bitmask_maxbit(const struct nfct_bitmask *b)
+{
+	return (b->words * 32) - 1;
+}
+
+/*
+ * nfct_bitmask_destroy - destroy bitmask object
+ *
+ * \param b pointer to the bitmask object
+ *
+ * This function releases the memory that is used by the bitmask object.
+ */
+void nfct_bitmask_destroy(struct nfct_bitmask *b)
+{
+	free(b);
+}
+
+/**
+ * @}
+ */
-- 
1.7.8.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] api: add connlabel api and attribute
  2012-11-15 15:50 [PATCH 0/3] libnetfilter_conntrack: add connlabel support Florian Westphal
  2012-11-15 15:50 ` [PATCH 1/3] api: add nfct_bitmask object Florian Westphal
@ 2012-11-15 15:50 ` Florian Westphal
  2012-11-15 21:07   ` Florian Westphal
  2012-11-15 15:50 ` [PATCH 3/3] examples: add connlabel dump/set/clear demo programs Florian Westphal
  2 siblings, 1 reply; 5+ messages in thread
From: Florian Westphal @ 2012-11-15 15:50 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

adds new labelmap api to create a name <-> bit mapping
from a text file (default: /etc/xtables/connlabel.conf).

nfct_labelmap_new(filename) is used to create the map,
nfct_labelmap_destroy() releases the resources allocated for the map.

Two functions are added to make map lookups:

nfct_labelmap_get_name(map, bit) returns the name of a bit,
nfct_labelmap_get_bit returns the bit associated with a name.

The connlabel attribute is represented by a nfct_bitmask object, the
nfct_bitmask api can be used to test/set/get individual bits
("labels").

The exisiting nfct_attr_get/set interfaces can be used to read or
replace the existing labels associated with a conntrack with a new set.
---
 include/internal/object.h                          |    4 +
 include/internal/prototypes.h                      |    9 +
 .../libnetfilter_conntrack.h                       |    9 +
 .../linux_nfnetlink_conntrack.h                    |    1 +
 src/conntrack/Makefile.am                          |    1 +
 src/conntrack/api.c                                |   65 ++++++
 src/conntrack/build_mnl.c                          |   12 +
 src/conntrack/getter.c                             |    6 +
 src/conntrack/labels.c                             |  239 ++++++++++++++++++++
 src/conntrack/parse.c                              |    1 +
 src/conntrack/parse_mnl.c                          |   25 ++
 src/conntrack/setter.c                             |   12 +
 12 files changed, 384 insertions(+), 0 deletions(-)
 create mode 100644 src/conntrack/labels.c

diff --git a/include/internal/object.h b/include/internal/object.h
index 609265d..bbb038a 100644
--- a/include/internal/object.h
+++ b/include/internal/object.h
@@ -189,6 +189,8 @@ struct nf_conntrack {
 
 	void *helper_info;
 	size_t helper_info_len;
+
+	struct nfct_bitmask *connlabels;
 };
 
 /*
@@ -305,4 +307,6 @@ struct nfct_bitmask {
 	uint32_t bits[];
 };
 
+struct nfct_labelmap;
+
 #endif
diff --git a/include/internal/prototypes.h b/include/internal/prototypes.h
index eeeea24..484deea 100644
--- a/include/internal/prototypes.h
+++ b/include/internal/prototypes.h
@@ -54,4 +54,13 @@ int __snprintf_expect(char *buf, unsigned int len, const struct nf_expect *exp,
 int __snprintf_expect_default(char *buf, unsigned int len, const struct nf_expect *exp, unsigned int msg_type, unsigned int flags);
 int __snprintf_expect_xml(char *buf, unsigned int len, const struct nf_expect *exp, unsigned int msg_type, unsigned int flags);
 
+/*
+ * connlabel internal prototypes
+ */
+struct nfct_labelmap *__labelmap_new(const char *);
+void __labelmap_destroy(struct nfct_labelmap *);
+
+int __labelmap_get_bit(struct nfct_labelmap *map, const char *name);
+const char *__labelmap_get_name(struct nfct_labelmap *map, unsigned int bit);
+
 #endif
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
index 97e2dd7..e3b1f47 100644
--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
@@ -133,6 +133,7 @@ enum nf_conntrack_attr {
 	ATTR_TIMESTAMP_START,			/* u64 bits, linux >= 2.6.38 */
 	ATTR_TIMESTAMP_STOP = 64,		/* u64 bits, linux >= 2.6.38 */
 	ATTR_HELPER_INFO,			/* variable length */
+	ATTR_CONNLABELS,			/* variable length */
 	ATTR_MAX
 };
 
@@ -284,6 +285,14 @@ int nfct_bitmask_test_bit(const struct nfct_bitmask *, unsigned int bit);
 void nfct_bitmask_unset_bit(struct nfct_bitmask *, unsigned int bit);
 void nfct_bitmask_destroy(struct nfct_bitmask *);
 
+/* connlabel name <-> bit translation mapping */
+struct nfct_labelmap;
+
+struct nfct_labelmap *nfct_labelmap_new(const char *mapfile);
+void nfct_labelmap_destroy(struct nfct_labelmap *map);
+const char *nfct_labelmap_get_name(struct nfct_labelmap *m, unsigned int bit);
+int nfct_labelmap_get_bit(struct nfct_labelmap *m, const char *name);
+
 /* setter */
 extern void nfct_set_attr(struct nf_conntrack *ct,
 			  const enum nf_conntrack_attr type,
diff --git a/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h b/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
index 1e32c7f..fab40ae 100644
--- a/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
+++ b/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
@@ -51,6 +51,7 @@ enum ctattr_type {
 	CTA_SECCTX,
 	CTA_TIMESTAMP,
 	CTA_MARK_MASK,
+	CTA_LABELS,
 	__CTA_MAX
 };
 #define CTA_MAX (__CTA_MAX - 1)
diff --git a/src/conntrack/Makefile.am b/src/conntrack/Makefile.am
index 01fed53..e1d8768 100644
--- a/src/conntrack/Makefile.am
+++ b/src/conntrack/Makefile.am
@@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libnfconntrack.la
 
 libnfconntrack_la_SOURCES = api.c \
 			    getter.c setter.c \
+			    labels.c \
 			    parse.c build.c \
 			    parse_mnl.c build_mnl.c \
 			    snprintf.c \
diff --git a/src/conntrack/api.c b/src/conntrack/api.c
index f1fcdc4..6dd7675 100644
--- a/src/conntrack/api.c
+++ b/src/conntrack/api.c
@@ -95,6 +95,8 @@ void nfct_destroy(struct nf_conntrack *ct)
 		free(ct->secctx);
 	if (ct->helper_info)
 		free(ct->helper_info);
+	if (ct->connlabels)
+		nfct_bitmask_destroy(ct->connlabels);
 	free(ct);
 	ct = NULL; /* bugtrap */
 }
@@ -1485,6 +1487,69 @@ void nfct_filter_dump_set_attr_u8(struct nfct_filter_dump *filter_dump,
  */
 
 /**
+ * \defgroup label Conntrack labels
+ *
+ * @{
+ */
+
+/**
+ * nfct_labelmap_get_name - get name of the label bit
+ *
+ * \param m label map obtained from nfct_label_open
+ * \param bit whose name should be returned
+ *
+ * returns a pointer to the name associated with the label.
+ * If no name has been configured, the empty string is returned.
+ * If bit is out of range, NULL is returned.
+ */
+const char *nfct_labelmap_get_name(struct nfct_labelmap *m, unsigned int bit)
+{
+	return __labelmap_get_name(m, bit);
+}
+
+/**
+ * nfct_labelmap_get_bit - get bit associated with the name
+ *
+ * \param h label handle obtained from nfct_labelmap_new
+ * \param name name of the label
+ *
+ * returns the bit associated with the name, or negative value on error.
+ */
+int nfct_labelmap_get_bit(struct nfct_labelmap *m, const char *name)
+{
+	return __labelmap_get_bit(m, name);
+}
+
+/**
+ * nfct_labelmap_new - create a new label map
+ *
+ * \param mapfile the file containing the bit <-> name mapping
+ *
+ * If mapfile is NULL, the default mapping file is used.
+ * returns a new label map, or NULL on error.
+ */
+struct nfct_labelmap *nfct_labelmap_new(const char *mapfile)
+{
+	return __labelmap_new(mapfile);
+}
+
+/**
+ * nfct_labelmap_destroy - destroy nfct_labelmap object
+ *
+ * \param map the label object to destroy.
+ *
+ * This function releases the memory that is used by the labelmap object.
+ */
+void nfct_labelmap_destroy(struct nfct_labelmap *map)
+{
+	__labelmap_destroy(map);
+}
+
+/**
+ * @}
+ */
+
+/*
  * \defgroup bitmask bitmask object
  *
  * @{
diff --git a/src/conntrack/build_mnl.c b/src/conntrack/build_mnl.c
index 46aec8a..a666e01 100644
--- a/src/conntrack/build_mnl.c
+++ b/src/conntrack/build_mnl.c
@@ -10,6 +10,7 @@
  */
 
 #include "internal/internal.h"
+#include <limits.h>
 #include <libmnl/libmnl.h>
 
 static int
@@ -379,6 +380,14 @@ nfct_build_zone(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
 	return 0;
 }
 
+static void
+nfct_build_labels(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
+{
+	struct nfct_bitmask *b = ct->connlabels;
+	unsigned int size = b->words * sizeof(b->bits[0]);
+	mnl_attr_put(nlh, CTA_LABELS, size, b->bits);
+}
+
 int
 nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
 {
@@ -475,5 +484,8 @@ nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
 	if (test_bit(ATTR_ZONE, ct->head.set))
 		nfct_build_zone(nlh, ct);
 
+	if (test_bit(ATTR_CONNLABELS, ct->head.set))
+		nfct_build_labels(nlh, ct);
+
 	return 0;
 }
diff --git a/src/conntrack/getter.c b/src/conntrack/getter.c
index e7ab048..53c9e0e 100644
--- a/src/conntrack/getter.c
+++ b/src/conntrack/getter.c
@@ -339,6 +339,11 @@ static const void *get_attr_helper_info(const struct nf_conntrack *ct)
 	return ct->helper_info;
 }
 
+static const void *get_attr_connlabels(const struct nf_conntrack *ct)
+{
+	return ct->connlabels;
+}
+
 const get_attr get_attr_array[ATTR_MAX] = {
 	[ATTR_ORIG_IPV4_SRC]		= get_attr_orig_ipv4_src,
 	[ATTR_ORIG_IPV4_DST] 		= get_attr_orig_ipv4_dst,
@@ -406,4 +411,5 @@ const get_attr get_attr_array[ATTR_MAX] = {
 	[ATTR_TIMESTAMP_START]		= get_attr_timestamp_start,
 	[ATTR_TIMESTAMP_STOP]		= get_attr_timestamp_stop,
 	[ATTR_HELPER_INFO]		= get_attr_helper_info,
+	[ATTR_CONNLABELS]		= get_attr_connlabels,
 };
diff --git a/src/conntrack/labels.c b/src/conntrack/labels.c
new file mode 100644
index 0000000..b64995f
--- /dev/null
+++ b/src/conntrack/labels.c
@@ -0,0 +1,239 @@
+#include <stdint.h>
+
+#include "internal/internal.h"
+
+#define MAX_BITS 1024
+
+#define CONNLABEL_CFG "/etc/xtables/connlabel.conf"
+#define HASH_SIZE 64
+
+struct labelmap_bucket {
+	char *name;
+	unsigned int bit;
+	struct labelmap_bucket *next;
+};
+
+struct nfct_labelmap {
+	struct labelmap_bucket *map_name[HASH_SIZE];
+	unsigned int namecount;
+	char **bit_to_name;
+};
+
+static struct labelmap_bucket* label_map_bucket_alloc(const char *n, unsigned int b)
+{
+	struct labelmap_bucket *bucket;
+	char *name = strdup(n);
+
+	if (!name)
+		return NULL;
+
+	bucket = malloc(sizeof(*bucket));
+	if (!bucket) {
+		free(name);
+		return NULL;
+	}
+	bucket->name = name;
+	bucket->bit = b;
+	return bucket;
+}
+
+static unsigned int hash_name(const char *name)
+{
+	unsigned int hash = 0;
+
+	while (*name) {
+		hash = (hash << 5) - hash + *name;
+		name++;
+	}
+	return hash & (HASH_SIZE - 1);
+}
+
+int __labelmap_get_bit(struct nfct_labelmap *m, const char *name)
+{
+	unsigned int i = hash_name(name);
+	struct labelmap_bucket *list = m->map_name[i];
+
+	while (list) {
+		if (strcmp(name, list->name) == 0)
+			return list->bit;
+		list = list->next;
+	}
+	return -1;
+}
+
+const char *__labelmap_get_name(struct nfct_labelmap *m, unsigned int bit)
+{
+	if (bit < m->namecount)
+		return m->bit_to_name[bit] ? m->bit_to_name[bit] : "";
+	return NULL;
+}
+
+static int map_insert(struct nfct_labelmap *m, const char *n, unsigned int b)
+{
+	unsigned int i = hash_name(n);
+	struct labelmap_bucket *list = m->map_name[i];
+
+	while (list) {
+		if (list->bit == b)
+			return -1;
+		list = list->next;
+	}
+
+	list = label_map_bucket_alloc(n, b);
+	if (!list)
+		return -1;
+
+	if (m->map_name[i])
+		list->next = m->map_name[i];
+	else
+		list->next = NULL;
+	m->map_name[i] = list;
+	return 0;
+}
+
+static int is_space_posix(int c)
+{
+	return c == ' ' || c == '\f' || c == '\r' || c == '\t' || c == '\v';
+}
+
+static char *trim_label(char *label)
+{
+	char *end;
+
+	while (is_space_posix(*label))
+		label++;
+	end = strchr(label, '\n');
+	if (end)
+		*end = 0;
+	else
+		end = strchr(label, '\0');
+	end--;
+
+	while (is_space_posix(*end) && end > label) {
+		*end = 0;
+		end--;
+	}
+
+	return *label ? label : NULL;
+}
+
+static int
+xtables_parse_connlabel_numerical(const char *s, char **end)
+{
+	unsigned long value;
+
+	value = strtoul(s, end, 0);
+	if (value == 0 && s == *end)
+		return -1;
+	if (value < 0 || value >= MAX_BITS)
+		return -1;
+	return value;
+}
+
+static void free_list(struct labelmap_bucket *b)
+{
+	if (b->next)
+		free_list(b->next);
+	free(b->name);
+	free(b);
+}
+
+void __labelmap_destroy(struct nfct_labelmap *map)
+{
+	unsigned int i;
+	struct labelmap_bucket *b;
+
+	for (i = 0; i < HASH_SIZE; i++) {
+		b = map->map_name[i];
+		if (b != NULL)
+			free_list(b);
+	}
+
+	free(map->bit_to_name);
+	free(map);
+}
+
+static void make_name_table(struct nfct_labelmap *m)
+{
+	struct labelmap_bucket *b;
+	unsigned int i;
+
+	for (i = 0; i < HASH_SIZE; i++) {
+		b = m->map_name[i];
+		while (b) {
+			m->bit_to_name[b->bit] = b->name;
+			b = b->next;
+		}
+	}
+}
+
+static struct nfct_labelmap *map_alloc(void)
+{
+	struct nfct_labelmap *map = malloc(sizeof(*map));
+	if (map) {
+		unsigned int i;
+		for (i = 0; i < HASH_SIZE; i++)
+			map->map_name[i] = NULL;
+	}
+	return map;
+}
+
+struct nfct_labelmap *__labelmap_new(const char *name)
+{
+	struct nfct_labelmap *map;
+	char label[1024];
+	char *end;
+	FILE *fp;
+	int added = 0;
+	unsigned int maxbit = 0;
+	uint32_t bits_seen[MAX_BITS/32];
+
+	fp = fopen(name ? name : CONNLABEL_CFG, "re");
+	if (!fp)
+		return NULL;
+
+	memset(bits_seen, 0, sizeof(bits_seen));
+
+	map = map_alloc();
+	if (!map) {
+		fclose(fp);
+		return NULL;
+	}
+
+	while (fgets(label, sizeof(label), fp)) {
+		int bit;
+
+		if (label[0] == '#')
+			continue;
+
+		bit = xtables_parse_connlabel_numerical(label, &end);
+		if (bit < 0 || test_bit(bit, bits_seen))
+			continue;
+
+		end = trim_label(end);
+		if (!end)
+			continue;
+		if (map_insert(map, end, bit) == 0) {
+			added++;
+			if (maxbit < bit)
+				maxbit = bit;
+			set_bit(bit, bits_seen);
+		}
+	}
+
+	fclose(fp);
+
+	if (added) {
+		map->namecount = maxbit + 1;
+		map->bit_to_name = calloc(sizeof(char *), map->namecount);
+		if (!map->bit_to_name)
+			goto err;
+		make_name_table(map);
+		return map;
+	}
+ err:
+	__labelmap_destroy(map);
+	return NULL;
+}
+
+
diff --git a/src/conntrack/parse.c b/src/conntrack/parse.c
index b9f9a99..6096e8d 100644
--- a/src/conntrack/parse.c
+++ b/src/conntrack/parse.c
@@ -8,6 +8,7 @@
  */
 
 #include "internal/internal.h"
+#include <libmnl/libmnl.h>
 
 static void __parse_ip(const struct nfattr *attr,
 		       struct __nfct_tuple *tuple,
diff --git a/src/conntrack/parse_mnl.c b/src/conntrack/parse_mnl.c
index 93f6681..a4272f9 100644
--- a/src/conntrack/parse_mnl.c
+++ b/src/conntrack/parse_mnl.c
@@ -11,6 +11,7 @@
 
 #include "internal/internal.h"
 #include <libmnl/libmnl.h>
+#include <limits.h>
 #include <endian.h>
 
 static int
@@ -772,6 +773,25 @@ nfct_parse_timestamp(const struct nlattr *attr, struct nf_conntrack *ct)
 	return 0;
 }
 
+static int nfct_parse_labels(const struct nlattr *attr, struct nf_conntrack *ct)
+{
+	uint16_t len = mnl_attr_get_payload_len(attr);
+	struct nfct_bitmask *mask;
+	uint32_t *bits;
+
+	if (len == 0)
+		return 0;
+
+	mask = nfct_bitmask_new((len * CHAR_BIT) - 1);
+	if (!mask)
+		return -1;
+	bits = mnl_attr_get_payload(attr);
+	if (len)
+		memcpy(mask->bits, bits, len);
+	nfct_set_attr(ct, ATTR_CONNLABELS, mask);
+	return 0;
+}
+
 static int
 nfct_parse_conntrack_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -934,6 +954,11 @@ nfct_payload_parse(const void *payload, size_t payload_len,
 			return -1;
 	}
 
+	if (tb[CTA_LABELS]) {
+		if (nfct_parse_labels(tb[CTA_LABELS], ct) < 0)
+			return -1;
+	}
+
 	return 0;
 }
 
diff --git a/src/conntrack/setter.c b/src/conntrack/setter.c
index dbcd68e..8879f02 100644
--- a/src/conntrack/setter.c
+++ b/src/conntrack/setter.c
@@ -421,6 +421,17 @@ retry:
 }
 
 static void
+set_attr_connlabels(struct nf_conntrack *ct, const void *value, size_t len)
+{
+	if (ct->connlabels == value)
+		return;
+
+	if (ct->connlabels)
+		nfct_bitmask_destroy(ct->connlabels);
+	ct->connlabels = (void *) value;
+}
+
+static void
 set_attr_do_nothing(struct nf_conntrack *ct, const void *value, size_t len) {}
 
 const set_attr set_attr_array[ATTR_MAX] = {
@@ -490,4 +501,5 @@ const set_attr set_attr_array[ATTR_MAX] = {
 	[ATTR_TIMESTAMP_START]	= set_attr_do_nothing,
 	[ATTR_TIMESTAMP_STOP]	= set_attr_do_nothing,
 	[ATTR_HELPER_INFO]	= set_attr_helper_info,
+	[ATTR_CONNLABELS]	= set_attr_connlabels,
 };
-- 
1.7.8.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] examples: add connlabel dump/set/clear demo programs
  2012-11-15 15:50 [PATCH 0/3] libnetfilter_conntrack: add connlabel support Florian Westphal
  2012-11-15 15:50 ` [PATCH 1/3] api: add nfct_bitmask object Florian Westphal
  2012-11-15 15:50 ` [PATCH 2/3] api: add connlabel api and attribute Florian Westphal
@ 2012-11-15 15:50 ` Florian Westphal
  2 siblings, 0 replies; 5+ messages in thread
From: Florian Westphal @ 2012-11-15 15:50 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

---
 examples/Makefile.am            |   10 +++
 examples/nfct-mnl-dump-labels.c |  103 +++++++++++++++++++++++
 examples/nfct-mnl-set-label.c   |  170 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 283 insertions(+), 0 deletions(-)
 create mode 100644 examples/nfct-mnl-dump-labels.c
 create mode 100644 examples/nfct-mnl-set-label.c

diff --git a/examples/Makefile.am b/examples/Makefile.am
index 55bd750..a366390 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -3,6 +3,8 @@ include $(top_srcdir)/Make_global.am
 check_PROGRAMS = nfct-mnl-create	\
 		 nfct-mnl-del		\
 		 nfct-mnl-dump		\
+		 nfct-mnl-dump-labels	\
+		 nfct-mnl-set-label	\
 		 nfct-mnl-event		\
 		 nfct-mnl-flush		\
 		 nfct-mnl-get		\
@@ -21,6 +23,14 @@ nfct_mnl_dump_SOURCES = nfct-mnl-dump.c
 nfct_mnl_dump_LDADD = ../src/libnetfilter_conntrack.la
 nfct_mnl_dump_LDFLAGS = -dynamic -ldl -lmnl
 
+nfct_mnl_dump_labels_SOURCES = nfct-mnl-dump-labels.c
+nfct_mnl_dump_labels_LDADD = ../src/libnetfilter_conntrack.la
+nfct_mnl_dump_labels_LDFLAGS = -dynamic -ldl -lmnl
+
+nfct_mnl_set_label_SOURCES = nfct-mnl-set-label.c
+nfct_mnl_set_label_LDADD = ../src/libnetfilter_conntrack.la
+nfct_mnl_set_label_LDFLAGS = -dynamic -ldl -lmnl
+
 nfct_mnl_event_SOURCES = nfct-mnl-event.c
 nfct_mnl_event_LDADD = ../src/libnetfilter_conntrack.la
 nfct_mnl_event_LDFLAGS = -dynamic -ldl -lmnl
diff --git a/examples/nfct-mnl-dump-labels.c b/examples/nfct-mnl-dump-labels.c
new file mode 100644
index 0000000..babb928
--- /dev/null
+++ b/examples/nfct-mnl-dump-labels.c
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <libmnl/libmnl.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+static void print_label(struct nf_conntrack *ct, struct nfct_labelmap *map)
+{
+	unsigned int i, max;
+	const struct nfct_bitmask *b = nfct_get_attr(ct, ATTR_CONNLABELS);
+	if (!b)
+		return;
+
+	puts("labels:");
+	max = nfct_bitmask_maxbit(b);
+	for (i = 0; i <= max; i++) {
+		if (nfct_bitmask_test_bit(b, i))
+			printf("\t'%s' (%d)\n", map ? nfct_labelmap_get_name(map, i) : "", i);
+	}
+}
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nf_conntrack *ct;
+	char buf[4096];
+
+	ct = nfct_new();
+	if (ct == NULL)
+		return MNL_CB_OK;
+
+	nfct_nlmsg_parse(nlh, ct);
+
+	nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0);
+	printf("%s\n", buf);
+
+	print_label(ct, data);
+
+	nfct_destroy(ct);
+
+	return MNL_CB_OK;
+}
+
+int main(void)
+{
+	struct mnl_socket *nl;
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfh;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	unsigned int seq, portid;
+	int ret;
+	struct nfct_labelmap *l = nfct_labelmap_new(NULL);
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL) {
+		perror("mnl_socket_open");
+		exit(EXIT_FAILURE);
+	}
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+		perror("mnl_socket_bind");
+		exit(EXIT_FAILURE);
+	}
+	portid = mnl_socket_get_portid(nl);
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
+	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+	nlh->nlmsg_seq = seq = time(NULL);
+
+	nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+	nfh->nfgen_family = AF_UNSPEC;
+	nfh->version = NFNETLINK_V0;
+	nfh->res_id = 0;
+
+
+	ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
+	if (ret == -1) {
+		perror("mnl_socket_recvfrom");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+
+
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, seq, portid, data_cb, l);
+		if (ret <= MNL_CB_STOP)
+			break;
+		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	}
+	if (ret == -1) {
+		perror("mnl_socket_recvfrom");
+		exit(EXIT_FAILURE);
+	}
+
+	if (l)
+		nfct_labelmap_destroy(l);
+
+	mnl_socket_close(nl);
+
+	return 0;
+}
diff --git a/examples/nfct-mnl-set-label.c b/examples/nfct-mnl-set-label.c
new file mode 100644
index 0000000..dd52011
--- /dev/null
+++ b/examples/nfct-mnl-set-label.c
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <libmnl/libmnl.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+struct callback_args {
+	struct mnl_socket *nl;
+	unsigned int seq;
+	int bit;
+};
+
+static void set_label(struct nf_conntrack *ct, struct callback_args *cbargs)
+{
+	struct nfct_bitmask *b = (void *) nfct_get_attr(ct, ATTR_CONNLABELS);
+	int bit = cbargs->bit;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfh;
+
+	if (b) {
+		if (bit >= 0 && nfct_bitmask_test_bit(b, bit))
+			return;
+	} else if (bit < 0)
+		return;
+
+	b = nfct_bitmask_new(bit < 0 ? 0 : bit);
+	if (!b)
+		return;
+	if (bit >= 0)
+		nfct_bitmask_set_bit(b, bit);
+	nfct_set_attr(ct, ATTR_CONNLABELS, b);
+
+	cbargs->seq++;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
+	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
+	nlh->nlmsg_seq = cbargs->seq;
+
+	nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+	nfh->nfgen_family = nfct_get_attr_u8(ct, ATTR_L3PROTO);
+	nfh->version = NFNETLINK_V0;
+	nfh->res_id = 0;
+
+	nfct_nlmsg_build(nlh, ct);
+
+	if (mnl_socket_sendto(cbargs->nl, nlh, nlh->nlmsg_len) < 0)
+		perror("mnl_socket_sendto");
+}
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nf_conntrack *ct;
+	char buf[4096];
+
+	ct = nfct_new();
+	if (ct == NULL)
+		return MNL_CB_OK;
+
+	nfct_nlmsg_parse(nlh, ct);
+
+	nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0);
+	printf("%s\n", buf);
+
+	set_label(ct, data);
+
+	nfct_destroy(ct);
+
+	return MNL_CB_OK;
+}
+
+static void show_labels(struct nfct_labelmap *l)
+{
+	unsigned int i = 0;
+	const char *name;
+
+	if (l) {
+		fputs("usage: program label, configured labels are:\n", stderr);
+		while ((name = nfct_labelmap_get_name(l, i))) {
+			if (*name)
+				fprintf(stderr, "%s -> bit %d\n", name, i);
+			i++;
+		}
+	} else {
+		fputs("no labels configured, usage: program bit\n", stderr);
+	}
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	struct mnl_socket *nl;
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfh;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	unsigned int seq, portid;
+	struct callback_args cbargs;
+	int ret;
+	struct nfct_labelmap *l = nfct_labelmap_new(NULL);
+
+	if (argc < 2)
+		show_labels(l);
+
+	cbargs.bit = l ? nfct_labelmap_get_bit(l, argv[1]) : -1;
+
+	if (cbargs.bit < 0) {
+		cbargs.bit = atoi(argv[1]);
+		if (cbargs.bit == 0 && argv[1][0] != '0')
+			show_labels(l);
+	}
+
+	if (cbargs.bit < 0)
+		puts("will clear all labels");
+	else
+		printf("will set label bit %d\n", cbargs.bit);
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL) {
+		perror("mnl_socket_open");
+		exit(EXIT_FAILURE);
+	}
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+		perror("mnl_socket_bind");
+		exit(EXIT_FAILURE);
+	}
+	portid = mnl_socket_get_portid(nl);
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
+	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+	nlh->nlmsg_seq = seq = time(NULL);
+
+	nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+	nfh->nfgen_family = AF_UNSPEC;
+	nfh->version = NFNETLINK_V0;
+	nfh->res_id = 0;
+
+
+	ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
+	if (ret == -1) {
+		perror("mnl_socket_recvfrom");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+
+	cbargs.nl = nl;
+	cbargs.seq = seq;
+
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, seq, portid, data_cb, &cbargs);
+		if (ret <= MNL_CB_STOP)
+			break;
+		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	}
+	if (ret == -1) {
+		perror("mnl_socket_recvfrom");
+		exit(EXIT_FAILURE);
+	}
+
+	if (l)
+		nfct_labelmap_destroy(l);
+	mnl_socket_close(nl);
+
+	return 0;
+}
-- 
1.7.8.6


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/3] api: add connlabel api and attribute
  2012-11-15 15:50 ` [PATCH 2/3] api: add connlabel api and attribute Florian Westphal
@ 2012-11-15 21:07   ` Florian Westphal
  0 siblings, 0 replies; 5+ messages in thread
From: Florian Westphal @ 2012-11-15 21:07 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

Florian Westphal <fw@strlen.de> wrote:
> --- a/src/conntrack/api.c
> +++ b/src/conntrack/api.c
> @@ -95,6 +95,8 @@ void nfct_destroy(struct nf_conntrack *ct)
>  		free(ct->secctx);
>  	if (ct->helper_info)
>  		free(ct->helper_info);
> +	if (ct->connlabels)
> +		nfct_bitmask_destroy(ct->connlabels);
>  	free(ct);
>  	ct = NULL; /* bugtrap */
>  }

Will cause double-free for nfct_cloned objects.

I'll fix nfct_clone and will add the missing nfct_copy*
handling in the next iteration, some time next week.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-11-15 21:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-15 15:50 [PATCH 0/3] libnetfilter_conntrack: add connlabel support Florian Westphal
2012-11-15 15:50 ` [PATCH 1/3] api: add nfct_bitmask object Florian Westphal
2012-11-15 15:50 ` [PATCH 2/3] api: add connlabel api and attribute Florian Westphal
2012-11-15 21:07   ` Florian Westphal
2012-11-15 15:50 ` [PATCH 3/3] examples: add connlabel dump/set/clear demo programs Florian Westphal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.