// Copyright 2013 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 "chrome/browser/net/dns_probe_runner.h" #include #include "base/bind.h" #include "base/optional.h" #include "mojo/public/cpp/bindings/message.h" #include "net/base/address_list.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" #include "net/base/network_isolation_key.h" #include "net/dns/public/resolve_error_info.h" #include "services/network/public/mojom/network_context.mojom.h" namespace chrome_browser_net { const char DnsProbeRunner::kKnownGoodHostname[] = "google.com"; namespace { DnsProbeRunner::Result EvaluateResponse( int net_error, const base::Optional& resolved_addresses) { switch (net_error) { case net::OK: break; case net::ERR_FAILED: // ERR_DNS_CACHE_MISS means HostResolver was not able to attempt DNS, e.g. // due to limitations from Chrome build configuration or because of // incompatibilities with the DNS configuration from the system. The result // Chrome would have gotten from DNS if attempted is therefore unknown. case net::ERR_DNS_CACHE_MISS: return DnsProbeRunner::UNKNOWN; // ERR_NAME_NOT_RESOLVED maps to NXDOMAIN, which means the server is working // but returned a wrong answer. case net::ERR_NAME_NOT_RESOLVED: return DnsProbeRunner::INCORRECT; // These results mean we heard *something* from the DNS server, but it was // unsuccessful (SERVFAIL) or malformed. case net::ERR_DNS_MALFORMED_RESPONSE: case net::ERR_DNS_SERVER_REQUIRES_TCP: // Shouldn't happen; DnsTransaction // will retry with TCP. case net::ERR_DNS_SERVER_FAILED: case net::ERR_DNS_SORT_ERROR: // Can only happen if the server responds. return DnsProbeRunner::FAILING; // Any other error means we never reached the DNS server in the first place. case net::ERR_DNS_TIMED_OUT: default: // Something else happened, probably at a network level. return DnsProbeRunner::UNREACHABLE; } if (!resolved_addresses) { // If net_error is OK, resolved_addresses should be set. The binding is not // closed here since it will be closed by the caller anyway. mojo::ReportBadMessage("resolved_addresses not set when net_error=OK"); return DnsProbeRunner::UNKNOWN; } else if (resolved_addresses.value().empty()) { return DnsProbeRunner::INCORRECT; } else { return DnsProbeRunner::CORRECT; } } } // namespace DnsProbeRunner::DnsProbeRunner( net::DnsConfigOverrides dns_config_overrides, const NetworkContextGetter& network_context_getter) : dns_config_overrides_(dns_config_overrides), network_context_getter_(network_context_getter) { CreateHostResolver(); } DnsProbeRunner::~DnsProbeRunner() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } void DnsProbeRunner::RunProbe(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); DCHECK(host_resolver_); DCHECK(callback_.is_null()); DCHECK(!receiver_.is_bound()); network::mojom::ResolveHostParametersPtr parameters = network::mojom::ResolveHostParameters::New(); parameters->dns_query_type = net::DnsQueryType::A; parameters->source = net::HostResolverSource::DNS; parameters->cache_usage = network::mojom::ResolveHostParameters::CacheUsage::DISALLOWED; // Use transient NIKs - don't want cached responses anyways, so no benefit // from sharing a cache, beyond multiple probes not evicting anything. host_resolver_->ResolveHost(net::HostPortPair(kKnownGoodHostname, 80), net::NetworkIsolationKey::CreateTransient(), std::move(parameters), receiver_.BindNewPipeAndPassRemote()); receiver_.set_disconnect_handler(base::BindOnce( &DnsProbeRunner::OnMojoConnectionError, base::Unretained(this))); callback_ = std::move(callback); } bool DnsProbeRunner::IsRunning() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return !callback_.is_null(); } void DnsProbeRunner::OnComplete( int32_t result, const net::ResolveErrorInfo& resolve_error_info, const base::Optional& resolved_addresses) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback_.is_null()); result_ = EvaluateResponse(resolve_error_info.error, resolved_addresses); receiver_.reset(); // ResolveHost will call OnComplete asynchronously, so callback_ can be // invoked directly here. Clear callback in case it starts a new probe // immediately. std::move(callback_).Run(); } void DnsProbeRunner::CreateHostResolver() { host_resolver_.reset(); network_context_getter_.Run()->CreateHostResolver( dns_config_overrides_, host_resolver_.BindNewPipeAndPassReceiver()); } void DnsProbeRunner::OnMojoConnectionError() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CreateHostResolver(); OnComplete(net::ERR_NAME_NOT_RESOLVED, net::ResolveErrorInfo(net::ERR_FAILED), base::nullopt); } } // namespace chrome_browser_net