diff --git a/src/libknot/dname.c b/src/libknot/dname.c
index ff037c949266c18a7a210fddd8f229ba183106f4..1326b54fdb59548574dd32cefd103cf7a79d0328 100644
--- a/src/libknot/dname.c
+++ b/src/libknot/dname.c
@@ -31,89 +31,6 @@
 #include "util/utils.h"
 #include "util/wire.h"
 
-
-/*----------------------------------------------------------------------------*/
-/* Non-API functions                                                          */
-/*----------------------------------------------------------------------------*/
-
-static knot_dname_t *knot_dname_new()
-{
-	knot_dname_t *dname = malloc(sizeof(knot_dname_t));
-
-	dname->name = NULL;
-	dname->count = 1;
-	dname->size = 0;
-
-	return dname;
-}
-
-/*!
- * \brief Converts domain name from string representation to wire format.
- *
- * This function also allocates the space for the wire format.
- *
- * \param name Domain name in string representation (presentation format).
- * \param size Size of the given domain name in characters (not counting the
- *             terminating 0 character.
- * \param dname Domain name where to store the wire format.
- *
- * \return Size of the wire format of the domain name in octets. If 0, no
- *         space has been allocated.
- *
- * \todo handle \X and \DDD (RFC 1035 5.1) or it can be handled by the parser?
- */
-static int knot_dname_str_to_wire(const char *name, uint size,
-                                    knot_dname_t *dname)
-{
-	if (size == 0 || size > KNOT_MAX_DNAME_LENGTH) {
-		return KNOT_EINVAL;
-	}
-
-	unsigned wire_size = size + 1;
-	if (name[0] == '.' && size == 1) {
-		wire_size = 1; /* Root label. */
-		size = 0;      /* Do not parse input. */
-	} else if (name[size - 1] != '.') {
-		++wire_size; /* No FQDN, reserve last root label. */
-	}
-
-	/* Create wire. */
-	uint8_t *wire = malloc(wire_size * sizeof(uint8_t));
-	if (wire == NULL)
-		return KNOT_ENOMEM;
-	*wire = '\0';
-
-	const uint8_t *ch = (const uint8_t *)name;
-	const uint8_t *np = ch + size;
-	uint8_t *label = wire;
-	uint8_t *w = wire + 1; /* Reserve 1 for label len */
-	while (ch != np) {
-		if (*ch == '.') {
-			/* Zero-length label inside a dname - invalid. */
-			if (*label == 0) {
-				free(wire);
-				return KNOT_EMALF;
-			}
-			label = w;
-			*label = '\0';
-		} else {
-			*w = *ch;
-			*label += 1;
-		}
-		++w;
-		++ch;
-	}
-
-	/* Check for non-FQDN name. */
-	if (*label > 0) {
-		*w = '\0';
-	}
-
-	dname->name = wire;
-	dname->size = wire_size;
-	return KNOT_EOK;
-}
-
 /*----------------------------------------------------------------------------*/
 
 static int knot_label_is_equal(const uint8_t *lb1, const uint8_t *lb2)
