Merge "Support variety of IPv6 addresses on RDNS-on-cache"
diff --git a/Android.bp b/Android.bp
index 625e7c8..b646def 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,7 @@
         "res_query.cpp",
         "res_send.cpp",
         "res_stats.cpp",
+        "util.cpp",
         "Dns64Configuration.cpp",
         "DnsProxyListener.cpp",
         "DnsResolver.cpp",
diff --git a/DnsProxyListener.cpp b/DnsProxyListener.cpp
index 74eb793..bb8251c 100644
--- a/DnsProxyListener.cpp
+++ b/DnsProxyListener.cpp
@@ -74,10 +74,6 @@
 // Limits the number of outstanding DNS queries by client UID.
 constexpr int MAX_QUERIES_PER_UID = 256;
 
-// Max packet size for answer, sync with getaddrinfo.c
-// TODO: switch to dynamically allocated buffers with std::vector
-constexpr int MAXPACKET = 8 * 1024;
-
 android::netdutils::OperationLimiter<uid_t> queryLimiter(MAX_QUERIES_PER_UID);
 
 void logArguments(int argc, char** argv) {
@@ -886,12 +882,13 @@
 
     // Send DNS query
     std::vector<uint8_t> ansBuf(MAXPACKET, 0);
-    int arcode, nsendAns = -1;
+    int rcode = ns_r_noerror;
+    int nsendAns = -1;
     NetworkDnsEventReported event;
     initDnsEvent(&event);
     if (queryLimiter.start(uid)) {
         nsendAns = resolv_res_nsend(&mNetContext, msg.data(), msgLen, ansBuf.data(), MAXPACKET,
-                                    &arcode, static_cast<ResNsendFlags>(mFlags), &event);
+                                    &rcode, static_cast<ResNsendFlags>(mFlags), &event);
         queryLimiter.finish(uid);
     } else {
         LOG(WARNING) << "ResNSendHandler::run: resnsend: from UID " << uid
@@ -909,13 +906,13 @@
         sendBE32(mClient, nsendAns);
         if (rr_type == ns_t_a || rr_type == ns_t_aaaa) {
             reportDnsEvent(INetdEventListener::EVENT_RES_NSEND, mNetContext, latencyUs,
-                           resNSendToAiError(nsendAns, arcode), event, rr_name);
+                           resNSendToAiError(nsendAns, rcode), event, rr_name);
         }
         return;
     }
 
     // Send rcode
-    if (!sendBE32(mClient, arcode)) {
+    if (!sendBE32(mClient, rcode)) {
         PLOG(WARNING) << "ResNSendHandler::run: resnsend: failed to send rcode to uid " << uid;
         return;
     }
@@ -932,7 +929,7 @@
         const int total_ip_addr_count =
                 extractResNsendAnswers((uint8_t*) ansBuf.data(), nsendAns, rr_type, &ip_addrs);
         reportDnsEvent(INetdEventListener::EVENT_RES_NSEND, mNetContext, latencyUs,
-                       resNSendToAiError(nsendAns, arcode), event, rr_name, ip_addrs,
+                       resNSendToAiError(nsendAns, rcode), event, rr_name, ip_addrs,
                        total_ip_addr_count);
     }
 }
diff --git a/getaddrinfo.cpp b/getaddrinfo.cpp
index a9550b0..6e2376b 100644
--- a/getaddrinfo.cpp
+++ b/getaddrinfo.cpp
@@ -108,20 +108,13 @@
 };
 
 #define PTON_MAX 16
-#define MAXPACKET (8 * 1024)
-
-typedef union {
-    HEADER hdr;
-    uint8_t buf[MAXPACKET];
-} querybuf;
 
 struct res_target {
     struct res_target* next;
-    const char* name;  /* domain name */
-    int qclass, qtype; /* class and type of query */
-    uint8_t* answer;   /* buffer to put answer */
-    int anslen;        /* size of answer buffer */
-    int n;             /* result length */
+    const char* name;                                                  // domain name
+    int qclass, qtype;                                                 // class and type of query
+    std::vector<uint8_t> answer = std::vector<uint8_t>(MAXPACKET, 0);  // buffer to put answer
+    int n = 0;                                                         // result length
 };
 
 static int str2number(const char*);
@@ -139,8 +132,8 @@
 static const struct afd* find_afd(int);
 static int ip6_str2scopeid(const char*, struct sockaddr_in6*, uint32_t*);
 
-static struct addrinfo* getanswer(const querybuf*, int, const char*, int, const struct addrinfo*,
-                                  int* herrno);
+static struct addrinfo* getanswer(const std::vector<uint8_t>&, int, const char*, int,
+                                  const struct addrinfo*, int* herrno);
 static int dns_getaddrinfo(const char* name, const addrinfo* pai,
                            const android_net_context* netcontext, addrinfo** rv,
                            NetworkDnsEventReported* event);
@@ -838,8 +831,8 @@
         }                            \
     } while (0)
 
