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::IPEndPoint
;
23 using net::ParseIPLiteralToNumber
;
24 using net::NetworkChangeNotifier
;
26 namespace chrome_browser_net
{
30 // How long the DnsProbeService will cache the probe result for.
31 // If it's older than this and we get a probe request, the service expires it
32 // and starts a new probe.
33 const int kMaxResultAgeMs
= 5000;
35 // The public DNS servers used by the DnsProbeService to verify internet
37 const char kGooglePublicDns1
[] = "8.8.8.8";
38 const char kGooglePublicDns2
[] = "8.8.4.4";
40 IPEndPoint
MakeDnsEndPoint(const std::string
& dns_ip_literal
) {
41 IPAddressNumber dns_ip_number
;
42 bool rv
= ParseIPLiteralToNumber(dns_ip_literal
, &dns_ip_number
);
44 return IPEndPoint(dns_ip_number
, net::dns_protocol::kDefaultPort
);
47 DnsProbeStatus
EvaluateResults(DnsProbeRunner::Result system_result
,
48 DnsProbeRunner::Result public_result
) {
49 // If the system DNS is working, assume the domain doesn't exist.
50 if (system_result
== DnsProbeRunner::CORRECT
)
51 return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN
;
53 // If the system DNS is unknown (e.g. on Android), but the public server is
54 // reachable, assume the domain doesn't exist.
55 if (system_result
== DnsProbeRunner::UNKNOWN
&&
56 public_result
== DnsProbeRunner::CORRECT
) {
57 return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN
;
60 // If the system DNS is not working but another public server is, assume the
61 // DNS config is bad (or perhaps the DNS servers are down or broken).
62 if (public_result
== DnsProbeRunner::CORRECT
)
63 return chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG
;
65 // If the system DNS is not working and another public server is unreachable,
66 // assume the internet connection is down (note that system DNS may be a
67 // router on the LAN, so it may be reachable but returning errors.)
68 if (public_result
== DnsProbeRunner::UNREACHABLE
)
69 return chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET
;
71 // Otherwise: the system DNS is not working and another public server is
72 // responding but with errors or incorrect results. This is an awkward case;
73 // an invasive captive portal or a restrictive firewall may be intercepting
74 // or rewriting DNS traffic, or the public server may itself be failing or
76 return chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE
;
79 void HistogramProbe(DnsProbeStatus status
, base::TimeDelta elapsed
) {
80 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(status
));
82 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ProbeResult", status
,
83 chrome_common_net::DNS_PROBE_MAX
);
84 UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.ProbeDuration", elapsed
);
89 DnsProbeService::DnsProbeService()
90 : state_(STATE_NO_RESULT
) {
91 NetworkChangeNotifier::AddDNSObserver(this);
92 SetSystemClientToCurrentConfig();
93 SetPublicClientToGooglePublicDns();
96 DnsProbeService::~DnsProbeService() {
97 NetworkChangeNotifier::RemoveDNSObserver(this);
100 void DnsProbeService::ProbeDns(const DnsProbeService::ProbeCallback
& callback
) {
101 pending_callbacks_
.push_back(callback
);
103 if (CachedResultIsExpired())
107 case STATE_NO_RESULT
:
110 case STATE_RESULT_CACHED
:
113 case STATE_PROBE_RUNNING
:
114 // Do nothing; probe is already running, and will call the callback.
119 void DnsProbeService::OnDNSChanged() {
121 SetSystemClientToCurrentConfig();
124 void DnsProbeService::SetSystemClientForTesting(
125 scoped_ptr
<DnsClient
> system_client
) {
126 system_runner_
.SetClient(system_client
.Pass());
129 void DnsProbeService::SetPublicClientForTesting(
130 scoped_ptr
<DnsClient
> public_client
) {
131 public_runner_
.SetClient(public_client
.Pass());
134 void DnsProbeService::ClearCachedResultForTesting() {
138 void DnsProbeService::SetSystemClientToCurrentConfig() {
139 DnsConfig system_config
;
140 NetworkChangeNotifier::GetDnsConfig(&system_config
);
141 system_config
.search
.clear();
142 system_config
.attempts
= 1;
143 system_config
.randomize_ports
= false;
145 scoped_ptr
<DnsClient
> system_client(DnsClient::CreateClient(NULL
));
146 system_client
->SetConfig(system_config
);
148 system_runner_
.SetClient(system_client
.Pass());
151 void DnsProbeService::SetPublicClientToGooglePublicDns() {
152 DnsConfig public_config
;
153 public_config
.nameservers
.push_back(MakeDnsEndPoint(kGooglePublicDns1
));
154 public_config
.nameservers
.push_back(MakeDnsEndPoint(kGooglePublicDns2
));
155 public_config
.attempts
= 1;
156 public_config
.randomize_ports
= false;
158 scoped_ptr
<DnsClient
> public_client(DnsClient::CreateClient(NULL
));
159 public_client
->SetConfig(public_config
);
161 public_runner_
.SetClient(public_client
.Pass());
164 void DnsProbeService::StartProbes() {
165 DCHECK_EQ(STATE_NO_RESULT
, state_
);
167 DCHECK(!system_runner_
.IsRunning());
168 DCHECK(!public_runner_
.IsRunning());
170 const base::Closure callback
= base::Bind(&DnsProbeService::OnProbeComplete
,
171 base::Unretained(this));
172 system_runner_
.RunProbe(callback
);
173 public_runner_
.RunProbe(callback
);
174 probe_start_time_
= base::Time::Now();
175 state_
= STATE_PROBE_RUNNING
;
177 DCHECK(system_runner_
.IsRunning());
178 DCHECK(public_runner_
.IsRunning());
181 void DnsProbeService::OnProbeComplete() {
182 DCHECK_EQ(STATE_PROBE_RUNNING
, state_
);
184 if (system_runner_
.IsRunning() || public_runner_
.IsRunning())
187 cached_result_
= EvaluateResults(system_runner_
.result(),
188 public_runner_
.result());
189 state_
= STATE_RESULT_CACHED
;
191 HistogramProbe(cached_result_
, base::Time::Now() - probe_start_time_
);
196 void DnsProbeService::CallCallbacks() {
197 DCHECK_EQ(STATE_RESULT_CACHED
, state_
);
198 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(cached_result_
));
199 DCHECK(!pending_callbacks_
.empty());
201 std::vector
<ProbeCallback
> callbacks
;
202 callbacks
.swap(pending_callbacks_
);
204 for (std::vector
<ProbeCallback
>::const_iterator i
= callbacks
.begin();
205 i
!= callbacks
.end(); ++i
) {
206 i
->Run(cached_result_
);
210 void DnsProbeService::ClearCachedResult() {
211 if (state_
== STATE_RESULT_CACHED
) {
212 state_
= STATE_NO_RESULT
;
213 cached_result_
= chrome_common_net::DNS_PROBE_MAX
;
217 bool DnsProbeService::CachedResultIsExpired() const {
218 if (state_
!= STATE_RESULT_CACHED
)
221 const base::TimeDelta kMaxResultAge
=
222 base::TimeDelta::FromMilliseconds(kMaxResultAgeMs
);
223 return base::Time::Now() - probe_start_time_
> kMaxResultAge
;
226 } // namespace chrome_browser_net