diff mbox

[conntrack-tools,1/2] conntrackd: support replication of connlabels

Message ID 1372022618-12312-1-git-send-email-fw@strlen.de
State Superseded
Headers show

Commit Message

Florian Westphal June 23, 2013, 9:23 p.m. UTC
- check if ct has label attribute, and at least one label
  (bit) is set
- serialize bitmap into array-of-u32, in network byte order
- add code to build new nfct_bitmask object from array-of-u32

Current parse functions don't have length information,
this adds optional parse2() which gets struct netattr pointer.

Attributes that want to use parse2 need to set .maxsize to nonzero
value.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 Tested with patched libnetfilter-conntrack and conntrackd w. UDP loopback.

 Warning, this makes conntrackd fail to build without current
 libnetfilter-conntrack HEAD+patches i've posted recently, i.e.
 this needs additional dependency magic.

 If you want to continue supporting older libnetfilter-conntrack
 versions please let me know.

 Also changes 'conntrackd -i|e' to print the connlabel names (if any).

 include/network.h |  4 +++
 src/build.c       | 39 ++++++++++++++++++++++++++++
 src/cache-ct.c    |  2 +-
 src/parse.c       | 77 +++++++++++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 111 insertions(+), 11 deletions(-)
diff mbox

Patch

diff --git a/include/network.h b/include/network.h
index 79745f3..cc312cb 100644
--- a/include/network.h
+++ b/include/network.h
@@ -228,9 +228,13 @@  enum nta_attr {
 	NTA_TCP_WSCALE_ORIG,	/* uint8_t */
 	NTA_TCP_WSCALE_REPL,	/* uint8_t */
 	NTA_HELPER_NAME,	/* string (variable length) */
+	NTA_LABELS,		/* array of uint32_t (variable length) */
 	NTA_MAX
 };
 
+/* allow to serialize/replicate up to 4k labels per flow */
+#define NTA_LABELS_MAX_SIZE	(4096/sizeof(uint32_t))
+
 struct nta_attr_natseqadj {
 	uint32_t orig_seq_correction_pos;
 	uint32_t orig_seq_offset_before;
diff --git a/src/build.c b/src/build.c
index e15eb4f..5799b51 100644
--- a/src/build.c
+++ b/src/build.c
@@ -158,6 +158,42 @@  static void build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n)
 		      sizeof(struct nfct_attr_grp_port));
 }
 
+static void ct_build_clabel(const struct nf_conntrack *ct, struct nethdr *n)
+{
+	const struct nfct_bitmask *b;
+	uint32_t *words;
+	unsigned int wordcount, i, maxbit;
+
+	if (!nfct_attr_is_set(ct, ATTR_CONNLABELS))
+		return;
+
+	b = nfct_get_attr(ct, ATTR_CONNLABELS);
+
+	maxbit = nfct_bitmask_maxbit(b);
+	for (i=0; i <= maxbit; i++) {
+		if (nfct_bitmask_test_bit(b, i))
+			break;
+	}
+
+	if (i > maxbit)
+		return;
+
+	wordcount = (nfct_bitmask_maxbit(b) / 32) + 1;
+	words = put_header(n, NTA_LABELS, wordcount * sizeof(*words));
+
+	for (i=0; i < wordcount; i++) {
+		int bit = 31;
+		uint32_t tmp = 0;
+
+		do {
+			if (nfct_bitmask_test_bit(b, (32 * i) + bit))
+				tmp |= (1 << bit);
+		} while (--bit >= 0);
+
+		words[i] = htonl(tmp);
+	}
+}
+
 #ifndef IPPROTO_DCCP
 #define IPPROTO_DCCP 33
 #endif
@@ -233,6 +269,9 @@  void ct2msg(const struct nf_conntrack *ct, struct nethdr *n)
 
 	if (nfct_attr_is_set(ct, ATTR_HELPER_NAME))
 		ct_build_str(ct, ATTR_HELPER_NAME, n, NTA_HELPER_NAME);
+
+	if (nfct_attr_is_set(ct, ATTR_CONNLABELS))
+		ct_build_clabel(ct, n);
 }
 
 static void
diff --git a/src/cache-ct.c b/src/cache-ct.c
index 0ad8d2a..6a24d5d 100644
--- a/src/cache-ct.c
+++ b/src/cache-ct.c
@@ -145,7 +145,7 @@  static int cache_ct_dump_step(void *data1, void *n)
 			     obj->ptr,
 			     NFCT_T_UNKNOWN, 
 			     container->type,