@@ -125,137 +42,142 @@ static int knot_label_is_equal(const uint8_t *lb1, const uint8_t *lb2)
 /* API functions                                                              */
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_new_from_str(const char *name, uint size)
+knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos)
 {
-	if (name == NULL || size == 0) {
-		return NULL;
-	}
-
-	knot_dname_t *dname = knot_dname_new();
-
-	if (dname == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
-
-	/*! \todo The function should return error codes. */
-	int ret = knot_dname_str_to_wire(name, size, dname);
-	if (ret != 0) {
-		dbg_dname("Failed to create domain name from string.\n");
-		knot_dname_free(&dname);
+	const uint8_t *name = pkt + *pos;
+	const uint8_t *endp = pkt + maxpos;
+	int parsed = knot_dname_wire_check(name, endp, pkt);
+	if (parsed < 0)
 		return NULL;
-	}
 
-	if (dname->size <= 0) {
-		dbg_dname("Could not parse domain name "
-		          "from string: '%.*s'\n", size, name);
+	/* Allocate space for the name. */
+	knot_dname_t *res = malloc(parsed);
+	if (res) {
+		/* Unpack name (expand compression pointers). */
+		if (knot_dname_unpack(res, name, parsed, pkt) > 0) {
+			*pos += parsed;
+		} else {
+			free(res);
+			res = NULL;
+		}
 	}
-	assert(dname->name != NULL);
 
-	return dname;
+	return res;
 }
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size)
+knot_dname_t *knot_dname_copy(const knot_dname_t *name)
 {
-	if (name == NULL) { /* && size != 0) { !OS: Nerozumjaju */
-		dbg_dname("No name given!\n");
-		return NULL;
-	}
-
-	knot_dname_t *dname = knot_dname_new();
+	return knot_dname_copy_part(name, knot_dname_size(name));
+}
 
-	if (dname == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
+/*----------------------------------------------------------------------------*/
 
-	dname->name = (uint8_t *)malloc(size * sizeof(uint8_t));
-	if (dname->name == NULL) {
-		ERR_ALLOC_FAILED;
-		knot_dname_free(&dname);
+knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len)
+{
+	assert(name && len > 0);
+	knot_dname_t *dst = malloc(len);
+	if (knot_dname_to_wire(dst, name, len) < 1) {
+		free(dst);
 		return NULL;
 	}
 
-	/*! \todo this won't work for non-linear names */
-	memcpy(dname->name, name, size);
-	dname->size = size;
-	return dname;
+	return dst;
 }
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
-                                         size_t *pos, size_t size)
+int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen)
 {
-	const uint8_t *name = wire + *pos;
-	const uint8_t *endp = wire + size;
-	int parsed = knot_dname_wire_check(name, endp, wire);
-	if (parsed < 0)
-		return NULL;
-
-	knot_dname_t *dname = knot_dname_new_from_wire(name, parsed);
-	if (dname)
-		*pos += parsed;
+	/* Write out non or partially compressed name. */
+	int len = 0;
+	while (*src != '\0' && !knot_wire_is_pointer(src)) {
+		uint8_t lblen = *src + 1;
+		if (len + lblen > maxlen)
+			return KNOT_ESPACE;
+		memcpy(dst + len, src, lblen);
+		len += lblen;
+		src += lblen;
+	}
 
-	return dname;
+	/* Terminated either FQDN \x00, or as a pointer. */
+	if (*src == '\0') {
+		if (len + 1> maxlen)
+			return KNOT_ESPACE;
+		*(dst + len) = '\0';
+		len += 1; /* \x00 */
+	} else {
+		if (len + 2 > maxlen)
+			return KNOT_ESPACE;
+		memcpy(dst + len, src, sizeof(uint16_t));
+		len += 2; /* ptr */
+	}
+	return len;
 }
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname)
+int knot_dname_unpack(uint8_t* dst, const knot_dname_t *src,
+                      size_t maxlen, const uint8_t *pkt)
 {
-	/* dname_new_from_wire() does not accept non-FQDN dnames, so we
-	 * do the copy by hand. It's faster anyway */
+	if (dst == NULL || src == NULL)
+		return KNOT_EINVAL;
 
-	if (dname == NULL) {
-		return NULL;
+	/* Seek first real label occurence. */
+	while (knot_wire_is_pointer(src)) {
+		src = knot_wire_next_label(src, pkt);
 	}
 
-	knot_dname_t *copy = knot_dname_new();
-	CHECK_ALLOC(copy, NULL);
-
-	copy->name = (uint8_t *)(malloc(dname->size));
-	if (copy->name == NULL) {
-		knot_dname_free(&copy);
-		return NULL;
+	/* Unpack rest of the labels. */
+	int len = 0;
+	while (*src != '\0') {
+		uint8_t lblen = *src + 1;
+		if (len + lblen > maxlen)
+			return KNOT_ESPACE;
+		memcpy(dst + len, src, lblen);
+		len += lblen;
+		src = knot_wire_next_label(src, pkt);
 	}
 
-	memcpy(copy->name, dname->name, dname->size);
-	copy->size = dname->size;
+	/* Terminal label */
+	if (len + 1 > maxlen)
+		return KNOT_EINVAL;
 
-	return copy;
+	*(dst + len) = '\0';
+	return len + 1;
 }
 
 /*----------------------------------------------------------------------------*/
 
-char *knot_dname_to_str(const knot_dname_t *dname)
+char *knot_dname_to_str(const knot_dname_t *name)
 {
-	if (!dname || dname->size == 0) {
-		return 0;
-	}
+	if (name == NULL)
+		return NULL;
 
+	/*! \todo Supply packet. */
+	/*! \todo Write to static buffer? */
 	// Allocate space for dname string + 1 char termination.
-	size_t alloc_size = dname->size + 1;
-	char *name = malloc(alloc_size);
-	if (name == NULL) {
+	int dname_size = knot_dname_size(name);
+	size_t alloc_size = dname_size + 1;
+	char *res = malloc(alloc_size);
+	if (res == NULL) {
 		return NULL;
 	}
 
 	uint8_t label_len = 0;
 	size_t  str_len = 0;
 
-	for (uint i = 0; i < dname->size; i++) {
-		uint8_t c = dname->name[i];
+	for (uint i = 0; i < dname_size; i++) {
+		uint8_t c = name[i];
 
 		// Read next label size.
 		if (label_len == 0) {
 			label_len = c;
 
 			// Write label separation.
-			if (str_len > 0 || dname->size == 1) {
-				name[str_len++] = '.';
+			if (str_len > 0 || dname_size == 1) {
+				res[str_len++] = '.';
 			}
 
 			continue;
@@ -263,35 +185,35 @@ char *knot_dname_to_str(const knot_dname_t *dname)
 
 		if (isalnum(c) != 0 || c == '-' || c == '_' || c == '*' ||
 		    c == '/') {
-			name[str_len++] = c;
+			res[str_len++] = c;
 		} else if (ispunct(c) != 0) {
 			// Increase output size for \x format.
 			alloc_size += 1;
-			char *extended = realloc(name, alloc_size);
+			char *extended = realloc(res, alloc_size);
 			if (extended == NULL) {
-				free(name);
+				free(res);
 				return NULL;
 			}
-			name = extended;
+			res = extended;
 
 			// Write encoded character.
-			name[str_len++] = '\\';
-			name[str_len++] = c;
+			res[str_len++] = '\\';
+			res[str_len++] = c;
 		} else {
 			// Increase output size for \DDD format.
 			alloc_size += 3;
-			char *extended = realloc(name, alloc_size);
+			char *extended = realloc(res, alloc_size);
 			if (extended == NULL) {
-				free(name);
+				free(res);
 				return NULL;
 			}
-			name = extended;
+			res = extended;
 
 			// Write encoded character.
-			int ret = snprintf(name + str_len, alloc_size - str_len,
+			int ret = snprintf(res + str_len, alloc_size - str_len,
 			                   "\\%03u", c);
 			if (ret <= 0 || ret >= alloc_size - str_len) {
-				free(name);
+				free(res);
 				return NULL;
 			}
 
@@ -302,160 +224,165 @@ char *knot_dname_to_str(const knot_dname_t *dname)
 	}
 
 	// String_termination.
-	name[str_len] = 0;
-
-	return name;
-}
+	res[str_len] = 0;
 
-/*----------------------------------------------------------------------------*/
-
-int knot_dname_to_lower(knot_dname_t *dname)
-{
-	return knot_dname_to_lower_copy(dname, (char*)dname->name, dname->size);
+	return res;
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
-                             size_t size)
+knot_dname_t *knot_dname_from_str(const char *name, unsigned len)
 {
-	if (dname == NULL || name == NULL || size < dname->size) {
-		return KNOT_EINVAL;
+	if (len == 0 || len > KNOT_DNAME_MAXLEN) {
+		return NULL;
 	}
 
-	for (int i = 0; i < dname->size; ++i) {
-		name[i] = knot_tolower(dname->name[i]);
+	/* Estimate wire size for special cases. */
+	unsigned wire_size = len + 1;
+	if (name[0] == '.' && len == 1) {
+		wire_size = 1; /* Root label. */
+		len = 0;      /* Do not parse input. */
+	} else if (name[len - 1] != '.') {
+		++wire_size; /* No FQDN, reserve last root label. */
 	}
-	return KNOT_EOK;
-}
 
-/*----------------------------------------------------------------------------*/
+	/* Create wire. */
+	uint8_t *wire = malloc(wire_size * sizeof(uint8_t));
+	if (wire == NULL)
+		return NULL;
+	*wire = '\0';
 
-const uint8_t *knot_dname_name(const knot_dname_t *dname)
-{
-	return dname->name;
-}
+	/* Parse labels. */
+	const uint8_t *ch = (const uint8_t *)name;
+	const uint8_t *np = ch + len;
+	uint8_t *label = wire;
+	uint8_t *w = wire + 1; /* Reserve 1 for label len */
+	while (ch != np) {
+		if (*ch == '.') {
+			/* Zero-length label inside a dname - invalid. */
+			if (*label == 0) {
+				free(wire);
+				return NULL;
+			}
+			label = w;
+			*label = '\0';
+		} else {
+			*w = *ch;
+			*label += 1;
+		}
+		++w;
+		++ch;
+	}
 
-/*----------------------------------------------------------------------------*/
+	/* Check for non-FQDN name. */
+	if (*label > 0) {
+		*w = '\0';
+	}
 
-uint knot_dname_size(const knot_dname_t *dname)
-{
-	return dname->size;
+	return wire;
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_is_fqdn(const knot_dname_t *dname)
+int knot_dname_to_lower(knot_dname_t *name)
 {
-	return (dname->name[dname->size - 1] == '\0');
+	/*! \todo Faster with \xdfdf mask. */
+	while (*name != '\0') {
+		for (uint8_t i = 0; i < *name; ++i)
+			name[1 + i] = knot_tolower(name[1 + i]);
+		name = (uint8_t *)knot_wire_next_label(name, NULL);
+		assert(name); /* Must not be used on compressed names. */
+	}
+
+	return KNOT_EOK;
 }
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
+int knot_dname_size(const knot_dname_t *name)
 {
-	if (dname == NULL || *knot_dname_name(dname) == '\0') { /* root */
-		return NULL;
-	}
-
-	knot_dname_t *parent = knot_dname_new();
-	if (parent == NULL) {
-		return NULL;
+	/* Count name size without terminal label. */
+	int len = 0;
+	while (*name != '\0' && !knot_wire_is_pointer(name)) {
+		uint8_t lblen = *name + 1;
+		len += lblen;
+		name += lblen;
 	}
 
-	parent->size = dname->size - dname->name[0] - 1;
-	parent->name = (uint8_t *)malloc(parent->size);
-	if (parent->name == NULL) {
-		ERR_ALLOC_FAILED;
-		knot_dname_free(&parent);
-		return NULL;
-	}
+	/* Compression pointer is 2 octets. */
+	if (knot_wire_is_pointer(name))
+		return len + 2;
 
-	memcpy(parent->name, &dname->name[dname->name[0] + 1], parent->size);
-	return parent;
+	return len + 1;
 }
 
 /*----------------------------------------------------------------------------*/
 
-void knot_dname_left_chop_no_copy(knot_dname_t *dname)
+int knot_dname_wire_size(const knot_dname_t *name, const uint8_t *pkt)
 {
-	uint8_t len = *knot_dname_name(dname);
-	if (len == 0)
-		return;
-
-	/*! \todo this will work only with linearized names (as of now) */
-	dname->size -= (len + 1);
-	memmove(dname->name, dname->name + len + 1, dname->size);
+	return knot_dname_prefixlen(name, KNOT_DNAME_MAXLABELS, pkt);
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_is_subdomain(const knot_dname_t *sub,
-                              const knot_dname_t *domain)
+bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain)
 {
 	if (sub == domain)
-		return 0;
+		return false;
 
 	/* Count labels. */
-	const uint8_t *sub_p = sub->name;
-	const uint8_t *domain_p = domain->name;
-	int sub_l = knot_dname_wire_labels(sub_p, NULL);
-	int domain_l = knot_dname_wire_labels(domain_p, NULL);
+	int sub_l = knot_dname_labels(sub, NULL);
+	int domain_l = knot_dname_labels(domain, NULL);
 
 	/* Subdomain must have more labels as parent. */
 	if (sub_l <= domain_l)
-		return 0;
+		return false;
 
 	/* Align end-to-end to common suffix. */
-	int common = knot_dname_align(&sub_p, sub_l, &domain_p, domain_l, NULL);
+	int common = knot_dname_align(&sub, sub_l, &domain, domain_l, NULL);
 
 	/* Compare common suffix. */
 	while(common > 0) {
 		/* Compare label. */
-		if (!knot_label_is_equal(sub_p, domain_p))
-			return 0;
+		if (!knot_label_is_equal(sub, domain))
+			return false;
 		/* Next label. */
-		sub_p = knot_wire_next_label(sub_p, NULL);
-		domain_p = knot_wire_next_label(domain_p, NULL);
+		sub = knot_wire_next_label(sub, NULL);
+		domain = knot_wire_next_label(domain, NULL);
 		--common;
 	}
-	return 1;
+	return true;
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_is_wildcard(const knot_dname_t *dname)
+int knot_dname_is_wildcard(const knot_dname_t *name)
 {
-	return (dname->size >= 2
-		&& dname->name[0] == 1
-		&& dname->name[1] == '*');
+	return name[0] == 1 && name[1] == '*';
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_matched_labels(const knot_dname_t *dname1,
-                                const knot_dname_t *dname2)
+int knot_dname_matched_labels(const knot_dname_t *dname1, const knot_dname_t *dname2)
 {
 	/* Count labels. */
-	const uint8_t *d1 = dname1->name;
-	const uint8_t *d2 = dname2->name;
-	int l1 = knot_dname_wire_labels(d1, NULL);
-	int l2 = knot_dname_wire_labels(d2, NULL);
+	int l1 = knot_dname_labels(dname1, NULL);
+	int l2 = knot_dname_labels(dname2, NULL);
 
 	/* Align end-to-end to common suffix. */
-	int common = knot_dname_align(&d1, l1, &d2, l2, NULL);
+	int common = knot_dname_align(&dname1, l1, &dname2, l2, NULL);
 
 	/* Count longest chain leading to root label. */
 	int matched = 0;
 	while (common > 0) {
-		if (knot_label_is_equal(d1, d2))
+		if (knot_label_is_equal(dname1, dname2))
 			++matched;
 		else
 			matched = 0; /* Broken chain. */
 
 		/* Next label. */
-		d1 = knot_wire_next_label(d1, NULL);
-		d2 = knot_wire_next_label(d2, NULL);
+		dname1 = knot_wire_next_label(dname1, NULL);
+		dname2 = knot_wire_next_label(dname2, NULL);
 		--common;
 	}
 
@@ -464,43 +391,43 @@ int knot_dname_matched_labels(const knot_dname_t *dname1,
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, int size,
+knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, unsigned labels,
                                         const knot_dname_t *suffix)
 {
-dbg_dname_exec_verb(
-	char *name = knot_dname_to_str(dname);
-	dbg_dname_verb("Replacing suffix of name %s, size %d with ", name,
-	               size);
-	free(name);
-	name = knot_dname_to_str(suffix);
-	dbg_dname_verb("%s (size %d)\n", name, suffix->size);
-	free(name);
-);
-	knot_dname_t *res = knot_dname_new();
-	CHECK_ALLOC(res, NULL);
-
-	res->size = dname->size - size + suffix->size;
-
-	dbg_dname_detail("Allocating %d bytes...\n", res->size);
-	res->name = (uint8_t *)malloc(res->size);
-	if (res->name == NULL) {
-		knot_dname_free(&res);
-		return NULL;
-	}
 
-	dbg_dname_hex((char *)res->name, res->size);
+	/* Calculate prefix and suffix lengths. */
+	int dname_lbs = knot_dname_labels(dname, NULL);
+	unsigned prefix_lbs = dname_lbs - labels;
 
-	dbg_dname_detail("Copying %d bytes from the original name.\n",
-	                 dname->size - size);
-	memcpy(res->name, dname->name, dname->size - size);
-	dbg_dname_hex((char *)res->name, res->size);
+	/* Trim 1 octet from prefix, as it is measured as FQDN. */
+	int prefix_len = knot_dname_prefixlen(dname, prefix_lbs, NULL) - 1;
+	int suffix_len = knot_dname_size(suffix);
+	if (prefix_len < 0 || suffix_len < 0)
+		return NULL;
 
-	dbg_dname_detail("Copying %d bytes from the suffix.\n", suffix->size);
-	memcpy(res->name + dname->size - size, suffix->name, suffix->size);
+	/* Create target name. */
+	int new_len = prefix_len + suffix_len;
+	knot_dname_t *out = malloc(new_len);
+	if (out == NULL)
+		return NULL;
 
-	dbg_dname_hex((char *)res->name, res->size);
+	/* Copy prefix. */
+	uint8_t *dst = out;
+	while (prefix_lbs > 0) {
+		memcpy(dst, dname, *dname + 1);
+		dst += *dname + 1;
+		dname = knot_wire_next_label(dname, NULL);
+		--prefix_lbs;
+	}
 
-	return res;
+	/* Copy suffix. */
+	while (*suffix != '\0') {
+		memcpy(dst, suffix, *suffix + 1);
+		dst += *suffix + 1;
+		suffix = knot_wire_next_label(suffix, NULL);
+	}
+	*dst = '\0';
+	return out;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -511,71 +438,64 @@ void knot_dname_free(knot_dname_t **dname)
 		return;
 	}
 
-	free((*dname)->name);
-
-//	slab_free(*dname);
 	free(*dname);
 	*dname = NULL;
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2)
+int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2)
 {
-	return knot_dname_wire_cmp(d1, d2, NULL);
+	return knot_dname_cmp_wire(d1, d2, NULL);
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2)
+int knot_dname_cmp_wire(const knot_dname_t *d1, const knot_dname_t *d2,
+                        const uint8_t *pkt)
 {
-	return knot_dname_wire_cmp(d1, d2, NULL);
-}
+	/* Convert to lookup format. */
+	uint8_t d1_lf[KNOT_DNAME_MAXLEN], d2_lf[KNOT_DNAME_MAXLEN];
+	if (knot_dname_lf(d1_lf, d1, pkt) < 0 || knot_dname_lf(d2_lf, d2, pkt) < 0)
+		return KNOT_EINVAL;
 
-int knot_dname_compare_non_canon(const knot_dname_t *d1, const knot_dname_t *d2)
-{
-	int ret = memcmp(d1->name, d2->name,
-	                 d1->size > d2->size ? d2->size : d1->size);
-	if (d1->size != d2->size && ret == 0) {
-		return d1->size < d2->size ? -1 : 1;
-	} else {
+	/* Compare common part. */
+	uint8_t common = d1_lf[0];
+	if (common > d2_lf[0])
+		common = d2_lf[0];
+	int ret = memcmp(d1_lf+1, d2_lf+1, common);
+	if (ret != 0)
 		return ret;
-	}
+
+	/* If they match, compare lengths. */
+	if (d1_lf[0] < d2_lf[0])
+		return -1;
+	if (d1_lf[0] > d2_lf[0])
+		return 1;
+	return 0;
 }
 
+
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
+int knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2)
 {
-	if (d2->size == 0) {
-		return d1;
-	}
-
-	// allocate new space
-	size_t new_size = d1->size + d2->size - 1; /* Trim the d1 \0 label */
-	uint8_t *new_dname = (uint8_t *)malloc(new_size);
-	CHECK_ALLOC_LOG(new_dname, NULL);
-
-	dbg_dname_detail("1: copying %d bytes from adress %p to %p\n",
-	                 d1->size, d1->name, new_dname);
-
-	memcpy(new_dname, d1->name, d1->size);
-
-	dbg_dname_detail("2: copying %d bytes from adress %p to %p\n",
-	                 d2->size, d2->name, new_dname + d1->size);
-
-	/* Overwrite the d1 \0 label. */
-	memcpy(new_dname + d1->size - 1, d2->name, d2->size);
-
-	uint8_t *old_name = d1->name;
-	d1->name = new_dname;
-	free(old_name);
+	/*! \todo Could be implemented more efficiently, check profile first. */
+	return (knot_dname_cmp(d1, d2) == 0);
+}
 
-	d1->size = new_size;
+/*----------------------------------------------------------------------------*/
 
-	return d1;
+knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
+{
+	/* This is problem equal to replacing last \x00 from d1 with d2. */
+	knot_dname_t *ret = knot_dname_replace_suffix(d1, 0, d2);
+	/* Like if we are reallocating d1. */
+	knot_dname_free(&d1);
+	return ret;
 }
 
+
 int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
                           const uint8_t *pkt)
 {
@@ -594,7 +514,7 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
 			return KNOT_ESPACE;
 
 		/* Reject more labels. */
-		if (labels == KNOT_MAX_DNAME_LABELS - 1)
+		if (labels == KNOT_DNAME_MAXLABELS - 1)
 			return KNOT_EMALF;
 
 		if (knot_wire_is_pointer(name)) {
@@ -618,7 +538,7 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
 				return KNOT_EMALF;
 			/* Check if there's enough space. */
 			int lblen = *name + 1;
-			if (name_len + lblen > KNOT_MAX_DNAME_LENGTH)
+			if (name_len + lblen > KNOT_DNAME_MAXLEN)
 				return KNOT_EMALF;
 			/* Update wire size only for noncompressed part. */
 			name_len += lblen;
@@ -640,11 +560,15 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
 	return wire_len;
 }
 
-int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt)
+int knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt)
 {
 	if (!name)
 		return KNOT_EINVAL;
 
+	/* Zero labels means 1 octet \x00 */
+	if (nlabels == 0)
+		return 1;
+
 	/* Seek first real label occurence. */
 	while (knot_wire_is_pointer(name)) {
 		name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
@@ -654,12 +578,14 @@ int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt)
 	while (*name != '\0') {
 		len += *name + 1;
 		name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
+		if (--nlabels == 0) /* Count N first labels only. */
+			break;
 	}
 
 	return len;
 }
 
-int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt)
+int knot_dname_labels(const uint8_t *name, const uint8_t *pkt)
 {
 	uint8_t count = 0;
 	while (*name != '\0') {
@@ -684,54 +610,30 @@ int knot_dname_align(const uint8_t **d1, uint8_t d1_labels,
 	return (d1_labels < d2_labels) ? d1_labels : d2_labels;
 }
 
-int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
-                        const uint8_t *pkt)
-{
-	/*! \todo lf conversion should respect packet wire. */
-
-	/* Convert to lookup format. */
-	unsigned buflen = DNAME_LFT_MAXLEN;
-	uint8_t d1_lf[DNAME_LFT_MAXLEN], d2_lf[DNAME_LFT_MAXLEN];
-	if (dname_lf(d1_lf, d1, buflen) < 0 || dname_lf(d2_lf, d2, buflen) < 0)
-		return KNOT_EINVAL;
-
-	/* Compare common part. */
-	uint8_t common = d1_lf[0];
-	if (common > d2_lf[0])
-		common = d2_lf[0];
-	int ret = memcmp(d1_lf+1, d2_lf+1, common);
-	if (ret != 0)
-		return ret;
-
-	/* If they match, compare lengths. */
-	if (d1_lf[0] < d2_lf[0])
-		return -1;
-	if (d1_lf[0] > d2_lf[0])
-		return 1;
-	return 0;
-}
-
-int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen)
+int knot_dname_lf(uint8_t *dst, const knot_dname_t *src, const uint8_t *pkt)
 {
-	if (src->size > maxlen)
-		return KNOT_ESPACE;
-	*dst = (uint8_t)src->size;
-	/* need to save last \x00 for root dname */
-	if (*dst > 1)
-		*dst -= 1;
-	*++dst = '\0';
-	uint8_t* l = src->name;
-	uint8_t lstack[DNAME_LFT_MAXLEN];
-	uint8_t *sp = lstack;
+	uint8_t *len = dst++;
+	*len = '\0';
+	*dst = '\0';
+	const uint8_t* l = src;
+	/*! \todo This could be made as offsets to pkt? */
+	const uint8_t* lstack[KNOT_DNAME_MAXLEN];
+	const uint8_t **sp = lstack;
 	while(*l != 0) { /* build label stack */
-		*sp++ = (l - src->name);
-		l += 1 + *l;
+		*sp++ = l;
+		l = knot_wire_next_label(l, pkt);
 	}
 	while(sp != lstack) {          /* consume stack */
-		l = src->name + *--sp; /* fetch rightmost label */
+		l = *--sp; /* fetch rightmost label */
 		memcpy(dst, l+1, *l);  /* write label */
 		dst += *l;
 		*dst++ = '\0';         /* label separator */
+		*len += *l + 1;
 	}
+
+	/* root label special case */
+	if (*len == 0)
+		*len = 1; /* \x00 */
+
 	return KNOT_EOK;
 }
diff --git a/src/libknot/dname.h b/src/libknot/dname.h
index 71b17beacb990b01d941deeebbfb3846745faa3f..994ce757fc3129db563a8d50dde75a37222afe33 100644
--- a/src/libknot/dname.h
+++ b/src/libknot/dname.h
@@ -30,92 +30,81 @@
 #include <stdint.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdbool.h>
+
+#include "libknot/consts.h"
+
+typedef uint8_t knot_dname_t;
 
 /*!
- * \brief Structure for representing a domain name.
+ * \brief Check dname on the wire for constraints.
+ *
+ * If the name passes such checks, it is safe to be used in rest of the functions.
  *
- * Stores the domain name in wire format.
+ * \param name Name on the wire.
+ * \param endp Name boundary.
+ * \param pkt Wire.
  *
- * \todo Consider restricting to FQDN only (see knot_dname_new_from_str()).
+ * \retval KNOT_EOK
+ * \retval KNOT_EMALF
+ * \retval KNOT_ESPACE
  */
-struct knot_dname {
-	uint8_t *name;		/*!< Wire format of the domain name. */
-	uint32_t count;		/*!< Reference counter. */
-	uint8_t size;		/*!< Length of the domain name. */
-};
-
-typedef struct knot_dname knot_dname_t;
-
-#define DNAME_LFT_MAXLEN 255 /* maximum lookup format length */
-
-/*----------------------------------------------------------------------------*/
+int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
+                          const uint8_t *pkt);
 
 /*!
- * \brief Creates a dname structure from domain name given in presentation
- *        format.
- *
- * The resulting domain name is stored in wire format, but it may not end with
- * root label (0).
- *
- * \note Newly created dname is referenced, caller is responsible for releasing
- *       it after use.
+ * \brief Parse dname from wire.
  *
- * \param name Domain name in presentation format (labels separated by dots).
- * \param size Size of the domain name (count of characters with all dots).
+ * \param pkt Message in wire format.
+ * \param pos Position of the domain name on wire.
+ * \param maxpos Domain name length.
  *
- * \return Newly allocated and initialized dname structure representing the
- *         given domain name.
+ * \return parsed domain name or NULL.
  */
-knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size);
+knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos);
 
 /*!
- * \brief Creates a dname structure from domain name given in wire format.
- *
- * \note The name is copied into the structure.
- * \note If the given name is not a FQDN, the result will be neither.
- * \note Newly created dname is referenced, caller is responsible for releasing
- *       it after use.
+ * \brief Duplicates the given domain name.
  *
- * \param name Domain name in wire format.
- * \param size Size of the domain name in octets.
+ * \param dname Domain name to be copied.
  *
- * \return Newly allocated and initialized dname structure representing the
- *         given domain name.
+ * \return New domain name which is an exact copy of \a dname.
+ */
+knot_dname_t *knot_dname_copy(const knot_dname_t *name);
+
+/*!
+ * \brief Duplicates part of the given domain name.
  *
- * \todo This function does not check if the given data is in correct wire
- *       format at all. It thus creates a invalid domain name, which if passed
- *       e.g. to knot_dname_to_str() may result in crash. Decide whether it
- *       is OK to retain this and check the data in other functions before
- *       calling this one, or if it should verify the given data.
+ * \param dname Domain name to be copied.
+ * \param len Part length.
  *
- * \warning Actually, right now this function does not accept non-FQDN dnames.
- *          For some reason there is a check for this.
+ * \return New domain name which is an partial copy of \a dname.
  */
-knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, unsigned int size);
+knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len);
 
 /*!
- * \brief Parse dname from wire.
+ * \brief Copy name to wire as is, no compression pointer expansion will be done.
  *
- * \param wire Message in wire format.
- * \param pos Position of the domain name on wire.
- * \param size Domain name length.
+ * \param dst Destination wire.
+ * \param src Source name.
+ * \param maxlen Maximum wire length.
  *
- * \return parsed domain name or NULL.
+ * \return number of bytes written
  */
-knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
-                                         size_t *pos, size_t size);
+int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen);
 
 /*!
- * \brief Duplicates the given domain name.
+ * \brief Write unpacked name (i.e. compression pointers expanded)
  *
- * \note Copied dname referense count is reset to 1, caller is responsible
- *       for releasing it after use.
- *
- * \param dname Domain name to be copied.
+ * \param dst Destination wire.
+ * \param src Source name.
+ * \param maxlen Maximum destination wire size.
+ * \param pkt Name packet wire (for compression pointers).
  *
- * \return New domain name which is an exact copy of \a dname.
+ * \return number of bytes written
  */
-knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname);
+int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src,
+                      size_t maxlen, const uint8_t *pkt);
 
 /*!
  * \brief Converts the given domain name to string representation.
@@ -127,53 +116,53 @@ knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname);
  * \return 0-terminated string representing the given domain name in
  *         presentation format.
  */
