Index: kernel/arch/amd64/include/arch/pm.h
===================================================================
--- kernel/arch/amd64/include/arch/pm.h	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ kernel/arch/amd64/include/arch/pm.h	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -57,9 +57,10 @@
 #ifdef CONFIG_FB
 
-#define VESA_INIT_DES      8
 #define VESA_INIT_SEGMENT  0x8000
+#define VESA_INIT_CODE_DES      8
+#define VESA_INIT_DATA_DES      9
 
 #undef GDT_ITEMS
-#define GDT_ITEMS  9
+#define GDT_ITEMS  10
 
 #endif /* CONFIG_FB */
Index: kernel/arch/amd64/src/pm.c
===================================================================
--- kernel/arch/amd64/src/pm.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ kernel/arch/amd64/src/pm.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -112,8 +112,6 @@
 	/* VESA Init descriptor */
 #ifdef CONFIG_FB
-	{
-		0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | DPL_KERNEL,
-		    0xf, 0, 0, 0, 0, 0
-	}
+	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | AR_READABLE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 },
+	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
 #endif
 };
Index: kernel/arch/ia32/include/arch/pm.h
===================================================================
--- kernel/arch/ia32/include/arch/pm.h	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ kernel/arch/ia32/include/arch/pm.h	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -50,9 +50,10 @@
 
 #define VESA_INIT_SEGMENT  0x8000
-#define VESA_INIT_DES      7
+#define VESA_INIT_CODE_DES      7
+#define VESA_INIT_DATA_DES      8
 #define KTEXT32_DES        KTEXT_DES
 
 #undef GDT_ITEMS
-#define GDT_ITEMS  8
+#define GDT_ITEMS  9
 
 #endif /* CONFIG_FB */
@@ -67,4 +68,5 @@
 #define AR_CODE       (3 << 3)
 #define AR_WRITABLE   (1 << 1)
+#define AR_READABLE   (1 << 1)
 #define AR_INTERRUPT  (0xe)
 #define AR_TRAP       (0xf)
Index: kernel/arch/ia32/src/boot/vesa_real.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_real.inc	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ kernel/arch/ia32/src/boot/vesa_real.inc	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -31,5 +31,14 @@
 vesa_init:
 	lidtl vesa_idtr
-	jmp $GDT_SELECTOR(VESA_INIT_DES), $vesa_init_real - vesa_init
+	
+	mov $GDT_SELECTOR(VESA_INIT_DATA_DES), %bx
+	
+	mov %bx, %es
+	mov %bx, %fs
+	mov %bx, %gs
+	mov %bx, %ds
+	mov %bx, %ss
+	
+	jmp $GDT_SELECTOR(VESA_INIT_CODE_DES), $vesa_init_real - vesa_init
 
 vesa_idtr:
@@ -39,5 +48,4 @@
 .code16
 vesa_init_real:
-	
 	mov %cr0, %eax
 	and $~1, %eax
@@ -45,5 +53,5 @@
 	
 	jmp $VESA_INIT_SEGMENT, $vesa_init_real2 - vesa_init
-	
+
 vesa_init_real2:
 	mov $VESA_INIT_SEGMENT, %bx
Index: kernel/arch/ia32/src/pm.c
===================================================================
--- kernel/arch/ia32/src/pm.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ kernel/arch/ia32/src/pm.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -75,5 +75,6 @@
 	/* VESA Init descriptor */
 #ifdef CONFIG_FB
-	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
+	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | AR_READABLE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 },
+	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
 #endif
 };
Index: uspace/app/dnsres/dnsres.c
===================================================================
--- uspace/app/dnsres/dnsres.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/app/dnsres/dnsres.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -50,4 +50,5 @@
 	int rc;
 	dnsr_hostinfo_t *hinfo;
+	char *hname;
 	char *saddr;
 
@@ -57,5 +58,7 @@
 	}
 
-	rc = dnsr_name2host(argv[1], &hinfo);
+	hname = argv[1];
+
+	rc = dnsr_name2host(hname, &hinfo);
 	if (rc != EOK) {
 		printf(NAME ": Error resolving '%s'.\n", argv[1]);
@@ -70,5 +73,9 @@
 	}
 
