summaryrefslogtreecommitdiffstats
path: root/net/dns
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-17 20:05:59 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-17 20:05:59 +0000
commitec666ab229bffb09e7ee4757e2d4224475564635 (patch)
treeeeef8ce113a7996018d8d6c1adc82dacb8ee6cc6 /net/dns
parentb9317188d97029eb518838fbf187c30fb7aa3a9f (diff)
downloadchromium_src-ec666ab229bffb09e7ee4757e2d4224475564635.zip
chromium_src-ec666ab229bffb09e7ee4757e2d4224475564635.tar.gz
chromium_src-ec666ab229bffb09e7ee4757e2d4224475564635.tar.bz2
[net/dns] Add test DualFamilyLocalhost and fix it when DnsClient enabled.
On some platforms, listening on "localhost" binds to the IPv6 loopback (::1), even if there's no global IPv6 connectivity. In such situations, HostResolverImpl restricts lookups to IPv4 (AF_INET) for performance reasons, but then navigating to http://localhost results in "connection refused". HostResolverProc has a workaround for this situation. This CL adds a test for this behavior and replicates the workaround in HostResolverImpl::ServeFromHosts (for the built-in asynchronous DNS). BUG=224215 Review URL: https://codereview.chromium.org/14208010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194663 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/dns')
-rw-r--r--net/dns/host_resolver_impl.cc32
-rw-r--r--net/dns/host_resolver_impl_unittest.cc80
-rw-r--r--net/dns/host_resolver_proc.h2
3 files changed, 106 insertions, 8 deletions
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 74a7675..d9c43df 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -250,6 +250,25 @@ AddressList EnsurePortOnAddressList(const AddressList& list, uint16 port) {
return AddressList::CopyWithPort(list, port);
}
+// Returns true if |addresses| contains only IPv4 loopback addresses.
+bool IsAllIPv4Loopback(const AddressList& addresses) {
+ for (unsigned i = 0; i < addresses.size(); ++i) {
+ const IPAddressNumber& address = addresses[i].address();
+ switch (addresses[i].GetFamily()) {
+ case ADDRESS_FAMILY_IPV4:
+ if (address[0] != 127)
+ return false;
+ break;
+ case ADDRESS_FAMILY_IPV6:
+ return false;
+ default:
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
// Creates NetLog parameters when the resolve failed.
base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number,
int net_error,
@@ -1950,7 +1969,6 @@ bool HostResolverImpl::ServeFromHosts(const Key& key,
DCHECK(addresses);
if (!HaveDnsConfig())
return false;
-
addresses->clear();
// HOSTS lookups are case-insensitive.
@@ -1979,6 +1997,17 @@ bool HostResolverImpl::ServeFromHosts(const Key& key,
addresses->push_back(IPEndPoint(it->second, info.port()));
}
+ // If got only loopback addresses and the family was restricted, resolve
+ // again, without restrictions. See SystemHostResolverCall for rationale.
+ if ((key.host_resolver_flags &
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) &&
+ IsAllIPv4Loopback(*addresses)) {
+ Key new_key(key);
+ new_key.address_family = ADDRESS_FAMILY_UNSPECIFIED;
+ new_key.host_resolver_flags &=
+ ~HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ return ServeFromHosts(new_key, info, addresses);
+ }
return !addresses->empty();
}
@@ -2118,6 +2147,7 @@ void HostResolverImpl::OnIPAddressChanged() {
void HostResolverImpl::OnDNSChanged() {
DnsConfig dns_config;
NetworkChangeNotifier::GetDnsConfig(&dns_config);
+
if (net_log_) {
net_log_->AddGlobalEntry(
NetLog::TYPE_DNS_CONFIG_CHANGED,
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 9ff359f..a262131 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -177,6 +177,16 @@ class MockHostResolverProc : public HostResolverProc {
DISALLOW_COPY_AND_ASSIGN(MockHostResolverProc);
};
+bool AddressListContains(const AddressList& list, const std::string& address,
+ int port) {
+ IPAddressNumber ip;
+ bool rv = ParseIPLiteralToNumber(address, &ip);
+ DCHECK(rv);
+ return std::find(list.begin(),
+ list.end(),
+ IPEndPoint(ip, port)) != list.end();
+}
+
// A wrapper for requests to a HostResolver.
class Request {
public:
@@ -231,12 +241,7 @@ class Request {
bool pending() const { return handle_ != NULL; }
bool HasAddress(const std::string& address, int port) const {
- IPAddressNumber ip;
- bool rv = ParseIPLiteralToNumber(address, &ip);
- DCHECK(rv);
- return std::find(list_.begin(),
- list_.end(),
- IPEndPoint(ip, port)) != list_.end();
+ return AddressListContains(list_, address, port);
}
// Returns the number of addresses in |list_|.
@@ -1482,4 +1487,67 @@ TEST_F(HostResolverImplDnsTest, DontDisableDnsClientOnSporadicFailure) {
EXPECT_EQ(OK, req->WaitForResult());
}
+// Confirm that resolving "localhost" is unrestricted even if there are no
+// global IPv6 address. See SystemHostResolverCall for rationale.
+// Test both the DnsClient and system host resolver paths.
+TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
+ // Use regular SystemHostResolverCall!
+ scoped_refptr<HostResolverProc> proc(new SystemHostResolverProc());
+ resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ DefaultParams(proc),
+ NULL));
+ resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
+
+ // Get the expected output.
+ AddressList addrlist;
+ int rv = proc->Resolve("localhost", ADDRESS_FAMILY_UNSPECIFIED, 0, &addrlist,
+ NULL);
+ if (rv != OK)
+ return;
+
+ for (unsigned i = 0; i < addrlist.size(); ++i)
+ LOG(WARNING) << addrlist[i].ToString();
+
+ bool saw_ipv4 = AddressListContains(addrlist, "127.0.0.1", 0);
+ bool saw_ipv6 = AddressListContains(addrlist, "::1", 0);
+ if (!saw_ipv4 && !saw_ipv6)
+ return;
+
+ HostResolver::RequestInfo info(HostPortPair("localhost", 80));
+ info.set_address_family(ADDRESS_FAMILY_UNSPECIFIED);
+ info.set_host_resolver_flags(HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6);
+
+ // Try without DnsClient.
+ ChangeDnsConfig(DnsConfig());
+ Request* req = CreateRequest(info);
+ // It is resolved via getaddrinfo, so expect asynchronous result.
+ EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
+ EXPECT_EQ(OK, req->WaitForResult());
+
+ EXPECT_EQ(saw_ipv4, req->HasAddress("127.0.0.1", 80));
+ EXPECT_EQ(saw_ipv6, req->HasAddress("::1", 80));
+
+ // Configure DnsClient with dual-host HOSTS file.
+ DnsConfig config = CreateValidDnsConfig();
+ DnsHosts hosts;
+ IPAddressNumber local_ipv4, local_ipv6;
+ ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &local_ipv4));
+ ASSERT_TRUE(ParseIPLiteralToNumber("::1", &local_ipv6));
+ if (saw_ipv4)
+ hosts[DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4)] = local_ipv4;
+ if (saw_ipv6)
+ hosts[DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6)] = local_ipv6;
+ config.hosts = hosts;
+
+ ChangeDnsConfig(config);
+ req = CreateRequest(info);
+ // Expect synchronous resolution from DnsHosts.
+ EXPECT_EQ(OK, req->Resolve());
+
+ EXPECT_EQ(saw_ipv4, req->HasAddress("127.0.0.1", 80));
+ EXPECT_EQ(saw_ipv6, req->HasAddress("::1", 80));
+}
+
} // namespace net
diff --git a/net/dns/host_resolver_proc.h b/net/dns/host_resolver_proc.h
index ee8777f..014a720 100644
--- a/net/dns/host_resolver_proc.h
+++ b/net/dns/host_resolver_proc.h
@@ -92,7 +92,7 @@ NET_EXPORT_PRIVATE int SystemHostResolverCall(
int* os_error);
// Wraps call to SystemHostResolverCall as an instance of HostResolverProc.
-class SystemHostResolverProc : public HostResolverProc {
+class NET_EXPORT_PRIVATE SystemHostResolverProc : public HostResolverProc {
public:
SystemHostResolverProc();
virtual int Resolve(const std::string& hostname,