Index: uspace/srv/net/dnsrsrv/dns_msg.c
===================================================================
--- uspace/srv/net/dnsrsrv/dns_msg.c	(revision 06fe3b6fbe1104797e755b13e3e1f9041b163913)
+++ uspace/srv/net/dnsrsrv/dns_msg.c	(revision d531bd6e25df500e048bf1e978ed6684fd0d65d0)
@@ -135,5 +135,5 @@
 }
 
-static int dns_name_decode(uint8_t *buf, size_t size, size_t boff, char **rname,
+int dns_name_decode(uint8_t *buf, size_t size, size_t boff, char **rname,
     size_t *eoff)
 {
@@ -405,4 +405,5 @@
 
 	memcpy(rr->rdata, bp, rdlength);
+	rr->roff = bp - buf;
 	bp += rdlength;
 	bsz -= rdlength;
@@ -491,6 +492,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->raw = malloc(size);
+	if (msg->raw == NULL) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	memcpy(msg->raw, data, size);
+	msg->raw_size = size;
+	log_msg(LOG_DEFAULT, LVL_NOTE, "dns_message_decode: msg->raw = %p, msg->raw_size=%zu",
+	    msg->raw, msg->raw_size);
 
 	hdr = data;
@@ -605,4 +621,5 @@
 	}
 
+	free(msg->raw);
 	free(msg);
 }
Index: uspace/srv/net/dnsrsrv/dns_msg.h
===================================================================
--- uspace/srv/net/dnsrsrv/dns_msg.h	(revision 06fe3b6fbe1104797e755b13e3e1f9041b163913)
+++ uspace/srv/net/dnsrsrv/dns_msg.h	(revision d531bd6e25df500e048bf1e978ed6684fd0d65d0)
@@ -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(uint8_t *, size_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 06fe3b6fbe1104797e755b13e3e1f9041b163913)
+++ uspace/srv/net/dnsrsrv/dns_type.h	(revision d531bd6e25df500e048bf1e978ed6684fd0d65d0)
@@ -43,6 +43,11 @@
 #include "dns_std.h"
 
-/** Unencoded DNS message */
+/** DNS message */
 typedef struct {
+	/** Raw message data */
+	void *raw;
+	/** Raw message size */
+	size_t raw_size;
+
 	/** Identifier */
 	uint16_t id;
@@ -95,4 +100,6 @@
 	/** Number of bytes in @c *rdata */
 	size_t rdata_size;
+	/** Offset in the raw message */
+	size_t roff;
 } dns_rr_t;
 
Index: uspace/srv/net/dnsrsrv/query.c
===================================================================
--- uspace/srv/net/dnsrsrv/query.c	(revision 06fe3b6fbe1104797e755b13e3e1f9041b163913)
+++ uspace/srv/net/dnsrsrv/query.c	(revision d531bd6e25df500e048bf1e978ed6684fd0d65d0)
@@ -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,9 +94,34 @@
 			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->raw, amsg->raw_size, rr->roff);
+			rc = dns_name_decode(amsg->raw, amsg->raw_size, 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;
@@ -100,6 +130,6 @@
 			info->name = 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->name, info->addr.ipv4);
 
 			dns_message_destroy(msg);
@@ -112,5 +142,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;
