1diff --git a/src/lib/ares_process.c b/src/lib/ares_process.c 2index 605e5f8..f07d7b3 100644 3--- a/src/lib/ares_process.c 4+++ b/src/lib/ares_process.c 5@@ -579,6 +579,12 @@ static void process_answer(ares_channel channel, unsigned char *abuf, 6 struct query *query; 7 struct list_node* list_head; 8 struct list_node* list_node; 9+ int rr_type, rr_class, rr_len, status; 10+ const unsigned char *aptr; 11+ unsigned int qdcount, ancount, i; 12+ char *hostname = NULL, *rr_name = NULL; 13+ long len; 14+ int acount = 0; 15 16 /* If there's no room in the answer for a header, we can't do much 17 * with it. */ 18@@ -590,6 +596,14 @@ static void process_answer(ares_channel channel, unsigned char *abuf, 19 tc = DNS_HEADER_TC(abuf); 20 rcode = DNS_HEADER_RCODE(abuf); 21 22+ /* Fetch the question and answer count from the header. */ 23+ qdcount = DNS_HEADER_QDCOUNT(abuf); 24+ ancount = DNS_HEADER_ANCOUNT(abuf); 25+ if (qdcount != 1) 26+ return; 27+ if (ancount == 0) 28+ return; 29+ 30 /* Find the query corresponding to this packet. The queries are 31 * hashed/bucketed by query id, so this lookup should be quick. Note that 32 * both the query id and the questions must be the same; when the query id 33@@ -654,12 +668,78 @@ static void process_answer(ares_channel channel, unsigned char *abuf, 34 if (alen > packetsz && !tcp) 35 alen = packetsz; 36 37+ /* Parse the RR name. */ 38+ aptr = abuf + HFIXEDSZ; 39+ status = ares_expand_name(aptr, abuf, alen, &hostname, &len); 40+ if (status != ARES_SUCCESS) 41+ return; 42+ 43+ /* Make sure there is enough data after the RR name for the fixed 44+ * part of the RR. 45+ */ 46+ if (aptr + RRFIXEDSZ > abuf + alen) 47+ { 48+ ares_free_string(hostname); 49+ return; 50+ } 51+ aptr += len + QFIXEDSZ; 52+ 53+ /* Examine each answer resource record (RR) in turn. */ 54+ for (i = 0; i < ancount; i++) 55+ { 56+ /* Decode the RR up to the data field. */ 57+ status = ares_expand_name(aptr, abuf, alen, &rr_name, &len); 58+ if (status != ARES_SUCCESS) 59+ { 60+ break; 61+ } 62+ aptr += len; 63+ if (aptr + RRFIXEDSZ > abuf + alen) 64+ { 65+ status = ARES_EBADRESP; 66+ break; 67+ } 68+ rr_type = DNS_RR_TYPE(aptr); 69+ rr_class = DNS_RR_CLASS(aptr); 70+ rr_len = DNS_RR_LEN(aptr); 71+ aptr += RRFIXEDSZ; 72+ if (aptr + rr_len > abuf + alen) 73+ { 74+ status = ARES_EBADRESP; 75+ break; 76+ } 77+ 78+ /* Check if we are really looking at a CAA record */ 79+ if ((rr_class == C_IN || rr_class == C_CHAOS) && (rr_type == T_A || rr_type == T_AAAA)) 80+ { 81+ acount++; 82+ } 83+ 84+ /* Propagate any failures */ 85+ if (status != ARES_SUCCESS) 86+ { 87+ break; 88+ } 89+ 90+ /* Don't lose memory in the next iteration */ 91+ ares_free(rr_name); 92+ rr_name = NULL; 93+ 94+ /* Move on to the next record */ 95+ aptr += rr_len; 96+ } 97+ 98+ if (hostname) 99+ ares_free(hostname); 100+ if (rr_name) 101+ ares_free(rr_name); 102+ 103 /* If we aren't passing through all error packets, discard packets 104 * with SERVFAIL, NOTIMP, or REFUSED response codes. 105 */ 106 if (!(channel->flags & ARES_FLAG_NOCHECKRESP)) 107 { 108- if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED) 109+ if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED || acount == 0) 110 { 111 skip_server(channel, query, whichserver); 112 if (query->server == whichserver) 113