| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/network/host_resolver.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "base/optional.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/net_errors.h" |
| #include "net/dns/host_resolver.h" |
| #include "net/dns/host_resolver_source.h" |
| #include "net/log/net_log.h" |
| #include "services/network/host_resolver_mdns_listener.h" |
| #include "services/network/public/cpp/host_resolver_mojom_traits.h" |
| #include "services/network/resolve_host_request.h" |
| |
| namespace network { |
| namespace { |
| static base::LazyInstance<HostResolver::ResolveHostCallback>::Leaky |
| resolve_host_callback; |
| } |
| |
| namespace { |
| base::Optional<net::HostResolver::ResolveHostParameters> |
| ConvertOptionalParameters( |
| const mojom::ResolveHostParametersPtr& mojo_parameters) { |
| if (!mojo_parameters) |
| return base::nullopt; |
| |
| net::HostResolver::ResolveHostParameters parameters; |
| parameters.dns_query_type = mojo_parameters->dns_query_type; |
| parameters.initial_priority = mojo_parameters->initial_priority; |
| parameters.source = mojo_parameters->source; |
| parameters.cache_usage = |
| mojo_parameters->allow_cached_response |
| ? net::HostResolver::ResolveHostParameters::CacheUsage::ALLOWED |
| : net::HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED; |
| parameters.include_canonical_name = mojo_parameters->include_canonical_name; |
| parameters.loopback_only = mojo_parameters->loopback_only; |
| parameters.is_speculative = mojo_parameters->is_speculative; |
| parameters.secure_dns_mode_override = mojo::FromOptionalSecureDnsMode( |
| mojo_parameters->secure_dns_mode_override); |
| return parameters; |
| } |
| } // namespace |
| |
| HostResolver::HostResolver( |
| mojo::PendingReceiver<mojom::HostResolver> resolver_receiver, |
| ConnectionShutdownCallback connection_shutdown_callback, |
| net::HostResolver* internal_resolver, |
| net::NetLog* net_log) |
| : receiver_(this, std::move(resolver_receiver)), |
| connection_shutdown_callback_(std::move(connection_shutdown_callback)), |
| internal_resolver_(internal_resolver), |
| net_log_(net_log) { |
| receiver_.set_disconnect_handler( |
| base::BindOnce(&HostResolver::OnConnectionError, base::Unretained(this))); |
| } |
| |
| HostResolver::HostResolver(net::HostResolver* internal_resolver, |
| net::NetLog* net_log) |
| : receiver_(this), |
| internal_resolver_(internal_resolver), |
| net_log_(net_log) {} |
| |
| HostResolver::~HostResolver() { |
| receiver_.reset(); |
| } |
| |
| void HostResolver::ResolveHost( |
| const net::HostPortPair& host, |
| const net::NetworkIsolationKey& network_isolation_key, |
| mojom::ResolveHostParametersPtr optional_parameters, |
| mojo::PendingRemote<mojom::ResolveHostClient> response_client) { |
| #if !BUILDFLAG(ENABLE_MDNS) |
| // TODO(crbug.com/821021): Handle without crashing if we create restricted |
| // HostResolvers for passing to untrusted processes. |
| DCHECK(!optional_parameters || |
| optional_parameters->source != net::HostResolverSource::MULTICAST_DNS); |
| #endif // !BUILDFLAG(ENABLE_MDNS) |
| |
| if (resolve_host_callback.Get()) |
| resolve_host_callback.Get().Run(host.host()); |
| |
| auto request = std::make_unique<ResolveHostRequest>( |
| internal_resolver_, host, network_isolation_key, |
| ConvertOptionalParameters(optional_parameters), net_log_); |
| |
| mojo::PendingReceiver<mojom::ResolveHostHandle> control_handle_receiver; |
| if (optional_parameters) |
| control_handle_receiver = std::move(optional_parameters->control_handle); |
| |
| int rv = request->Start( |
| std::move(control_handle_receiver), std::move(response_client), |
| base::BindOnce(&HostResolver::OnResolveHostComplete, |
| base::Unretained(this), request.get())); |
| if (rv != net::ERR_IO_PENDING) |
| return; |
| |
| // Store the request with the resolver so it can be cancelled on resolver |
| // shutdown. |
| bool insertion_result = requests_.emplace(std::move(request)).second; |
| DCHECK(insertion_result); |
| } |
| |
| void HostResolver::MdnsListen( |
| const net::HostPortPair& host, |
| net::DnsQueryType query_type, |
| mojo::PendingRemote<mojom::MdnsListenClient> response_client, |
| MdnsListenCallback callback) { |
| #if !BUILDFLAG(ENABLE_MDNS) |
| NOTREACHED(); |
| #endif // !BUILDFLAG(ENABLE_MDNS) |
| |
| auto listener = std::make_unique<HostResolverMdnsListener>(internal_resolver_, |
| host, query_type); |
| int rv = |
| listener->Start(std::move(response_client), |
| base::BindOnce(&HostResolver::OnMdnsListenerCancelled, |
| base::Unretained(this), listener.get())); |
| if (rv == net::OK) { |
| bool insertion_result = listeners_.emplace(std::move(listener)).second; |
| DCHECK(insertion_result); |
| } |
| |
| std::move(callback).Run(rv); |
| } |
| |
| size_t HostResolver::GetNumOutstandingRequestsForTesting() const { |
| return requests_.size(); |
| } |
| |
| void HostResolver::SetResolveHostCallbackForTesting( |
| ResolveHostCallback callback) { |
| resolve_host_callback.Get() = std::move(callback); |
| } |
| |
| void HostResolver::OnResolveHostComplete(ResolveHostRequest* request, |
| int error) { |
| DCHECK_NE(net::ERR_IO_PENDING, error); |
| |
| auto found_request = requests_.find(request); |
| DCHECK(found_request != requests_.end()); |
| requests_.erase(found_request); |
| } |
| |
| void HostResolver::OnMdnsListenerCancelled(HostResolverMdnsListener* listener) { |
| auto found_listener = listeners_.find(listener); |
| DCHECK(found_listener != listeners_.end()); |
| listeners_.erase(found_listener); |
| } |
| |
| void HostResolver::OnConnectionError() { |
| DCHECK(connection_shutdown_callback_); |
| |
| requests_.clear(); |
| |
| // Invoke last as callback may delete |this|. |
| std::move(connection_shutdown_callback_).Run(this); |
| } |
| |
| } // namespace network |