diff options
author | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-03 20:34:27 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-03 20:34:27 +0000 |
commit | eaf3a3bae88dd03ce597c2b0568fabbd79aad0ce (patch) | |
tree | 02d8a7a8a6cf6ba03038aac08664cb226d36357a /net/base | |
parent | 153b1e70cfb9e463bb2d400a4f6adcf539b92008 (diff) | |
download | chromium_src-eaf3a3bae88dd03ce597c2b0568fabbd79aad0ce.zip chromium_src-eaf3a3bae88dd03ce597c2b0568fabbd79aad0ce.tar.gz chromium_src-eaf3a3bae88dd03ce597c2b0568fabbd79aad0ce.tar.bz2 |
Fix remaining localhost resolution issues.
If host resolution is restricted to a single address family and the results of a resolution are all localhost of that type, try again without the address family restriction.
Also make --disable-ipv6 apply to resolution of ip literals.
BUG=42058, 49024, 32522
TEST=Manual testing in various network configurations. See https://spreadsheets.google.com/ccc?key=0AhSnKEusL6UgdFZIRmxTUnYtZDhjX3lKclBqMHo4YUE&hl=en&authkey=CLKDxMYB
Review URL: http://codereview.chromium.org/3231005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58534 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r-- | net/base/address_family.h | 5 | ||||
-rw-r--r-- | net/base/host_resolver_impl.cc | 46 | ||||
-rw-r--r-- | net/base/host_resolver_proc.cc | 59 | ||||
-rw-r--r-- | net/base/mock_host_resolver.cc | 37 |
4 files changed, 113 insertions, 34 deletions
diff --git a/net/base/address_family.h b/net/base/address_family.h index 49e1583..8ea5256 100644 --- a/net/base/address_family.h +++ b/net/base/address_family.h @@ -17,11 +17,14 @@ enum AddressFamily { }; // HostResolverFlags is a bitflag enum used by host resolver procedures to -// determine the value of addrinfo.ai_flags. +// determine the value of addrinfo.ai_flags and work around getaddrinfo +// peculiarities. enum { HOST_RESOLVER_CANONNAME = 1 << 0, // AI_CANONNAME // Hint to the resolver proc that only loopback addresses are configured. HOST_RESOLVER_LOOPBACK_ONLY = 1 << 1, + // Indicate the address family was set because no IPv6 support was detected. + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 = 1 << 2, }; typedef int HostResolverFlags; diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc index 2118cb4..4b4649d 100644 --- a/net/base/host_resolver_impl.cc +++ b/net/base/host_resolver_impl.cc @@ -875,26 +875,33 @@ int HostResolverImpl::Resolve(const RequestInfo& info, // Update the net log and notify registered observers. OnStartRequest(source_net_log, request_net_log, request_id, info); + // Build a key that identifies the request in the cache and in the + // outstanding jobs map. + Key key = GetEffectiveKeyForRequest(info); + // Check for IP literal. IPAddressNumber ip_number; if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) { - DCHECK_EQ((info.host_resolver_flags() & - ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY)), 0) - << " Unhandled flag"; - AddressList result(ip_number, info.port(), - (info.host_resolver_flags() & HOST_RESOLVER_CANONNAME)); - - *addresses = result; + DCHECK_EQ(key.host_resolver_flags & + ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY | + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6), + 0) << " Unhandled flag"; + bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 && + !ipv6_probe_monitoring_; + int net_error = OK; + if (ip_number.size() == 16 && ipv6_disabled) { + net_error = ERR_NAME_NOT_RESOLVED; + } else { + AddressList result(ip_number, info.port(), + (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)); + *addresses = result; + } // Update the net log and notify registered observers. - OnFinishRequest(source_net_log, request_net_log, request_id, info, OK, - 0 /* os_error (unknown since from cache) */); - return OK; + OnFinishRequest(source_net_log, request_net_log, request_id, info, + net_error, 0 /* os_error (unknown since from cache) */); + return net_error; } - // Build a key that identifies the request in the cache and in the - // outstanding jobs map. - Key key = GetEffectiveKeyForRequest(info); - // If we have an unexpired cache entry, use it. if (info.allow_cached_response() && cache_.get()) { const HostCache::Entry* cache_entry = cache_->Lookup( @@ -1285,11 +1292,16 @@ void HostResolverImpl::ProcessQueuedRequests() { HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest( const RequestInfo& info) const { + HostResolverFlags effective_flags = + info.host_resolver_flags() | additional_resolver_flags_; AddressFamily effective_address_family = info.address_family(); - if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED) + if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED && + default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) { effective_address_family = default_address_family_; - return Key(info.hostname(), effective_address_family, - info.host_resolver_flags() | additional_resolver_flags_); + if (ipv6_probe_monitoring_) + effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + } + return Key(info.hostname(), effective_address_family, effective_flags); } HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) { diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc index fd350df..86304dc 100644 --- a/net/base/host_resolver_proc.cc +++ b/net/base/host_resolver_proc.cc @@ -18,6 +18,42 @@ namespace net { +namespace { + +bool IsAllLocalhostOfOneFamily(const struct addrinfo* ai) { + bool saw_v4_localhost = false; + bool saw_v6_localhost = false; + for (; ai != NULL; ai = ai->ai_next) { + switch (ai->ai_family) { + case AF_INET: { + const struct sockaddr_in* addr_in = + reinterpret_cast<struct sockaddr_in*>(ai->ai_addr); + if ((ntohl(addr_in->sin_addr.s_addr) & 0xff000000) == 0x7f000000) + saw_v4_localhost = true; + else + return false; + break; + } + case AF_INET6: { + const struct sockaddr_in6* addr_in6 = + reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr); + if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr)) + saw_v6_localhost = true; + else + return false; + break; + } + default: + NOTREACHED(); + return false; + } + } + + return saw_v4_localhost != saw_v6_localhost; +} + +} // namespace + HostResolverProc* HostResolverProc::default_proc_ = NULL; HostResolverProc::HostResolverProc(HostResolverProc* previous) { @@ -161,15 +197,36 @@ int SystemHostResolverProc(const std::string& host, hints.ai_socktype = SOCK_STREAM; int err = getaddrinfo(host.c_str(), NULL, &hints, &ai); + bool should_retry = false; #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) // If we fail, re-initialise the resolver just in case there have been any // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. if (err && DnsReloadTimerHasExpired()) { res_nclose(&_res); if (!res_ninit(&_res)) - err = getaddrinfo(host.c_str(), NULL, &hints, &ai); + should_retry = true; } #endif + // If the lookup was restricted (either by address family, or address + // detection), and the results where all localhost of a single family, + // maybe we should retry. There were several bugs related to these + // issues, for example http://crbug.com/42058 and http://crbug.com/49024 + if ((hints.ai_family != AF_UNSPEC || hints.ai_flags & AI_ADDRCONFIG) && + err == 0 && IsAllLocalhostOfOneFamily(ai)) { + if (host_resolver_flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) { + hints.ai_family = AF_UNSPEC; + should_retry = true; + } + if (hints.ai_flags & AI_ADDRCONFIG) { + hints.ai_flags &= ~AI_ADDRCONFIG; + should_retry = true; + } + } + if (should_retry) { + freeaddrinfo(ai); + ai = NULL; + err = getaddrinfo(host.c_str(), NULL, &hints, &ai); + } if (err) { if (os_error) { diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc index 2baeb26..8c2a9a4 100644 --- a/net/base/mock_host_resolver.cc +++ b/net/base/mock_host_resolver.cc @@ -156,8 +156,10 @@ void RuleBasedHostResolverProc::AddRuleForAddressFamily( AddressFamily address_family, const std::string& replacement) { DCHECK(!replacement.empty()); - Rule rule(Rule::kResolverTypeSystem, host_pattern, - address_family, 0, replacement, "", 0); + HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + Rule rule(Rule::kResolverTypeSystem, host_pattern, address_family, flags, + replacement, "", 0); rules_.push_back(rule); } @@ -169,13 +171,12 @@ void RuleBasedHostResolverProc::AddIPLiteralRule( // consequently we do not support remapping them. IPAddressNumber ip_number; DCHECK(!ParseIPLiteralToNumber(host_pattern, &ip_number)); - Rule rule(Rule::kResolverTypeIPLiteral, - host_pattern, - ADDRESS_FAMILY_UNSPECIFIED, - canonical_name.empty() ? 0 : HOST_RESOLVER_CANONNAME, - ip_literal, - canonical_name, - 0); + HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + if (!canonical_name.empty()) + flags |= HOST_RESOLVER_CANONNAME; + Rule rule(Rule::kResolverTypeIPLiteral, host_pattern, + ADDRESS_FAMILY_UNSPECIFIED, flags, ip_literal, canonical_name, 0); rules_.push_back(rule); } @@ -184,22 +185,28 @@ void RuleBasedHostResolverProc::AddRuleWithLatency( const std::string& replacement, int latency_ms) { DCHECK(!replacement.empty()); - Rule rule(Rule::kResolverTypeSystem, host_pattern, - ADDRESS_FAMILY_UNSPECIFIED, 0, replacement, "", latency_ms); + HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, + flags, replacement, "", latency_ms); rules_.push_back(rule); } void RuleBasedHostResolverProc::AllowDirectLookup( const std::string& host_pattern) { - Rule rule(Rule::kResolverTypeSystem, host_pattern, - ADDRESS_FAMILY_UNSPECIFIED, 0, "", "", 0); + HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, + flags, "", "", 0); rules_.push_back(rule); } void RuleBasedHostResolverProc::AddSimulatedFailure( const std::string& host_pattern) { - Rule rule(Rule::kResolverTypeFail, host_pattern, - ADDRESS_FAMILY_UNSPECIFIED, 0, "", "", 0); + HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | + HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + Rule rule(Rule::kResolverTypeFail, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, + flags, "", "", 0); rules_.push_back(rule); } |