summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/host_resolver_impl.cc46
-rw-r--r--net/base/host_resolver_impl_unittest.cc155
-rw-r--r--net/base/net_error_list.h3
-rw-r--r--net/dns/dns_transaction.cc2
-rw-r--r--net/dns/dns_transaction_unittest.cc2
5 files changed, 123 insertions, 85 deletions
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index 811a002..edab00e 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -137,6 +137,7 @@ enum DnsResolveStatus {
RESOLVE_STATUS_DNS_SUCCESS = 0,
RESOLVE_STATUS_PROC_SUCCESS,
RESOLVE_STATUS_FAIL,
+ RESOLVE_STATUS_SUSPECT_NETBIOS,
RESOLVE_STATUS_MAX
};
@@ -146,6 +147,25 @@ void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
RESOLVE_STATUS_MAX);
}
+bool ResemblesNetBIOSName(const std::string& hostname) {
+ return (hostname.size() < 16) && (hostname.find('.') == std::string::npos);
+}
+
+// True if |hostname| ends with either ".local" or ".local.".
+bool ResemblesMulticastDNSName(const std::string& hostname) {
+ DCHECK(!hostname.empty());
+ const char kSuffix[] = ".local.";
+ const size_t kSuffixLen = sizeof(kSuffix) - 1;
+ const size_t kSuffixLenTrimmed = kSuffixLen - 1;
+ if (hostname[hostname.size() - 1] == '.') {
+ return hostname.size() > kSuffixLen &&
+ !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
+ }
+ return hostname.size() > kSuffixLenTrimmed &&
+ !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed,
+ kSuffix, kSuffixLenTrimmed);
+}
+
//-----------------------------------------------------------------------------
// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
@@ -1055,7 +1075,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
: resolver_(resolver->AsWeakPtr()),
key_(key),
had_non_speculative_request_(false),
- had_dns_config_(false),
+ dns_task_error_(OK),
net_log_(BoundNetLog::Make(request_net_log.net_log(),
NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
@@ -1219,9 +1239,9 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
- had_dns_config_ = resolver_->HaveDnsConfig();
- // Job::Start must not complete synchronously.
- if (had_dns_config_) {
+ // Caution: Job::Start must not complete synchronously.
+ if (resolver_->HaveDnsConfig() &&
+ !ResemblesMulticastDNSName(key_.hostname)) {
StartDnsTask();
} else {
StartProcTask();
@@ -1251,10 +1271,17 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
DCHECK(is_proc_running());
- if (had_dns_config_) {
- // TODO(szym): guess if the hostname is a NetBIOS name and discount it.
+ if (dns_task_error_ != OK) {
if (net_error == OK) {
- UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
+ if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
+ ResemblesNetBIOSName(key_.hostname)) {
+ UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
+ } else {
+ UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
+ }
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
+ std::abs(dns_task_error_),
+ GetAllErrorCodesForUma());
} else {
UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
}
@@ -1291,6 +1318,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
DCHECK(is_dns_running());
if (net_error != OK) {
+ dns_task_error_ = net_error;
dns_task_.reset();
// TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
@@ -1413,8 +1441,8 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
bool had_non_speculative_request_;
- // True if resolver had DnsConfig when the Job was started.
- bool had_dns_config_;
+ // Result of DnsTask.
+ int dns_task_error_;
BoundNetLog net_log_;
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index 60d6ed1..43b2e52 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -43,46 +43,6 @@ HostResolverImpl::ProcTaskParams DefaultParams(
return HostResolverImpl::ProcTaskParams(resolver_proc, kMaxRetryAttempts);
}
-HostResolverImpl* CreateHostResolverImpl(HostResolverProc* resolver_proc) {
- return new HostResolverImpl(
- HostCache::CreateDefaultCache(),
- DefaultLimits(),
- DefaultParams(resolver_proc),
- scoped_ptr<DnsConfigService>(NULL),
- scoped_ptr<DnsClient>(NULL),
- NULL);
-}
-
-HostResolverImpl* CreateHostResolverImplWithDnsClient(
- HostResolverProc* resolver_proc,
- scoped_ptr<DnsConfigService> dns_config_service) {
- // Initially with empty DnsConfig. Use |dns_config_service| to update it.
- return new HostResolverImpl(
- HostCache::CreateDefaultCache(),
- DefaultLimits(),
- DefaultParams(resolver_proc),
- dns_config_service.Pass(),
- CreateMockDnsClient(DnsConfig()),
- NULL);
-}
-
-// This HostResolverImpl will only allow 1 outstanding resolve at a time.
-HostResolverImpl* CreateSerialHostResolverImpl(
- HostResolverProc* resolver_proc) {
- HostResolverImpl::ProcTaskParams params = DefaultParams(resolver_proc);
- params.max_retry_attempts = 0u;
-
- PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
-
- return new HostResolverImpl(
- HostCache::CreateDefaultCache(),
- limits,
- params,
- scoped_ptr<DnsConfigService>(NULL),
- scoped_ptr<DnsClient>(NULL),
- NULL);
-}
-
// A HostResolverProc that pushes each host mapped into a list and allows
// waiting for a specific number of requests. Unlike RuleBasedHostResolverProc
// it never calls SystemHostResolverProc. By default resolves all hostnames to
@@ -446,10 +406,7 @@ class HostResolverImplTest : public testing::Test {
public:
static const int kDefaultPort = 80;
- HostResolverImplTest()
- : proc_(new MockHostResolverProc()),
- resolver_(CreateHostResolverImpl(proc_)) {
- }
+ HostResolverImplTest() : proc_(new MockHostResolverProc()) {}
protected:
// A Request::Handler which is a proxy to the HostResolverImplTest fixture.
@@ -473,8 +430,29 @@ class HostResolverImplTest : public testing::Test {
HostResolverImplTest* test;
};
+ void CreateResolver() {
+ resolver_.reset(new HostResolverImpl(
+ HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ DefaultParams(proc_),
+ scoped_ptr<DnsConfigService>(NULL),
+ scoped_ptr<DnsClient>(NULL),
+ NULL));
+ }
+
+ // This HostResolverImpl will only allow 1 outstanding resolve at a time and
+ // perform no retries.
void CreateSerialResolver() {
- resolver_.reset(CreateSerialHostResolverImpl(proc_));
+ HostResolverImpl::ProcTaskParams params = DefaultParams(proc_);
+ params.max_retry_attempts = 0u;
+ PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
+ resolver_.reset(new HostResolverImpl(
+ HostCache::CreateDefaultCache(),
+ limits,
+ params,
+ scoped_ptr<DnsConfigService>(NULL),
+ scoped_ptr<DnsClient>(NULL),
+ NULL));
}
// The Request will not be made until a call to |Resolve()|, and the Job will
@@ -510,7 +488,11 @@ class HostResolverImplTest : public testing::Test {
return CreateRequest(hostname, kDefaultPort);
}
- void TearDown() OVERRIDE {
+ virtual void SetUp() OVERRIDE {
+ CreateResolver();
+ }
+
+ virtual void TearDown() OVERRIDE {
if (resolver_.get())
EXPECT_EQ(0u, resolver_->num_running_jobs_for_tests());
EXPECT_FALSE(proc_->HasBlockedRequests());
@@ -573,7 +555,7 @@ TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
proc_->SignalAll();
// To ensure there was no spurious callback, complete with a new resolver.
- resolver_.reset(CreateHostResolverImpl(proc_));
+ CreateResolver();
Request* req1 = CreateRequest("just.testing", 80);
EXPECT_EQ(ERR_IO_PENDING, req1->Resolve());
@@ -1250,19 +1232,36 @@ DnsConfig CreateValidDnsConfig() {
return config;
}
+// Specialized fixture for tests of DnsTask.
+class HostResolverImplDnsTest : public HostResolverImplTest {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ config_service_ = new MockDnsConfigService();
+ resolver_.reset(new HostResolverImpl(
+ HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ DefaultParams(proc_),
+ scoped_ptr<DnsConfigService>(config_service_),
+ CreateMockDnsClient(DnsConfig()),
+ NULL));
+ }
+
+ void ChangeDnsConfig(const DnsConfig& config) {
+ config_service_->ChangeConfig(config);
+ config_service_->ChangeHosts(config.hosts);
+ }
+
+ // Owned by |resolver_|.
+ MockDnsConfigService* config_service_;
+};
+
// TODO(szym): Test AbortAllInProgressJobs due to DnsConfig change.
// TODO(cbentzel): Test a mix of requests with different HostResolverFlags.
// Test successful and fallback resolutions in HostResolverImpl::DnsTask.
-TEST_F(HostResolverImplTest, DnsTask) {
- // Initially, there's DnsConfigService, but no DnsConfig.
- // Note, |config_service| will be owned by |resolver_|.
- MockDnsConfigService* config_service = new MockDnsConfigService();
- resolver_.reset(
- CreateHostResolverImplWithDnsClient(
- proc_,
- scoped_ptr<DnsConfigService>(config_service)));
+TEST_F(HostResolverImplDnsTest, DnsTask) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
proc_->AddRuleForAllFamilies("er_succeed", "192.168.1.101");
proc_->AddRuleForAllFamilies("nx_succeed", "192.168.1.102");
@@ -1274,9 +1273,7 @@ TEST_F(HostResolverImplTest, DnsTask) {
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[0]->WaitForResult());
- DnsConfig config = CreateValidDnsConfig();
- config_service->ChangeHosts(config.hosts);
- config_service->ChangeConfig(config);
+ ChangeDnsConfig(CreateValidDnsConfig());
EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80)->Resolve());
EXPECT_EQ(ERR_IO_PENDING, CreateRequest("er_fail", 80)->Resolve());
@@ -1286,13 +1283,13 @@ TEST_F(HostResolverImplTest, DnsTask) {
proc_->SignalMultiple(requests_.size());
- for (size_t i = 0; i < requests_.size(); ++i) {
- EXPECT_NE(ERR_UNEXPECTED, requests_[i]->WaitForResult()) << 1;
- }
+ for (size_t i = 1; i < requests_.size(); ++i)
+ EXPECT_NE(ERR_UNEXPECTED, requests_[i]->WaitForResult()) << i;
EXPECT_EQ(OK, requests_[1]->result());
// Resolved by MockDnsClient.
EXPECT_TRUE(requests_[1]->HasOneAddress("127.0.0.1", 80));
+ // Fallback to ProcTask.
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[2]->result());
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[3]->result());
EXPECT_EQ(OK, requests_[4]->result());
@@ -1301,18 +1298,9 @@ TEST_F(HostResolverImplTest, DnsTask) {
EXPECT_TRUE(requests_[5]->HasOneAddress("192.168.1.102", 80));
}
-TEST_F(HostResolverImplTest, ServeFromHosts) {
- // Note, |config_service| will be owned by |resolver_|.
- MockDnsConfigService* config_service = new MockDnsConfigService();
- resolver_.reset(
- CreateHostResolverImplWithDnsClient(
- proc_,
- scoped_ptr<DnsConfigService>(config_service)));
-
+TEST_F(HostResolverImplDnsTest, ServeFromHosts) {
// Initially, use empty HOSTS file.
- DnsConfig config = CreateValidDnsConfig();
- config_service->ChangeHosts(DnsHosts());
- config_service->ChangeConfig(config);
+ ChangeDnsConfig(CreateValidDnsConfig());
proc_->AddRuleForAllFamilies("", "0.0.0.0"); // Default to failures.
proc_->SignalMultiple(1u); // For the first request which misses.
@@ -1332,8 +1320,7 @@ TEST_F(HostResolverImplTest, ServeFromHosts) {
hosts[DnsHostsKey("er_both", ADDRESS_FAMILY_IPV6)] = local_ipv6;
// Update HOSTS file.
- config_service->ChangeConfig(config);
- config_service->ChangeHosts(hosts);
+ config_service_->ChangeHosts(hosts);
Request* req1 = CreateRequest("er_ipv4", 80);
EXPECT_EQ(OK, req1->Resolve());
@@ -1363,4 +1350,24 @@ TEST_F(HostResolverImplTest, ServeFromHosts) {
EXPECT_TRUE(req6->HasOneAddress("127.0.0.1", 80));
}
+TEST_F(HostResolverImplDnsTest, BypassDnsTask) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies("", "0.0.0.0"); // Default to failures.
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok.local", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok.local.", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("oklocal", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("oklocal.", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+
+ proc_->SignalMultiple(requests_.size());
+
+ for (size_t i = 0; i < 2; ++i)
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[i]->WaitForResult()) << i;
+
+ for (size_t i = 2; i < requests_.size(); ++i)
+ EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
+}
+
} // namespace net
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 44da326..90f2337 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -657,3 +657,6 @@ NET_ERROR(DNS_TIMED_OUT, -803)
// The entry was not found in cache, for cache-only lookups.
NET_ERROR(DNS_CACHE_MISS, -804)
+
+// Suffix search list rules prevent resolution of the given host name.
+NET_ERROR(DNS_SEARCH_EMPTY, -805)
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
index 9df0614..a496fef 100644
--- a/net/dns/dns_transaction.cc
+++ b/net/dns/dns_transaction.cc
@@ -360,7 +360,7 @@ class DnsTransactionImpl : public DnsTransaction,
if (ndots > 0 && !had_hostname)
qnames_.push_back(labeled_hostname);
- return qnames_.empty() ? ERR_NAME_NOT_RESOLVED : OK;
+ return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
}
void DoCallback(AttemptResult result) {
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 4192ca8..51c5b6a 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -647,7 +647,7 @@ TEST_F(DnsTransactionTest, EmptySuffixSearch) {
// A single label name is not even attempted.
TransactionHelper helper1("singlelabel",
dns_protocol::kTypeA,
- ERR_NAME_NOT_RESOLVED);
+ ERR_DNS_SEARCH_EMPTY);
helper1.StartTransaction(transaction_factory_.get());
EXPECT_TRUE(helper1.has_completed());