Index: /pjproject/trunk/pjlib-util/include/pjlib-util/errno.h
===================================================================
--- /pjproject/trunk/pjlib-util/include/pjlib-util/errno.h	(revision 1355)
+++ /pjproject/trunk/pjlib-util/include/pjlib-util/errno.h	(revision 1356)
@@ -175,4 +175,11 @@
  */
 #define PJLIB_UTIL_EDNSNOANSWERREC  (PJLIB_UTIL_ERRNO_START+47)	/* 320047 */
+/**
+ * @hideinitializer
+ * Invalid DNS answer. This error is raised for example when the DNS
+ * answer does not have a query section, or the type of RR in the answer
+ * doesn't match the query.
+ */
+#define PJLIB_UTIL_EDNSINANSWER	    (PJLIB_UTIL_ERRNO_START+48)	/* 320048 */
 
 
Index: /pjproject/trunk/pjlib-util/include/pjlib-util/resolver.h
===================================================================
--- /pjproject/trunk/pjlib-util/include/pjlib-util/resolver.h	(revision 1355)
+++ /pjproject/trunk/pjlib-util/include/pjlib-util/resolver.h	(revision 1356)
@@ -197,4 +197,31 @@
     unsigned	bad_ns_ttl;	/**< See #PJ_DNS_RESOLVER_BAD_NS_TTL	    */
 } pj_dns_settings;
