From cbed092460b44feab66db84d21356391e96fe94e Mon Sep 17 00:00:00 2001
From: Daniel Salzman <daniel.salzman@nic.cz>
Date: Wed, 10 Sep 2014 10:54:07 +0200
Subject: [PATCH] dname: add output buffer parameters to knot_dname_from_str

---
 src/knot/conf/cf-parse.y             |   8 +-
 src/knot/ctl/knotc_main.c            |   4 +-
 src/knot/ctl/remote.c                |   8 +-
 src/knot/modules/synth_record.c      |   4 +-
 src/knot/nameserver/nsec_proofs.c    |   2 +-
 src/knot/zone/zone.c                 |   2 +-
 src/knot/zone/zonedb-load.c          |   2 +-
 src/knot/zone/zonefile.c             |   2 +-
 src/libknot/dname.c                  | 148 +++++++++++++++++++++------
 src/libknot/dname.h                  |  22 +++-
 src/libknot/dnssec/key.c             |   2 +-
 src/utils/common/params.c            |   2 +-
 src/utils/dig/dig_exec.c             |   2 +-
 src/utils/nsec3hash/nsec3hash_main.c |   4 +-
 src/utils/nsupdate/nsupdate_exec.c   |   6 +-
 tests/changeset.c                    |  12 +--
 tests/conf.c                         |   2 +-
 tests/dname.c                        |  30 +++---
 tests/dnssec_keys.c                  |   2 +-
 tests/dnssec_nsec3.c                 |   4 +-
 tests/dnssec_sign.c                  |   8 +-
 tests/dnssec_zone_nsec.c             |   6 +-
 tests/node.c                         |   2 +-
 tests/pkt.c                          |   2 +-
 tests/rrl.c                          |   2 +-
 tests/rrset.c                        |   4 +-
 tests/zone_update.c                  |   2 +-
 tests/zonedb.c                       |   6 +-
 tests/ztree.c                        |  10 +-
 29 files changed, 203 insertions(+), 107 deletions(-)

diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index 9010d4fc52..0db4e115d1 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 d882106d7d..a959c02911 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -662,7 +662,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;
 	}
@@ -673,7 +673,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 ea54d54764..fa774b92b8 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -591,7 +591,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);
@@ -855,7 +855,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);
@@ -900,7 +900,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;
 	}
@@ -949,7 +949,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/modules/synth_record.c b/src/knot/modules/synth_record.c
index 779b3517a1..80be22c2a3 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/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c
index b24491285e..6f6b8b5a37 100644
--- a/src/knot/nameserver/nsec_proofs.c
+++ b/src/knot/nameserver/nsec_proofs.c
@@ -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;
 	}
diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c
index de302bc8cd..68e27c8acc 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 6bb1f6da7e..94ff044b05 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 9c26863ad5..2f1b24254c 100644
--- a/src/knot/zone/zonefile.c
+++ b/src/knot/zone/zonefile.c
@@ -184,7 +184,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/dname.c b/src/libknot/dname.c
index cfc027db82..7e512d6aec 100644
--- a/src/libknot/dname.c
+++ b/src/libknot/dname.c
@@ -318,60 +318,144 @@ char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen)
 
 /*----------------------------------------------------------------------------*/
 
-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 = 0;
+	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++;
+		} else if (name[name_len -1] != '.') { /* Check for non-FQDN. */
+			alloc_size++;
+		}
+		alloc_size += name_len + 1; /* + 1 ~ first label length. */
+	} else {
+		alloc_size = maxlen;
+	}
+
+	/* Check the maximal wire size. */
+	if (alloc_size > KNOT_DNAME_MAXLEN) {
+		alloc_size = KNOT_DNAME_MAXLEN;
 	}
 
-	/* Create wire. */
-	uint8_t *wire = malloc(wire_size * sizeof(uint8_t));
-	if (wire == NULL)
+	/* Prepare output buffer. */
+	uint8_t *wire = (dst == NULL) ? malloc(alloc_size) : dst;
+	if (wire == NULL) {
 		return NULL;
-	*wire = '\0';
+	}
 
