1 // Copyright 2018 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 "services/network/host_resolver.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/optional.h"
12 #include "mojo/public/cpp/bindings/pending_receiver.h"
13 #include "net/base/host_port_pair.h"
14 #include "net/base/net_errors.h"
15 #include "net/dns/host_resolver.h"
16 #include "net/dns/host_resolver_source.h"
17 #include "net/log/net_log.h"
18 #include "services/network/host_resolver_mdns_listener.h"
19 #include "services/network/public/cpp/host_resolver_mojom_traits.h"
20 #include "services/network/resolve_host_request.h"
21
22 namespace network {
23 namespace {
24 static base::LazyInstance<HostResolver::ResolveHostCallback>::Leaky
25 resolve_host_callback;
26 }
27
28 namespace {
29 base::Optional<net::HostResolver::ResolveHostParameters>
ConvertOptionalParameters(const mojom::ResolveHostParametersPtr & mojo_parameters)30 ConvertOptionalParameters(
31 const mojom::ResolveHostParametersPtr& mojo_parameters) {
32 if (!mojo_parameters)
33 return base::nullopt;
34
35 net::HostResolver::ResolveHostParameters parameters;
36 parameters.dns_query_type = mojo_parameters->dns_query_type;
37 parameters.initial_priority = mojo_parameters->initial_priority;
38 parameters.source = mojo_parameters->source;
39 switch (mojo_parameters->cache_usage) {
40 case mojom::ResolveHostParameters::CacheUsage::ALLOWED:
41 parameters.cache_usage =
42 net::HostResolver::ResolveHostParameters::CacheUsage::ALLOWED;
43 break;
44 case mojom::ResolveHostParameters::CacheUsage::STALE_ALLOWED:
45 parameters.cache_usage =
46 net::HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
47 break;
48 case mojom::ResolveHostParameters::CacheUsage::DISALLOWED:
49 parameters.cache_usage =
50 net::HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
51 break;
52 }
53 parameters.include_canonical_name = mojo_parameters->include_canonical_name;
54 parameters.loopback_only = mojo_parameters->loopback_only;
55 parameters.is_speculative = mojo_parameters->is_speculative;
56 parameters.secure_dns_mode_override = mojo::FromOptionalSecureDnsMode(
57 mojo_parameters->secure_dns_mode_override);
58 return parameters;
59 }
60 } // namespace
61
HostResolver(mojo::PendingReceiver<mojom::HostResolver> resolver_receiver,ConnectionShutdownCallback connection_shutdown_callback,net::HostResolver * internal_resolver,net::NetLog * net_log)62 HostResolver::HostResolver(
63 mojo::PendingReceiver<mojom::HostResolver> resolver_receiver,
64 ConnectionShutdownCallback connection_shutdown_callback,
65 net::HostResolver* internal_resolver,
66 net::NetLog* net_log)
67 : receiver_(this),
68 pending_receiver_(std::move(resolver_receiver)),
69 connection_shutdown_callback_(std::move(connection_shutdown_callback)),
70 internal_resolver_(internal_resolver),
71 net_log_(net_log) {
72 // Bind the pending receiver asynchronously to give the resolver a chance
73 // to set up (some resolvers need to obtain the system config asynchronously).
74 base::SequencedTaskRunnerHandle::Get()->PostTask(
75 FROM_HERE,
76 base::BindOnce(&HostResolver::AsyncSetUp, weak_factory_.GetWeakPtr()));
77 }
78
HostResolver(net::HostResolver * internal_resolver,net::NetLog * net_log)79 HostResolver::HostResolver(net::HostResolver* internal_resolver,
80 net::NetLog* net_log)
81 : receiver_(this),
82 internal_resolver_(internal_resolver),
83 net_log_(net_log) {}
84
~HostResolver()85 HostResolver::~HostResolver() {
86 receiver_.reset();
87 }
88
ResolveHost(const net::HostPortPair & host,const net::NetworkIsolationKey & network_isolation_key,mojom::ResolveHostParametersPtr optional_parameters,mojo::PendingRemote<mojom::ResolveHostClient> response_client)89 void HostResolver::ResolveHost(
90 const net::HostPortPair& host,
91 const net::NetworkIsolationKey& network_isolation_key,
92 mojom::ResolveHostParametersPtr optional_parameters,
93 mojo::PendingRemote<mojom::ResolveHostClient> response_client) {
94 #if !BUILDFLAG(ENABLE_MDNS)
95 // TODO(crbug.com/821021): Handle without crashing if we create restricted
96 // HostResolvers for passing to untrusted processes.
97 DCHECK(!optional_parameters ||
98 optional_parameters->source != net::HostResolverSource::MULTICAST_DNS);
99 #endif // !BUILDFLAG(ENABLE_MDNS)
100
101 if (resolve_host_callback.Get())
102 resolve_host_callback.Get().Run(host.host());
103
104 auto request = std::make_unique<ResolveHostRequest>(
105 internal_resolver_, host, network_isolation_key,
106 ConvertOptionalParameters(optional_parameters), net_log_);
107
108 mojo::PendingReceiver<mojom::ResolveHostHandle> control_handle_receiver;
109 if (optional_parameters)
110 control_handle_receiver = std::move(optional_parameters->control_handle);
111
112 int rv = request->Start(
113 std::move(control_handle_receiver), std::move(response_client),
114 base::BindOnce(&HostResolver::OnResolveHostComplete,
115 base::Unretained(this), request.get()));
116 if (rv != net::ERR_IO_PENDING)
117 return;
118
119 // Store the request with the resolver so it can be cancelled on resolver
120 // shutdown.
121 bool insertion_result = requests_.emplace(std::move(request)).second;
122 DCHECK(insertion_result);
123 }
124
MdnsListen(const net::HostPortPair & host,net::DnsQueryType query_type,mojo::PendingRemote<mojom::MdnsListenClient> response_client,MdnsListenCallback callback)125 void HostResolver::MdnsListen(
126 const net::HostPortPair& host,
127 net::DnsQueryType query_type,
128 mojo::PendingRemote<mojom::MdnsListenClient> response_client,
129 MdnsListenCallback callback) {
130 #if !BUILDFLAG(ENABLE_MDNS)
131 NOTREACHED();
132 #endif // !BUILDFLAG(ENABLE_MDNS)
133
134 auto listener = std::make_unique<HostResolverMdnsListener>(internal_resolver_,
135 host, query_type);
136 int rv =
137 listener->Start(std::move(response_client),
138 base::BindOnce(&HostResolver::OnMdnsListenerCancelled,
139 base::Unretained(this), listener.get()));
140 if (rv == net::OK) {
141 bool insertion_result = listeners_.emplace(std::move(listener)).second;
142 DCHECK(insertion_result);
143 }
144
145 std::move(callback).Run(rv);
146 }
147
GetNumOutstandingRequestsForTesting() const148 size_t HostResolver::GetNumOutstandingRequestsForTesting() const {
149 return requests_.size();
150 }
151
SetResolveHostCallbackForTesting(ResolveHostCallback callback)152 void HostResolver::SetResolveHostCallbackForTesting(
153 ResolveHostCallback callback) {
154 resolve_host_callback.Get() = std::move(callback);
155 }
156
AsyncSetUp()157 void HostResolver::AsyncSetUp() {
158 receiver_.Bind(std::move(pending_receiver_));
159 receiver_.set_disconnect_handler(
160 base::BindOnce(&HostResolver::OnConnectionError, base::Unretained(this)));
161 }
162
OnResolveHostComplete(ResolveHostRequest * request,int error)163 void HostResolver::OnResolveHostComplete(ResolveHostRequest* request,
164 int error) {
165 DCHECK_NE(net::ERR_IO_PENDING, error);
166
167 auto found_request = requests_.find(request);
168 DCHECK(found_request != requests_.end());
169 requests_.erase(found_request);
170 }
171
OnMdnsListenerCancelled(HostResolverMdnsListener * listener)172 void HostResolver::OnMdnsListenerCancelled(HostResolverMdnsListener* listener) {
173 auto found_listener = listeners_.find(listener);
174 DCHECK(found_listener != listeners_.end());
175 listeners_.erase(found_listener);
176 }
177
OnConnectionError()178 void HostResolver::OnConnectionError() {
179 DCHECK(connection_shutdown_callback_);
180
181 requests_.clear();
182
183 // Invoke last as callback may delete |this|.
184 std::move(connection_shutdown_callback_).Run(this);
185 }
186
187 } // namespace network
188