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