// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/dns/dns_task_results_manager.h" #include #include #include #include #include "base/check.h" #include "base/functional/callback_forward.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "net/base/connection_endpoint_metadata.h" #include "net/base/net_errors.h" #include "net/dns/host_resolver_internal_result.h" #include "net/dns/host_resolver_results_test_util.h" #include "net/dns/https_record_rdata.h" #include "net/test/test_with_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" #include "url/scheme_host_port.h" using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::UnorderedElementsAre; namespace net { namespace { class FakeDelegate : public DnsTaskResultsManager::Delegate { public: FakeDelegate() = default; ~FakeDelegate() override = default; private: void OnServiceEndpointsUpdated() override { // Do nothing for now. } }; IPEndPoint MakeIPEndPoint(std::string_view ip_literal, uint16_t port = 0) { std::optional ip = IPAddress::FromIPLiteral(std::move(ip_literal)); return IPEndPoint(*ip, port); } std::unique_ptr CreateDataResult( std::string_view domain_name, std::vector ip_endpoints, DnsQueryType query_type) { return std::make_unique( std::string(domain_name), query_type, /*expiration=*/base::TimeTicks(), /*timed_expiration=*/base::Time(), HostResolverInternalResult::Source::kDns, std::move(ip_endpoints), std::vector(), std::vector()); } std::unique_ptr CreateNoData( std::string_view domain_name, DnsQueryType query_type) { return std::make_unique( std::string(domain_name), query_type, /*expiration=*/base::TimeTicks(), /*timed_expiration=*/base::Time(), HostResolverInternalResult::Source::kDns, ERR_NAME_NOT_RESOLVED); } std::unique_ptr CreateMetadata( std::string_view domain_name, std::multimap metadatas) { return std::make_unique( std::string(domain_name), DnsQueryType::HTTPS, /*expiration=*/base::TimeTicks(), /*timed_expiration=*/base::Time(), HostResolverInternalResult::Source::kDns, std::move(metadatas)); } std::unique_ptr CreateAlias( std::string_view domain_name, DnsQueryType query_type, std::string_view alias_target) { return std::make_unique( std::string(domain_name), query_type, /*expiration=*/base::TimeTicks(), /*timed_expiration=*/base::Time(), HostResolverInternalResult::Source::kDns, std::string(alias_target)); } std::vector WithPort(const std::vector& endpoints, uint16_t port) { std::vector out_endpoints; for (const auto& endpoint : endpoints) { out_endpoints.emplace_back(endpoint.address(), port); } return out_endpoints; } static constexpr std::string_view kHostName = "www.example.com"; static constexpr std::string_view kAliasTarget1 = "alias1.example.net"; static constexpr std::string_view kAliasTarget2 = "alias2.example.net"; static const ConnectionEndpointMetadata kMetadata1( /*supported_protocol_alpns=*/{"h3"}, /*ech_config_list=*/{}, std::string(kHostName)); static const ConnectionEndpointMetadata kMetadata2( /*supported_protocol_alpns=*/{"h2", "http/1.1"}, /*ech_config_list=*/{}, std::string(kHostName)); static const std::multimap kMetadatas{{1, kMetadata1}, {2, kMetadata2}}; // A helper class to create a DnsTaskResultsManager. class ManagerFactory { public: explicit ManagerFactory(DnsTaskResultsManager::Delegate* delegate) : delegate_(delegate), host_( HostResolver::Host(url::SchemeHostPort("https", kHostName, 443))) {} std::unique_ptr Create() { return std::make_unique( delegate_, host_, query_types_, NetLogWithSource()); } ManagerFactory& query_types(DnsQueryTypeSet query_types) { query_types_ = query_types; return *this; } private: raw_ptr delegate_; HostResolver::Host host_; DnsQueryTypeSet query_types_ = {DnsQueryType::A, DnsQueryType::AAAA, DnsQueryType::HTTPS}; }; } // namespace class DnsTaskResultsManagerTest : public TestWithTaskEnvironment { public: DnsTaskResultsManagerTest() : TestWithTaskEnvironment( base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} void SetUp() override { delegate_ = std::make_unique(); } protected: ManagerFactory factory() { return ManagerFactory(delegate_.get()); } private: std::unique_ptr delegate_; }; TEST_F(DnsTaskResultsManagerTest, IsMetadataReady) { // HTTPS RR is not queried. std::unique_ptr manager = factory().query_types({DnsQueryType::A, DnsQueryType::AAAA}).Create(); ASSERT_TRUE(manager->IsMetadataReady()); // HTTPS RR is queried. manager = factory() .query_types( {DnsQueryType::A, DnsQueryType::AAAA, DnsQueryType::HTTPS}) .Create(); ASSERT_FALSE(manager->IsMetadataReady()); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, /*results=*/{}); ASSERT_TRUE(manager->IsMetadataReady()); } TEST_F(DnsTaskResultsManagerTest, IPv6NotQueried) { std::unique_ptr manager = factory().query_types({DnsQueryType::A, DnsQueryType::HTTPS}).Create(); std::unique_ptr result = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443))))); EXPECT_THAT(manager->GetAliases(), UnorderedElementsAre(kHostName)); } TEST_F(DnsTaskResultsManagerTest, IPv4First) { std::unique_ptr manager = factory().Create(); // A comes first. Service endpoints creation should be delayed. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is responded. Service endpoints should be available. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result2.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); } TEST_F(DnsTaskResultsManagerTest, IPv6First) { std::unique_ptr manager = factory().Create(); // AAAA comes first. Service endpoints should be available immediately. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result1.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); // A is responded. Service endpoints should be updated. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1"), MakeIPEndPoint("192.0.2.2")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result2.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443), MakeIPEndPoint("192.0.2.2", 443)), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); } TEST_F(DnsTaskResultsManagerTest, IPv6Timedout) { std::unique_ptr manager = factory().Create(); // A comes first. Service endpoints creation should be delayed. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is timed out. Service endpoints should be available after timeout. FastForwardBy(DnsTaskResultsManager::kResolutionDelay + base::Milliseconds(1)); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443))))); // AAAA is responded after timeout. Service endpoints should be updated. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result2.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); } TEST_F(DnsTaskResultsManagerTest, IPv6NoDataBeforeIPv4) { std::unique_ptr manager = factory().Create(); // AAAA is responded with no data. Service endpoints should not be available. std::unique_ptr result1 = CreateNoData(kHostName, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // A is responded. Service endpoints creation should happen without resolution // delay. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result2.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443))))); } TEST_F(DnsTaskResultsManagerTest, IPv6NoDataAfterIPv4) { std::unique_ptr manager = factory().Create(); // A is responded. Service endpoints creation should be delayed. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is responded with no data before the resolution delay timer. Service // endpoints should be available without waiting for the timeout. std::unique_ptr result2 = CreateNoData(kHostName, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result2.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443))))); } TEST_F(DnsTaskResultsManagerTest, IPv6EmptyDataAfterIPv4) { std::unique_ptr manager = factory().Create(); // A is responded. Service endpoints creation should be delayed. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is responded with a non-cacheable result (an empty result) before the // resolution delay timer. Service endpoints should be available without // waiting for the timeout. manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443))))); } TEST_F(DnsTaskResultsManagerTest, IPv4AndIPv6NoData) { std::unique_ptr manager = factory().Create(); // AAAA is responded with no data. Service endpoints should not be available. std::unique_ptr result1 = CreateNoData(kHostName, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // A is responded with no data. Service endpoints should not be available. std::unique_ptr result2 = CreateNoData(kHostName, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result2.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); } TEST_F(DnsTaskResultsManagerTest, IPv4NoDataIPv6AfterResolutionDelay) { std::unique_ptr manager = factory().Create(); // A comes first with no data. Service endpoints creation should be delayed // and the resolution delay timer should not start. std::unique_ptr result1 = CreateNoData(kHostName, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result1.get()}); ASSERT_FALSE(manager->IsResolutionDelayTimerRunningForTest()); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // The resolution delay passed. Service endpoints should not be available yet. FastForwardBy(DnsTaskResultsManager::kResolutionDelay + base::Milliseconds(1)); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is responded. Service endpoints should be updated. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result2.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); } TEST_F(DnsTaskResultsManagerTest, MetadataFirst) { std::unique_ptr manager = factory().Create(); // HTTPS comes first. Service endpoints should not be available yet since // Chrome doesn't support ipv{4,6}hint yet. std::unique_ptr result1 = CreateMetadata(kHostName, kMetadatas); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, {result1.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); ASSERT_TRUE(manager->IsMetadataReady()); // A is responded. Service endpoints creation should be delayed. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result2.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is responded. Service endpoints should be available with metadatas. std::unique_ptr result3 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result3.get()}); EXPECT_THAT( manager->GetCurrentEndpoints(), ElementsAre( ExpectServiceEndpoint(ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), ElementsAre(MakeIPEndPoint("2001:db8::1", 443)), kMetadata1), ExpectServiceEndpoint(ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), ElementsAre(MakeIPEndPoint("2001:db8::1", 443)), kMetadata2))); } TEST_F(DnsTaskResultsManagerTest, MetadataDifferentTargetName) { std::unique_ptr manager = factory().Create(); // HTTPS is responded and the target name is different from QNAME. const ConnectionEndpointMetadata kMetadataDifferentTargetName( /*supported_protocol_alpns=*/{"h2", "http/1.1"}, /*ech_config_list=*/{}, /*target_name=*/"other.example.net."); std::unique_ptr result1 = CreateMetadata(kHostName, {{1, kMetadataDifferentTargetName}}); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, {result1.get()}); ASSERT_TRUE(manager->IsMetadataReady()); // AAAA is responded. Service endpoints should be available without metadatas // since the target name is different. std::unique_ptr result2 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result2.get()}); ASSERT_TRUE(manager->IsMetadataReady()); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); } TEST_F(DnsTaskResultsManagerTest, MetadataAfterIPv6) { std::unique_ptr manager = factory().Create(); // AAAA comes first. Service endpoints should be available without metadatas. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result1.get()}); ASSERT_FALSE(manager->IsMetadataReady()); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); // HTTPS is responded. Metadata should be available. std::unique_ptr result2 = CreateMetadata(kHostName, kMetadatas); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, {result2.get()}); ASSERT_TRUE(manager->IsMetadataReady()); EXPECT_THAT( manager->GetCurrentEndpoints(), ElementsAre( ExpectServiceEndpoint(IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443)), kMetadata1), ExpectServiceEndpoint(IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443)), kMetadata2))); } TEST_F(DnsTaskResultsManagerTest, IPv6TimedoutAfterMetadata) { std::unique_ptr manager = factory().Create(); // A comes first. Service endpoints creation should be delayed. std::unique_ptr result1 = CreateDataResult( kHostName, {MakeIPEndPoint("192.0.2.1")}, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result1.get()}); ASSERT_FALSE(manager->IsMetadataReady()); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // HTTPS is responded. Service endpoints should not be available because // the manager is waiting for the resolution delay and Chrome doesn't support // ipv6hint yet. std::unique_ptr result2 = CreateMetadata(kHostName, kMetadatas); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, {result2.get()}); ASSERT_TRUE(manager->IsMetadataReady()); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is timed out. Service endpoints should be available with metadatas. FastForwardBy(DnsTaskResultsManager::kResolutionDelay + base::Milliseconds(1)); ASSERT_TRUE(manager->IsMetadataReady()); EXPECT_THAT( manager->GetCurrentEndpoints(), ElementsAre( ExpectServiceEndpoint(ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), IsEmpty(), kMetadata1), ExpectServiceEndpoint(ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), IsEmpty(), kMetadata2))); } TEST_F(DnsTaskResultsManagerTest, IPv4NoDataIPv6TimedoutAfterMetadata) { std::unique_ptr manager = factory().Create(); // HTTPS is responded. Service endpoints should not be available because // the manager is waiting for the resolution delay and Chrome doesn't support // address hints yet. std::unique_ptr result1 = CreateMetadata(kHostName, kMetadatas); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, {result1.get()}); ASSERT_TRUE(manager->IsMetadataReady()); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // A is responded with no address. Service endpoints should not be available // since there are no addresses. std::unique_ptr result2 = CreateNoData(kHostName, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result2.get()}); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); // AAAA is timed out. Service endpoints should not be available since there // are no addresses. FastForwardBy(DnsTaskResultsManager::kResolutionDelay + base::Milliseconds(1)); ASSERT_TRUE(manager->GetCurrentEndpoints().empty()); } TEST_F(DnsTaskResultsManagerTest, EndpointOrdering) { // Has both IPv4/v6 addresses and metadata. constexpr static const std::string_view kSvcbHost1 = "svc1.example.com"; // Has both IPv4/v6 addresses but no metadata. constexpr static const std::string_view kSvcbHost2 = "svc2.example.com"; // Only has IPv4 addresses. constexpr static const std::string_view kSvcbHost3 = "svc3.example.com"; const std::vector kSvcbHost1IPv4s = {MakeIPEndPoint("192.0.2.1")}; const std::vector kSvcbHost2IPv4s = {MakeIPEndPoint("192.0.2.2")}; const std::vector kSvcbHost3IPv4s = {MakeIPEndPoint("192.0.2.3")}; const std::vector kSvcbHost1IPv6s = { MakeIPEndPoint("2001:db8::1")}; const std::vector kSvcbHost2IPv6s = { MakeIPEndPoint("2001:db8::2")}; const ConnectionEndpointMetadata kSvcbHost1Metadata1( /*supported_protocol_alpns=*/{"h2", "http/1.1"}, /*ech_config_list=*/{}, /*target_name=*/std::string(kSvcbHost1)); const ConnectionEndpointMetadata kSvcbHost1Metadata2( /*supported_protocol_alpns=*/{"h3"}, /*ech_config_list=*/{}, /*target_name=*/std::string(kSvcbHost1)); const std::multimap kSvcbHost1Metadatas{{1, kSvcbHost1Metadata1}, {2, kSvcbHost1Metadata2}}; struct TestData { std::string_view host; std::vector ipv4_endpoints; std::vector ipv6_endpoints; std::multimap metadatas; }; const TestData kTestDatas[] = { {kSvcbHost1, /*ipv4_addresses=*/kSvcbHost1IPv4s, /*ipv6_addresses=*/kSvcbHost1IPv6s, /*metadatas=*/kSvcbHost1Metadatas}, {kSvcbHost2, /*ipv4_addresses=*/kSvcbHost2IPv4s, /*ipv6_addresses=*/kSvcbHost2IPv6s, /*metadatas=*/{}}, {kSvcbHost3, /*ipv4_addresses=*/kSvcbHost3IPv4s, /*ipv6_addresses=*/{}, /*metadatas=*/{}}, }; std::unique_ptr manager = factory().Create(); for (const auto& testdata : kTestDatas) { if (!testdata.ipv4_endpoints.empty()) { std::unique_ptr result = CreateDataResult( testdata.host, testdata.ipv4_endpoints, DnsQueryType::A); manager->ProcessDnsTransactionResults(DnsQueryType::A, {result.get()}); } if (!testdata.ipv6_endpoints.empty()) { std::unique_ptr result = CreateDataResult( testdata.host, testdata.ipv6_endpoints, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result.get()}); } if (!testdata.metadatas.empty()) { std::unique_ptr result = CreateMetadata(testdata.host, testdata.metadatas); manager->ProcessDnsTransactionResults(DnsQueryType::HTTPS, {result.get()}); } } const std::vector kExpects = { ServiceEndpoint(WithPort(kSvcbHost1IPv4s, 443), WithPort(kSvcbHost1IPv6s, 443), kSvcbHost1Metadata1), ServiceEndpoint(WithPort(kSvcbHost1IPv4s, 443), WithPort(kSvcbHost1IPv6s, 443), kSvcbHost1Metadata2), ServiceEndpoint(WithPort(kSvcbHost2IPv4s, 443), WithPort(kSvcbHost2IPv6s, 443), ConnectionEndpointMetadata()), ServiceEndpoint(WithPort(kSvcbHost3IPv4s, 443), {}, ConnectionEndpointMetadata()), }; ASSERT_EQ(manager->GetCurrentEndpoints().size(), kExpects.size()); for (size_t i = 0; i < manager->GetCurrentEndpoints().size(); ++i) { SCOPED_TRACE(i); EXPECT_THAT(manager->GetCurrentEndpoints()[i], kExpects[i]); } } TEST_F(DnsTaskResultsManagerTest, Aliases) { std::unique_ptr manager = factory().Create(); // AAAA is responded with aliases. std::unique_ptr result1 = CreateAlias(kHostName, DnsQueryType::AAAA, kAliasTarget1); std::unique_ptr result2 = CreateAlias(kAliasTarget1, DnsQueryType::AAAA, kAliasTarget2); std::unique_ptr result3 = CreateDataResult( kHostName, {MakeIPEndPoint("2001:db8::1")}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults( DnsQueryType::AAAA, {result1.get(), result2.get(), result3.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( IsEmpty(), ElementsAre(MakeIPEndPoint("2001:db8::1", 443))))); EXPECT_THAT(manager->GetAliases(), UnorderedElementsAre(kHostName, kAliasTarget1, kAliasTarget2)); } // Regression test for crbug.com/369232963. An IPv4 mapped IPv6 address should // be handled without crashing. TEST_F(DnsTaskResultsManagerTest, Ipv4MappedIpv6) { std::unique_ptr manager = factory().Create(); auto ip_address = *IPAddress::FromIPLiteral("::ffff:192.0.2.1"); IPEndPoint endpoint(ConvertIPv4MappedIPv6ToIPv4(ip_address), /*port=*/0); std::unique_ptr result = CreateDataResult(kHostName, {endpoint}, DnsQueryType::AAAA); manager->ProcessDnsTransactionResults(DnsQueryType::AAAA, {result.get()}); EXPECT_THAT(manager->GetCurrentEndpoints(), ElementsAre(ExpectServiceEndpoint( ElementsAre(MakeIPEndPoint("192.0.2.1", 443)), IsEmpty()))); } } // namespace net