-	printf("Host name: %s address: %s\n", hinfo->name, saddr);
+	printf("Host name: %s\n", hname);
+	if (str_cmp(hname, hinfo->cname) != 0)
+		printf("Canonical name: %s\n", hinfo->cname);
+	printf("Address: %s\n", saddr);
+
 	dnsr_hostinfo_destroy(hinfo);
 	free(saddr);
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/app/ping/ping.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -234,5 +234,5 @@
 
 	if (hinfo != NULL) {
-		rc = asprintf(&sdest, "%s (%s)", hinfo->name, adest);
+		rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
 		if (rc < 0) {
 			printf(NAME ": Out of memory.\n");
Index: uspace/lib/c/generic/dnsr.c
===================================================================
--- uspace/lib/c/generic/dnsr.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/lib/c/generic/dnsr.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -71,4 +71,7 @@
 {
 	async_exch_t *exch = dnsr_exchange_begin();
+	char cname_buf[DNSR_NAME_MAX_SIZE + 1];
+	ipc_call_t cnreply;
+	size_t act_size;
 	dnsr_hostinfo_t *info;
 
@@ -76,4 +79,6 @@
 	aid_t req = async_send_0(exch, DNSR_NAME2HOST, &answer);
 	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	aid_t cnreq = async_data_read(exch, cname_buf, DNSR_NAME_MAX_SIZE,
+	    &cnreply);
 
 	dnsr_exchange_end(exch);
@@ -81,8 +86,15 @@
 	if (retval != EOK) {
 		async_forget(req);
+		async_forget(cnreq);
 		return retval;
 	}
 
 	async_wait_for(req, &retval);
+	if (retval != EOK) {
+		async_forget(cnreq);
+		return EIO;
+	}
+
+	async_wait_for(cnreq, &retval);
 	if (retval != EOK)
 		return EIO;
@@ -92,5 +104,9 @@
 		return ENOMEM;
 
-	info->name = str_dup(name);
+	act_size = IPC_GET_ARG2(cnreply);
+	assert(act_size <= DNSR_NAME_MAX_SIZE);
+	cname_buf[act_size] = '\0';
+
+	info->cname = str_dup(cname_buf);
 	info->addr.ipv4 = IPC_GET_ARG1(answer);
 
@@ -104,5 +120,5 @@
 		return;
 
-	free(info->name);
+	free(info->cname);
 	free(info);
 }
Index: uspace/lib/c/include/inet/dnsr.h
===================================================================
--- uspace/lib/c/include/inet/dnsr.h	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/lib/c/include/inet/dnsr.h	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -38,7 +38,11 @@
 #include <inet/inet.h>
 
+enum {
+	DNSR_NAME_MAX_SIZE = 255
+};
+
 typedef struct {
-	/** Host name */
-	char *name;
+	/** Host canonical name */
+	char *cname;
 	/** Host address */
 	inet_addr_t addr;
Index: uspace/srv/net/dnsrsrv/dns_msg.c
===================================================================
--- uspace/srv/net/dnsrsrv/dns_msg.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/srv/net/dnsrsrv/dns_msg.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -50,4 +50,10 @@
 static uint16_t dns_uint16_t_decode(uint8_t *, size_t);
 
+/** Extend dynamically allocated string with suffix.
+ *
+ * @a *dstr points to a dynamically alocated buffer containing a string.
+ * Reallocate this buffer so that concatenation of @a *dstr and @a suff can
+ * fit in and append @a suff.
+ */
 static int dns_dstr_ext(char **dstr, const char *suff)
 {
@@ -77,4 +83,14 @@
 }
 
+/** Encode DNS name.
+ *
+ * Encode DNS name or measure the size of encoded name (with @a buf NULL,
+ * and @a buf_size 0).
+ *
+ * @param name		String to encode
+ * @param buf		Buffer or NULL
+ * @param buf_size      Buffer size or 0 if @a buf is NULL
+ * @param act_size	Place to store actual encoded size
+ */
 static int dns_name_encode(char *name, uint8_t *buf, size_t buf_size,
     size_t *act_size)
@@ -135,5 +151,12 @@
 }
 
-static int dns_name_decode(uint8_t *buf, size_t size, size_t boff, char **rname,
+/** Decode DNS name.
+ *
+ * @param pdu	PDU from which we are decoding
+ * @param boff	Starting offset within PDU
+ * @param rname	Place to return dynamically allocated string
+ * @param eoff	Place to store end offset (offset after last decoded byte)
+ */
+int dns_name_decode(dns_pdu_t *pdu, size_t boff, char **rname,
     size_t *eoff)
 {
@@ -151,9 +174,9 @@
 	name = NULL;
 
-	if (boff > size)
+	if (boff > pdu->size)
 		return EINVAL;
 
-	bp = buf + boff;
-	bsize = min(size - boff, DNS_NAME_MAX_SIZE);
+	bp = pdu->data + boff;
+	bsize = min(pdu->size - boff, DNS_NAME_MAX_SIZE);
 	first = true;
 	*eoff = 0;
@@ -192,8 +215,8 @@
 			--bsize;
 
-			if (ptr >= (size_t)(bp - buf)) {
+			if (ptr >= (size_t)(bp - pdu->data)) {
 				log_msg(LOG_DEFAULT, LVL_DEBUG,
 				    "Pointer- forward ref %zu, pos=%zu",
-				    ptr, (size_t)(bp - buf));
+				    ptr, (size_t)(bp - pdu->data));
 				/* Forward reference */
 				rc = EINVAL;
@@ -205,5 +228,5 @@
 			 * XXX Is assumption correct?
 			 */
-			eptr = bp - buf;
+			eptr = bp - pdu->data;
 			/*
 			 * This is where encoded name ends in terms where
@@ -212,5 +235,5 @@
 			*eoff = eptr;
 
-			bp = buf + ptr;
+			bp = pdu->data + ptr;
 			bsize = eptr - ptr;
 			continue;
@@ -245,5 +268,5 @@
 	*rname = name;
 	if (*eoff == 0)
-		*eoff = bp - buf;
+		*eoff = bp - pdu->data;
 	return EOK;
 error:
@@ -284,4 +307,14 @@
 }
 
+/** Encode DNS question.
+ *
+ * Encode DNS question or measure the size of encoded question (with @a buf NULL,
+ * and @a buf_size 0).
+ *
+ * @param question	Question to encode
+ * @param buf		Buffer or NULL
+ * @param buf_size      Buffer size or 0 if @a buf is NULL
+ * @param act_size	Place to store actual encoded size
+ */
 static int dns_question_encode(dns_question_t *question, uint8_t *buf,
     size_t buf_size, size_t *act_size)
@@ -310,5 +343,12 @@
 }
 
-static int dns_question_decode(uint8_t *buf, size_t buf_size, size_t boff,
+/** Decode DNS question.
+ *
+ * @param pdu		PDU from which we are decoding
+ * @param boff		Starting offset within PDU
+ * @param rquestion	Place to return dynamically allocated question
+ * @param eoff		Place to store end offset (offset after last decoded byte)
+ */
+static int dns_question_decode(dns_pdu_t *pdu, size_t boff,
     dns_question_t **rquestion, size_t *eoff)
 {
@@ -321,5 +361,5 @@
 		return ENOMEM;
 
-	rc = dns_name_decode(buf, buf_size, boff, &question->qname, &name_eoff);
+	rc = dns_name_decode(pdu, boff, &question->qname, &name_eoff);
 	if (rc != EOK) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "Error decoding name");
@@ -328,12 +368,13 @@
 	}
 
-	if (name_eoff + 2 * sizeof(uint16_t) > buf_size) {
+	if (name_eoff + 2 * sizeof(uint16_t) > pdu->size) {
 		free(question);
 		return EINVAL;
 	}
 
-	question->qtype = dns_uint16_t_decode(buf + name_eoff, buf_size - name_eoff);
-	question->qclass = dns_uint16_t_decode(buf + sizeof(uint16_t) + name_eoff,
-	    buf_size - sizeof(uint16_t) - name_eoff);
+	question->qtype = dns_uint16_t_decode(pdu->data + name_eoff,
+	    pdu->size - name_eoff);
+	question->qclass = dns_uint16_t_decode(pdu->data + sizeof(uint16_t)
+	    + name_eoff, pdu->size - sizeof(uint16_t) - name_eoff);
 	*eoff = name_eoff + 2 * sizeof(uint16_t);
 
@@ -342,6 +383,13 @@
 }
 
-static int dns_rr_decode(uint8_t *buf, size_t buf_size, size_t boff,
-    dns_rr_t **retrr, size_t *eoff)
+/** Decode DNS resource record.
+ *
+ * @param pdu		PDU from which we are decoding
+ * @param boff		Starting offset within PDU
+ * @param retrr		Place to return dynamically allocated resource record
+ * @param eoff		Place to store end offset (offset after last decoded byte)
+ */
+static int dns_rr_decode(dns_pdu_t *pdu, size_t boff, dns_rr_t **retrr,
+    size_t *eoff)
 {
 	dns_rr_t *rr;
@@ -356,5 +404,5 @@
 		return ENOMEM;
 
-	rc = dns_name_decode(buf, buf_size, boff, &rr->name, &name_eoff);
+	rc = dns_name_decode(pdu, boff, &rr->name, &name_eoff);
 	if (rc != EOK) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "Error decoding name");
@@ -363,5 +411,5 @@
 	}
 
-	if (name_eoff + 2 * sizeof(uint16_t) > buf_size) {
+	if (name_eoff + 2 * sizeof(uint16_t) > pdu->size) {
 		free(rr->name);
 		free(rr);
@@ -369,6 +417,6 @@
 	}
 
-	bp = buf + name_eoff;
-	bsz = buf_size - name_eoff;
+	bp = pdu->data + name_eoff;
+	bsz = pdu->size - name_eoff;
 
 	if (bsz < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
@@ -405,12 +453,22 @@
 
 	memcpy(rr->rdata, bp, rdlength);
+	rr->roff = bp - pdu->data;
 	bp += rdlength;
 	bsz -= rdlength;
 
-	*eoff = bp - buf;
+	*eoff = bp - pdu->data;
 	*retrr = rr;
 	return EOK;
 }
 
+/** Encode DNS message.
+ *
+ * @param msg	Message
+ * @param rdata	Place to store encoded data pointer
+ * @param rsize	Place to store encoded data size
+ *
+ * @return 	EOK on success, EINVAL if message contains invalid data,
+ *		ENOMEM if out of memory
+ */
 int dns_message_encode(dns_message_t *msg, void **rdata, size_t *rsize)
 {
@@ -474,4 +532,13 @@
 }
 
+/** Decode DNS message.
+ *
+ * @param data	Encoded PDU data
+ * @param size	Encoded PDU size
+ * @param rmsg	Place to store pointer to decoded message
+ *
+ * @return	EOK on success, EINVAL if message contains invalid data,
+ * 		ENOMEM if out of memory
+ */
 int dns_message_decode(void *data, size_t size, dns_message_t **rmsg)
 {
@@ -491,6 +558,21 @@
 		return ENOMEM;
 
-	if (size < sizeof(dns_header_t))
-		return EINVAL;
+	if (size < sizeof(dns_header_t)) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	/* Store a copy of raw message data for string decompression */
+
+	msg->pdu.data = malloc(size);
+	if (msg->pdu.data == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	memcpy(msg->pdu.data, data, size);
+	msg->pdu.size = size;
+	log_msg(LOG_DEFAULT, LVL_NOTE, "dns_message_decode: pdu->data = %p, "
+	    "pdu->size=%zu", msg->pdu.data, msg->pdu.size);
 
 	hdr = data;
@@ -512,5 +594,5 @@
 
 	for (i = 0; i < qd_count; i++) {
-		rc = dns_question_decode(data, size, doff, &question, &field_eoff);
+		rc = dns_question_decode(&msg->pdu, doff, &question, &field_eoff);
 		if (rc != EOK) {
 			log_msg(LOG_DEFAULT, LVL_DEBUG, "error decoding question");
@@ -525,5 +607,5 @@
 
 	for (i = 0; i < an_count; i++) {
-		rc = dns_rr_decode(data, size, doff, &rr, &field_eoff);
+		rc = dns_rr_decode(&msg->pdu, doff, &rr, &field_eoff);
 		if (rc != EOK) {
 			log_msg(LOG_DEFAULT, LVL_DEBUG, "Error decoding answer");
@@ -542,4 +624,5 @@
 }
 
+/** Destroy question. */
 static void dns_question_destroy(dns_question_t *question)
 {
@@ -548,4 +631,5 @@
 }
 
+/** Destroy resource record. */
 static void dns_rr_destroy(dns_rr_t *rr)
 {
@@ -555,4 +639,5 @@
 }
 
+/** Create new empty message. */
 dns_message_t *dns_message_new(void)
 {
@@ -571,4 +656,5 @@
 }
 
+/** Destroy message. */
 void dns_message_destroy(dns_message_t *msg)
 {
@@ -605,4 +691,5 @@
 	}
 
+	free(msg->pdu.data);
 	free(msg);
 }
Index: uspace/srv/net/dnsrsrv/dns_msg.h
===================================================================
--- uspace/srv/net/dnsrsrv/dns_msg.h	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/srv/net/dnsrsrv/dns_msg.h	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -47,4 +47,5 @@
 extern dns_message_t *dns_message_new(void);
 extern void dns_message_destroy(dns_message_t *);
+extern int dns_name_decode(dns_pdu_t *, size_t, char **, size_t *);
 extern uint32_t dns_uint32_t_decode(uint8_t *, size_t);
 
Index: uspace/srv/net/dnsrsrv/dns_type.h
===================================================================
--- uspace/srv/net/dnsrsrv/dns_type.h	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/srv/net/dnsrsrv/dns_type.h	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -43,6 +43,17 @@
 #include "dns_std.h"
 
-/** Unencoded DNS message */
+/** Encoded DNS PDU */
 typedef struct {
+	/** Encoded PDU data */
+	uint8_t *data;
+	/** Encoded PDU size */
+	size_t size;
+} dns_pdu_t;
+
+/** DNS message */
+typedef struct {
+	/* Encoded PDU */
+	dns_pdu_t pdu;
+
 	/** Identifier */
 	uint16_t id;
@@ -95,4 +106,6 @@
 	/** Number of bytes in @c *rdata */
 	size_t rdata_size;
+	/** Offset in the raw message */
+	size_t roff;
 } dns_rr_t;
 
@@ -100,5 +113,5 @@
 typedef struct {
 	/** Host name */
-	char *name;
+	char *cname;
 	/** Host address */
 	inet_addr_t addr;
Index: uspace/srv/net/dnsrsrv/dnsrsrv.c
===================================================================
--- uspace/srv/net/dnsrsrv/dnsrsrv.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/srv/net/dnsrsrv/dnsrsrv.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -89,4 +89,8 @@
 	char *name;
 	dns_host_info_t *hinfo;
+	ipc_callid_t rcallid;
+	size_t size;
+	sysarg_t retval;
+	size_t act_size;
 	int rc;
 
@@ -100,11 +104,26 @@
 	}
 
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(rcallid, EREFUSED);
+		async_answer_0(callid, EREFUSED);
+		return;
+	}
+
 	rc = dns_name2host(name, &hinfo);
 	if (rc != EOK) {
+		async_answer_0(rcallid, rc);
 		async_answer_0(callid, rc);
 		return;
 	}
 
-	async_answer_1(callid, EOK, hinfo->addr.ipv4);
+	act_size = str_size(hinfo->cname);
+	if (act_size > size) {
+		async_answer_0(rcallid, EOVERFLOW);
+		async_answer_0(callid, EOVERFLOW);
+		return;
+	}
+
+	retval = async_data_read_finalize(rcallid, hinfo->cname, act_size);
+	async_answer_1(callid, retval, hinfo->addr.ipv4);
 
 	dns_hostinfo_destroy(hinfo);
Index: uspace/srv/net/dnsrsrv/query.c
===================================================================
--- uspace/srv/net/dnsrsrv/query.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/srv/net/dnsrsrv/query.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -54,4 +54,6 @@
 	dns_question_t *question;
 	dns_host_info_t *info;
+	char *sname, *cname;
+	size_t eoff;
 	int rc;
 
@@ -83,4 +85,7 @@
 	}
 
+	/* Start with the caller-provided name */
+	sname = str_dup(name);
+
 	list_foreach(amsg->answer, link) {
 		dns_rr_t *rr = list_get_instance(link, dns_rr_t, msg);
@@ -89,17 +94,41 @@
 			rr->name, rr->rtype, rr->rclass, rr->rdata_size);
 
+		if (rr->rtype == DTYPE_CNAME && rr->rclass == DC_IN &&
+		    str_cmp(rr->name, sname) == 0) {
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "decode cname (%p, %zu, %zu)",
+			    amsg->pdu.data, amsg->pdu.size, rr->roff);
+			rc = dns_name_decode(&amsg->pdu, rr->roff, &cname, &eoff);
+			if (rc != EOK) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "error decoding cname");
+				assert(rc == EINVAL || rc == ENOMEM);
+				dns_message_destroy(msg);
+				dns_message_destroy(amsg);
+				return rc;
+			}
+
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "name = '%s' "
+			    "cname = '%s'", sname, cname);
+
+			free(sname);
+			/* Continue looking for the more canonical name */
+			sname = cname;
+		}
+
 		if (rr->rtype == DTYPE_A && rr->rclass == DC_IN &&
-			rr->rdata_size == sizeof(uint32_t)) {
+			rr->rdata_size == sizeof(uint32_t) &&
+			    str_cmp(rr->name, sname) == 0) {
 
 			info = calloc(1, sizeof(dns_host_info_t));
 			if (info == NULL) {
+				dns_message_destroy(msg);
 				dns_message_destroy(amsg);
 				return ENOMEM;
 			}
 
-			info->name = str_dup(rr->name);
+			info->cname = str_dup(rr->name);
 			info->addr.ipv4 = dns_uint32_t_decode(rr->rdata, rr->rdata_size);
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "info->addr = %x",
-			    info->addr.ipv4);
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "info->name = '%s' "
+			    "info->addr = %x", info->cname, info->addr.ipv4);
 
 			dns_message_destroy(msg);
@@ -112,5 +141,5 @@
 	dns_message_destroy(msg);
 	dns_message_destroy(amsg);
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "No A/IN found, fail");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "'%s' not resolved, fail", sname);
 
 	return EIO;
