Loading res_send.cpp +67 −108 Original line number Diff line number Diff line Loading @@ -397,24 +397,20 @@ static DnsQueryEvent* addDnsQueryEvent(NetworkDnsEventReported* event) { int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, uint32_t flags) { int gotsomewhere, terrno, v_circuit, resplen, n; ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED; LOG(DEBUG) << __func__; // Should not happen if (anssiz < HFIXEDSZ) { // TODO: Remove errno once callers stop using it errno = EINVAL; return -EINVAL; } LOG(DEBUG) << __func__; res_pquery(buf, buflen); v_circuit = buflen > PACKETSZ; gotsomewhere = 0; terrno = ETIMEDOUT; int anslen = 0; Stopwatch cacheStopwatch; cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); ResolvCacheStatus cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs()); if (cache_status == RESOLV_CACHE_FOUND) { HEADER* hp = (HEADER*)(void*)ans; Loading Loading @@ -442,8 +438,8 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // 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); int 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); Loading @@ -454,7 +450,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } if (!fallback) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; return -ETIMEDOUT; } } Loading @@ -478,90 +474,62 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int res_set_usable_server(selectedServer, statp->nscount, usable_servers); } /* * Send request, RETRY times, or until successful. */ // Send request, RETRY times, or until successful. int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count; int useTcp = buflen > PACKETSZ; int gotsomewhere = 0; int terrno = ETIMEDOUT; for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int ns = 0; ns < statp->nscount; ns++) { for (int ns = 0; ns < statp->nscount; ++ns) { if (!usable_servers[ns]) continue; int nsaplen; time_t now = 0; int delay = 0; *rcode = RCODE_INTERNAL_ERROR; // Get server addr const sockaddr* nsap = get_nsaddr(statp, ns); nsaplen = sockaddrSize(nsap); const int nsaplen = sockaddrSize(nsap); same_ns: static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; char abuf[NI_MAXHOST]; DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 << ") address = " << abuf; ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; int delay = 0; bool fallbackTCP = false; const bool shouldRecordStats = (attempt == 0); int resplen; Stopwatch queryStopwatch; if (v_circuit) { /* Use VC; at most one attempt per server. */ bool shouldRecordStats = (attempt == 0); if (useTcp) { // TCP; at most one attempt per server. attempt = retryTimes; n = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, &delay); dnsQueryEvent->set_latency_micros( saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_TCP); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* * Only record stats the first time we try a query. This ensures that * queries that deterministically fail (e.g., a name that always returns * SERVFAIL or times out) do not unduly affect the stats. */ if (shouldRecordStats) { res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, params.max_samples); resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); } LOG(INFO) << __func__ << ": used send_vc " << n; if (n < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); return -terrno; }; if (n == 0) goto next_ns; resplen = n; resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, &delay); } else { /* Use datagrams. */ LOG(INFO) << __func__ << ": using send_dg"; n = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, // UDP resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, &gotsomewhere, &now, rcode, &delay); fallbackTCP = useTcp ? true : false; } LOG(INFO) << __func__ << ": used send_" << ((useTcp) ? "vc " : "dg ") << resplen; dnsQueryEvent->set_latency_micros( saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_UDP); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* Only record stats the first time we try a query. See above. */ if (attempt == 0) { // Only record stats the first time we try a query. This ensures that // queries that deterministically fail (e.g., a name that always returns // SERVFAIL or times out) do not unduly affect the stats. if (shouldRecordStats) { res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, Loading @@ -569,17 +537,16 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); } LOG(INFO) << __func__ << ": used send_dg " << n; if (n < 0) { if (resplen == 0) continue; if (fallbackTCP) { ns--; continue; } if (resplen < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); return -terrno; }; if (n == 0) goto next_ns; if (v_circuit) goto same_ns; resplen = n; } LOG(DEBUG) << __func__ << ": got answer:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); Loading @@ -589,23 +556,15 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } res_nclose(statp); return (resplen); next_ns:; } // for each ns } // for each retry res_nclose(statp); if (!v_circuit) { if (!gotsomewhere) { // TODO: Remove errno once callers stop using it errno = ECONNREFUSED; /* no nameservers found */ terrno = ECONNREFUSED; } else { terrno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT : ECONNREFUSED; // TODO: Remove errno once callers stop using it errno = ETIMEDOUT; /* no answer obtained */ terrno = ETIMEDOUT; } } else { errno = terrno; } errno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT /* no answer obtained */ : ECONNREFUSED /* no nameservers found */; _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; } Loading resolv_integration_test.cpp +155 −26 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include <netdutils/InternetAddresses.h> #include <netdutils/NetworkConstants.h> // SHA256_SIZE #include <netdutils/ResponseCode.h> #include <netdutils/Slice.h> #include <netdutils/SocketOption.h> #include <netinet/in.h> #include <openssl/base64.h> Loading Loading @@ -89,8 +90,10 @@ using android::net::INetd; using android::net::ResolverStats; using android::net::metrics::DnsMetricsListener; using android::netdutils::enableSockopt; using android::netdutils::makeSlice; using android::netdutils::ResponseCode; using android::netdutils::ScopedAddrinfo; using android::netdutils::toHex; // TODO: move into libnetdutils? namespace { Loading Loading @@ -3492,23 +3495,39 @@ TEST_F(ResolverTest, ConnectTlsServerTimeout) { // TODO: Perhaps move parameterized tests to an independent file. enum class CallType { GETADDRINFO, GETHOSTBYNAME }; class ResolverParameterizedTest : public ResolverTest, public testing::WithParamInterface<CallType> {}; public testing::WithParamInterface<CallType> { protected: void VerifyQueryHelloExampleComV4(const test::DNSResponder& dns, const CallType calltype) { if (calltype == CallType::GETADDRINFO) { const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM}; ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints); ASSERT_TRUE(result != nullptr); EXPECT_EQ(kHelloExampleComAddrV4, ToString(result)); } else if (calltype == CallType::GETHOSTBYNAME) { const hostent* result = gethostbyname("hello"); ASSERT_TRUE(result != nullptr); ASSERT_EQ(4, result->h_length); ASSERT_FALSE(result->h_addr_list[0] == nullptr); EXPECT_EQ(kHelloExampleComAddrV4, ToString(result)); EXPECT_TRUE(result->h_addr_list[1] == nullptr); } else { FAIL() << "Unsupported call type: " << static_cast<uint32_t>(calltype); } EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom)); } }; INSTANTIATE_TEST_SUITE_P(TestQueryCall, ResolverParameterizedTest, INSTANTIATE_TEST_SUITE_P(QueryCallTest, ResolverParameterizedTest, testing::Values(CallType::GETADDRINFO, CallType::GETHOSTBYNAME), [](const testing::TestParamInfo<CallType>& info) { std::string name; switch (info.param) { case CallType::GETADDRINFO: name = "GetAddrInfo"; break; return "GetAddrInfo"; case CallType::GETHOSTBYNAME: name = "GetHostByName"; break; return "GetHostByName"; default: name = "InvalidParameter"; // Should not happen. return "InvalidParameter"; // Should not happen. } return name; }); TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) { Loading Loading @@ -3549,7 +3568,7 @@ TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) { .rclass = ns_c_in, .ttl = 0, // no cache }; EXPECT_TRUE(test::DNSResponder::fillRdata("1.2.3.4", recordAnswer)); EXPECT_TRUE(test::DNSResponder::fillRdata(kHelloExampleComAddrV4, recordAnswer)); header.answers.push_back(std::move(recordAnswer)); // Authority section. Loading Loading @@ -3580,21 +3599,131 @@ TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) { 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); VerifyQueryHelloExampleComV4(dns, calltype); } TEST_P(ResolverParameterizedTest, MessageCompression) { const auto& calltype = GetParam(); // The response with compressed domain name by a pointer. See RFC 1035 section 4.1.4. // // Ignoring the other fields of the message, the domain name of question section and answer // section are presented as: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 12 | 5 | h | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 14 | e | l | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 16 | l | o | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 18 | 7 | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 20 | x | a | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 22 | m | p | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 24 | l | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 26 | 3 | c | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 28 | o | m | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 30 | 0 | ... | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 35 | 1 1| 12 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ const std::vector<uint8_t> kResponseAPointer = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0xc0, 0x0c, /* Name: hello.example.com (a pointer) */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; // The response with compressed domain name by a sequence of labels ending with a pointer. See // RFC 1035 section 4.1.4. // // Ignoring the other fields of the message, the domain name of question section and answer // section are presented as: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 12 | 5 | h | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 14 | e | l | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 16 | l | o | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 18 | 7 | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 20 | x | a | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 22 | m | p | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 24 | l | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 26 | 3 | c | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 28 | o | m | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 30 | 0 | ... | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 35 | 5 | h | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 37 | e | l | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 39 | l | o | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 41 | 1 1| 18 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ const std::vector<uint8_t> kResponseLabelEndingWithAPointer = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xc0, 0x12, /* Name: hello.example.com (a label ending with a pointer) */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; for (const auto& response : {kResponseAPointer, kResponseLabelEndingWithAPointer}) { SCOPED_TRACE(StringPrintf("Hex dump: %s", toHex(makeSlice(response)).c_str())); test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET); dns.addMappingBinaryPacket(kHelloExampleComQueryV4, response); StartDns(dns, {}); ASSERT_TRUE(mDnsClient.SetResolversForNetwork()); // Expect no cache because the TTL of testing responses are 0. VerifyQueryHelloExampleComV4(dns, calltype); } } No newline at end of file tests/resolv_gold_test.cpp +0 −38 Original line number Diff line number Diff line Loading @@ -33,44 +33,6 @@ namespace net { using android::net::NetworkDnsEventReported; using android::netdutils::ScopedAddrinfo; static const std::vector<uint8_t> kHelloExampleComQueryV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x01, 0x00, /* Flags: rd */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x00, /* Answer RRs: 0 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01 /* Class: IN */ }; static const std::vector<uint8_t> kHelloExampleComResponseV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; // Fixture test class definition. class TestBase : public ::testing::Test { protected: Loading tests/resolv_test_utils.h +39 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,45 @@ static constexpr char kLocalHostAddr[] = "127.0.0.1"; static constexpr char kIp6LocalHost[] = "ip6-localhost"; static constexpr char kIp6LocalHostAddr[] = "::1"; static constexpr char kHelloExampleCom[] = "hello.example.com."; static constexpr char kHelloExampleComAddrV4[] = "1.2.3.4"; static const std::vector<uint8_t> kHelloExampleComQueryV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x01, 0x00, /* Flags: rd */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x00, /* Answer RRs: 0 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01 /* Class: IN */ }; static const std::vector<uint8_t> kHelloExampleComResponseV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; // Illegal hostnames static constexpr char kBadCharAfterPeriodHost[] = "hello.example.^com."; Loading Loading
res_send.cpp +67 −108 Original line number Diff line number Diff line Loading @@ -397,24 +397,20 @@ static DnsQueryEvent* addDnsQueryEvent(NetworkDnsEventReported* event) { int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, uint32_t flags) { int gotsomewhere, terrno, v_circuit, resplen, n; ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED; LOG(DEBUG) << __func__; // Should not happen if (anssiz < HFIXEDSZ) { // TODO: Remove errno once callers stop using it errno = EINVAL; return -EINVAL; } LOG(DEBUG) << __func__; res_pquery(buf, buflen); v_circuit = buflen > PACKETSZ; gotsomewhere = 0; terrno = ETIMEDOUT; int anslen = 0; Stopwatch cacheStopwatch; cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); ResolvCacheStatus cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs()); if (cache_status == RESOLV_CACHE_FOUND) { HEADER* hp = (HEADER*)(void*)ans; Loading Loading @@ -442,8 +438,8 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // 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); int 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); Loading @@ -454,7 +450,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } if (!fallback) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; return -ETIMEDOUT; } } Loading @@ -478,90 +474,62 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int res_set_usable_server(selectedServer, statp->nscount, usable_servers); } /* * Send request, RETRY times, or until successful. */ // Send request, RETRY times, or until successful. int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count; int useTcp = buflen > PACKETSZ; int gotsomewhere = 0; int terrno = ETIMEDOUT; for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int ns = 0; ns < statp->nscount; ns++) { for (int ns = 0; ns < statp->nscount; ++ns) { if (!usable_servers[ns]) continue; int nsaplen; time_t now = 0; int delay = 0; *rcode = RCODE_INTERNAL_ERROR; // Get server addr const sockaddr* nsap = get_nsaddr(statp, ns); nsaplen = sockaddrSize(nsap); const int nsaplen = sockaddrSize(nsap); same_ns: static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; char abuf[NI_MAXHOST]; DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 << ") address = " << abuf; ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; int delay = 0; bool fallbackTCP = false; const bool shouldRecordStats = (attempt == 0); int resplen; Stopwatch queryStopwatch; if (v_circuit) { /* Use VC; at most one attempt per server. */ bool shouldRecordStats = (attempt == 0); if (useTcp) { // TCP; at most one attempt per server. attempt = retryTimes; n = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, &delay); dnsQueryEvent->set_latency_micros( saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_TCP); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* * Only record stats the first time we try a query. This ensures that * queries that deterministically fail (e.g., a name that always returns * SERVFAIL or times out) do not unduly affect the stats. */ if (shouldRecordStats) { res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, params.max_samples); resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); } LOG(INFO) << __func__ << ": used send_vc " << n; if (n < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); return -terrno; }; if (n == 0) goto next_ns; resplen = n; resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, &delay); } else { /* Use datagrams. */ LOG(INFO) << __func__ << ": using send_dg"; n = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, // UDP resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, &gotsomewhere, &now, rcode, &delay); fallbackTCP = useTcp ? true : false; } LOG(INFO) << __func__ << ": used send_" << ((useTcp) ? "vc " : "dg ") << resplen; dnsQueryEvent->set_latency_micros( saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_UDP); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* Only record stats the first time we try a query. See above. */ if (attempt == 0) { // Only record stats the first time we try a query. This ensures that // queries that deterministically fail (e.g., a name that always returns // SERVFAIL or times out) do not unduly affect the stats. if (shouldRecordStats) { res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, Loading @@ -569,17 +537,16 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); } LOG(INFO) << __func__ << ": used send_dg " << n; if (n < 0) { if (resplen == 0) continue; if (fallbackTCP) { ns--; continue; } if (resplen < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); return -terrno; }; if (n == 0) goto next_ns; if (v_circuit) goto same_ns; resplen = n; } LOG(DEBUG) << __func__ << ": got answer:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); Loading @@ -589,23 +556,15 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } res_nclose(statp); return (resplen); next_ns:; } // for each ns } // for each retry res_nclose(statp); if (!v_circuit) { if (!gotsomewhere) { // TODO: Remove errno once callers stop using it errno = ECONNREFUSED; /* no nameservers found */ terrno = ECONNREFUSED; } else { terrno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT : ECONNREFUSED; // TODO: Remove errno once callers stop using it errno = ETIMEDOUT; /* no answer obtained */ terrno = ETIMEDOUT; } } else { errno = terrno; } errno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT /* no answer obtained */ : ECONNREFUSED /* no nameservers found */; _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; } Loading
resolv_integration_test.cpp +155 −26 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include <netdutils/InternetAddresses.h> #include <netdutils/NetworkConstants.h> // SHA256_SIZE #include <netdutils/ResponseCode.h> #include <netdutils/Slice.h> #include <netdutils/SocketOption.h> #include <netinet/in.h> #include <openssl/base64.h> Loading Loading @@ -89,8 +90,10 @@ using android::net::INetd; using android::net::ResolverStats; using android::net::metrics::DnsMetricsListener; using android::netdutils::enableSockopt; using android::netdutils::makeSlice; using android::netdutils::ResponseCode; using android::netdutils::ScopedAddrinfo; using android::netdutils::toHex; // TODO: move into libnetdutils? namespace { Loading Loading @@ -3492,23 +3495,39 @@ TEST_F(ResolverTest, ConnectTlsServerTimeout) { // TODO: Perhaps move parameterized tests to an independent file. enum class CallType { GETADDRINFO, GETHOSTBYNAME }; class ResolverParameterizedTest : public ResolverTest, public testing::WithParamInterface<CallType> {}; public testing::WithParamInterface<CallType> { protected: void VerifyQueryHelloExampleComV4(const test::DNSResponder& dns, const CallType calltype) { if (calltype == CallType::GETADDRINFO) { const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM}; ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints); ASSERT_TRUE(result != nullptr); EXPECT_EQ(kHelloExampleComAddrV4, ToString(result)); } else if (calltype == CallType::GETHOSTBYNAME) { const hostent* result = gethostbyname("hello"); ASSERT_TRUE(result != nullptr); ASSERT_EQ(4, result->h_length); ASSERT_FALSE(result->h_addr_list[0] == nullptr); EXPECT_EQ(kHelloExampleComAddrV4, ToString(result)); EXPECT_TRUE(result->h_addr_list[1] == nullptr); } else { FAIL() << "Unsupported call type: " << static_cast<uint32_t>(calltype); } EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom)); } }; INSTANTIATE_TEST_SUITE_P(TestQueryCall, ResolverParameterizedTest, INSTANTIATE_TEST_SUITE_P(QueryCallTest, ResolverParameterizedTest, testing::Values(CallType::GETADDRINFO, CallType::GETHOSTBYNAME), [](const testing::TestParamInfo<CallType>& info) { std::string name; switch (info.param) { case CallType::GETADDRINFO: name = "GetAddrInfo"; break; return "GetAddrInfo"; case CallType::GETHOSTBYNAME: name = "GetHostByName"; break; return "GetHostByName"; default: name = "InvalidParameter"; // Should not happen. return "InvalidParameter"; // Should not happen. } return name; }); TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) { Loading Loading @@ -3549,7 +3568,7 @@ TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) { .rclass = ns_c_in, .ttl = 0, // no cache }; EXPECT_TRUE(test::DNSResponder::fillRdata("1.2.3.4", recordAnswer)); EXPECT_TRUE(test::DNSResponder::fillRdata(kHelloExampleComAddrV4, recordAnswer)); header.answers.push_back(std::move(recordAnswer)); // Authority section. Loading Loading @@ -3580,21 +3599,131 @@ TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) { 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); VerifyQueryHelloExampleComV4(dns, calltype); } TEST_P(ResolverParameterizedTest, MessageCompression) { const auto& calltype = GetParam(); // The response with compressed domain name by a pointer. See RFC 1035 section 4.1.4. // // Ignoring the other fields of the message, the domain name of question section and answer // section are presented as: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 12 | 5 | h | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 14 | e | l | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 16 | l | o | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 18 | 7 | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 20 | x | a | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 22 | m | p | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 24 | l | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 26 | 3 | c | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 28 | o | m | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 30 | 0 | ... | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 35 | 1 1| 12 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ const std::vector<uint8_t> kResponseAPointer = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0xc0, 0x0c, /* Name: hello.example.com (a pointer) */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; // The response with compressed domain name by a sequence of labels ending with a pointer. See // RFC 1035 section 4.1.4. // // Ignoring the other fields of the message, the domain name of question section and answer // section are presented as: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 12 | 5 | h | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 14 | e | l | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 16 | l | o | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 18 | 7 | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 20 | x | a | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 22 | m | p | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 24 | l | e | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 26 | 3 | c | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 28 | o | m | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 30 | 0 | ... | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 35 | 5 | h | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 37 | e | l | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 39 | l | o | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // 41 | 1 1| 18 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ const std::vector<uint8_t> kResponseLabelEndingWithAPointer = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xc0, 0x12, /* Name: hello.example.com (a label ending with a pointer) */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; for (const auto& response : {kResponseAPointer, kResponseLabelEndingWithAPointer}) { SCOPED_TRACE(StringPrintf("Hex dump: %s", toHex(makeSlice(response)).c_str())); test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET); dns.addMappingBinaryPacket(kHelloExampleComQueryV4, response); StartDns(dns, {}); ASSERT_TRUE(mDnsClient.SetResolversForNetwork()); // Expect no cache because the TTL of testing responses are 0. VerifyQueryHelloExampleComV4(dns, calltype); } } No newline at end of file
tests/resolv_gold_test.cpp +0 −38 Original line number Diff line number Diff line Loading @@ -33,44 +33,6 @@ namespace net { using android::net::NetworkDnsEventReported; using android::netdutils::ScopedAddrinfo; static const std::vector<uint8_t> kHelloExampleComQueryV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x01, 0x00, /* Flags: rd */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x00, /* Answer RRs: 0 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01 /* Class: IN */ }; static const std::vector<uint8_t> kHelloExampleComResponseV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; // Fixture test class definition. class TestBase : public ::testing::Test { protected: Loading
tests/resolv_test_utils.h +39 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,45 @@ static constexpr char kLocalHostAddr[] = "127.0.0.1"; static constexpr char kIp6LocalHost[] = "ip6-localhost"; static constexpr char kIp6LocalHostAddr[] = "::1"; static constexpr char kHelloExampleCom[] = "hello.example.com."; static constexpr char kHelloExampleComAddrV4[] = "1.2.3.4"; static const std::vector<uint8_t> kHelloExampleComQueryV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x01, 0x00, /* Flags: rd */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x00, /* Answer RRs: 0 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01 /* Class: IN */ }; static const std::vector<uint8_t> kHelloExampleComResponseV4 = { /* Header */ 0x00, 0x00, /* Transaction ID: 0x0000 */ 0x81, 0x80, /* Flags: qr rd ra */ 0x00, 0x01, /* Questions: 1 */ 0x00, 0x01, /* Answer RRs: 1 */ 0x00, 0x00, /* Authority RRs: 0 */ 0x00, 0x00, /* Additional RRs: 0 */ /* Queries */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ /* Answers */ 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */ 0x00, 0x01, /* Type: A */ 0x00, 0x01, /* Class: IN */ 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */ 0x00, 0x04, /* Data length: 4 */ 0x01, 0x02, 0x03, 0x04 /* Address: 1.2.3.4 */ }; // Illegal hostnames static constexpr char kBadCharAfterPeriodHost[] = "hello.example.^com."; Loading