diff --git a/src/dnssec.c b/src/dnssec.c
index 26d14cca..95c8cbbf 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -814,13 +814,7 @@ static void add_question2val_chain(struct mem_funcs *mf,
     const uint8_t *qname, uint16_t qtype, uint16_t qclass,
     getdns_network_req *netreq)
 {
-	_getdns_rrset q_rrset;
-	uint8_t cname_spc[256];
-	size_t cname_len = sizeof(cname_spc);
-	size_t anti_loop;
-	_getdns_rdf_iter rdf_spc, *rdf;
-	_getdns_rrtype_iter *rr, rr_spc;
-
+	_getdns_rrset_spc q_rrset;
 	chain_head *head;
 
 	assert(pkt);
@@ -828,43 +822,26 @@ static void add_question2val_chain(struct mem_funcs *mf,
 	assert(qname);
 
 	/* First find the canonical name for the question */
-	q_rrset.name     = qname;
-	q_rrset.rr_type  = GETDNS_RRTYPE_CNAME;
-	q_rrset.rr_class = qclass;
-	q_rrset.pkt      = pkt;
-	q_rrset.pkt_len  = pkt_len;
-	q_rrset.sections = SECTION_ANSWER;
+	q_rrset.rrset.name     = qname;
+	q_rrset.rrset.rr_type  = qtype;
+	q_rrset.rrset.rr_class = qclass;
+	q_rrset.rrset.pkt      = pkt;
+	q_rrset.rrset.pkt_len  = pkt_len;
+	q_rrset.rrset.sections = SECTION_ANSWER;
 
-	for (anti_loop = MAX_CNAME_REFERRALS; anti_loop; anti_loop--) {
-		if (!(rr = _getdns_rrtype_iter_init(&rr_spc, &q_rrset)))
-			break;
-		if (!(rdf = _getdns_rdf_iter_init(&rdf_spc, &rr->rr_i)))
-			break;
-		q_rrset.name = _getdns_rdf_if_or_as_decompressed(
-				rdf, cname_spc, &cname_len);
-	}
-
-	/* If the qtype was a CNAME, and we got one, we'r done.
-	 * We asked for it directly, so no redirection applies.
-	 * Otherwise we have to check the referred to name/qtype.
-	 */
-	if (qtype == GETDNS_RRTYPE_CNAME && q_rrset.name != qname)
+	if (_getdns_initialized_rrset_answer(&q_rrset))
 		return;
 
-	q_rrset.rr_type  = qtype;
-	if (!(rr = _getdns_rrtype_iter_init(&rr_spc, &q_rrset))) {
-		/* No answer for the question.  Add a head for this rrset
-		 * anyway, to validate proof of non-existance, or to find
-		 * proof that the packet is insecure.
-		 */
-		debug_sec_print_rrset("Adding NX rrset: ", &q_rrset);
-		head = add_rrset2val_chain(mf, chain_p, &q_rrset, netreq);
+	/* No answer for the question.  Add a head for this rrset
+	 * anyway, to validate proof of non-existance, or to find
+	 * proof that the packet is insecure.
+	 */
+	debug_sec_print_rrset("Adding NX rrset: ", &q_rrset.rrset);
+	head = add_rrset2val_chain(mf, chain_p, &q_rrset.rrset, netreq);
 
-		/* On empty packet, find SOA (zonecut) for the qname */
-		if (head && GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0)
-
-			val_chain_sched_soa(head, q_rrset.name);
-	}
+	/* On empty packet, find SOA (zonecut) for the qname */
+	if (head && GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0)
+		val_chain_sched_soa(head, q_rrset.rrset.name);
 }
 
 
diff --git a/src/general.c b/src/general.c
index a497fda3..4b80dbdd 100644
--- a/src/general.c
+++ b/src/general.c
@@ -84,76 +84,15 @@ static int
 no_answer(getdns_dns_req *dns_req)
 {
 	getdns_network_req **netreq_p, *netreq;
-	int new_canonical = 0, cnames_followed;
-	uint8_t canon_spc[256];
-	const uint8_t *canon;
-	size_t canon_len;
-	uint8_t owner_spc[256];
-	const uint8_t *owner;
-	size_t owner_len;
-
-	_getdns_rr_iter rr_spc, *rr;
-	_getdns_rdf_iter rdf_spc, *rdf;
 
 	for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
-		if (netreq->response_len == 0 ||
-		    GLDNS_ANCOUNT(netreq->response) == 0)
-			continue;
-		canon = netreq->owner->name;
-		canon_len = netreq->owner->name_len;
-		if (netreq->request_type != GETDNS_RRTYPE_CNAME
-		    && GLDNS_ANCOUNT(netreq->response) > 1) do {
-			new_canonical = 0, cnames_followed = 0;
-			for ( rr = _getdns_rr_iter_init(&rr_spc
-			                               , netreq->response
-			                               , netreq->response_len)
-			    ; rr && _getdns_rr_iter_section(rr)
-			         <= SECTION_ANSWER
-			    ; rr = _getdns_rr_iter_next(rr)) {
+		_getdns_rrset_spc answer;
 
-				if (_getdns_rr_iter_section(rr) !=
-				    SECTION_ANSWER)
-					continue;
-
-				if (gldns_read_uint16(rr->rr_type) !=
-				    GETDNS_RRTYPE_CNAME)
-					continue;
-				
-				owner = _getdns_owner_if_or_as_decompressed(
-				    rr, owner_spc, &owner_len);
-				if (!_getdns_dname_equal(canon, owner))
-					continue;
-
-				if (!(rdf = _getdns_rdf_iter_init(
-				    &rdf_spc, rr)))
-					continue;
-
-				canon = _getdns_rdf_if_or_as_decompressed(
-				    rdf, canon_spc, &canon_len);
-				new_canonical = 1;
-				cnames_followed++;
-			}
-		} while (new_canonical && cnames_followed<MAX_CNAME_REFERRALS);
-		for ( rr = _getdns_rr_iter_init(&rr_spc
-					       , netreq->response
-					       , netreq->response_len)
-		    ; rr && _getdns_rr_iter_section(rr)
-			 <= SECTION_ANSWER
-		    ; rr = _getdns_rr_iter_next(rr)) {
-
-			if (_getdns_rr_iter_section(rr) !=
-			    SECTION_ANSWER)
-				continue;
-
-			if (gldns_read_uint16(rr->rr_type) !=
-			    netreq->request_type)
-				continue;
-			
-			owner = _getdns_owner_if_or_as_decompressed(
-			    rr, owner_spc, &owner_len);
-			if (_getdns_dname_equal(canon, owner))
-				return 0;
-		}
+		if (netreq->response_len > 0 &&
+		    GLDNS_ANCOUNT(netreq->response) > 0 &&
+		    _getdns_rrset_answer(&answer, netreq->response
+		                                , netreq->response_len))
+			return 0;
 	}
 	return 1;
 }