-char *knot_dname_to_str(const knot_dname_t *dname);
-
-int knot_dname_to_lower(knot_dname_t *dname);
-
-int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
-                             size_t size);
+char *knot_dname_to_str(const knot_dname_t *name);
 
 /*!
- * \brief Returns the domain name in wire format.
+ * \brief Creates a dname structure from domain name given in presentation
+ *        format.
  *
- * \param dname Domain name.
+ * The resulting FQDN is stored in the wire format.
  *
- * \return Wire format of the domain name.
+ * \param name Domain name in presentation format (labels separated by dots).
+ * \param len Size of the domain name (count of characters with all dots).
+ *
+ * \return new name or NULL
  */
-const uint8_t *knot_dname_name(const knot_dname_t *dname);
+knot_dname_t *knot_dname_from_str(const char *name, unsigned len);
 
 /*!
- * \brief Returns size of the given domain name.
+ * \brief Convert name to lowercase.
  *
- * \param dname Domain name to get the size of.
+ * \note Name must not be compressed.
+ *
+ * \param name Domain name to be converted.
  *
- * \return Size of the domain name in wire format in octets.
+ * \return KNOT_EOK
+ * \retval KNOT_EINVAL
  */
-unsigned int knot_dname_size(const knot_dname_t *dname);
+int knot_dname_to_lower(knot_dname_t *name);
 
 /*!
- * \brief Checks if the given domain name is a fully-qualified domain name.
+ * \brief Returns size of the given domain name.
  *
- * \param dname Domain name to check.
+ * \param dname Domain name to get the size of.
  *
- * \retval <> 0 if \a dname is a FQDN.
- * \retval 0 otherwise.
+ * \retval size of the domain name
+ * \retval KNOT_ERROR
  */
