diff --git a/include/internal/internal.h b/include/internal/internal.h
index aaf6bd4..a5c7923 100644
--- a/include/internal/internal.h
+++ b/include/internal/internal.h
@@ -6,6 +6,7 @@
 #ifndef __LIBNETFILTER_CONNTRACK_INTERNAL__
 #define __LIBNETFILTER_CONNTRACK_INTERNAL__
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
diff --git a/include/internal/prototypes.h b/include/internal/prototypes.h
index cc8de1d..577270b 100644
--- a/include/internal/prototypes.h
+++ b/include/internal/prototypes.h
@@ -16,6 +16,7 @@ int __snprintf_proto(char *buf, unsigned int len, const struct __nfct_tuple *tup
 int __snprintf_conntrack_default(char *buf, unsigned int len, const struct nf_conntrack *ct, const unsigned int msg_type, const unsigned int flags);
 int __snprintf_conntrack_xml(char *buf, unsigned int len, const struct nf_conntrack *ct, const unsigned int msg_type, const unsigned int flags);
 int __snprintf_connlabels(char *buf, unsigned int len, const struct nf_conntrack *ct, const char *prefix, const char *end);
+int __snprintf_connlabels_names(char *buf, unsigned int len, const struct nf_conntrack *ct, const char *prefix, const char *end, bool xml);
 
 enum __nfct_addr {
 	__ADDR_SRC = 0,
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
index 39dc24c..eedf85e 100644
--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
@@ -389,6 +389,9 @@ enum {
 
 	NFCT_OF_TIMESTAMP_BIT = 3,
 	NFCT_OF_TIMESTAMP = (1 << NFCT_OF_TIMESTAMP_BIT),
+
+	NFCT_OF_CONNLABELS_BIT = 4,
+	NFCT_OF_CONNLABELS = (1 << NFCT_OF_CONNLABELS_BIT),
 };
 
 extern int nfct_snprintf(char *buf, 
diff --git a/src/conntrack/snprintf_default.c b/src/conntrack/snprintf_default.c
index a1edef4..7befbd7 100644
--- a/src/conntrack/snprintf_default.c
+++ b/src/conntrack/snprintf_default.c
@@ -313,9 +313,89 @@ __snprintf_connlabels(char *buf, unsigned int len,
 	return size;
 }
 
+/*
+ * Labels can have any name, there are no restrictions.
+ * We will only print alpha numerical ones; else parsers
+ * could choke when putinng "&>" and friends into output
+ * (especially when using XML format).  ASCII machines only.
+ */
+static bool label_is_sane(const char *label)
+{
+	for (;*label; label++) {
+		if (*label >= 'a' && *label <= 'z')
+			continue;
+		if (*label >= 'A' && *label <= 'Z')
+			continue;
+		if (*label >= '0' && *label <= '9')
+			continue;
+		if (*label == ' ' || *label == '-')
+			continue;
+		return false;
+	}
+	return true;
+}
+
+int
+__snprintf_connlabels_names(char *buf, unsigned int len,
+			    const struct nf_conntrack *ct,
+			    const char *prefix, const char *end, bool xml)
+{
+	const struct nfct_bitmask *b = nfct_get_attr(ct, ATTR_CONNLABELS);
+	unsigned int i, max;
+	int ret, size = 0, offset = 0;
+	struct nfct_labelmap *map;
+
+	if (!b)
+		return 0;
+	map = nfct_labelmap_new(NULL);
+	if (!map)
+		return __snprintf_connlabels(buf, len, ct, prefix, end);
+
+	ret = snprintf(buf, len, "%s", prefix);
+	BUFFER_SIZE(ret, size, len, offset);
+	max = nfct_bitmask_maxbit(b);
+	for (i = 0; i <= max && len; i++) {
+		const char *name;
+		if (!nfct_bitmask_test_bit(b, i))
+			continue;
+		name = nfct_labelmap_get_name(map, i);
+		if (!name || !label_is_sane(name))
+			name = "";
+
+		if (xml)
+			ret = snprintf(buf + offset, len, "<label name=\"%s\" ", name);
+		else if (strcmp(name, "") != 0)
+			ret = snprintf(buf + offset, len, "%s ", name);
+		else
+			ret = 0;
+		BUFFER_SIZE(ret, size, len, offset);
+
+		if (xml)
+			ret = snprintf(buf + offset, len, "bit=\"%u\"/>", i);
+		else
+			ret = snprintf(buf + offset, len, "(%u),", i);
+		BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	nfct_labelmap_destroy(map);
+	if (offset && end) {
+		if (!xml) {
+			offset--; /* remove last , */
+			size--;
+		}
+		ret = snprintf(buf + offset, len, "%s", end);
+		BUFFER_SIZE(ret, size, len, offset);
+	}
+	return size;
+}
+
 static int
-__snprintf_clabels(char *buf, unsigned int len, const struct nf_conntrack *ct)
+__snprintf_clabels(char *buf, unsigned int len,
+		   const struct nf_conntrack *ct, bool names)
 {
+	if (names)
+		return  __snprintf_connlabels_names(buf, len, ct,
+					   "labels=", " ", false);
 	return __snprintf_connlabels(buf, len, ct, "labels=", " ");
 }
 
@@ -458,7 +538,7 @@ int __snprintf_conntrack_default(char *buf,
 	}
 
 	if (test_bit(ATTR_CONNLABELS, ct->head.set)) {
-		ret = __snprintf_clabels(buf+offset, len, ct);
+		ret = __snprintf_clabels(buf+offset, len, ct, flags & NFCT_OF_CONNLABELS );
 		BUFFER_SIZE(ret, size, len, offset);
 	}
 
diff --git a/src/conntrack/snprintf_xml.c b/src/conntrack/snprintf_xml.c
index f373f5b..1c2440a 100644
--- a/src/conntrack/snprintf_xml.c
+++ b/src/conntrack/snprintf_xml.c
@@ -349,8 +349,12 @@ static int __snprintf_tuple_xml(char *buf,
 }
 
 static int
-__snprintf_clabels_xml(char *buf, unsigned int len, const struct nf_conntrack *ct)
+__snprintf_clabels_xml(char *buf, unsigned int len,
+		       const struct nf_conntrack *ct, bool names)
 {
+	if (names)
+		return __snprintf_connlabels_names(buf, len, ct,
+				"<labels>", "</labels>", true);
 	return __snprintf_connlabels(buf, len, ct, "<labels>", "</labels>");
 }
 
@@ -440,7 +444,7 @@ int __snprintf_conntrack_xml(char *buf,
 	}
 
 	if (test_bit(ATTR_CONNLABELS, ct->head.set)) {
-		ret = __snprintf_clabels_xml(buf+offset, len, ct);
+		ret = __snprintf_clabels_xml(buf+offset, len, ct, flags & NFCT_OF_CONNLABELS);
 		BUFFER_SIZE(ret, size, len, offset);
 	}
 
