Merge "Avoid keeping sending queries to an invalid nameserver"
diff --git a/tests/Android.bp b/tests/Android.bp
index cf13ddb..0d6ddff 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -50,16 +50,16 @@
         "libssl",
     ],
     static_libs: [
-        "dnsresolver_aidl_interface-unstable-cpp",
+        "dnsresolver_aidl_interface-unstable-ndk_platform",
         "golddata_proto",
         "libbase",
         "libgmock",
         "liblog",
         "libnetd_resolv",
-        "libnetd_test_dnsresponder",
+        "libnetd_test_dnsresponder_ndk",
         "libnetd_test_resolv_utils",
         "libnetdutils",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-ndk_platform",
         "netd_event_listener_interface-ndk_platform",
         "server_configurable_flags",
         "stats_proto",
diff --git a/tests/golddata.proto b/tests/golddata.proto
index dfc21f1..05133fc 100644
--- a/tests/golddata.proto
+++ b/tests/golddata.proto
@@ -160,6 +160,12 @@
             int32 ai_flags = 5;
         }
 
+        // The arguments used to send a DNS query by call type CALL_GETHOSTBYNAME.
+        message HostByName {
+            string host = 1;
+            AddressFamily family = 2;
+        }
+
         // The call is used to send DNS lookups.
         CallType call = 1;
 
@@ -167,6 +173,7 @@
         oneof Arg {
             // The arguments of call type CALL_GETADDRINFO.
             AddrInfo addrinfo = 2;
+            HostByName hostbyname = 3;
         }
     };
 
diff --git a/tests/resolv_gold_test.cpp b/tests/resolv_gold_test.cpp
index 92fc277..29ec615 100644
--- a/tests/resolv_gold_test.cpp
+++ b/tests/resolv_gold_test.cpp
@@ -20,25 +20,34 @@
 #include <Fwmark.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <gmock/gmock-matchers.h>
 #include <google/protobuf/text_format.h>
 #include <gtest/gtest.h>
 
 #include "PrivateDnsConfiguration.h"
-#include "dns_responder/dns_responder.h"
-#include "dns_responder_client.h"
 #include "getaddrinfo.h"
+#include "gethnamaddr.h"
 #include "golddata.pb.h"
 #include "resolv_cache.h"
 #include "resolv_test_utils.h"
+#include "tests/dns_responder/dns_responder.h"
+#include "tests/dns_responder/dns_responder_client_ndk.h"
 #include "tests/dns_responder/dns_tls_certificate.h"
 #include "tests/dns_responder/dns_tls_frontend.h"
 