-int knot_dname_is_fqdn(const knot_dname_t *dname);
+int knot_dname_size(const knot_dname_t *name);
 
 /*!
- * \brief Creates new domain name by removing leftmost label from \a dname.
- *
- * \note Newly created dname reference count is set to 1, caller is responsible
- *        for releasing it after use.
+ * \brief Returns wire size of the given domain name (expaned compression ptrs).
  *
- * \param dname Domain name to remove the first label from.
+ * \param dname Domain name to get the size of.
+ * \param pkt Related packet (or NULL if unpacked)
  *
- * \return New domain name with the same labels as \a dname, except for the
- *         leftmost label, which is removed.
+ * \retval size of the domain name
+ * \retval KNOT_ERROR
  */
-knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
+int knot_dname_wire_size(const knot_dname_t *name, const uint8_t *pkt);
 
 /*!
  * \brief Checks if one domain name is a subdomain of other.
@@ -184,8 +173,7 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
  * \retval <> 0 if \a sub is a subdomain of \a domain.
  * \retval 0 otherwise.
  */
-int knot_dname_is_subdomain(const knot_dname_t *sub,
-                              const knot_dname_t *domain);
+bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain);
 
 /*!
  * \brief Checks if the domain name is a wildcard.
@@ -195,7 +183,7 @@ int knot_dname_is_subdomain(const knot_dname_t *sub,
  * \retval <> 0 if \a dname is a wildcard domain name.
  * \retval 0 otherwise.
  */
