diff --git a/src/common/log.c b/src/common/log.c
index a5c8b1c8554cd81c65831618649f2fccbea19fd0..7eb73ccff6e96aa8fc6a38a148762d90d456438a 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -403,7 +403,7 @@ int log_msg_zone(int priority, const knot_dname_t *zone, const char *fmt, ...)
 {
 	va_list args;
 	va_start(args, fmt);
-	char *zone_str = knot_dname_to_str(zone);
+	char *zone_str = knot_dname_to_str_alloc(zone);
 	int result = log_msg_text(priority,
 				  zone_str ? zone_str : LOG_NULL_ZONE_STRING,
 				  fmt, args);
diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index 9010d4fc52d023a52bedba4dc324043b1bd76595..0db4e115d1d034b9f36d13cfbe951057f70b0151 100644
--- a/src/knot/conf/cf-parse.y
+++ b/src/knot/conf/cf-parse.y
@@ -307,7 +307,7 @@ static void query_module_create(void *scanner, const char *name, const char *par
 static int conf_key_exists(void *scanner, char *item)
 {
 	/* Find existing node in keys. */
-	knot_dname_t *sample = knot_dname_from_str(item);
+	knot_dname_t *sample = knot_dname_from_str_alloc(item);
 	knot_dname_to_lower(sample);
 	conf_key_t* r = 0;
 	WALK_LIST (r, new_config->keys) {
@@ -328,7 +328,7 @@ static int conf_key_add(void *scanner, knot_tsig_key_t **key, char *item)
 	*key = 0;
 
 	/* Find in keys */
-	knot_dname_t *sample = knot_dname_from_str(item);
+	knot_dname_t *sample = knot_dname_from_str_alloc(item);
 	knot_dname_to_lower(sample);
 
 	conf_key_t* r = 0;
@@ -376,7 +376,7 @@ static void conf_zone_start(void *scanner, char *name) {
 	/* Check domain name. */
 	knot_dname_t *dn = NULL;
 	if (this_zone->name != NULL) {
-		dn = knot_dname_from_str(this_zone->name);
+		dn = knot_dname_from_str_alloc(this_zone->name);
 	}
 	if (dn == NULL) {
 		free(this_zone->name);
@@ -679,7 +679,7 @@ keys:
      }
 
      if (fqdn != NULL && !conf_key_exists(scanner, fqdn)) {
-         knot_dname_t *dname = knot_dname_from_str(fqdn);
+         knot_dname_t *dname = knot_dname_from_str_alloc(fqdn);
 	 if (!dname) {
              cf_error(scanner, "key name '%s' not in valid domain name format",
                       fqdn);
diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
index ca6b25a20d9768ab51239a67cecaded7123f7b8a..122a31e0f0ccd421b40d9f4cb59c46e5ef7e9191 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -656,7 +656,7 @@ static int cmd_checkconf(int argc, char *argv[], unsigned flags)
 static bool fetch_zone(int argc, char *argv[], conf_zone_t *zone)
 {
 	/* Convert zone name to dname */
-	knot_dname_t *zone_name = knot_dname_from_str(zone->name);
+	knot_dname_t *zone_name = knot_dname_from_str_alloc(zone->name);
 	if (zone_name == NULL) {
 		return false;
 	}
@@ -667,7 +667,7 @@ static bool fetch_zone(int argc, char *argv[], conf_zone_t *zone)
 	int i = 0;
 	while (!found && i < argc) {
 		/* Convert the argument to dname */
-		knot_dname_t *arg_name = knot_dname_from_str(argv[i]);
+		knot_dname_t *arg_name = knot_dname_from_str_alloc(argv[i]);
 
 		if (arg_name != NULL) {
 			(void)knot_dname_to_lower(arg_name);
diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 21f0bd4a07451a6bcd495d2b3336e6123ee23799..90a91bb29c0f699b7a49c0f366b8f7834543988f 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -607,7 +607,7 @@ static void log_command(const char *cmd, const remote_cmdargs_t* args)
 		uint16_t rr_count = rr->rrs.rr_count;
 		for (uint16_t j = 0; j < rr_count; j++) {
 			const knot_dname_t *dn = knot_ns_name(&rr->rrs, j);
-			char *name = knot_dname_to_str(dn);
+			char *name = knot_dname_to_str_alloc(dn);
 
 			int ret = snprintf(params, rest, " %s", name);
 			free(name);
@@ -637,7 +637,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt)
 		return KNOT_EMALF;
 	}
 
-	knot_dname_t *realm = knot_dname_from_str(KNOT_CTL_REALM);
+	knot_dname_t *realm = knot_dname_from_str_alloc(KNOT_CTL_REALM);
 	if (!knot_dname_is_sub(qname, realm) != 0) {
 		dbg_server("remote: qname != *%s\n", KNOT_CTL_REALM_EXT);
 		knot_dname_free(&realm, NULL);
@@ -899,7 +899,7 @@ knot_pkt_t* remote_query(const char *query, const knot_tsig_key_t *key)
 
 	/* Question section. */
 	char *qname = strcdup(query, KNOT_CTL_REALM_EXT);
-	knot_dname_t *dname = knot_dname_from_str(qname);
+	knot_dname_t *dname = knot_dname_from_str_alloc(qname);
 	free(qname);
 	if (!dname) {
 		knot_pkt_free(&pkt);
@@ -944,7 +944,7 @@ int remote_build_rr(knot_rrset_t *rr, const char *k, uint16_t t)
 	}
 
 	/* Assert K is FQDN. */
-	knot_dname_t *key = knot_dname_from_str(k);
+	knot_dname_t *key = knot_dname_from_str_alloc(k);
 	if (key == NULL) {
 		return KNOT_ENOMEM;
 	}
@@ -993,7 +993,7 @@ int remote_create_ns(knot_rrset_t *rr, const char *d)
 	}
 
 	/* Create dname. */
-	knot_dname_t *dn = knot_dname_from_str(d);
+	knot_dname_t *dn = knot_dname_from_str_alloc(d);
 	if (!dn) {
 		return KNOT_ERROR;
 	}
diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c
index 9d9e2123a4926c84578e38274cf7ba6cf6f04e05..a2cab60076ed8b8e04e4fc671850ac507dad4868 100644
--- a/src/knot/dnssec/nsec3-chain.c
+++ b/src/knot/dnssec/nsec3-chain.c
@@ -287,7 +287,7 @@ static zone_node_t *create_nsec3_node(knot_dname_t *owner,
 	if (!new_node) {
 		return NULL;
 	}
-	
+
 	node_set_parent(new_node, apex_node);
 
 	knot_rrset_t nsec3_rrset;
@@ -384,7 +384,7 @@ static int connect_nsec3_nodes(zone_node_t *a, zone_node_t *b,
 
 	assert(raw_length == knot_nsec3_hash_length(algorithm));
 
-	uint8_t *b32_hash = (uint8_t *)knot_dname_to_str(b->owner);
+	uint8_t *b32_hash = (uint8_t *)knot_dname_to_str_alloc(b->owner);
 	size_t b32_length = knot_nsec3_hash_b32_length(algorithm);
 	if (!b32_hash) {
 		return KNOT_ENOMEM;
diff --git a/src/knot/modules/synth_record.c b/src/knot/modules/synth_record.c
index 779b3517a11d9d0af2fa122749791612423f14e4..80be22c2a3fa16383e78d5ffb117587964d5551e 100644
--- a/src/knot/modules/synth_record.c
+++ b/src/knot/modules/synth_record.c
@@ -185,7 +185,7 @@ static knot_dname_t *synth_ptrname(const char *addr_str, synth_template_t *tpl)
 	memcpy(ptrname + written, tpl->zone, zone_len);
 
 	/* Convert to domain name. */
-	return knot_dname_from_str(ptrname);
+	return knot_dname_from_str_alloc(ptrname);
 }
 
 static int reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, knot_rrset_t *rr)
@@ -361,7 +361,7 @@ int synth_record_load(struct query_plan *plan, struct query_module *self)
 	/* Parse zone if generating reverse record. */
 	if (tpl->type == SYNTH_REVERSE) {
 		tpl->zone = strtok_r(NULL, " ", &saveptr);
-		knot_dname_t *check_name = knot_dname_from_str(tpl->zone);
+		knot_dname_t *check_name = knot_dname_from_str_alloc(tpl->zone);
 		if (check_name == NULL) {
 			MODULE_ERR("invalid zone '%s'", tpl->zone);
 			return KNOT_EMALF;
diff --git a/src/knot/nameserver/chaos.c b/src/knot/nameserver/chaos.c
index 41822136355eede084f8557e4ed8e47cd2763114..086ca8e7aff258df824dfdfd1f3091f0c1ce0d5e 100644
--- a/src/knot/nameserver/chaos.c
+++ b/src/knot/nameserver/chaos.c
@@ -26,7 +26,7 @@
  */
 static const char *get_txt_response_string(const knot_dname_t *qname)
 {
-	char *qname_str = knot_dname_to_str(qname);
+	char *qname_str = knot_dname_to_str_alloc(qname);
 	const char *response = NULL;
 
 	/* id.server and hostname.bind should have similar meaning */
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index 0dd6214ce5d528471ab26fe8c7b1bebcbd70ee98..5214f158d07c4c3ae73320500637b9e2272adadb 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -416,8 +416,8 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda
 	qdata->name = knot_cname_name(&cname_rr.rrs);
 
 #ifdef KNOT_NS_DEBUG
-	char *cname_str = knot_dname_to_str(cname_node->owner);
-	char *target_str = knot_dname_to_str(qdata->name);
+	char *cname_str = knot_dname_to_str_alloc(cname_node->owner);
+	char *target_str = knot_dname_to_str_alloc(qdata->name);
 	dbg_ns("%s: FOLLOW '%s' -> '%s'\n", __func__, cname_str, target_str);
 	free(cname_str);
 	free(target_str);
diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c
index abf8546a364f40e913c530d8121760b4908eb533..1cb76edbb3bb51b4ce799d2919251d355b997cbf 100644
--- a/src/knot/nameserver/nsec_proofs.c
+++ b/src/knot/nameserver/nsec_proofs.c
@@ -107,7 +107,7 @@ static int ns_put_covering_nsec3(const zone_contents_t *zone,
 	}
 
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(prev->owner);
+	char *name = knot_dname_to_str_alloc(prev->owner);
 	dbg_ns_verb("Covering NSEC3 node: %s\n", name);
 	free(name);
 );
@@ -155,7 +155,7 @@ static int ns_put_nsec3_closest_encloser_proof(
 
 	if (zone_contents_nsec3params(zone) == NULL) {
 dbg_ns_exec_verb(
-		char *name = knot_dname_to_str(zone->apex->owner);
+		char *name = knot_dname_to_str_alloc(zone->apex->owner);
 		dbg_ns_verb("No NSEC3PARAM found in zone %s.\n", name);
 		free(name);
 );
@@ -163,7 +163,7 @@ dbg_ns_exec_verb(
 	}
 
 dbg_ns_exec_detail(
-	char *name = knot_dname_to_str((*closest_encloser)->owner);
+	char *name = knot_dname_to_str_alloc((*closest_encloser)->owner);
 	dbg_ns_detail("Closest encloser: %s\n", name);
 	free(name);
 );
@@ -186,14 +186,14 @@ dbg_ns_exec_detail(
 	assert(nsec3_node != NULL);
 
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(nsec3_node->owner);
+	char *name = knot_dname_to_str_alloc(nsec3_node->owner);
 	dbg_ns_verb("NSEC3 node: %s\n", name);
 	free(name);
-	name = knot_dname_to_str((*closest_encloser)->owner);
+	name = knot_dname_to_str_alloc((*closest_encloser)->owner);
 	dbg_ns_verb("Closest provable encloser: %s\n", name);
 	free(name);
 	if (next_closer != NULL) {
-		name = knot_dname_to_str(next_closer);
+		name = knot_dname_to_str_alloc(next_closer);
 		dbg_ns_verb("Next closer name: %s\n", name);
 		free(name);
 	} else {
@@ -218,7 +218,7 @@ dbg_ns_exec_verb(
 			return KNOT_ERROR; /*servfail */
 		}
 dbg_ns_exec_verb(
-		char *name = knot_dname_to_str(new_next_closer);
+		char *name = knot_dname_to_str_alloc(new_next_closer);
 		dbg_ns_verb("Next closer name: %s\n", name);
 		free(name);
 );
@@ -244,7 +244,7 @@ static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name)
 {
 	assert(name != NULL);
 
-	knot_dname_t *wildcard = knot_dname_from_str("*");
+	knot_dname_t *wildcard = knot_dname_from_str_alloc("*");
 	if (wildcard == NULL) {
 		return NULL;
 	}
@@ -254,7 +254,7 @@ static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name)
 		return NULL;
 
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(wildcard);
+	char *name = knot_dname_to_str_alloc(wildcard);
 	dbg_ns_verb("Wildcard: %s\n", name);
 	free(name);
 );
@@ -386,7 +386,7 @@ static int ns_put_nsec3_wildcard(const zone_contents_t *zone,
 		return KNOT_ERROR; /* servfail */
 	}
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(next_closer);
+	char *name = knot_dname_to_str_alloc(next_closer);
 	dbg_ns_verb("Next closer name: %s\n", name);
 	free(name);
 );
@@ -480,7 +480,7 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname,
 	}
 
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(previous->owner);
+	char *name = knot_dname_to_str_alloc(previous->owner);
 	dbg_ns_verb("Previous node: %s\n", name);
 	free(name);
 );
@@ -517,7 +517,7 @@ dbg_ns_exec_verb(
 
 	while (knot_dname_cmp(prev_new->owner, wildcard) > 0) {
 dbg_ns_exec_verb(
-		char *name = knot_dname_to_str(prev_new->owner);
+		char *name = knot_dname_to_str_alloc(prev_new->owner);
 		dbg_ns_verb("Previous node: %s\n", name);
 		free(name);
 );
@@ -527,7 +527,7 @@ dbg_ns_exec_verb(
 	assert(knot_dname_cmp(prev_new->owner, wildcard) < 0);
 
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(prev_new->owner);
+	char *name = knot_dname_to_str_alloc(prev_new->owner);
 	dbg_ns_verb("Previous node: %s\n", name);
 	free(name);
 );
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index 9a4158ade629db75a427d4be0928f39e36b77930..494d00bbf6c61be155d381c6928b1e7f7f2f9fe7 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -436,7 +436,7 @@ static bool singleton_replaced(changeset_t *changeset,
 	if (!should_replace(rr)) {
 		return false;
 	}
-	
+
 	zone_node_t *n = zone_contents_find_node_for_rr(changeset->add, rr);
 	if (n == NULL) {
 		return false;
@@ -446,12 +446,12 @@ static bool singleton_replaced(changeset_t *changeset,
 	if (rrs == NULL) {
 		return false;
 	}
-	
+
 	// Replace singleton RR.
 	knot_rdataset_clear(rrs, NULL);
 	node_remove_rdataset(n, rr->type);
 	node_add_rrset(n, rr, NULL);
-	
+
 	return true;
 }
 
@@ -544,7 +544,7 @@ static int process_add_nsec3param(const zone_node_t *node,
 {
 	if (node == NULL || !node_rrtype_exists(node, KNOT_RRTYPE_SOA)) {
 		// Ignore non-apex additions
-		char *owner = knot_dname_to_str(rr->owner);
+		char *owner = knot_dname_to_str_alloc(rr->owner);
 		log_warning("DDNS, refusing to add NSEC3PARAM to non-apex "
 		            "node '%s'", owner);
 		free(owner);
@@ -555,7 +555,7 @@ static int process_add_nsec3param(const zone_node_t *node,
 		return add_rr_to_chgset(rr, changeset, NULL);
 	}
 
-	char *owner = knot_dname_to_str(rr->owner);
+	char *owner = knot_dname_to_str_alloc(rr->owner);
 	log_warning("DDNS, refusing to add second NSEC3PARAM to node '%s'", owner);
 	free(owner);
 
@@ -918,7 +918,7 @@ int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
 		}
 		return KNOT_EINVAL;
 	}
-	
+
 	changeset_t *changeset = update->change;
 
 	if (changeset->soa_from == NULL) {
diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c
index ee94c00cae4dc024ad5b82f86c71cdc6a10c6937..e9058ba9bd7a9961fb609bc01db4fd2bf012aa6f 100644
--- a/src/knot/zone/contents.c
+++ b/src/knot/zone/contents.c
@@ -748,7 +748,7 @@ int zone_contents_remove_node(zone_contents_t *contents, const knot_dname_t *own
 	}
 
 dbg_zone_exec_verb(
-	char *name = knot_dname_to_str(owner);
+	char *name = knot_dname_to_str_alloc(owner);
 	dbg_zone_verb("Removing zone node: %s\n", name);
 	free(name);
 );
@@ -805,8 +805,8 @@ int zone_contents_find_dname(const zone_contents_t *zone,
 	}
 
 dbg_zone_exec_verb(
-	char *name_str = knot_dname_to_str(name);
-	char *zone_str = knot_dname_to_str(zone->apex->owner);
+	char *name_str = knot_dname_to_str_alloc(name);
+	char *zone_str = knot_dname_to_str_alloc(zone->apex->owner);
 	dbg_zone_verb("Searching for name %s in zone %s...\n",
 		      name_str, zone_str);
 	free(name_str);
@@ -822,10 +822,10 @@ dbg_zone_exec_verb(
 	*previous = prev;
 
 dbg_zone_exec_detail(
-	char *name_str = (*node) ? knot_dname_to_str((*node)->owner)
+	char *name_str = (*node) ? knot_dname_to_str_alloc((*node)->owner)
 				 : "(nil)";
 	char *name_str2 = (*previous != NULL)
-			  ? knot_dname_to_str((*previous)->owner)
+			  ? knot_dname_to_str_alloc((*previous)->owner)
 			  : "(nil)";
 dbg_zone_detail("Search function returned %d, node %s (%p) and prev: %s (%p)\n",
 			exact_match, name_str, *node, name_str2, *previous);
@@ -937,7 +937,7 @@ int zone_contents_find_nsec3_for_name(const zone_contents_t *zone,
 	}
 
 dbg_zone_exec_verb(
-	char *n = knot_dname_to_str(nsec3_name);
+	char *n = knot_dname_to_str_alloc(nsec3_name);
 	dbg_zone_verb("NSEC3 node name: %s.\n", n);
 	free(n);
 );
@@ -953,7 +953,7 @@ dbg_zone_exec_verb(
 
 dbg_zone_exec_detail(
 	if (found) {
-		char *n = knot_dname_to_str(found->owner);
+		char *n = knot_dname_to_str_alloc(found->owner);
 		dbg_zone_detail("Found NSEC3 node: %s.\n", n);
 		free(n);
 	} else {
@@ -962,7 +962,7 @@ dbg_zone_exec_detail(
 
 	if (prev) {
 		assert(prev->owner);
-		char *n = knot_dname_to_str(prev->owner);
+		char *n = knot_dname_to_str_alloc(prev->owner);
 		dbg_zone_detail("Found previous NSEC3 node: %s.\n", n);
 		free(n);
 	} else {
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
index 199171dcb9c2663fbc600302a2e384a8b175c6e4..0403c862480938f197ce913d24b48a2db865a336 100644
--- a/src/knot/zone/semantic-check.c
+++ b/src/knot/zone/semantic-check.c
@@ -181,7 +181,7 @@ static void log_error_from_node(err_handler_t *handler,
 
 	handler->error_count++;
 
-	char *name = knot_dname_to_str(node->owner);
+	char *name = knot_dname_to_str_alloc(node->owner);
 	const char *errmsg = error_messages[-error];
 
 	log_zone_warning(zone_name, "semantic check, node '%s' (%s%s%s)",
diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c
index ef601ec07996eaa232737f339bc6d9ce90efef71..370a45d1e89395e7ae827182a4967ee6b070ac91 100644
--- a/src/knot/zone/zone-tree.c
+++ b/src/knot/zone/zone-tree.c
@@ -170,9 +170,9 @@ int zone_tree_get_less_or_equal(zone_tree_t *tree,
 	}
 
 dbg_zone_exec_detail(
-		char *name = knot_dname_to_str(owner);
+		char *name = knot_dname_to_str_alloc(owner);
 		char *name_f = (*found != NULL)
-			? knot_dname_to_str((*found)->owner)
+			? knot_dname_to_str_alloc((*found)->owner)
 			: "none";
 
 		dbg_zone_detail("Searched for owner %s in zone tree.\n",
@@ -214,7 +214,7 @@ zone_node_t *zone_tree_get_next(zone_tree_t *tree,
 		fval = hattrie_iter_val(it);
 		hattrie_iter_free(it);
 	}
-	
+
 	n = (zone_node_t *)*fval;
 	/* Next node must be non-empty and auth. */
 	if (n->rrset_count == 0 || n->flags & NODE_FLAGS_NONAUTH) {
diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c
index 56000527db5e00e25ff0805a20ff4ae322c665b9..e3557ebbba4eef651c8da7f2c4544d8c59e05b6e 100644
--- a/src/knot/zone/zone.c
+++ b/src/knot/zone/zone.c
@@ -60,7 +60,7 @@ zone_t* zone_new(conf_zone_t *conf)
 	}
 	memset(zone, 0, sizeof(zone_t));
 
-	zone->name = knot_dname_from_str(conf->name);
+	zone->name = knot_dname_from_str_alloc(conf->name);
 	knot_dname_to_lower(zone->name);
 	if (zone->name == NULL) {
 		free(zone);
diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c
index 6bb1f6da7eed8a15cc38505d388c9eace6b604cc..94ff044b05bdf562bb78f01cf5a8c6692e5b8448 100644
--- a/src/knot/zone/zonedb-load.c
+++ b/src/knot/zone/zonedb-load.c
@@ -199,7 +199,7 @@ static knot_zonedb_t *create_zonedb(const conf_t *conf, server_t *server)
 
 		conf_zone_t *zone_config = (conf_zone_t *)*hattrie_iter_val(it);
 
-		knot_dname_t *apex = knot_dname_from_str(zone_config->name);
+		knot_dname_t *apex = knot_dname_from_str_alloc(zone_config->name);
 		zone_t *old_zone = knot_zonedb_find(db_old, apex);
 		knot_dname_free(&apex, NULL);
 
diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c
index 1275b1905cd292ff1cf607c5149f61acd4d02c13..82c347064921f4c9a78eb82cab3915d1cd465ba6 100644
--- a/src/knot/zone/zonefile.c
+++ b/src/knot/zone/zonefile.c
@@ -64,7 +64,7 @@ static bool handle_err(zcreator_t *zc, const zone_node_t *node,
                        const knot_rrset_t *rr, int ret, bool master)
 {
 	const knot_dname_t *zname = zc->z->apex->owner;
-	char *rrname = rr ? knot_dname_to_str(rr->owner) : NULL;
+	char *rrname = rr ? knot_dname_to_str_alloc(rr->owner) : NULL;
 	if (ret == KNOT_EOUTOFZONE) {
 		WARNING(zname, "ignoring out-of-zone data, owner '%s'",
 		        rrname ? rrname : "unknown");
@@ -201,7 +201,7 @@ static void scanner_process(zs_scanner_t *scanner)
 	knot_rrset_init(&rr, owner, scanner->r_type, scanner->r_class);
 	int ret = add_rdata_to_rr(&rr, scanner);
 	if (ret != KNOT_EOK) {
-		char *rr_name = knot_dname_to_str(rr.owner);
+		char *rr_name = knot_dname_to_str_alloc(rr.owner);
 		const knot_dname_t *zname = zc->z->apex->owner;
 		ERROR(zname, "failed to add RDATA, file '%s', line %"PRIu64", owner '%s'",
 		      scanner->file.name, scanner->line_counter, rr_name);
@@ -224,7 +224,7 @@ static zone_contents_t *create_zone_from_name(const char *origin)
 	if (origin == NULL) {
 		return NULL;
 	}
-	knot_dname_t *owner = knot_dname_from_str(origin);
+	knot_dname_t *owner = knot_dname_from_str_alloc(origin);
 	if (owner == NULL) {
 		return NULL;
 	}
diff --git a/src/libknot/consts.h b/src/libknot/consts.h
index 0310673860119b2c16a85cf75f50815af0b483dc..6bd94da895d6e9fc3c92196c1331fb35fa8807b9 100644
--- a/src/libknot/consts.h
+++ b/src/libknot/consts.h
@@ -34,8 +34,9 @@
 /*!
  * \brief Basic limits for domain names (RFC 1035).
  */
-#define KNOT_DNAME_MAXLEN 255     /*!< 1-byte maximum. */
-#define KNOT_DNAME_MAXLABELS 127  /*!< 1-char labels. */
+#define KNOT_DNAME_MAXLEN      255 /*!< 1-byte maximum. */
+#define KNOT_DNAME_MAXLABELS   127 /*!< 1-char labels. */
+#define KNOT_DNAME_MAXLABELLEN  63 /*!< 2^6 - 1 */
 
 /*!
  * \brief Address family numbers.
diff --git a/src/libknot/dname.c b/src/libknot/dname.c
index e5ad1b8494e5eb17b9880f55fcfe18ab9578b196..31b7a6b88313fbcd1d130547349711f1e79eef20 100644
--- a/src/libknot/dname.c
+++ b/src/libknot/dname.c
@@ -73,8 +73,8 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
 				is_compressed = true;
 			}
 		} else {
-			/* Check label length (maximum 63 bytes allowed). */
-			if (*name > 63)
+			/* Check label length. */
+			if (*name > KNOT_DNAME_MAXLABELLEN)
 				return KNOT_EMALF;
 			/* Check if there's enough space. */
 			int lblen = *name + 1;
@@ -211,17 +211,24 @@ int knot_dname_unpack(uint8_t* dst, const knot_dname_t *src,
 
 /*----------------------------------------------------------------------------*/
 
-char *knot_dname_to_str(const knot_dname_t *name)
+char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen)
 {
-	if (name == NULL)
+	if (name == NULL) {
 		return NULL;
+	}
 
-	/*! \todo Supply packet. */
-	/*! \todo Write to static buffer? */
-	// Allocate space for dname string + 1 char termination.
 	int dname_size = knot_dname_size(name);
-	size_t alloc_size = dname_size + 1;
-	char *res = malloc(alloc_size);
+	if (dname_size <= 0) {
+		return NULL;
+	}
+
+	/* Check the size for len(dname) + 1 char termination. */
+	size_t alloc_size = (dst == NULL) ? dname_size + 1 : maxlen;
+	if (alloc_size < dname_size + 1) {
+		return NULL;
+	}
+
+	char *res = (dst == NULL) ? malloc(alloc_size) : dst;
 	if (res == NULL) {
 		return NULL;
 	}
@@ -232,11 +239,11 @@ char *knot_dname_to_str(const knot_dname_t *name)
 	for (uint i = 0; i < dname_size; i++) {
 		uint8_t c = name[i];
 
-		// Read next label size.
+		/* Read next label size. */
 		if (label_len == 0) {
 			label_len = c;
 
-			// Write label separation.
+			/* Write label separation. */
 			if (str_len > 0 || dname_size == 1) {
 				res[str_len++] = '.';
 			}
@@ -253,33 +260,47 @@ char *knot_dname_to_str(const knot_dname_t *name)
 			 * encoded in \ddd notation.
 			 */
 
-			// Increase output size for \x format.
-			alloc_size += 1;
-			char *extended = realloc(res, alloc_size);
-			if (extended == NULL) {
-				free(res);
-				return NULL;
+			if (dst != NULL) {
+				if (maxlen <= str_len + 2) {
+					return NULL;
+				}
+			} else {
+				/* Extend output buffer for \x format. */
+				alloc_size += 1;
+				char *extended = realloc(res, alloc_size);
+				if (extended == NULL) {
+					free(res);
+					return NULL;
+				}
+				res = extended;
 			}
-			res = extended;
 
-			// Write encoded character.
+			/* Write encoded character. */
 			res[str_len++] = '\\';
 			res[str_len++] = c;
 		} else {
-			// Increase output size for \DDD format.
-			alloc_size += 3;
-			char *extended = realloc(res, alloc_size);
-			if (extended == NULL) {
-				free(res);
-				return NULL;
+			if (dst != NULL) {
+				if (maxlen <= str_len + 4) {
+					return NULL;
+				}
+			} else {
+				/* Extend output buffer for \DDD format. */
+				alloc_size += 3;
+				char *extended = realloc(res, alloc_size);
+				if (extended == NULL) {
+					free(res);
+					return NULL;
+				}
+				res = extended;
 			}
-			res = extended;
 
-			// Write encoded character.
+			/* Write encoded character. */
 			int ret = snprintf(res + str_len, alloc_size - str_len,
 			                   "\\%03u", c);
 			if (ret <= 0 || ret >= alloc_size - str_len) {
-				free(res);
+				if (dst == NULL) {
+					free(res);
+				}
 				return NULL;
 			}
 
@@ -289,7 +310,7 @@ char *knot_dname_to_str(const knot_dname_t *name)
 		label_len--;
 	}
 
-	// String_termination.
+	/* String_termination. */
 	res[str_len] = 0;
 
 	return res;
@@ -297,60 +318,143 @@ char *knot_dname_to_str(const knot_dname_t *name)
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_from_str(const char *name)
+knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen)
 {
 	if (name == NULL) {
 		return NULL;
 	}
 
-	unsigned len = strlen(name);
-	if (len > KNOT_DNAME_MAXLEN) {
+	size_t name_len = strlen(name);
+	if (name_len == 0) {
 		return NULL;
 	}
 
-	/* 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. */
+	/* Wire size estimation. */
+	size_t alloc_size = maxlen;
+	if (dst == NULL) {
+		/* Check for the root label. */
+		if (name[0] == '.') {
+			/* Just the root dname can begin with a dot. */
+			if (name_len > 1) {
+				return NULL;
+			}
+			name_len = 0; /* Skip the following parsing. */
+			alloc_size = 1;
+		} else if (name[name_len - 1] != '.') { /* Check for non-FQDN. */
+			alloc_size = 1 + name_len + 1;
+		} else {
+			alloc_size = 1 + name_len ; /* + 1 ~ first label length. */
+		}
 	}
 
-	/* Create wire. */
-	uint8_t *wire = malloc(wire_size * sizeof(uint8_t));
-	if (wire == NULL)
+	/* The minimal (root) dname takes 1 byte. */
+	if (alloc_size == 0) {
 		return NULL;
-	*wire = '\0';
+	}
+
+	/* Check the maximal wire size. */
+	if (alloc_size > KNOT_DNAME_MAXLEN) {
+		alloc_size = KNOT_DNAME_MAXLEN;
+	}
+
+	/* Prepare output buffer. */
+	uint8_t *wire = (dst == NULL) ? malloc(alloc_size) : dst;
+	if (wire == NULL) {
+		return NULL;
+	}
 
-	/* 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;
+	uint8_t *wire_pos = wire + 1;
+	uint8_t *wire_end = wire + alloc_size;
+
+	/* Initialize the first label (root label). */
+	*label = 0;
+
+	const uint8_t *ch = (const uint8_t *)name;
+	const uint8_t *end = ch + name_len;
+
+	while (ch < end) {
+		/* Check the output buffer for enough space. */
+		if (wire_pos >= wire_end) {
+			goto dname_from_str_failed;
+		}
+
+		switch (*ch) {
+		case '.':
+			/* Check for invalid zero-length label. */
+			if (*label == 0 && name_len > 1) {
+				goto dname_from_str_failed;
 			}
-			label = w;
-			*label = '\0';
-		} else {
-			*w = *ch;
-			*label += 1;
+			label = wire_pos++;
+			*label = 0;
+			break;
+		case '\\':
+			ch++;
+
+			/* At least one more character is required OR
+			 * check for maximal label length.
+			 */
+			if (ch == end || ++(*label) > KNOT_DNAME_MAXLABELLEN) {
+				goto dname_from_str_failed;
+			}
+
+			/* Check for \DDD notation. */
+			if (isdigit(*ch) != 0) {
+				/* Check for next two digits. */
+				if (ch + 2 >= end ||
+				    isdigit(*(ch + 1)) == 0 ||
+				    isdigit(*(ch + 2)) == 0) {
+					goto dname_from_str_failed;
+				}
+
+				uint32_t num = (*(ch + 0) - '0') * 100 +
+				               (*(ch + 1) - '0') * 10 +
+				               (*(ch + 2) - '0') * 1;
+				if (num > UINT8_MAX) {
+					goto dname_from_str_failed;
+				}
+				*(wire_pos++) = num;
+				ch +=2;
+			} else {
+				*(wire_pos++) = *ch;
+			}
+			break;
+		default:
+			/* Check for maximal label length. */
+			if (++(*label) > KNOT_DNAME_MAXLABELLEN) {
+				goto dname_from_str_failed;
+			}
+			*(wire_pos++) = *ch;
 		}
-		++w;
-		++ch;
+		ch++;
 	}
 
 	/* Check for non-FQDN name. */
 	if (*label > 0) {
-		*w = '\0';
+		if (wire_pos >= wire_end) {
+			goto dname_from_str_failed;
+		}
+		*(wire_pos++) = 0;
+	}
+
+	/* Reduce output buffer if the size is overestimated. */
+	if (wire_pos < wire_end && dst == NULL) {
+		uint8_t *reduced = realloc(wire, wire_pos - wire);
+		if (reduced == NULL) {
+			goto dname_from_str_failed;
+		}
+		wire = reduced;
 	}
 
 	return wire;
+
+dname_from_str_failed:
+
+	if (dst == NULL) {
+		free(wire);
+	}
+
+	return NULL;
 }
 
 /*----------------------------------------------------------------------------*/
diff --git a/src/libknot/dname.h b/src/libknot/dname.h
index 58bfc174e03d347572c1a54cee3d480ed833a746..db7af67c6bd21a6d6191659f81a8aee5b793f543 100644
--- a/src/libknot/dname.h
+++ b/src/libknot/dname.h
@@ -118,31 +118,51 @@ 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.
+ * \brief Converts the given domain name to its string representation.
  *
- * \note Allocates new memory, remember to free it.
+ * \note Output buffer is allocated automatically if dst is NULL.
  *
- * \todo The function doesn't process escaped characters like \DDD or \X.
+ * \param dst    Output buffer.
+ * \param name   Domain name to be converted.
+ * \param maxlen Output buffer length.
  *
- * \param name Domain name to be converted.
- *
- * \return 0-terminated string representing the given domain name in
- *         presentation format.
+ * \return 0-terminated string if successful, NULL if error.
+ */
+char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen);
+
+/*!
+ * \brief This function is a shortcut for \ref knot_dname_to_str with
+ *        no output buffer parameters.
  */
-char *knot_dname_to_str(const knot_dname_t *name);
+static inline char *knot_dname_to_str_alloc(const knot_dname_t *name)
+{
+	return knot_dname_to_str(NULL, name, 0);
+}
 
 /*!
  * \brief Creates a dname structure from domain name given in presentation
  *        format.
  *
- * The resulting FQDN is stored in the wire format.
+ * \note The resulting FQDN is stored in the wire format.
+ * \note Output buffer is allocated automatically if dst is NULL.
  *
- * \param name Domain name in presentation format (labels separated by dots,
- *             '\0' terminated).
+ * \param dst    Output buffer.
+ * \param name   Domain name in presentation format (labels separated by dots,
+ *               '\0' terminated).
+ * \param maxlen Output buffer length.
  *
- * \return New name or NULL
+ * \return New dname if successful, NULL if error.
+ */
+knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen);
+
+/*!
+ * \brief This function is a shortcut for \ref knot_dname_from_str with
+ *        no output buffer parameters.
  */
-knot_dname_t *knot_dname_from_str(const char *name);
+static inline knot_dname_t *knot_dname_from_str_alloc(const char *name)
+{
+	return knot_dname_from_str(NULL, name, 0);
+}
 
 /*!
  * \brief Convert name to lowercase.
diff --git a/src/libknot/dnssec/key.c b/src/libknot/dnssec/key.c
index dc6fff2894e68b6ae1f16264ebcbc85f262c3b56..2b9cce3102257bec449d69ca3f725d334675bc50 100644
--- a/src/libknot/dnssec/key.c
+++ b/src/libknot/dnssec/key.c
@@ -528,7 +528,7 @@ int knot_tsig_create_key(const char *name, int algorithm,
 	}
 
 	knot_dname_t *dname;
-	dname = knot_dname_from_str(name);
+	dname = knot_dname_from_str_alloc(name);
 	if (!dname) {
 		return KNOT_ENOMEM;
 	}
diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c
index 75f3590e2031d8aa0e6b6f12ca577fa29b4089b2..647ea6b95752cad3054b70abcdb23ce300e7ed0d 100644
--- a/src/libknot/rrset-dump.c
+++ b/src/libknot/rrset-dump.c
@@ -804,16 +804,23 @@ static void wire_dname_to_str(rrset_dump_params_t *p)
 	}
 
 	// Write dname string.
-	char *dname_str = knot_dname_to_str(p->in);
-	if (p->style->ascii_to_idn != NULL) {
+	if (p->style->ascii_to_idn == NULL) {
+		char *dname_str = knot_dname_to_str(p->out, p->in, p->out_max);
+		if (dname_str == NULL) {
+			return;
+		}
+		out_len = strlen(dname_str);
+	} else {
+		char *dname_str = knot_dname_to_str_alloc(p->in);
 		p->style->ascii_to_idn(&dname_str);
+
+		int ret = snprintf(p->out, p->out_max, "%s", dname_str);
+		free(dname_str);
+		if (ret < 0 || (size_t)ret >= p->out_max) {
+			return;
+		}
+		out_len = ret;
 	}
-	int ret = snprintf(p->out, p->out_max, "%s", dname_str);
-	free(dname_str);
-	if (ret < 0 || (size_t)ret >= p->out_max) {
-		return;
-	}
-	out_len = ret;
 
 	// Fill in output.
 	p->in += in_len;
@@ -1831,7 +1838,7 @@ int knot_rrset_txt_dump_header(const knot_rrset_t      *rrset,
 	int    ret;
 
 	// Dump rrset owner.
-	char *name = knot_dname_to_str(rrset->owner);
+	char *name = knot_dname_to_str_alloc(rrset->owner);
 	if (style->ascii_to_idn != NULL) {
 		style->ascii_to_idn(&name);
 	}
diff --git a/src/libknot/rrtype/tsig.c b/src/libknot/rrtype/tsig.c
index 814883d48d452289453ec93d0846e4cb7951d4da..7722d3a1d47de58d42800ec65542936cee350190 100644
--- a/src/libknot/rrtype/tsig.c
+++ b/src/libknot/rrtype/tsig.c
@@ -241,7 +241,7 @@ knot_tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig)
 	}
 
 	/* Convert alg name to string. */
-	char *name = knot_dname_to_str(alg_name);
+	char *name = knot_dname_to_str_alloc(alg_name);
 	if (!name) {
 		dbg_tsig("TSIG: rdata: cannot convert alg name.\n");
 		return KNOT_TSIG_ALG_NULL;
@@ -336,7 +336,7 @@ int tsig_alg_from_name(const knot_dname_t *alg_name)
 		return 0;
 	}
 
-	char *name = knot_dname_to_str(alg_name);
+	char *name = knot_dname_to_str_alloc(alg_name);
 	if (!name) {
 		return 0;
 	}
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 43c6b6c009139dac48714c15aca865ddedbfa589..2d91e2db75eccfccbaf61c6754bb04f1766ac322 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -69,7 +69,7 @@ static int knot_tsig_check_key(const knot_rrset_t *tsig_rr,
 		return KNOT_EMALF;
 	}
 
-	char *name = knot_dname_to_str(tsig_name);
+	char *name = knot_dname_to_str_alloc(tsig_name);
 	if (!name) {
 		return KNOT_EMALF;
 	}
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
index b4ff5fa5fe6a92469bddd9772d4dd6a0f70032ca..d516518aff7e90fb24b17504ebdb98e44e2a4908 100644
--- a/src/utils/common/exec.c
+++ b/src/utils/common/exec.c
@@ -376,7 +376,7 @@ static void print_section_host(const knot_rrset_t *rrsets,
 		char                type[32] = "NULL";
 		char                *owner;
 
-		owner = knot_dname_to_str(rrset->owner);
+		owner = knot_dname_to_str_alloc(rrset->owner);
 		if (style->style.ascii_to_idn != NULL) {
 			style->style.ascii_to_idn(&owner);
 		}
@@ -432,7 +432,7 @@ static void print_error_host(const uint8_t    code,
 
 	knot_lookup_table_t *rcode;
 
-	owner = knot_dname_to_str(knot_pkt_qname(packet));
+	owner = knot_dname_to_str_alloc(knot_pkt_qname(packet));
 	if (style->style.ascii_to_idn != NULL) {
 		style->style.ascii_to_idn(&owner);
 	}
@@ -486,7 +486,7 @@ void print_header_xfr(const knot_pkt_t *packet, const style_t  *style)
 	}
 
 	if (style->show_header) {
-		char *owner = knot_dname_to_str(knot_pkt_qname(packet));
+		char *owner = knot_dname_to_str_alloc(knot_pkt_qname(packet));
 		if (style->style.ascii_to_idn != NULL) {
 			style->style.ascii_to_idn(&owner);
 		}
diff --git a/src/utils/common/params.c b/src/utils/common/params.c
index 3e308834cfef4f796da0f4bf6840ea418d73d6b2..0058e3a3aacf3389981050a75fba4e5695d67193 100644
--- a/src/utils/common/params.c
+++ b/src/utils/common/params.c
@@ -434,7 +434,7 @@ int params_parse_tsig(const char *value, knot_key_params_t *key_params)
 	}
 
 	/* Set key name and secret. */
-	key_params->name = knot_dname_from_str(k);
+	key_params->name = knot_dname_from_str_alloc(k);
 	knot_dname_to_lower(key_params->name);
 	int r = knot_binary_from_base64(s, &key_params->secret);
 	if (r != KNOT_EOK) {
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index 2dc8d16844213fb38a9a32a1f83e1c7101715635..e5f5f3b32bc69b5f594d2244f9f6108036b64567 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -315,7 +315,7 @@ static knot_pkt_t* create_query_packet(const query_t *query)
 	}
 
 	// Create QNAME from string.
-	knot_dname_t *qname = knot_dname_from_str(query->owner);
+	knot_dname_t *qname = knot_dname_from_str_alloc(query->owner);
 	if (qname == NULL) {
 		knot_pkt_free(&packet);
 		return NULL;
diff --git a/src/utils/nsec3hash/nsec3hash_main.c b/src/utils/nsec3hash/nsec3hash_main.c
index 8fa87a43c41fc5e71877de628f4622439913f174..5cfb8b938f09fa5df89bdb822774343d5cd446c6 100644
--- a/src/utils/nsec3hash/nsec3hash_main.c
+++ b/src/utils/nsec3hash/nsec3hash_main.c
@@ -150,10 +150,10 @@ int main(int argc, char *argv[])
 			fprintf(stderr, "Cannot transform IDN domain name.\n");
 			goto fail;
 		}
-		dname = knot_dname_from_str(ascii_name);
+		dname = knot_dname_from_str_alloc(ascii_name);
 		free(ascii_name);
 	} else {
-		dname = knot_dname_from_str(argv[4]);
+		dname = knot_dname_from_str_alloc(argv[4]);
 	}
 	if (dname == NULL) {
 		fprintf(stderr, "Cannot parse domain name.\n");
diff --git a/src/utils/nsupdate/nsupdate_exec.c b/src/utils/nsupdate/nsupdate_exec.c
index 8b8cf397ccc047570038799afc68f5a666bc3502..c212d6987a33a08b2341e6c55d023b0b06397b8d 100644
--- a/src/utils/nsupdate/nsupdate_exec.c
+++ b/src/utils/nsupdate/nsupdate_exec.c
@@ -145,7 +145,7 @@ enum {
 
 static bool dname_isvalid(const char *lp)
 {
-	knot_dname_t *dn = knot_dname_from_str(lp);
+	knot_dname_t *dn = knot_dname_from_str_alloc(lp);
 	if (dn == NULL) {
 		return false;
 	}
@@ -187,7 +187,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags)
 		fqdn = false;
 	}
 
-	knot_dname_t *owner = knot_dname_from_str(owner_str);
+	knot_dname_t *owner = knot_dname_from_str_alloc(owner_str);
 	free(owner_str);
 	if (owner == NULL) {
 		return KNOT_EPARSEFAIL;
@@ -388,7 +388,7 @@ static int build_query(nsupdate_params_t *params)
 	/* Write question. */
 	knot_wire_set_id(query->wire, knot_random_uint16_t());
 	knot_wire_set_opcode(query->wire, KNOT_OPCODE_UPDATE);
-	knot_dname_t *qname = knot_dname_from_str(params->zone);
+	knot_dname_t *qname = knot_dname_from_str_alloc(params->zone);
 	int ret = knot_pkt_put_question(query, qname, params->class_num,
 	                                params->type_num);
 	knot_dname_free(&qname, NULL);
diff --git a/tests/changeset.c b/tests/changeset.c
index e76da37344626cc1eeacce2abdc3609df9cda360..b9734dd0802f73c7c93d7493df59731c8ec5edb8 100644
--- a/tests/changeset.c
+++ b/tests/changeset.c
@@ -29,7 +29,7 @@ int main(int argc, char *argv[])
 	ok(changeset_empty(NULL), "changeset: NULL empty");
 
 	// Test creation.
-	knot_dname_t *d = knot_dname_from_str("test.");
+	knot_dname_t *d = knot_dname_from_str_alloc("test.");
 	assert(d);
 	changeset_t *ch = changeset_new(d);
 	knot_dname_free(&d, NULL);
@@ -41,7 +41,7 @@ int main(int argc, char *argv[])
 	ok(changeset_size(ch) == 0, "changeset: empty size");
 
 	// Test additions.
-	d = knot_dname_from_str("non.terminals.test.");
+	d = knot_dname_from_str_alloc("non.terminals.test.");
 	assert(d);
 	knot_rrset_t *apex_txt_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, NULL);
 	assert(apex_txt_rr);
@@ -66,7 +66,7 @@ int main(int argc, char *argv[])
 
 	// Add another node.
 	knot_dname_free(&d, NULL);
-	d = knot_dname_from_str("here.come.more.non.terminals.test");
+	d = knot_dname_from_str_alloc("here.come.more.non.terminals.test");
 	assert(d);
 	knot_rrset_t *other_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, NULL);
 	assert(other_rr);
@@ -114,14 +114,14 @@ int main(int argc, char *argv[])
 
 	// Create new changeset.
 	knot_dname_free(&d, NULL);
-	d = knot_dname_from_str("test.");
+	d = knot_dname_from_str_alloc("test.");
 	assert(d);
 	changeset_t *ch2 = changeset_new(d);
 	knot_dname_free(&d, NULL);
 	assert(ch2);
 	// Add something to add section.
 	knot_dname_free(&apex_txt_rr->owner, NULL);
-	apex_txt_rr->owner = knot_dname_from_str("something.test.");
+	apex_txt_rr->owner = knot_dname_from_str_alloc("something.test.");
 	assert(apex_txt_rr->owner);
 	ret = changeset_add_rrset(ch2, apex_txt_rr);
 	assert(ret == KNOT_EOK);
@@ -129,7 +129,7 @@ int main(int argc, char *argv[])
 	// Add something to remove section.
 	knot_dname_free(&apex_txt_rr->owner, NULL);
 	apex_txt_rr->owner =
-		knot_dname_from_str("and.now.for.something.completely.different.test.");
+		knot_dname_from_str_alloc("and.now.for.something.completely.different.test.");
 	assert(apex_txt_rr->owner);
 	ret = changeset_rem_rrset(ch2, apex_txt_rr);
 	assert(ret == KNOT_EOK);
diff --git a/tests/conf.c b/tests/conf.c
index 0b25aad27454f5c7145e4cce2892bbe6b46bb5fd..a70a756a677795cdae52cee252194a5826db556f 100644
--- a/tests/conf.c
+++ b/tests/conf.c
@@ -114,7 +114,7 @@ int main(int argc, char *argv[])
 
 	// Test 21: Load key dname
 	const char *sample_str = "key0.example.net";
-	knot_dname_t *sample = knot_dname_from_str(sample_str);
+	knot_dname_t *sample = knot_dname_from_str_alloc(sample_str);
 	if (list_size(&conf->keys) > 0) {
 		knot_tsig_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k;
 		ok(knot_dname_cmp(sample, k->name) == 0,
diff --git a/tests/dname.c b/tests/dname.c
index 4c7158a9c0ddb0cc103231387f1bf435dd9fe457..498eabd6c97568d2d8ef076a4b3fa22a2ae57b86 100644
--- a/tests/dname.c
+++ b/tests/dname.c
@@ -14,6 +14,7 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <stdlib.h>
 #include <tap/basic.h>
 
 #include "libknot/dname.h"
@@ -24,104 +25,460 @@ static int test_fw(size_t l, const char *w) {
 	return knot_dname_wire_check((const uint8_t *)w, np, NULL) > 0;
 }
 
+/* Test dname to/from string operations */
+static void test_str(const char *in_str, const char *in_bin, size_t bin_len) {
+	uint8_t      d1[KNOT_DNAME_MAXLEN] = "";
+	char         s1[4 * KNOT_DNAME_MAXLEN] = "";
+	knot_dname_t *d2 = NULL, *aux_d = NULL;
+	char         *s2 = NULL, *aux_s = NULL;
+	int          ret = 0;
+
+	/* dname_from_str */
+	aux_d = knot_dname_from_str(d1, in_str, sizeof(d1));
+	ok(aux_d != NULL, "dname_from_str: %s", in_str);
+	if (aux_d == NULL) {
+		skip_block(10, "dname_from_str: %s", in_str);
+		return;
+	}
+
+	/* dname_wire_check */
+	ret = knot_dname_wire_check(d1, d1 + sizeof(d1), NULL);
+	ok(ret == bin_len, "dname_wire_check: %s", in_str);
+
+	/* dname compare */
+	ok(memcmp(d1, in_bin, bin_len) == 0, "dname compare: %s", in_str);
+
+	/* dname_to_str */
+	aux_s = knot_dname_to_str(s1, d1, sizeof(s1));
+	ok(aux_s != NULL, "dname_to_str: %s", in_str);
+	if (aux_s == NULL) {
+		skip_block(7, "dname_to_str: %s", in_str);
+		return;
+	}
+
+	/* dname_from_str_alloc */
+	d2 = knot_dname_from_str_alloc(s1);
+	ok(d2 != NULL, "dname_from_str_alloc: %s", s1);
+	if (d2 == NULL) {
+		skip_block(6, "dname_from_str_alloc: %s", s1);
+		return;
+	}
+
+	/* dname_wire_check */
+	ret = knot_dname_wire_check(d2, d2 + bin_len, NULL);
+	ok(ret == bin_len, "dname_wire_check: %s", s1);
+
+	/* dname compare */
+	ok(memcmp(d2, in_bin, bin_len) == 0, "dname compare: %s", s1);
+
+	/* dname_to_str_alloc */
+	s2 = knot_dname_to_str_alloc(d2);
+	knot_dname_free(&d2, NULL);
+	ok(s2 != NULL, "dname_to_str_alloc: %s", s1);
+	if (s2 == NULL) {
+		skip_block(3, "dname_to_str_alloc: %s", s1);
+		return;
+	}
+
+	/* As the string representation is ambiguous, the following steps
+	 * are just for comparison in wire form.
+	 */
+	d2 = knot_dname_from_str_alloc(s2);
+	ok(d2 != NULL, "dname_from_str_alloc: %s", s2);
+	if (aux_d == NULL) {
+		skip_block(2, "dname_from_str_alloc: %s", s2);
+		free(s2);
+		return;
+	}
+
+	/* dname_wire_check */
+	ret = knot_dname_wire_check(d2, d2 + bin_len, NULL);
+	ok(ret == bin_len, "dname_wire_check: %s", s2);
+
+	/* dname compare */
+	ok(memcmp(d2, in_bin, bin_len) == 0, "dname compare: %s", s2);
+
+	knot_dname_free(&d2, NULL);
+	free(s2);
+}
+
 int main(int argc, char *argv[])
 {
-	plan(29);
- 
+	plan(285);
+
 	knot_dname_t *d = NULL, *d2 = NULL;
 	const char *w = NULL, *t = NULL;
 	unsigned len = 0;
 	size_t pos = 0;
+	char *s = NULL;
+
+	/* DNAME WIRE CHECKS */
 
-	/* 1. NULL wire */
+	/* NULL wire */
 	ok(!test_fw(0, NULL), "parsing NULL dname");
 
-	/* 2. empty label */
+	/* empty label */
 	ok(test_fw(1, ""), "parsing empty dname");
 
-	/* 3. incomplete dname */
-	ok(!test_fw(5, "\x08""dddd"), "parsing incomplete wire");
+	/* incomplete dname */
+	ok(!test_fw(5, "\x08" "dddd"), "parsing incomplete wire");
 
-	/* 4. non-fqdn */
-	ok(!test_fw(3, "\x02""ab"), "parsing non-fqdn name");
+	/* non-fqdn */
+	ok(!test_fw(3, "\x02" "ab"), "parsing non-fqdn name");
 
-	/* 5. label > 63b */
-	w = "\x40""dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
-	ok(!test_fw(65, w), "parsing label > 63b");
+	/* label length == 63 */
+	w = "\x3f" "123456789012345678901234567890123456789012345678901234567890123";
+	ok(test_fw(1 + 63 + 1, w), "parsing label length == 63");
 
-	/* 6. label count == 126 */
-	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64";
-	ok(test_fw(253, w), "parsing label count == 127");
+	/* label length > 63 */
+	w = "\x40" "1234567890123456789012345678901234567890123456789012345678901234";
+	ok(!test_fw(1 + 64 + 1, w), "parsing label length > 63");
 
-	/* 7. label count == 127 */
-	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64";
-	ok(test_fw(255, w), "parsing label count == 127");
+	/* label count == 127 (also maximal dname length) */
+	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64";
+	ok(test_fw(127 * 2 + 1, w), "parsing label count == 127");
 
-	/* 8. label count > 127 */
-	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64";
-	ok(!test_fw(257, w), "parsing label count > 127");
+	/* label count > 127 */
+	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64";
+	ok(!test_fw(128 * 2 + 1, w), "parsing label count > 127");
 
-	/* 9. dname length > 255 */
-	w = "\xff""ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
-	ok(!test_fw(257, w), "parsing dname len > 255");
+	/* dname length > 255 */
+	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x02\x64\x64";
+	ok(!test_fw(126 * 2 + 3 + 1, w), "parsing dname len > 255");
 
-	/* 10. special case - invalid label */
-	w = "\x20\x68\x6d\x6e\x63\x62\x67\x61\x61\x61\x61\x65\x72\x6b\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x67\x6e\x69\x64\x68\x62\x61\x61\x61\x61\x65\x6c\x64\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x61\x63\x6f\x63\x64\x62\x61\x61\x61\x61\x65\x6b\x72\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x69\x62\x63\x6d\x6a\x6f\x61\x61\x61\x61\x65\x72\x6a\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x6f\x6c\x6e\x6c\x67\x68\x61\x61\x61\x61\x65\x73\x72\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x6a\x6b\x64\x66\x66\x67\x61\x61\x61\x61\x65\x6c\x68\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x67\x67\x6c\x70\x70\x61\x61\x61\x61\x61\x65\x73\x72\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x65\x6b\x6c\x67\x70\x66\x61\x61\x61\x61\x65\x6c\x68\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x0\x21\x42\x63\x84\xa5\xc6\xe7\x8\xa\xd\x11\x73\x3\x6e\x69\x63\x2\x43\x5a";
-	ok(!test_fw(277, w), "parsing invalid label (spec. case 1)");
+	/* DNAME STRING CHECKS */
 
-	/* 11. parse from string (correct) .*/
-	len = 10;
-	w = "\x04""abcd""\x03""efg";
-	t = "abcd.efg";
-	d = knot_dname_from_str(t);
-	ok(d && knot_dname_size(d) == len && memcmp(d, w, len) == 0,
-	   "dname_fromstr: parsed correct non-FQDN name");
-	knot_dname_free(&d, NULL);
+	/* root dname */
+	test_str(".", "\x00", 1);
 
-	/* 12. parse FQDN from string (correct) .*/
-	t = "abcd.efg.";
-	d = knot_dname_from_str(t);
-	ok(d && knot_dname_size(d) == len && memcmp(d, w, len) == 0,
-	   "dname_fromstr: parsed correct FQDN name");
-	knot_dname_free(&d, NULL);
+	/* 1-char dname */
+	test_str("a.", "\x01""a", 2 + 1);
+
+	/* 1-char dname - non-fqdn */
+	test_str("a", "\x01""a", 2 + 1);
+
+	/* wildcard and asterisks */
+	test_str("*.*a.a*a.**.",
+	         "\x01" "*" "\x02" "*a" "\x03" "a*a" "\x02" "**",
+	         2 + 3 + 4 + 3 + 1);
+
+	/* special label */
+	test_str("\\000\\0320\\ \\\\\\\"\\.\\@\\*.",
+	         "\x09" "\x00\x20\x30\x20\x5c\x22.@*",
+	         10 + 1);
+
+	/* unescaped special characters */
+	test_str("_a.b-c./d.",
+	         "\x02" "_a" "\x03" "b-c" "\x02" "/d",
+	         3 + 4 + 3 + 1);
+
+	/* all possible characters */
+	test_str("\\000\\001\\002\\003\\004\\005\\006\\007\\008\\009\\010\\011\\012\\013\\014\\015\\016\\017\\018\\019",
+	         "\x14" "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13",
+	         22);
+	test_str("\\020\\021\\022\\023\\024\\025\\026\\027\\028\\029\\030\\031\\032\\033\\034\\035\\036\\037\\038\\039",
+	         "\x14" "\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27",
+	         22);
+	test_str("\\040\\041\\042\\043\\044\\045\\046\\047\\048\\049\\050\\051\\052\\053\\054\\055\\056\\057\\058\\059",
+	         "\x14" "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b",
+	         22);
+	test_str("\\060\\061\\062\\063\\064\\065\\066\\067\\068\\069\\070\\071\\072\\073\\074\\075\\076\\077\\078\\079",
+	         "\x14" "\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
+	         22);
+	test_str("\\080\\081\\082\\083\\084\\085\\086\\087\\088\\089\\090\\091\\092\\093\\094\\095\\096\\097\\098\\099",
+	         "\x14" "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63",
+	         22);
+	test_str("\\100\\101\\102\\103\\104\\105\\106\\107\\108\\109\\110\\111\\112\\113\\114\\115\\116\\117\\118\\119",
+	         "\x14" "\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77",
+	         22);
+	test_str("\\120\\121\\122\\123\\124\\125\\126\\127\\128\\129\\130\\131\\132\\133\\134\\135\\136\\137\\138\\139",
+	         "\x14" "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b",
+	         22);
+	test_str("\\140\\141\\142\\143\\144\\145\\146\\147\\148\\149\\150\\151\\152\\153\\154\\155\\156\\157\\158\\159",
+	         "\x14" "\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
+	         22);
+	test_str("\\160\\161\\162\\163\\164\\165\\166\\167\\168\\169\\170\\171\\172\\173\\174\\175\\176\\177\\178\\179",
+	         "\x14" "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3",
+	         22);
+	test_str("\\180\\181\\182\\183\\184\\185\\186\\187\\188\\189\\190\\191\\192\\193\\194\\195\\196\\197\\198\\199",
+	         "\x14" "\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
+	         22);
+	test_str("\\200\\201\\202\\203\\204\\205\\206\\207\\208\\209\\210\\211\\212\\213\\214\\215\\216\\217\\218\\219",
+	         "\x14" "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb",
+	         22);
+	test_str("\\220\\221\\222\\223\\224\\225\\226\\227\\228\\229\\230\\231\\232\\233\\234\\235\\236\\237\\238\\239",
+	         "\x14" "\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+	         22);
+	test_str("\\240\\241\\242\\243\\244\\245\\246\\247\\248\\249\\250\\251\\252\\253\\254\\255",
+	         "\x10" "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+	         18);
+
+	/* maximal dname label length */
+	test_str("12345678901234567890123456789012345678901234567890123456789012\\063",
+		 "\x3f" "12345678901234567890123456789012345678901234567890123456789012?",
+		 65);
+
+	/* maximal dname length */
+	test_str("1234567890123456789012345678901234567890123456789."
+	         "1234567890123456789012345678901234567890123456789."
+	         "1234567890123456789012345678901234567890123456789."
+	         "1234567890123456789012345678901234567890123456789."
+	         "\\#234567890123456789012345678901234567890123456789012\\063",
+	         "\x31" "1234567890123456789012345678901234567890123456789"
+	         "\x31" "1234567890123456789012345678901234567890123456789"
+	         "\x31" "1234567890123456789012345678901234567890123456789"
+	         "\x31" "1234567890123456789012345678901234567890123456789"
+	         "\x35" "#234567890123456789012345678901234567890123456789012?",
+	         255);
+
+	/* NULL output, positive maxlen */
+	w = "\x02" "aa";
+	s = knot_dname_to_str(NULL, (const uint8_t *)w, 1);
+	ok(s != NULL, "dname_to_str: null dname");
+	if (s != NULL) {
+		ok(memcmp(s, "aa.", 4) == 0, "dname_to_str: null dname compare");
+		free(s);
+	} else {
+		skip("dname_to_str: null dname");
+	}
+
+	/* non-NULL output, zero maxlen */
+	char s_small[2];
+	s = knot_dname_to_str(s_small, (const uint8_t *)w, 0);
+	ok(s == NULL, "dname_to_str: non-NULL output, zero maxlen");
+
+	/* small buffer */
+	s = knot_dname_to_str(s_small, (const uint8_t *)w, 1);
+	ok(s == NULL, "dname_to_str: small buffer");
+
+	/* NULL dname */
+	s = knot_dname_to_str_alloc(NULL);
+	ok(s == NULL, "dname_to_str: null dname");
 
-	/* 13. parse name from string (incorrect) .*/
+	/* empty dname is considered as a root dname */
+	w = "";
+	s = knot_dname_to_str_alloc((const uint8_t *)w);
+	ok(s != NULL, "dname_to_str: empty dname");
+	if (s != NULL) {
+		ok(memcmp(s, ".", 1) == 0, "dname_to_str: empty dname is root dname");
+		free(s);
+	} else {
+		skip("dname_to_str: empty dname");
+	}
+
+	/* incomplete dname */
+	w = "\x08" "dddd";
+	s = knot_dname_to_str_alloc((const uint8_t *)w);
+	ok(s != NULL, "dname_to_str: incomplete dname");
+	free(s);
+
+	/* non-fqdn */
+	w = "\x02" "ab";
+	s = knot_dname_to_str_alloc((const uint8_t *)w);
+	ok(s != NULL, "dname_to_str: non-fqdn");
+	free(s);
+
+	/* label length > 63 */
+	w = "\x40" "1234567890123456789012345678901234567890123456789012345678901234";
+	s = knot_dname_to_str_alloc((const uint8_t *)w);
+	ok(s != NULL, "dname_to_str: label length > 63");
+	free(s);
+
+	/* label count > 127 */
+	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64";
+	s = knot_dname_to_str_alloc((const uint8_t *)w);
+	ok(s != NULL, "dname_to_str: label count > 127");
+	free(s);
+
+	/* dname length > 255 */
+	w = "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64"
+	    "\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x01\x64\x02\x64\x64";
+	s = knot_dname_to_str_alloc((const uint8_t *)w);
+	ok(s != NULL, "dname_to_str: dname length > 255");
+	free(s);
+
+	/* NULL output, positive maxlen */
+	s = "aa.";
+	d = knot_dname_from_str(NULL, s, 1);
+	ok(s != NULL, "dname_from_str: null name");
+	if (s != NULL) {
+		ok(memcmp(d, "\x02" "aa", 4) == 0, "dname_from_str: null name compare");
+		free(d);
+	} else {
+		skip("dname_from_str: null name");
+	}
+
+	/* non-NULL output, zero maxlen */
+	uint8_t d_small[2];
+	d = knot_dname_from_str(d_small, s, 0);
+	ok(d == NULL, "dname_from_str: non-NULL output, zero maxlen");
+
+	/* small buffer */
+	d = knot_dname_from_str(d_small, s, 1);
+	ok(d == NULL, "dname_from_str: small buffer");
+
+	/* NULL string */
+	d = knot_dname_from_str_alloc(NULL);
+	ok(d == NULL, "dname_from_str: null string");
+
+	/* empty string */
+	t = "";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: empty string");
+
+	/* empty label */
 	t = "..";
-	d = knot_dname_from_str(t);
-	ok(d == NULL, "dname_fromstr: parsed incorrect name");
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: empty label");
+
+	/* leading dot */
+	t = ".a";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: leading dot");
+
+	/* incomplete decimal notation I */
+	t = "\\1";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: incomplete decimal I");
+
+	/* incomplete decimal notation II */
+	t = "\\12";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: incomplete decimal II");
+
+	/* invalid decimal notation I */
+	t = "\\256";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: invalid decimal I");
+
+	/* invalid decimal notation II */
+	t = "\\2x6";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: invalid decimal II");
 
-	/* 14. equal name is subdomain */
+	/* invalid escape notation */
+	t = "\\2";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: invalid escape");
+
+	/* label length > 63 I */
+	t = "1234567890123456789012345678901234567890123456789012345678901234";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: label length > 63 I");
+
+	/* label length > 63 II */
+	t = "123456789012345678901234567890123456789012345678901234567890123\\?";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: label length > 63 II");
+
+	/* label length > 63 III */
+	t = "123456789012345678901234567890123456789012345678901234567890123\\063";
+	d = knot_dname_from_str_alloc(t);
+	ok(d == NULL, "dname_from_str: label length > 63 III");
+
+	/* dname length > 255 */
+	t = "1234567890123456789012345678901234567890123456789."
+	    "1234567890123456789012345678901234567890123456789."
+	    "1234567890123456789012345678901234567890123456789."
+	    "1234567890123456789012345678901234567890123456789."
+	    "123456789012345678901234567890123456789012345678901234.",
+	ok(d == NULL, "dname_from_str: dname length > 255");
+
+	/* DNAME SUBDOMAIN CHECKS */
+
+	/* equal name is subdomain */
 	t = "ab.cd.ef";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	t = "ab.cd.ef";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_sub(d, d2), "dname_subdomain: equal name");
 	knot_dname_free(&d, NULL);
 
-	/* 15. true subdomain */
+	/* true subdomain */
 	t = "0.ab.cd.ef";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(knot_dname_is_sub(d, d2), "dname_subdomain: true subdomain");
 	knot_dname_free(&d, NULL);
 
-	/* 16. not subdomain */
+	/* not subdomain */
 	t = "cd.ef";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_sub(d, d2), "dname_subdomain: not subdomain");
 	knot_dname_free(&d, NULL);
 
-	/* 17. root subdomain */
+	/* root subdomain */
 	t = ".";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(knot_dname_is_sub(d2, d), "dname_subdomain: root subdomain");
 	knot_dname_free(&d, NULL);
 	knot_dname_free(&d2, NULL);
 
-	/* 18-19. dname cat (valid) */
+	/* DNAME CAT CHECKS */
+
+	/* dname cat (valid) */
 	w = "\x03""cat";
 	d = knot_dname_copy((const uint8_t *)w, NULL);
 	t = "*";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	d2 = knot_dname_cat(d2, d);
 	t = "\x01""*""\x03""cat";
 	len = 2 + 4 + 1;
@@ -130,7 +487,9 @@ int main(int argc, char *argv[])
 	knot_dname_free(&d, NULL);
 	knot_dname_free(&d2, NULL);
 
-	/* 20-21. parse from wire (valid) */
+	/* DNAME PARSE CHECKS */
+
+	/* parse from wire (valid) */
 	t = "\x04""abcd""\x03""efg";
 	len = 10;
 	pos = 0;
@@ -139,7 +498,7 @@ int main(int argc, char *argv[])
 	ok(pos == len, "dname_parse: valid name (parsed length)");
 	knot_dname_free(&d, NULL);
 
-	/* 22-23. parse from wire (invalid) */
+	/* parse from wire (invalid) */
 	t = "\x08""dddd";
 	len = 5;
 	pos = 0;
@@ -147,30 +506,38 @@ int main(int argc, char *argv[])
 	ok(d == NULL, "dname_parse: bad name");
 	ok(pos == 0, "dname_parse: bad name (parsed length)");
 
-	/* name equality checks */
+	/* DNAME EQUALITY CHECKS */
+
 	t = "ab.cd.ef";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(knot_dname_is_equal(d, d), "dname_is_equal: equal names");
+
 	t = "ab.cd.fe";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_equal(d, d2), "dname_is_equal: same label count");
 	knot_dname_free(&d2, NULL);
+
 	t = "ab.cd";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_equal(d, d2), "dname_is_equal: len(d1) < len(d2)");
 	knot_dname_free(&d2, NULL);
+
 	t = "ab.cd.ef.gh";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_equal(d, d2), "dname_is_equal: len(d1) > len(d2)");
 	knot_dname_free(&d2, NULL);
+
 	t = "ab.cd.efe";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_equal(d, d2), "dname_is_equal: last label longer");
 	knot_dname_free(&d2, NULL);
+
 	t = "ab.cd.e";
-	d2 = knot_dname_from_str(t);
+	d2 = knot_dname_from_str_alloc(t);
 	ok(!knot_dname_is_equal(d, d2), "dname_is_equal: last label shorter");
 	knot_dname_free(&d2, NULL);
 
+	knot_dname_free(&d, NULL);
+
 	return 0;
 }
diff --git a/tests/dnssec_keys.c b/tests/dnssec_keys.c
index 8dbb91924cbea06be3a99694210546cd2ba70b1f..b2b048c65a2f7fb7b36772aec4c4c3501f6b3829 100644
--- a/tests/dnssec_keys.c
+++ b/tests/dnssec_keys.c
@@ -205,7 +205,7 @@ int main(int argc, char *argv[])
 		knot_key_params_t params = { 0 };
 		knot_tsig_key_t tsig_key = { 0 };
 		const char *owner = "shared.example.com.";
-		knot_dname_t *name = knot_dname_from_str(owner);
+		knot_dname_t *name = knot_dname_from_str_alloc(owner);
 
 		result = knot_tsig_key_from_params(&params, &tsig_key);
 		ok(result == KNOT_EINVAL,
diff --git a/tests/dnssec_nsec3.c b/tests/dnssec_nsec3.c
index 17dbb8e8777c853dad27f4c3db851bba1f0f5f6f..4e5dfe4b50b7c3cea4590d93bbbd5533b20eb2fd 100644
--- a/tests/dnssec_nsec3.c
+++ b/tests/dnssec_nsec3.c
@@ -54,7 +54,7 @@ int main(int argc, char *argv[])
 		'a', 'b', 'c', 'd'     // salt
 	};
 
-	knot_dname_t *owner = knot_dname_from_str("test.");
+	knot_dname_t *owner = knot_dname_from_str_alloc("test.");
 	rrset = knot_rrset_new(owner, KNOT_RRTYPE_NSEC3PARAM, KNOT_CLASS_IN, NULL);
 	knot_dname_free(&owner, NULL);
 
@@ -81,7 +81,7 @@ int main(int argc, char *argv[])
 	params.salt = (uint8_t *)strdup("happywithnsec3");
 
 	const char *dname_str = "knot-dns.cz.";
-	knot_dname_t *dname = knot_dname_from_str(dname_str);
+	knot_dname_t *dname = knot_dname_from_str_alloc(dname_str);
 
 	uint8_t expected[] = {
 		0x72, 0x40, 0x55, 0x83, 0x92, 0x93, 0x95, 0x28, 0xee, 0xa2,
diff --git a/tests/dnssec_sign.c b/tests/dnssec_sign.c
index 5941c0ffeceb20072536a4bb3328fb52836b8836..abe6e2f34f93e8fcbefd4a7270e562bb246cf939 100644
--- a/tests/dnssec_sign.c
+++ b/tests/dnssec_sign.c
@@ -93,7 +93,7 @@ int main(int argc, char *argv[])
 
 	// RSA
 
-	kp.name = knot_dname_from_str("example.com.");
+	kp.name = knot_dname_from_str_alloc("example.com.");
 	kp.algorithm = 5;
 	knot_binary_from_base64("pSxiFXG8wB1SSHdok+OdaAp6QdvqjpZ17ucNge21iYVfv+DZq52l21KdmmyEqoG9wG/87O7XG8XVLNyYPue8Mw==", &kp.modulus);
 	knot_binary_from_base64("AQAB", &kp.public_exponent);
@@ -109,7 +109,7 @@ int main(int argc, char *argv[])
 
 	// DSA
 
-	kp.name = knot_dname_from_str("example.com.");
+	kp.name = knot_dname_from_str_alloc("example.com.");
 	kp.algorithm = 6;
 	knot_binary_from_base64("u7tr4jc7CH0+r2muVEZyjYu7hpMrQ1dHGAMv7hr5dBFYzkutfdBmDSW4C+qxaXWo14gi+jJ8XqFqQ7rQn23DdQ==", &kp.prime);
 	knot_binary_from_base64("tgZ5X6pFoCOM2NzfiAYVG1434Mk=", &kp.subprime);
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
 	// ECDSA
 
 #ifdef KNOT_ENABLE_ECDSA
-	kp.name = knot_dname_from_str("example.com");
+	kp.name = knot_dname_from_str_alloc("example.com");
 	kp.algorithm = 13;
 	knot_binary_from_base64("1N/PvpB8jZcvv+zr3Q987RKK1cBxDKULzEc5F/nnpSg=", &kp.private_key);
 	knot_binary_from_base64("AAAAAH3t6EfkvHK5fQMGslhWcCfMF6Q3oNbol2f19DGAb8r49ZX7iQ12sFIyrs2CiwDxFR9Y7fF2zOZ005VV1LA3m1Q=", &kp.rdata);
@@ -135,7 +135,7 @@ int main(int argc, char *argv[])
 #endif
 
 #if KNOT_ENABLE_GOST
-	kp.name = knot_dname_from_str("example.com");
+	kp.name = knot_dname_from_str_alloc("example.com");
 	kp.algorithm = 12;
 	knot_binary_from_base64("MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgIgN2CMRL538HmFM9+GHYM54rEDYO+tLDV3q7AtK1nZ4iA=", &kp.private_key);
 	knot_binary_from_base64("eHh4eOJ4YHvlasoDRc4ZnvRzldoTUgwWSW0bPv7r9xJ074Dn8KzM4yU9fJgTwIT1TsaHmejYopDnVdjxZyrKNra8Keo=", &kp.rdata);
diff --git a/tests/dnssec_zone_nsec.c b/tests/dnssec_zone_nsec.c
index f3f578c20d4959a89c143c921f8461d23bc3826a..5b2a0750cbfe0d1501ff203c31f19d07972e77fb 100644
--- a/tests/dnssec_zone_nsec.c
+++ b/tests/dnssec_zone_nsec.c
@@ -23,9 +23,9 @@ int main(int argc, char *argv[])
 {
 	plan(1);
 
-	knot_dname_t *owner  = knot_dname_from_str("name.example.com");
-	knot_dname_t *apex   = knot_dname_from_str("example.com");
-	knot_dname_t *expect = knot_dname_from_str("sv9o5lv8kgv6lm1t9dkst43b3c0aagbj.example.com");
+	knot_dname_t *owner  = knot_dname_from_str_alloc("name.example.com");
+	knot_dname_t *apex   = knot_dname_from_str_alloc("example.com");
+	knot_dname_t *expect = knot_dname_from_str_alloc("sv9o5lv8kgv6lm1t9dkst43b3c0aagbj.example.com");
 
 	knot_nsec3_params_t params = {
 		.algorithm = 1, .flags = 0, .iterations = 10,
diff --git a/tests/node.c b/tests/node.c
index 3d527721d8a6dabb34a1a4eefd0aa38575577ac8..9f75eab1b2edf6e9e233457d12eda23c4696144f 100644
--- a/tests/node.c
+++ b/tests/node.c
@@ -50,7 +50,7 @@ int main(int argc, char *argv[])
 {
 	plan(23);
 	
-	knot_dname_t *dummy_owner = knot_dname_from_str("test.");
+	knot_dname_t *dummy_owner = knot_dname_from_str_alloc("test.");
 	// Test new
 	zone_node_t *node = node_new(dummy_owner, NULL);
 	ok(node != NULL, "Node: new");
diff --git a/tests/pkt.c b/tests/pkt.c
index 3a0d9b36db3654bd1f9761cc74bbe266ab48746a..cb596a13faac13eef8233959035846f7b042e86e 100644
--- a/tests/pkt.c
+++ b/tests/pkt.c
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
 	knot_dname_t* dnames[NAMECOUNT] = {0};
 	knot_rrset_t* rrsets[NAMECOUNT] = {0};
 	for (unsigned i = 0; i < NAMECOUNT; ++i) {
-		dnames[i] = knot_dname_from_str(g_names[i]);
+		dnames[i] = knot_dname_from_str_alloc(g_names[i]);
 	}
 
 	uint8_t *edns_str = (uint8_t *)"ab";
diff --git a/tests/rrl.c b/tests/rrl.c
index 3b8899de1086f2831084956099cdb96ee1a7644c..dcb7e9635ede8ad1a8b48417059342c18bb361ab 100644
--- a/tests/rrl.c
+++ b/tests/rrl.c
@@ -102,7 +102,7 @@ int main(int argc, char *argv[])
 		return KNOT_ERROR; /* Fatal */
 	}
 
-	knot_dname_t *qname = knot_dname_from_str("beef.");
+	knot_dname_t *qname = knot_dname_from_str_alloc("beef.");
 	int ret = knot_pkt_put_question(query, qname, KNOT_CLASS_IN, KNOT_RRTYPE_A);
 	knot_dname_free(&qname, NULL);
 	if (ret != KNOT_EOK) {
diff --git a/tests/rrset.c b/tests/rrset.c
index 1849a19fe790aeffeffec0b4a133c9ca315bf9ea..8c2192214984ef3549d4317e6321aadaded0c05d 100644
--- a/tests/rrset.c
+++ b/tests/rrset.c
@@ -39,7 +39,7 @@ int main(int argc, char *argv[])
 	plan(19);
 
 	// Test new
-	knot_dname_t *dummy_owner = knot_dname_from_str("test.");
+	knot_dname_t *dummy_owner = knot_dname_from_str_alloc("test.");
 	assert(dummy_owner);
 
 	knot_rrset_t *rrset = knot_rrset_new(dummy_owner, KNOT_RRTYPE_TXT,
@@ -52,7 +52,7 @@ int main(int argc, char *argv[])
 
 	// Test init
 	knot_dname_free(&dummy_owner, NULL);
-	dummy_owner = knot_dname_from_str("test2.");
+	dummy_owner = knot_dname_from_str_alloc("test2.");
 	assert(dummy_owner);
 
 	knot_dname_free(&rrset->owner, NULL);
diff --git a/tests/zone_update.c b/tests/zone_update.c
index 5553b8e6463d25d758b6cfcda8186459a6e95b43..cf596543fea94a0f394e0cb158f40e9723965b39 100644
--- a/tests/zone_update.c
+++ b/tests/zone_update.c
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
 {
 	plan(5);
 
-	knot_dname_t *apex = knot_dname_from_str("test");
+	knot_dname_t *apex = knot_dname_from_str_alloc("test");
 	assert(apex);
 	zone_contents_t *zone = zone_contents_new(apex);
 	knot_dname_free(&apex, NULL);
diff --git a/tests/zonedb.c b/tests/zonedb.c
index 2670d733ea8ed48a0f532b299d154ea1322ae135..cc0ed69ab3d69bdfb045986564bbb27694a9fa4d 100644
--- a/tests/zonedb.c
+++ b/tests/zonedb.c
@@ -72,7 +72,7 @@ int main(int argc, char *argv[])
 	/* Lookup of exact names. */
 	nr_passed = 0;
 	for (unsigned i = 0; i < ZONE_COUNT; ++i) {
-		dname = knot_dname_from_str(zone_list[i]);
+		dname = knot_dname_from_str_alloc(zone_list[i]);
 		if (knot_zonedb_find(db, dname) == zones[i]) {
 			++nr_passed;
 		} else {
@@ -89,7 +89,7 @@ int main(int argc, char *argv[])
 		if (strcmp(zone_list[i], ".") != 0) {
 			strlcat(buf, zone_list[i], sizeof(buf));
 		}
-		dname = knot_dname_from_str(buf);
+		dname = knot_dname_from_str_alloc(buf);
 		if (knot_zonedb_find_suffix(db, dname) == zones[i]) {
 			++nr_passed;
 		} else {
@@ -102,7 +102,7 @@ int main(int argc, char *argv[])
 	/* Remove all zones. */
 	nr_passed = 0;
 	for (unsigned i = 0; i < ZONE_COUNT; ++i) {
-		dname = knot_dname_from_str(zone_list[i]);
+		dname = knot_dname_from_str_alloc(zone_list[i]);
 		if (knot_zonedb_del(db, dname) == KNOT_EOK) {
 			zone_free(&zones[i]);
 			++nr_passed;
diff --git a/tests/ztree.c b/tests/ztree.c
index 4d24d9cd5c2848d2f310240490923f26d9a807bc..0edbc7ecd5480534c6985c8cb8190e66638ee2a3 100644
--- a/tests/ztree.c
+++ b/tests/ztree.c
@@ -24,10 +24,10 @@ static zone_node_t NODE[NCOUNT];
 static knot_dname_t* ORDER[NCOUNT];
 static void ztree_init_data()
 {
-	NAME[0] = knot_dname_from_str(".");
-	NAME[1] = knot_dname_from_str("master.ac.");
-	NAME[2] = knot_dname_from_str("ac.");
-	NAME[3] = knot_dname_from_str("ns.");
+	NAME[0] = knot_dname_from_str_alloc(".");
+	NAME[1] = knot_dname_from_str_alloc("master.ac.");
+	NAME[2] = knot_dname_from_str_alloc("ac.");
+	NAME[3] = knot_dname_from_str_alloc("ns.");
 
 	knot_dname_t *order[NCOUNT] = {
 	        NAME[0], NAME[2], NAME[1], NAME[3]
@@ -55,8 +55,8 @@ static int ztree_iter_data(zone_node_t **node, void *data)
 	int result = KNOT_EOK;
 	if (owner != ORDER[*i]) {
 		result = KNOT_ERROR;
-		char *exp_s = knot_dname_to_str(ORDER[*i]);
-		char *owner_s = knot_dname_to_str(owner);
+		char *exp_s = knot_dname_to_str_alloc(ORDER[*i]);
+		char *owner_s = knot_dname_to_str_alloc(owner);
 		diag("ztree: at index: %u expected '%s' got '%s'\n", *i, exp_s, owner_s);
 		free(exp_s);
 		free(owner_s);
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
 	/* 4. ordered lookup */
 	node = NULL;
 	const zone_node_t *prev = NULL;
-	knot_dname_t *tmp_dn = knot_dname_from_str("z.ac.");
+	knot_dname_t *tmp_dn = knot_dname_from_str_alloc("z.ac.");
 	zone_tree_find_less_or_equal(t, tmp_dn, &node, &prev);
 	knot_dname_free(&tmp_dn, NULL);
 	ok(prev == NODE + 1, "ztree: ordered lookup");