1 // Copyright 2013 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_runner.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/optional.h"
11 #include "mojo/public/cpp/bindings/message.h"
12 #include "net/base/address_list.h"
13 #include "net/base/host_port_pair.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/network_isolation_key.h"
16 #include "net/dns/public/resolve_error_info.h"
17 #include "services/network/public/mojom/network_context.mojom.h"
18 
19 namespace chrome_browser_net {
20 
21 const char DnsProbeRunner::kKnownGoodHostname[] = "google.com";
22 
23 namespace {
24 
EvaluateResponse(int net_error,const base::Optional<net::AddressList> & resolved_addresses)25 DnsProbeRunner::Result EvaluateResponse(
26     int net_error,
27     const base::Optional<net::AddressList>& resolved_addresses) {
28   switch (net_error) {
29     case net::OK:
30       break;
31 
32     case net::ERR_FAILED:
33     // ERR_DNS_CACHE_MISS means HostResolver was not able to attempt DNS, e.g.
34     // due to limitations from Chrome build configuration or because of
35     // incompatibilities with the DNS configuration from the system. The result
36     // Chrome would have gotten from DNS if attempted is therefore unknown.
37     case net::ERR_DNS_CACHE_MISS:
38       return DnsProbeRunner::UNKNOWN;
39 
40     // ERR_NAME_NOT_RESOLVED maps to NXDOMAIN, which means the server is working
41     // but returned a wrong answer.
42     case net::ERR_NAME_NOT_RESOLVED:
43       return DnsProbeRunner::INCORRECT;
44 
45     // These results mean we heard *something* from the DNS server, but it was
46     // unsuccessful (SERVFAIL) or malformed.
47     case net::ERR_DNS_MALFORMED_RESPONSE:
48     case net::ERR_DNS_SERVER_REQUIRES_TCP:  // Shouldn't happen; DnsTransaction
49                                             // will retry with TCP.
50     case net::ERR_DNS_SERVER_FAILED:
51     case net::ERR_DNS_SORT_ERROR:  // Can only happen if the server responds.
52       return DnsProbeRunner::FAILING;
53 
54     // Any other error means we never reached the DNS server in the first place.
55     case net::ERR_DNS_TIMED_OUT:
56     default:
57       // Something else happened, probably at a network level.
58       return DnsProbeRunner::UNREACHABLE;
59   }
60 
61   if (!resolved_addresses) {
62     // If net_error is OK, resolved_addresses should be set. The binding is not
63     // closed here since it will be closed by the caller anyway.
64     mojo::ReportBadMessage("resolved_addresses not set when net_error=OK");
65     return DnsProbeRunner::UNKNOWN;
66   } else if (resolved_addresses.value().empty()) {
67     return DnsProbeRunner::INCORRECT;
68   } else {
69     return DnsProbeRunner::CORRECT;
70   }
71 }
72 
73 }  // namespace
74 
DnsProbeRunner(net::DnsConfigOverrides dns_config_overrides,const NetworkContextGetter & network_context_getter)75 DnsProbeRunner::DnsProbeRunner(
76     net::DnsConfigOverrides dns_config_overrides,
77     const NetworkContextGetter& network_context_getter)
78     : dns_config_overrides_(dns_config_overrides),
79       network_context_getter_(network_context_getter) {
80   CreateHostResolver();
81 }
82 
~DnsProbeRunner()83 DnsProbeRunner::~DnsProbeRunner() {
84   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
85 }
86 
RunProbe(base::OnceClosure callback)87 void DnsProbeRunner::RunProbe(base::OnceClosure callback) {
88   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
89   DCHECK(!callback.is_null());
90   DCHECK(host_resolver_);
91   DCHECK(callback_.is_null());
92   DCHECK(!receiver_.is_bound());
93 
94   network::mojom::ResolveHostParametersPtr parameters =
95       network::mojom::ResolveHostParameters::New();
96   parameters->dns_query_type = net::DnsQueryType::A;
97   parameters->source = net::HostResolverSource::DNS;
98   parameters->cache_usage =
99       network::mojom::ResolveHostParameters::CacheUsage::DISALLOWED;
100 
101   // Use transient NIKs - don't want cached responses anyways, so no benefit
102   // from sharing a cache, beyond multiple probes not evicting anything.
103   host_resolver_->ResolveHost(net::HostPortPair(kKnownGoodHostname, 80),
104                               net::NetworkIsolationKey::CreateTransient(),
105                               std::move(parameters),
106                               receiver_.BindNewPipeAndPassRemote());
107   receiver_.set_disconnect_handler(base::BindOnce(
108       &DnsProbeRunner::OnMojoConnectionError, base::Unretained(this)));
109 
110   callback_ = std::move(callback);
111 }
112 
IsRunning() const113 bool DnsProbeRunner::IsRunning() const {
114   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
115   return !callback_.is_null();
116 }
117 
OnComplete(int32_t result,const net::ResolveErrorInfo & resolve_error_info,const base::Optional<net::AddressList> & resolved_addresses)118 void DnsProbeRunner::OnComplete(
119     int32_t result,
120     const net::ResolveErrorInfo& resolve_error_info,
121     const base::Optional<net::AddressList>& resolved_addresses) {
122   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
123   DCHECK(!callback_.is_null());
124 
125   result_ = EvaluateResponse(resolve_error_info.error, resolved_addresses);
126   receiver_.reset();
127 
128   // ResolveHost will call OnComplete asynchronously, so callback_ can be
129   // invoked directly here.  Clear callback in case it starts a new probe
130   // immediately.
131   std::move(callback_).Run();
132 }
133 
CreateHostResolver()134 void DnsProbeRunner::CreateHostResolver() {
135   host_resolver_.reset();
136   network_context_getter_.Run()->CreateHostResolver(
137       dns_config_overrides_, host_resolver_.BindNewPipeAndPassReceiver());
138 }
139 
OnMojoConnectionError()140 void DnsProbeRunner::OnMojoConnectionError() {
141   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
142   CreateHostResolver();
143   OnComplete(net::ERR_NAME_NOT_RESOLVED, net::ResolveErrorInfo(net::ERR_FAILED),
144              base::nullopt);
145 }
146 
147 }  // namespace chrome_browser_net
148