-int knot_dname_is_wildcard(const knot_dname_t *dname);
+int knot_dname_is_wildcard(const knot_dname_t *name);
 
 /*!
  * \brief Returns the number of labels common for the two domain names (counted
@@ -214,15 +202,15 @@ int knot_dname_matched_labels(const knot_dname_t *dname1,
  *        name.
  *
  * \param dname Domain name where to replace the suffix.
- * \param size Size of the suffix to be replaced.
+ * \param labels Size of the suffix to be replaced.
  * \param suffix New suffix to be used as a replacement.
  *
  * \return New domain name created by replacing suffix of \a dname of size
  *         \a size with \a suffix.
  */
 knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname,
-                                            int size,
-                                            const knot_dname_t *suffix);
+                                        unsigned labels,
+                                        const knot_dname_t *suffix);
 
 /*!
  * \brief Destroys the given domain name.
@@ -247,7 +235,20 @@ void knot_dname_free(knot_dname_t **dname);
  * \retval > 0 if \a d1 goes after \a d2 in canonical order.
  * \retval 0 if the domain names are identical.
  */
-int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2);
+int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);
+
+/*!
+ * \brief Compare domain name by labels.
+ *
+ * \todo No case insensitivity, flags...
+ *
+ * \param d1 Domain name.
+ * \param d2 Domain name.
+ * \param pkt Packet wire related to names (or NULL).
+ * \return
+ */
+int knot_dname_cmp_wire(const knot_dname_t *d1, const knot_dname_t *d2,
+                        const uint8_t *pkt);
 
 /*!
  * \brief Compares two domain names (case sensitive).
@@ -259,87 +260,46 @@ int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2);
  * \retval > 0 if \a d1 goes after \a d2 in canonical order.
  * \retval 0 if the domain names are identical.
  */