+
+
+/**
+ * This structure represents DNS A record, as the result of parsing
+ * DNS response packet using #pj_dns_parse_a_response().
+ */
+typedef struct pj_dns_a_record
+{
+    /** The target name being queried.   */
+    pj_str_t		name;
+
+    /** If target name corresponds to a CNAME entry, the alias contains
+     *  the value of the CNAME entry, otherwise it will be empty.
+     */
+    pj_str_t		alias;
+
+    /** Number of IP addresses. */
+    unsigned		addr_count;
+
+    /** IP addresses of the host found in the response */
+    pj_in_addr		addr[PJ_DNS_MAX_IP_IN_A_REC];
+
+    /** Internal buffer for hostname and alias. */
+    char		buf_[128];
+
+} pj_dns_a_record;
+
 
 /**
@@ -366,4 +393,17 @@
 						  pj_bool_t notify);
 
+/**
+ * A utility function to parse a DNS response containing A records into 
+ * DNS A record.
+ *
+ * @param pkt	    The DNS response packet.
+ * @param rec	    The structure to be initialized with the parsed
+ *		    DNS A record from the packet.
+ *
+ * @return	    PJ_SUCCESS if response can be parsed successfully.
+ */
+PJ_DECL(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
+					     pj_dns_a_record *rec);
+
 
 /**
Index: /pjproject/trunk/pjlib-util/src/pjlib-util/errno.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/errno.c	(revision 1355)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/errno.c	(revision 1356)
@@ -59,4 +59,5 @@
     PJ_BUILD_ERR( PJLIB_UTIL_EDNSNOWORKINGNS,	"No working DNS nameserver"),
     PJ_BUILD_ERR( PJLIB_UTIL_EDNSNOANSWERREC,	"No answer record in the DNS response"),
+    PJ_BUILD_ERR( PJLIB_UTIL_EDNSINANSWER,	"Invalid DNS answer"),
 
     PJ_BUILD_ERR( PJLIB_UTIL_EDNS_FORMERR,	"DNS \"Format error\""),
Index: /pjproject/trunk/pjlib-util/src/pjlib-util/resolver.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/resolver.c	(revision 1355)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/resolver.c	(revision 1356)
@@ -425,4 +425,5 @@
 
     PJ_ASSERT_RETURN(resolver && count && servers, PJ_EINVAL);
+    PJ_ASSERT_RETURN(count < PJ_DNS_RESOLVER_MAX_NS, PJ_EINVAL);
 
     pj_mutex_lock(resolver->mutex);
@@ -801,4 +802,101 @@
 }
 
+
+/* 
+ * DNS response containing A packet. 
+ */
+PJ_DEF(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
+					    pj_dns_a_record *rec)
+{
+    pj_str_t hostname, alias, *res_name;
+    unsigned bufstart = 0;
+    unsigned bufleft = sizeof(rec->buf_);
+    unsigned i, ansidx;
+
+    PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL);
+
+    /* Init the record */
+    pj_bzero(rec, sizeof(pj_dns_a_record));
+
+    /* Return error if there's error in the packet. */
+    if (PJ_DNS_GET_RCODE(pkt->hdr.flags))
+	return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags));
+
+    /* Return error if there's no query section */
+    if (pkt->hdr.qdcount == 0)
+	return PJLIB_UTIL_EDNSINANSWER;
+
+    /* Return error if there's no answer */
+    if (pkt->hdr.anscount == 0)
+	return PJLIB_UTIL_EDNSNOANSWERREC;
+
+    /* Get the hostname from the query. */
+    hostname = pkt->q[0].name;
+
+    /* Copy hostname to the record */
+    if (hostname.slen > (int)bufleft) {
+	return PJ_ENAMETOOLONG;
+    }
+
+    pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen);
+    rec->name.ptr = &rec->buf_[bufstart];
+    rec->name.slen = hostname.slen;
+
+    bufstart += hostname.slen;
+    bufleft -= hostname.slen;
+
+    /* Find the first RR which name matches the hostname */
+    for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) {
+	if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0)
+	    break;
+    }
+
+    if (ansidx == pkt->hdr.anscount)
+	return PJLIB_UTIL_EDNSNOANSWERREC;
+
+    /* If hostname is a CNAME, get the alias. */
+    if (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME) {
+	alias = pkt->ans[ansidx].rdata.cname.name;
+	res_name = &alias;
+    } else if (pkt->ans[ansidx].type == PJ_DNS_TYPE_A) {
+	alias.ptr = NULL;
+	alias.slen = 0;
+	res_name = &hostname;
+    } else {
+	return PJLIB_UTIL_EDNSINANSWER;
+    }
+
+    /* Copy alias to the record, if present. */
+    if (alias.slen) {
+	if (alias.slen > (int)bufleft)
+	    return PJ_ENAMETOOLONG;
+
+	pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen);
+	rec->alias.ptr = &rec->buf_[bufstart];
+	rec->alias.slen = alias.slen;
+
+	bufstart += alias.slen;
+	bufleft -= alias.slen;
+    }
+
+    /* Now scan the answer for all type A RRs where the name matches
+     * hostname or alias.
+     */
+    for (i=0; i<pkt->hdr.anscount; ++i) {
+	if (pkt->ans[i].type == PJ_DNS_TYPE_A &&
+	    pj_stricmp(&pkt->ans[i].name, res_name)==0 &&
+	    rec->addr_count < PJ_DNS_MAX_IP_IN_A_REC)
+	{
+	    rec->addr[rec->addr_count].s_addr = 
+		pkt->ans[i].rdata.a.ip_addr.s_addr;
+	    ++rec->addr_count;
+	}
+    }
+
+    if (rec->addr_count == 0)
+	return PJLIB_UTIL_EDNSNOANSWERREC;
+
+    return PJ_SUCCESS;
+}
 
 
@@ -1031,6 +1129,8 @@
 
     /* Duplicate the packet.
-     * We don't need to keep the query, NS, and AR sections from the packet,
-     * so exclude from duplication.
+     * We don't need to keep the NS and AR sections from the packet,
+     * so exclude from duplication. We do need to keep the Query
+     * section since DNS A parser needs the query section to know
+     * the name being requested.
      */
     res_pool = pj_pool_create_on_buf("respool", cache->buf, sizeof(cache->buf));
@@ -1038,5 +1138,5 @@
 	cache->pkt = NULL;
 	pj_dns_packet_dup(res_pool, pkt, 
-			  PJ_DNS_NO_QD | PJ_DNS_NO_NS | PJ_DNS_NO_AR,
+			  PJ_DNS_NO_NS | PJ_DNS_NO_AR,
 			  &cache->pkt);
     }