diff --git a/src/rr-iter.c b/src/rr-iter.c
index 999d9607..e6a711de 100644
--- a/src/rr-iter.c
+++ b/src/rr-iter.c
@@ -240,6 +240,62 @@ _getdns_owner_if_or_as_decompressed(_getdns_rr_iter *i,
 	    ff_bytes, len, 0);
 }
 
+_getdns_rrset *
+_getdns_initialized_rrset_answer(_getdns_rrset_spc *query_rrset)
+{
+	_getdns_rrset *rrset = &query_rrset->rrset;
+	uint16_t qtype = rrset->rr_type;
+	size_t cname_loop_protection;
+
+	assert(query_rrset);
+
+	/* Follow CNAMEs */
+	rrset->rr_type = GETDNS_RRTYPE_CNAME;
+	for ( cname_loop_protection = MAX_CNAME_REFERRALS
+	    ; cname_loop_protection > 0
+	    ; cname_loop_protection-- ) {
+		_getdns_rrtype_iter rr_spc, *rr;
+		_getdns_rdf_iter rdf_spc, *rdf;
+
+		if (!(rr = _getdns_rrtype_iter_init(&rr_spc, rrset)))
+			break;
+		if (!(rdf = _getdns_rdf_iter_init(&rdf_spc, &rr->rr_i)))
+			break;
+		query_rrset->name_len = sizeof(query_rrset->name_spc);
+		rrset->name = _getdns_rdf_if_or_as_decompressed(
+		    rdf, query_rrset->name_spc, &query_rrset->name_len);
+	}
+	rrset->rr_type = qtype;
+	if (qtype == GETDNS_RRTYPE_CNAME &&
+	    cname_loop_protection < MAX_CNAME_REFERRALS)
+		return rrset; /* The CNAME was the answer */
+
+	return _getdns_rrset_has_rrs(rrset) ? rrset : NULL;
+}
+
+_getdns_rrset *
+_getdns_rrset_answer(_getdns_rrset_spc *spc, const uint8_t *pkt, size_t len)
+{
+	_getdns_rr_iter rr_spc, *rr;
+
+	assert(spc);
+
+	spc->rrset.name = NULL;
+	spc->name_len = sizeof(spc->name_spc);
+	if (   !(rr = _getdns_rr_iter_init(&rr_spc, pkt, len))
+	    || _getdns_rr_iter_section(rr) != SECTION_QUESTION
+	    || !(spc->rrset.name = _getdns_owner_if_or_as_decompressed(
+			    rr, spc->name_spc, &spc->name_len))
+	    || rr->nxt < rr->rr_type + 4)
+		return NULL;
+
+	spc->rrset.rr_class = rr_iter_class(rr);
+	spc->rrset.rr_type = rr_iter_type(rr);
+	spc->rrset.pkt = pkt;
+	spc->rrset.pkt_len = len;
+	spc->rrset.sections = SECTION_ANSWER;
+	return _getdns_initialized_rrset_answer(spc);
+}
 
 /* Utility function to compare owner name of rr with name */
 static int rr_owner_equal(_getdns_rr_iter *rr, const uint8_t *name)