-	/* 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) {
+		switch (*ch) {
+		case '.':
+			/* Check for invalid zero-length label. */
+			if (*label == 0 && name_len > 1) {
+				goto dname_from_str_failed;
+			}
+			label = wire_pos++;
+			*label = 0;
+			break;
+		case '\\':
+			ch++;
+			/* At least one more character is required. */
+			if (ch == end) {
+				goto dname_from_str_failed;
+			}
+
+			/* Check for maximal label length. */
+			if (++(*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;
+			}
+
+			/* At least trailing root label should follow. */
+			if (wire_pos >= wire_end) {
+				goto dname_from_str_failed;
+			}
+
+			break;
+		default:
+			/* Check for maximal label length. */
+			if (++(*label) > KNOT_DNAME_MAXLABELLEN) {
+				goto dname_from_str_failed;
+			}
+			*(wire_pos++) = *ch;
+
+			/* At least trailing root label should follow. */
+			if (wire_pos >= wire_end) {
+				goto dname_from_str_failed;
 			}
-			label = w;
-			*label = '\0';
-		} else {
-			*w = *ch;
-			*label += 1;
 		}
-		++w;
-		++ch;
+		ch++;
 	}
 
 	/* Check for non-FQDN name. */
 	if (*label > 0) {
-		*w = '\0';
+		*(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 bafe66847d..db7af67c6b 100644
--- a/src/libknot/dname.h
+++ b/src/libknot/dname.h
@@ -143,14 +143,26 @@ static inline char *knot_dname_to_str_alloc(const knot_dname_t *name)
  * \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(const char *name);
+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.
+ */
+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 dc6fff2894..2b9cce3102 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/utils/common/params.c b/src/utils/common/params.c
index 3e308834cf..0058e3a3aa 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 2dc8d16844..e5f5f3b32b 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 8fa87a43c4..5cfb8b938f 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 8b8cf397cc..c212d6987a 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 e76da37344..b9734dd080 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 0b25aad274..a70a756a67 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 4c7158a9c0..4d8910e4bd 100644
--- a/tests/dname.c
+++ b/tests/dname.c
@@ -73,46 +73,46 @@ int main(int argc, char *argv[])
 	len = 10;
 	w = "\x04""abcd""\x03""efg";
 	t = "abcd.efg";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(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);
 
 	/* 12. parse FQDN from string (correct) .*/
 	t = "abcd.efg.";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(d && knot_dname_size(d) == len && memcmp(d, w, len) == 0,
 	   "dname_fromstr: parsed correct FQDN name");
 	knot_dname_free(&d, NULL);
 
 	/* 13. parse name from string (incorrect) .*/
 	t = "..";
-	d = knot_dname_from_str(t);
+	d = knot_dname_from_str_alloc(t);
 	ok(d == NULL, "dname_fromstr: parsed incorrect name");
 
 	/* 14. 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 */
 	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 */
 	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 */
 	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);
@@ -121,7 +121,7 @@ int main(int argc, char *argv[])
 	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;
@@ -149,26 +149,26 @@ int main(int argc, char *argv[])
 
 	/* name 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);
 
diff --git a/tests/dnssec_keys.c b/tests/dnssec_keys.c
index 8dbb91924c..b2b048c65a 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 17dbb8e877..4e5dfe4b50 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 5941c0ffec..abe6e2f34f 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 f3f578c20d..5b2a0750cb 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 3d527721d8..9f75eab1b2 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 3a0d9b36db..cb596a13fa 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 3b8899de10..dcb7e9635e 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 1849a19fe7..8c21922149 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 5553b8e646..cf596543fe 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 2670d733ea..cc0ed69ab3 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 09523665e3..0edbc7ecd5 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]
@@ -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");
-- 
GitLab