diff --git a/src/common/mempattern.h b/src/common/mempattern.h
index 7bef8513616633dfcbcff69a692b9d9b64d7223a..c7062cafadaaa7c2439fe586702ad1a6f071596b 100644
--- a/src/common/mempattern.h
+++ b/src/common/mempattern.h
@@ -34,6 +34,9 @@ typedef void* (*mm_alloc_t)(void* ctx, size_t len);
 typedef void (*mm_free_t)(void *p);
 typedef void (*mm_flush_t)(void *p);
 
+/* Reusable functions. */
+static inline void mm_nofree(void *p) {}
+
 /* Memory allocation context. */
 typedef struct mm_ctx {
 	void *ctx; /* \note Must be first */
diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index 663adad2e59c87515b8c9c566ad999ce8968cee2..9aab081e6355acdcb482cc62402086ce5a993ec6 100644
--- a/src/knot/conf/cf-parse.y
+++ b/src/knot/conf/cf-parse.y
@@ -263,7 +263,7 @@ static void conf_acl_item(void *scanner, char *item)
 static int conf_key_exists(void *scanner, char *item)
 {
     /* Find existing node in keys. */
-    knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item), 0);
+    knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item));
     conf_key_t* r = 0;
     WALK_LIST (r, new_config->keys) {
         if (knot_dname_compare(r->k.name, sample) == 0) {
@@ -283,7 +283,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_new_from_str(item, strlen(item), 0);
+    knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item));
 
     conf_key_t* r = 0;
     WALK_LIST (r, new_config->keys) {
@@ -338,7 +338,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_new_from_str(this_zone->name, nlen, 0);
+      dn = knot_dname_new_from_str(this_zone->name, nlen);
    }
    if (dn == NULL) {
      free(this_zone->name);
@@ -608,7 +608,7 @@ keys:
      }
 
      if (fqdn != NULL && !conf_key_exists(scanner, fqdn)) {
-         knot_dname_t *dname = knot_dname_new_from_str(fqdn, fqdnl, 0);
+         knot_dname_t *dname = knot_dname_new_from_str(fqdn, fqdnl);
 	 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 35af4368883746ad800868cdde82f71ebc2065e0..12bee2600076471da6e7eae4e28ab48747526a79 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -145,7 +145,7 @@ static int cmd_remote_print_reply(const knot_rrset_t *rr)
 static int cmd_remote_reply(int c)
 {
 	uint8_t *rwire = malloc(SOCKET_MTU_SZ);
-	knot_packet_t *reply = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+	knot_packet_t *reply = knot_packet_new();
 	if (!rwire || !reply) {
 		free(rwire);
 		knot_packet_free(&reply);
diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 685a48b6235ae2b8c8907f7dc6c9904670393c60..9ccfa3faba20bd9d231eaa5de9523db0548e4f84 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -454,7 +454,7 @@ static int remote_send_chunk(int c, knot_packet_t *pkt, const char* d,
                              uint16_t dlen, uint8_t* rwire, size_t rlen)
 {
 	int ret = KNOT_ERROR;
-	knot_packet_t *resp = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+	knot_packet_t *resp = knot_packet_new_mm(&pkt->mm);
 	if (!resp) {
 		return ret;
 	}
@@ -465,7 +465,7 @@ static int remote_send_chunk(int c, knot_packet_t *pkt, const char* d,
 		knot_packet_free(&resp);
 		return ret;
 	}
-	ret = knot_response_init_from_query(resp, pkt, 1);
+	ret = knot_response_init_from_query(resp, pkt);
 	if (ret != KNOT_EOK)  {
 		knot_packet_free(&resp);
 		return ret;
@@ -525,7 +525,7 @@ int remote_answer(int fd, server_t *s, knot_packet_t *pkt, uint8_t* rwire, size_
 	}
 
 	knot_dname_t *realm = knot_dname_new_from_str(KNOT_CTL_REALM,
-	                                              KNOT_CTL_REALM_LEN, NULL);
+	                                              KNOT_CTL_REALM_LEN);
 	if (!knot_dname_is_subdomain(qname, realm) != 0) {
 		dbg_server("remote: qname != *%s\n", KNOT_CTL_REALM_EXT);
 		knot_dname_free(&realm);
@@ -536,7 +536,7 @@ int remote_answer(int fd, server_t *s, knot_packet_t *pkt, uint8_t* rwire, size_
 	/* Command:
 	 * QNAME: leftmost label of QNAME
 	 */
-	size_t cmd_len = knot_dname_label_size(qname, 0);
+	size_t cmd_len = *knot_dname_name(qname);
 	char *cmd = strndup((char*)qname->name + 1, cmd_len);
 
 	/* Data:
@@ -588,7 +588,7 @@ int remote_answer(int fd, server_t *s, knot_packet_t *pkt, uint8_t* rwire, size_
 int remote_process(server_t *s, conf_iface_t *ctl_if, int r,
                    uint8_t* buf, size_t buflen)
 {
-	knot_packet_t *pkt =  knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	knot_packet_t *pkt =  knot_packet_new();
 	if (!pkt) {
 		dbg_server("remote: not enough space to allocate query\n");
 		return KNOT_ENOMEM;
@@ -674,7 +674,7 @@ knot_packet_t* remote_query(const char *query, const knot_tsig_key_t *key)
 		return NULL;
 	}
 
-	knot_packet_t *qr = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	knot_packet_t *qr = knot_packet_new();
 	if (!qr) {
 		return NULL;
 	}
@@ -689,25 +689,23 @@ knot_packet_t* remote_query(const char *query, const knot_tsig_key_t *key)
 	}
 
 	/* Question section. */
-	knot_question_t q;
 	char *qname = strcdup(query, KNOT_CTL_REALM_EXT);
-	q.qname = knot_dname_new_from_str(qname, strlen(qname), 0);
-	if (!q.qname) {
+	knot_dname_t *dname = knot_dname_new_from_str(qname, strlen(qname));
+	if (!dname) {
 		knot_packet_free(&qr);
 		free(qname);
 		return NULL;
 	}
-	q.qtype = KNOT_RRTYPE_ANY;
-	q.qclass = KNOT_CLASS_CH;
 
 	/* Cannot return != KNOT_EOK, but still. */
-	if (knot_query_set_question(qr, &q) != KNOT_EOK) {
+	if (knot_query_set_question(qr, dname, KNOT_CLASS_CH, KNOT_RRTYPE_ANY) != KNOT_EOK) {
 		knot_packet_free(&qr);
+		knot_dname_free(&dname);
 		free(qname);
 		return NULL;
 	}
 
-	knot_dname_release(q.qname);
+	knot_dname_free(&dname);
 	free(qname);
 
 	return qr;
@@ -724,7 +722,7 @@ int remote_query_append(knot_packet_t *qry, knot_rrset_t *data)
 	size_t bsize = 0;
 	int ret = knot_rrset_to_wire(data, sp, &bsize, qry->max_size, &rrs, 0);
 	if (ret == KNOT_EOK) {
-		qry->header.nscount += rrs;
+		knot_wire_add_nscount(qry->wireformat, rrs);
 	}
 
 	/* Finalize packet size. */
@@ -760,7 +758,7 @@ knot_rrset_t* remote_build_rr(const char *k, uint16_t t)
 	}
 
 	/* Assert K is FQDN. */
-	knot_dname_t *key = knot_dname_new_from_nonfqdn_str(k, strlen(k), 0);
+	knot_dname_t *key = knot_dname_new_from_str(k, strlen(k));
 	if (!key) {
 		return NULL;
 	}
@@ -808,7 +806,7 @@ int remote_create_ns(knot_rrset_t *rr, const char *d)
 	}
 
 	/* Create dname. */
-	knot_dname_t *dn = knot_dname_new_from_nonfqdn_str(d, strlen(d), NULL);
+	knot_dname_t *dn = knot_dname_new_from_str(d, strlen(d));
 	if (!dn) {
 		return KNOT_ERROR;
 	}
diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c
index e6c95649fd10542228d40c23a514339bcff53d6c..244aa6b91c103149984144ca882a674094c74c43 100644
--- a/src/knot/server/notify.c
+++ b/src/knot/server/notify.c
@@ -47,7 +47,7 @@
 static int notify_request(const knot_rrset_t *rrset,
                           uint8_t *buffer, size_t *size)
 {
-	knot_packet_t *pkt = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	knot_packet_t *pkt = knot_packet_new();
 	CHECK_ALLOC_LOG(pkt, KNOT_ENOMEM);
 
 	/*! \todo Get rid of the numeric constant. */
@@ -63,14 +63,7 @@ static int notify_request(const knot_rrset_t *rrset,
 		return KNOT_ERROR;
 	}
 
-	knot_question_t question;
-
-	// this is ugly!!
-	question.qname = rrset->owner;
-	question.qtype = rrset->type;
-	question.qclass = rrset->rclass;
-
-	rc = knot_query_set_question(pkt, &question);
+	rc = knot_query_set_question(pkt, rrset->owner, rrset->rclass, rrset->type);
 	if (rc != KNOT_EOK) {
 		knot_packet_free(&pkt);
 		return KNOT_ERROR;
@@ -78,7 +71,6 @@ static int notify_request(const knot_rrset_t *rrset,
 
 	/* Set random query ID. */
 	knot_packet_set_random_id(pkt);
-	knot_wire_set_id(pkt->wireformat, pkt->header.id);
 
 	/*! \todo add the SOA RR to the Answer section as a hint */
 	/*! \todo this should not use response API!! */
@@ -123,14 +115,13 @@ static int notify_request(const knot_rrset_t *rrset,
 int notify_create_response(knot_packet_t *request, uint8_t *buffer,
                            size_t *size)
 {
-	knot_packet_t *response =
-		knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	knot_packet_t *response = knot_packet_new_mm(&request->mm);
 	CHECK_ALLOC_LOG(response, KNOT_ENOMEM);
 
 	/* Set maximum packet size. */
 	int rc = knot_packet_set_max_size(response, *size);
 	if (rc == KNOT_EOK) {
-		rc = knot_response_init_from_query(response, request, 1);
+		rc = knot_response_init_from_query(response, request);
 	}
 
 	/* Aggregated result check. */
diff --git a/src/knot/server/rrl.c b/src/knot/server/rrl.c
index f064d8fd87738c3b312905c877e9fab2940663d7..2bacd06e171ac098f685e3fd54e79075f09d82c3 100644
--- a/src/knot/server/rrl.c
+++ b/src/knot/server/rrl.c
@@ -99,8 +99,8 @@ static uint8_t rrl_clsid(rrl_req_t *p)
 	}
 
 	/* Check query type for spec. classes. */
-	if (p->qst) {
-		switch(p->qst->qtype) {
+	if (p->query) {
+		switch(knot_packet_qtype(p->query)) {
 		case KNOT_RRTYPE_ANY:      /* ANY spec. class */
 			return CLS_ANY;
 			break;
@@ -143,7 +143,7 @@ static int rrl_clsname(char *dst, size_t maxlen, uint8_t cls,
 		dbg_rrl_verb("%s: using zone/fallback name\n", __func__);
 		break;
 	default:
-		if (p->qst) dn = p->qst->qname;
+		if (p->query) dn = knot_packet_qname(p->query);
 		break;
 	}
 
diff --git a/src/knot/server/rrl.h b/src/knot/server/rrl.h
index 59ac9a6bfd622246763916f107a118e92750f24f..549a7b6bd392c37e8ad45aabfb6f3ed43cd7a3a9 100644
--- a/src/knot/server/rrl.h
+++ b/src/knot/server/rrl.h
@@ -78,7 +78,7 @@ typedef struct rrl_req {
 	const uint8_t *w;
 	uint16_t len;
 	unsigned flags;
-	const knot_question_t *qst;
+	knot_packet_t *query;
 } rrl_req_t;
 
 /*!
diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
index f8fe90bb4caa14c36d5f641e376b287aa8677465..bb76713c919b59437f94406f1caa0366e7676507 100644
--- a/src/knot/server/tcp-handler.c
+++ b/src/knot/server/tcp-handler.c
@@ -166,7 +166,7 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
 	/* Parse query. */
 	size_t resp_len = qbuf_maxlen; // 64K
 	knot_packet_type_t qtype = KNOT_QUERY_NORMAL;
-	knot_packet_t *packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	knot_packet_t *packet = knot_packet_new();
 	if (packet == NULL) {
 		int ret = knot_ns_error_response_from_query_wire(ns, qbuf, n,
 		                                            KNOT_RCODE_SERVFAIL,
@@ -268,8 +268,6 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
 		break;
 	}
 
-	knot_packet_free(&packet);
-
 	/* Send answer. */
 	if (res == KNOT_EOK) {
 		tcp_reply(fd, qbuf, resp_len);
@@ -278,6 +276,8 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
 		        qtype, fd, knot_strerror(res));;
 	}
 
+	knot_packet_free(&packet);
+
 	return res;
 }
 
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
index 259ac5aa1169028d8727505b4e3f12b7e647994f..de4a354f4dbf88043ddcc606b82080bdc0e6ecbb 100644
--- a/src/knot/server/udp-handler.c
+++ b/src/knot/server/udp-handler.c
@@ -152,7 +152,7 @@ int udp_handle(struct answer_ctx *ans, int fd,
 	return KNOT_EOK;
 #endif
 
-	knot_packet_t *packet = knot_packet_new_mm(KNOT_PACKET_PREALLOC_QUERY, ans->mm);
+	knot_packet_t *packet = knot_packet_new_mm(ans->mm);
 	if (packet == NULL) {
 		dbg_net("udp: failed to create packet\n");
 		int ret = knot_ns_error_response_from_query_wire(ns, qbuf, qbuflen,
@@ -220,7 +220,7 @@ int udp_handle(struct answer_ctx *ans, int fd,
 		rrl_req_t rrl_rq;
 		memset(&rrl_rq, 0, sizeof(rrl_req_t));
 		rrl_rq.w = qbuf; /* Wire */
-		rrl_rq.qst = &packet->question;
+		rrl_rq.query = packet;
 
 		rcu_read_lock();
 		rrl_rq.flags = packet->flags;
@@ -535,7 +535,7 @@ int udp_reader(iohandler_t *h, dthread_t *thread)
 	mm_ctx_t mm;
 	mm.ctx = pool;
 	mm.alloc = (mm_alloc_t)mp_alloc;
-	mm.free = NULL;
+	mm.free = mm_nofree;
 
 	/* Create UDP answering context. */
 	struct answer_ctx ans_ctx;
diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c
index c7c1abfcca05e5157395c61474f7eadc31177fde..0d032e48f49d21b777b0e0b5d3035e74d526c364 100644
--- a/src/knot/server/xfr-handler.c
+++ b/src/knot/server/xfr-handler.c
@@ -563,7 +563,7 @@ static int xfr_task_finalize(xfrworker_t *w, knot_ns_xfr_t *rq)
 static int xfr_task_resp(xfrworker_t *w, knot_ns_xfr_t *rq)
 {
 	knot_nameserver_t *ns = w->master->ns;
-	knot_packet_t *re = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+	knot_packet_t *re = knot_packet_new();
 	if (re == NULL) {
 		return KNOT_ENOMEM;
 	}
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index d1a3bf694e4d07f9339d37e0636a52836f1e67cb..c69b0d13bcc7f0e64600f5ecd82daa55578ecc98 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -581,7 +581,7 @@ static int zones_load_zone(knot_zone_t **dst, const char *zone_name,
 	/* Check if loaded origin matches. */
 	const knot_dname_t *dname = knot_zone_name(*dst);
 	knot_dname_t *dname_req = NULL;
-	dname_req = knot_dname_new_from_str(zone_name, strlen(zone_name), 0);
+	dname_req = knot_dname_new_from_str(zone_name, strlen(zone_name));
 	if (knot_dname_compare(dname, dname_req) != 0) {
 		log_server_error("Origin of the zone db file is "
 				 "different than '%s'\n",
@@ -1035,8 +1035,7 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst,
 
 	/* Convert the zone name into a domain name. */
 	/* Local allocation, will be discarded. */
-	knot_dname_t *dname = knot_dname_new_from_str(z->name, strlen(z->name),
-	                                              NULL);
+	knot_dname_t *dname = knot_dname_new_from_str(z->name, strlen(z->name));
 	if (dname == NULL) {
 		log_server_error("Error creating domain name from zone"
 		                 " name\n");
@@ -1521,7 +1520,7 @@ static int zones_update_forward(int fd, knot_ns_transport_t ttype,
 	rq->packet_nr = (int)knot_packet_id(query);
 
 	/* Duplicate query to keep it in memory during forwarding. */
-	rq->query = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	rq->query = knot_packet_new();
 	if (!rq->query) {
 		xfr_task_free(rq);
 		rcu_read_unlock();
@@ -1535,7 +1534,7 @@ static int zones_update_forward(int fd, knot_ns_transport_t ttype,
 		rcu_read_unlock();
 		return KNOT_ENOMEM;
 	}
-	rq->query->free_wireformat = 1;
+	rq->query->flags |= KNOT_PF_FREE_WIRE;
 	memcpy(rq->query->wireformat, query->wireformat, knot_packet_size(query));
 
 	/* Retain pointer to zone and issue. */
@@ -2050,7 +2049,6 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver,
 	int ret = knot_ns_prep_normal_response(nameserver, query, &resp, &zone,
 	                                       (transport == NS_TRANSPORT_TCP)
 	                                       ? *rsize : 0);
-	query->zone = zone;
 
 	switch (ret) {
 	case KNOT_EOK:
@@ -2641,8 +2639,7 @@ int zones_save_zone(const knot_ns_xfr_t *xfr)
 
 	/* Check if the new zone apex dname matches zone name. */
 	knot_dname_t *cur_name = knot_dname_new_from_str(zd->conf->name,
-	                                                 strlen(zd->conf->name),
-	                                                 NULL);
+	                                                 strlen(zd->conf->name));
 	const knot_dname_t *new_name = NULL;
 	new_name = knot_node_owner(knot_zone_contents_apex(new_zone));
 	int r = knot_dname_compare(cur_name, new_name);
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
index 1d3c5c4e0bebe0551600b051bd8249c98018a493..5bd0b7596d3d78c07496cca963513e0b370c8a2f 100644
--- a/src/knot/zone/semantic-check.c
+++ b/src/knot/zone/semantic-check.c
@@ -308,7 +308,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 	/* label number at the 2nd index should be same as owner's */
 	uint8_t labels_rdata = knot_rrset_rdata_rrsig_labels(rrsig, rr_pos);
 
-	int tmp = knot_dname_label_count(knot_rrset_owner(rrset)) -
+	int tmp = knot_dname_wire_labels(knot_rrset_owner(rrset)->name, NULL) -
 		  labels_rdata;
 
 	if (tmp != 0) {
@@ -685,7 +685,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 	/* Local allocation, will be discarded. */
 	knot_dname_t *next_dname =
 		knot_dname_new_from_str((char *)next_dname_decoded,
-					   real_size, NULL);
+					   real_size);
 	if (next_dname == NULL) {
 		free(next_dname_decoded);
 		log_zone_warning("Could not create new dname!\n");
@@ -893,13 +893,15 @@ static int sem_check_node_optional(knot_zone_contents_t *zone,
 			if (glue_node == NULL) {
 				/* Try wildcard. */
 				knot_dname_t *wildcard =
-					knot_dname_new_from_str("*", 1, NULL);
+					knot_dname_new_from_str("*", 1);
 				if (wildcard == NULL) {
 					knot_dname_free(&ns_dname);
 					return KNOT_ENOMEM;
 				}
 				
-				knot_dname_left_chop_no_copy(ns_dname);
+				knot_dname_t *old_ns_dname = ns_dname;
+				ns_dname = knot_dname_left_chop(ns_dname);
+				knot_dname_free(&old_ns_dname);
 		
 				if (knot_dname_cat(wildcard,
 				                   ns_dname) == NULL) {
@@ -1244,7 +1246,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 		/* Local allocation, will be discarded. */
 		knot_dname_t *next_dname =
 			knot_dname_new_from_str((char *)next_dname_decoded,
-						real_size, NULL);
+						real_size);
 		if (next_dname == NULL) {
 			dbg_semcheck("Could not allocate dname!\n");
 			free(next_dname_decoded);
diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c
index ac414f1b991ce258cd83812c86bb46d1ef75d66b..c6cb2aff3c26366247cec5366e51d070c149402e 100644
--- a/src/knot/zone/zone-load.c
+++ b/src/knot/zone/zone-load.c
@@ -257,8 +257,7 @@ static int add_rdata_to_rr(knot_rrset_t *rrset, const scanner_t *scanner)
 			knot_dname_t *dname =
 				knot_dname_new_from_wire(scanner->r_data +
 			                                 scanner->r_data_blocks[i],
-			                                 scanner->r_data_blocks[i + 1] - scanner->r_data_blocks[i],
-			                                 NULL);
+			                                 scanner->r_data_blocks[i + 1] - scanner->r_data_blocks[i]);
 			if (dname == NULL) {
 				return KNOT_ERROR;
 			}
@@ -319,8 +318,7 @@ static void process_rr(const scanner_t *scanner)
     	} else {
     		current_owner = 
     			knot_dname_new_from_wire(scanner->r_owner,
-    			                         scanner->r_owner_length,
-    			                         NULL);
+		                                 scanner->r_owner_length);
 	    	if (current_owner == NULL) {
 			parser->ret = KNOT_ERROR;
 			return;
@@ -603,7 +601,7 @@ int knot_zload_open(zloader_t **dst, const char *source, const char *origin,
 	}
 	
 	context->origin_from_config =
-		knot_dname_new_from_str(origin, strlen(origin), NULL);
+		knot_dname_new_from_str(origin, strlen(origin));
 	assert(context->origin_from_config);
 	knot_dname_to_lower(context->origin_from_config);
 	/* Add first DNAME to lookup tree. */
diff --git a/src/libknot/dname.c b/src/libknot/dname.c
index 754efe485ecef85665a53883c19b804f324ef6ba..ff037c949266c18a7a210fddd8f229ba183106f4 100644
--- a/src/libknot/dname.c
+++ b/src/libknot/dname.c
@@ -31,96 +31,20 @@
 #include "util/utils.h"
 #include "util/wire.h"
 
-/*! \todo dnames allocated from TLS cache will be discarded after thread
- *        termination. This shouldn't happpen.
- */
-#if 0
-/*
- * Memory cache.
- */
-#include "common/slab/slab.h"
-#include <stdio.h>
-#include <pthread.h>
-
-/*! \brief TLS unique key for each thread cache. */
-static pthread_key_t dname_ckey;
-static pthread_once_t dname_once = PTHREAD_ONCE_INIT;
-
-/*! \brief Destroy thread dname cache (automatically called). */
-static void knot_dname_cache_free(void *ptr)
-{
-	slab_cache_t* cache = (slab_cache_t*)ptr;
-	if (cache) {
-		slab_cache_destroy(cache);
-		free(cache);
-	}
-}
-
-/*! \brief Cleanup for main() TLS. */
-static void knot_dname_cache_main_free()
-{
-	knot_dname_cache_free(pthread_getspecific(dname_ckey));
-}
-
-static void knot_dname_cache_init()
-{
-	(void) pthread_key_create(&dname_ckey, knot_dname_cache_free);
-	atexit(knot_dname_cache_main_free); // Main thread cleanup
-}
-#endif
-
-/*!
- * \brief Allocate item from thread cache.
- * \retval Allocated dname instance on success.
- * \retval NULL on error.
- */
-static knot_dname_t* knot_dname_alloc()
-{
-	return malloc(sizeof(knot_dname_t));
-
-	/*! \todo dnames allocated from TLS cache will be discarded after thread
-	 *        termination. This shouldn't happpen.
-	 */
-#if 0
-	/* Initialize dname cache TLS key. */
-	(void)pthread_once(&dname_once, knot_dname_cache_init);
-
-	/* Create cache if not exists. */
-	slab_cache_t* cache = pthread_getspecific(dname_ckey);
-	if (knot_unlikely(!cache)) {
-		cache = malloc(sizeof(slab_cache_t));
-		if (!cache) {
-			return 0;
-		}
-
-		/* Initialize cache. */
-		slab_cache_init(cache, sizeof(knot_dname_t));
-		(void)pthread_setspecific(dname_ckey, cache);
-	}
-
-	return slab_cache_alloc(cache);
-#endif
-}
 
 /*----------------------------------------------------------------------------*/
 /* Non-API functions                                                          */
 /*----------------------------------------------------------------------------*/
 
-static int knot_dname_set(knot_dname_t *dname, uint8_t *wire,
-                            short wire_size, const uint8_t *labels,
-                            short label_count)
+static knot_dname_t *knot_dname_new()
 {
-	dname->name = wire;
-	dname->size = wire_size;
-	dname->label_count = label_count;
+	knot_dname_t *dname = malloc(sizeof(knot_dname_t));
 
-	assert(label_count >= 0);
-
-	dname->labels = (uint8_t *)malloc(dname->label_count * sizeof(uint8_t));
-	CHECK_ALLOC_LOG(dname->labels, -1);
-	memcpy(dname->labels, labels, dname->label_count);
+	dname->name = NULL;
+	dname->count = 1;
+	dname->size = 0;
 
-	return 0;
+	return dname;
 }
 
 /*!
@@ -141,258 +65,72 @@ static int knot_dname_set(knot_dname_t *dname, uint8_t *wire,
 static int knot_dname_str_to_wire(const char *name, uint size,
                                     knot_dname_t *dname)
 {
-	if (size > KNOT_MAX_DNAME_LENGTH) {
-		return -1;
-	}
-
-	uint wire_size;
-	int root = (*name == '.' && size == 1);
-	// root => different size
-	if (root) {
-		wire_size = 1;
-	} else {
-		wire_size = size + 1;
+	if (size == 0 || size > KNOT_MAX_DNAME_LENGTH) {
+		return KNOT_EINVAL;
 	}
 
-	uint8_t *wire;
-	uint8_t labels[KNOT_MAX_DNAME_LABELS];
-	short label_count = 0;
-
-	// signed / unsigned issues??
-	wire = (uint8_t *)malloc(wire_size * sizeof(uint8_t));
-	if (wire == NULL) {
-		return -1;
+	unsigned wire_size = size + 1;
+	if (name[0] == '.' && size == 1) {
+		wire_size = 1; /* Root label. */
+		size = 0;      /* Do not parse input. */
+	} else if (name[size - 1] != '.') {
+		++wire_size; /* No FQDN, reserve last root label. */
 	}
 
-	dbg_dname_verb("Allocated space for wire format of dname: %p\n", wire);
-
-	if (root) {
-		*wire = '\0';
-		label_count = 0;
-		return knot_dname_set(dname, wire, wire_size, labels,
-		                        label_count);
-	}
+	/* Create wire. */
+	uint8_t *wire = malloc(wire_size * sizeof(uint8_t));
+	if (wire == NULL)
+		return KNOT_ENOMEM;
+	*wire = '\0';
 
 	const uint8_t *ch = (const uint8_t *)name;
-	uint8_t *label_start = wire;
-	uint8_t *w = wire + 1;
-	uint8_t label_length = 0;
-
-	while (ch - (const uint8_t *)name < size) {
-		assert(w - wire - 1 == ch - (const uint8_t *)name);
-
+	const uint8_t *np = ch + size;
+	uint8_t *label = wire;
+	uint8_t *w = wire + 1; /* Reserve 1 for label len */
+	while (ch != np) {
 		if (*ch == '.') {
 			/* Zero-length label inside a dname - invalid. */
-			if (label_length == 0) {
+			if (*label == 0) {
 				free(wire);
-				return -1;
+				return KNOT_EMALF;
 			}
-			dbg_dname_detail("Position %zd (%p): "
-			                 "label length: %u\n",
-			                 label_start - wire,
-			                 label_start, label_length);
-			*label_start = label_length;
-			labels[label_count++] = label_start - wire;
-			label_start = w;
-			label_length = 0;
+			label = w;
+			*label = '\0';
 		} else {
-			assert(w - wire < wire_size);
-			dbg_dname_detail("Position %zd (%p): character: %c\n",
-			                 w - wire, w, *ch);
 			*w = *ch;
-			++label_length;
+			*label += 1;
 		}
-
 		++w;
 		++ch;
-		assert(ch >= (const uint8_t *)name);
 	}
 
-	--ch;
-	if (*ch == '.') { // put 0 for root label if the name ended with .
-		--w;
-		dbg_dname_detail("Position %zd (%p): character: (null)\n",
-		                 w - wire, w);
-		*w = 0;
-	} else { // otherwise we did not save the last label length
-		dbg_dname_detail("Position %zd (%p): label length: %u\n",
-		                 label_start - wire,
-		                 label_start, label_length);
-		*label_start = label_length;
-		labels[label_count++] = label_start - wire;
+	/* Check for non-FQDN name. */
+	if (*label > 0) {
+		*w = '\0';
 	}
 
-	return knot_dname_set(dname, wire, wire_size, labels, label_count);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static inline int knot_dname_tolower(uint8_t c, int cs)
-{
-	return (cs) ? c : knot_tolower(c);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static int knot_dname_compare_labels(const uint8_t *label1,
-                                       const uint8_t *label2, int cs)
-{
-	const uint8_t *pos1 = label1;
-	const uint8_t *pos2 = label2;
-
-	int label_length = (*pos1 < *pos2) ? *pos1 : *pos2;
-	int i = 0;
-
-	while (i < label_length
-	       && knot_dname_tolower(*(++pos1), cs)
-	          == knot_dname_tolower(*(++pos2), cs)) {
-		++i;
-	}
-
-	if (i < label_length) {  // difference in some octet
-		return (knot_dname_tolower(*pos1, cs)
-		        - knot_dname_tolower(*pos2, cs));
-	}
-
-	return (label1[0] - label2[0]);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static int knot_dname_find_labels(knot_dname_t *dname, int alloc)
-{
-	const uint8_t *name = dname->name;
-	const uint8_t *pos = name;
-	const uint size = dname->size;
-
-	uint8_t labels[KNOT_MAX_DNAME_LABELS];
-	short label_count = 0;
-
-	while (pos - name < size && *pos != '\0' && label_count < KNOT_MAX_DNAME_LABELS ) {
-		if (*pos > 63) { /* Check label lengths. */
-			dbg_dname("Wrong wire format of domain name!\n");
-			dbg_dname("Label %d exceeds 63 bytes.\n", label_count);
-			return -1;
-		}
-		labels[label_count++] = pos - name;
-		pos += *pos + 1;
-	}
-
-	// TODO: how to check if the domain name has right format?
-	if (label_count == KNOT_MAX_DNAME_LABELS) {
-		dbg_dname("Wrong wire format of domain name!\n");
-		dbg_dname("Too many labels: %s\n", name);
-		return -1;
-	}
-
-	if (pos - name > size || *pos != '\0' ) {
-		dbg_dname("Wrong wire format of domain name!\n");
-		dbg_dname("Position: %"PRIuPTR", character: %d, expected size: %d\n",
-		          pos - name, *pos, size);
-		return -1;
-	}
-
-	if (alloc) {
-		dname->labels
-			= (uint8_t *)malloc(label_count * sizeof(uint8_t));
-		CHECK_ALLOC_LOG(dname->labels, KNOT_ENOMEM);
-	}
-
-	memcpy(dname->labels, labels, label_count);
-	dname->label_count = label_count;
-
-	return 0;
+	dname->name = wire;
+	dname->size = wire_size;
+	return KNOT_EOK;
 }
 
 /*----------------------------------------------------------------------------*/
 
-static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
-                            int cs)
+static int knot_label_is_equal(const uint8_t *lb1, const uint8_t *lb2)
 {
-dbg_dname_exec_verb(
-	char *name1 = knot_dname_to_str(d1);
-	char *name2 = knot_dname_to_str(d2);
-
-	dbg_dname_verb("Comparing dnames %s and %s\n", name1, name2);
-
-	for (int i = 0; i < strlen(name1); ++i) {
-		name1[i] = knot_tolower(name1[i]);
-	}
-	for (int i = 0; i < strlen(name2); ++i) {
-		name2[i] = knot_tolower(name2[i]);
-	}
-
-	dbg_dname_detail("After to lower: %s and %s\n", name1, name2);
-
-	free(name1);
-	free(name2);
-);
-
-	if (!cs && d1 == d2) {
-		return 0;
-	}
-
-	int l1 = d1->label_count;
-	int l2 = d2->label_count;
-	dbg_dname_detail("Label counts: %d and %d\n", l1, l2);
-	assert(l1 >= 0);
-	assert(l2 >= 0);
-
-	// compare labels from last to first
-	while (l1 > 0 && l2 > 0) {
-		dbg_dname_detail("Comparing labels %d and %d\n",
-		                 l1 - 1, l2 - 1);
-		dbg_dname_detail(" at offsets: %d and %d\n",
-		                 d1->labels[l1 - 1], d2->labels[l2 - 1]);
-		int res = knot_dname_compare_labels(
-		                   &d1->name[d1->labels[--l1]],
-		                   &d2->name[d2->labels[--l2]],
-		                   cs);
-		if (res != 0) {
-			return res;
-		} // otherwise the labels are identical, continue with previous
-	}
-
-	// if all labels matched, the shorter name is first
-	if (l1 == 0 && l2 > 0) {
-		return -1;
-	}
-
-	if (l1 > 0 && l2 == 0) {
-		return 1;
-	}
-
-	return 0;
+	return (*lb1 == *lb2) && memcmp(lb1 + 1, lb2 + 1, *lb1) == 0;
 }
 
 /*----------------------------------------------------------------------------*/
 /* API functions                                                              */
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_new()
-{
-	knot_dname_t *dname = knot_dname_alloc();
-
-	dname->name = NULL;
-	dname->labels = NULL;
-	dname->node = NULL;
-	dname->count = 1;
-	dname->size = 0;
-	dname->label_count = 0;
-
-	return dname;
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_dname_t *knot_dname_new_from_str(const char *name, uint size,
-                                          struct knot_node *node)
+knot_dname_t *knot_dname_new_from_str(const char *name, uint size)
 {
 	if (name == NULL || size == 0) {
 		return NULL;
 	}
 
-//	knot_dname_t *dname = knot_dname_alloc();
 	knot_dname_t *dname = knot_dname_new();
 
 	if (dname == NULL) {
@@ -408,47 +146,18 @@ knot_dname_t *knot_dname_new_from_str(const char *name, uint size,
 		return NULL;
 	}
 
-dbg_dname_exec_verb(
-	dbg_dname_verb("Created dname with size: %d\n", dname->size);
-	dbg_dname_verb("Label offsets: ");
-	for (int i = 0; i < dname->label_count; ++i) {
-		dbg_dname_verb("%d, ", dname->labels[i]);
-	}
-	dbg_dname_verb("\n");
-);
-
 	if (dname->size <= 0) {
 		dbg_dname("Could not parse domain name "
 		          "from string: '%.*s'\n", size, name);
 	}
 	assert(dname->name != NULL);
 
-	dname->node = node;
 	return dname;
 }
 
 /*----------------------------------------------------------------------------*/
 
-knot_dname_t *knot_dname_new_from_nonfqdn_str(const char *name, uint size,
-                                                  struct knot_node *node)
-{
-	knot_dname_t *dname = NULL;
-
-	if (name[size - 1] != '.') {
-		char *fqdn = strcdup(name, ".");
-		dname = knot_dname_new_from_str(fqdn, size + 1, node);
-		free(fqdn);
-	} else {
-		dname = knot_dname_new_from_str(name, size, node);
-	}
-
-	return dname;
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size,
-                                           struct knot_node *node)
+knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size)
 {
 	if (name == NULL) { /* && size != 0) { !OS: Nerozumjaju */
 		dbg_dname("No name given!\n");
@@ -469,116 +178,26 @@ knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size,
 		return NULL;
 	}
 
+	/*! \todo this won't work for non-linear names */
 	memcpy(dname->name, name, size);
 	dname->size = size;
-
-	if (knot_dname_find_labels(dname, 1) != 0) {
-		dbg_dname("Could not find labels in dname (new from wire).\n");
-		knot_dname_free(&dname);
-		return NULL;
-	}
-
-	dname->node = node;
 	return dname;
 }
 
 /*----------------------------------------------------------------------------*/
 
 knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
-                                         size_t *pos, size_t size,
-                                         knot_node_t *node,
-                                         knot_dname_t *dname)
+                                         size_t *pos, size_t size)
 {
-	uint8_t name[KNOT_MAX_DNAME_LENGTH];
-	uint8_t labels[KNOT_MAX_DNAME_LABELS];
-
-	short l = 0;
-	size_t i = 0, p = *pos;
-	int pointer_used = 0;
-
-	while (p < size && wire[p] != 0) {
-		/* Check maximum number of labels (may overflow). */
-		if (l == KNOT_MAX_DNAME_LABELS) {
-			return NULL;
-		}
-		labels[l] = i;
-		dbg_dname_detail("Next label (%d.) position: %zu\n", l, i);
-
-		if (knot_wire_is_pointer(wire + p)) {
-			// pointer.
-			size_t ptr = knot_wire_get_pointer(wire + p);
-
-			/* Check that the pointer points backwards
-			 * otherwise it could result in infinite loop
-			 */
-			if (ptr >= p) {
-				return NULL;
-			}
-
-			p = ptr;
-
-			if (!pointer_used) {
-				*pos += 2;
-				pointer_used = 1;
-			}
-			if (p >= size) {
-				return NULL;
-			}
-		} else {
-			// label; first byte is label length
-			uint8_t length = *(wire + p);
-			/* Check label length (maximum 63 bytes allowed). */
-			if (length > 63) {
-				return NULL;
-			}
-			/* Check if there's enough space. */
-			if (i + length + 2 > KNOT_MAX_DNAME_LENGTH) {
-				return NULL;
-			}
-			//printf("Label %d (max %d), length: %u.\n", l, KNOT_MAX_DNAME_LABELS, length);
-			memcpy(name + i, wire + p, length + 1);
-			p += length + 1;
-			i += length + 1;
-			if (!pointer_used) {
-				*pos += length + 1;
-			}
-			++l;
-		}
-	}
-	if (p >= size) {
+	const uint8_t *name = wire + *pos;
+	const uint8_t *endp = wire + size;
+	int parsed = knot_dname_wire_check(name, endp, wire);
+	if (parsed < 0)
 		return NULL;
-	}
 
-	name[i] = 0;
-	if (!pointer_used) {
-		*pos += 1;
-	}
-
-	/* Allocate if NULL. */
-	if (dname == NULL) {
-		dname = knot_dname_new();
-		if (dname) {
-			dname->name = (uint8_t *)malloc((i + 1) * sizeof(uint8_t));
-			dname->labels = (uint8_t *)malloc((l + 1) * sizeof(uint8_t));
-		}
-	}
-
-	if (dname == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
-
-	if (dname->name == NULL || dname->labels == NULL) {
-		ERR_ALLOC_FAILED;
-		knot_dname_free(&dname);
-		return NULL;
-	}
-
-	memcpy(dname->name, name, i + 1);
-	memcpy(dname->labels, labels, l + 1);
-	dname->size = i + 1;
-	dname->label_count = l;
-	dname->node = node;
+	knot_dname_t *dname = knot_dname_new_from_wire(name, parsed);
+	if (dname)
+		*pos += parsed;
 
 	return dname;
 }
@@ -587,7 +206,6 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
 
 knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname)
 {
-	//return knot_dname_new_from_wire(dname->name, dname->size, dname->node);
 	/* dname_new_from_wire() does not accept non-FQDN dnames, so we
 	 * do the copy by hand. It's faster anyway */
 
@@ -598,27 +216,15 @@ knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname)
 	knot_dname_t *copy = knot_dname_new();
 	CHECK_ALLOC(copy, NULL);
 
-	copy->labels = (uint8_t *)(malloc(dname->label_count));
-
-	if (copy->labels == NULL) {
-		knot_dname_free(&copy);
-		return NULL;
-	}
-
 	copy->name = (uint8_t *)(malloc(dname->size));
 	if (copy->name == NULL) {
 		knot_dname_free(&copy);
 		return NULL;
 	}
 
-	memcpy(copy->labels, dname->labels, dname->label_count);
-	copy->label_count = dname->label_count;
-
 	memcpy(copy->name, dname->name, dname->size);
 	copy->size = dname->size;
 
-	copy->node = dname->node;
-
 	return copy;
 }
 
@@ -705,14 +311,7 @@ char *knot_dname_to_str(const knot_dname_t *dname)
 
 int knot_dname_to_lower(knot_dname_t *dname)
 {
-	if (dname == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	for (int i = 0; i < dname->size; ++i) {
-		dname->name[i] = knot_tolower(dname->name[i]);
-	}
-	return KNOT_EOK;
+	return knot_dname_to_lower_copy(dname, (char*)dname->name, dname->size);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -746,97 +345,6 @@ uint knot_dname_size(const knot_dname_t *dname)
 
 /*----------------------------------------------------------------------------*/
 
-uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels)
-{
-	assert(labels < dname->label_count);
-	assert(dname->labels != NULL);
-	return (dname->labels[labels]);
-}
-
-/*----------------------------------------------------------------------------*/
-
-const struct knot_node *knot_dname_node(const knot_dname_t *dname)
-
-{
-	return knot_dname_get_node(dname);
-}
-
-/*----------------------------------------------------------------------------*/
-
-struct knot_node *knot_dname_get_node(const knot_dname_t *dname)
-{
-	if (dname == NULL) {
-		return NULL;
-	}
-
-	knot_node_t *node = dname->node;
-
-	/*
-	 * If the zone contains new zone contents (during an update), we should
-	 * return new node. Check if the node has the new node set. If it does
-	 * not, it means this is already the new node. If it has, return the
-	 * new node. If the new node is empty, return NULL, as the node will be
-	 * deleted later.
-	 */
-dbg_dname_exec_detail(
-	dbg_dname_detail("Getting node from dname: node: %p, zone: %p\n", node,
-			 knot_node_zone(node));
-	if (node != NULL && knot_node_zone(node) != NULL
-	    && knot_zone_contents(knot_node_zone(node)) != NULL) {
-		dbg_dname_detail("zone contents gen: %d, new node of the node: "
-			 "%p, is empty: %d\n",
-			 knot_zone_contents_gen_is_new(knot_zone_contents(
-							 knot_node_zone(node))),
-			 knot_node_new_node(node),
-			 knot_node_new_node(node)
-			       ? knot_node_is_empty(knot_node_new_node(node))
-			       : -1);
-	}
-);
-
-	if (node && knot_node_zone(node)
-	    && knot_zone_contents(knot_node_zone(node))
-	    && knot_zone_contents_gen_is_new(knot_zone_contents(
-		knot_node_zone(node)))
-	    && knot_node_new_node(node) != NULL) {
-		node = knot_node_get_new_node(node);
-		if (knot_node_is_empty(node)) {
-			node = NULL;
-		}
-	}
-
-	return node;
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_dname_set_node(knot_dname_t *dname, knot_node_t *node)
-{
-	dname->node = node;
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_dname_update_node(knot_dname_t *dname)
-{
-dbg_dname_exec_detail(
-	char *name = knot_dname_to_str(dname);
-	dbg_dname_detail("Updating node pointer in dname %p: %s. Before: %p\n",
-	                 dname, name, dname->node);
-	free(name);
-);
-
-	knot_node_update_ref(&dname->node);
-	dbg_dname_detail("After: %p\n", dname->node);
-
-	if (knot_node_is_empty(dname->node)) {
-		dbg_dname_detail("Node is empty, setting to NULL.\n");
-		dname->node = NULL;
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
 int knot_dname_is_fqdn(const knot_dname_t *dname)
 {
 	return (dname->name[dname->size - 1] == '\0');
@@ -846,10 +354,7 @@ int knot_dname_is_fqdn(const knot_dname_t *dname)
 
 knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
 {
-	if (dname == NULL ||
-		/* Root domain. */
-		((knot_dname_label_count(dname) == 0) &&
-		 (knot_dname_is_fqdn(dname)))) {
+	if (dname == NULL || *knot_dname_name(dname) == '\0') { /* root */
 		return NULL;
 	}
 
@@ -858,25 +363,6 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
 		return NULL;
 	}
 
-	// last label, the result should be root domain
-	if (dname->label_count == 1) {
-		dbg_dname_verb("Chopping last label.\n");
-		parent->label_count = 0;
-
-		parent->name = (uint8_t *)malloc(1);
-		if (parent->name == NULL) {
-			ERR_ALLOC_FAILED;
-			knot_dname_free(&parent);
-			return NULL;
-		}
-
-		*parent->name = 0;
-
-		parent->size = 1;
-
-		return parent;
-	}
-
 	parent->size = dname->size - dname->name[0] - 1;
 	parent->name = (uint8_t *)malloc(parent->size);
 	if (parent->name == NULL) {
@@ -885,24 +371,7 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
 		return NULL;
 	}
 
-	parent->labels = (uint8_t *)malloc(dname->label_count - 1);
-	if (parent->labels == NULL) {
-		ERR_ALLOC_FAILED;
-		free(parent->name);
-		knot_dname_free(&parent);
-		return NULL;
-	}
-
 	memcpy(parent->name, &dname->name[dname->name[0] + 1], parent->size);
-
-
-	short first_label_length = dname->labels[1];
-
-	for (int i = 0; i < dname->label_count - 1; ++i) {
-		parent->labels[i] = dname->labels[i + 1] - first_label_length;
-	}
-	parent->label_count = dname->label_count - 1;
-
 	return parent;
 }
 
@@ -910,24 +379,13 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
 
 void knot_dname_left_chop_no_copy(knot_dname_t *dname)
 {
-	// copy the name
-	if (dname->label_count > 1) {
-		short first_label_length = dname->labels[1];
-
-		memmove(dname->name, &dname->name[dname->labels[1]],
-			dname->size - first_label_length);
-		// adjust labels
-		for (int i = 0; i < dname->label_count - 1; ++i) {
-			dname->labels[i] = dname->labels[i + 1]
-			                   - first_label_length;
-		}
-		dname->label_count = dname->label_count - 1;
-		dname->size -= first_label_length;
-	} else {
-		dname->name[0] = '\0';
-		dname->size = 1;
-		dname->label_count = 0;
-	}
+	uint8_t len = *knot_dname_name(dname);
+	if (len == 0)
+		return;
+
+	/*! \todo this will work only with linearized names (as of now) */
+	dname->size -= (len + 1);
+	memmove(dname->name, dname->name + len + 1, dname->size);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -935,53 +393,32 @@ void knot_dname_left_chop_no_copy(knot_dname_t *dname)
 int knot_dname_is_subdomain(const knot_dname_t *sub,
                               const knot_dname_t *domain)
 {
-dbg_dname_exec_verb(
-	char *name1 = knot_dname_to_str(sub);
-	char *name2 = knot_dname_to_str(domain);
-
-	dbg_dname_verb("Checking if %s is subdomain of %s\n", name1, name2);
-	free(name1);
-	free(name2);
-);
-
-	if (sub == domain) {
+	if (sub == domain)
 		return 0;
-	}
 
-	// if one of the names is fqdn and the other is not
-	if ((sub->name[sub->size - 1] == '\0'
-	      && domain->name[domain->size - 1] != '\0')
-	    || (sub->name[sub->size - 1] != '\0'
-		&& domain->name[domain->size - 1] == '\0')) {
-		return 0;
-	}
+	/* Count labels. */
+	const uint8_t *sub_p = sub->name;
+	const uint8_t *domain_p = domain->name;
+	int sub_l = knot_dname_wire_labels(sub_p, NULL);
+	int domain_l = knot_dname_wire_labels(domain_p, NULL);
 
-	int l1 = sub->label_count;
-	int l2 = domain->label_count;
-
-	dbg_dname_detail("Label counts: %d and %d\n", l1, l2);
+	/* Subdomain must have more labels as parent. */
+	if (sub_l <= domain_l)
+		return 0;
 
-	if (l1 <= l2) {  // if sub does not have more labes than domain
-		return 0;  // it is not its subdomain
-	}
+	/* Align end-to-end to common suffix. */
+	int common = knot_dname_align(&sub_p, sub_l, &domain_p, domain_l, NULL);
 
-	// compare labels from last to first
-	while (l1 > 0 && l2 > 0) {
-		dbg_dname_detail("Comparing labels %d and %d\n",
-		                 l1 - 1, l2 - 1);
-		dbg_dname_detail(" at offsets: %d and %d\n",
-		                 sub->labels[l1 - 1], domain->labels[l2 - 1]);
-		// if some labels do not match
-		if (knot_dname_compare_labels(&sub->name[sub->labels[--l1]],
-		                    &domain->name[domain->labels[--l2]], 0)
-		    != 0) {
-			return 0;  // sub is not a subdomain of domain
-		} // otherwise the labels are identical, continue with previous
+	/* Compare common suffix. */
+	while(common > 0) {
+		/* Compare label. */
+		if (!knot_label_is_equal(sub_p, domain_p))
+			return 0;
+		/* Next label. */
+		sub_p = knot_wire_next_label(sub_p, NULL);
+		domain_p = knot_wire_next_label(domain_p, NULL);
+		--common;
 	}
-
-	// if all labels matched, it should be subdomain (more labels)
-	assert(l1 > l2);
-
 	return 1;
 }
 
@@ -999,20 +436,27 @@ int knot_dname_is_wildcard(const knot_dname_t *dname)
 int knot_dname_matched_labels(const knot_dname_t *dname1,
                                 const knot_dname_t *dname2)
 {
-	int l1 = dname1->label_count;
-	int l2 = dname2->label_count;
+	/* Count labels. */
+	const uint8_t *d1 = dname1->name;
+	const uint8_t *d2 = dname2->name;
+	int l1 = knot_dname_wire_labels(d1, NULL);
+	int l2 = knot_dname_wire_labels(d2, NULL);
 
-	// compare labels from last to first
+	/* Align end-to-end to common suffix. */
+	int common = knot_dname_align(&d1, l1, &d2, l2, NULL);
+
+	/* Count longest chain leading to root label. */
 	int matched = 0;
-	while (l1 > 0 && l2 > 0) {
-		int res = knot_dname_compare_labels(
-		               &dname1->name[dname1->labels[--l1]],
-		               &dname2->name[dname2->labels[--l2]], 0);
-		if (res == 0) {
+	while (common > 0) {
+		if (knot_label_is_equal(d1, d2))
 			++matched;
-		} else  {
-			break;
-		}
+		else
+			matched = 0; /* Broken chain. */
+
+		/* Next label. */
+		d1 = knot_wire_next_label(d1, NULL);
+		d2 = knot_wire_next_label(d2, NULL);
+		--common;
 	}
 
 	return matched;
@@ -1020,24 +464,6 @@ int knot_dname_matched_labels(const knot_dname_t *dname1,
 
 /*----------------------------------------------------------------------------*/
 
-int knot_dname_label_count(const knot_dname_t *dname)
-{
-	return dname->label_count;
-}
-
-/*----------------------------------------------------------------------------*/
-
-uint8_t knot_dname_label_size(const knot_dname_t *dname, int i)
-{
-	assert(i >= 0);
-	assert(dname->size == 1 || i + 1 == dname->label_count
-	       || dname->labels[i + 1] - dname->labels[i] - 1
-	          == dname->name[dname->labels[i]]);
-	return dname->name[dname->labels[i]];
-}
-
-/*----------------------------------------------------------------------------*/
-
 knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, int size,
                                         const knot_dname_t *suffix)
 {
@@ -1074,8 +500,6 @@ dbg_dname_exec_verb(
 
 	dbg_dname_hex((char *)res->name, res->size);
 
-	knot_dname_find_labels(res, 1);
-
 	return res;
 }
 
@@ -1089,9 +513,6 @@ void knot_dname_free(knot_dname_t **dname)
 
 	free((*dname)->name);
 
-	free((*dname)->labels);
-
-
 //	slab_free(*dname);
 	free(*dname);
 	*dname = NULL;
@@ -1101,14 +522,14 @@ void knot_dname_free(knot_dname_t **dname)
 
 int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2)
 {
-	return knot_dname_cmp(d1, d2, 0);
+	return knot_dname_wire_cmp(d1, d2, NULL);
 }
 
 /*----------------------------------------------------------------------------*/
 
 int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2)
 {
-	return knot_dname_cmp(d1, d2, 1);
+	return knot_dname_wire_cmp(d1, d2, NULL);
 }
 
 int knot_dname_compare_non_canon(const knot_dname_t *d1, const knot_dname_t *d2)
@@ -1130,22 +551,11 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
 		return d1;
 	}
 
-	if (knot_dname_is_fqdn(d1)) {
-		return NULL;
-	}
-
 	// allocate new space
-	uint8_t *new_dname = (uint8_t *)malloc(d1->size + d2->size);
+	size_t new_size = d1->size + d2->size - 1; /* Trim the d1 \0 label */
+	uint8_t *new_dname = (uint8_t *)malloc(new_size);
 	CHECK_ALLOC_LOG(new_dname, NULL);
 
-	uint8_t *new_labels = (uint8_t *)malloc(d1->label_count
-	                                        + d2->label_count);
-	if (new_labels == NULL) {
-		ERR_ALLOC_FAILED;
-		free(new_dname);
-		return NULL;
-	}
-
 	dbg_dname_detail("1: copying %d bytes from adress %p to %p\n",
 	                 d1->size, d1->name, new_dname);
 
@@ -1154,24 +564,174 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
 	dbg_dname_detail("2: copying %d bytes from adress %p to %p\n",
 	                 d2->size, d2->name, new_dname + d1->size);
 
-	memcpy(new_dname + d1->size, d2->name, d2->size);
-
-	// update labels
-	memcpy(new_labels, d1->labels, d1->label_count);
-	for (int i = 0; i < d2->label_count; ++i) {
-		new_labels[d1->label_count + i] = d2->labels[i] + d1->size;
-	}
-
-	uint8_t *old_labels = d1->labels;
-	d1->labels = new_labels;
-	free(old_labels);
-	d1->label_count += d2->label_count;
+	/* Overwrite the d1 \0 label. */
+	memcpy(new_dname + d1->size - 1, d2->name, d2->size);
 
 	uint8_t *old_name = d1->name;
 	d1->name = new_dname;
 	free(old_name);
 
-	d1->size += d2->size;
+	d1->size = new_size;
 
 	return d1;
 }
+
+int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
+                          const uint8_t *pkt)
+{
+	if (name == NULL || name == endp)
+		return KNOT_EMALF;
+
+	int wire_len = 0; /* Keep terminal label in advance. */
+	int name_len = 0;
+	uint8_t is_compressed = 0;
+	uint8_t labels = 0;
+
+	while (*name != '\0') {
+
+		/* Check bounds (must have at least 2 octets remaining). */
+		if (name + 2 > endp)
+			return KNOT_ESPACE;
+
+		/* Reject more labels. */
+		if (labels == KNOT_MAX_DNAME_LABELS - 1)
+			return KNOT_EMALF;
+
+		if (knot_wire_is_pointer(name)) {
+			/* Check that the pointer points backwards
+			 * otherwise it could result in infinite loop
+			 */
+			if (pkt == NULL)
+				return KNOT_EINVAL;
+			uint16_t ptr = knot_wire_get_pointer(name);
+			if (ptr >= (name - pkt))
+				return KNOT_EMALF;
+
+			name = pkt + ptr; /* Hop to compressed label */
+			if (!is_compressed) { /* Measure compressed size only */
+				wire_len += sizeof(uint16_t);
+				is_compressed = 1;
+			}
+		} else {
+			/* Check label length (maximum 63 bytes allowed). */
+			if (*name > 63)
+				return KNOT_EMALF;
+			/* Check if there's enough space. */
+			int lblen = *name + 1;
+			if (name_len + lblen > KNOT_MAX_DNAME_LENGTH)
+				return KNOT_EMALF;
+			/* Update wire size only for noncompressed part. */
+			name_len += lblen;
+			if (!is_compressed)
+				wire_len += lblen;
+			/* Hop to next label. */
+			name += lblen;
+			++labels;
+		}
+
+		/* Check bounds (must have at least 1 octet). */
+		if (name + 1 > endp)
+			return KNOT_ESPACE;
+	}
+
+	if (!is_compressed) /* Terminal label. */
+		wire_len += 1;
+
+	return wire_len;
+}
+
+int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt)
+{
+	if (!name)
+		return KNOT_EINVAL;
+
+	/* Seek first real label occurence. */
+	while (knot_wire_is_pointer(name)) {
+		name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
+	}
+
+	int len = 1; /* Terminal label */
+	while (*name != '\0') {
+		len += *name + 1;
+		name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
+	}
+
+	return len;
+}
+
+int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt)
+{
+	uint8_t count = 0;
+	while (*name != '\0') {
+		++count;
+		name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
+		if (!name)
+			return KNOT_EMALF;
+	}
+	return count;
+}
+
+int knot_dname_align(const uint8_t **d1, uint8_t d1_labels,
+                     const uint8_t **d2, uint8_t d2_labels,
+                     uint8_t *wire)
+{
+	for (unsigned j = d1_labels; j < d2_labels; ++j)
+		*d2 = knot_wire_next_label(*d2, wire);
+
+	for (unsigned j = d2_labels; j < d1_labels; ++j)
+		*d1 = knot_wire_next_label(*d1, wire);
+
+	return (d1_labels < d2_labels) ? d1_labels : d2_labels;
+}
+
+int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
+                        const uint8_t *pkt)
+{
+	/*! \todo lf conversion should respect packet wire. */
+
+	/* Convert to lookup format. */
+	unsigned buflen = DNAME_LFT_MAXLEN;
+	uint8_t d1_lf[DNAME_LFT_MAXLEN], d2_lf[DNAME_LFT_MAXLEN];
+	if (dname_lf(d1_lf, d1, buflen) < 0 || dname_lf(d2_lf, d2, buflen) < 0)
+		return KNOT_EINVAL;
+
+	/* Compare common part. */
+	uint8_t common = d1_lf[0];
+	if (common > d2_lf[0])
+		common = d2_lf[0];
+	int ret = memcmp(d1_lf+1, d2_lf+1, common);
+	if (ret != 0)
+		return ret;
+
+	/* If they match, compare lengths. */
+	if (d1_lf[0] < d2_lf[0])
+		return -1;
+	if (d1_lf[0] > d2_lf[0])
+		return 1;
+	return 0;
+}
+
+int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen)
+{
+	if (src->size > maxlen)
+		return KNOT_ESPACE;
+	*dst = (uint8_t)src->size;
+	/* need to save last \x00 for root dname */
+	if (*dst > 1)
+		*dst -= 1;
+	*++dst = '\0';
+	uint8_t* l = src->name;
+	uint8_t lstack[DNAME_LFT_MAXLEN];
+	uint8_t *sp = lstack;
+	while(*l != 0) { /* build label stack */
+		*sp++ = (l - src->name);
+		l += 1 + *l;
+	}
+	while(sp != lstack) {          /* consume stack */
+		l = src->name + *--sp; /* fetch rightmost label */
+		memcpy(dst, l+1, *l);  /* write label */
+		dst += *l;
+		*dst++ = '\0';         /* label separator */
+	}
+	return KNOT_EOK;
+}
diff --git a/src/libknot/dname.h b/src/libknot/dname.h
index a872a4d87a61c9a27db052ce9a026ffe9e5832b9..71b17beacb990b01d941deeebbfb3846745faa3f 100644
--- a/src/libknot/dname.h
+++ b/src/libknot/dname.h
@@ -31,9 +31,6 @@
 #include <string.h>
 #include <stdio.h>
 
-struct knot_node;
-
-/*----------------------------------------------------------------------------*/
 /*!
  * \brief Structure for representing a domain name.
  *
@@ -43,28 +40,15 @@ struct knot_node;
  */
 struct knot_dname {
 	uint8_t *name;		/*!< Wire format of the domain name. */
-	uint8_t *labels;	/*!< Array of labels positions in name. */
-	struct knot_node *node;	/*!< Zone node the domain name belongs to. */
 	uint32_t count;		/*!< Reference counter. */
 	uint8_t size;		/*!< Length of the domain name. */
-	uint8_t label_count;	/*!< Number of labels. */
 };
 
 typedef struct knot_dname knot_dname_t;
 
-/*----------------------------------------------------------------------------*/
+#define DNAME_LFT_MAXLEN 255 /* maximum lookup format length */
 
-/*!
- * \brief Creates empty dname structure (no name, no owner node).
- *
- * \note Newly created dname is referenced, caller is responsible for releasing
- *       it after use.
- *
- * \return Newly allocated and initialized dname structure.
- *
- * \todo Possibly useless.
- */
-knot_dname_t *knot_dname_new();
+/*----------------------------------------------------------------------------*/
 
 /*!
  * \brief Creates a dname structure from domain name given in presentation
@@ -78,28 +62,11 @@ knot_dname_t *knot_dname_new();
  *
  * \param name Domain name in presentation format (labels separated by dots).
  * \param size Size of the domain name (count of characters with all dots).
- * \param node Zone node the domain name belongs to. Set to NULL if not
- *             applicable.
  *
  * \return Newly allocated and initialized dname structure representing the
  *         given domain name.
  */
-knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size,
-                                          struct knot_node *node);
-
-/*!
- * \brief Creates a dname structure from domain name possibly given in
- *        non-presentation format.
- *
- * Works the same as knot_dname_new_from_str but makes sure, that the name
- * is terminated with a dot.
- *
- * \see knot_dname_new_from_str
- *
- */
-knot_dname_t *knot_dname_new_from_nonfqdn_str(const char *name,
-                                              unsigned int size,
-                                              struct knot_node *node);
+knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size);
 
 /*!
  * \brief Creates a dname structure from domain name given in wire format.
@@ -111,8 +78,6 @@ knot_dname_t *knot_dname_new_from_nonfqdn_str(const char *name,
  *
  * \param name Domain name in wire format.
  * \param size Size of the domain name in octets.
- * \param node Zone node the domain name belongs to. Set to NULL if not
- *             applicable.
  *
  * \return Newly allocated and initialized dname structure representing the
  *         given domain name.
@@ -126,9 +91,7 @@ knot_dname_t *knot_dname_new_from_nonfqdn_str(const char *name,
  * \warning Actually, right now this function does not accept non-FQDN dnames.
  *          For some reason there is a check for this.
  */
-knot_dname_t *knot_dname_new_from_wire(const uint8_t *name,
-                                           unsigned int size,
-                                           struct knot_node *node);
+knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, unsigned int size);
 
 /*!
  * \brief Parse dname from wire.
@@ -136,16 +99,11 @@ knot_dname_t *knot_dname_new_from_wire(const uint8_t *name,
  * \param wire Message in wire format.
  * \param pos Position of the domain name on wire.
  * \param size Domain name length.
- * \param node Zone node the domain name belongs to. Set to NULL if not
- *             applicable.
- * \param dname Destination dname (will allocate new when NULL).
  *
  * \return parsed domain name or NULL.
  */
 knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
-                                         size_t *pos, size_t size,
-                                         struct knot_node *node,
-                                         knot_dname_t *dname);
+                                         size_t *pos, size_t size);
 
 /*!
  * \brief Duplicates the given domain name.
@@ -194,31 +152,6 @@ const uint8_t *knot_dname_name(const knot_dname_t *dname);
  */
 unsigned int knot_dname_size(const knot_dname_t *dname);
 
-/*!
- * \brief Returns size of a part of domain name.
- *
- * \param dname Domain name.
- * \param labels Count of labels to get the size of (counted from left).
- *
- * \return Size of first \a labels labels of \a dname, counted from left.
- */
-uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels);
-
-/*!
- * \brief Returns the zone node the domain name belongs to.
- *
- * \param dname Domain name to get the zone node of.
- *
- * \return Zone node the domain name belongs to or NULL if none.
- */
-const struct knot_node *knot_dname_node(const knot_dname_t *dname);
-
-struct knot_node *knot_dname_get_node(const knot_dname_t *dname);
-
-void knot_dname_update_node(knot_dname_t *dname);
-
-void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node);
-
 /*!
  * \brief Checks if the given domain name is a fully-qualified domain name.
  *
@@ -242,13 +175,6 @@ int knot_dname_is_fqdn(const knot_dname_t *dname);
  */
 knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
 
-/*!
- * \brief Removes leftmost label from \a dname.
- *
- * \param dname Domain name to remove the first label from.
- */
-void knot_dname_left_chop_no_copy(knot_dname_t *dname);
-
 /*!
  * \brief Checks if one domain name is a subdomain of other.
  *
@@ -281,28 +207,7 @@ int knot_dname_is_wildcard(const knot_dname_t *dname);
  * \return Number of labels common for the two domain names.
  */
 int knot_dname_matched_labels(const knot_dname_t *dname1,
-                                const knot_dname_t *dname2);
-
-/*!
- * \brief Returns the number of labels in the domain name.
- *
- * \param dname Domain name to get the label count of.
- *
- * \return Number of labels in \a dname.
- *
- * \todo Find out if this counts the root label also.
- */
-int knot_dname_label_count(const knot_dname_t *dname);
-
-/*!
- * \brief Returns the size of the requested label in the domain name.
- *
- * \param dname Domain name to get the label size from.
- * \param i Index of the label (0 is the leftmost label).
- *
- * \return Size of \a i-th label in \a dname (counted from left).
- */
-uint8_t knot_dname_label_size(const knot_dname_t *dname, int i);
+                              const knot_dname_t *dname2);
 
 /*!
  * \brief Replaces the suffix of given size in one domain name with other domain
@@ -397,6 +302,67 @@ static inline void knot_dname_release(knot_dname_t *dname) {
 	}
 }
 
+/* ! New nocopy based API.
+ * \note Temporary, subject to name changes.
+ */
+
+int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
+                          const uint8_t *pkt);
+
+/*! Calculate wire size.
+ *  \note Expects already checked name.
+ *  \note pkt Supply if name uses dname compression, NULL otherwise.
+ */
+int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt);
+
+/*! Calculate label count.
+ *  \note Expects already checked name.
+ */
+int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt);
+
+/*!
+ * \brief Align name and reference to a common number of suffix labels.
+ */
+int knot_dname_align(const uint8_t **d1, uint8_t d1_labels,
+                     const uint8_t **d2, uint8_t d2_labels,
+                     uint8_t *wire);
+
+/*!
+ * \brief Compare domain name by labels.
+ *
+ * \todo No case insensitivity, flags...
+ *
+ * \param d1 Domain name.
+ * \param d2 Domain name.
+ * \param pkt Packet wire related to names (or NULL).
+ * \return
+ */
+int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
+                        const uint8_t *pkt);
+
+/*!
+ * \brief Convert domain name from wire to lookup format.
+ *
+ * Formats names from rightmost label to the leftmost, separated by the lowest
+ * possible character (\x00). Sorting such formatted names also gives
+ * correct canonical order (for NSEC/NSEC3).
+ *
+ * Example:
+ * Name: lake.example.com. Wire: \x04lake\x07example\x03com\x00
+ * Lookup format com\x00example\x00lake\x00
+ *
+ * Maximum length of such a domain name is DNAME_LFT_MAXLEN characters.
+ *
+ * \param dst Memory to store converted name into.
+ * \param maxlen Maximum memory length.
+ * \param src Source domain name.
+ *
+ * \retval KNOT_EOK if successful
+ * \retval KNOT_ESPACE when not enough memory.
+ * \retval KNOT_EINVAL on invalid parameters
+ */
+int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen);
+
 #endif /* _KNOT_DNAME_H_ */
 
 /*! @} */
diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c
index 4a95240181d212ddd196250f90a6dbba55d37865..2c22663d48e3346271326f892d4d3b2fddeadd0d 100644
--- a/src/libknot/nameserver/name-server.c
+++ b/src/libknot/nameserver/name-server.c
@@ -432,8 +432,16 @@ dbg_ns_exec_verb(
 		const knot_dname_t *cname =
 			knot_rrset_rdata_cname_name(cname_rrset);
 		dbg_ns_detail("CNAME name from RDATA: %p\n", cname);
-		// change the node to the node of that name
-		*node = knot_dname_node(cname);
+
+		/* Attempt to find mentioned name in zone. */
+		rcu_read_lock();
+		const knot_zone_t *zone = resp->zone;
+		knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+		const knot_node_t *encloser = NULL, *prev = NULL;
+		knot_zone_contents_find_dname(contents, cname, node, &encloser, &prev);
+		if (*node == NULL && encloser && encloser->wildcard_child)
+			*node = encloser->wildcard_child;
+		rcu_read_unlock();
 		dbg_ns_detail("This name's node: %p\n", *node);
 
 		// save the new name which should be used for replacing wildcard
@@ -639,7 +647,7 @@ dbg_ns_exec_verb(
 static int ns_put_additional_for_rrset(knot_packet_t *resp,
                                        const knot_rrset_t *rrset)
 {
-	const knot_node_t *node = NULL;
+	const knot_node_t *node = NULL, *encloser = NULL, *prev = NULL;
 
 	int ret = 0;
 
@@ -656,15 +664,15 @@ dbg_ns_exec_detail(
 		free(name);
 );
 		assert(dname != NULL);
-		node = knot_dname_node(dname);
-
-		dbg_ns_detail("Node saved in RDATA dname: %p\n", node);
-		if (node != NULL && node->owner != dname) {
-			// the stored node should be the wildcard covering the
-			// name
-			dbg_ns_detail("Node is wildcard.\n");
-			assert(knot_dname_is_wildcard(knot_node_owner(node)));
-		}
+
+		/* Attempt to find mentioned name in zone. */
+		rcu_read_lock();
+		const knot_zone_t *zone = resp->zone;
+		knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+		knot_zone_contents_find_dname(contents, dname, &node, &encloser, &prev);
+		if (node == NULL && encloser && encloser->wildcard_child)
+			node = encloser->wildcard_child;
+		rcu_read_unlock();
 
 		knot_rrset_t *rrset_add;
 
@@ -933,8 +941,8 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone,
 static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser,
                                       const knot_dname_t *name)
 {
-	int ce_labels = knot_dname_label_count(closest_encloser);
-	int qname_labels = knot_dname_label_count(name);
+	int ce_labels = knot_dname_wire_labels(closest_encloser->name, NULL);
+	int qname_labels = knot_dname_wire_labels(name->name, NULL);
 
 	assert(ce_labels < qname_labels);
 
@@ -949,7 +957,9 @@ static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser,
 	}
 
 	for (int i = 0; i < (qname_labels - ce_labels - 1); ++i) {
-		knot_dname_left_chop_no_copy(next_closer);
+		knot_dname_t *old_next_closer = next_closer;
+		next_closer = knot_dname_left_chop(next_closer);
+		knot_dname_free(&old_next_closer);
 	}
 
 	return next_closer;
@@ -1163,7 +1173,7 @@ static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name)
 {
 	assert(name != NULL);
 
-	knot_dname_t *wildcard = knot_dname_new_from_str("*", 1, NULL);
+	knot_dname_t *wildcard = knot_dname_new_from_str("*", 1);
 	if (wildcard == NULL) {
 		return NULL;
 	}
@@ -2011,9 +2021,9 @@ static int ns_dname_is_too_long(const knot_rrset_t *rrset,
                                 const knot_dname_t *qname)
 {
 	// TODO: add function for getting DNAME target
-	if (knot_dname_label_count(qname)
-	        - knot_dname_label_count(knot_rrset_owner(rrset))
-	        + knot_dname_label_count(knot_rrset_rdata_dname_target(rrset))
+	if (knot_dname_wire_labels(qname->name, NULL)
+	        - knot_dname_wire_labels(knot_rrset_owner(rrset)->name, NULL)
+	        + knot_dname_wire_labels(knot_rrset_rdata_dname_target(rrset)->name, NULL)
 	        > KNOT_MAX_DNAME_LENGTH) {
 		return 1;
 	} else {
@@ -2605,7 +2615,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig)
 
 	// Clean the response structure
 	dbg_ns_verb("Clearing response structure..\n");
-	knot_response_clear(xfr->response, 0);
+	knot_response_clear(xfr->response);
 
 	// increment the packet number
 	++xfr->packet_nr;
@@ -2996,12 +3006,12 @@ static int ns_ixfr(knot_ns_xfr_t *xfr)
 /*----------------------------------------------------------------------------*/
 
 static int knot_ns_prepare_response(knot_packet_t *query, knot_packet_t **resp,
-                                    size_t max_size, int copy_question)
+                                    size_t max_size)
 {
 	assert(max_size >= 500);
 
 	// initialize response packet structure
-	*resp = knot_packet_new_mm(KNOT_PACKET_PREALLOC_RESPONSE, &query->mm);
+	*resp = knot_packet_new_mm(&query->mm);
 	if (*resp == NULL) {
 		dbg_ns("Failed to create packet structure.\n");
 		return KNOT_ENOMEM;
@@ -3015,7 +3025,7 @@ static int knot_ns_prepare_response(knot_packet_t *query, knot_packet_t **resp,
 		return ret;
 	}
 
-	ret = knot_response_init_from_query(*resp, query, copy_question);
+	ret = knot_response_init_from_query(*resp, query);
 
 	if (ret != KNOT_EOK) {
 		dbg_ns("Failed to init response structure.\n");
@@ -3056,7 +3066,7 @@ knot_nameserver_t *knot_ns_create()
 	}
 
 	// prepare empty response with SERVFAIL error
-	knot_packet_t *err = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+	knot_packet_t *err = knot_packet_new();
 	if (err == NULL) {
 		ERR_ALLOC_FAILED;
 		free(ns);
@@ -3350,8 +3360,7 @@ int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver,
 	if (query->parsed > KNOT_WIRE_HEADER_SIZE
 	                    + KNOT_WIRE_QUESTION_MIN_SIZE) {
 		// in this case the whole question was parsed, append it
-		size_t question_size = 4 + knot_dname_size(
-		                        knot_packet_qname(query));
+		size_t question_size = knot_packet_question_size(query);
 
 		if (max_size > KNOT_WIRE_HEADER_SIZE + question_size) {
 			/*
@@ -3488,7 +3497,7 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver,
 		resp_max_size = MAX_UDP_PAYLOAD;
 	}
 
-	ret = knot_ns_prepare_response(query, resp, resp_max_size, 1);
+	ret = knot_ns_prepare_response(query, resp, resp_max_size);
 	if (ret != KNOT_EOK) {
 		return KNOT_ERROR;
 	}
@@ -3535,6 +3544,10 @@ dbg_ns_exec_verb(
 	knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db);
 	*zone = ns_get_zone_for_qname(zonedb, qname, qtype);
 
+	/* Assign zone to packets. */
+	query->zone = *zone;
+	(*resp)->zone = *zone;
+
 	return KNOT_EOK;
 }
 
@@ -3627,11 +3640,15 @@ int knot_ns_prep_update_response(knot_nameserver_t *nameserver,
 		resp_max_size = MAX_UDP_PAYLOAD;
 	}
 
-	ret = knot_ns_prepare_response(query, resp, resp_max_size, 0);
+	ret = knot_ns_prepare_response(query, resp, resp_max_size);
 	if (ret != KNOT_EOK) {
 		return KNOT_ERROR;
 	}
 
+	/* Trim question for DDNS answer. */
+	knot_packet_set_size(query, KNOT_WIRE_HEADER_SIZE);
+	knot_wire_set_qdcount(query->wireformat, 0);
+
 	dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n",
 	            query->parsed, query->size);
 	dbg_ns_detail("Opt RR: version: %d, payload: %d\n",
@@ -3821,7 +3838,7 @@ dbg_ns_exec(
 int knot_ns_init_xfr_resp(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
 {
 	int ret = KNOT_EOK;
-	knot_packet_t *resp = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+	knot_packet_t *resp = knot_packet_new_mm(&xfr->query->mm);
 	if (resp == NULL) {
 		dbg_ns("Failed to create packet structure.\n");
 		/*! \todo xfr->wire is not NULL, will fail on assert! */
@@ -3836,7 +3853,7 @@ int knot_ns_init_xfr_resp(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
 	resp->wireformat = xfr->wire;
 	resp->max_size = xfr->wire_size;
 
-	ret = knot_response_init_from_query(resp, xfr->query, 1);
+	ret = knot_response_init_from_query(resp, xfr->query);
 
 	if (ret != KNOT_EOK) {
 		dbg_ns("Failed to init response structure.\n");
diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c
index f963b9d1861915f25b5ec55854ec9dde1b95f15b..6e1cbbb9801961e727aef7849e9731d51bba4b32 100644
--- a/src/libknot/packet/packet.c
+++ b/src/libknot/packet/packet.c
@@ -25,267 +25,33 @@
 #include "util/wire.h"
 #include "tsig.h"
 
-/*----------------------------------------------------------------------------*/
-
-#define DEFAULT_RRCOUNT_QUERY(type) DEFAULT_##type##COUNT_QUERY
-#define DEFAULT_RRCOUNT(type) DEFAULT_##type##COUNT
-
-#define DEFAULT_RRSET_COUNT(type, packet) \
-	((packet->prealloc_type == KNOT_PACKET_PREALLOC_NONE)  \
-		? 0  \
-		: (packet->prealloc_type == KNOT_PACKET_PREALLOC_QUERY)  \
-			? DEFAULT_##type##_QUERY  \
-			: DEFAULT_##type)
-
 /*----------------------------------------------------------------------------*/
 /* Non-API functions                                                          */
 /*----------------------------------------------------------------------------*/
-/*!
- * \brief Sets all the pointers in the packet structure to the respective
- *        parts of the pre-allocated space.
- */
-static void knot_packet_init_pointers_response(knot_packet_t *pkt)
-{
-	dbg_packet_detail("Packet pointer: %p\n", pkt);
-
-	char *pos = (char *)pkt + PREALLOC_PACKET;
-
-	// put QNAME directly after the structure
-	pkt->question.qname = (knot_dname_t *)pos;
-	pos += PREALLOC_QNAME_DNAME;
-
-	dbg_packet_detail("QNAME: %p\n", pkt->question.qname);
-
-	pkt->question.qname->name = (uint8_t *)pos;
-	pos += PREALLOC_QNAME_NAME;
-	pkt->question.qname->labels = (uint8_t *)pos;
-	pos += PREALLOC_QNAME_LABELS;
-
-	// then answer, authority and additional sections
-	if (DEFAULT_ANCOUNT == 0) {
-		pkt->answer = NULL;
-	} else {
-		pkt->answer = (const knot_rrset_t **)pos;
-		pos += DEFAULT_ANCOUNT * sizeof(const knot_rrset_t *);
-	}
-
-	if (DEFAULT_NSCOUNT == 0) {
-		pkt->authority = NULL;
-	} else {
-		pkt->authority = (const knot_rrset_t **)pos;
-		pos += DEFAULT_NSCOUNT * sizeof(const knot_rrset_t *);
-	}
-
-	if (DEFAULT_ARCOUNT == 0) {
-		pkt->additional = NULL;
-	} else {
-		pkt->additional = (const knot_rrset_t **)pos;
-		pos += DEFAULT_ARCOUNT * sizeof(const knot_rrset_t *);
-	}
-
-	dbg_packet_detail("Answer section: %p\n", pkt->answer);
-	dbg_packet_detail("Authority section: %p\n", pkt->authority);
-	dbg_packet_detail("Additional section: %p\n", pkt->additional);
-
-	pkt->max_an_rrsets = DEFAULT_ANCOUNT;
-	pkt->max_ns_rrsets = DEFAULT_NSCOUNT;
-	pkt->max_ar_rrsets = DEFAULT_ARCOUNT;
-
-	// wildcard nodes and SNAMEs associated with them
-	pkt->wildcard_nodes.nodes = (const knot_node_t **)pos;
-	pos += DEFAULT_WILDCARD_NODES * sizeof(const knot_node_t *);
-	pkt->wildcard_nodes.snames = (const knot_dname_t **)pos;
-	pos += DEFAULT_WILDCARD_NODES * sizeof(knot_dname_t *);
-
-	dbg_packet_detail("Wildcard nodes: %p\n", pkt->wildcard_nodes.nodes);
-	dbg_packet_detail("Wildcard SNAMEs: %p\n", pkt->wildcard_nodes.snames);
-
-	pkt->wildcard_nodes.default_count = DEFAULT_WILDCARD_NODES;
-	pkt->wildcard_nodes.max = DEFAULT_WILDCARD_NODES;
-
-	pkt->tmp_rrsets = (const knot_rrset_t **)pos;
-	pos += DEFAULT_TMP_RRSETS * sizeof(const knot_rrset_t *);
-
-	dbg_packet_detail("Tmp rrsets: %p\n", pkt->tmp_rrsets);
-
-	pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS;
-
-	assert((char *)pos == (char *)pkt + PREALLOC_RESPONSE);
-}
 
 /*----------------------------------------------------------------------------*/
-/*!
- * \brief Sets all the pointers in the packet structure to the respective
- *        parts of the pre-allocated space.
- */
-static void knot_packet_init_pointers_query(knot_packet_t *pkt)
-{
-	dbg_packet_detail("Packet pointer: %p\n", pkt);
-
-	char *pos = (char *)pkt + PREALLOC_PACKET;
-
-	// put QNAME directly after the structure
-	pkt->question.qname = (knot_dname_t *)pos;
-	pos += PREALLOC_QNAME_DNAME;
-
-	dbg_packet_detail("QNAME: %p (%zu after start of packet)\n",
-	                  pkt->question.qname,
-	                  (void *)pkt->question.qname - (void *)pkt);
-
-	pkt->question.qname->name = (uint8_t *)pos;
-	pos += PREALLOC_QNAME_NAME;
-	pkt->question.qname->labels = (uint8_t *)pos;
-	pos += PREALLOC_QNAME_LABELS;
-
-
-	// then answer, authority and additional sections
-	if (DEFAULT_ANCOUNT_QUERY == 0) {
-		pkt->answer = NULL;
-	} else {
-		pkt->answer = (const knot_rrset_t **)pos;
-		pos += DEFAULT_ANCOUNT_QUERY * sizeof(const knot_rrset_t *);
-	}
-
-	if (DEFAULT_NSCOUNT_QUERY == 0) {
-		pkt->authority = NULL;
-	} else {
-		pkt->authority = (const knot_rrset_t **)pos;
-		pos += DEFAULT_NSCOUNT_QUERY * sizeof(const knot_rrset_t *);
-	}
-
-	if (DEFAULT_ARCOUNT_QUERY == 0) {
-		pkt->additional = NULL;
-	} else {
-		pkt->additional = (const knot_rrset_t **)pos;
-		pos += DEFAULT_ARCOUNT_QUERY * sizeof(const knot_rrset_t *);
-	}
-
-	dbg_packet_detail("Answer section: %p\n", pkt->answer);
-	dbg_packet_detail("Authority section: %p\n", pkt->authority);
-	dbg_packet_detail("Additional section: %p\n", pkt->additional);
-
-	pkt->max_an_rrsets = DEFAULT_ANCOUNT_QUERY;
-	pkt->max_ns_rrsets = DEFAULT_NSCOUNT_QUERY;
-	pkt->max_ar_rrsets = DEFAULT_ARCOUNT_QUERY;
-
-	pkt->tmp_rrsets = (const knot_rrset_t **)pos;
-	pos += DEFAULT_TMP_RRSETS_QUERY * sizeof(const knot_rrset_t *);
-
-	dbg_packet_detail("Tmp rrsets: %p\n", pkt->tmp_rrsets);
-
-	pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS_QUERY;
-
-	dbg_packet_detail("Allocated total: %u\n", PREALLOC_QUERY);
-
-	assert(pos == (char *)pkt + PREALLOC_QUERY);
-}
 
 /*----------------------------------------------------------------------------*/
 /*!
- * \brief Parses DNS header from the wire format.
- *
- * \note This function also adjusts the position (\a pos) and size of remaining
- *       bytes in the wire format (\a remaining) according to what was parsed
- *       (though it actually always parses the 12 bytes of the header).
- *
- * \param[in,out] pos Wire format to parse the header from.
- * \param[in,out] remaining Remaining size of the wire format.
- * \param[out] header Header structure to fill in.
- *
- * \retval KNOT_EOK
- * \retval KNOT_EFEWDATA
+ * \brief Processes DNS Question entry from the wire format.
  */
-static int knot_packet_parse_header(const uint8_t *wire, size_t *pos,
-                                      size_t size, knot_header_t *header)
+static int knot_packet_parse_question(knot_packet_t *pkt)
 {
-	assert(wire != NULL);
-	assert(pos != NULL);
-	assert(header != NULL);
-
-	if (size - *pos < KNOT_WIRE_HEADER_SIZE) {
-		dbg_packet("Not enough data to parse header.\n");
-		return KNOT_EFEWDATA;
-	}
-
-	header->id = knot_wire_get_id(wire);
-	header->flags1 = knot_wire_get_flags1(wire);
-	header->flags2 = knot_wire_get_flags2(wire);
+	assert(pkt != NULL);
 
-	header->qdcount = knot_wire_get_qdcount(wire);
-	header->ancount = knot_wire_get_ancount(wire);
-	header->nscount = knot_wire_get_nscount(wire);
-	header->arcount = knot_wire_get_arcount(wire);
+	dbg_packet("Parsing Question starting on position %zu.\n", pkt->parsed);
 
-	*pos += KNOT_WIRE_HEADER_SIZE;
-
-	return KNOT_EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Parses DNS Question entry from the wire format.
- *
- * \note This function also adjusts the position (\a pos) and size of remaining
- *       bytes in the wire format (\a remaining) according to what was parsed.
- *
- * \param[in,out] pos Wire format to parse the Question from.
- * \param[in,out] remaining Remaining size of the wire format.
- * \param[out] question DNS Question structure to be filled.
- *
- * \retval KNOT_EOK
- * \retval KNOT_EFEWDATA
- * \retval KNOT_ENOMEM
- */
-static int knot_packet_parse_question(const uint8_t *wire, size_t *pos,
-                                        size_t size,
-                                        knot_question_t *question, int alloc)
-{
-	assert(pos != NULL);
-	assert(wire != NULL);
-	assert(question != NULL);
-
-	if (size - *pos < KNOT_WIRE_QUESTION_MIN_SIZE) {
-		dbg_packet("Not enough data to parse question.\n");
-		return KNOT_EFEWDATA;  // malformed
-	}
-
-	dbg_packet("Parsing Question starting on position %zu.\n", *pos);
-
-	// domain name must end with 0, so just search for 0
-	int i = *pos;
-	while (i < size && wire[i] != 0) {
-		++i;
-	}
-
-	if (size - i - 1 < 4) {
-		dbg_packet("Not enough data to parse question.\n");
-		return KNOT_EFEWDATA;  // no 0 found or not enough data left
-	}
+	/* Process question. */
+	int len = knot_dname_wire_check(pkt->wireformat + pkt->parsed,
+	                                pkt->wireformat + pkt->size,
+	                                pkt->wireformat);
+	if (len <= 0)
+		return KNOT_EMALF;
 
-	dbg_packet_verb("Parsing dname starting on position %zu and "
-	                      "%zu bytes long.\n", *pos, i - *pos + 1);
-	dbg_packet_verb("Alloc: %d\n", alloc);
-	if (alloc) {
-		question->qname = knot_dname_parse_from_wire(wire, pos,
-		                                             i + 1,
-		                                             NULL, NULL);
-		if (question->qname == NULL) {
-			return KNOT_ENOMEM;
-		}
-		knot_dname_to_lower(question->qname);
-	} else {
-		assert(question->qname != NULL); /* When alloc=0, must be set. */
-		void *parsed = knot_dname_parse_from_wire(wire, pos,
-		                                     i + 1,
-	                                             NULL, question->qname);
-		if (!parsed) {
-			return KNOT_EMALF;
-		}
-		knot_dname_to_lower(question->qname);
-	}
-	question->qtype = knot_wire_read_u16(wire + i + 1);
-	question->qclass = knot_wire_read_u16(wire + i + 3);
-	*pos += 4;
+	/*! \todo Question case should be preserved. */
+	/* knot_dname_to_lower(question->qname); */
+	pkt->parsed += len + 2 * sizeof(uint16_t); /* Class + Type */
+	pkt->qname_size = len;
 
 	return KNOT_EOK;
 }
@@ -296,37 +62,24 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos,
  *
  * \param rrsets Space for RRSets.
  * \param max_count Size of the space available for the RRSets.
- * \param default_max_count Size of the space pre-allocated for the RRSets when
- *        the response structure was initialized.
- * \param step How much the space should be increased.
  *
  * \retval KNOT_EOK
  * \retval KNOT_ENOMEM
  */
-static int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets,
-                                        short *max_count,
-                                        short default_max_count, short step)
+int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets,
+                                      short *max_count,
+                                      mm_ctx_t *mm)
 {
-	dbg_packet_verb("Max count: %d, default max count: %d\n",
-	       *max_count, default_max_count);
-	int free_old = (*max_count) != default_max_count;
-	const knot_rrset_t **old = *rrsets;
-
-	short new_max_count = *max_count + step;
-	const knot_rrset_t **new_rrsets = (const knot_rrset_t **)malloc(
+	short new_max_count = *max_count + RRSET_ALLOC_STEP;
+	const knot_rrset_t **new_rrsets = mm->alloc(mm->ctx,
 		new_max_count * sizeof(knot_rrset_t *));
 	CHECK_ALLOC_LOG(new_rrsets, KNOT_ENOMEM);
-
-	memset(new_rrsets, 0, new_max_count * sizeof(knot_rrset_t *));
 	memcpy(new_rrsets, *rrsets, (*max_count) * sizeof(knot_rrset_t *));
 
+	mm->free(*rrsets);
 	*rrsets = new_rrsets;
 	*max_count = new_max_count;
 
-	if (free_old) {
-		free(old);
-	}
-
 	return KNOT_EOK;
 }
 
@@ -410,8 +163,7 @@ static knot_rrset_t *knot_packet_parse_rr(const uint8_t *wire, size_t *pos,
 	dbg_packet("Parsing RR from position: %zu, total size: %zu\n",
 	           *pos, size);
 
-	knot_dname_t *owner = knot_dname_parse_from_wire(wire, pos, size,
-	                                                     NULL, NULL);
+	knot_dname_t *owner = knot_dname_parse_from_wire(wire, pos, size);
 	dbg_packet_detail("Created owner: %p, actual position: %zu\n", owner,
 	                  *pos);
 	if (owner == NULL) {
@@ -490,8 +242,7 @@ static int knot_packet_add_rrset(knot_rrset_t *rrset,
                                  const knot_rrset_t ***rrsets,
                                  short *rrset_count,
                                  short *max_rrsets,
-                                 short default_rrsets,
-                                 const knot_packet_t *packet,
+                                 knot_packet_t *packet,
                                  knot_packet_flag_t flags)
 {
 	assert(rrset != NULL);
@@ -507,8 +258,8 @@ dbg_packet_exec_verb(
 );
 
 	if (*rrset_count == *max_rrsets
-	    && knot_packet_realloc_rrsets(rrsets, max_rrsets, default_rrsets,
-	                                    STEP_ANCOUNT) != KNOT_EOK) {
+	    && knot_packet_realloc_rrsets(rrsets, max_rrsets,
+	                                  &packet->mm) != KNOT_EOK) {
 		return KNOT_ENOMEM;
 	}
 
@@ -557,7 +308,6 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
                                  uint16_t *parsed_rrs,
                                  const knot_rrset_t ***rrsets,
                                  short *rrset_count, short *max_rrsets,
-                                 short default_rrsets,
                                  knot_packet_t *packet,
                                  knot_packet_flag_t flags)
 {
@@ -590,7 +340,7 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
 		++(*parsed_rrs);
 
 		err = knot_packet_add_rrset(rrset, rrsets, rrset_count,
-		                            max_rrsets, default_rrsets, packet, flags);
+		                            max_rrsets, packet, flags);
 		if (err < 0) {
 			break;
 		} else if (err == 1) {	// merged, shallow data copy
@@ -642,29 +392,13 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
 static void knot_packet_free_allocated_space(knot_packet_t *pkt)
 {
 	dbg_packet_verb("Freeing additional space in packet.\n");
-	if (pkt->prealloc_type == KNOT_PACKET_PREALLOC_NONE) {
-		dbg_packet_detail("Freeing QNAME.\n");
-		knot_dname_release(pkt->question.qname);
-	}
-
-	if (pkt->max_an_rrsets > DEFAULT_RRSET_COUNT(ANCOUNT, pkt)) {
-		free(pkt->answer);
-	}
-	if (pkt->max_ns_rrsets > DEFAULT_RRSET_COUNT(NSCOUNT, pkt)) {
-		free(pkt->authority);
-	}
-	if (pkt->max_ar_rrsets > DEFAULT_RRSET_COUNT(ARCOUNT, pkt)) {
-		free(pkt->additional);
-	}
-
-	if (pkt->wildcard_nodes.max > pkt->wildcard_nodes.default_count) {
-		free(pkt->wildcard_nodes.nodes);
-		free(pkt->wildcard_nodes.snames);
-	}
 
-	if (pkt->tmp_rrsets_max > DEFAULT_RRSET_COUNT(TMP_RRSETS, pkt)) {
-		free(pkt->tmp_rrsets);
-	}
+	pkt->mm.free(pkt->answer);
+	pkt->mm.free(pkt->authority);
+	pkt->mm.free(pkt->additional);
+	pkt->mm.free(pkt->wildcard_nodes.nodes);
+	pkt->mm.free(pkt->wildcard_nodes.snames);
+	pkt->mm.free(pkt->tmp_rrsets);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -684,9 +418,9 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, size_t *pos,
 
 	dbg_packet_verb("Parsing Answer RRs...\n");
 	if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
-	   packet->size, packet->header.ancount, &packet->parsed_an,
+	   packet->size, knot_wire_get_ancount(packet->wireformat), &packet->parsed_an,
 	   &packet->answer, &packet->an_rrsets, &packet->max_an_rrsets,
-	   DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet, flags)) != KNOT_EOK) {
+	                                 packet, flags)) != KNOT_EOK) {
 		return err;
 	}
 
@@ -697,9 +431,9 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, size_t *pos,
 
 	dbg_packet_verb("Parsing Authority RRs...\n");
 	if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
-	   packet->size, packet->header.nscount, &packet->parsed_ns,
+	   packet->size, knot_wire_get_nscount(packet->wireformat), &packet->parsed_ns,
 	   &packet->authority, &packet->ns_rrsets, &packet->max_ns_rrsets,
-	   DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet, flags)) != KNOT_EOK) {
+	   packet, flags)) != KNOT_EOK) {
 		return err;
 	}
 
@@ -710,9 +444,9 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, size_t *pos,
 
 	dbg_packet_verb("Parsing Additional RRs...\n");
 	if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
-	   packet->size, packet->header.arcount, &packet->parsed_ar,
+	   packet->size, knot_wire_get_arcount(packet->wireformat), &packet->parsed_ar,
 	   &packet->additional, &packet->ar_rrsets, &packet->max_ar_rrsets,
-	   DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet, flags)) != KNOT_EOK) {
+	   packet, flags)) != KNOT_EOK) {
 		return err;
 	}
 
@@ -755,42 +489,21 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, size_t *pos,
 /* API functions                                                              */
 /*----------------------------------------------------------------------------*/
 
-knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc)
+knot_packet_t *knot_packet_new()
 {
 	mm_ctx_t mm;
 	mm_ctx_init(&mm);
-	return knot_packet_new_mm(prealloc, &mm);
+	return knot_packet_new_mm(&mm);
 }
 
-knot_packet_t *knot_packet_new_mm(knot_packet_prealloc_type_t prealloc, mm_ctx_t *mm)
+knot_packet_t *knot_packet_new_mm(mm_ctx_t *mm)
 {
 	knot_packet_t *pkt = NULL;
-	void (*init_pointers)(knot_packet_t *pkt) = NULL;
-	size_t size = 0;
-
-	switch (prealloc) {
-	case KNOT_PACKET_PREALLOC_NONE:
-		size = sizeof(knot_packet_t);
-		break;
-	case KNOT_PACKET_PREALLOC_QUERY:
-		size = PREALLOC_QUERY;
-		init_pointers = knot_packet_init_pointers_query;
-		break;
-	case KNOT_PACKET_PREALLOC_RESPONSE:
-		size = PREALLOC_RESPONSE;
-		init_pointers = knot_packet_init_pointers_response;
-		break;
-	}
-
-	pkt = (knot_packet_t *)mm->alloc(mm->ctx, size);
+
+	pkt = (knot_packet_t *)mm->alloc(mm->ctx, sizeof(knot_packet_t));
 	CHECK_ALLOC_LOG(pkt, NULL);
-	memset(pkt, 0, size);
+	memset(pkt, 0, sizeof(knot_packet_t));
 	memcpy(&pkt->mm, mm, sizeof(mm_ctx_t));
-	if (init_pointers != NULL) {
-		init_pointers(pkt);
-	}
-
-	pkt->prealloc_type = prealloc;
 
 	// set EDNS version to not supported
 	pkt->opt_rr.version = EDNS_NOT_SUPPORTED;
@@ -804,52 +517,27 @@ int knot_packet_parse_from_wire(knot_packet_t *packet,
                                   const uint8_t *wireformat, size_t size,
                                   int question_only, knot_packet_flag_t flags)
 {
-	if (packet == NULL || wireformat == NULL) {
+	if (packet == NULL || wireformat == NULL || size < KNOT_WIRE_HEADER_SIZE)
 		return KNOT_EINVAL;
-	}
 
-	int err;
 
-	// save the wireformat in the packet
-	// TODO: can we just save the pointer, or we have to copy the data??
+	int err = KNOT_EOK;
+
 	assert(packet->wireformat == NULL);
 	packet->wireformat = (uint8_t*)wireformat;
 	packet->size = size;
-	packet->free_wireformat = 0;
-
-	if (size < 2) {
-		return KNOT_EMALF;
-	}
-
-	size_t pos = 0;
-
-	dbg_packet_verb("Parsing wire format of packet (size %zu).\nHeader\n",
-	                size);
-	if ((err = knot_packet_parse_header(wireformat, &pos, size,
-	                                      &packet->header)) != KNOT_EOK) {
-		return err;
-	}
-
-	packet->parsed = pos;
-
-	dbg_packet_verb("Question (prealloc type: %d)...\n",
-	                packet->prealloc_type);
+	packet->flags &= ~KNOT_PF_FREE_WIRE;
+	packet->parsed = KNOT_WIRE_HEADER_SIZE;
 
-	if (packet->header.qdcount > 1) {
+	uint16_t qdcount = knot_wire_get_qdcount(packet->wireformat);
+	if (qdcount == 1) {
+		if ((err = knot_packet_parse_question(packet)) != KNOT_EOK)
+			return err;
+	} else if (qdcount > 1) {
 		dbg_packet("QDCOUNT larger than 1, FORMERR.\n");
 		return KNOT_EMALF;
 	}
 
-	if (packet->header.qdcount == 1) {
-		if ((err = knot_packet_parse_question(wireformat, &pos, size,
-		             &packet->question, packet->prealloc_type
-		                                == KNOT_PACKET_PREALLOC_NONE)
-		     ) != KNOT_EOK) {
-			return err;
-		}
-		packet->parsed = pos;
-	}
-
 dbg_packet_exec_detail(
 	knot_packet_dump(packet);
 );
@@ -876,9 +564,9 @@ int knot_packet_parse_rest(knot_packet_t *packet, knot_packet_flag_t flags)
 		return KNOT_EINVAL;
 	}
 
-	if (packet->header.ancount == packet->parsed_an
-	    && packet->header.nscount == packet->parsed_ns
-	    && packet->header.arcount == packet->parsed_ar
+	if (knot_wire_get_ancount(packet->wireformat) == packet->parsed_an
+	    && knot_wire_get_nscount(packet->wireformat) == packet->parsed_ns
+	    && knot_wire_get_arcount(packet->wireformat) == packet->parsed_ar
 	    && packet->parsed == packet->size) {
 		return KNOT_EOK;
 	}
@@ -906,8 +594,8 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
 	*rr = NULL;
 
 	if (packet->parsed >= packet->size) {
-		assert(packet->an_rrsets <= packet->header.ancount);
-		if (packet->parsed_an != packet->header.ancount) {
+		assert(packet->an_rrsets <= knot_wire_get_ancount(packet->wireformat));
+		if (packet->parsed_an != knot_wire_get_ancount(packet->wireformat)) {
 			dbg_packet("Parsed less RRs than expected.\n");
 			return KNOT_EMALF;
 		} else {
@@ -916,7 +604,7 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
 		}
 	}
 
-	if (packet->parsed_an == packet->header.ancount) {
+	if (packet->parsed_an == knot_wire_get_ancount(packet->wireformat)) {
 		assert(packet->parsed < packet->size);
 		//dbg_packet("Trailing garbage, ignoring...\n");
 		// there may be other data in the packet
@@ -957,8 +645,8 @@ int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
 	*rr = NULL;
 
 	if (packet->parsed >= packet->size) {
-		assert(packet->ar_rrsets <= packet->header.arcount);
-		if (packet->parsed_ar != packet->header.arcount) {
+		assert(packet->ar_rrsets <= knot_wire_get_arcount(packet->wireformat));
+		if (packet->parsed_ar != knot_wire_get_arcount(packet->wireformat)) {
 			dbg_packet("Parsed less RRs than expected.\n");
 			return KNOT_EMALF;
 		} else {
@@ -967,7 +655,7 @@ int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
 		}
 	}
 
-	if (packet->parsed_ar == packet->header.arcount) {
+	if (packet->parsed_ar == knot_wire_get_arcount(packet->wireformat)) {
 		assert(packet->parsed < packet->size);
 		dbg_packet_verb("Trailing garbage, treating as malformed...\n");
 		return KNOT_EMALF;
@@ -1011,8 +699,7 @@ size_t knot_packet_max_size(const knot_packet_t *packet)
 
 size_t knot_packet_question_size(const knot_packet_t *packet)
 {
-	return (KNOT_WIRE_HEADER_SIZE + 4
-	        + knot_dname_size(packet->question.qname));
+	return KNOT_WIRE_HEADER_SIZE + packet->qname_size + 2 * sizeof(uint16_t);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1024,6 +711,16 @@ size_t knot_packet_parsed(const knot_packet_t *packet)
 
 /*----------------------------------------------------------------------------*/
 
+int knot_packet_set_size(knot_packet_t *packet, int size)
+{
+	if (packet == NULL || size > packet->max_size)
+		return KNOT_EINVAL;
+
+	return packet->size = size;
+}
+
+/*----------------------------------------------------------------------------*/
+
 int knot_packet_set_max_size(knot_packet_t *packet, int max_size)
 {
 	if (packet == NULL || max_size <= 0) {
@@ -1038,22 +735,17 @@ int knot_packet_set_max_size(knot_packet_t *packet, int max_size)
 			return KNOT_ENOMEM;
 		}
 
-		uint8_t *wire_old = packet->wireformat;
-
-		memcpy(wire_new, packet->wireformat, packet->max_size);
-		packet->wireformat = wire_new;
-
-		if (packet->max_size > 0 && packet->free_wireformat) {
-			if (packet->mm.free)
-				packet->mm.free(wire_old);
+		if (packet->max_size > 0) {
+			memcpy(wire_new, packet->wireformat, packet->max_size);
+			if (packet->flags & KNOT_PF_FREE_WIRE)
+				packet->mm.free(packet->wireformat);
 		}
 
-		packet->free_wireformat = 1;
+		packet->wireformat = wire_new;
+		packet->max_size = max_size;
+		packet->flags |= KNOT_PF_FREE_WIRE;
 	}
 
-	// set max size
-	packet->max_size = max_size;
-
 	return KNOT_EOK;
 }
 
@@ -1062,18 +754,7 @@ int knot_packet_set_max_size(knot_packet_t *packet, int max_size)
 uint16_t knot_packet_id(const knot_packet_t *packet)
 {
 	assert(packet != NULL);
-	return packet->header.id;
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_packet_set_id(knot_packet_t *packet, uint16_t id)
-{
-	if (packet == NULL) {
-		return;
-	}
-
-	packet->header.id = id;
+	return knot_wire_get_id(packet->wireformat);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1084,7 +765,7 @@ void knot_packet_set_random_id(knot_packet_t *packet)
 		return;
 	}
 
-	packet->header.id = knot_random_id();
+	knot_wire_set_id(packet->wireformat, knot_random_id());
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1092,15 +773,8 @@ void knot_packet_set_random_id(knot_packet_t *packet)
 uint8_t knot_packet_opcode(const knot_packet_t *packet)
 {
 	assert(packet != NULL);
-	return knot_wire_flags_get_opcode(packet->header.flags1);
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_question_t *knot_packet_question(knot_packet_t *packet)
-{
-	if (packet == NULL) return NULL;
-	return &packet->question;
+	uint8_t flags = knot_wire_get_flags1(packet->wireformat);
+	return knot_wire_flags_get_opcode(flags);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1111,7 +785,11 @@ const knot_dname_t *knot_packet_qname(const knot_packet_t *packet)
 		return NULL;
 	}
 
-	return packet->question.qname;
+	/*! \todo This will leak until dname API is finished, it's just placeholder
+	 *        to make it compile and work.
+	 */
+	const uint8_t *qname = packet->wireformat + KNOT_WIRE_HEADER_SIZE;
+	return knot_dname_new_from_wire(qname, knot_dname_wire_size(qname, NULL));
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1119,15 +797,8 @@ const knot_dname_t *knot_packet_qname(const knot_packet_t *packet)
 uint16_t knot_packet_qtype(const knot_packet_t *packet)
 {
 	assert(packet != NULL);
-	return packet->question.qtype;
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_packet_set_qtype(knot_packet_t *packet, uint16_t qtype)
-{
-	assert(packet != NULL);
-	packet->question.qtype = qtype;
+	unsigned off = KNOT_WIRE_HEADER_SIZE + packet->qname_size;
+	return knot_wire_read_u16(packet->wireformat + off);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1135,7 +806,8 @@ void knot_packet_set_qtype(knot_packet_t *packet, uint16_t qtype)
 uint16_t knot_packet_qclass(const knot_packet_t *packet)
 {
 	assert(packet != NULL);
-	return packet->question.qclass;
+	unsigned off = KNOT_WIRE_HEADER_SIZE + packet->qname_size + sizeof(uint16_t);
+	return knot_wire_read_u16(packet->wireformat + off);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1146,7 +818,8 @@ int knot_packet_is_query(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return (knot_wire_flags_get_qr(packet->header.flags1) == 0);
+	uint8_t flags = knot_wire_get_flags1(packet->wireformat);
+	return (knot_wire_flags_get_qr(flags) == 0);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1168,7 +841,8 @@ int knot_packet_rcode(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return knot_wire_flags_get_rcode(packet->header.flags2);
+	uint8_t flags = knot_wire_get_flags2(packet->wireformat);
+	return knot_wire_flags_get_rcode(flags);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1179,7 +853,8 @@ int knot_packet_tc(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return knot_wire_flags_get_tc(packet->header.flags1);
+	uint8_t flags = knot_wire_get_flags1(packet->wireformat);
+	return knot_wire_flags_get_tc(flags);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1190,7 +865,7 @@ int knot_packet_qdcount(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return packet->header.qdcount;
+	return knot_wire_get_qdcount(packet->wireformat);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1201,7 +876,7 @@ int knot_packet_ancount(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return packet->header.ancount;
+	return knot_wire_get_ancount(packet->wireformat);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1212,7 +887,7 @@ int knot_packet_nscount(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return packet->header.nscount;
+	return knot_wire_get_nscount(packet->wireformat);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1223,7 +898,7 @@ int knot_packet_arcount(const knot_packet_t *packet)
 		return KNOT_EINVAL;
 	}
 
-	return packet->header.arcount;
+	return knot_wire_get_arcount(packet->wireformat);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1356,12 +1031,12 @@ int knot_packet_add_tmp_rrset(knot_packet_t *packet,
 		return KNOT_EINVAL;
 	}
 
-	if (packet->tmp_rrsets_count == packet->tmp_rrsets_max
-	    && knot_packet_realloc_rrsets(&packet->tmp_rrsets,
-			&packet->tmp_rrsets_max,
-			DEFAULT_RRSET_COUNT(TMP_RRSETS, packet),
-			STEP_TMP_RRSETS) != KNOT_EOK) {
-		return KNOT_ENOMEM;
+	if (packet->tmp_rrsets_count == packet->tmp_rrsets_max) {
+		int ret = knot_packet_realloc_rrsets(&packet->tmp_rrsets,
+		                                     &packet->tmp_rrsets_max,
+		                                     &packet->mm);
+		if (ret != KNOT_EOK)
+			return ret;
 	}
 
 	packet->tmp_rrsets[packet->tmp_rrsets_count++] = tmp_rrset;
@@ -1405,60 +1080,6 @@ dbg_packet_exec(
 
 /*----------------------------------------------------------------------------*/
 
-void knot_packet_header_to_wire(const knot_header_t *header,
-                                  uint8_t **pos, size_t *size)
-{
-	if (header == NULL || pos == NULL || *pos == NULL || size == NULL) {
-		return;
-	}
-
-	knot_wire_set_id(*pos, header->id);
-	knot_wire_set_flags1(*pos, header->flags1);
-	knot_wire_set_flags2(*pos, header->flags2);
-	knot_wire_set_qdcount(*pos, header->qdcount);
-	knot_wire_set_ancount(*pos, header->ancount);
-	knot_wire_set_nscount(*pos, header->nscount);
-	knot_wire_set_arcount(*pos, header->arcount);
-
-	*pos += KNOT_WIRE_HEADER_SIZE;
-	*size += KNOT_WIRE_HEADER_SIZE;
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_packet_question_to_wire(knot_packet_t *packet)
-{
-	if (packet == NULL || packet->question.qname == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	if (packet->size > KNOT_WIRE_HEADER_SIZE) {
-		return KNOT_ERROR;
-	}
-
-	// TODO: get rid of the numeric constants
-	size_t qsize = 4 + knot_dname_size(packet->question.qname);
-	if (qsize > packet->max_size - KNOT_WIRE_HEADER_SIZE) {
-		return KNOT_ESPACE;
-	}
-
-	// create the wireformat of Question
-	uint8_t *pos = packet->wireformat + KNOT_WIRE_HEADER_SIZE;
-	memcpy(pos, knot_dname_name(packet->question.qname),
-	       knot_dname_size(packet->question.qname));
-
-	pos += knot_dname_size(packet->question.qname);
-	knot_wire_write_u16(pos, packet->question.qtype);
-	pos += 2;
-	knot_wire_write_u16(pos, packet->question.qclass);
-
-	packet->size += knot_dname_size(packet->question.qname) + 4;
-
-	return KNOT_EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
 int knot_packet_edns_to_wire(knot_packet_t *packet)
 {
 	if (packet == NULL) {
@@ -1469,7 +1090,7 @@ int knot_packet_edns_to_wire(knot_packet_t *packet)
 	                                  packet->wireformat + packet->size,
 	                                  packet->max_size - packet->size);
 
-	packet->header.arcount += 1;
+	knot_wire_add_arcount(packet->wireformat, 1);
 
 	return KNOT_EOK;
 }
@@ -1487,20 +1108,11 @@ int knot_packet_to_wire(knot_packet_t *packet,
 	assert(packet->size <= packet->max_size);
 
 	// if there are no additional RRSets, add EDNS OPT RR
-	if (packet->header.arcount == 0
+	if (knot_wire_get_arcount(packet->wireformat) == 0
 	    && packet->opt_rr.version != EDNS_NOT_SUPPORTED) {
 	    knot_packet_edns_to_wire(packet);
 	}
 
-	// set QDCOUNT (in response it is already set, in query it is needed)
-	knot_wire_set_qdcount(packet->wireformat, packet->header.qdcount);
-	// set ANCOUNT to the packet
-	knot_wire_set_ancount(packet->wireformat, packet->header.ancount);
-	// set NSCOUNT to the packet
-	knot_wire_set_nscount(packet->wireformat, packet->header.nscount);
-	// set ARCOUNT to the packet
-	knot_wire_set_arcount(packet->wireformat, packet->header.arcount);
-
 	//assert(response->size == size);
 	*wire = packet->wireformat;
 	*wire_size = packet->size;
@@ -1532,17 +1144,14 @@ void knot_packet_free(knot_packet_t **packet)
 	knot_packet_free_allocated_space(*packet);
 
 	// free the space for wireformat
-	if ((*packet)->wireformat != NULL && (*packet)->free_wireformat) {
-		if ((*packet)->mm.free)
-			(*packet)->mm.free((*packet)->wireformat);
-	}
+	if ((*packet)->flags & KNOT_PF_FREE_WIRE)
+		(*packet)->mm.free((*packet)->wireformat);
 
 	// free EDNS options
 	knot_edns_free_options(&(*packet)->opt_rr);
 
 	dbg_packet("Freeing packet structure\n");
-	if ((*packet)->mm.free)
-		(*packet)->mm.free(*packet);
+	(*packet)->mm.free(*packet);
 	*packet = NULL;
 }
 
@@ -1567,36 +1176,34 @@ void knot_packet_dump(const knot_packet_t *packet)
 	}
 
 #ifdef KNOT_PACKET_DEBUG
+	uint8_t flags1 = knot_wire_get_flags1(packet->wireformat);
+	uint8_t flags2 = knot_wire_get_flags2(packet->wireformat);
 	dbg_packet("DNS packet:\n-----------------------------\n");
 
 	dbg_packet("\nHeader:\n");
-	dbg_packet("  ID: %u\n", packet->header.id);
+	dbg_packet("  ID: %u\n", knot_wire_get_id(packet->wireformat));
 	dbg_packet("  FLAGS: %s %s %s %s %s %s %s\n",
-	       knot_wire_flags_get_qr(packet->header.flags1) ? "qr" : "",
-	       knot_wire_flags_get_aa(packet->header.flags1) ? "aa" : "",
-	       knot_wire_flags_get_tc(packet->header.flags1) ? "tc" : "",
-	       knot_wire_flags_get_rd(packet->header.flags1) ? "rd" : "",
-	       knot_wire_flags_get_ra(packet->header.flags2) ? "ra" : "",
-	       knot_wire_flags_get_ad(packet->header.flags2) ? "ad" : "",
-	       knot_wire_flags_get_cd(packet->header.flags2) ? "cd" : "");
-	dbg_packet("  RCODE: %u\n", knot_wire_flags_get_rcode(
-	                   packet->header.flags2));
-	dbg_packet("  OPCODE: %u\n", knot_wire_flags_get_opcode(
-	                   packet->header.flags1));
-	dbg_packet("  QDCOUNT: %u\n", packet->header.qdcount);
-	dbg_packet("  ANCOUNT: %u\n", packet->header.ancount);
-	dbg_packet("  NSCOUNT: %u\n", packet->header.nscount);
-	dbg_packet("  ARCOUNT: %u\n", packet->header.arcount);
+	       knot_wire_flags_get_qr(flags1) ? "qr" : "",
+	       knot_wire_flags_get_aa(flags1) ? "aa" : "",
+	       knot_wire_flags_get_tc(flags1) ? "tc" : "",
+	       knot_wire_flags_get_rd(flags1) ? "rd" : "",
+	       knot_wire_flags_get_ra(flags2) ? "ra" : "",
+	       knot_wire_flags_get_ad(flags2) ? "ad" : "",
+	       knot_wire_flags_get_cd(flags2) ? "cd" : "");
+	dbg_packet("  RCODE: %u\n", knot_wire_flags_get_rcode(flags2));
+	dbg_packet("  OPCODE: %u\n", knot_wire_flags_get_opcode(flags1));
+	dbg_packet("  QDCOUNT: %u\n", knot_wire_get_qdcount(packet->wireformat));
+	dbg_packet("  ANCOUNT: %u\n", knot_wire_get_ancount(packet->wireformat));
+	dbg_packet("  NSCOUNT: %u\n", knot_wire_get_nscount(packet->wireformat));
+	dbg_packet("  ARCOUNT: %u\n", knot_wire_get_arcount(packet->wireformat));
 
 	if (knot_packet_qdcount(packet) > 0) {
 		dbg_packet("\nQuestion:\n");
-		char *qname = knot_dname_to_str(packet->question.qname);
+		char *qname = knot_dname_to_str(knot_packet_qname(packet));
 		dbg_packet("  QNAME: %s\n", qname);
 		free(qname);
-		dbg_packet("  QTYPE: %u (%u)\n", packet->question.qtype,
-		           packet->question.qtype);
-		dbg_packet("  QCLASS: %u (%u)\n", packet->question.qclass,
-		           packet->question.qclass);
+		dbg_packet("  QTYPE: %u\n", knot_packet_qtype(packet));
+		dbg_packet("  QCLASS: %u\n", knot_packet_qclass(packet));
 	}
 
 	dbg_packet("\nAnswer RRSets:\n");
diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h
index 0921fba430a8c3bc1fb37974543eb84da80f8a04..e86afc9e1bb1ad3ebaf395169d96ad92afb77cb4 100644
--- a/src/libknot/packet/packet.h
+++ b/src/libknot/packet/packet.h
@@ -38,50 +38,19 @@
 
 /*----------------------------------------------------------------------------*/
 
+/* How many RRs pointers to alloc in one step. */
+#define RRSET_ALLOC_STEP 8
+
 struct knot_wildcard_nodes {
 	const knot_node_t **nodes; /*!< Wildcard nodes from CNAME processing. */
 	const knot_dname_t **snames;  /*!< SNAMEs related to the nodes. */
 	short count;             /*!< Count of items in the previous arrays. */
 	short max;               /*!< Capacity of the structure (allocated). */
-	short default_count;
 };
 
 typedef struct knot_wildcard_nodes knot_wildcard_nodes_t;
 
 /*----------------------------------------------------------------------------*/
-/*!
- * \brief Structure representing the DNS packet header.
- */
-struct knot_header {
-	uint16_t id;      /*!< ID stored in host byte order. */
-	uint8_t flags1;   /*!< First octet of header flags. */
-	uint8_t flags2;   /*!< Second octet of header flags. */
-	uint16_t qdcount; /*!< Number of Question RRs, in host byte order. */
-	uint16_t ancount; /*!< Number of Answer RRs, in host byte order. */
-	uint16_t nscount; /*!< Number of Authority RRs, in host byte order. */
-	uint16_t arcount; /*!< Number of Additional RRs, in host byte order. */
-};
-
-typedef struct knot_header knot_header_t;
-
-/*!
- * \brief Structure representing one Question entry in the DNS packet.
- */
-struct knot_question {
-	knot_dname_t *qname;  /*!< Question domain name. */
-	uint16_t qtype;         /*!< Question TYPE. */
-	uint16_t qclass;        /*!< Question CLASS. */
-};
-
-typedef struct knot_question knot_question_t;
-
-enum knot_packet_prealloc_type {
-	KNOT_PACKET_PREALLOC_NONE,
-	KNOT_PACKET_PREALLOC_QUERY,
-	KNOT_PACKET_PREALLOC_RESPONSE
-};
-
-typedef enum knot_packet_prealloc_type knot_packet_prealloc_type_t;
 
 /* Maximum number of compressed names. */
 #define COMPR_MAXLEN 64
@@ -98,21 +67,8 @@ typedef struct {
 /*----------------------------------------------------------------------------*/
 /*!
  * \brief Structure representing a DNS packet.
- *
- * \note QNAME, Answer, Authority and Additonal sections are by default put to
- *       preallocated space after the structure with default sizes. If the
- *       space is not enough, more space is allocated dynamically.
  */
 struct knot_packet {
-	/*! \brief DNS header. */
-	knot_header_t header;
-
-	/*!
-	 * \brief Question section.
-	 *
-	 * \note Only one Question is supported!
-	 */
-	knot_question_t question;
 
 	const knot_rrset_t **answer;      /*!< Answer RRSets. */
 	const knot_rrset_t **authority;   /*!< Authority RRSets. */
@@ -130,12 +86,12 @@ struct knot_packet {
 
 	uint8_t *wireformat;  /*!< Wire format of the packet. */
 
-	short free_wireformat;
 	size_t parsed;
 	uint16_t parsed_an;
 	uint16_t parsed_ns;
 	uint16_t parsed_ar;
 
+	uint8_t qname_size; /*!< QNAME size. */
 	size_t size;      /*!< Current wire size of the packet. */
 	size_t max_size;  /*!< Maximum allowed size of the packet. */
 
@@ -152,8 +108,6 @@ struct knot_packet {
 
 	struct knot_packet *query; /*!< Associated query. */
 
-	knot_packet_prealloc_type_t prealloc_type;
-
 	size_t tsig_size;	/*!< Space to reserve for the TSIG RR. */
 	knot_rrset_t *tsig_rr;  /*!< TSIG RR stored in the packet. */
 	uint16_t flags;         /*!< Packet flags. */
@@ -169,88 +123,14 @@ typedef struct knot_packet knot_packet_t;
  * \brief Packet flags.
  */
 enum {
-	KNOT_PF_NULL     = 0 << 0, /*!< No flags. */
-	KNOT_PF_QUERY    = 1 << 0, /*!< Packet is query. */
-	KNOT_PF_WILDCARD = 1 << 1, /*!< Query to wildcard name. */
-	KNOT_PF_RESPONSE = 1 << 2  /*!< Packet is response. */
-};
-
-/*!
- * \brief Default sizes for response structure parts and steps for increasing
- *        them.
- */
-enum {
-	DEFAULT_ANCOUNT = 6,         /*!< Default count of Answer RRSets. */
-	DEFAULT_NSCOUNT = 8,         /*!< Default count of Authority RRSets. */
-	DEFAULT_ARCOUNT = 28,        /*!< Default count of Additional RRSets. */
-
-	DEFAULT_ANCOUNT_QUERY = 1,   /*!< Default count of Answer RRSets. */
-	DEFAULT_NSCOUNT_QUERY = 0,   /*!< Default count of Authority RRSets. */
-	DEFAULT_ARCOUNT_QUERY = 1,  /*!< Default count of Additional RRSets. */
-	/*!
-	 * \brief Default count of all domain names in response.
-	 *
-	 * Used for compression table.
-	 */
-	DEFAULT_DOMAINS_IN_RESPONSE = 22,
-
-	/*! \brief Default count of temporary RRSets stored in response. */
-	DEFAULT_TMP_RRSETS = 5,
-
-	/*! \brief Default count of wildcard nodes saved for later processing.*/
-	DEFAULT_WILDCARD_NODES = 1,
-
-	/*! \brief Default count of temporary RRSets stored in query. */
-	DEFAULT_TMP_RRSETS_QUERY = 2,
-
-	STEP_ANCOUNT = 6, /*!< Step for increasing space for Answer RRSets. */
-	STEP_NSCOUNT = 8, /*!< Step for increasing space for Authority RRSets.*/
-	STEP_ARCOUNT = 8,/*!< Step for increasing space for Additional RRSets.*/
-	STEP_DOMAINS = 10,   /*!< Step for resizing compression table. */
-	STEP_TMP_RRSETS = 5,  /*!< Step for increasing temorary RRSets count. */
-	STEP_WILDCARD_NODES = 2
+	KNOT_PF_NULL      = 0 << 0, /*!< No flags. */
+	KNOT_PF_QUERY     = 1 << 0, /*!< Packet is query. */
+	KNOT_PF_WILDCARD  = 1 << 1, /*!< Query to wildcard name. */
+	KNOT_PF_RESPONSE  = 1 << 2, /*!< Packet is response. */
+	KNOT_PF_FREE_WIRE = 1 << 3  /*!< Free wire. */
 };
 
 /*----------------------------------------------------------------------------*/
-#define PREALLOC_RRSETS(count) (count * sizeof(knot_rrset_t *))
-
-/*! \brief Sizes for preallocated space in the response structure. */
-enum {
-	/*! \brief Size of the response structure itself. */
-	PREALLOC_PACKET = sizeof(knot_packet_t),
-	/*! \brief Space for QNAME dname structure. */
-	PREALLOC_QNAME_DNAME = sizeof(knot_dname_t),
-	/*! \brief Space for QNAME name (maximum domain name size). */
-	PREALLOC_QNAME_NAME = 256,
-	/*! \brief Space for QNAME labels (maximum label count). */
-	PREALLOC_QNAME_LABELS = 127,
-	/*! \brief Total space for QNAME. */
-	PREALLOC_QNAME = PREALLOC_QNAME_DNAME
-	                 + PREALLOC_QNAME_NAME
-	                 + PREALLOC_QNAME_LABELS,
-
-	PREALLOC_WC_NODES =
-		DEFAULT_WILDCARD_NODES * sizeof(knot_node_t *),
-	PREALLOC_WC_SNAMES =
-		DEFAULT_WILDCARD_NODES * sizeof(knot_dname_t *),
-	PREALLOC_WC = PREALLOC_WC_NODES + PREALLOC_WC_SNAMES,
-
-	PREALLOC_QUERY = PREALLOC_PACKET
-	                 + PREALLOC_QNAME
-	                 + PREALLOC_RRSETS(DEFAULT_ANCOUNT_QUERY)
-	                 + PREALLOC_RRSETS(DEFAULT_NSCOUNT_QUERY)
-	                 + PREALLOC_RRSETS(DEFAULT_ARCOUNT_QUERY)
-	                 + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS_QUERY),
-
-	/*! \brief Total preallocated size for the response. */
-	PREALLOC_RESPONSE = PREALLOC_PACKET
-	                 + PREALLOC_QNAME
-	                 + PREALLOC_RRSETS(DEFAULT_ANCOUNT)
-	                 + PREALLOC_RRSETS(DEFAULT_NSCOUNT)
-	                 + PREALLOC_RRSETS(DEFAULT_ARCOUNT)
-	                 + PREALLOC_WC
-	                 + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS)
-};
 
 /*! \brief Flags which control packet parsing. */
 typedef enum {
@@ -264,18 +144,14 @@ typedef enum {
 /*!
  * \brief Creates new empty packet structure.
  *
- * \param prealloc What space should be preallocated in the structure.
- *
  * \return New packet structure or NULL if an error occured.
  */
-knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc);
+knot_packet_t *knot_packet_new();
 
 /*!
  * \brief Memory managed version of new packet create.
- *
- * See knot_packet_new() for info about parameters and output.
  */
-knot_packet_t *knot_packet_new_mm(knot_packet_prealloc_type_t prealloc, mm_ctx_t *mm);
+knot_packet_t *knot_packet_new_mm(mm_ctx_t *mm);
 
 /*!
  * \brief Parses the DNS packet from wire format.
@@ -335,9 +211,9 @@ size_t knot_packet_parsed(const knot_packet_t *packet);
  */
 int knot_packet_set_max_size(knot_packet_t *packet, int max_size);
 
-uint16_t knot_packet_id(const knot_packet_t *packet);
+int knot_packet_set_size(knot_packet_t *packet, int size);
 
-void knot_packet_set_id(knot_packet_t *packet, uint16_t id);
+uint16_t knot_packet_id(const knot_packet_t *packet);
 
 void knot_packet_set_random_id(knot_packet_t *packet);
 
@@ -350,15 +226,6 @@ void knot_packet_set_random_id(knot_packet_t *packet);
  */
 uint8_t knot_packet_opcode(const knot_packet_t *packet);
 
-/*!
- * \brief Return question section from the packet.
- *
- * \param packet Packet instance.
- *
- * \return pointer to question section.
- */
-knot_question_t *knot_packet_question(knot_packet_t *packet);
-
 /*!
  * \brief Returns the QNAME from the packet.
  *
@@ -515,19 +382,6 @@ int knot_packet_add_tmp_rrset(knot_packet_t *response,
 
 void knot_packet_free_tmp_rrsets(knot_packet_t *pkt);
 
-/*!
- * \brief Converts the header structure to wire format.
- *
- * \note This function also adjusts the position (\a pos) according to
- *       the size of the converted wire format.
- *
- * \param[in] header DNS header structure to convert.
- * \param[out] pos Position where to put the converted header. The space has
- *                 to be allocated before calling this function.
- * \param[out] size Size of the wire format of the header in bytes.
- */
-void knot_packet_header_to_wire(const knot_header_t *header,
-                                  uint8_t **pos, size_t *size);
 
 int knot_packet_question_to_wire(knot_packet_t *packet);
 
@@ -577,6 +431,13 @@ void knot_packet_dump(const knot_packet_t *packet);
  */
 int knot_packet_free_rrsets(knot_packet_t *packet);
 
+/*!
+ * \brief (Temporary) realloc RRs array size.
+ */
+int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets,
+                               short *max_count,
+                               mm_ctx_t *mm);
+
 #endif /* _KNOT_PACKET_H_ */
 
 /*! @} */
diff --git a/src/libknot/packet/query.c b/src/libknot/packet/query.c
index 4bededc9f113524ad015d75c14a290e4dc04e835..7fa19a406bf20cb1093b142fc478ae7149c95740 100644
--- a/src/libknot/packet/query.c
+++ b/src/libknot/packet/query.c
@@ -62,31 +62,45 @@ int knot_query_init(knot_packet_t *query)
 	if (query == NULL) {
 		return KNOT_EINVAL;
 	}
-	// set the qr bit to 0
-	knot_wire_flags_clear_qr(&query->header.flags1);
-
-	uint8_t *pos = query->wireformat;
-	knot_packet_header_to_wire(&query->header, &pos, &query->size);
 
+	query->size = KNOT_WIRE_HEADER_SIZE;
+	memset(query->wireformat, 0, query->size);
 	return KNOT_EOK;
 }
 
 /*----------------------------------------------------------------------------*/
 
 int knot_query_set_question(knot_packet_t *query,
-                              const knot_question_t *question)
+                            const knot_dname_t *qname,
+                            uint16_t qclass, uint16_t qtype)
 {
-	if (query == NULL || question == NULL) {
+	if (query == NULL || qname == NULL) {
 		return KNOT_EINVAL;
 	}
 
-	query->question.qname = question->qname;
-	query->question.qclass = question->qclass;
-	query->question.qtype = question->qtype;
-	query->header.qdcount = 1;
+	assert(query->size == KNOT_WIRE_HEADER_SIZE);
+
+	/* Calculate question size. */
+	uint8_t *dst = query->wireformat + KNOT_WIRE_HEADER_SIZE;
+	size_t qname_len = knot_dname_size(qname);
+	size_t qsize = 2 * sizeof(uint16_t) + qname_len;
+	if (KNOT_WIRE_HEADER_SIZE + qsize > query->max_size) {
+		return KNOT_ESPACE;
+	}
+
+	/* Copy name wireformat and TYPE+CLASS. */
+	memcpy(dst, knot_dname_name(qname), qname_len);
+	dst += qname_len;
+	knot_wire_write_u16(dst, qtype);
+	dst += sizeof(uint16_t);
+	knot_wire_write_u16(dst, qclass);
 
-	// convert the Question to wire format right away
-	return knot_packet_question_to_wire(query);
+	/* Update question count and sizes. */
+	knot_wire_set_qdcount(query->wireformat, 1);
+	query->size += qsize;
+	query->qname_size = qname_len;
+
+	return KNOT_EOK;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -96,8 +110,7 @@ int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode)
 	if (query == NULL) {
 		return KNOT_EINVAL;
 	}
-	// set the OPCODE in the structure
-	knot_wire_flags_set_opcode(&query->header.flags1, opcode);
+
 	// set the OPCODE in the wire format
 	knot_wire_set_opcode(query->wireformat, opcode);
 
@@ -151,7 +164,7 @@ int knot_query_add_rrset_authority(knot_packet_t *query,
 	}
 	query->size += written;
 	++query->ns_rrsets;
-	++query->header.nscount;
+	knot_wire_add_nscount(query->wireformat, 1);
 
 	return KNOT_EOK;
 }
diff --git a/src/libknot/packet/query.h b/src/libknot/packet/query.h
index ee5418a2818a1f53cc01658016ca4389cd7aebf6..0c021731ce66cf9daa3337431b9a1f7df8dc4a5d 100644
--- a/src/libknot/packet/query.h
+++ b/src/libknot/packet/query.h
@@ -64,7 +64,8 @@ int knot_query_edns_supported(const knot_packet_t *query);
 int knot_query_init(knot_packet_t *query);
 
 int knot_query_set_question(knot_packet_t *query,
-                              const knot_question_t *question);
+                            const knot_dname_t *qname,
+                            uint16_t qclass, uint16_t qtype);
 
 int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode);
 
diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c
index 015cdb11e78d308a4ebd2e214267663c70493e62..422454ecf8d6edc4893cae6ad3f30cae3b0a066b 100644
--- a/src/libknot/packet/response.c
+++ b/src/libknot/packet/response.c
@@ -33,7 +33,8 @@
  *
  * Update current best score.
  */
-static bool knot_response_compr_score(uint8_t *n, uint8_t *p, uint8_t labels,
+static bool knot_response_compr_score(const uint8_t *n, const uint8_t *p,
+                                      uint8_t labels,
                                       uint8_t *wire, knot_compr_ptr_t *match)
 {
 	uint16_t score = 0;
@@ -65,22 +66,6 @@ static bool knot_response_compr_score(uint8_t *n, uint8_t *p, uint8_t labels,
 	return false;
 }
 
-/*!
- * \brief Align name and reference to a common number of suffix labels.
- */
-static uint8_t knot_response_compr_align(uint8_t **name, uint8_t nlabels,
-                                         uint8_t **ref, uint8_t reflabels,
-                                         uint8_t *wire)
-{
-	for (unsigned j = nlabels; j < reflabels; ++j)
-		*ref = knot_wire_next_label(*ref, wire);
-
-	for (unsigned j = reflabels; j < nlabels; ++j)
-		*name = knot_wire_next_label(*name, wire);
-
-	return (nlabels < reflabels) ? nlabels : reflabels;
-}
-
 int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr,
                                  uint8_t *dst, size_t max)
 {
@@ -90,6 +75,7 @@ int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr,
 
 	/* Do not compress small dnames. */
 	uint8_t *name = dname->name;
+	unsigned name_labels = knot_dname_wire_labels(name, NULL);
 	if (dname->size <= 2) {
                 if (dname->size > max)
                         return KNOT_ESPACE;
@@ -103,28 +89,28 @@ int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr,
 	unsigned match_id = 0;
 	knot_compr_ptr_t match = { 0, 0 };
 	for (; i < COMPR_MAXLEN && compr->table[i].off > 0; ++i) {
-		uint8_t *name = dname->name;
-		uint8_t *ref = compr->wire + compr->table[i].off;
-		lbcount = knot_response_compr_align(&name, dname->label_count,
-		                                    &ref, compr->table[i].lbcount,
-		                                    compr->wire);
+		const uint8_t *sample = dname->name;
+		const uint8_t *ref = compr->wire + compr->table[i].off;
+		lbcount = knot_dname_align(&sample, name_labels,
+		                           &ref, compr->table[i].lbcount,
+		                           compr->wire);
 
-		if (knot_response_compr_score(name, ref, lbcount, compr->wire,
+		if (knot_response_compr_score(sample, ref, lbcount, compr->wire,
 		                              &match)) {
 			match_id = i;
-			if (match.lbcount == dname->label_count)
+			if (match.lbcount == name_labels)
 				break; /* Best match, break. */
 		}
 	}
 
 	/* Write non-matching prefix. */
 	unsigned written = 0;
-	for (unsigned j = match.lbcount; j < dname->label_count; ++j) {
+	for (unsigned j = match.lbcount; j < name_labels; ++j) {
 		if (written + *name + 1 > max)
 			return KNOT_ESPACE;
 		memcpy(dst + written, name, *name + 1);
 		written += *name + 1;
-		name = knot_wire_next_label(name, compr->wire);
+		name = (uint8_t *)knot_wire_next_label(name, compr->wire);
 	}
 
 	/* Write out pointer covering suffix. */
@@ -149,7 +135,7 @@ int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr,
 	}
 
 	/* Do not insert if exceeds bounds or full match. */
-	if (match.lbcount == dname->label_count ||
+	if (match.lbcount == name_labels ||
 	    compr->wire_pos > KNOT_WIRE_PTR_MAX)
 		return written;
 
@@ -163,7 +149,7 @@ int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr,
 	/* Store in dname table. */
 	if (compr->table[i].off == 0) {
 		compr->table[i].off = (uint16_t)compr->wire_pos;
-		compr->table[i].lbcount = dname->label_count;
+		compr->table[i].lbcount = name_labels;
 	}
 
 	return written;
@@ -227,50 +213,12 @@ dbg_response_exec(
 		                  resp->size);
 	} else if (tc) {
 		dbg_response_verb("Setting TC bit.\n");
-		knot_wire_flags_set_tc(&resp->header.flags1);
 		knot_wire_set_tc(resp->wireformat);
 	}
 
 	return rr_count > 0 ? rr_count : ret;
 }
 
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Reallocate space for RRSets.
- *
- * \param rrsets Space for RRSets.
- * \param max_count Size of the space available for the RRSets.
- * \param default_max_count Size of the space pre-allocated for the RRSets when
- *        the response structure was initialized.
- * \param step How much the space should be increased.
- *
- * \retval KNOT_EOK
- * \retval KNOT_ENOMEM
- */
-static int knot_response_realloc_rrsets(const knot_rrset_t ***rrsets,
-                                          short *max_count,
-                                          short default_max_count, short step)
-{
-	int free_old = (*max_count) != default_max_count;
-	const knot_rrset_t **old = *rrsets;
-
-	short new_max_count = *max_count + step;
-	const knot_rrset_t **new_rrsets = (const knot_rrset_t **)malloc(
-		new_max_count * sizeof(knot_rrset_t *));
-	CHECK_ALLOC_LOG(new_rrsets, KNOT_ENOMEM);
-
-	memcpy(new_rrsets, *rrsets, (*max_count) * sizeof(knot_rrset_t *));
-
-	*rrsets = new_rrsets;
-	*max_count = new_max_count;
-
-	if (free_old) {
-		free(old);
-	}
-
-	return KNOT_EOK;
-}
-
 /*----------------------------------------------------------------------------*/
 /*!
  * \brief Reallocate space for Wildcard nodes.
@@ -281,40 +229,32 @@ static int knot_response_realloc_rrsets(const knot_rrset_t ***rrsets,
 static int knot_response_realloc_wc_nodes(const knot_node_t ***nodes,
                                           const knot_dname_t ***snames,
                                           short *max_count,
-                                          short default_max_count, short step)
+                                          mm_ctx_t *mm)
 {
-	dbg_packet_detail("Max count: %d, default max count: %d\n",
-	                  *max_count, default_max_count);
-	int free_old = (*max_count) != default_max_count;
-
-	const knot_node_t **old_nodes = *nodes;
-	const knot_dname_t **old_snames = *snames;
 
-	short new_max_count = *max_count + step;
+	short new_max_count = *max_count + RRSET_ALLOC_STEP;
 
-	const knot_node_t **new_nodes = (const knot_node_t **)malloc(
+	const knot_node_t **new_nodes = mm->alloc(mm->ctx,
 		new_max_count * sizeof(knot_node_t *));
 	CHECK_ALLOC_LOG(new_nodes, KNOT_ENOMEM);
 
-	const knot_dname_t **new_snames = (const knot_dname_t **)malloc(
+	const knot_dname_t **new_snames = mm->alloc(mm->ctx,
 	                        new_max_count * sizeof(knot_dname_t *));
 	if (new_snames == NULL) {
-		free(new_nodes);
+		mm->free(new_nodes);
 		return KNOT_ENOMEM;
 	}
 
 	memcpy(new_nodes, *nodes, (*max_count) * sizeof(knot_node_t *));
 	memcpy(new_snames, *snames, (*max_count) * sizeof(knot_dname_t *));
 
+	mm->free(*nodes);
+	mm->free(*snames);
+
 	*nodes = new_nodes;
 	*snames = new_snames;
 	*max_count = new_max_count;
 
-	if (free_old) {
-		free(old_nodes);
-		free(old_snames);
-	}
-
 	return KNOT_EOK;
 }
 
@@ -333,95 +273,63 @@ int knot_response_init(knot_packet_t *response)
 	}
 
 	// set the qr bit to 1
-	knot_wire_flags_set_qr(&response->header.flags1);
+	memset(response->wireformat, 0, KNOT_WIRE_HEADER_SIZE);
 
-	uint8_t *pos = response->wireformat;
-	knot_packet_header_to_wire(&response->header, &pos,
-	                                &response->size);
+	uint8_t flags = knot_wire_get_flags1(response->wireformat);
+	knot_wire_flags_set_qr(&flags);
+	knot_wire_set_flags1(response->wireformat, flags);
 
 	return KNOT_EOK;
 }
 
 /*----------------------------------------------------------------------------*/
 
-int knot_response_init_from_query(knot_packet_t *response,
-                                  knot_packet_t *query,
-                                  int copy_question)
+int knot_response_init_from_query(knot_packet_t *response, knot_packet_t *query)
 {
-
 	if (response == NULL || query == NULL) {
 		return KNOT_EINVAL;
 	}
 
-	// copy the header from the query
-	memcpy(&response->header, &query->header, sizeof(knot_header_t));
-
-	/*! \todo Constant. */
-	size_t to_copy = 12;
-
-	if (copy_question) {
-		// copy the Question section (but do not copy the QNAME)
-		memcpy(&response->question, &query->question,
-		       sizeof(knot_question_t));
-
-		/* Insert QNAME into compression table. */
-		response->compression[0].off = KNOT_WIRE_HEADER_SIZE;
-		response->compression[0].lbcount = response->question.qname->label_count;
-
-
-		/*! \todo Constant. */
-		to_copy += 4 + knot_dname_size(response->question.qname);
-	} else {
-		response->header.qdcount = 0;
-		knot_wire_set_qdcount(response->wireformat, 0);
-	}
-
-	assert(response->max_size >= to_copy);
+	/* Header + question size. */
+	size_t to_copy = knot_packet_question_size(query);
+	assert(to_copy <= response->max_size);
 	if (response->wireformat != query->wireformat) {
 		memcpy(response->wireformat, query->wireformat, to_copy);
 	}
-	response->size = to_copy;
 
-	// set the qr bit to 1
-	knot_wire_flags_set_qr(&response->header.flags1);
-	knot_wire_set_qr(response->wireformat);
+	/* Insert QNAME into compression table. */
+	uint8_t *qname = response->wireformat + KNOT_WIRE_HEADER_SIZE;
+	response->compression[0].off = KNOT_WIRE_HEADER_SIZE;
+	response->compression[0].lbcount = knot_dname_wire_labels(qname, NULL);
 
-	// clear TC flag
-	knot_wire_flags_clear_tc(&response->header.flags1);
+	/* Update size and flags. */
+	knot_wire_set_qdcount(response->wireformat, 1);
+	knot_wire_set_qr(response->wireformat);
 	knot_wire_clear_tc(response->wireformat);
-
-	// clear AD flag
-	knot_wire_flags_clear_ad(&response->header.flags2);
-	knot_wire_clear_ad(response->wireformat);
-
-	// clear RA flag
-	knot_wire_flags_clear_ra(&response->header.flags2);
 	knot_wire_clear_ad(response->wireformat);
+	knot_wire_clear_ra(response->wireformat);
 
-	// set counts to 0
-	response->header.ancount = 0;
+	/* Reset RR counts */
 	knot_wire_set_ancount(response->wireformat, 0);
-	response->header.nscount = 0;
 	knot_wire_set_nscount(response->wireformat, 0);
-	response->header.arcount = 0;
 	knot_wire_set_arcount(response->wireformat, 0);
 
 	response->query = query;
-
+	response->size = to_copy;
+	response->qname_size = query->qname_size;
 	return KNOT_EOK;
 }
 
 /*----------------------------------------------------------------------------*/
 
-void knot_response_clear(knot_packet_t *resp, int clear_question)
+void knot_response_clear(knot_packet_t *resp)
 {
 	if (resp == NULL) {
 		return;
 	}
 
-	resp->size = (clear_question) ? KNOT_WIRE_HEADER_SIZE
-	              : KNOT_WIRE_HEADER_SIZE + 4
-	                + knot_dname_size(resp->question.qname);
+	/* Keep question. */
+	resp->size = knot_packet_question_size(resp);
 	resp->an_rrsets = 0;
 	resp->ns_rrsets = 0;
 	resp->ar_rrsets = 0;
@@ -440,9 +348,9 @@ void knot_response_clear(knot_packet_t *resp, int clear_question)
 	 *        the list of wildcard nodes should be cleared here.
 	 */
 
-	resp->header.ancount = 0;
-	resp->header.nscount = 0;
-	resp->header.arcount = 0;
+	knot_wire_set_ancount(resp->wireformat, 0);
+	knot_wire_set_nscount(resp->wireformat, 0);
+	knot_wire_set_arcount(resp->wireformat, 0);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -528,12 +436,12 @@ int knot_response_add_rrset_answer(knot_packet_t *response,
 	}
 
 	dbg_response_verb("add_rrset_answer()\n");
-	assert(response->header.arcount == 0);
-	assert(response->header.nscount == 0);
+	assert(knot_wire_get_arcount(response->wireformat) == 0);
+	assert(knot_wire_get_nscount(response->wireformat) == 0);
 
 	if (response->an_rrsets == response->max_an_rrsets
-	    && knot_response_realloc_rrsets(&response->answer,
-	          &response->max_an_rrsets, DEFAULT_ANCOUNT, STEP_ANCOUNT)
+	    && knot_packet_realloc_rrsets(&response->answer,
+	          &response->max_an_rrsets, &response->mm)
 	       != KNOT_EOK) {
 		return KNOT_ENOMEM;
 	}
@@ -556,7 +464,7 @@ int knot_response_add_rrset_answer(knot_packet_t *response,
 	                                        rrset, tc);
 
 	if (rrs >= 0) {
-		response->header.ancount += rrs;
+		knot_wire_add_ancount(response->wireformat, rrs);
 
 		if (rotate) {
 			// do round-robin rotation of the RRSet
@@ -580,11 +488,11 @@ int knot_response_add_rrset_authority(knot_packet_t *response,
 		return KNOT_EINVAL;
 	}
 
-	assert(response->header.arcount == 0);
+	assert(knot_wire_get_arcount(response->wireformat) == 0);
 
 	if (response->ns_rrsets == response->max_ns_rrsets
-	    && knot_response_realloc_rrsets(&response->authority,
-			&response->max_ns_rrsets, DEFAULT_NSCOUNT, STEP_NSCOUNT)
+	    && knot_packet_realloc_rrsets(&response->authority,
+			&response->max_ns_rrsets, &response->mm)
 		!= 0) {
 		return KNOT_ENOMEM;
 	}
@@ -605,7 +513,7 @@ int knot_response_add_rrset_authority(knot_packet_t *response,
 	                                        rrset, tc);
 
 	if (rrs >= 0) {
-		response->header.nscount += rrs;
+		knot_wire_add_nscount(response->wireformat, rrs);
 
 		if (rotate) {
 			// do round-robin rotation of the RRSet
@@ -632,15 +540,15 @@ int knot_response_add_rrset_additional(knot_packet_t *response,
 	int ret;
 
 	// if this is the first additional RRSet, add EDNS OPT RR first
-	if (response->header.arcount == 0
+	if (knot_wire_get_arcount(response->wireformat) == 0
 	    && response->opt_rr.version != EDNS_NOT_SUPPORTED
 	    && (ret = knot_packet_edns_to_wire(response)) != KNOT_EOK) {
 		return ret;
 	}
 
 	if (response->ar_rrsets == response->max_ar_rrsets
-	    && knot_response_realloc_rrsets(&response->additional,
-			&response->max_ar_rrsets, DEFAULT_ARCOUNT, STEP_ARCOUNT)
+	    && knot_packet_realloc_rrsets(&response->additional,
+			&response->max_ar_rrsets, &response->mm)
 		!= 0) {
 		return KNOT_ENOMEM;
 	}
@@ -660,7 +568,7 @@ int knot_response_add_rrset_additional(knot_packet_t *response,
 	                                        tc);
 
 	if (rrs >= 0) {
-		response->header.arcount += rrs;
+		knot_wire_add_arcount(response->wireformat, rrs);
 
 		if (rotate) {
 			// do round-robin rotation of the RRSet
@@ -681,8 +589,9 @@ void knot_response_set_rcode(knot_packet_t *response, short rcode)
 		return;
 	}
 
-	knot_wire_flags_set_rcode(&response->header.flags2, rcode);
-	knot_wire_set_rcode(response->wireformat, rcode);
+	uint8_t flags = knot_wire_get_flags2(response->wireformat);
+	knot_wire_flags_set_rcode(&flags, rcode);
+	knot_wire_set_flags2(response->wireformat, flags);
 }
 
 /*----------------------------------------------------------------------------*/
@@ -693,7 +602,6 @@ void knot_response_set_aa(knot_packet_t *response)
 		return;
 	}
 
-	knot_wire_flags_set_aa(&response->header.flags1);
 	knot_wire_set_aa(response->wireformat);
 }
 
@@ -705,7 +613,6 @@ void knot_response_set_tc(knot_packet_t *response)
 		return;
 	}
 
-	knot_wire_flags_set_tc(&response->header.flags1);
 	knot_wire_set_tc(response->wireformat);
 }
 
@@ -736,8 +643,7 @@ int knot_response_add_wildcard_node(knot_packet_t *response,
 	    && knot_response_realloc_wc_nodes(&response->wildcard_nodes.nodes,
 	                                      &response->wildcard_nodes.snames,
 	                                      &response->wildcard_nodes.max,
-	                                      DEFAULT_WILDCARD_NODES,
-	                                     STEP_WILDCARD_NODES) != KNOT_EOK) {
+	                                      &response->mm) != KNOT_EOK) {
 		return KNOT_ENOMEM;
 	}
 
diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h
index b68ca45d852478602a9bc50a6ac68628ecb59133..7bd1887a80090c4f1b058dc9587bb38e72367c87 100644
--- a/src/libknot/packet/response.h
+++ b/src/libknot/packet/response.h
@@ -105,9 +105,7 @@ int knot_response_init(knot_packet_t *response);
  *
  * \retval KNOT_EOK
  */
-int knot_response_init_from_query(knot_packet_t *response,
-                                  knot_packet_t *query,
-                                  int copy_question);
+int knot_response_init_from_query(knot_packet_t *response, knot_packet_t *query);
 
 /*!
  * \brief Clears the response structure for reuse.
@@ -119,7 +117,7 @@ int knot_response_init_from_query(knot_packet_t *response,
  *
  * \todo Replace the use of this function with something else maybe?
  */
-void knot_response_clear(knot_packet_t *resp, int clear_question);
+void knot_response_clear(knot_packet_t *resp);
 
 /*!
  * \brief Sets the OPT RR of the response.
diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c
index c8c7fe75264c7d86aa9e1579c8bf2f9b28045ec1..6cadd1106d7bfd07832423fa8fa3be3e14ffb8ee 100644
--- a/src/libknot/rrset-dump.c
+++ b/src/libknot/rrset-dump.c
@@ -846,7 +846,7 @@ static void wire_dname_to_str(rrset_dump_params_t *p)
 	} while (label_len > 0);
 
 	// Create dname.
-	dname = knot_dname_new_from_wire(p->in - in_len, in_len, NULL);
+	dname = knot_dname_new_from_wire(p->in - in_len, in_len);
 	if (dname == NULL) {
 		return;
 	}
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index 34614f7cd8e54d217dafdfeda3f24dfcaf020d07..b22982974b9035bedd659c50c41b02584ccdf5b1 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -696,7 +696,7 @@ static int rrset_deserialize_rr(knot_rrset_t *rrset, size_t rdata_pos,
 			stream_offset += 1;
 			knot_dname_t *dname =
 				knot_dname_new_from_wire(stream + stream_offset,
-			                                 dname_size, NULL);
+			                                 dname_size);
 			if (dname == NULL) {
 				return KNOT_ERROR;
 			}
@@ -1208,7 +1208,7 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
 		if (descriptor_item_is_dname(item)) {
 			pos2 = *pos;
 			knot_dname_t *dname = knot_dname_parse_from_wire(
-					wire, &pos2, total_size, NULL, NULL);
+					wire, &pos2, total_size);
 			if (dname == NULL) {
 				return KNOT_EMALF;
 			}
@@ -2320,7 +2320,7 @@ int rrset_deserialize(uint8_t *stream, size_t *stream_size,
 	uint8_t owner_size = *(stream + offset);
 	offset += 1;
 	knot_dname_t *owner = knot_dname_new_from_wire(stream + offset,
-	                                               owner_size, NULL);
+	                                               owner_size);
 	assert(owner);
 	offset += owner_size;
 	/* Read type. */
diff --git a/src/libknot/sign/key.c b/src/libknot/sign/key.c
index d721e642d7fa3c34ba264147cd32ac6047b239fb..1fc821eb29778591a0c0eaa690560c154c8522b6 100644
--- a/src/libknot/sign/key.c
+++ b/src/libknot/sign/key.c
@@ -139,8 +139,7 @@ static int get_key_info_from_public_key(const char *filename,
 	free(buffer);
 
 	knot_dname_t *owner = knot_dname_new_from_wire(scanner->r_owner,
-	                                               scanner->r_owner_length,
-	                                               NULL);
+	                                               scanner->r_owner_length);
 	if (!owner) {
 		scanner_free(scanner);
 		return KNOT_ENOMEM;
@@ -517,8 +516,7 @@ static int knot_tsig_create_key_from_args(knot_dname_t *name, int algorithm,
 int knot_tsig_create_key(const char *name, int algorithm,
                          const char *b64secret, knot_tsig_key_t *key)
 {
-	knot_dname_t *dname;
-	dname = knot_dname_new_from_nonfqdn_str(name, strlen(name), NULL);
+	knot_dname_t *dname = knot_dname_new_from_str(name, strlen(name));
 	if (!dname)
 		return KNOT_ENOMEM;
 
diff --git a/src/libknot/sign/sig0.c b/src/libknot/sign/sig0.c
index d1f1ea93cce18eb18e13e971202e6291e8e8cc69..4ac37d64e9b8fed5f4cd80a94ba7067189b357ef 100644
--- a/src/libknot/sign/sig0.c
+++ b/src/libknot/sign/sig0.c
@@ -38,7 +38,7 @@
  */
 static knot_rrset_t *sig0_create_rrset(void)
 {
-	knot_dname_t *root = knot_dname_new_from_str(".", 1, NULL);
+	knot_dname_t *root = knot_dname_new_from_str(".", 1);
 	uint32_t ttl = 0;
 	knot_rrset_t *sig_record = knot_rrset_new(root, KNOT_RRTYPE_SIG,
 	                                          KNOT_CLASS_ANY, ttl);
diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c
index fd5970985951738b31c06c9e1cc3ee183b53177c..46964a27a293d72a2ead31948b0e829e45ae1e82 100644
--- a/src/libknot/tsig.c
+++ b/src/libknot/tsig.c
@@ -160,7 +160,7 @@ int tsig_rdata_set_alg_name(knot_rrset_t *tsig, knot_dname_t *alg_name)
 int tsig_rdata_set_alg(knot_rrset_t *tsig, knot_tsig_algorithm_t alg)
 {
 	const char *s = tsig_alg_to_str(alg);
-	knot_dname_t *alg_name = knot_dname_new_from_str(s, strlen(s), NULL);
+	knot_dname_t *alg_name = knot_dname_new_from_str(s, strlen(s));
 	int ret = tsig_rdata_set_alg_name(tsig, alg_name);
 	knot_dname_release(alg_name);
 	return ret;
diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c
index ab9172dc449bd4868ff20764097503ccb0eda324..febc73acbde415d4ad821aed7a7b5a752dd1c7b9 100644
--- a/src/libknot/updates/xfr-in.c
+++ b/src/libknot/updates/xfr-in.c
@@ -43,7 +43,7 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 			      uint16_t qclass, knot_ns_xfr_t *xfr, size_t *size,
 			      const knot_rrset_t *soa, int use_tsig)
 {
-	knot_packet_t *pkt = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+	knot_packet_t *pkt = knot_packet_new();
 	CHECK_ALLOC_LOG(pkt, KNOT_ENOMEM);
 
 	/*! \todo Get rid of the numeric constant. */
@@ -59,23 +59,10 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 		return KNOT_ERROR;
 	}
 
-	knot_question_t question;
-
-	/* Retain qname until the question is freed. */
-	knot_dname_retain(qname);
-
 	/* Set random query ID. */
 	knot_packet_set_random_id(pkt);
-	knot_wire_set_id(pkt->wireformat, pkt->header.id);
-
-	// this is ugly!!
-	question.qname = (knot_dname_t *)qname;
-	question.qtype = qtype;
-	question.qclass = qclass;
-
-	rc = knot_query_set_question(pkt, &question);
+	rc = knot_query_set_question(pkt, qname, qclass, qtype);
 	if (rc != KNOT_EOK) {
-		knot_dname_release(question.qname);
 		knot_packet_free(&pkt);
 		return KNOT_ERROR;
 	}
@@ -99,7 +86,6 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 	rc = knot_packet_to_wire(pkt, &wire, &wire_size);
 	if (rc != KNOT_EOK) {
 		dbg_xfrin("Failed to write packet to wire.\n");
-		knot_dname_release(question.qname);
 		knot_packet_free(&pkt);
 		return KNOT_ERROR;
 	}
@@ -141,9 +127,6 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 
 	knot_packet_free(&pkt);
 
-	/* Release qname. */
-	knot_dname_release(question.qname);
-
 	return KNOT_EOK;
 }
 
@@ -452,8 +435,7 @@ int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr)
 
 	/*! \todo Should TC bit be checked? */
 
-	knot_packet_t *packet =
-			knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+	knot_packet_t *packet = knot_packet_new();
 	if (packet == NULL) {
 		dbg_xfrin("Could not create packet structure.\n");
 		return KNOT_ENOMEM;
@@ -886,7 +868,7 @@ static int xfrin_parse_first_rr(knot_packet_t **packet, const uint8_t *pkt,
 	assert(packet != NULL);
 	assert(rr != NULL);
 
-	*packet = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+	*packet = knot_packet_new();
 	if (*packet == NULL) {
 		dbg_xfrin("Could not create packet structure.\n");
 		return KNOT_ENOMEM;
@@ -2449,17 +2431,6 @@ static void xfrin_zone_contents_free2(knot_zone_contents_t **contents)
 
 /*----------------------------------------------------------------------------*/
 
-static void xfrin_cleanup_old_nodes(knot_node_t *node, void *data)
-{
-	UNUSED(data);
-	assert(node != NULL);
-
-	knot_node_set_new_node(node, NULL);
-	knot_dname_set_node(knot_node_get_owner(node), node);
-}
-
-/*----------------------------------------------------------------------------*/
-
 static void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents,
                                         knot_zone_contents_t **new_contents)
 {
@@ -2471,18 +2442,6 @@ static void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents,
 		// destroy the shallow copy of zone
 		xfrin_zone_contents_free2(new_contents);
 	}
-
-	if (old_contents != NULL) {
-		// cleanup old zone tree - reset pointers to new node to NULL
-		// also set pointers from dnames to old nodes
-		knot_zone_contents_tree_apply_inorder(old_contents,
-						      xfrin_cleanup_old_nodes,
-						      NULL);
-
-		knot_zone_contents_nsec3_apply_inorder(old_contents,
-						       xfrin_cleanup_old_nodes,
-						       NULL);
-	}
 }
 
 /*----------------------------------------------------------------------------*/
@@ -3241,56 +3200,6 @@ int xfrin_apply_changesets(knot_zone_t *zone,
 
 /*----------------------------------------------------------------------------*/
 
-static int xfrin_switch_node_in_rdata(knot_dname_t **dname, void *data)
-{
-	UNUSED(data);
-	if (dname == NULL || *dname == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	if ((*dname)->node != NULL) {
-		knot_dname_update_node(*dname);
-	}
-
-	return KNOT_EOK;
-}
-
-static void xfrin_switch_node_in_rrset(knot_rrset_t *rrset)
-{
-	if (rrset == NULL) {
-		return;
-	}
-
-	if (rrset->rrsigs) {
-		xfrin_switch_node_in_rrset(rrset->rrsigs);
-	}
-
-	if (rrset->owner->node != NULL) {
-		knot_dname_update_node(rrset->owner);
-	}
-
-	rrset_dnames_apply(rrset, xfrin_switch_node_in_rdata, NULL);
-}
-
-static void xfrin_switch_node_in_node(knot_node_t **node, void *data)
-{
-	UNUSED(data);
-	if (node == NULL || *node == NULL) {
-		return;
-	}
-
-	if ((*node)->owner->node != NULL) {
-		knot_dname_update_node((*node)->owner);
-	}
-
-	knot_rrset_t **rr_array = knot_node_get_rrsets_no_copy(*node);
-	for (uint16_t i = 0; i < (*node)->rrset_count; ++i) {
-		xfrin_switch_node_in_rrset(rr_array[i]);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
 int xfrin_switch_zone(knot_zone_t *zone,
                       knot_zone_contents_t *new_contents,
                       int transfer_type)
@@ -3310,17 +3219,6 @@ int xfrin_switch_zone(knot_zone_t *zone,
 	dbg_xfrin_verb("Old contents: %p, apex: %p, new apex: %p\n",
 		       old, (old) ? old->apex : NULL, new_contents->apex);
 
-	// switch pointers in domain names, now only the new zone is used
-	if (transfer_type == XFR_TYPE_IIN || transfer_type == XFR_TYPE_UPDATE) {
-		/* Switch node references in owner DNAMEs and RDATA dnames. */
-		int ret = knot_zone_tree_apply(new_contents->nodes,
-					       xfrin_switch_node_in_node, NULL);
-		assert(ret == KNOT_EOK);
-		ret = knot_zone_tree_apply(new_contents->nsec3_nodes,
-					   xfrin_switch_node_in_node, NULL);
-		assert(ret == KNOT_EOK);
-	}
-
 	// set generation to old, so that the flags may be used in next transfer
 	// and we do not search for new nodes anymore
 	knot_zone_contents_set_gen_old(new_contents);
diff --git a/src/libknot/util/debug.c b/src/libknot/util/debug.c
index 9f8d8527fc443b5c9fd2c5b866bb45cc58280f4b..97c9e5af4c28c1d4a1b36b63dbc188ebc7ebfbfc 100644
--- a/src/libknot/util/debug.c
+++ b/src/libknot/util/debug.c
@@ -44,10 +44,7 @@ void knot_node_dump(knot_node_t *node)
 	name = knot_dname_to_str(node->owner);
 	dbg_node_detail("owner: %s\n", name);
 	free(name);
-	dbg_node_detail("labels: ");
-	hex_print(node->owner->labels, node->owner->label_count);
 	dbg_node_detail("node: %p\n", node);
-	dbg_node_detail("node (in node's owner): %p\n", node->owner->node);
 
 	if (knot_node_is_deleg_point(node)) {
 		dbg_node_detail("delegation point\n");
diff --git a/src/libknot/util/wire.h b/src/libknot/util/wire.h
index e2f283de7b57bbecef837dbfeb8cb156dba15c3c..80588a689dec8036a1b111fe206b1b46fa03880e 100644
--- a/src/libknot/util/wire.h
+++ b/src/libknot/util/wire.h
@@ -148,6 +148,15 @@ static inline void knot_wire_set_qdcount(uint8_t *packet, uint16_t qdcount)
 	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT, qdcount);
 }
 
+/*!
+ * \brief Adds to QDCOUNT.
+ */
+static inline void knot_wire_add_qdcount(uint8_t *packet, int16_t n)
+{
+	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT,
+	                    knot_wire_get_qdcount(packet) + n);
+}
+
 /*!
  * \brief Returns the ANCOUNT (count of Answer entries) from wire format of
  *        the packet.
@@ -173,6 +182,15 @@ static inline void knot_wire_set_ancount(uint8_t *packet, uint16_t ancount)
 	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT, ancount);
 }
 
+/*!
+ * \brief Adds to ANCOUNT.
+ */
+static inline void knot_wire_add_ancount(uint8_t *packet, int16_t n)
+{
+	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT,
+	                    knot_wire_get_ancount(packet) + n);
+}
+
 /*!
  * \brief Returns the NSCOUNT (count of Authority entries) from wire format of
  *        the packet.
@@ -198,6 +216,15 @@ static inline void knot_wire_set_nscount(uint8_t *packet, uint16_t nscount)
 	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT, nscount);
 }
 
+/*!
+ * \brief Adds to NSCOUNT.
+ */
+static inline void knot_wire_add_nscount(uint8_t *packet, int16_t n)
+{
+	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT,
+	                    knot_wire_get_nscount(packet) + n);
+}
+
 /*!
  * \brief Returns the ARCOUNT (count of Additional entries) from wire format of
  *        the packet.
@@ -223,6 +250,15 @@ static inline void knot_wire_set_arcount(uint8_t *packet, uint16_t arcount)
 	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT, arcount);
 }
 
+/*!
+ * \brief Adds to ARCOUNT.
+ */
+static inline void knot_wire_add_arcount(uint8_t *packet, int16_t n)
+{
+	knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT,
+	                    knot_wire_get_arcount(packet) + n);
+}
+
 /*
  * Packet header flags manipulation functions.
  */
@@ -919,10 +955,12 @@ static inline uint16_t knot_wire_get_pointer(const uint8_t *pos)
 	return (knot_wire_read_u16(pos) - KNOT_WIRE_PTR_BASE);	// Return offset.
 }
 
-static inline uint8_t *knot_wire_next_label(uint8_t *lp, uint8_t *wire)
+static inline const uint8_t *knot_wire_next_label(const uint8_t *lp, const uint8_t *wire)
 {
 	lp = lp + (lp[0] + sizeof(uint8_t));
 	if (knot_wire_is_pointer(lp)) {
+		if (!wire)
+			return NULL;
 		lp = wire + knot_wire_get_pointer(lp);
 	}
 	return lp;
diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c
index 59eea304193096e160055f8dc741d22f51f6d4fd..cd358f7528be13676b98b26272fa7187cbabd8cc 100644
--- a/src/libknot/zone/node.c
+++ b/src/libknot/zone/node.c
@@ -707,13 +707,6 @@ void knot_node_free(knot_node_t **node)
 		(*node)->rrset_count = 0;
 	}
 
-	// set owner's node pointer to NULL, but only if the 'node' does
-	// not point to the owner's node
-	if (node != &(*node)->owner->node
-	    && knot_dname_node(knot_node_owner(*node)) == *node) {
-		knot_dname_set_node((*node)->owner, NULL);
-	}
-
 	knot_dname_release((*node)->owner);
 
 	free(*node);
diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c
index e9dfff0311b0e9732da7de2d595c3866a89c9df1..3375590c578e34bd2d383ceaa7883946ff5b7e15 100644
--- a/src/libknot/zone/zone-contents.c
+++ b/src/libknot/zone/zone-contents.c
@@ -134,7 +134,7 @@ static const knot_node_t *knot_zone_contents_find_wildcard_child(
 	assert(zone != NULL);
 	assert(closest_encloser != NULL);
 
-	knot_dname_t *tmp = knot_dname_new_from_str("*", 1, NULL);
+	knot_dname_t *tmp = knot_dname_new_from_str("*", 1);
 	CHECK_ALLOC(tmp, NULL);
 
 	knot_dname_t *wildcard = knot_dname_cat(tmp, knot_node_owner(
@@ -213,71 +213,7 @@ static void knot_zone_contents_adjust_rdata_dname(knot_zone_contents_t *zone,
                                                   knot_node_t *node,
                                                   knot_dname_t **in_dname)
 {
-//	const knot_node_t *old_dname_node = (*in_dname)->node;
 	knot_zone_contents_insert_dname_into_table(in_dname, lookup_tree);
-//	assert((*in_dname)->node == old_dname_node || old_dname_node == NULL);
-
-	knot_dname_t *dname = *in_dname;
-	/*
-	 * The case when dname.node is already set is handled here.
-	 * No use to check it later.
-	 */
-	if (knot_dname_node(dname) != NULL
-	    || !knot_dname_is_subdomain(dname, knot_node_owner(
-				      knot_zone_contents_apex(zone)))) {
-		// The name's node is either already set
-		// or the name does not belong to the zone
-		dbg_zone_detail("Name's node either set or the name "
-				"does not belong to the zone (%p).\n",
-				knot_dname_node(dname));
-		return;
-	}
-
-	const knot_node_t *n = NULL;
-	const knot_node_t *closest_encloser = NULL;
-	const knot_node_t *prev = NULL;
-
-	int ret = knot_zone_contents_find_dname(zone, dname, &n,
-					      &closest_encloser, &prev);
-
-	if (ret == KNOT_EINVAL || ret == KNOT_EBADZONE) {
-		// TODO: do some cleanup if needed
-		dbg_zone_detail("Failed to find the name in zone: %s\n",
-				knot_strerror(ret));
-		return;
-	}
-
-	assert(ret != KNOT_ZONE_NAME_FOUND || n == closest_encloser);
-
-	if (ret != KNOT_ZONE_NAME_FOUND && (closest_encloser != NULL)) {
-			/*!
-			 * \note There is no need to set closer encloser to the
-			 *       name. We may find the possible wildcard child
-			 *       right away.
-			 *       Having the closest encloser saved in the dname
-			 *       would disrupt the query processing algorithms
-			 *       anyway.
-			 */
-
-			dbg_zone_verb("Trying to find wildcard child.\n");
-
-			n = knot_zone_contents_find_wildcard_child(zone,
-							      closest_encloser);
-
-			if (n != NULL) {
-				knot_dname_set_node(dname, (knot_node_t *)n);
-				dbg_zone_exec_detail(
-					char *name = knot_dname_to_str(
-							    knot_node_owner(n));
-					char *name2 = knot_dname_to_str(dname);
-					dbg_zone_detail("Set wildcard node %s "
-							"to RDATA dname %s.\n",
-							name, name2);
-					free(name);
-					free(name2);
-				);
-			}
-	}
 }
 
 /*----------------------------------------------------------------------------*/
@@ -391,11 +327,6 @@ static int knot_zone_contents_adjust_node(knot_node_t *node,
 	knot_zone_contents_insert_dname_into_table(&node->owner, lookup_tree);
 //	assert(node->owner->node == old_dname_node || old_dname_node == NULL);
 
-	// assure that owner has proper node
-	if (knot_dname_node(knot_node_owner(node)) == NULL) {
-		knot_dname_set_node(knot_node_get_owner(node), node);
-	}
-
 	// check if this node is not a wildcard child of its parent
 	if (knot_dname_is_wildcard(knot_node_owner(node))) {
 		assert(knot_node_parent(node) != NULL);
@@ -554,11 +485,6 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree(
 		return;
 	}
 
-	// assure that owner has proper node
-	if (knot_dname_node(knot_node_owner(node)) == NULL) {
-		knot_dname_set_node(knot_node_get_owner(node), node);
-	}
-
 	/*
 	 * We assume, that NSEC3 nodes have none DNAMEs in their RDATA and
 	 * that node owners are all unique. \todo Harmful?
@@ -660,7 +586,7 @@ dbg_zone_exec_verb(
 );
 
 	/* Will be returned to caller, make sure it is released after use. */
-	*nsec3_name = knot_dname_new_from_str((char *)name_b32, size, NULL);
+	*nsec3_name = knot_dname_new_from_str((char *)name_b32, size);
 
 	free(name_b32);
 
@@ -933,8 +859,7 @@ dbg_zone_exec_detail(
 		knot_dname_left_chop(knot_node_owner(node));
 	if(chopped == NULL) {
 		/* Root domain and root domain only. */
-		assert(node->owner && node->owner->labels &&
-		       node->owner->labels[0] == 0);
+		assert(node->owner && *node->owner->name == '\0');
 		return KNOT_EOK;
 	}
 
@@ -1439,8 +1364,8 @@ dbg_zone_detail("Search function returned %d, node %s (%p) and prev: %s (%p)\n",
 
 		int matched_labels = knot_dname_matched_labels(
 				knot_node_owner((*closest_encloser)), name);
-		while (matched_labels < knot_dname_label_count(
-				knot_node_owner((*closest_encloser)))) {
+		while (matched_labels < knot_dname_wire_labels(
+				knot_node_owner((*closest_encloser))->name, NULL)) {
 			(*closest_encloser) =
 				knot_node_parent((*closest_encloser));
 			assert(*closest_encloser);
@@ -2217,7 +2142,7 @@ static void knot_zc_integrity_check_parent(const knot_node_t *node,
 	// if direct child
 	if (knot_dname_is_subdomain(node_owner, parent_owner)
 	    && knot_dname_matched_labels(node_owner, parent_owner)
-	       == knot_dname_label_count(parent_owner)) {
+	       == knot_dname_wire_labels(parent_owner->name, NULL)) {
 
 		// check the parent pointer
 		const knot_node_t *parent = knot_node_parent(node);
@@ -2272,29 +2197,6 @@ typedef struct find_dname_data {
 
 /*----------------------------------------------------------------------------*/
 
-static void knot_zc_integrity_check_owner(const knot_node_t *node,
-                                          check_data_t *check_data,
-                                          const char *name)
-{
-	// check node stored in owner
-	const knot_node_t *owner_node =
-			knot_dname_node(knot_node_owner(node));
-	if (owner_node != node) {
-		char *name2 = (owner_node != NULL)
-				? knot_dname_to_str(knot_node_owner(owner_node))
-				: "none";
-		fprintf(stderr, "Wrong owner's node: node %s, owner's node %s"
-			"\n", name, name2);
-		if (owner_node != NULL) {
-			free(name2);
-		}
-
-		++check_data->errors;
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
 static void knot_zc_integrity_check_node(knot_node_t *node, void *data)
 {
 	assert(node != NULL);
@@ -2315,9 +2217,6 @@ static void knot_zc_integrity_check_node(knot_node_t *node, void *data)
 	// & wildcard child
 	knot_zc_integrity_check_parent(node, check_data, name);
 
-	// check owner
-	knot_zc_integrity_check_owner(node, check_data, name);
-
 	/*! \todo Check NSEC3 node. */
 
 	free(name);
@@ -2347,9 +2246,6 @@ static void knot_zc_integrity_check_nsec3(knot_node_t *node, void *data)
 		++check_data->errors;
 	}
 
-	// check owner
-	knot_zc_integrity_check_owner(node, check_data, name);
-
 	free(name);
 }
 
diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c
index 27cdf5f22339c64156ea93421145eb5ad8ac2eb8..c31c6dc51c301155f3818fc303492d69a963f314 100644
--- a/src/libknot/zone/zone-tree.c
+++ b/src/libknot/zone/zone-tree.c
@@ -27,53 +27,6 @@
 /* Non-API functions                                                          */
 /*----------------------------------------------------------------------------*/
 
-#define DNAME_LFT_MAXLEN 255 /* maximum lookup format length */
-
-/*!
- * \brief Convert domain name from wire to lookup format.
- *
- * Formats names from rightmost label to the leftmost, separated by the lowest
- * possible character (\x00). Sorting such formatted names also gives
- * correct canonical order (for NSEC/NSEC3).
- *
- * Example:
- * Name: lake.example.com. Wire: \x04lake\x07example\x03com\x00
- * Lookup format com\x00example\x00lake\x00
- *
- * Maximum length of such a domain name is DNAME_LFT_MAXLEN characters.
- *
- * \param dst Memory to store converted name into.
- * \param maxlen Maximum memory length.
- * \param src Source domain name.
- *
- * \retval KNOT_EOK if successful
- * \retval KNOT_ESPACE when not enough memory.
- * \retval KNOT_EINVAL on invalid parameters
- */
-static int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen) {
-	if (src->size > maxlen)
-		return KNOT_ESPACE;
-	*dst = (uint8_t)src->size;
-	/* need to save last \x00 for root dname */
-	if (*dst > 1)
-		*dst -= 1;
-	*++dst = '\0';
-	uint8_t* l = src->name;
-	uint8_t lstack[DNAME_LFT_MAXLEN];
-	uint8_t *sp = lstack;
-	while(*l != 0) { /* build label stack */
-		*sp++ = (l - src->name);
-		l += 1 + *l;
-	}
-	while(sp != lstack) {          /* consume stack */
-		l = src->name + *--sp; /* fetch rightmost label */
-		memcpy(dst, l+1, *l);  /* write label */
-		dst += *l;
-		*dst++ = '\0';         /* label separator */
-	}
-	return KNOT_EOK;
-}
-
 static value_t knot_zone_node_copy(value_t v)
 {
 	return v;
diff --git a/src/tests/knot/conf_tests.c b/src/tests/knot/conf_tests.c
index 0904a4e2a7ea83916a437bbc7b50d62929ba4265..84ace6f17f488763a3a73fb42c7c787fc537a432 100644
--- a/src/tests/knot/conf_tests.c
+++ b/src/tests/knot/conf_tests.c
@@ -128,7 +128,7 @@ static int conf_tests_run(int argc, char *argv[])
 	// Test 21: Load key dname
 	const char *sample_str = "key0.example.net";
 	knot_dname_t *sample = knot_dname_new_from_str(sample_str,
-	                                               strlen(sample_str), 0);
+	                                               strlen(sample_str));
 	if (conf->key_count > 0) {
 		knot_tsig_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k;
 		ok(knot_dname_compare(sample, k->name) == 0,
diff --git a/src/tests/knot/rrl_tests.c b/src/tests/knot/rrl_tests.c
index e7d26dd3b8fad976f3360f80ba936db48cd2034b..46c60ff33f9d0f2c16f128bea656cc747c6d9923 100644
--- a/src/tests/knot/rrl_tests.c
+++ b/src/tests/knot/rrl_tests.c
@@ -120,24 +120,22 @@ static int rrl_tests_count(int argc, char *argv[])
 static int rrl_tests_run(int argc, char *argv[])
 {
 	/* Prepare query. */
-	knot_question_t qst;
-	qst.qclass = KNOT_CLASS_IN;
-	qst.qtype = KNOT_RRTYPE_A;
-	qst.qname = knot_dname_new_from_str("beef.", 5, NULL);
-	knot_packet_t *query = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
-	knot_query_init(query);
+	knot_packet_t *query = knot_packet_new();
 	if (knot_packet_set_max_size(query, 512) < 0) {
-		knot_dname_free(&qst.qname);
 		knot_packet_free(&query);
 		return KNOT_ERROR; /* Fatal */
 	}
-	int ret = knot_query_set_question(query, &qst);
+	knot_query_init(query);
+
+	knot_dname_t *qname = knot_dname_new_from_str("beef.", 5);
+	int ret = knot_query_set_question(query, qname, KNOT_CLASS_IN, KNOT_RRTYPE_A);
+	knot_dname_free(&qname);
 	if (ret != KNOT_EOK) {
-		knot_dname_free(&qst.qname);
 		knot_packet_free(&query);
 		return KNOT_ERROR; /* Fatal */
 	}
 
+
 	/* Prepare response */
 	knot_nameserver_t *ns = knot_ns_create();
 	uint8_t rbuf[65535];
@@ -148,7 +146,7 @@ static int rrl_tests_run(int argc, char *argv[])
 	rrl_req_t rq;
 	rq.w = rbuf;
 	rq.len = rlen;
-	rq.qst = &qst;
+	rq.query = query;
 	rq.flags = 0;
 
 	/* 1. create rrl table */
@@ -165,7 +163,7 @@ static int rrl_tests_run(int argc, char *argv[])
 	ok(ret == KNOT_EOK, "rrl: setlocks");
 
 	/* 4. N unlimited requests. */
-	knot_dname_t *apex = knot_dname_new_from_str("rrl.", 4, NULL);
+	knot_dname_t *apex = knot_dname_new_from_str("rrl.", 4);
 	knot_zone_t *zone = knot_zone_new(knot_node_new(apex, NULL, 0));
 	sockaddr_t addr;
 	sockaddr_t addr6;
@@ -220,7 +218,6 @@ static int rrl_tests_run(int argc, char *argv[])
 	ok(rd.passed, "rrl: hashtable is ~ consistent");
 #endif
 
-	knot_dname_release(qst.qname);
 	knot_dname_release(apex);
 	knot_zone_deep_free(&zone);
 	knot_ns_destroy(&ns);
diff --git a/src/tests/libknot/dname_tests.c b/src/tests/libknot/dname_tests.c
index 73ca67de9647df7a8133d922fb8836bf36e1fbe1..bb37d2e94593de8460efada10a4ac881e9f0827e 100644
--- a/src/tests/libknot/dname_tests.c
+++ b/src/tests/libknot/dname_tests.c
@@ -20,18 +20,8 @@
 
 /* Test dname_parse_from_wire */
 static int test_fw(size_t l, const char *w) {
-	size_t p = 0;
-	knot_dname_t *d = NULL;
-	d = knot_dname_parse_from_wire((const uint8_t*)w, &p, l, NULL, NULL);
-	int ret = (d != NULL);
-//	d = knot_dname_new_from_wire((const uint8_t*)w, l, 0);
-//	if (d) {
-//		for(unsigned i = 0; i < d->label_count; ++i) {
-//			diag("%d", knot_dname_label_size(d, i));
-//		}
-//	}
-	knot_dname_free(&d);
-	return ret;
+	const uint8_t *np = (const uint8_t *)w + l;
+	return knot_dname_wire_check((const uint8_t *)w, np, NULL) > 0;
 }
 
 static int dname_tests_count(int argc, char *argv[]);
@@ -45,12 +35,15 @@ unit_api dname_tests_api = {
 
 static int dname_tests_count(int argc, char *argv[])
 {
-	return 8;
+	return 21;
 }
 
 static int dname_tests_run(int argc, char *argv[])
 {
-	const char *w = NULL;
+	knot_dname_t *d = NULL, *d2 = NULL;
+	const char *w = NULL, *t = NULL;
+	unsigned len = 0;
+	size_t pos = 0;
 
 	/* 1. NULL wire */
 	ok(!test_fw(0, NULL), "parsing NULL dname");
@@ -80,5 +73,84 @@ static int dname_tests_run(int argc, char *argv[])
 	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)");
 
-	return 0;
+	/* 9. parse from string (correct) .*/
+	len = 10;
+	w = "\x04""abcd""\x03""efg";
+	t = "abcd.efg";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(d && d->size == len && memcmp(d->name, w, len) == 0,
+	   "dname_fromstr: parsed correct non-FQDN name");
+	knot_dname_free(&d);
+
+	/* 10. parse FQDN from string (correct) .*/
+	t = "abcd.efg.";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(d && d->size == len && memcmp(d->name, w, len) == 0,
+	   "dname_fromstr: parsed correct FQDN name");
+	knot_dname_free(&d);
+
+	/* 11. parse name from string (incorrect) .*/
+	t = "..";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(d == NULL, "dname_fromstr: parsed incorrect name");
+
+	/* 12. equal name is subdomain */
+	t = "ab.cd.ef";
+	d2 = knot_dname_new_from_str(t, strlen(t));
+	t = "ab.cd.ef";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(!knot_dname_is_subdomain(d, d2), "dname_subdomain: equal name");
+	knot_dname_free(&d);
+
+	/* 13. true subdomain */
+	t = "0.ab.cd.ef";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(knot_dname_is_subdomain(d, d2), "dname_subdomain: true subdomain");
+	knot_dname_free(&d);
+
+	/* 14. not subdomain */
+	t = "cd.ef";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(!knot_dname_is_subdomain(d, d2), "dname_subdomain: not subdomain");
+	knot_dname_free(&d);
+
+	/* 15. root subdomain */
+	t = ".";
+	d = knot_dname_new_from_str(t, strlen(t));
+	ok(knot_dname_is_subdomain(d2, d), "dname_subdomain: root subdomain");
+	knot_dname_free(&d);
+	knot_dname_free(&d2);
+
+	/* 16-17. dname cat (valid) */
+	w = "\x03""cat";
+	len = 5;
+	d = knot_dname_new_from_wire((const uint8_t *)w, len);
+	t = "*";
+	d2 = knot_dname_new_from_str(t, strlen(t));
+	d2 = knot_dname_cat(d2, d);
+	t = "\x01""*""\x03""cat";
+	len = 2 + 4 + 1;
+	ok (d2 && len == d2->size, "dname_cat: valid concatenation size");
+	ok(memcmp(d2->name, t, len) == 0, "dname_cat: valid concatenation");
+	knot_dname_free(&d);
+	knot_dname_free(&d2);
+
+	/* 18-19. parse from wire (valid) */
+	t = "\x04""abcd""\x03""efg";
+	len = 10;
+	pos = 0;
+	d = knot_dname_parse_from_wire((const uint8_t *)t, &pos, len);
+	ok(d != NULL, "dname_parse: valid name");
+	cmp_ok(pos, "==", len, "dname_parse: valid name (parsed length)");
+	knot_dname_free(&d);
+
+	/* 20-21. parse from wire (invalid) */
+	t = "\x08""dddd";
+	len = 5;
+	pos = 0;
+	d = knot_dname_parse_from_wire((const uint8_t *)t, &pos, len);
+	ok(d == NULL, "dname_parse: bad name");
+	cmp_ok(pos, "==", 0, "dname_parse: bad name (parsed length)");
+
+	done_testing();
 }
diff --git a/src/tests/libknot/rrset_tests.c b/src/tests/libknot/rrset_tests.c
index d140681017bf7d023b6bbcdbfd5b732165e16353..a8c9932eb12c3073c4e3ac1f320776ad1cb14a4d 100644
--- a/src/tests/libknot/rrset_tests.c
+++ b/src/tests/libknot/rrset_tests.c
@@ -170,8 +170,7 @@ static void create_test_dnames()
 	for (int i = 0; i < TEST_DNAME_COUNT; i++) {
 		test_dnames[i] =
 			knot_dname_new_from_str(test_dname_strings[i],
-		                                strlen(test_dname_strings[i]),
-		                                NULL);
+		                                strlen(test_dname_strings[i]));
 	}
 }
 
diff --git a/src/tests/libknot/sign_tests.c b/src/tests/libknot/sign_tests.c
index 6b77218bf08bb9774a4a91d137b927d6a64d4295..1a7864d734317a93c804cecfe27112b6eba14b48 100644
--- a/src/tests/libknot/sign_tests.c
+++ b/src/tests/libknot/sign_tests.c
@@ -208,8 +208,7 @@ static int sign_tests_run(int argc, char *argv[])
 		knot_tsig_key_t tsig_key;
 		const char *owner = "shared.example.com.";
 		knot_dname_t *name = knot_dname_new_from_str(owner,
-							     strlen(owner),
-							     NULL);
+							     strlen(owner));
 
 		result = knot_tsig_key_from_params(&params, &tsig_key);
 		ok(result == KNOT_EINVAL,
diff --git a/src/tests/libknot/ztree_tests.c b/src/tests/libknot/ztree_tests.c
index 53506af7b6530a3c8c85c015dda897d836f5cc60..4d322ac1bcf405e1ef3a5ff0b75e34309ea530d3 100644
--- a/src/tests/libknot/ztree_tests.c
+++ b/src/tests/libknot/ztree_tests.c
@@ -24,10 +24,10 @@ static knot_node_t NODE[NCOUNT];
 static knot_dname_t* ORDER[NCOUNT];
 static void ztree_init_data()
 {
-	NAME[0] = knot_dname_new_from_str(".", 1, NULL);
-	NAME[1] = knot_dname_new_from_str("master.ac.", 10, NULL);
-	NAME[2] = knot_dname_new_from_str("ac.", 3, NULL);
-	NAME[3] = knot_dname_new_from_str("ns.", 3, NULL);
+	NAME[0] = knot_dname_new_from_str(".", 1);
+	NAME[1] = knot_dname_new_from_str("master.ac.", 10);
+	NAME[2] = knot_dname_new_from_str("ac.", 3);
+	NAME[3] = knot_dname_new_from_str("ns.", 3);
 
 	knot_dname_t *order[NCOUNT] = {
 	        NAME[0], NAME[2], NAME[1], NAME[3]
@@ -37,7 +37,6 @@ static void ztree_init_data()
 	for (unsigned i = 0; i < NCOUNT; ++i) {
 		memset(NODE + i, 0, sizeof(knot_node_t));
 		NODE[i].owner = NAME[i];
-		NAME[i]->node = NODE + i;
 		NODE[i].prev = NODE + ((NCOUNT + i - 1) % NCOUNT);
 		NODE[i].rrset_count = 1; /* required for ordered search */
 	}
@@ -120,7 +119,7 @@ static int ztree_tests_run(int argc, char *argv[])
 	passed = 1;
 	node = NULL;
 	const knot_node_t *prev = NULL;
-	knot_dname_t *tmp_dn = knot_dname_new_from_str("z.ac.", 5, NULL);
+	knot_dname_t *tmp_dn = knot_dname_new_from_str("z.ac.", 5);
 	knot_zone_tree_find_less_or_equal(t, tmp_dn, &node, &prev);
 	knot_dname_free(&tmp_dn);
 	ok(prev == NODE + 1, "ztree: ordered lookup");
diff --git a/src/tests/xfr_tests.c b/src/tests/xfr_tests.c
index fee09f2680d8e44d98da2f3199e1d5468f6bff87..e278c531fe81e5dc1d600d195fc53f43f7c0c4e2 100644
--- a/src/tests/xfr_tests.c
+++ b/src/tests/xfr_tests.c
@@ -319,7 +319,7 @@ int main(int argc, char **argv)
 			if (zone == NULL) sig_integrity_check = 0;
 			if (sig_integrity_check) {
 				log_server_info("Starting integrity check of zone: %s\n", zone);
-				knot_dname_t* zdn = knot_dname_new_from_str(zone, strlen(zone), NULL);
+				knot_dname_t* zdn = knot_dname_new_from_str(zone, strlen(zone));
 				assert(zdn);
 				knot_zone_t *z = knot_zonedb_find_zone(server->nameserver->zone_db, zdn);
 				int ic_ret = knot_zone_contents_integrity_check(z->contents);
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
index 0a9c1a9f2889575735a71b0cc734e28eb5fae070..38a6482b6f91f7ee795ca4e5c52c941d76822d67 100644
--- a/src/utils/common/exec.c
+++ b/src/utils/common/exec.c
@@ -101,8 +101,10 @@ static void print_header(const knot_packet_t *packet, const style_t *style)
 		       ";; Flags:%1s; "
 		       "ZONE: %u; PREREQ: %u; UPDATE: %u; ADDITIONAL: %u\n",
 		       opcode_str, rcode_str, knot_packet_id(packet),
-		       flags, packet->header.qdcount, packet->header.ancount,
-		       packet->header.nscount, packet->header.arcount);
+		       flags, knot_wire_get_qdcount(packet->wireformat),
+		       knot_wire_get_ancount(packet->wireformat),
+		       knot_wire_get_nscount(packet->wireformat),
+		       knot_wire_get_arcount(packet->wireformat));
 
 		break;
 	default:
@@ -110,8 +112,10 @@ static void print_header(const knot_packet_t *packet, const style_t *style)
 		       ";; Flags:%1s; "
 		       "QUERY: %u; ANSWER: %u; AUTHORITY: %u; ADDITIONAL: %u\n",
 		       opcode_str, rcode_str, knot_packet_id(packet),
-		       flags, packet->header.qdcount, packet->header.ancount,
-		       packet->header.nscount, packet->header.arcount);
+		       flags, knot_wire_get_qdcount(packet->wireformat),
+		       knot_wire_get_ancount(packet->wireformat),
+		       knot_wire_get_nscount(packet->wireformat),
+		       knot_wire_get_arcount(packet->wireformat));
 		break;
 	}
 }
@@ -316,7 +320,7 @@ static void print_section_host(const knot_rrset_t **rrsets,
 }
 
 static void print_error_host(const uint8_t         code,
-                             const knot_question_t *question)
+                             const knot_packet_t   *packet)
 {
 	const char *rcode_str = "NULL";
 	char type[32] = "NULL";
@@ -324,12 +328,12 @@ static void print_error_host(const uint8_t         code,
 
 	knot_lookup_table_t *rcode;
 
-	owner = knot_dname_to_str(question->qname);
+	owner = knot_dname_to_str(knot_packet_qname(packet));
 	rcode = knot_lookup_by_id(knot_rcode_names, code);
 	if (rcode != NULL) {
 		rcode_str = rcode->name;
 	}
-	knot_rrtype_to_string(question->qtype, type, sizeof(type));
+	knot_rrtype_to_string(knot_packet_qtype(packet), type, sizeof(type));
 
 	if (code == KNOT_RCODE_NOERROR) {
 		printf("Host %s has no %s record\n", owner, type);
@@ -340,11 +344,10 @@ static void print_error_host(const uint8_t         code,
 	free(owner);
 }
 
-knot_packet_t* create_empty_packet(const knot_packet_prealloc_type_t type,
-                                   const size_t                      max_size)
+knot_packet_t* create_empty_packet(const size_t max_size)
 {
 	// Create packet skeleton.
-	knot_packet_t *packet = knot_packet_new(type);
+	knot_packet_t *packet = knot_packet_new();
 	if (packet == NULL) {
 		DBG_NULL;
 		return NULL;
@@ -362,7 +365,7 @@ knot_packet_t* create_empty_packet(const knot_packet_prealloc_type_t type,
 	return packet;
 }
 
-void print_header_xfr(const knot_question_t *question, const style_t  *style)
+void print_header_xfr(const knot_packet_t *packet, const style_t  *style)
 {
 	if (style == NULL) {
 		DBG_NULL;
@@ -371,7 +374,7 @@ void print_header_xfr(const knot_question_t *question, const style_t  *style)
 
 	char xfr[16] = "AXFR";
 
-	switch (question->qtype) {
+	switch (knot_packet_qtype(packet)) {
 	case KNOT_RRTYPE_AXFR:
 		break;
 	case KNOT_RRTYPE_IXFR:
@@ -382,7 +385,7 @@ void print_header_xfr(const knot_question_t *question, const style_t  *style)
 	}
 
 	if (style->show_header) {
-		char *owner = knot_dname_to_str(question->qname);
+		char *owner = knot_dname_to_str(knot_packet_qname(packet));
 		if (owner != NULL) {
 			printf("\n;; %s for %s\n", xfr, owner);
 			free(owner);
@@ -398,20 +401,21 @@ void print_data_xfr(const knot_packet_t *packet,
 		return;
 	}
 
+	uint16_t ancount = knot_wire_get_ancount(packet->wireformat);
 	switch (style->format) {
 	case FORMAT_DIG:
-		print_section_dig(packet->answer, packet->header.ancount,style);
+		print_section_dig(packet->answer, ancount,style);
 		break;
 	case FORMAT_HOST:
-		print_section_host(packet->answer, packet->header.ancount, style);
+		print_section_host(packet->answer, ancount, style);
 		break;
 	case FORMAT_FULL:
-		print_section_full(packet->answer, packet->header.ancount, style);
+		print_section_full(packet->answer, ancount, style);
 
 		// Print TSIG record if any.
 		if (style->show_additional) {
 			print_section_full(packet->additional,
-			                   packet->header.arcount,
+			                   knot_wire_get_arcount(packet->wireformat),
 			                   style);
 		}
 		break;
@@ -449,7 +453,11 @@ void print_packet(const knot_packet_t *packet,
 		return;
 	}
 
-	uint16_t additionals = packet->header.arcount;
+	uint8_t rcode = knot_wire_get_rcode(packet->wireformat);
+	uint16_t qdcount = knot_wire_get_qdcount(packet->wireformat);
+	uint16_t ancount = knot_wire_get_ancount(packet->wireformat);
+	uint16_t arcount = knot_wire_get_arcount(packet->wireformat);
+	uint16_t nscount = knot_wire_get_nscount(packet->wireformat);
 
 	// Print packet information header.
 	if (style->show_header) {
@@ -463,83 +471,82 @@ void print_packet(const knot_packet_t *packet,
 			print_opt_section(&packet->opt_rr);
 		}
 
-		additionals--;
+		arcount--;
 	}
 
 	// Print DNS sections.
 	switch (style->format) {
 	case FORMAT_DIG:
-		if (packet->header.ancount > 0) {
-			print_section_dig(packet->answer, packet->header.ancount,
+		if (ancount > 0) {
+			print_section_dig(packet->answer, ancount,
 			                  style);
 		}
 		break;
 	case FORMAT_HOST:
-		if (packet->header.ancount > 0) {
-			print_section_host(packet->answer, packet->header.ancount,
+		if (ancount > 0) {
+			print_section_host(packet->answer, ancount,
 			                   style);
 		} else {
-			uint8_t rcode = knot_wire_get_rcode(packet->wireformat);
-			print_error_host(rcode, &packet->question);
+			print_error_host(rcode, packet);
 		}
 		break;
 	case FORMAT_NSUPDATE:
-		if (style->show_question && packet->header.qdcount > 0) {
+		if (style->show_question && qdcount > 0) {
 			printf("\n;; ZONE SECTION:\n;; ");
-			print_section_question(packet->question.qname,
-			                       packet->question.qclass,
-			                       packet->question.qtype,
+			print_section_question(knot_packet_qname(packet),
+			                       knot_packet_qclass(packet),
+			                       knot_packet_qtype(packet),
 			                       style);
 		}
 
-		if (style->show_answer && packet->header.ancount > 0) {
+		if (style->show_answer && ancount > 0) {
 			printf("\n;; PREREQUISITE SECTION:\n");
 			print_section_full(packet->answer,
-			                   packet->header.ancount,
+			                   ancount,
 			                   style);
 		}
 
-		if (style->show_authority && packet->header.nscount > 0) {
+		if (style->show_authority && nscount > 0) {
 			printf("\n;; UPDATE SECTION:\n");
 			print_section_full(packet->authority,
-			                   packet->header.nscount,
+			                   nscount,
 			                   style);
 		}
 
-		if (style->show_additional && additionals > 0) {
+		if (style->show_additional && arcount > 0) {
 			printf("\n;; ADDITIONAL DATA:\n");
 			print_section_full(packet->additional,
-			                   packet->header.arcount,
+			                   arcount,
 			                   style);
 		}
 		break;
 	case FORMAT_FULL:
-		if (style->show_question && packet->header.qdcount > 0) {
+		if (style->show_question && qdcount > 0) {
 			printf("\n;; QUESTION SECTION:\n;; ");
-			print_section_question(packet->question.qname,
-			                       packet->question.qclass,
-			                       packet->question.qtype,
+			print_section_question(knot_packet_qname(packet),
+			                       knot_packet_qclass(packet),
+			                       knot_packet_qtype(packet),
 			                       style);
 		}
 
-		if (style->show_answer && packet->header.ancount > 0) {
+		if (style->show_answer && ancount > 0) {
 			printf("\n;; ANSWER SECTION:\n");
 			print_section_full(packet->answer,
-			                   packet->header.ancount,
+			                   ancount,
 			                   style);
 		}
 
-		if (style->show_authority && packet->header.nscount > 0) {
+		if (style->show_authority && nscount > 0) {
 			printf("\n;; AUTHORITY SECTION:\n");
 			print_section_full(packet->authority,
-			                   packet->header.nscount,
+			                   nscount,
 			                   style);
 		}
 
-		if (style->show_additional && additionals > 0) {
+		if (style->show_additional && arcount > 0) {
 			printf("\n;; ADDITIONAL SECTION:\n");
 				print_section_full(packet->additional,
-				                   packet->header.arcount,
+				                   arcount,
 				                   style);
 		}
 		break;
diff --git a/src/utils/common/exec.h b/src/utils/common/exec.h
index 63189e12527d0ba8b2532625b6628d486c4209ed..00d969c0df5d01298643738489426d73b04032e9 100644
--- a/src/utils/common/exec.h
+++ b/src/utils/common/exec.h
@@ -42,22 +42,20 @@ typedef struct {
 /*!
  * \brief Allocates empty packet and sets packet size and random id.
  *
- * \param type		Packet preallocation type.
  * \param max_size	Maximal packet size.
  *
  * \retval packet	if success.
  * \retval NULL		if error.
  */
-knot_packet_t* create_empty_packet(const knot_packet_prealloc_type_t type,
-                                   const size_t                      max_size);
+knot_packet_t* create_empty_packet(const size_t                      max_size);
 
 /*!
  * \brief Prints information header for transfer.
  *
- * \param question	Packet question section.
+ * \param packet	Parsed packet.
  * \param style		Style of the output.
  */
-void print_header_xfr(const knot_question_t *question, const style_t *style);
+void print_header_xfr(const knot_packet_t *packet, const style_t *style);
 
 /*!
  * \brief Prints answer section for 1 transfer message.
diff --git a/src/utils/common/params.c b/src/utils/common/params.c
index 56dc662132381c14fc8f2a29491a025dc82ef5d5..3c50885c3e488d11f4d24fb07397b099cfa687fd 100644
--- a/src/utils/common/params.c
+++ b/src/utils/common/params.c
@@ -344,7 +344,7 @@ int params_parse_tsig(const char *value, knot_key_params_t *key_params)
 	}
 
 	/* Set key name and secret. */
-	key_params->name = knot_dname_new_from_nonfqdn_str(k, strlen(k), NULL);
+	key_params->name = knot_dname_new_from_str(k, strlen(k));
 	key_params->secret = strdup(s);
 
 	DBG("%s: parsed name '%s'\n", __func__, k);
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index 8a13e96303c99b30d69679066f85fa7ce08d8742..d7aa30b94483dfc262ad164ebcb7677a05734df4 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -35,7 +35,6 @@ static knot_packet_t* create_query_packet(const query_t *query,
                                           uint8_t       **data,
                                           size_t        *data_len)
 {
-	knot_question_t q;
 	knot_packet_t   *packet;
 
 	// Set packet buffer size.
@@ -52,7 +51,7 @@ static knot_packet_t* create_query_packet(const query_t *query,
 	}
 
 	// Create packet skeleton.
-	packet = create_empty_packet(KNOT_PACKET_PREALLOC_NONE, max_size);
+	packet = create_empty_packet(max_size);
 	if (packet == NULL) {
 		return NULL;
 	}
@@ -80,20 +79,19 @@ static knot_packet_t* create_query_packet(const query_t *query,
 		knot_wire_set_cd(packet->wireformat);
 	}
 
-	// Fill auxiliary question structure.
-	q.qclass = query->class_num;
-	q.qtype = query->type_num;
-	q.qname = knot_dname_new_from_str(query->owner, strlen(query->owner), 0);
-	if (q.qname == NULL) {
+	// Create QNAME from string.
+	knot_dname_t *qname = knot_dname_new_from_str(query->owner,
+	                                              strlen(query->owner));
+	if (qname == NULL) {
 		knot_packet_free(&packet);
 		return NULL;
 	}
 
 	// Set packet question.
-	if (knot_query_set_question(packet, &q) != KNOT_EOK) {
-		// It's necessary to release q.qname by hand as it isn't
-		// connected with the packet yet.
-		knot_dname_release(q.qname);
+	int ret = knot_query_set_question(packet, qname,
+	                                  query->class_num, query->type_num);
+	if (ret != KNOT_EOK) {
+		knot_dname_free(&qname);
 		knot_packet_free(&packet);
 		return NULL;
 	}
@@ -103,13 +101,13 @@ static knot_packet_t* create_query_packet(const query_t *query,
 		// SOA rdata in wireformat.
 		uint8_t wire[22] = { 0x0 };
 		size_t  pos = 0;
-		int     ret;
 
 		// Create rrset with SOA record.
-		knot_rrset_t *soa = knot_rrset_new(q.qname,
+		knot_rrset_t *soa = knot_rrset_new(qname,
 		                                   KNOT_RRTYPE_SOA,
 		                                   query->class_num,
 		                                   0);
+		knot_dname_free(&qname); /* Won't be needed anymore. */
 		if (soa == NULL) {
 			knot_packet_free(&packet);
 			return NULL;
@@ -217,16 +215,16 @@ static bool check_reply_id(const knot_packet_t *reply,
 static void check_reply_question(const knot_packet_t *reply,
                                  const knot_packet_t *query)
 {
-	if (reply->header.qdcount < 1) {
+	if (knot_wire_get_qdcount(reply->wireformat) < 1) {
 		WARN("response doesn't have question section\n");
 		return;
 	}
 
-	int name_diff = knot_dname_compare_cs(reply->question.qname,
-	                                      query->question.qname);
+	int name_diff = knot_dname_compare_cs(knot_packet_qname(reply),
+	                                      knot_packet_qname(query));
 
-	if (reply->question.qclass != query->question.qclass ||
-	    reply->question.qtype  != query->question.qtype ||
+	if (knot_packet_qclass(reply) != knot_packet_qclass(query) ||
+	    knot_packet_qtype(reply)  != knot_packet_qtype(query) ||
 	    name_diff != 0) {
 		WARN("query/response question sections are different\n");
 		return;
@@ -235,7 +233,7 @@ static void check_reply_question(const knot_packet_t *reply,
 
 static int64_t first_serial_check(const knot_packet_t *reply)
 {
-	if (reply->header.ancount <= 0) {
+	if (knot_wire_get_ancount(reply->wireformat) <= 0) {
 		return -1;
 	}
 
@@ -250,11 +248,11 @@ static int64_t first_serial_check(const knot_packet_t *reply)
 
 static bool last_serial_check(const uint32_t serial, const knot_packet_t *reply)
 {
-	if (reply->header.ancount <= 0) {
+	if (knot_wire_get_ancount(reply->wireformat) <= 0) {
 		return false;
 	}
 
-	const knot_rrset_t *last = *(reply->answer + reply->header.ancount - 1);
+	const knot_rrset_t *last = *(reply->answer + knot_wire_get_ancount(reply->wireformat) - 1);
 
 	if (last->type != KNOT_RRTYPE_SOA) {
 		return false;
@@ -321,7 +319,7 @@ static int process_query_packet(const knot_packet_t     *query,
 		gettimeofday(&t_end, NULL);
 
 		// Create reply packet structure to fill up.
-		reply = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+		reply = knot_packet_new();
 		if (reply == NULL) {
 			net_close(net);
 			return -1;
@@ -527,7 +525,7 @@ static int process_packet_xfr(const knot_packet_t     *query,
 	}
 
 	// Print leading transfer information.
-	print_header_xfr(&query->question, style);
+	print_header_xfr(query, style);
 
 	// Loop over reply messages unless first and last SOA serials differ.
 	while (true) {
@@ -539,7 +537,7 @@ static int process_packet_xfr(const knot_packet_t     *query,
 		}
 
 		// Create reply packet structure to fill up.
-		reply = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+		reply = knot_packet_new();
 		if (reply == NULL) {
 			net_close(net);
 			return -1;
@@ -609,7 +607,7 @@ static int process_packet_xfr(const knot_packet_t     *query,
 		}
 
 		msg_count++;
-		rr_count += reply->header.ancount;
+		rr_count += knot_wire_get_ancount(reply->wireformat);
 		total_len += in_len;
 
 		// Print reply packet.
diff --git a/src/utils/nsupdate/nsupdate_exec.c b/src/utils/nsupdate/nsupdate_exec.c
index 705e7c01ecdb825b4c76c19eb743f745390896f9..a68dc959e9c8be7ce3a2cb3c691c906e6a4a5998 100644
--- a/src/utils/nsupdate/nsupdate_exec.c
+++ b/src/utils/nsupdate/nsupdate_exec.c
@@ -128,7 +128,7 @@ enum {
 };
 
 static int dname_isvalid(const char *lp, size_t len) {
-	knot_dname_t *dn = knot_dname_new_from_str(lp, len, NULL);
+	knot_dname_t *dn = knot_dname_new_from_str(lp, len);
 	if (dn == NULL) {
 		return 0;
 	}
@@ -164,7 +164,7 @@ static int parse_partial_rr(scanner_t *s, const char *lp, unsigned flags) {
 
 	/* Extract owner. */
 	size_t len = strcspn(lp, SEP_CHARS);
-	knot_dname_t *owner = knot_dname_new_from_str(lp, len, NULL);
+	knot_dname_t *owner = knot_dname_new_from_str(lp, len);
 	if (owner == NULL) {
 		return KNOT_EPARSEFAIL;
 	}
@@ -172,8 +172,7 @@ static int parse_partial_rr(scanner_t *s, const char *lp, unsigned flags) {
 	/* ISC nsupdate doesn't do this, but it seems right to me. */
 	if (!knot_dname_is_fqdn(owner)) {
 		knot_dname_t* suf = knot_dname_new_from_wire(s->zone_origin,
-		                                             s->zone_origin_length,
-		                                             NULL);
+		                                             s->zone_origin_length);
 		if (suf == NULL) {
 			knot_dname_free(&owner);
 			return KNOT_ENOMEM;
@@ -301,23 +300,21 @@ static int pkt_append(nsupdate_params_t *p, int sect)
 {
 	/* Check packet state first. */
 	int ret = KNOT_EOK;
+	knot_dname_t * qname = NULL;
 	scanner_t *s = p->rrp;
 	if (!p->pkt) {
-		p->pkt = create_empty_packet(KNOT_PACKET_PREALLOC_RESPONSE,
-		                             MAX_PACKET_SIZE);
-		knot_question_t q;
-		q.qclass = p->class_num;
-		q.qtype = p->type_num;
-		q.qname = knot_dname_new_from_nonfqdn_str(p->zone, strlen(p->zone), NULL);
-		ret = knot_query_set_question(p->pkt, &q);
-		if (ret != KNOT_EOK) {
+		p->pkt = create_empty_packet(MAX_PACKET_SIZE);
+		qname = knot_dname_new_from_str(p->zone, strlen(p->zone));
+		ret = knot_query_set_question(p->pkt, qname, p->class_num, p->type_num);
+		knot_dname_free(&qname);
+		if (ret != KNOT_EOK)
 			return ret;
-		}
+
 		knot_query_set_opcode(p->pkt, KNOT_OPCODE_UPDATE);
 	}
 
 	/* Form a rrset. */
-	knot_dname_t *o = knot_dname_new_from_wire(s->r_owner, s->r_owner_length, NULL);
+	knot_dname_t *o = knot_dname_new_from_wire(s->r_owner, s->r_owner_length);
 	if (!o) {
 		DBG("%s: failed to create dname - %s\n",
 		    __func__, knot_strerror(ret));
@@ -729,8 +726,6 @@ int cmd_send(const char* lp, nsupdate_params_t *params)
 	}
 
 	/* Clear sent packet. */
-	knot_question_t *q = knot_packet_question(params->pkt);
-	knot_dname_release(q->qname);
 	knot_packet_free_rrsets(params->pkt);
 	knot_packet_free(&params->pkt);
 
@@ -746,7 +741,7 @@ int cmd_send(const char* lp, nsupdate_params_t *params)
 	}
 
 	/* Parse response. */
-	params->resp = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+	params->resp = knot_packet_new();
 	if (!params->resp) {
 		free_sign_context(&sign_ctx);
 		return KNOT_ENOMEM;