1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/net/dns_probe_service.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_util.h"
12 #include "net/dns/dns_client.h"
13 #include "net/dns/dns_config_service.h"
14 #include "net/dns/dns_protocol.h"
16 using base::FieldTrialList
;
17 using base::StringToInt
;
18 using chrome_common_net::DnsProbeStatus
;
21 using net::IPAddressNumber
;
22 using net::ParseIPLiteralToNumber
;
23 using net::NetworkChangeNotifier
;
25 namespace chrome_browser_net
{
29 // How long the DnsProbeService will cache the probe result for.
30 // If it's older than this and we get a probe request, the service expires it
31 // and starts a new probe.
32 const int kMaxResultAgeMs
= 5000;
34 // The public DNS servers used by the DnsProbeService to verify internet
36 const char kGooglePublicDns1
[] = "8.8.8.8";
37 const char kGooglePublicDns2
[] = "8.8.4.4";
39 net::IPEndPoint
MakeDnsEndPoint(const std::string
& dns_ip_literal
) {
40 IPAddressNumber dns_ip_number
;
41 bool rv
= ParseIPLiteralToNumber(dns_ip_literal
, &dns_ip_number
);
43 return net::IPEndPoint(dns_ip_number
, net::dns_protocol::kDefaultPort
);
46 DnsProbeStatus
EvaluateResults(DnsProbeRunner::Result system_result
,
47 DnsProbeRunner::Result public_result
) {
48 // If the system DNS is working, assume the domain doesn't exist.
49 if (system_result
== DnsProbeRunner::CORRECT
)
50 return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN
;
52 // If the system DNS is unknown (e.g. on Android), but the public server is
53 // reachable, assume the domain doesn't exist.
54 if (system_result
== DnsProbeRunner::UNKNOWN
&&
55 public_result
== DnsProbeRunner::CORRECT
) {
56 return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN
;
59 // If the system DNS is not working but another public server is, assume the
60 // DNS config is bad (or perhaps the DNS servers are down or broken).
61 if (public_result
== DnsProbeRunner::CORRECT
)
62 return chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG
;
64 // If the system DNS is not working and another public server is unreachable,
65 // assume the internet connection is down (note that system DNS may be a
66 // router on the LAN, so it may be reachable but returning errors.)
67 if (public_result
== DnsProbeRunner::UNREACHABLE
)
68 return chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET
;
70 // Otherwise: the system DNS is not working and another public server is
71 // responding but with errors or incorrect results. This is an awkward case;
72 // an invasive captive portal or a restrictive firewall may be intercepting
73 // or rewriting DNS traffic, or the public server may itself be failing or
75 return chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE
;
78 void HistogramProbe(DnsProbeStatus status
, base::TimeDelta elapsed
) {
79 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(status
));
81 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ProbeResult", status
,
82 chrome_common_net::DNS_PROBE_MAX
);
83 UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.ProbeDuration", elapsed
);
88 DnsProbeService::DnsProbeService()
89 : state_(STATE_NO_RESULT
) {
90 NetworkChangeNotifier::AddDNSObserver(this);
91 SetSystemClientToCurrentConfig();
92 SetPublicClientToGooglePublicDns();
95 DnsProbeService::~DnsProbeService() {
96 NetworkChangeNotifier::RemoveDNSObserver(this);
99 void DnsProbeService::ProbeDns(const DnsProbeService::ProbeCallback
& callback
) {
100 pending_callbacks_
.push_back(callback
);
102 if (CachedResultIsExpired())
106 case STATE_NO_RESULT
:
109 case STATE_RESULT_CACHED
:
112 case STATE_PROBE_RUNNING
:
113 // Do nothing; probe is already running, and will call the callback.
118 void DnsProbeService::OnDNSChanged() {
120 SetSystemClientToCurrentConfig();
123 void DnsProbeService::OnInitialDNSConfigRead() {
127 void DnsProbeService::SetSystemClientForTesting(
128 scoped_ptr
<DnsClient
> system_client
) {
129 system_runner_
.SetClient(system_client
.Pass());
132 void DnsProbeService::SetPublicClientForTesting(
133 scoped_ptr
<DnsClient
> public_client
) {
134 public_runner_
.SetClient(public_client
.Pass());
137 void DnsProbeService::ClearCachedResultForTesting() {
141 void DnsProbeService::SetSystemClientToCurrentConfig() {
142 DnsConfig system_config
;
143 NetworkChangeNotifier::GetDnsConfig(&system_config
);
144 system_config
.search
.clear();
145 system_config
.attempts
= 1;
146 system_config
.randomize_ports
= false;
148 scoped_ptr
<DnsClient
> system_client(DnsClient::CreateClient(NULL
));
149 system_client
->SetConfig(system_config
);
151 system_runner_
.SetClient(system_client
.Pass());
154 void DnsProbeService::SetPublicClientToGooglePublicDns() {
155 DnsConfig public_config
;
156 public_config
.nameservers
.push_back(MakeDnsEndPoint(kGooglePublicDns1
));
157 public_config
.nameservers
.push_back(MakeDnsEndPoint(kGooglePublicDns2
));
158 public_config
.attempts
= 1;
159 public_config
.randomize_ports
= false;
161 scoped_ptr
<DnsClient
> public_client(DnsClient::CreateClient(NULL
));
162 public_client
->SetConfig(public_config
);
164 public_runner_
.SetClient(public_client
.Pass());
167 void DnsProbeService::StartProbes() {
168 DCHECK_EQ(STATE_NO_RESULT
, state_
);
170 DCHECK(!system_runner_
.IsRunning());
171 DCHECK(!public_runner_
.IsRunning());
173 const base::Closure callback
= base::Bind(&DnsProbeService::OnProbeComplete
,
174 base::Unretained(this));
175 system_runner_
.RunProbe(callback
);
176 public_runner_
.RunProbe(callback
);
177 probe_start_time_
= base::Time::Now();
178 state_
= STATE_PROBE_RUNNING
;
180 DCHECK(system_runner_
.IsRunning());
181 DCHECK(public_runner_
.IsRunning());
184 void DnsProbeService::OnProbeComplete() {
185 DCHECK_EQ(STATE_PROBE_RUNNING
, state_
);
187 if (system_runner_
.IsRunning() || public_runner_
.IsRunning())
190 cached_result_
= EvaluateResults(system_runner_
.result(),
191 public_runner_
.result());
192 state_
= STATE_RESULT_CACHED
;
194 HistogramProbe(cached_result_
, base::Time::Now() - probe_start_time_
);
199 void DnsProbeService::CallCallbacks() {
200 DCHECK_EQ(STATE_RESULT_CACHED
, state_
);
201 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(cached_result_
));
202 DCHECK(!pending_callbacks_
.empty());
204 std::vector
<ProbeCallback
> callbacks
;
205 callbacks
.swap(pending_callbacks_
);
207 for (std::vector
<ProbeCallback
>::const_iterator i
= callbacks
.begin();
208 i
!= callbacks
.end(); ++i
) {
209 i
->Run(cached_result_
);
213 void DnsProbeService::ClearCachedResult() {
214 if (state_
== STATE_RESULT_CACHED
) {
215 state_
= STATE_NO_RESULT
;
216 cached_result_
= chrome_common_net::DNS_PROBE_MAX
;
220 bool DnsProbeService::CachedResultIsExpired() const {
221 if (state_
!= STATE_RESULT_CACHED
)
224 const base::TimeDelta kMaxResultAge
=
225 base::TimeDelta::FromMilliseconds(kMaxResultAgeMs
);
226 return base::Time::Now() - probe_start_time_
> kMaxResultAge
;
229 } // namespace chrome_browser_net