// Copyright (c) 2012 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 "net/dns/host_resolver.h" #include #include #include #include #include "base/bind.h" #include "base/check.h" #include "base/no_destructor.h" #include "base/notreached.h" #include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" #include "base/time/time_delta_from_string.h" #include "base/values.h" #include "net/base/address_list.h" #include "net/base/features.h" #include "net/base/net_errors.h" #include "net/base/network_change_notifier.h" #include "net/dns/context_host_resolver.h" #include "net/dns/dns_client.h" #include "net/dns/dns_util.h" #include "net/dns/host_cache.h" #include "net/dns/host_resolver_manager.h" #include "net/dns/host_resolver_results.h" #include "net/dns/mapped_host_resolver.h" #include "net/dns/resolve_context.h" #include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(IS_ANDROID) #include "base/android/build_info.h" #include "net/android/network_library.h" #endif // BUILDFLAG(IS_ANDROID) namespace net { namespace { // The experiment settings of features::kUseDnsHttpsSvcb. See the comments in // net/base/features.h for more details. const char kUseDnsHttpsSvcbEnable[] = "enable"; const char kUseDnsHttpsSvcbEnableInsecure[] = "enable_insecure"; const char kUseDnsHttpsSvcbInsecureExtraTimeMax[] = "insecure_extra_time_max"; const char kUseDnsHttpsSvcbInsecureExtraTimePercent[] = "insecure_extra_time_percent"; const char kUseDnsHttpsSvcbInsecureExtraTimeMin[] = "insecure_extra_time_min"; const char kUseDnsHttpsSvcbSecureExtraTimeMax[] = "secure_extra_time_max"; const char kUseDnsHttpsSvcbSecureExtraTimePercent[] = "secure_extra_time_percent"; const char kUseDnsHttpsSvcbSecureExtraTimeMin[] = "secure_extra_time_min"; const char kUseDnsHttpsSvcbExtraTimeAbsolute[] = "extra_time_absolute"; const char kUseDnsHttpsSvcbExtraTimePercent[] = "extra_time_percent"; class FailingRequestImpl : public HostResolver::ResolveHostRequest, public HostResolver::ProbeRequest { public: explicit FailingRequestImpl(int error) : error_(error) {} FailingRequestImpl(const FailingRequestImpl&) = delete; FailingRequestImpl& operator=(const FailingRequestImpl&) = delete; ~FailingRequestImpl() override = default; int Start(CompletionOnceCallback callback) override { return error_; } int Start() override { return error_; } AddressList* GetAddressResults() const override { return nullptr; } std::vector* GetEndpointResults() const override { return nullptr; } const absl::optional>& GetTextResults() const override { static const base::NoDestructor>> nullopt_result; return *nullopt_result; } const absl::optional>& GetHostnameResults() const override { static const base::NoDestructor>> nullopt_result; return *nullopt_result; } const std::set* GetDnsAliasResults() const override { return nullptr; } ResolveErrorInfo GetResolveErrorInfo() const override { return ResolveErrorInfo(error_); } const absl::optional& GetStaleInfo() const override { static const absl::optional nullopt_result; return nullopt_result; } private: const int error_; }; bool EndpointResultIsNonProtocol(const HostResolverEndpointResult& result) { return result.metadata.supported_protocol_alpns.empty(); } void GetTimeDeltaFromDictString(const base::Value::Dict& args, base::StringPiece key, base::TimeDelta* out) { const std::string* value_string = args.FindString(key); if (!value_string) return; *out = base::TimeDeltaFromString(*value_string).value_or(*out); } } // namespace HostResolver::HttpsSvcbOptions::HttpsSvcbOptions() = default; HostResolver::HttpsSvcbOptions::HttpsSvcbOptions( const HttpsSvcbOptions& other) = default; HostResolver::HttpsSvcbOptions::HttpsSvcbOptions(HttpsSvcbOptions&& other) = default; HostResolver::HttpsSvcbOptions::~HttpsSvcbOptions() = default; // static HostResolver::HttpsSvcbOptions HostResolver::HttpsSvcbOptions::FromDict( const base::Value::Dict& dict) { net::HostResolver::HttpsSvcbOptions options; options.enable = dict.FindBool(kUseDnsHttpsSvcbEnable).value_or(options.enable); options.enable_insecure = dict.FindBool(kUseDnsHttpsSvcbEnableInsecure) .value_or(options.enable_insecure); GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbInsecureExtraTimeMax, &options.insecure_extra_time_max); options.insecure_extra_time_percent = dict.FindInt(kUseDnsHttpsSvcbInsecureExtraTimePercent) .value_or(options.insecure_extra_time_percent); GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbInsecureExtraTimeMin, &options.insecure_extra_time_min); GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbSecureExtraTimeMax, &options.secure_extra_time_max); options.secure_extra_time_percent = dict.FindInt(kUseDnsHttpsSvcbSecureExtraTimePercent) .value_or(options.secure_extra_time_percent); GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbSecureExtraTimeMin, &options.secure_extra_time_min); GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbExtraTimeAbsolute, &options.extra_time_absolute); options.extra_time_percent = dict.FindInt(kUseDnsHttpsSvcbExtraTimePercent) .value_or(options.extra_time_percent); return options; } // static HostResolver::HttpsSvcbOptions HostResolver::HttpsSvcbOptions::FromFeatures() { net::HostResolver::HttpsSvcbOptions options; options.enable = base::FeatureList::IsEnabled(features::kUseDnsHttpsSvcb); options.enable_insecure = features::kUseDnsHttpsSvcbEnableInsecure.Get(); options.insecure_extra_time_max = features::kUseDnsHttpsSvcbInsecureExtraTimeMax.Get(); options.insecure_extra_time_percent = features::kUseDnsHttpsSvcbInsecureExtraTimePercent.Get(); options.insecure_extra_time_min = features::kUseDnsHttpsSvcbInsecureExtraTimeMin.Get(); options.secure_extra_time_max = features::kUseDnsHttpsSvcbSecureExtraTimeMax.Get(); options.secure_extra_time_percent = features::kUseDnsHttpsSvcbSecureExtraTimePercent.Get(); options.secure_extra_time_min = features::kUseDnsHttpsSvcbSecureExtraTimeMin.Get(); options.extra_time_absolute = features::kUseDnsHttpsSvcbExtraTimeAbsolute.Get(); options.extra_time_percent = features::kUseDnsHttpsSvcbExtraTimePercent.Get(); return options; } HostResolver::ManagerOptions::ManagerOptions() = default; HostResolver::ManagerOptions::ManagerOptions(const ManagerOptions& other) = default; HostResolver::ManagerOptions::ManagerOptions(ManagerOptions&& other) = default; HostResolver::ManagerOptions::~ManagerOptions() = default; const std::vector* HostResolver::ResolveHostRequest::GetExperimentalResultsForTesting() const { NOTREACHED(); return nullptr; } const size_t HostResolver::ManagerOptions::kDefaultRetryAttempts = static_cast(-1); std::unique_ptr HostResolver::Factory::CreateResolver( HostResolverManager* manager, base::StringPiece host_mapping_rules, bool enable_caching) { return HostResolver::CreateResolver(manager, host_mapping_rules, enable_caching); } std::unique_ptr HostResolver::Factory::CreateStandaloneResolver( NetLog* net_log, const ManagerOptions& options, base::StringPiece host_mapping_rules, bool enable_caching) { return HostResolver::CreateStandaloneResolver( net_log, options, host_mapping_rules, enable_caching); } HostResolver::ResolveHostParameters::ResolveHostParameters() = default; HostResolver::ResolveHostParameters::ResolveHostParameters( const ResolveHostParameters& other) = default; HostResolver::~HostResolver() = default; std::unique_ptr HostResolver::CreateDohProbeRequest() { // Should be overridden in any HostResolver implementation where this method // may be called. NOTREACHED(); return nullptr; } std::unique_ptr HostResolver::CreateMdnsListener( const HostPortPair& host, DnsQueryType query_type) { // Should be overridden in any HostResolver implementation where this method // may be called. NOTREACHED(); return nullptr; } HostCache* HostResolver::GetHostCache() { return nullptr; } base::Value HostResolver::GetDnsConfigAsValue() const { return base::Value(base::Value::Type::DICTIONARY); } void HostResolver::SetRequestContext(URLRequestContext* request_context) { // Should be overridden in any HostResolver implementation where this method // may be called. NOTREACHED(); } HostResolverManager* HostResolver::GetManagerForTesting() { // Should be overridden in any HostResolver implementation where this method // may be called. NOTREACHED(); return nullptr; } const URLRequestContext* HostResolver::GetContextForTesting() const { // Should be overridden in any HostResolver implementation where this method // may be called. NOTREACHED(); return nullptr; } handles::NetworkHandle HostResolver::GetTargetNetworkForTesting() const { return handles::kInvalidNetworkHandle; } // static std::unique_ptr HostResolver::CreateResolver( HostResolverManager* manager, base::StringPiece host_mapping_rules, bool enable_caching) { DCHECK(manager); auto resolve_context = std::make_unique( nullptr /* url_request_context */, enable_caching); auto resolver = std::make_unique( manager, std::move(resolve_context)); if (host_mapping_rules.empty()) return resolver; auto remapped_resolver = std::make_unique(std::move(resolver)); remapped_resolver->SetRulesFromString(host_mapping_rules); return remapped_resolver; } // static std::unique_ptr HostResolver::CreateStandaloneResolver( NetLog* net_log, absl::optional options, base::StringPiece host_mapping_rules, bool enable_caching) { std::unique_ptr resolver = CreateStandaloneContextResolver(net_log, std::move(options), enable_caching); if (host_mapping_rules.empty()) return resolver; auto remapped_resolver = std::make_unique(std::move(resolver)); remapped_resolver->SetRulesFromString(host_mapping_rules); return remapped_resolver; } // static std::unique_ptr HostResolver::CreateStandaloneContextResolver( NetLog* net_log, absl::optional options, bool enable_caching) { auto resolve_context = std::make_unique( nullptr /* url_request_context */, enable_caching); return std::make_unique( std::make_unique( std::move(options).value_or(ManagerOptions()), NetworkChangeNotifier::GetSystemDnsConfigNotifier(), net_log), std::move(resolve_context)); } // static std::unique_ptr HostResolver::CreateStandaloneNetworkBoundResolver( NetLog* net_log, handles::NetworkHandle target_network, absl::optional options, base::StringPiece host_mapping_rules, bool enable_caching) { #if BUILDFLAG(IS_ANDROID) // Note that the logic below uses Android APIs that don't work on a sandboxed // process: This is not problematic because this function is used only by // Cronet which doesn't enable sandboxing. auto resolve_context = std::make_unique( nullptr /*url_request_context */, enable_caching); auto manager_options = std::move(options).value_or(ManagerOptions()); // Support the use of the built-in resolver when possible. bool is_builtin_resolver_supported = manager_options.insecure_dns_client_enabled && base::android::BuildInfo::GetInstance()->sdk_int() >= base::android::SDK_VERSION_P; if (is_builtin_resolver_supported) { // Pre-existing DnsConfigOverrides is currently ignored, consider extending // if a use case arises. DCHECK(manager_options.dns_config_overrides == DnsConfigOverrides()); std::vector dns_servers; bool dns_over_tls_active; std::string dns_over_tls_hostname; std::vector search_suffixes; if (android::GetDnsServersForNetwork(&dns_servers, &dns_over_tls_active, &dns_over_tls_hostname, &search_suffixes, target_network)) { DnsConfigOverrides dns_config_overrides = DnsConfigOverrides::CreateOverridingEverythingWithDefaults(); dns_config_overrides.nameservers = dns_servers; // Android APIs don't specify whether to use DoT or DoH. So, leave the // decision to `DnsConfig::allow_dns_over_https_upgrade` default value. dns_config_overrides.dns_over_tls_active = dns_over_tls_active; dns_config_overrides.dns_over_tls_hostname = dns_over_tls_hostname; dns_config_overrides.search = search_suffixes; manager_options.dns_config_overrides = dns_config_overrides; // Regardless of DoH vs DoT, the important contract to respect is not to // perform insecure DNS lookups if `dns_over_tls_active` == true. manager_options.additional_types_via_insecure_dns_enabled = !dns_over_tls_active; } else { // Disable when android::GetDnsServersForNetwork fails. is_builtin_resolver_supported = false; } } manager_options.insecure_dns_client_enabled = is_builtin_resolver_supported; return std::make_unique( HostResolverManager::CreateNetworkBoundHostResolverManager( manager_options, target_network, net_log), std::move(resolve_context)); #else // !BUILDFLAG(IS_ANDROID) NOTIMPLEMENTED(); return nullptr; #endif // BUILDFLAG(IS_ANDROID) } // static AddressFamily HostResolver::DnsQueryTypeSetToAddressFamily( DnsQueryTypeSet dns_query_types) { DCHECK(HasAddressType(dns_query_types)); // If the set of query types contains A and AAAA, defer the choice of address // family. Otherwise, pick the corresponding address family. if (dns_query_types.HasAll({DnsQueryType::A, DnsQueryType::AAAA})) return ADDRESS_FAMILY_UNSPECIFIED; if (dns_query_types.Has(DnsQueryType::AAAA)) return ADDRESS_FAMILY_IPV6; DCHECK(dns_query_types.Has(DnsQueryType::A)); return ADDRESS_FAMILY_IPV4; } // static HostResolverFlags HostResolver::ParametersToHostResolverFlags( const ResolveHostParameters& parameters) { HostResolverFlags flags = 0; if (parameters.include_canonical_name) flags |= HOST_RESOLVER_CANONNAME; if (parameters.loopback_only) flags |= HOST_RESOLVER_LOOPBACK_ONLY; if (parameters.avoid_multicast_resolution) flags |= HOST_RESOLVER_AVOID_MULTICAST; return flags; } // static int HostResolver::SquashErrorCode(int error) { // TODO(crbug.com/1043281): Consider squashing ERR_INTERNET_DISCONNECTED. if (error == OK || error == ERR_IO_PENDING || error == ERR_INTERNET_DISCONNECTED || error == ERR_NAME_NOT_RESOLVED || error == ERR_DNS_NAME_HTTPS_ONLY) { return error; } else { return ERR_NAME_NOT_RESOLVED; } } // static std::vector HostResolver::AddressListToEndpointResults(const AddressList& address_list) { HostResolverEndpointResult connection_endpoint; connection_endpoint.ip_endpoints = address_list.endpoints(); std::vector list; list.push_back(std::move(connection_endpoint)); return list; } // static AddressList HostResolver::EndpointResultToAddressList( const std::vector& endpoints, const std::set& aliases) { AddressList list; auto non_protocol_endpoint = base::ranges::find_if(endpoints, &EndpointResultIsNonProtocol); if (non_protocol_endpoint == endpoints.end()) return list; list.endpoints() = non_protocol_endpoint->ip_endpoints; std::vector aliases_vector(aliases.begin(), aliases.end()); list.SetDnsAliases(std::move(aliases_vector)); return list; } HostResolver::HostResolver() = default; // static std::unique_ptr HostResolver::CreateFailingRequest(int error) { return std::make_unique(error); } // static std::unique_ptr HostResolver::CreateFailingProbeRequest(int error) { return std::make_unique(error); } } // namespace net