-namespace android {
-namespace net {
+namespace android::net {
+
+using android::base::StringPrintf;
 using android::netdutils::ScopedAddrinfo;
 using std::chrono::milliseconds;
 
+enum class DnsProtocol { CLEARTEXT, TLS };
+
+// The buffer size of resolv_gethostbyname().
+// TODO: Consider moving to packages/modules/DnsResolver/tests/resolv_test_utils.h.
+constexpr unsigned int MAXPACKET = 8 * 1024;
+
 const std::string kTestDataPath = android::base::GetExecutableDirectory() + "/testdata/";
 const std::vector<std::string> kGoldFilesGetAddrInfo = {
         "getaddrinfo.topsite.google.pbtxt",    "getaddrinfo.topsite.youtube.pbtxt",
@@ -46,6 +55,10 @@
         "getaddrinfo.topsite.facebook.pbtxt",  "getaddrinfo.topsite.reddit.pbtxt",
         "getaddrinfo.topsite.wikipedia.pbtxt", "getaddrinfo.topsite.ebay.pbtxt",
         "getaddrinfo.topsite.netflix.pbtxt",   "getaddrinfo.topsite.bing.pbtxt"};
+const std::vector<std::string> kGoldFilesGetAddrInfoTls = {"getaddrinfo.tls.topsite.google.pbtxt"};
+const std::vector<std::string> kGoldFilesGetHostByName = {"gethostbyname.topsite.youtube.pbtxt"};
+const std::vector<std::string> kGoldFilesGetHostByNameTls = {
+        "gethostbyname.tls.topsite.youtube.pbtxt"};
 
 // Fixture test class definition.
 class TestBase : public ::testing::Test {
@@ -62,8 +75,8 @@
         resolv_delete_cache_for_net(TEST_NETID);
     }
 
-    void SetResolverConfiguration(const std::vector<std::string>& servers = {},
-                                  const std::vector<std::string>& domains = {},
+    void SetResolverConfiguration(const std::vector<std::string>& servers,
+                                  const std::vector<std::string>& domains,
                                   const std::vector<std::string>& tlsServers = {},
                                   const std::string& tlsHostname = "",
                                   const std::string& caCert = "") {
@@ -110,6 +123,111 @@
         return false;
     }
 
+    GoldTest ToProto(const std::string& file) {
+        // Convert the testing configuration from .pbtxt file to proto.
+        std::string file_content;
+        EXPECT_TRUE(android::base::ReadFileToString(kTestDataPath + file, &file_content))
+                << strerror(errno);
+        android::net::GoldTest goldtest;
+        EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString(file_content, &goldtest));
+        return goldtest;
+    }
+
+    void SetupMappings(const android::net::GoldTest& goldtest, test::DNSResponder& dns) {
+        for (const auto& m : goldtest.packet_mapping()) {
+            // Convert string to bytes because .proto type "bytes" is "string" type in C++.
+            // See also the section "Scalar Value Types" in "Language Guide (proto3)".
+            // TODO: Use C++20 std::span in addMappingBinaryPacket. It helps to take both
+            // std::string and std::vector without conversions.
+            dns.addMappingBinaryPacket(
+                    std::vector<uint8_t>(m.query().begin(), m.query().end()),
+                    std::vector<uint8_t>(m.response().begin(), m.response().end()));
+        }
+    }
+
+    android_net_context GetNetContext(const DnsProtocol protocol) {
+        return protocol == DnsProtocol::TLS ? kNetcontextTls : kNetcontext;
+    }
+
+    template <class AddressType>
+    void VerifyAddress(const android::net::GoldTest& goldtest, const AddressType& result) {
+        if (goldtest.result().return_code() != GT_EAI_NO_ERROR) {
+            EXPECT_EQ(result, nullptr);
+        } else {
+            ASSERT_NE(result, nullptr);
+            const auto& addresses = goldtest.result().addresses();
+            EXPECT_THAT(ToStrings(result), ::testing::UnorderedElementsAreArray(addresses));
+        }
+    }
+
+    void VerifyGetAddrInfo(const android::net::GoldTest& goldtest, const DnsProtocol protocol) {
+        ASSERT_TRUE(goldtest.config().has_addrinfo());
+        const auto& args = goldtest.config().addrinfo();
+        const addrinfo hints = {
+                // Clear the flag AI_ADDRCONFIG to avoid flaky test because AI_ADDRCONFIG looks at
+                // whether connectivity is available. It makes that the resolver may send only A
+                // or AAAA DNS query per connectivity even AF_UNSPEC has been assigned. See also
+                // have_ipv6() and have_ipv4() in packages/modules/DnsResolver/getaddrinfo.cpp.
+                // TODO: Consider keeping the configuration flag AI_ADDRCONFIG once the unit
+                // test can treat the IPv4 and IPv6 connectivity.
+                .ai_flags = args.ai_flags() & ~AI_ADDRCONFIG,
+                .ai_family = args.family(),
+                .ai_socktype = args.socktype(),
+                .ai_protocol = args.protocol(),
+        };
+        addrinfo* res = nullptr;
+        const android_net_context netcontext = GetNetContext(protocol);
+        NetworkDnsEventReported event;
+        const int rv =
+                resolv_getaddrinfo(args.host().c_str(), nullptr, &hints, &netcontext, &res, &event);
+        ScopedAddrinfo result(res);
+        ASSERT_EQ(rv, goldtest.result().return_code());
+        VerifyAddress(goldtest, result);
+    }
+
+    void VerifyGetHostByName(const android::net::GoldTest& goldtest, const DnsProtocol protocol) {
+        ASSERT_TRUE(goldtest.config().has_hostbyname());
+        const auto& args = goldtest.config().hostbyname();
+        hostent* hp = nullptr;
+        hostent hbuf;
+        char tmpbuf[MAXPACKET];
+        const android_net_context netcontext = GetNetContext(protocol);
+        NetworkDnsEventReported event;
+        const int rv = resolv_gethostbyname(args.host().c_str(), args.family(), &hbuf, tmpbuf,
+                                            sizeof(tmpbuf), &netcontext, &hp, &event);
+        ASSERT_EQ(rv, goldtest.result().return_code());
+        VerifyAddress(goldtest, hp);
+    }
+
+    void VerifyResolver(const android::net::GoldTest& goldtest, const test::DNSResponder& dns,
+                        const test::DnsTlsFrontend& tls, const DnsProtocol protocol) {
+        size_t queries;
+        std::string name;
+
+        // Verify DNS query calls and results by proto. Then, determine expected query times and
+        // queried name for checking server query status later.
+        switch (const auto calltype = goldtest.config().call()) {
+            case android::net::CallType::CALL_GETADDRINFO:
+                ASSERT_TRUE(goldtest.config().has_addrinfo());
+                ASSERT_NO_FATAL_FAILURE(VerifyGetAddrInfo(goldtest, protocol));
+                queries = goldtest.config().addrinfo().family() == AF_UNSPEC ? 2U : 1U;
+                name = goldtest.config().addrinfo().host();
+                break;
+            case android::net::CallType::CALL_GETHOSTBYNAME:
+                ASSERT_TRUE(goldtest.config().has_hostbyname());
+                ASSERT_NO_FATAL_FAILURE(VerifyGetHostByName(goldtest, protocol));
+                queries = 1U;
+                name = goldtest.config().hostbyname().host();
+                break;
+            default:
+                FAIL() << "Unsupported call type: " << calltype;
+        }
+
+        // Verify DNS server query status.
+        EXPECT_EQ(GetNumQueries(dns, name.c_str()), queries);
+        if (protocol == DnsProtocol::TLS) EXPECT_EQ(tls.queries(), static_cast<int>(queries));
+    }
+
     static constexpr res_params kParams = {
             .sample_validity = 300,
             .success_threshold = 25,
@@ -138,19 +256,6 @@
 };
 class ResolvGetAddrInfo : public TestBase {};
 
-// Parameterized test class definition.
-class ResolvGoldTest : public TestBase, public ::testing::WithParamInterface<std::string> {};
-
-// GetAddrInfo tests.
-INSTANTIATE_TEST_SUITE_P(GetAddrInfo, ResolvGoldTest, ::testing::ValuesIn(kGoldFilesGetAddrInfo),
-                         [](const ::testing::TestParamInfo<std::string>& info) {
-                             std::string name = info.param;
-                             std::replace_if(
-                                     std::begin(name), std::end(name),
-                                     [](char ch) { return !std::isalnum(ch); }, '_');
-                             return name;
-                         });
-
 // Fixture tests.
 TEST_F(ResolvGetAddrInfo, RemovePacketMapping) {
     test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
@@ -166,7 +271,7 @@
     ScopedAddrinfo result(res);
     ASSERT_NE(result, nullptr);
     ASSERT_EQ(rv, 0);
-    EXPECT_EQ(ToString(result), "1.2.3.4");
+    EXPECT_EQ(ToString(result), kHelloExampleComAddrV4);
 
     // Remove existing DNS record.
     dns.removeMappingBinaryPacket(kHelloExampleComQueryV4);
@@ -231,8 +336,8 @@
 
 TEST_F(ResolvGetAddrInfo, BasicTlsQuery) {
     test::DNSResponder dns;
-    dns.addMapping(kHelloExampleCom, ns_type::ns_t_a, "1.2.3.4");
-    dns.addMapping(kHelloExampleCom, ns_type::ns_t_aaaa, "::1.2.3.4");
+    dns.addMapping(kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4);
+    dns.addMapping(kHelloExampleCom, ns_type::ns_t_aaaa, kHelloExampleComAddrV6);
     ASSERT_TRUE(dns.startServer());
 
     test::DnsTlsFrontend tls;
@@ -253,66 +358,71 @@
     ASSERT_EQ(rv, 0);
     EXPECT_EQ(GetNumQueries(dns, kHelloExampleCom), 2U);
     const std::vector<std::string> result_strs = ToStrings(result);
-    EXPECT_THAT(result_strs, testing::UnorderedElementsAreArray({"1.2.3.4", "::1.2.3.4"}));
+    EXPECT_THAT(result_strs, testing::UnorderedElementsAreArray(
+                                     {kHelloExampleComAddrV4, kHelloExampleComAddrV6}));
     EXPECT_EQ(tls.queries(), 3);
 }
 
-// Parameterized tests.
+// Parameterized test class definition.
+using GoldTestParamType = std::tuple<DnsProtocol, std::string /* filename */>;
+class ResolvGoldTest : public TestBase, public ::testing::WithParamInterface<GoldTestParamType> {
+  public:
+    // Generate readable string for test name from test parameters.
+    static std::string Name(::testing::TestParamInfo<GoldTestParamType> info) {
+        const auto& [protocol, file] = info.param;
+        std::string name = StringPrintf(
+                "%s_%s", protocol == DnsProtocol::CLEARTEXT ? "CLEARTEXT" : "TLS", file.c_str());
+        std::replace_if(
+                std::begin(name), std::end(name), [](char ch) { return !std::isalnum(ch); }, '_');
+        return name;
+    }
+};
+
+// GetAddrInfo tests.
+INSTANTIATE_TEST_SUITE_P(GetAddrInfo, ResolvGoldTest,
+                         ::testing::Combine(::testing::Values(DnsProtocol::CLEARTEXT),
+                                            ::testing::ValuesIn(kGoldFilesGetAddrInfo)),
+                         ResolvGoldTest::Name);
+INSTANTIATE_TEST_SUITE_P(GetAddrInfoTls, ResolvGoldTest,
+                         ::testing::Combine(::testing::Values(DnsProtocol::TLS),
+                                            ::testing::ValuesIn(kGoldFilesGetAddrInfoTls)),
+                         ResolvGoldTest::Name);
+
+// GetHostByName tests.
+INSTANTIATE_TEST_SUITE_P(GetHostByName, ResolvGoldTest,
+                         ::testing::Combine(::testing::Values(DnsProtocol::CLEARTEXT),
+                                            ::testing::ValuesIn(kGoldFilesGetHostByName)),
+                         ResolvGoldTest::Name);
+INSTANTIATE_TEST_SUITE_P(GetHostByNameTls, ResolvGoldTest,
+                         ::testing::Combine(::testing::Values(DnsProtocol::TLS),
+                                            ::testing::ValuesIn(kGoldFilesGetHostByNameTls)),
+                         ResolvGoldTest::Name);
+
 TEST_P(ResolvGoldTest, GoldData) {
-    const auto& testFile = GetParam();
+    const auto& [protocol, file] = GetParam();
 
-    // Convert the testing configuration from .pbtxt file to proto.
-    std::string file_content;
-    ASSERT_TRUE(android::base::ReadFileToString(kTestDataPath + testFile, &file_content))
-            << strerror(errno);
-    android::net::GoldTest goldtest;
-    ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(file_content, &goldtest));
-    ASSERT_EQ(android::net::CallType::CALL_GETADDRINFO, goldtest.config().call());
-    ASSERT_TRUE(goldtest.config().has_addrinfo());
-
+    // Setup DNS server configuration.
     test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
     ASSERT_TRUE(dns.startServer());
-    ASSERT_NO_FATAL_FAILURE(SetResolvers());
+    test::DnsTlsFrontend tls;
 
-    // Register packet mapping (query, response) from proto.
-    for (const auto& m : goldtest.packet_mapping()) {
-        // Convert string to bytes because .proto type "bytes" is "string" type in C++.
-        // See also the section "Scalar Value Types" in "Language Guide (proto3)".
-        dns.addMappingBinaryPacket(std::vector<uint8_t>(m.query().begin(), m.query().end()),
-                                   std::vector<uint8_t>(m.response().begin(), m.response().end()));
+    if (protocol == DnsProtocol::CLEARTEXT) {
+        ASSERT_NO_FATAL_FAILURE(SetResolvers());
+    } else if (protocol == DnsProtocol::TLS) {
+        ASSERT_TRUE(tls.startServer());
+        ASSERT_NO_FATAL_FAILURE(SetResolversWithTls());
+        EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address()));
+        tls.clearQueries();
     }
 
-    addrinfo* res = nullptr;
-    const auto& args = goldtest.config().addrinfo();
-    const addrinfo hints = {
-            // Clear the flag AI_ADDRCONFIG to avoid flaky test because AI_ADDRCONFIG looks at
-            // whether connectivity is available. It makes that the resolver may send only A
-            // or AAAA DNS query per connectivity even AF_UNSPEC has been assigned. See also
-            // have_ipv6() and have_ipv4() in packages/modules/DnsResolver/getaddrinfo.cpp.
-            // TODO: Consider keeping the configuration flag AI_ADDRCONFIG once the unit
-            // test can treat the IPv4 and IPv6 connectivity.
-            .ai_flags = args.ai_flags() & ~AI_ADDRCONFIG,
-            .ai_family = args.family(),
-            .ai_socktype = args.socktype(),
-            .ai_protocol = args.protocol(),
-    };
-    NetworkDnsEventReported event;
-    const int rv =
-            resolv_getaddrinfo(args.host().c_str(), nullptr, &hints, &kNetcontext, &res, &event);
-    ScopedAddrinfo result(res);
-    ASSERT_EQ(goldtest.result().return_code(), rv);
+    // Read test configuration from proto text file to proto.
+    const auto goldtest = ToProto(file);
 
-    if (goldtest.result().return_code() != GT_EAI_NO_ERROR) {
-        ASSERT_EQ(result, nullptr);
-    } else {
-        ASSERT_NE(result, nullptr);
-        const auto& addresses = goldtest.result().addresses();
-        EXPECT_THAT(ToStrings(result),
-                    ::testing::UnorderedElementsAreArray(
-                            std::vector<std::string>(addresses.begin(), addresses.end())));
-    }
-    EXPECT_EQ(GetNumQueries(dns, args.host().c_str()), (hints.ai_family == AF_UNSPEC) ? 2U : 1U);
+    // Register packet mappings (query, response) from proto.
+    SetupMappings(goldtest, dns);
+
+    // Verify the resolver by proto.
+    VerifyResolver(goldtest, dns, tls, protocol);
 }
 
-}  // end of namespace net
-}  // end of namespace android
+}  // namespace android::net
\ No newline at end of file
diff --git a/tests/resolv_test_utils.cpp b/tests/resolv_test_utils.cpp
index da27fd8..f3652d0 100644
--- a/tests/resolv_test_utils.cpp
+++ b/tests/resolv_test_utils.cpp
@@ -57,6 +57,27 @@
     return host;
 }
 