-int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2);
-int knot_dname_compare_non_canon(const knot_dname_t *d1,
-                                 const knot_dname_t *d2);
+int knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2);
 
 /*!
  * \brief Concatenates two domain names.
  *
- * \note Member \a node is ignored, i.e. preserved.
- *
- * \param d1 First domain name (will be modified).
+  * \param d1 First domain name (will be modified).
  * \param d2 Second domain name (will not be modified).
  *
- * \return The concatenated domain name (i.e. modified \a d1) or NULL if
- *         the operation is not valid (e.g. \a d1 is a FQDN).
+ * \return The concatenated domain name or NULL
  */
 knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2);
 
 /*!
- * \brief Increment reference counter for dname.
+ * \brief Cound length of the N first labels.
  *
- * Function makes shallow copy (reference).
+ * \param name Domain name.
+ * \param nlabels N first labels.
+ * \param pkt Related packet (or NULL if not compressed).
  *
- * \param dname Referenced dname.
+ * \retval length of the prefix
  */
-static inline void knot_dname_retain(knot_dname_t *dname) {
-	if (dname) {
-		__sync_add_and_fetch(&dname->count, 1);
-	}
-}
+int knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt);
 
 /*!
- * \brief Decrement reference counter for dname.
+ * \brief Return number of labels in the domain name.
  *
- * \param dname Referenced dname.
- */
-static inline void knot_dname_release(knot_dname_t *dname) {
-	if (dname) {
-		if (__sync_sub_and_fetch(&dname->count, 1) == 0) {
-			knot_dname_free(&dname);
-		}
-	}
-}
-
-/* ! New nocopy based API.
- * \note Temporary, subject to name changes.
- */
-
-int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
-                          const uint8_t *pkt);
-
-/*! Calculate wire size.
- *  \note Expects already checked name.
- *  \note pkt Supply if name uses dname compression, NULL otherwise.
- */
-int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt);
-
-/*! Calculate label count.
- *  \note Expects already checked name.
+ * Terminal nullbyte is not counted.
+ *
+ * \param name Domain name.
+ * \param pkt Related packet (or NULL if not compressed).
  */