@@ -119,5 +148,5 @@
 void dns_hostinfo_destroy(dns_host_info_t *info)
 {
-	free(info->name);
+	free(info->cname);
 	free(info);
 }
Index: uspace/srv/net/dnsrsrv/transport.c
===================================================================
--- uspace/srv/net/dnsrsrv/transport.c	(revision acdb5bacffa0840fa18ced3443b7bcb244837b8d)
+++ uspace/srv/net/dnsrsrv/transport.c	(revision 6e8ed225cc7dd39c1ed1a153a30f39a7d443bbb6)
@@ -54,4 +54,7 @@
 #define REQ_TIMEOUT (5*1000*1000)
 
+/** Maximum number of retries */
+#define REQ_RETRY_MAX 3
+
 typedef struct {
 	link_t lreq;
@@ -184,4 +187,5 @@
 	struct sockaddr_in addr;
 	trans_req_t *treq;
+	int ntry;
 
 	req_data = NULL;
@@ -196,27 +200,39 @@
 		goto error;
 
-	rc = sendto(transport_fd, req_data, req_size, 0,
-	    (struct sockaddr *)&addr, sizeof(addr));
-	if (rc != EOK)
-		goto error;
-
-	treq = treq_create(req);
-	if (treq == NULL) {
-		rc = ENOMEM;
-		goto error;
-	}
-
-	fibril_mutex_lock(&treq->done_lock);
-	while (treq->done != true) {
-		rc = fibril_condvar_wait_timeout(&treq->done_cv, &treq->done_lock,
-		    REQ_TIMEOUT);
-		if (rc == ETIMEOUT) {
-			fibril_mutex_unlock(&treq->done_lock);
-			rc = EIO;
+	ntry = 0;
+
+	while (ntry < REQ_RETRY_MAX) {
+		rc = sendto(transport_fd, req_data, req_size, 0,
+		    (struct sockaddr *)&addr, sizeof(addr));
+		if (rc != EOK)
+			goto error;
+
+		treq = treq_create(req);
+		if (treq == NULL) {
+			rc = ENOMEM;
 			goto error;
 		}
-	}
-
-	fibril_mutex_unlock(&treq->done_lock);
+
+
+		fibril_mutex_lock(&treq->done_lock);
+		while (treq->done != true) {
+			rc = fibril_condvar_wait_timeout(&treq->done_cv, &treq->done_lock,
+			    REQ_TIMEOUT);
+			if (rc == ETIMEOUT) {
+				++ntry;
+				break;
+			}
+		}
+
+		fibril_mutex_unlock(&treq->done_lock);
+
+		if (rc != ETIMEOUT)
+			break;
+	}
+
+	if (ntry >= REQ_RETRY_MAX) {
+		rc = EIO;
+		goto error;
+	}
 
 	if (treq->status != EOK) {
