summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authorvandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-03 20:34:27 +0000
committervandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-03 20:34:27 +0000
commiteaf3a3bae88dd03ce597c2b0568fabbd79aad0ce (patch)
tree02d8a7a8a6cf6ba03038aac08664cb226d36357a /net/base
parent153b1e70cfb9e463bb2d400a4f6adcf539b92008 (diff)
downloadchromium_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.h5
-rw-r--r--net/base/host_resolver_impl.cc46
-rw-r--r--net/base/host_resolver_proc.cc59
-rw-r--r--net/base/mock_host_resolver.cc37
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);
}