-int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt);
+int knot_dname_labels(const uint8_t *name, const uint8_t *pkt);
 
 /*!
- * \brief Align name and reference to a common number of suffix labels.
+ * \brief Align name end-to-end and return common number of suffix labels.
  */
 int knot_dname_align(const uint8_t **d1, uint8_t d1_labels,
                      const uint8_t **d2, uint8_t d2_labels,
                      uint8_t *wire);
 
-/*!
- * \brief Compare domain name by labels.
- *
- * \todo No case insensitivity, flags...
- *
- * \param d1 Domain name.
- * \param d2 Domain name.
- * \param pkt Packet wire related to names (or NULL).
- * \return
- */
-int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
-                        const uint8_t *pkt);
-
 /*!
  * \brief Convert domain name from wire to lookup format.
  *
@@ -351,17 +311,17 @@ int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
  * Name: lake.example.com. Wire: \x04lake\x07example\x03com\x00
  * Lookup format com\x00example\x00lake\x00
  *
- * Maximum length of such a domain name is DNAME_LFT_MAXLEN characters.
+ * Maximum length of such a domain name is KNOT_DNAME_MAXLEN characters.
  *
  * \param dst Memory to store converted name into.
- * \param maxlen Maximum memory length.
  * \param src Source domain name.
+ * \param pkt Source name packet (NULL if not any).
  *
  * \retval KNOT_EOK if successful
  * \retval KNOT_ESPACE when not enough memory.
  * \retval KNOT_EINVAL on invalid parameters
  */
-int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen);
+int knot_dname_lf(uint8_t *dst, const knot_dname_t *src, const uint8_t *pkt);
 
 #endif /* _KNOT_DNAME_H_ */