Loading res_send.cpp +3 −1 Original line number Original line Diff line number Diff line Loading @@ -506,6 +506,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int const bool shouldRecordStats = (attempt == 0); const bool shouldRecordStats = (attempt == 0); int resplen; int resplen; Stopwatch queryStopwatch; Stopwatch queryStopwatch; int retry_count_for_event = 0; if (useTcp) { if (useTcp) { // TCP; at most one attempt per server. // TCP; at most one attempt per server. attempt = retryTimes; attempt = retryTimes; Loading @@ -524,6 +525,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, &gotsomewhere, &now, rcode, &delay); &gotsomewhere, &now, rcode, &delay); fallbackTCP = useTcp ? true : false; fallbackTCP = useTcp ? true : false; retry_count_for_event = attempt; LOG(INFO) << __func__ << ": used send_dg " << resplen; LOG(INFO) << __func__ << ": used send_dg " << resplen; } } Loading @@ -532,7 +534,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_retry_times(retry_count_for_event); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_type(getQueryType(buf, buflen)); dnsQueryEvent->set_type(getQueryType(buf, buflen)); Loading resolv_unit_test.cpp +296 −0 Original line number Original line Diff line number Diff line Loading @@ -641,6 +641,179 @@ TEST_F(ResolvGetAddrInfoTest, ServerResponseError) { // TODO: Add private DNS server timeout test. // TODO: Add private DNS server timeout test. TEST_F(ResolvGetAddrInfoTest, ServerTimeout) { TEST_F(ResolvGetAddrInfoTest, ServerTimeout) { constexpr char host_name[] = "hello.example.com."; constexpr char host_name[] = "hello.example.com."; // Following fields will not be verified during the test in proto NetworkDnsEventReported. // So don't need to config those values: event_type, return_code, latency_micros, // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes. // Expected_event is 16 DNS queries and only "type" and "retry_times" fields are changed. // 2(T_AAAA + T_A) * 2(w/ retry) * 2(query w/ and w/o domain) * 2(SOCK_DGRAM and SOCK_STREAM) constexpr char expected_event[] = R"Event( NetworkDnsEventReported { dns_query_events: { dns_query_event:[ { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, ] } })Event"; test::DNSResponder dns(static_cast<ns_rcode>(-1) /*no response*/); test::DNSResponder dns(static_cast<ns_rcode>(-1) /*no response*/); dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4"); dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4"); dns.setResponseProbability(0.0); // always ignore requests and don't response dns.setResponseProbability(0.0); // always ignore requests and don't response Loading @@ -651,6 +824,7 @@ TEST_F(ResolvGetAddrInfoTest, ServerTimeout) { const addrinfo hints = {.ai_family = AF_UNSPEC}; const addrinfo hints = {.ai_family = AF_UNSPEC}; NetworkDnsEventReported event; NetworkDnsEventReported event; int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event); int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event); EXPECT_THAT(event, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(expected_event))); EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv); EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv); } } Loading Loading @@ -810,6 +984,128 @@ TEST_F(ResolvGetAddrInfoTest, MultiAnswerSections) { } } } } TEST_F(ResolvGetAddrInfoTest, TruncatedResponse) { // Following fields will not be verified during the test in proto NetworkDnsEventReported. // So don't need to config those values: event_type, return_code, latency_micros, // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes. constexpr char event_ipv4[] = R"Event( NetworkDnsEventReported { dns_query_events: { dns_query_event:[ { rcode: 254, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 1, cache_hit: 1, ip_version: 1, protocol: 2, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 1, cache_hit: 2, ip_version: 0, protocol: 0, retry_times: 0, dns_server_index: 0, connected: 0, } ] } })Event"; constexpr char event_ipv6[] = R"Event( NetworkDnsEventReported { dns_query_events: { dns_query_event:[ { rcode: 254, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 28, cache_hit: 1, ip_version: 1, protocol: 2, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 28, cache_hit: 2, ip_version: 0, protocol: 0, retry_times: 0, dns_server_index: 0, connected: 0, } ] } })Event"; test::DNSResponder dns; dns.addMapping(kHelloExampleCom, ns_type::ns_t_cname, kCnameA); dns.addMapping(kCnameA, ns_type::ns_t_cname, kCnameB); dns.addMapping(kCnameB, ns_type::ns_t_cname, kCnameC); dns.addMapping(kCnameC, ns_type::ns_t_cname, kCnameD); dns.addMapping(kCnameD, ns_type::ns_t_a, kHelloExampleComAddrV4); dns.addMapping(kCnameD, ns_type::ns_t_aaaa, kHelloExampleComAddrV6); ASSERT_TRUE(dns.startServer()); ASSERT_EQ(0, SetResolvers()); static const struct TestConfig { int ai_family; const std::string expected_addr; const std::string expected_event; } testConfigs[]{ {AF_INET, kHelloExampleComAddrV4, event_ipv4}, {AF_INET6, kHelloExampleComAddrV6, event_ipv6}, }; for (const auto& config : testConfigs) { SCOPED_TRACE(StringPrintf("family: %d", config.ai_family)); dns.clearQueries(); addrinfo* result = nullptr; const addrinfo hints = {.ai_family = config.ai_family}; NetworkDnsEventReported event; int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event); EXPECT_THAT(event, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(config.expected_event))); ScopedAddrinfo result_cleanup(result); EXPECT_EQ(rv, 0); EXPECT_TRUE(result != nullptr); // Expect UDP response is truncated. The resolver retries over TCP. See RFC 1035 // section 4.2.1. EXPECT_EQ(GetNumQueriesForProtocol(dns, IPPROTO_UDP, kHelloExampleCom), 1U); EXPECT_EQ(GetNumQueriesForProtocol(dns, IPPROTO_TCP, kHelloExampleCom), 1U); EXPECT_EQ(ToString(result), config.expected_addr); } } TEST_F(GetHostByNameForNetContextTest, AlphabeticalHostname) { TEST_F(GetHostByNameForNetContextTest, AlphabeticalHostname) { constexpr char host_name[] = "jiababuei.example.com."; constexpr char host_name[] = "jiababuei.example.com."; constexpr char v4addr[] = "1.2.3.4"; constexpr char v4addr[] = "1.2.3.4"; Loading Loading
res_send.cpp +3 −1 Original line number Original line Diff line number Diff line Loading @@ -506,6 +506,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int const bool shouldRecordStats = (attempt == 0); const bool shouldRecordStats = (attempt == 0); int resplen; int resplen; Stopwatch queryStopwatch; Stopwatch queryStopwatch; int retry_count_for_event = 0; if (useTcp) { if (useTcp) { // TCP; at most one attempt per server. // TCP; at most one attempt per server. attempt = retryTimes; attempt = retryTimes; Loading @@ -524,6 +525,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, &gotsomewhere, &now, rcode, &delay); &gotsomewhere, &now, rcode, &delay); fallbackTCP = useTcp ? true : false; fallbackTCP = useTcp ? true : false; retry_count_for_event = attempt; LOG(INFO) << __func__ << ": used send_dg " << resplen; LOG(INFO) << __func__ << ": used send_dg " << resplen; } } Loading @@ -532,7 +534,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_retry_times(retry_count_for_event); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_type(getQueryType(buf, buflen)); dnsQueryEvent->set_type(getQueryType(buf, buflen)); Loading
resolv_unit_test.cpp +296 −0 Original line number Original line Diff line number Diff line Loading @@ -641,6 +641,179 @@ TEST_F(ResolvGetAddrInfoTest, ServerResponseError) { // TODO: Add private DNS server timeout test. // TODO: Add private DNS server timeout test. TEST_F(ResolvGetAddrInfoTest, ServerTimeout) { TEST_F(ResolvGetAddrInfoTest, ServerTimeout) { constexpr char host_name[] = "hello.example.com."; constexpr char host_name[] = "hello.example.com."; // Following fields will not be verified during the test in proto NetworkDnsEventReported. // So don't need to config those values: event_type, return_code, latency_micros, // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes. // Expected_event is 16 DNS queries and only "type" and "retry_times" fields are changed. // 2(T_AAAA + T_A) * 2(w/ retry) * 2(query w/ and w/o domain) * 2(SOCK_DGRAM and SOCK_STREAM) constexpr char expected_event[] = R"Event( NetworkDnsEventReported { dns_query_events: { dns_query_event:[ { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, } { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 255, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 1, dns_server_index: 0, connected: 0, }, ] } })Event"; test::DNSResponder dns(static_cast<ns_rcode>(-1) /*no response*/); test::DNSResponder dns(static_cast<ns_rcode>(-1) /*no response*/); dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4"); dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4"); dns.setResponseProbability(0.0); // always ignore requests and don't response dns.setResponseProbability(0.0); // always ignore requests and don't response Loading @@ -651,6 +824,7 @@ TEST_F(ResolvGetAddrInfoTest, ServerTimeout) { const addrinfo hints = {.ai_family = AF_UNSPEC}; const addrinfo hints = {.ai_family = AF_UNSPEC}; NetworkDnsEventReported event; NetworkDnsEventReported event; int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event); int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event); EXPECT_THAT(event, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(expected_event))); EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv); EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv); } } Loading Loading @@ -810,6 +984,128 @@ TEST_F(ResolvGetAddrInfoTest, MultiAnswerSections) { } } } } TEST_F(ResolvGetAddrInfoTest, TruncatedResponse) { // Following fields will not be verified during the test in proto NetworkDnsEventReported. // So don't need to config those values: event_type, return_code, latency_micros, // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes. constexpr char event_ipv4[] = R"Event( NetworkDnsEventReported { dns_query_events: { dns_query_event:[ { rcode: 254, type: 1, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 1, cache_hit: 1, ip_version: 1, protocol: 2, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 1, cache_hit: 2, ip_version: 0, protocol: 0, retry_times: 0, dns_server_index: 0, connected: 0, } ] } })Event"; constexpr char event_ipv6[] = R"Event( NetworkDnsEventReported { dns_query_events: { dns_query_event:[ { rcode: 254, type: 28, cache_hit: 1, ip_version: 1, protocol: 1, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 28, cache_hit: 1, ip_version: 1, protocol: 2, retry_times: 0, dns_server_index: 0, connected: 0, }, { rcode: 0, type: 28, cache_hit: 2, ip_version: 0, protocol: 0, retry_times: 0, dns_server_index: 0, connected: 0, } ] } })Event"; test::DNSResponder dns; dns.addMapping(kHelloExampleCom, ns_type::ns_t_cname, kCnameA); dns.addMapping(kCnameA, ns_type::ns_t_cname, kCnameB); dns.addMapping(kCnameB, ns_type::ns_t_cname, kCnameC); dns.addMapping(kCnameC, ns_type::ns_t_cname, kCnameD); dns.addMapping(kCnameD, ns_type::ns_t_a, kHelloExampleComAddrV4); dns.addMapping(kCnameD, ns_type::ns_t_aaaa, kHelloExampleComAddrV6); ASSERT_TRUE(dns.startServer()); ASSERT_EQ(0, SetResolvers()); static const struct TestConfig { int ai_family; const std::string expected_addr; const std::string expected_event; } testConfigs[]{ {AF_INET, kHelloExampleComAddrV4, event_ipv4}, {AF_INET6, kHelloExampleComAddrV6, event_ipv6}, }; for (const auto& config : testConfigs) { SCOPED_TRACE(StringPrintf("family: %d", config.ai_family)); dns.clearQueries(); addrinfo* result = nullptr; const addrinfo hints = {.ai_family = config.ai_family}; NetworkDnsEventReported event; int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event); EXPECT_THAT(event, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(config.expected_event))); ScopedAddrinfo result_cleanup(result); EXPECT_EQ(rv, 0); EXPECT_TRUE(result != nullptr); // Expect UDP response is truncated. The resolver retries over TCP. See RFC 1035 // section 4.2.1. EXPECT_EQ(GetNumQueriesForProtocol(dns, IPPROTO_UDP, kHelloExampleCom), 1U); EXPECT_EQ(GetNumQueriesForProtocol(dns, IPPROTO_TCP, kHelloExampleCom), 1U); EXPECT_EQ(ToString(result), config.expected_addr); } } TEST_F(GetHostByNameForNetContextTest, AlphabeticalHostname) { TEST_F(GetHostByNameForNetContextTest, AlphabeticalHostname) { constexpr char host_name[] = "jiababuei.example.com."; constexpr char host_name[] = "jiababuei.example.com."; constexpr char v4addr[] = "1.2.3.4"; constexpr char v4addr[] = "1.2.3.4"; Loading