+std::vector<std::string> ToStrings(const hostent* he) {
+    std::vector<std::string> hosts;
+    if (he == nullptr) {
+        hosts.push_back("<null>");
+        return hosts;
+    }
+    uint32_t i = 0;
+    while (he->h_addr_list[i] != nullptr) {
+        char host[INET6_ADDRSTRLEN];
+        if (!inet_ntop(he->h_addrtype, he->h_addr_list[i], host, sizeof(host))) {
+            hosts.push_back("<invalid>");
+            return hosts;
+        } else {
+            hosts.push_back(host);
+        }
+        i++;
+    }
+    if (hosts.empty()) hosts.push_back("<invalid>");
+    return hosts;
+}
+
 std::vector<std::string> ToStrings(const addrinfo* ai) {
     std::vector<std::string> hosts;
     if (!ai) {
diff --git a/tests/resolv_test_utils.h b/tests/resolv_test_utils.h
index 48d8c23..c285582 100644
--- a/tests/resolv_test_utils.h
+++ b/tests/resolv_test_utils.h
@@ -41,6 +41,7 @@
 static constexpr char kIp6LocalHostAddr[] = "::1";
 static constexpr char kHelloExampleCom[] = "hello.example.com.";
 static constexpr char kHelloExampleComAddrV4[] = "1.2.3.4";
+static constexpr char kHelloExampleComAddrV6[] = "::1.2.3.4";
 
 static const std::vector<uint8_t> kHelloExampleComQueryV4 = {
         /* Header */
@@ -106,5 +107,6 @@
 std::string ToString(const addrinfo* ai);
 std::string ToString(const android::netdutils::ScopedAddrinfo& ai);
 std::string ToString(const sockaddr_storage* addr);
+std::vector<std::string> ToStrings(const hostent* he);
 std::vector<std::string> ToStrings(const addrinfo* ai);
 std::vector<std::string> ToStrings(const android::netdutils::ScopedAddrinfo& ai);
diff --git a/tests/testdata/getaddrinfo.tls.topsite.google.pbtxt b/tests/testdata/getaddrinfo.tls.topsite.google.pbtxt
new file mode 100644
index 0000000..a4c1661
--- /dev/null
+++ b/tests/testdata/getaddrinfo.tls.topsite.google.pbtxt
@@ -0,0 +1,61 @@
+# Location: Taipei, Taiwan
+# Network: Wifi, GoogleGuest
+# Date: 26 NOV 2019
+
+config {
+    call: CALL_GETADDRINFO
+    addrinfo {
+        host: "www.google.com."
+        family: GT_AF_UNSPEC
+        socktype: GT_SOCK_DGRAM
+        protocol: GT_IPPROTO_IP
+        ai_flags: 1024
+    };
+}
+result {
+    return_code: GT_EAI_NO_ERROR
+    addresses: "2404:6800:4008:801::2004"
+    addresses: "172.217.27.132"
+}
+packet_mapping {
+    query:    "\x00\x00\x01\x20\x00\x01\x00\x00\x00\x00\x00\x01\x03\x77\x77\x77"
+              "\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x1c\x00\x01"
+              "\x00\x00\x29\x20\x00\x00\x00\x80\x00\x00\x55\x00\x0c\x00\x51\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+    response: "\x00\x00\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x03\x77\x77\x77"
+              "\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x1c\x00\x01"
+              "\xc0\x0c\x00\x1c\x00\x01\x00\x00\x01\x2b\x00\x10\x24\x04\x68\x00"
+              "\x40\x08\x08\x01\x00\x00\x00\x00\x00\x00\x20\x04\x00\x00\x29\x02"
+              "\x00\x00\x00\x80\x00\x01\x8d\x00\x0c\x01\x89\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00"
+}
+packet_mapping {
+    query:    "\x00\x00\x01\x20\x00\x01\x00\x00\x00\x00\x00\x01\x03\x77\x77\x77"
+              "\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x01\x00\x01"
+              "\x00\x00\x29\x20\x00\x00\x00\x80\x00\x00\x55\x00\x0c\x00\x51\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+    response: "\x00\x00\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x03\x77\x77\x77"
+              "\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x01\x00\x01"
+              "\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x86\x00\x04\xac\xd9\x1b\x84"
+              "\x00\x00\x29\x02\x00\x00\x00\x80\x00\x01\x99\x00\x0c\x01\x95\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00"
+}
diff --git a/tests/testdata/gethostbyname.tls.topsite.youtube.pbtxt b/tests/testdata/gethostbyname.tls.topsite.youtube.pbtxt
new file mode 100644
index 0000000..5f32518
--- /dev/null
+++ b/tests/testdata/gethostbyname.tls.topsite.youtube.pbtxt
@@ -0,0 +1,48 @@
+# Location: Taipei, Taiwan
+# Network: Wifi, GoogleGuest
+# Date: 26 NOV 2019
+
+config {
+    call: CALL_GETHOSTBYNAME
+    hostbyname {
+        host: "www.youtube.com."
+        family: GT_AF_INET
+    };
+}
+result {
+    return_code: GT_EAI_NO_ERROR
+    addresses: "216.58.200.46"
+    addresses: "172.217.160.78"
+    addresses: "216.58.200.238"
+    addresses: "172.217.27.142"
+    addresses: "172.217.160.110"
+    addresses: "172.217.24.14"
+}
+packet_mapping {
+    query:    "\x00\x00\x01\x20\x00\x01\x00\x00\x00\x00\x00\x01\x03\x77\x77\x77"
+              "\x07\x79\x6f\x75\x74\x75\x62\x65\x03\x63\x6f\x6d\x00\x00\x01\x00"
+              "\x01\x00\x00\x29\x20\x00\x00\x00\x80\x00\x00\x54\x00\x0c\x00\x50"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+    response: "\x00\x00\x81\x80\x00\x01\x00\x07\x00\x00\x00\x01\x03\x77\x77\x77"
+              "\x07\x79\x6f\x75\x74\x75\x62\x65\x03\x63\x6f\x6d\x00\x00\x01\x00"
+              "\x01\xc0\x0c\x00\x05\x00\x01\x00\x00\x54\x24\x00\x16\x0a\x79\x6f"
+              "\x75\x74\x75\x62\x65\x2d\x75\x69\x01\x6c\x06\x67\x6f\x6f\x67\x6c"
+              "\x65\xc0\x18\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xd8"
+              "\x3a\xc8\x2e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\xa0\x4e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xd8"
+              "\x3a\xc8\xee\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\x1b\x8e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\xa0\x6e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\x18\x0e\x00\x00\x29\x02\x00\x00\x00\x80\x00\x01\x26\x00\x0c"
+              "\x01\x22\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+              "\x00\x00\x00\x00"
+}
\ No newline at end of file
diff --git a/tests/testdata/gethostbyname.topsite.youtube.pbtxt b/tests/testdata/gethostbyname.topsite.youtube.pbtxt
new file mode 100644
index 0000000..d113e55
--- /dev/null
+++ b/tests/testdata/gethostbyname.topsite.youtube.pbtxt
@@ -0,0 +1,34 @@
+# Location: Taipei, Taiwan
+# Network: Wifi, GoogleGuest
+# Date: 15 OCT 2019
+
+config {
+    call: CALL_GETHOSTBYNAME
+    hostbyname {
+        host: "www.youtube.com."
+        family: GT_AF_INET
+    };
+}
+result {
+    return_code: GT_EAI_NO_ERROR
+    addresses: "216.58.200.46"
+    addresses: "172.217.160.78"
+    addresses: "172.217.27.142"
+    addresses: "172.217.160.110"
+    addresses: "172.217.24.14"
+}
+packet_mapping {
+    query:    "\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\x77\x77\x77"
+              "\x07\x79\x6f\x75\x74\x75\x62\x65\x03\x63\x6f\x6d\x00\x00\x01\x00"
+              "\x01"
+    response: "\x00\x00\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\x03\x77\x77\x77"
+              "\x07\x79\x6f\x75\x74\x75\x62\x65\x03\x63\x6f\x6d\x00\x00\x01\x00"
+              "\x01\xc0\x0c\x00\x05\x00\x01\x00\x00\x54\x5f\x00\x16\x0a\x79\x6f"
+              "\x75\x74\x75\x62\x65\x2d\x75\x69\x01\x6c\x06\x67\x6f\x6f\x67\x6c"
+              "\x65\xc0\x18\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xd8"
+              "\x3a\xc8\x2e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\xa0\x4e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\x1b\x8e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\xa0\x6e\xc0\x2d\x00\x01\x00\x01\x00\x00\x01\x2b\x00\x04\xac"
+              "\xd9\x18\x0e"
+}
\ No newline at end of file