-			     0);
+			     NFCT_OF_CONNLABELS);
 
 	for (i = 0; i < obj->cache->num_features; i++) {
 		if (obj->cache->features[i]->dump) {
diff --git a/src/parse.c b/src/parse.c
index 8ce4495..f3ec6ac 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -29,15 +29,19 @@ 
 static void ct_parse_u8(struct nf_conntrack *ct, int attr, void *data);
 static void ct_parse_u16(struct nf_conntrack *ct, int attr, void *data);
 static void ct_parse_u32(struct nf_conntrack *ct, int attr, void *data);
-static void ct_parse_str(struct nf_conntrack *ct, int attr, void *data);
+static void ct_parse_str(struct nf_conntrack *ct,
+			 const struct netattr *, void *data);
 static void ct_parse_group(struct nf_conntrack *ct, int attr, void *data);
 static void ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data);
+static void ct_parse_clabel(struct nf_conntrack *ct,
+			    const struct netattr *, void *data);
 
 struct ct_parser {
 	void 	(*parse)(struct nf_conntrack *ct, int attr, void *data);
-	int 	attr;
-	int	size;
-	int	max_size;
+	void	(*parse2)(struct nf_conntrack *ct, const struct netattr *, void *);
+	uint16_t attr;
+	uint16_t size;
+	uint16_t max_size;
 };
 
 static struct ct_parser h[NTA_MAX] = {
@@ -176,10 +180,15 @@  static struct ct_parser h[NTA_MAX] = {
 		.size	= NTA_SIZE(sizeof(uint8_t)),
 	},
 	[NTA_HELPER_NAME] = {
-		.parse	= ct_parse_str,
+		.parse2	= ct_parse_str,
 		.attr	= ATTR_HELPER_NAME,
 		.max_size = NFCT_HELPER_NAME_MAX,
 	},
+	[NTA_LABELS] = {
+		.parse2 = ct_parse_clabel,
+		.attr	= ATTR_CONNLABELS,
+		.max_size = NTA_SIZE(NTA_LABELS_MAX_SIZE),
+	},
 };
 
 static void
@@ -204,9 +213,9 @@  ct_parse_u32(struct nf_conntrack *ct, int attr, void *data)
 }
 
 static void
-ct_parse_str(struct nf_conntrack *ct, int attr, void *data)
+ct_parse_str(struct nf_conntrack *ct, const struct netattr *attr, void *data)
 {
-	nfct_set_attr(ct, h[attr].attr, data);
+	nfct_set_attr(ct, h[attr->nta_attr].attr, data);
 }
 
 static void
@@ -216,6 +225,44 @@  ct_parse_group(struct nf_conntrack *ct, int attr, void *data)
 }
 
 static void
+ct_parse_clabel(struct nf_conntrack *ct, const struct netattr *attr, void *data)
+{
+	struct nfct_bitmask *bitm;
+	unsigned int i, wordcount;
+	const uint32_t *words;
+	unsigned int len;
+
+	len = attr->nta_len - NTA_LENGTH(0);
+	wordcount =  len / sizeof(*words);
+	if (!wordcount)
+		return;
+
+	if (len & (sizeof(*words) - 1))
+		return;
+
+	bitm = nfct_bitmask_new((len * 8) - 1);
+	if (!bitm)
+		return;
+
+	words = data;
+	for (i=0; i < wordcount; i++) {
+		uint32_t word;
+		int bit;
+
+		if (words[i] == 0)
+			continue;
+
+		word = htonl(words[i]);
+		bit = 31;
+		do {
+			if (word & (1 << bit))
+				nfct_bitmask_set_bit(bitm, (32 * i) + bit);
+		} while (--bit >= 0);
+	}
+	nfct_set_attr(ct, ATTR_CONNLABELS, bitm);
+}
+
+static void
 ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data)
 {
 	struct nta_attr_natseqadj *this = data;
@@ -248,14 +295,22 @@  int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain)
 		ATTR_NETWORK2HOST(attr);
 		if (attr->nta_len > len)
 			return -1;
+		if (attr->nta_len < NTA_LENGTH(0))
+			return -1;
 		if (attr->nta_attr > NTA_MAX)
 			return -1;
 		if (h[attr->nta_attr].size &&
 		    attr->nta_len != h[attr->nta_attr].size)
 			return -1;
-		if (h[attr->nta_attr].max_size &&
-		    attr->nta_len > h[attr->nta_attr].max_size)
-			return -1;
+
+		if (h[attr->nta_attr].max_size) {
+			if (attr->nta_len > h[attr->nta_attr].max_size)
+				return -1;
+			h[attr->nta_attr].parse2(ct, attr, NTA_DATA(attr));
+			attr = NTA_NEXT(attr, len);
+			continue;
+		}
+
 		if (h[attr->nta_attr].parse == NULL) {
 			attr = NTA_NEXT(attr, len);
 			continue;
@@ -457,6 +512,8 @@  int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain)
 			goto err;
 		if (attr->nta_attr > NTA_MAX)
 			goto err;
+		if (attr->nta_len < NTA_LENGTH(0))
+			goto err;
 		if (exp_h[attr->nta_attr].size &&
 		    attr->nta_len != exp_h[attr->nta_attr].size)
 			goto err;