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