diff --git a/src/rr-iter.h b/src/rr-iter.h
index d9221df2..d657d484 100644
--- a/src/rr-iter.h
+++ b/src/rr-iter.h
@@ -108,7 +108,6 @@ static inline uint16_t rr_iter_type(_getdns_rr_iter *rr)
 static inline uint16_t rr_iter_class(_getdns_rr_iter *rr)
 { return rr->rr_type + 4 <= rr->nxt ? gldns_read_uint16(rr->rr_type + 2) : 0; }
 
-
 typedef struct _getdns_rrset {
 	const uint8_t  *name;
 	uint16_t        rr_class;
@@ -118,6 +117,18 @@ typedef struct _getdns_rrset {
 	_getdns_section sections;
 } _getdns_rrset;
 
+typedef struct _getdns_rrset_spc {
+	_getdns_rrset rrset;
+	uint8_t       name_spc[256];
+	size_t        name_len;
+} _getdns_rrset_spc;
+
+_getdns_rrset *_getdns_rrset_answer(
+    _getdns_rrset_spc *rrset2init, const uint8_t *pkt, size_t pkt_len);
+
+_getdns_rrset *_getdns_initialized_rrset_answer(
+    _getdns_rrset_spc *query_rrset);
+
 typedef struct _getdns_rrtype_iter {
 	_getdns_rr_iter  rr_i;
 	_getdns_rrset   *rrset;
@@ -164,6 +175,8 @@ _getdns_rrset_iter *_getdns_rrset_iter_init(_getdns_rrset_iter *i,
     const uint8_t *pkt, size_t pkt_len, _getdns_section sections);
 _getdns_rrset_iter *_getdns_rrset_iter_next(_getdns_rrset_iter *i);
 
+
+
 static inline _getdns_rrset *_getdns_rrset_iter_value(_getdns_rrset_iter *i)
 { return i && i->rr_i.pos ? &i->rrset : NULL; }
 
diff --git a/src/util-internal.c b/src/util-internal.c
index 508ff1f4..22a5e0a8 100644
--- a/src/util-internal.c
+++ b/src/util-internal.c
@@ -553,17 +553,16 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
 	size_t bin_size;
 	const uint8_t *bin_data;
 	_getdns_section section;
-	uint8_t canonical_name_space[256], owner_name_space[256],
-	    query_name_space[256];
-	const uint8_t *canonical_name, *owner_name, *query_name;
-	size_t canonical_name_len = sizeof(canonical_name_space),
-	       owner_name_len = sizeof(owner_name_space),
+	uint8_t owner_name_space[256], query_name_space[256];
+	const uint8_t *owner_name, *query_name;
+	size_t owner_name_len = sizeof(owner_name_space),
 	       query_name_len = sizeof(query_name_space);
-	int new_canonical = 0, cnames_followed,
-	    request_answered, all_numeric_label;
+	int all_numeric_label;
 	uint16_t rr_type;
 	getdns_dict *header = NULL;
 	getdns_list *bad_dns = NULL;
+	_getdns_rrset_spc answer_spc;
+	_getdns_rrset *answer;
 
 	if (!result)
 		goto error;
@@ -593,9 +592,6 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
 		goto error;
 	header = NULL;
 
-	canonical_name = req->owner->name;
-	canonical_name_len = req->owner->name_len;
-
 	if (req->query &&
 	    (rr_iter = _getdns_rr_iter_init(&rr_iter_storage, req->query
 	                                   , req->response  - req->query)))
@@ -652,23 +648,6 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
 			goto error;
 		else	rr_dict = NULL;
 
-		if (rr_type == GETDNS_RRTYPE_CNAME) {
-
-			owner_name_len = sizeof(owner_name_space);
-			owner_name = _getdns_owner_if_or_as_decompressed(
-			    rr_iter, owner_name_space, &owner_name_len);
-			if (!_getdns_dname_equal(canonical_name, owner_name))
-				continue;
-
-			if (!(rdf_iter = _getdns_rdf_iter_init(
-			     &rdf_iter_storage, rr_iter)))
-				continue;
-
-			new_canonical = 1;
-			canonical_name = _getdns_rdf_if_or_as_decompressed(
-			    rdf_iter,canonical_name_space,&canonical_name_len);
-			continue;
-		}
 		if (srvs->capacity && rr_type == GETDNS_RRTYPE_SRV) {
 			if (srvs->count >= srvs->capacity &&
 			    !_grow_srvs(&context->mf, srvs))
@@ -724,42 +703,14 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
 	if (getdns_dict_set_int(result, "answer_type", GETDNS_NAMETYPE_DNS))
 		goto error;
 	
-	cnames_followed = new_canonical;
-	while (cnames_followed < MAX_CNAME_REFERRALS && new_canonical) {
-		new_canonical = 0;
+	
+	answer = _getdns_rrset_answer(&answer_spc, req->response
+	                                         , req->response_len);
 
-		for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
-		                                    , req->response
-		                                    , req->response_len)
-		    ; rr_iter && _getdns_rr_iter_section(rr_iter)
-		              <= SECTION_ANSWER
-		    ; rr_iter = _getdns_rr_iter_next(rr_iter)) {
-
-			if (_getdns_rr_iter_section(rr_iter) !=
-			    SECTION_ANSWER)
-				continue;
-
-			if (gldns_read_uint16(rr_iter->rr_type) !=
-			    GETDNS_RRTYPE_CNAME)
-				continue;
-
-			owner_name = _getdns_owner_if_or_as_decompressed(
-			    rr_iter, owner_name_space, &owner_name_len);
-			if (!_getdns_dname_equal(canonical_name, owner_name))
-				continue;
-
-			if (!(rdf_iter = _getdns_rdf_iter_init(
-			     &rdf_iter_storage, rr_iter)))
-				continue;
-
-			canonical_name = _getdns_rdf_if_or_as_decompressed(
-			    rdf_iter,canonical_name_space,&canonical_name_len);
-			new_canonical = 1;
-			cnames_followed++;
-		}
-	}
-	if (_getdns_dict_set_const_bindata(
-	    result, "canonical_name", canonical_name_len, canonical_name))
+	if (answer_spc.rrset.name &&
+	    _getdns_dict_set_const_bindata(result, "canonical_name"
+	                                         , answer_spc.name_len
+	                                         , answer_spc.rrset.name))
 		goto error;
 
 	if (!req->owner->add_warning_for_bad_dns)
@@ -768,35 +719,15 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
 	if (!(bad_dns = getdns_list_create_with_context(context)))
 		goto error;
 
-	if (cnames_followed && req->request_type != GETDNS_RRTYPE_CNAME) {
-		request_answered = 0;
-		for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
-						    , req->response
-						    , req->response_len)
-		    ; rr_iter && _getdns_rr_iter_section(rr_iter)
-			      <= SECTION_ANSWER
-		    ; rr_iter = _getdns_rr_iter_next(rr_iter)) {
+	if (   !answer
+	    && req->request_type != GETDNS_RRTYPE_CNAME
+	    && query_name
+	    && answer_spc.rrset.name
+	    && !_getdns_dname_equal(query_name, answer_spc.rrset.name)
+	    && _getdns_list_append_int(bad_dns
+		    , GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE))
+		goto error;
 
-			if (_getdns_rr_iter_section(rr_iter) !=
-			    SECTION_ANSWER)
-				continue;
-			if (gldns_read_uint16(rr_iter->rr_type) !=
-			    req->request_type)
-				continue;
-
-			owner_name=_getdns_owner_if_or_as_decompressed(
-			    rr_iter, owner_name_space,&owner_name_len);
-			if (_getdns_dname_equal(
-			    canonical_name, owner_name)) {
-				request_answered = 1;
-				break;
-			}
-		}
-		if (!request_answered && 
-		    _getdns_list_append_int(bad_dns,
-		    GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE))
-			goto error;
-	}
 	all_numeric_label = 0;
 	for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
 					    , req->response