-static struct addrinfo* getanswer(const querybuf* answer, int anslen, const char* qname, int qtype,
-                                  const struct addrinfo* pai, int* herrno) {
+static struct addrinfo* getanswer(const std::vector<uint8_t>& answer, int anslen, const char* qname,
+                                  int qtype, const struct addrinfo* pai, int* herrno) {
     struct addrinfo sentinel = {};
     struct addrinfo *cur;
     struct addrinfo ai;
@@ -856,14 +849,13 @@
     int (*name_ok)(const char*);
     char hostbuf[8 * 1024];
 
-    assert(answer != NULL);
     assert(qname != NULL);
     assert(pai != NULL);
 
     cur = &sentinel;
 
     canonname = NULL;
-    eom = answer->buf + anslen;
+    eom = answer.data() + anslen;
     switch (qtype) {
         case T_A:
         case T_AAAA:
@@ -876,18 +868,18 @@
     /*
      * find first satisfactory answer
      */
-    hp = &answer->hdr;
+    hp = reinterpret_cast<const HEADER*>(answer.data());
     ancount = ntohs(hp->ancount);
     qdcount = ntohs(hp->qdcount);
     bp = hostbuf;
     ep = hostbuf + sizeof hostbuf;
-    cp = answer->buf;
+    cp = answer.data();
     BOUNDED_INCR(HFIXEDSZ);
     if (qdcount != 1) {
         *herrno = NO_RECOVERY;
         return (NULL);
     }
-    n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+    n = dn_expand(answer.data(), eom, cp, bp, ep - bp);
     if ((n < 0) || !(*name_ok)(bp)) {
         *herrno = NO_RECOVERY;
         return (NULL);
@@ -911,7 +903,7 @@
     haveanswer = 0;
     had_error = 0;
     while (ancount-- > 0 && cp < eom && !had_error) {
-        n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+        n = dn_expand(answer.data(), eom, cp, bp, ep - bp);
         if ((n < 0) || !(*name_ok)(bp)) {
             had_error++;
             continue;
@@ -931,7 +923,7 @@
             continue; /* XXX - had_error++ ? */
         }
         if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && type == T_CNAME) {
-            n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
+            n = dn_expand(answer.data(), eom, cp, tbuf, sizeof tbuf);
             if ((n < 0) || !(*name_ok)(tbuf)) {
                 had_error++;
                 continue;
@@ -1397,16 +1389,11 @@
     res_target q = {};
     res_target q2 = {};
 
-    auto buf = std::make_unique<querybuf>();
-    auto buf2 = std::make_unique<querybuf>();
-
     switch (pai->ai_family) {
         case AF_UNSPEC: {
             /* prefer IPv6 */
             q.name = name;
             q.qclass = C_IN;
-            q.answer = buf->buf;
-            q.anslen = sizeof(buf->buf);
             int query_ipv6 = 1, query_ipv4 = 1;
             if (pai->ai_flags & AI_ADDRCONFIG) {
                 query_ipv6 = have_ipv6(netcontext->app_mark, netcontext->uid);
@@ -1419,8 +1406,6 @@
                     q2.name = name;
                     q2.qclass = C_IN;
                     q2.qtype = T_A;
-                    q2.answer = buf2->buf;
-                    q2.anslen = sizeof(buf2->buf);
                 }
             } else if (query_ipv4) {
                 q.qtype = T_A;
@@ -1433,15 +1418,11 @@
             q.name = name;
             q.qclass = C_IN;
             q.qtype = T_A;
-            q.answer = buf->buf;
-            q.anslen = sizeof(buf->buf);
             break;
         case AF_INET6:
             q.name = name;
             q.qclass = C_IN;
             q.qtype = T_AAAA;
-            q.answer = buf->buf;
-            q.anslen = sizeof(buf->buf);
             break;
         default:
             return EAI_FAMILY;
@@ -1460,13 +1441,13 @@
 
     addrinfo sentinel = {};
     addrinfo* cur = &sentinel;
-    addrinfo* ai = getanswer(buf.get(), q.n, q.name, q.qtype, pai, &he);
+    addrinfo* ai = getanswer(q.answer, q.n, q.name, q.qtype, pai, &he);
     if (ai) {
         cur->ai_next = ai;
         while (cur && cur->ai_next) cur = cur->ai_next;
     }
     if (q.next) {
-        ai = getanswer(buf2.get(), q2.n, q2.name, q2.qtype, pai, &he);
+        ai = getanswer(q2.answer, q2.n, q2.name, q2.qtype, pai, &he);
         if (ai) cur->ai_next = ai;
     }
     if (sentinel.ai_next == NULL) {
@@ -1578,7 +1559,6 @@
  */
 static int res_queryN(const char* name, res_target* target, res_state res, int* herrno) {
     uint8_t buf[MAXPACKET];
-    HEADER* hp;
     int n;
     struct res_target* t;
     int rcode;
@@ -1591,10 +1571,7 @@
     ancount = 0;
 
     for (t = target; t; t = t->next) {
-        uint8_t* answer;
-        int anslen;
-
-        hp = (HEADER*) (void*) t->answer;
+        HEADER* hp = (HEADER*)(void*)t->answer.data();
         bool retried = false;
     again:
         hp->rcode = NOERROR; /* default */
@@ -1602,8 +1579,7 @@
         /* make it easier... */
         int cl = t->qclass;
         int type = t->qtype;
-        answer = t->answer;
-        anslen = t->anslen;
+        const int anslen = t->answer.size();
 
         LOG(DEBUG) << __func__ << ": (" << cl << ", " << type << ")";
 
@@ -1620,7 +1596,7 @@
             return n;
         }
 
-        n = res_nsend(res, buf, n, answer, anslen, &rcode, 0);
+        n = res_nsend(res, buf, n, t->answer.data(), anslen, &rcode, 0);
         if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
             // Record rcode from DNS response header only if no timeout.
             // Keep rcode timeout for reporting later if any.
@@ -1689,7 +1665,7 @@
     assert(name != NULL);
     assert(target != NULL);
 
-    hp = (HEADER*) (void*) target->answer; /*XXX*/
+    hp = (HEADER*)(void*)target->answer.data();
 
     errno = 0;
     *herrno = HOST_NOT_FOUND; /* default, if we never query */
@@ -1721,7 +1697,7 @@
          * the domain stuff is tried.  Will have a better
          * fix after thread pools are used.
          */
-        _resolv_populate_res_for_net(res);
+        resolv_populate_res_for_net(res);
 
         for (const auto& domain : res->search_domains) {
             ret = res_querydomainN(name, domain.c_str(), target, res, herrno);
diff --git a/gethnamaddr.cpp b/gethnamaddr.cpp
index 2a8c92b..6dcd358 100644
--- a/gethnamaddr.cpp
+++ b/gethnamaddr.cpp
@@ -95,8 +95,6 @@
 #define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
 #define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
 
-#define MAXPACKET (8 * 1024)
-
 constexpr int MAXADDRS = 35;
 
 typedef union {
diff --git a/res_cache.cpp b/res_cache.cpp
index e14ccfb..68affe0 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -61,10 +61,14 @@
 #include "DnsStats.h"
 #include "res_debug.h"
 #include "resolv_private.h"
+#include "util.h"
 
 using android::base::StringAppendF;
 using android::net::DnsQueryEvent;
 using android::net::DnsStats;
+using android::net::PROTO_DOT;
+using android::net::PROTO_TCP;
+using android::net::PROTO_UDP;
 using android::netdutils::DumpWriter;
 using android::netdutils::IPSockAddr;
 
@@ -936,7 +940,7 @@
     struct resolv_cache_info* next;
     int nscount;
     std::vector<std::string> nameservers;
-    struct addrinfo* nsaddrinfo[MAXNS];  // TODO: Use struct sockaddr_storage.
+    std::vector<IPSockAddr> nameserverSockAddrs;
     int revision_id;  // # times the nameservers have been replaced
     res_params params;
     struct res_stats nsstats[MAXNS];
@@ -1566,6 +1570,21 @@
     return res;
 }
 
+bool isValidServer(const std::string& server) {
+    const addrinfo hints = {
+            .ai_family = AF_UNSPEC,
+            .ai_socktype = SOCK_DGRAM,
+    };
+    addrinfo* result = nullptr;
+    if (int err = getaddrinfo_numeric(server.c_str(), "53", hints, &result); err != 0) {
+        LOG(WARNING) << __func__ << ": getaddrinfo_numeric(" << server
+                     << ") = " << gai_strerror(err);
+        return false;
+    }
+    freeaddrinfo(result);
+    return true;
+}
+
 }  // namespace
 
 int resolv_set_nameservers(unsigned netid, const std::vector<std::string>& servers,
@@ -1577,24 +1596,11 @@
 
     // Parse the addresses before actually locking or changing any state, in case there is an error.
     // As a side effect this also reduces the time the lock is kept.
-    // TODO: find a better way to replace addrinfo*, something like std::vector<SafeAddrinfo>
-    addrinfo* nsaddrinfo[MAXNS];
-    for (int i = 0; i < numservers; i++) {
-        // The addrinfo structures allocated here are freed in free_nameservers_locked().
-        const addrinfo hints = {
-                .ai_flags = AI_NUMERICHOST,
-                .ai_family = AF_UNSPEC,
-                .ai_socktype = SOCK_DGRAM,
-        };
-        const int rt = getaddrinfo_numeric(nameservers[i].c_str(), "53", hints, &nsaddrinfo[i]);
-        if (rt != 0) {
-            for (int j = 0; j < i; j++) {
-                freeaddrinfo(nsaddrinfo[j]);
-            }
-            LOG(INFO) << __func__ << ": getaddrinfo_numeric(" << nameservers[i]
-                      << ") = " << gai_strerror(rt);
-            return -EINVAL;
-        }
+    std::vector<IPSockAddr> ipSockAddrs;
+    ipSockAddrs.reserve(nameservers.size());
+    for (const auto& server : nameservers) {
+        if (!isValidServer(server)) return -EINVAL;
+        ipSockAddrs.push_back(IPSockAddr::toIPSockAddr(server, 53));
     }
 
     std::lock_guard guard(cache_mutex);
@@ -1610,10 +1616,10 @@
         free_nameservers_locked(cache_info);
         cache_info->nameservers = std::move(nameservers);
         for (int i = 0; i < numservers; i++) {
-            cache_info->nsaddrinfo[i] = nsaddrinfo[i];
             LOG(INFO) << __func__ << ": netid = " << netid
                       << ", addr = " << cache_info->nameservers[i];
         }
+        cache_info->nameserverSockAddrs = std::move(ipSockAddrs);
         cache_info->nscount = numservers;
     } else {
         if (cache_info->params.max_samples != old_max_samples) {
@@ -1624,23 +1630,15 @@
             // under which servers are considered usable.
             res_cache_clear_stats_locked(cache_info);
         }
-        for (int j = 0; j < numservers; j++) {
-            freeaddrinfo(nsaddrinfo[j]);
-        }
     }
 
     // Always update the search paths. Cache-flushing however is not necessary,
     // since the stored cache entries do contain the domain, not just the host name.
     cache_info->search_domains = filter_domains(domains);
 
-    std::vector<IPSockAddr> serverSockAddrs;
-    serverSockAddrs.reserve(cache_info->nameservers.size());
-    for (const auto& server : cache_info->nameservers) {
-        serverSockAddrs.push_back(IPSockAddr::toIPSockAddr(server, 53));
-    }
-
-    if (!cache_info->dnsStats->setServers(serverSockAddrs, android::net::PROTO_TCP) ||
-        !cache_info->dnsStats->setServers(serverSockAddrs, android::net::PROTO_UDP)) {
+    // Setup stats for cleartext dns servers.
+    if (!cache_info->dnsStats->setServers(cache_info->nameserverSockAddrs, PROTO_TCP) ||
+        !cache_info->dnsStats->setServers(cache_info->nameserverSockAddrs, PROTO_UDP)) {
         LOG(WARNING) << __func__ << ": netid = " << netid << ", failed to set dns stats";
         return -EINVAL;
     }
@@ -1662,44 +1660,38 @@
 }
 
 static void free_nameservers_locked(resolv_cache_info* cache_info) {
-    int i;
-    for (i = 0; i < cache_info->nscount; i++) {
-        cache_info->nameservers.clear();
-        if (cache_info->nsaddrinfo[i] != nullptr) {
-            freeaddrinfo(cache_info->nsaddrinfo[i]);
-            cache_info->nsaddrinfo[i] = nullptr;
-        }
-    }
     cache_info->nscount = 0;
+    cache_info->nameservers.clear();
+    cache_info->nameserverSockAddrs.clear();
     res_cache_clear_stats_locked(cache_info);
 }
 
-void _resolv_populate_res_for_net(res_state statp) {
-    if (statp == NULL) {
+void resolv_populate_res_for_net(ResState* statp) {
+    if (statp == nullptr) {
         return;
     }
     LOG(INFO) << __func__ << ": netid=" << statp->netid;
 
     std::lock_guard guard(cache_mutex);
     resolv_cache_info* info = find_cache_info_locked(statp->netid);
-    if (info != NULL) {
-        int nserv;
-        struct addrinfo* ai;
-        for (nserv = 0; nserv < MAXNS; nserv++) {
-            ai = info->nsaddrinfo[nserv];
-            if (ai == NULL) {
-                break;
-            }
+    if (info == nullptr) return;
 
-            if ((size_t)ai->ai_addrlen <= sizeof(statp->nsaddrs[0])) {
-                memcpy(&statp->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
-            } else {
-                LOG(INFO) << __func__ << ": found too long addrlen";
-            }
+    // TODO: Convert nsaddrs[] to c++ container and remove the size-checking.
+    const int serverNum = std::min(MAXNS, static_cast<int>(info->nameserverSockAddrs.size()));
+
+    for (int nserv = 0; nserv < serverNum; nserv++) {
+        sockaddr_storage ss = info->nameserverSockAddrs.at(nserv);
+
+        if (auto sockaddr_len = sockaddrSize(ss); sockaddr_len != 0) {
+            memcpy(&statp->nsaddrs[nserv], &ss, sockaddr_len);
+        } else {
+            LOG(WARNING) << __func__ << ": can't get sa_len from "
+                         << info->nameserverSockAddrs.at(nserv);
         }
-        statp->nscount = nserv;
-        statp->search_domains = info->search_domains;
     }
+
+    statp->nscount = serverNum;
+    statp->search_domains = info->search_domains;
 }
 
 /* Resolver reachability statistics. */
@@ -1748,31 +1740,18 @@
             return -1;
         }
         int i;
-        for (i = 0; i < info->nscount; i++) {
-            // Verify that the following assumptions are held, failure indicates corruption:
-            //  - getaddrinfo() may never return a sockaddr > sockaddr_storage
-            //  - all addresses are valid
-            //  - there is only one address per addrinfo thanks to numeric resolution
-            int addrlen = info->nsaddrinfo[i]->ai_addrlen;
-            if (addrlen < (int) sizeof(struct sockaddr) || addrlen > (int) sizeof(servers[0])) {
-                LOG(INFO) << __func__ << ": nsaddrinfo[" << i << "].ai_addrlen == " << addrlen;
-                errno = EMSGSIZE;
-                return -1;
-            }
-            if (info->nsaddrinfo[i]->ai_addr == NULL) {
-                LOG(INFO) << __func__ << ": nsaddrinfo[" << i << "].ai_addr == NULL";
-                errno = ENOENT;
-                return -1;
-            }
-            if (info->nsaddrinfo[i]->ai_next != NULL) {
-                LOG(INFO) << __func__ << ": nsaddrinfo[" << i << "].ai_next != NULL";
-                errno = ENOTUNIQ;
-                return -1;
-            }
-        }
         *nscount = info->nscount;
+
+        // It shouldn't happen, but just in case of buffer overflow.
+        if (info->nscount != static_cast<int>(info->nameserverSockAddrs.size())) {
+            LOG(INFO) << __func__ << ": nscount " << info->nscount
+                      << " != " << info->nameserverSockAddrs.size();
+            errno = EFAULT;
+            return -1;
+        }
+
         for (i = 0; i < info->nscount; i++) {
-            memcpy(&servers[i], info->nsaddrinfo[i]->ai_addr, info->nsaddrinfo[i]->ai_addrlen);
+            servers[i] = info->nameserverSockAddrs.at(i);
             stats[i] = info->nsstats[i];
         }
 
diff --git a/res_init.cpp b/res_init.cpp
index e15127f..16fd98c 100644
--- a/res_init.cpp
+++ b/res_init.cpp
@@ -112,7 +112,7 @@
     }
 
     // The following dummy initialization is probably useless because
-    // it's overwritten later by _resolv_populate_res_for_net().
+    // it's overwritten later by resolv_populate_res_for_net().
     // TODO: check if it's safe to remove.
     const sockaddr_union u{
             .sin.sin_addr.s_addr = INADDR_ANY,
diff --git a/res_query.cpp b/res_query.cpp
index 43c81fa..7702b44 100644
--- a/res_query.cpp
+++ b/res_query.cpp
@@ -89,12 +89,6 @@
 #include "resolv_cache.h"
 #include "resolv_private.h"
 
-#if PACKETSZ > 1024
-#define MAXPACKET PACKETSZ
-#else
-#define MAXPACKET 1024
-#endif
-
 /*
  * Formulate a normal query, send, and await answer.
  * Returned answer is placed in supplied buffer "answer".
@@ -256,7 +250,7 @@
          * be loaded once for the thread instead of each
          * time a query is tried.
          */
-        _resolv_populate_res_for_net(statp);
+        resolv_populate_res_for_net(statp);
 
         for (const auto& domain : statp->search_domains) {
             if (domain == "." || domain == "") ++root_on_list;
diff --git a/res_send.cpp b/res_send.cpp
index 2fba22c..ef86d0c 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -83,7 +83,6 @@
 
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
-#include <netinet/in.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -110,6 +109,7 @@
 #include "res_init.h"
 #include "resolv_cache.h"
 #include "stats.pb.h"
+#include "util.h"
 
 // TODO: use the namespace something like android::netd_resolv for libnetd_resolv
 using android::net::CacheStatus;
@@ -136,7 +136,6 @@
 
 static DnsTlsDispatcher sDnsTlsDispatcher;
 
-static int get_salen(const struct sockaddr*);
 static struct sockaddr* get_nsaddr(res_state, size_t);
 static int send_vc(res_state, res_params* params, const uint8_t*, int, uint8_t*, int, int*, int,
                    time_t*, int*, int*);
@@ -226,15 +225,6 @@
     return tsnow;
 }
 
-static struct iovec evConsIovec(void* buf, size_t cnt) {
-    struct iovec ret;
-
-    memset(&ret, 0xf5, sizeof ret);
-    ret.iov_base = buf;
-    ret.iov_len = cnt;
-    return ret;
-}
-
 // END: Code copied from ISC eventlib
 
 /* BIONIC-BEGIN: implement source port randomization */
@@ -436,7 +426,7 @@
     } else if (cache_status != RESOLV_CACHE_UNSUPPORTED) {
         // had a cache miss for a known network, so populate the thread private
         // data so the normal resolve path can do its thing
-        _resolv_populate_res_for_net(statp);
+        resolv_populate_res_for_net(statp);
     }
     if (statp->nscount == 0) {
         // We have no nameservers configured, so there's no point trying.
@@ -449,6 +439,25 @@
         return -ESRCH;
     }
 
+    // DoT
+    if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) {
+        bool fallback = false;
+        resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen), Slice(ans, anssiz),
+                               rcode, &fallback);
+        if (resplen > 0) {
+            LOG(DEBUG) << __func__ << ": got answer from DoT";
+            res_pquery(ans, resplen);
+            if (cache_status == RESOLV_CACHE_NOTFOUND) {
+                resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
+            }
+            return resplen;
+        }
+        if (!fallback) {
+            _resolv_cache_query_failed(statp->netid, buf, buflen, flags);
+            return -terrno;
+        }
+    }
+
     res_stats stats[MAXNS];
     res_params params;
     int revision_id = resolv_cache_get_resolver_stats(statp->netid, &params, stats);
@@ -483,31 +492,9 @@
             int delay = 0;
             *rcode = RCODE_INTERNAL_ERROR;
             const sockaddr* nsap = get_nsaddr(statp, ns);
-            nsaplen = get_salen(nsap);
+            nsaplen = sockaddrSize(nsap);
 
         same_ns:
-            // TODO: Since we expect there is only one DNS server being queried here while this
-            // function tries to query all of private DNS servers. Consider moving it to other
-            // reasonable place. In addition, maybe add stats for private DNS.
-            if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) {
-                bool fallback = false;
-                resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen),
-                                       Slice(ans, anssiz), rcode, &fallback);
-                if (resplen > 0) {
-                    LOG(DEBUG) << __func__ << ": got answer from DoT";
-                    res_pquery(ans, resplen);
-                    if (cache_status == RESOLV_CACHE_NOTFOUND) {
-                        resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
-                    }
-                    return resplen;
-                }
-                if (!fallback) {
-                    _resolv_cache_query_failed(statp->netid, buf, buflen, flags);
-                    res_nclose(statp);
-                    return -terrno;
-                }
-            }
-
             static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
             char abuf[NI_MAXHOST];
             DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event);
@@ -625,15 +612,6 @@
 
 /* Private */
 
-static int get_salen(const struct sockaddr* sa) {
-    if (sa->sa_family == AF_INET)
-        return (sizeof(struct sockaddr_in));
-    else if (sa->sa_family == AF_INET6)
-        return (sizeof(struct sockaddr_in6));
-    else
-        return (0); /* unknown, die on connect */
-}
-
 static struct sockaddr* get_nsaddr(res_state statp, size_t n) {
     return (struct sockaddr*)(void*)&statp->nsaddrs[n];
 }
@@ -669,13 +647,12 @@
     struct sockaddr* nsap;
     int nsaplen;
     int truncating, connreset, n;
-    struct iovec iov[2];
     uint8_t* cp;
 
     LOG(INFO) << __func__ << ": using send_vc";
 
     nsap = get_nsaddr(statp, (size_t) ns);
-    nsaplen = get_salen(nsap);
+    nsaplen = sockaddrSize(nsap);
 
     connreset = 0;
 same_ns:
@@ -754,8 +731,10 @@
      * Send length & message
      */
     uint16_t len = htons(static_cast<uint16_t>(buflen));
-    iov[0] = evConsIovec(&len, INT16SZ);
-    iov[1] = evConsIovec((void*) buf, (size_t) buflen);
+    const iovec iov[] = {
+            {.iov_base = &len, .iov_len = INT16SZ},
+            {.iov_base = const_cast<uint8_t*>(buf), .iov_len = static_cast<size_t>(buflen)},
+    };
     if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
         *terrno = errno;
         PLOG(DEBUG) << __func__ << ": write failed: ";
@@ -863,8 +842,8 @@
 }
 
 /* return -1 on error (errno set), 0 on success */
-static int connect_with_timeout(int sock, const struct sockaddr* nsap, socklen_t salen,
-                                const struct timespec timeout) {
+static int connect_with_timeout(int sock, const sockaddr* nsap, socklen_t salen,
+                                const timespec timeout) {
     int res, origflags;
 
     origflags = fcntl(sock, F_GETFL, 0);
@@ -876,8 +855,8 @@
         goto done;
     }
     if (res != 0) {
-        struct timespec now = evNowTime();
-        struct timespec finish = evAddTime(now, timeout);
+        timespec now = evNowTime();
+        timespec finish = evAddTime(now, timeout);
         LOG(INFO) << __func__ << ": " << sock << " send_vc";
         res = retrying_poll(sock, POLLIN | POLLOUT, &finish);
         if (res <= 0) {
@@ -941,7 +920,7 @@
     int resplen, n, s;
 
     nsap = get_nsaddr(statp, (size_t) ns);
-    nsaplen = get_salen(nsap);
+    nsaplen = sockaddrSize(nsap);
     if (statp->nssocks[ns] == -1) {
         statp->nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (statp->nssocks[ns] < 0) {
@@ -1102,6 +1081,7 @@
     char hbuf[NI_MAXHOST];
     char sbuf[NI_MAXSERV];
     constexpr int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+    const int err = errno;
 
     if (!WOULD_LOG(DEBUG)) return;
 
@@ -1111,6 +1091,7 @@
         strncpy(sbuf, "?", sizeof(sbuf) - 1);
         sbuf[sizeof(sbuf) - 1] = '\0';
     }
+    errno = err;
     PLOG(DEBUG) << __func__ << ": " << str << " ([" << hbuf << "]." << sbuf << "): ";
 }
 
@@ -1243,7 +1224,7 @@
     assert(event != nullptr);
     ResState res;
     res_init(&res, netContext, event);
-    _resolv_populate_res_for_net(&res);
+    resolv_populate_res_for_net(&res);
     *rcode = NOERROR;
     return res_nsend(&res, msg, msgLen, ans, ansLen, rcode, flags);
 }
diff --git a/resolv_cache.h b/resolv_cache.h
index 6ede2e0..16019f2 100644
--- a/resolv_cache.h
+++ b/resolv_cache.h
@@ -42,7 +42,7 @@
 // The name servers are retrieved from the cache which is associated
 // with the network to which ResState is associated.
 struct ResState;
-void _resolv_populate_res_for_net(ResState* statp);
+void resolv_populate_res_for_net(ResState* statp);
 
 std::vector<unsigned> resolv_list_caches();
 
diff --git a/resolv_cache_unit_test.cpp b/resolv_cache_unit_test.cpp
index 22e61c0..9f4d0af 100644
--- a/resolv_cache_unit_test.cpp
+++ b/resolv_cache_unit_test.cpp
@@ -43,7 +43,6 @@
 // Constant values sync'd from res_cache.cpp
 constexpr int DNS_HEADER_SIZE = 12;
 constexpr int MAX_ENTRIES = 64 * 2 * 5;
-constexpr int MAXPACKET = 8 * 1024;
 
 namespace {
 
@@ -85,7 +84,7 @@
                 .rclass = question.qclass,
                 .ttl = ttl,
         };
-        test::DNSResponder::fillAnswerRdata(rdata_str, record);
+        test::DNSResponder::fillRdata(rdata_str, record);
         header.answers.push_back(std::move(record));
     }
 
@@ -99,13 +98,6 @@
     return std::time(nullptr);
 }
 
-std::string addrToString(const sockaddr_storage* addr) {
-    char out[INET6_ADDRSTRLEN] = {0};
-    getnameinfo((const sockaddr*)addr, sizeof(sockaddr_storage), out, INET6_ADDRSTRLEN, nullptr, 0,
-                NI_NUMERICHOST);
-    return std::string(out);
-}
-
 // Comparison for res_stats. Simply check the count in the cache test.
 bool operator==(const res_stats& a, const res_stats& b) {
     return std::tie(a.sample_count, a.sample_next) == std::tie(b.sample_count, b.sample_next);
diff --git a/resolv_integration_test.cpp b/resolv_integration_test.cpp
index 27e21d2..207dd05 100644
--- a/resolv_integration_test.cpp
+++ b/resolv_integration_test.cpp
@@ -3486,3 +3486,115 @@
     EXPECT_GE(3000, std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
     EXPECT_LE(1000, std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
 }
+
+// Parameterized tests.
+// TODO: Merge the existing tests as parameterized test if possible.
+// TODO: Perhaps move parameterized tests to an independent file.
+enum class CallType { GETADDRINFO, GETHOSTBYNAME };
+class ResolverParameterizedTest : public ResolverTest,
+                                  public testing::WithParamInterface<CallType> {};
+
+INSTANTIATE_TEST_SUITE_P(TestQueryCall, ResolverParameterizedTest,
+                         testing::Values(CallType::GETADDRINFO, CallType::GETHOSTBYNAME),
+                         [](const testing::TestParamInfo<CallType>& info) {
+                             std::string name;
+                             switch (info.param) {
+                                 case CallType::GETADDRINFO:
+                                     name = "GetAddrInfo";
+                                     break;
+                                 case CallType::GETHOSTBYNAME:
+                                     name = "GetHostByName";
+                                     break;
+                                 default:
+                                     name = "InvalidParameter";  // Should not happen.
+                             }
+                             return name;
+                         });
+
+TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) {
+    // DNS response may have more information in authority section and additional section.
+    // Currently, getanswer() of packages/modules/DnsResolver/getaddrinfo.cpp doesn't parse the
+    // content of authority section and additional section. Test these sections if they crash
+    // the resolver, just in case. See also RFC 1035 section 4.1.
+    const auto& calltype = GetParam();
+    test::DNSHeader header(kDefaultDnsHeader);
+
+    // Create a DNS response which has a authoritative nameserver record in authority
+    // section and its relevant address record in additional section.
+    //
+    // Question
+    //   hello.example.com.     IN      A
+    // Answer
+    //   hello.example.com.     IN      A   1.2.3.4
+    // Authority:
+    //   hello.example.com.     IN      NS  ns1.example.com.
+    // Additional:
+    //   ns1.example.com.       IN      A   5.6.7.8
+    //
+    // A response may have only question, answer, and authority section. Current testing response
+    // should be able to cover this condition.
+
+    // Question section.
+    test::DNSQuestion question{
+            .qname = {.name = kHelloExampleCom},
+            .qtype = ns_type::ns_t_a,
+            .qclass = ns_c_in,
+    };
+    header.questions.push_back(std::move(question));
+
+    // Answer section.
+    test::DNSRecord recordAnswer{
+            .name = {.name = kHelloExampleCom},
+            .rtype = ns_type::ns_t_a,
+            .rclass = ns_c_in,
+            .ttl = 0,  // no cache
+    };
+    EXPECT_TRUE(test::DNSResponder::fillRdata("1.2.3.4", recordAnswer));
+    header.answers.push_back(std::move(recordAnswer));
+
+    // Authority section.
+    test::DNSRecord recordAuthority{
+            .name = {.name = kHelloExampleCom},
+            .rtype = ns_type::ns_t_ns,
+            .rclass = ns_c_in,
+            .ttl = 0,  // no cache
+    };
+    EXPECT_TRUE(test::DNSResponder::fillRdata("ns1.example.com.", recordAuthority));
+    header.authorities.push_back(std::move(recordAuthority));
+
+    // Additional section.
+    test::DNSRecord recordAdditional{
+            .name = {.name = "ns1.example.com."},
+            .rtype = ns_type::ns_t_a,
+            .rclass = ns_c_in,
+            .ttl = 0,  // no cache
+    };
+    EXPECT_TRUE(test::DNSResponder::fillRdata("5.6.7.8", recordAdditional));
+    header.additionals.push_back(std::move(recordAdditional));
+
+    // Start DNS server.
+    test::DNSResponder dns(test::DNSResponder::MappingType::DNS_HEADER);
+    dns.addMappingDnsHeader(kHelloExampleCom, ns_type::ns_t_a, header);
+    ASSERT_TRUE(dns.startServer());
+    ASSERT_TRUE(mDnsClient.SetResolversForNetwork());
+    dns.clearQueries();
+
+    // Expect that get the address and the resolver doesn't crash.
+    if (calltype == CallType::GETADDRINFO) {
+        const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
+        ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
+        EXPECT_TRUE(result != nullptr);
+        EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom));
+        EXPECT_EQ("1.2.3.4", ToString(result));
+    } else if (calltype == CallType::GETHOSTBYNAME) {
+        const hostent* result = gethostbyname("hello");
+        EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom));
+        ASSERT_FALSE(result == nullptr);
+        ASSERT_EQ(4, result->h_length);
+        ASSERT_FALSE(result->h_addr_list[0] == nullptr);
+        EXPECT_EQ("1.2.3.4", ToString(result));
+        EXPECT_TRUE(result->h_addr_list[1] == nullptr);
+    } else {
+        FAIL() << "Unsupported call type: " << static_cast<uint32_t>(calltype);
+    }
+}
\ No newline at end of file
diff --git a/resolv_private.h b/resolv_private.h
index 1babd84..e5efc64 100644
--- a/resolv_private.h
+++ b/resolv_private.h
@@ -86,6 +86,7 @@
     struct sockaddr_in sin;
     struct sockaddr_in6 sin6;
 };
+constexpr int MAXPACKET = 8 * 1024;
 
 struct ResState {
     unsigned netid;                           // NetId: cache key and socket mark
@@ -195,4 +196,11 @@
     }
 }
 
+inline std::string addrToString(const sockaddr_storage* addr) {
+    char out[INET6_ADDRSTRLEN] = {0};
+    getnameinfo((const sockaddr*)addr, sizeof(sockaddr_storage), out, INET6_ADDRSTRLEN, nullptr, 0,
+                NI_NUMERICHOST);
+    return std::string(out);
+}
+
 #endif  // NETD_RESOLV_PRIVATE_H
diff --git a/resolv_unit_test.cpp b/resolv_unit_test.cpp
index 3295cac..23a2aa7 100644
--- a/resolv_unit_test.cpp
+++ b/resolv_unit_test.cpp
@@ -67,7 +67,7 @@
                 .rclass = rclass,
                 .ttl = ttl,
         };
