• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/net/dns_probe_service.h"
6 
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"
15 
16 using base::FieldTrialList;
17 using base::StringToInt;
18 using chrome_common_net::DnsProbeStatus;
19 using net::DnsClient;
20 using net::DnsConfig;
21 using net::IPAddressNumber;
22 using net::IPEndPoint;
23 using net::ParseIPLiteralToNumber;
24 using net::NetworkChangeNotifier;
25 
26 namespace chrome_browser_net {
27 
28 namespace {
29 
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;
34 
35 // The public DNS servers used by the DnsProbeService to verify internet
36 // connectivity.
37 const char kGooglePublicDns1[] = "8.8.8.8";
38 const char kGooglePublicDns2[] = "8.8.4.4";
39 
MakeDnsEndPoint(const std::string & dns_ip_literal)40 IPEndPoint MakeDnsEndPoint(const std::string& dns_ip_literal) {
41   IPAddressNumber dns_ip_number;
42   bool rv = ParseIPLiteralToNumber(dns_ip_literal, &dns_ip_number);
43   DCHECK(rv);
44   return IPEndPoint(dns_ip_number, net::dns_protocol::kDefaultPort);
45 }
46 
EvaluateResults(DnsProbeRunner::Result system_result,DnsProbeRunner::Result public_result)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;
52 
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;
58   }
59 
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;
64 
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;
70 
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
75   // down.
76   return chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE;
77 }
78 
HistogramProbe(DnsProbeStatus status,base::TimeDelta elapsed)79 void HistogramProbe(DnsProbeStatus status, base::TimeDelta elapsed) {
80   DCHECK(chrome_common_net::DnsProbeStatusIsFinished(status));
81 
82   UMA_HISTOGRAM_ENUMERATION("DnsProbe.ProbeResult", status,
83                             chrome_common_net::DNS_PROBE_MAX);
84   UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.ProbeDuration", elapsed);
85 }
86 
87 }  // namespace
88 
DnsProbeService()89 DnsProbeService::DnsProbeService()
90     : state_(STATE_NO_RESULT) {
91   NetworkChangeNotifier::AddDNSObserver(this);
92   SetSystemClientToCurrentConfig();
93   SetPublicClientToGooglePublicDns();
94 }
95 
~DnsProbeService()96 DnsProbeService::~DnsProbeService() {
97   NetworkChangeNotifier::RemoveDNSObserver(this);
98 }
99 
ProbeDns(const DnsProbeService::ProbeCallback & callback)100 void DnsProbeService::ProbeDns(const DnsProbeService::ProbeCallback& callback) {
101   pending_callbacks_.push_back(callback);
102 
103   if (CachedResultIsExpired())
104     ClearCachedResult();
105 
106   switch (state_) {
107     case STATE_NO_RESULT:
108       StartProbes();
109       break;
110     case STATE_RESULT_CACHED:
111       CallCallbacks();
112       break;
113     case STATE_PROBE_RUNNING:
114       // Do nothing; probe is already running, and will call the callback.
115       break;
116   }
117 }
118 
OnDNSChanged()119 void DnsProbeService::OnDNSChanged() {
120   ClearCachedResult();
121   SetSystemClientToCurrentConfig();
122 }
123 
SetSystemClientForTesting(scoped_ptr<DnsClient> system_client)124 void DnsProbeService::SetSystemClientForTesting(
125     scoped_ptr<DnsClient> system_client) {
126   system_runner_.SetClient(system_client.Pass());
127 }
128 
SetPublicClientForTesting(scoped_ptr<DnsClient> public_client)129 void DnsProbeService::SetPublicClientForTesting(
130     scoped_ptr<DnsClient> public_client) {
131   public_runner_.SetClient(public_client.Pass());
132 }
133 
ClearCachedResultForTesting()134 void DnsProbeService::ClearCachedResultForTesting() {
135   ClearCachedResult();
136 }
137 
SetSystemClientToCurrentConfig()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;
144 
145   scoped_ptr<DnsClient> system_client(DnsClient::CreateClient(NULL));
146   system_client->SetConfig(system_config);
147 
148   system_runner_.SetClient(system_client.Pass());
149 }
150 
SetPublicClientToGooglePublicDns()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;
157 
158   scoped_ptr<DnsClient> public_client(DnsClient::CreateClient(NULL));
159   public_client->SetConfig(public_config);
160 
161   public_runner_.SetClient(public_client.Pass());
162 }
163 
StartProbes()164 void DnsProbeService::StartProbes() {
165   DCHECK_EQ(STATE_NO_RESULT, state_);
166 
167   DCHECK(!system_runner_.IsRunning());
168   DCHECK(!public_runner_.IsRunning());
169 
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;
176 
177   DCHECK(system_runner_.IsRunning());
178   DCHECK(public_runner_.IsRunning());
179 }
180 
OnProbeComplete()181 void DnsProbeService::OnProbeComplete() {
182   DCHECK_EQ(STATE_PROBE_RUNNING, state_);
183 
184   if (system_runner_.IsRunning() || public_runner_.IsRunning())
185     return;
186 
187   cached_result_ = EvaluateResults(system_runner_.result(),
188                                    public_runner_.result());
189   state_ = STATE_RESULT_CACHED;
190 
191   HistogramProbe(cached_result_, base::Time::Now() - probe_start_time_);
192 
193   CallCallbacks();
194 }
195 
CallCallbacks()196 void DnsProbeService::CallCallbacks() {
197   DCHECK_EQ(STATE_RESULT_CACHED, state_);
198   DCHECK(chrome_common_net::DnsProbeStatusIsFinished(cached_result_));
199   DCHECK(!pending_callbacks_.empty());
200 
201   std::vector<ProbeCallback> callbacks;
202   callbacks.swap(pending_callbacks_);
203 
204   for (std::vector<ProbeCallback>::const_iterator i = callbacks.begin();
205        i != callbacks.end(); ++i) {
206     i->Run(cached_result_);
207   }
208 }
209 
ClearCachedResult()210 void DnsProbeService::ClearCachedResult() {
211   if (state_ == STATE_RESULT_CACHED) {
212     state_ = STATE_NO_RESULT;
213     cached_result_ = chrome_common_net::DNS_PROBE_MAX;
214   }
215 }
216 
CachedResultIsExpired() const217 bool DnsProbeService::CachedResultIsExpired() const {
218   if (state_ != STATE_RESULT_CACHED)
219     return false;
220 
221   const base::TimeDelta kMaxResultAge =
222       base::TimeDelta::FromMilliseconds(kMaxResultAgeMs);
223   return base::Time::Now() - probe_start_time_ > kMaxResultAge;
224 }
225 
226 }  // namespace chrome_browser_net
227