-        EXPECT_TRUE(test::DNSResponder::fillAnswerRdata(rdata, record));
+        EXPECT_TRUE(test::DNSResponder::fillRdata(rdata, record));
         return record;
     }
 
diff --git a/tests/dns_responder/dns_responder.cpp b/tests/dns_responder/dns_responder.cpp
index 072c2dd..8c79fbf 100644
--- a/tests/dns_responder/dns_responder.cpp
+++ b/tests/dns_responder/dns_responder.cpp
@@ -742,7 +742,7 @@
                     .rclass = ns_class::ns_c_in,
                     .ttl = kAnswerRecordTtlSec,  // seconds
             };
-            if (!fillAnswerRdata(it->second, record)) return false;
+            if (!fillRdata(it->second, record)) return false;
             answers->push_back(std::move(record));
             if (rtype != ns_type::ns_t_cname) break;
             rname = it->second;
@@ -758,7 +758,7 @@
     return true;
 }
 
-bool DNSResponder::fillAnswerRdata(const std::string& rdatastr, DNSRecord& record) {
+bool DNSResponder::fillRdata(const std::string& rdatastr, DNSRecord& record) {
     if (record.rtype == ns_type::ns_t_a) {
         record.rdata.resize(4);
         if (inet_pton(AF_INET, rdatastr.c_str(), record.rdata.data()) != 1) {
@@ -771,7 +771,8 @@
             LOG(ERROR) << "inet_pton(AF_INET6, " << rdatastr << ") failed";
             return false;
         }
-    } else if ((record.rtype == ns_type::ns_t_ptr) || (record.rtype == ns_type::ns_t_cname)) {
+    } else if ((record.rtype == ns_type::ns_t_ptr) || (record.rtype == ns_type::ns_t_cname) ||
+               (record.rtype == ns_type::ns_t_ns)) {
         constexpr char delimiter = '.';
         std::string name = rdatastr;
         std::vector<char> rdata;
diff --git a/tests/dns_responder/dns_responder.h b/tests/dns_responder/dns_responder.h
index ed4b089..7211649 100644
--- a/tests/dns_responder/dns_responder.h
+++ b/tests/dns_responder/dns_responder.h
@@ -171,7 +171,7 @@
     std::condition_variable& getCv() { return cv; }
     std::mutex& getCvMutex() { return cv_mutex_; }
     void setDeferredResp(bool deferred_resp);
-    static bool fillAnswerRdata(const std::string& rdatastr, DNSRecord& record);
+    static bool fillRdata(const std::string& rdatastr, DNSRecord& record);
 
   private:
     // Key used for accessing mappings.
diff --git a/util.cpp b/util.cpp
new file mode 100644
index 0000000..91a033e
--- /dev/null
+++ b/util.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "util.h"
+
+socklen_t sockaddrSize(const sockaddr* sa) {
+    if (sa == nullptr) return 0;
+
+    switch (sa->sa_family) {
+        case AF_INET:
+            return sizeof(sockaddr_in);
+        case AF_INET6:
+            return sizeof(sockaddr_in6);
+        default:
+            return 0;
+    }
+}
+
+socklen_t sockaddrSize(const sockaddr_storage& ss) {
+    return sockaddrSize(reinterpret_cast<const sockaddr*>(&ss));
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..d879011
--- /dev/null
+++ b/util.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#pragma once
+
+#include <netinet/in.h>
+
+socklen_t sockaddrSize(const sockaddr* sa);
+socklen_t sockaddrSize(const sockaddr_storage& ss);