From 99677208ff3b216fdfec551fbe548da5520cd6fb Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 29 Oct 2020 10:46:47 +0100 Subject: BASELINE: Update Chromium to 86.0.4240.124 Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644 Reviewed-by: Allan Sandfeld Jensen --- chromium/net/dns/BUILD.gn | 7 +- chromium/net/dns/README.md | 391 ++++++++++++++ chromium/net/dns/address_sorter_posix.cc | 8 +- chromium/net/dns/address_sorter_posix_unittest.cc | 5 +- chromium/net/dns/address_sorter_unittest.cc | 2 +- chromium/net/dns/dns_client.cc | 15 +- chromium/net/dns/dns_config.cc | 1 - chromium/net/dns/dns_config.h | 4 - chromium/net/dns/dns_config_overrides.cc | 17 +- chromium/net/dns/dns_config_overrides.h | 1 - chromium/net/dns/dns_config_service_posix.cc | 25 +- .../net/dns/dns_config_service_posix_unittest.cc | 10 +- chromium/net/dns/dns_config_service_win.cc | 98 ++-- chromium/net/dns/dns_config_service_win.h | 7 +- .../net/dns/dns_config_service_win_unittest.cc | 73 ++- chromium/net/dns/dns_hosts.cc | 2 +- chromium/net/dns/dns_hosts_unittest.cc | 2 +- chromium/net/dns/dns_query.cc | 15 +- chromium/net/dns/dns_query.h | 7 +- chromium/net/dns/dns_query_unittest.cc | 11 + chromium/net/dns/dns_reloader.cc | 6 +- chromium/net/dns/dns_reloader.h | 4 +- chromium/net/dns/dns_session.cc | 61 +-- chromium/net/dns/dns_session.h | 43 +- chromium/net/dns/dns_session_unittest.cc | 243 --------- chromium/net/dns/dns_socket_allocator.cc | 75 +++ chromium/net/dns/dns_socket_allocator.h | 54 ++ chromium/net/dns/dns_socket_allocator_unittest.cc | 82 +++ chromium/net/dns/dns_socket_pool.cc | 223 -------- chromium/net/dns/dns_socket_pool.h | 98 ---- chromium/net/dns/dns_socket_pool_unittest.cc | 108 ---- chromium/net/dns/dns_test_util.cc | 10 +- chromium/net/dns/dns_test_util.h | 4 +- chromium/net/dns/dns_transaction.cc | 162 ++++-- chromium/net/dns/dns_transaction_unittest.cc | 559 ++++++++++++++------- chromium/net/dns/dns_udp_tracker.cc | 104 +++- chromium/net/dns/dns_udp_tracker.h | 29 +- chromium/net/dns/dns_udp_tracker_unittest.cc | 136 +++-- chromium/net/dns/fuzzed_host_resolver_util.cc | 1 - chromium/net/dns/host_resolver_manager.cc | 6 +- chromium/net/dns/host_resolver_manager_unittest.cc | 3 - chromium/net/dns/host_resolver_proc.cc | 2 +- chromium/net/dns/httpssvc_metrics.cc | 14 +- chromium/net/dns/httpssvc_metrics.h | 4 +- chromium/net/dns/mdns_cache.cc | 19 +- chromium/net/dns/mdns_cache.h | 4 +- chromium/net/dns/mdns_cache_unittest.cc | 44 ++ chromium/net/dns/mdns_client_impl.cc | 29 +- chromium/net/dns/mdns_client_impl.h | 16 +- chromium/net/dns/mdns_client_unittest.cc | 116 ++++- chromium/net/dns/public/util.cc | 6 +- chromium/net/dns/resolve_context.cc | 2 +- chromium/net/dns/resolve_context_unittest.cc | 12 +- chromium/net/dns/serial_worker_unittest.cc | 6 +- 54 files changed, 1731 insertions(+), 1255 deletions(-) create mode 100644 chromium/net/dns/README.md delete mode 100644 chromium/net/dns/dns_session_unittest.cc create mode 100644 chromium/net/dns/dns_socket_allocator.cc create mode 100644 chromium/net/dns/dns_socket_allocator.h create mode 100644 chromium/net/dns/dns_socket_allocator_unittest.cc delete mode 100644 chromium/net/dns/dns_socket_pool.cc delete mode 100644 chromium/net/dns/dns_socket_pool.h delete mode 100644 chromium/net/dns/dns_socket_pool_unittest.cc (limited to 'chromium/net/dns') diff --git a/chromium/net/dns/BUILD.gn b/chromium/net/dns/BUILD.gn index 3e24edd0b48..0c38656f7a1 100644 --- a/chromium/net/dns/BUILD.gn +++ b/chromium/net/dns/BUILD.gn @@ -61,8 +61,8 @@ source_set("dns") { "dns_server_iterator.h", "dns_session.cc", "dns_session.h", - "dns_socket_pool.cc", - "dns_socket_pool.h", + "dns_socket_allocator.cc", + "dns_socket_allocator.h", "dns_transaction.cc", "dns_udp_tracker.cc", "dns_udp_tracker.h", @@ -391,8 +391,7 @@ source_set("tests") { "dns_hosts_unittest.cc", "dns_query_unittest.cc", "dns_response_unittest.cc", - "dns_session_unittest.cc", - "dns_socket_pool_unittest.cc", + "dns_socket_allocator_unittest.cc", "dns_transaction_unittest.cc", "dns_udp_tracker_unittest.cc", "dns_util_unittest.cc", diff --git a/chromium/net/dns/README.md b/chromium/net/dns/README.md new file mode 100644 index 00000000000..7bb8b074168 --- /dev/null +++ b/chromium/net/dns/README.md @@ -0,0 +1,391 @@ +# Chrome Host Resolution + +Implementation and support of host resolution for the Chrome network stack. +Includes client implementations of host resolution protocols (DNS and mDNS), +host resolution caching, support for dealing with system host resolution +(including reading HOSTS files and tracking system network settings related to +host resolution), and various related utilities. + +*** promo +Note: "DNS" in this directory (including the directory name) is often used as +shorthand for all host resolution, not just that using the Domain Name System. +This document attempts to use "DNS" only to refer to the actual Domain Name +System, except when referring to strings or paths that contain other usage of +"DNS". +*** + +[TOC] + +## Usage + +### From outside the network service + +Most interaction with host resolution should be through the [network service](/services/network/README.md) +[`network::HostResolver`](/services/network/public/mojom/host_resolver.mojom), +retrieved from [`network::NetworkContext`](/services/network/public/mojom/network_context.mojom) +using `network::NetworkContext::CreateHostResolver()`. + +Host resolution is requested using `network::HostResolver::ResolveHost()`. There +is also a shortcut using `network::NetworkContext::ResolveHost()` when a +separate passable object is not needed. + +Some general utilities are also available in [`/net/dns/public/`](/net/dns/public/) +that are intended for use by any code, inside or outside the network service. +Otherwise, code outside the network service should never interact directly with +the code in [`/net/dns/`](/net/dns/). + +### From inside the network service + +Inside the network service or inside the Chrome networking stack, host +resolution goes through [`net::HostResolver`](/net/dns/host_resolver.h), +retrieved from [`net::URLRequestContext`](/net/url_request/url_request_context.h). + +### Stand-alone tools + +Tests and stand-alone tools not part of the browser may interact with host +resolution directly by creating their own HostResolvers using +`net::HostResolver::CreateStandaloneResolver()`. + +## Test support + +### MockHostResolver + +[`net::MockHostResolver`](/net/dns/mock_host_resolver.h) + +Tests with the ability to inject and replace the used `net::HostResolver` should +replace it with a `net::MockHostResolver`, allowing rule-based results. +`net::MockCachingHostResolver` is the same except it includes basic support for +the caching functionality normally done by prod `net::HostResolver`s. + +Some tests may also find `net::HangingHostResolver` useful. It will begin host +resolution requests, but never complete them until cancellation. + +### TestHostResolver + +[`content::TestHostResolver`](/content/public/test/test_host_resolver.h) + +Used by most browser tests (via [`content::BrowserTestBase`](/content/public/test/browser_test_base.h)), +`content::TestHostResolver` installs itself on creation globally into all host +resolvers in the process. By default, only allows resolution of the local host +and returns `net::ERR_NOT_IMPLEMENTED` for other hostnames. Allows setting rules +for other results using a [net::RuleBasedHostResolverProc](/net/dns/mock_host_resolver.h). + +*** note +**Warning:** `content::TestHostResolver` only replaces host address resolution +to the system and then artificially uses such system resolution for many +requests that would normally be handled differently (e.g. using the built-in DNS +client). This means a significant amount of normal prod host resolution logic +will be bypassed in tests using `content::TestHostResolver`. +*** + +### Request remapping + +Most prod logic for creating HostResolvers will check if any global remappings +have been requested. In the browser, this is requested using the +["host-resolver-rules"](/services/network/public/cpp/network_switches.h) +commandline flag. + +See [`net::HostMappingRules`](/net/base/host_mapping_rules.h) for details on the +format of the rules string. Allows remapping any request hostname to another +hostname, an IP address, or a NOTFOUND error. + +## Implementation + +### HostResolver + +[`net::HostResolver`](/net/dns/host_resolver.h) + +The main interface for requesting host resolution within the network stack or +network service. In prod, generally owned, and retrieved as-needed from +[`net::URLRequestContext`](/net/url_request/url_request_context.h)s. Created +using `net::HostResolver::CreateResolver()` or +`net::HostResolver::CreateStandaloneResolver()`. + +Various implementations are used in prod. + +#### ContextHostResolver + +[`net::ContextHostResolver`](/net/dns/context_host_resolver.h) + +The main prod implementation of `net::HostResolver`. Expected to be owned 1:1 by +a single `net::URLRequestContext`, the `net::ContextHostResolver` owns or keeps +references to per-URLRequestContext properties used for host resolution, +including an owned [`net::HostCache`](/net/dns/host_cache.h). + +On resolution, calls into an underlying `net::HostResolverManager` with the per- +context properties. + +On destruction, silently cancels all host resolution requests made through the +`net::ContextHostResolver` instance. This prevents the underlying +`net::HostResolverManager` from continuing to reference the per-context +properties that may be destroyed on destruction of the `net::URLRequestContext` +or `net::ContextHostResolver`. + +#### MappedHostResolver + +[`net::MappedHostResolver`](/net/dns/mapped_host_resolver.h) + +A wrapping implementation around another `net::HostResolver`. Maintains request +remapping rules to remap request hostnames to other hostnames or IP addresses. + +Used to implement the ["host-resolver-rules"](/services/network/public/cpp/network_switches.h) +commandline flag. + +#### StaleHostResolver + +[`cronet::StaleHostResolver`](/components/cronet/stale_host_resolver.h) + +A wrapping implementation around another `net::HostResolver`. Returns stale +(expired or invalidated by network changes) data from the `net::HostCache` when +non-stale results take longer than a configurable timeout. Reduces host +resolution latency at the expense of accuracy. + +Only used and created by [Cronet](/components/cronet/README.md). + +### HostResolverManager + +[`net::HostResolverManager`](/net/dns/host_resolver_manager.h) + +Scheduler and controller of host resolution requests. Contains the logic for +immediate host resolution from fast local sources (e.g. querying +`net::HostCache`s, IP address literals, etc). Throttles, schedules, and merges +asynchronous jobs for resolution from slower network sources. + +On destruction, silently cancels all in-progress host resolution requests. + +In prod, a single shared `net::HostResolverManager` is generally used for the +entire browser. The shared manager is owned and configured by the +[`network::NetworkService`](/services/network/network_service.h). + +#### Request + +`net::HostResolverManager::RequestImpl` + +Implementation of [`net::HostResolver::ResolveHostRequest`](/net/dns/host_resolver.h) +and overall representation of a single request for resolution from a +`net::HostResolverManager`. The `RequestImpl` object itself primarily acts only +as a container of parameters and results for the request, leaving the actual +logic to the `net::HostResolverManager` itself. + +Data collected at this layer: + +* "Net.DNS.Request.TotalTime" (recommended for experiments) +* "Net.DNS.Request.TotalTimeAsync" + +#### Job + +`net::HostResolverManager::Job` + +Representation of an asynchronous job for resolution from slower network +sources. Contains the logic to determine and query the appropriate source for +host resolution results with retry and fallback support to other sources. On +completion adds results to relevant `net::HostCache`s and invokes request +callbacks. + +Multiple requests can be merged into a single Job if compatible. This includes +merging newly-started Jobs with already-running Jobs. + +`net::HostResolverManager` schedules and throttles running +`net::HostResolverManager::Job`s using a [`net::PrioritizedDispatcher`](/net/base/prioritized_dispatcher.h). +The throttling is important to avoid overworking network sources, especially +poorly designed home routers that may crash on only a small number of concurrent +DNS resolves. + +Data collected at this layer: + +* "Net.DNS.ResolveSuccessTime" +* "Net.DNS.ResolveFailureTime" +* "Net.DNS.ResolveCategory" +* "Net.DNS.ResolveError.Fast" +* "Net.DNS.ResolveError.Slow" +* "Net.DNS.SecureDnsMode.[Off/Automatic/Secure].ResolveTime" + +### Host resolution sources + +Various sources are used to query host resolution. The sources to be used by a +`net::HostResolverManager::Job` are determined in advance of running the Job by +`net::HostResolverManager::CreateTaskSequence()`, which outputs a list of +`net::HostResolverManager::TaskType` specifying the order of sources to attempt. +By default, this will use internal logic to decide the source to use and will +often allow fallback to additional sources. + +The sources chosen by default are also affected by the Secure DNS mode, by +default determined from +[`net::DnsConfig::secure_dns_mode`](/net/dns/dns_config.h) but overridable for +individual requests using +`net::HostResolver::ResolveHostParameters::secure_dns_mode_override`. + +Specific sources for a request can be +specified using `net::HostResolver::ResolveHostParameters::source` and +[`net::HostResolverSource`](/net/dns/host_resolver_source.h). + +The Job will then use *Task objects that implement the behavior specific to the +particular resolution sources. + +#### SYSTEM + +`net::HostResolverSource::SYSTEM` +`net::HostResolverManager::TaskType::PROC` + +Implemented by: `net::HostResolverManager::ProcTask` + +Usually called the "system resolver" or sometimes the "proc resolver". Results +are queried from the system or OS using the `getaddrinfo()` OS API call. This +source is only capable of address (A and AAAA) resolves but will also query for +canonname info if the request includes the `HOST_RESOLVER_CANONNAME` flag. The +system will query from its own internal cache, HOSTS files, DNS, and sometimes +mDNS, depending on the capabilities of the system. + +When host resolution requests do not specify a source, the system resolver will +always be used for **address resolves** when **any** of the following are true: + +* Requests with the `HOST_RESOLVER_CANONNAME` flag +* For hostnames ending in ".local" +* When the Secure DNS mode is `net::DnsConfig::SecureDnsMode::OFF` and + `net::HostResolverSource::DNS` is not enabled via + `net::HostResolverManager::SetInsecureDnsClientEnabled(true)` +* When a system DNS configuration could not be determined + +Secure DNS requests cannot be made using the system resolver. + +`net::HostResolverManager::ProcTask` uses a blocking +[`base::TaskRunner`](/base/task_runner.h) to make blocking resolution requests. +On a timeout, additional attempts are made, but previous attempts are not +cancelled as there is no cancellation mechanism for `getaddrinfo()`. The first +attempt to complete is used and any other attempt completions are ignored. + +Each attempt calls [`net::HostResolverProc`](/net/dns/host_resolver_proc.h). In +prod, this is always implemented by a `net::SystemHostResolverProc`, which makes +the actual call to `getaddrinfo()` using the +[`net::AddressInfo`](/net/dns/address_info.h) helper, but in tests, the +`net::HostResolverProc` may be replaced by a chain of test implementations to +override behavior. + +Data collected specifically for this source: + +* "Net.DNS.SecureDnsTaskFailure.FallbackProcTask.Error" + +#### DNS + +`net::HostResolverSource::DNS` +`net::HostResolverManager::TaskType::DNS` +`net::HostResolverManager::TaskType::SECURE_DNS` + +Implemented by: `net::HostResolverManager::DnsTask` + +Usually called the "built-in resolver" or the "async resolver". Results are +queried from DNS using [`net::DnsClient`](/net/dns/dns_client.h), a Chrome +network stack implementation of a DNS "stub resolver" or "DNS client". + +When host resolution requests do not specify a source, the built-in resolver +will be used when **all** of the following are true: + +* DnsClient is enabled for insecure requests enabled via + `net::HostResolverManager::SetInsecureDnsClientEnabled(true)` or + the Secure DNS mode is not `net::DnsConfig::SecureDnsMode::OFF`. +* The system DNS configuration could be determined successfully +* The request hostname does not end in ".local" +* The request is not an address query with the `HOST_RESOLVER_CANONNAME` flag + +The `net::HostResolverManager::DnsTask` will create and run a +[`net::DnsTransaction`](/net/dns/dns_transaction.h) for each DNS name/type pair +to be queried. The task will then process successful results from the returned +[`net::DnsResponse`](/net/dns/dns_response.h). + +When a request requires both A and AAAA results, they are handled via two +separate `net::DnsTransaction`s and the `net::HostResolverManager::DnsTask` will +request a second slots from the `net::PrioritizedDispatcher` used by +`net::HostResolverManager`. The A transaction is started immediately on starting +the `net::HostResolverManager::DnsTask`, and the AAAA transaction is started +once a second dispatcher slot can be obtained. + +Each `net::DnsTransaction` internally makes a series of `net::DnsAttempt`s, each +representing an individual DNS request. A single `net::DnsTransaction` can run +many `net::DnsAttempt`s due to retry logic, fallback between multiple configured +DNS servers, and name permutation due to configured search suffixes. + +Data collected specifically for this source (more internally to +`net::DnsTransaction` implementation not listed here): + +* "Net.DNS.DnsTask.ErrorBeforeFallback.Fast" +* "Net.DNS.DnsTask.ErrorBeforeFallback.Slow" +* "Net.DNS.DnsTask.SuccessTime" +* "Net.DNS.InsecureDnsTask.FailureTime" +* "Net.DNS.JobQueueTime.PerTransaction" +* "Net.DNS.JobQueueTime.Failure" +* "Net.DNS.JobQueueTime.Success" +* "Net.DNS.SecureDnsTask.DnsModeSecure.FailureTime" +* "Net.DNS.SecureDnsTask.DnsModeAutomatic.FailureTime" +* "Net.DNS.SecureDnsTask.ErrorBeforeFallback.Fast" +* "Net.DNS.SecureDnsTask.ErrorBeforeFallback.Slow" +* "Net.DNS.SecureDnsTaskFailure.FallbackDnsTask.Error" + +#### MULTICAST_DNS + +`net::HostResolverSource::MULTICAST_DNS` +`net::HostResolverManager::TaskType::MDNS` + +Implemented by [`net::HostResolverMdnsTask`](/net/dns/host_resolver_mdns_task.h) + +Results are queried from mDNS using [`net::MDnsClient`](/net/dns/mdns_client.h). + +When host resolution requests do not specify a source, mDNS is only used for +non-address requests when the request hostname ends in ".local". + +mDNS requests start with [`net::HostResolverMdnsTask`](/net/dns/host_resolver_mdns_task.h), +which will create and run a [`net::MDnsTransaction`](/net/dns/mdns_client.h) for +each query type needed. + +Unlike `net::HostResolverManager::DnsTask`, each `net::HostResolverMdnsTask` +will only ever use a single dispatcher slot, even when both A and AAAA types are +queried concurrently. + +`net::MDnsClient` maintains its own cache, separate from the main +[`net::HostCache`](/net/dns/host_cache.h) owned by the +[`net::ContextHostResolver`](/net/dns/context_host_resolver.h). As such, mDNS +results are never cached in the `net::HostCache`. + +### IPv6 and connectivity + +Some poorly written DNS servers, especially on home routers, are unaware of the +existence of IPv6 and will result in bad performance or even crash when sent +AAAA DNS queries. + +To avoid such issues, `net::HostResolverManager` heuristically detects IPv4-only +networks by attempting a UDP connection to `2001:4860:4860::8888` (the IPv6 +address for Google Public DNS). If the connection fails, Chrome will convert +host resolution requests for `net::DnsQueryType::UNSPECIFIED` to +`net::DnsQueryType::A`. This generally results in disallowing AAAA requests. + +Exceptions when AAAA requests are always allowed despite a failed connectivity +check: + +* The host resolution request explicitly requests `net::DnsQueryType::AAAA` +* IP address literal resolution including when a hostname request has been + rewritten to an IP address literal using `net::MappedHostResolver` +* Results read from HOSTS files where there is no non-loopback IPv4 result. Note + that this exception only applies when Chrome does the read from HOSTS. When + Chrome's built-in DNS client is not used, HOSTS is only read by the system + where Chrome would only request A results to avoid the system making AAAA DNS + queries. + +The heuristic for detecting IPv4-only networks is not perfect. E.g., it fails +and disallows AAAA requests in private (no global internet access including to +Google Public DNS) IPv6-only networks, which could then break most Chrome usage +on the network because, being an IPv6-only network, AAAA results are necessary. + +Workarounds to allow Chrome to attempt to load IPv6 endpoints when the +connectivity check fails: + +* Starting Chrome with + `--host-resolver-rules="MAP the.hostname.com [dead::beef]"` where + `the.hostname.com` is the hostname to allow resolving and `dead::beef` is the + IPv6 address to resolve it to. `net::MappedHostResolver` acts at a level + before IPv6 connectivity checks, and if a hostname is remapped to an IP + literal, connectivity checks do not apply. +* Add entries for the hostnames to resolve to the HOSTS file with just IPv6 + results. Only works with the built-in DNS client is used. +* Add a network route to `2001:4860:4860::8888`. Doesn't have to actually be + functional (could just drop requests to it). As long as Chrome can connect a + UDP socket to the address, it will pass the heuristic checking + IPv6-connectivity. diff --git a/chromium/net/dns/address_sorter_posix.cc b/chromium/net/dns/address_sorter_posix.cc index b7683911481..e0443455a67 100644 --- a/chromium/net/dns/address_sorter_posix.cc +++ b/chromium/net/dns/address_sorter_posix.cc @@ -9,7 +9,7 @@ #include #include -#if defined(OS_MACOSX) || defined(OS_BSD) +#if defined(OS_APPLE) || defined(OS_BSD) #include // Must be included before ifaddrs.h. #include #include @@ -28,7 +28,7 @@ #include "net/socket/client_socket_factory.h" #include "net/socket/datagram_client_socket.h" -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) #include "net/base/address_tracker_linux.h" #endif @@ -329,7 +329,7 @@ void AddressSorterPosix::Sort(const AddressList& list, void AddressSorterPosix::OnIPAddressChanged() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); source_map_.clear(); -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) const internal::AddressTrackerLinux* tracker = NetworkChangeNotifier::GetAddressTracker(); if (!tracker) @@ -346,7 +346,7 @@ void AddressSorterPosix::OnIPAddressChanged() { info.prefix_length = msg.ifa_prefixlen; FillPolicy(address, &info); } -#elif defined(OS_MACOSX) || defined(OS_BSD) +#elif defined(OS_APPLE) || defined(OS_BSD) // It's not clear we will receive notification when deprecated flag changes. // Socket for ioctl. int ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0); diff --git a/chromium/net/dns/address_sorter_posix_unittest.cc b/chromium/net/dns/address_sorter_posix_unittest.cc index 92a15b69e4e..35053c7539d 100644 --- a/chromium/net/dns/address_sorter_posix_unittest.cc +++ b/chromium/net/dns/address_sorter_posix_unittest.cc @@ -20,6 +20,7 @@ #include "net/socket/socket_performance_watcher.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/stream_socket.h" +#include "net/test/test_with_task_environment.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "testing/gtest/include/gtest/gtest.h" @@ -203,7 +204,9 @@ void OnSortComplete(AddressList* result_buf, } // namespace -class AddressSorterPosixTest : public testing::Test { +// TaskEnvironment is required to register an IPAddressObserver from the +// constructor of AddressSorterPosix. +class AddressSorterPosixTest : public TestWithTaskEnvironment { protected: AddressSorterPosixTest() : sorter_(&socket_factory_) {} diff --git a/chromium/net/dns/address_sorter_unittest.cc b/chromium/net/dns/address_sorter_unittest.cc index 49ca0c2c57f..aab36e245ce 100644 --- a/chromium/net/dns/address_sorter_unittest.cc +++ b/chromium/net/dns/address_sorter_unittest.cc @@ -42,9 +42,9 @@ void OnSortComplete(AddressList* result_buf, } TEST(AddressSorterTest, Sort) { + base::test::TaskEnvironment task_environment; int expected_result = OK; #if defined(OS_WIN) - base::test::TaskEnvironment task_environment; EnsureWinsockInit(); SOCKET sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { diff --git a/chromium/net/dns/dns_client.cc b/chromium/net/dns/dns_client.cc index 08358b8375e..b70f66db484 100644 --- a/chromium/net/dns/dns_client.cc +++ b/chromium/net/dns/dns_client.cc @@ -12,7 +12,7 @@ #include "base/values.h" #include "net/dns/address_sorter.h" #include "net/dns/dns_session.h" -#include "net/dns/dns_socket_pool.h" +#include "net/dns/dns_socket_allocator.h" #include "net/dns/dns_transaction.h" #include "net/dns/dns_util.h" #include "net/dns/resolve_context.h" @@ -245,14 +245,11 @@ class DnsClientImpl : public DnsClient { if (new_effective_config) { DCHECK(new_effective_config.value().IsValid()); - std::unique_ptr socket_pool( - new_effective_config.value().randomize_ports - ? DnsSocketPool::CreateDefault(socket_factory_, - rand_int_callback_) - : DnsSocketPool::CreateNull(socket_factory_, rand_int_callback_)); - session_ = - new DnsSession(std::move(new_effective_config).value(), - std::move(socket_pool), rand_int_callback_, net_log_); + auto socket_allocator = std::make_unique( + socket_factory_, new_effective_config.value().nameservers, net_log_); + session_ = new DnsSession(std::move(new_effective_config).value(), + std::move(socket_allocator), rand_int_callback_, + net_log_); factory_ = DnsTransactionFactory::CreateFactory(session_.get()); } } diff --git a/chromium/net/dns/dns_config.cc b/chromium/net/dns/dns_config.cc index c6d757e5144..af2c38e3f02 100644 --- a/chromium/net/dns/dns_config.cc +++ b/chromium/net/dns/dns_config.cc @@ -24,7 +24,6 @@ DnsConfig::DnsConfig(std::vector nameservers) dns_over_tls_hostname(std::string()), unhandled_options(false), append_to_multi_label_name(true), - randomize_ports(false), ndots(1), timeout(kDnsDefaultTimeout), attempts(2), diff --git a/chromium/net/dns/dns_config.h b/chromium/net/dns/dns_config.h index d65a31eb45d..6ab6e4147fb 100644 --- a/chromium/net/dns/dns_config.h +++ b/chromium/net/dns/dns_config.h @@ -86,10 +86,6 @@ struct NET_EXPORT DnsConfig { // True, except on Windows where it can be configured. bool append_to_multi_label_name; - // Indicates that source port randomization is required. This uses additional - // resources on some platforms. - bool randomize_ports; - // Resolver options; see man resolv.conf. // Minimum number of dots before global resolution precedes |search|. diff --git a/chromium/net/dns/dns_config_overrides.cc b/chromium/net/dns/dns_config_overrides.cc index 0ea96839251..fa0437e7fc4 100644 --- a/chromium/net/dns/dns_config_overrides.cc +++ b/chromium/net/dns/dns_config_overrides.cc @@ -25,10 +25,9 @@ bool DnsConfigOverrides::operator==(const DnsConfigOverrides& other) const { return nameservers == other.nameservers && search == other.search && hosts == other.hosts && append_to_multi_label_name == other.append_to_multi_label_name && - randomize_ports == other.randomize_ports && ndots == other.ndots && - timeout == other.timeout && attempts == other.attempts && - doh_attempts == other.doh_attempts && rotate == other.rotate && - use_local_ipv6 == other.use_local_ipv6 && + ndots == other.ndots && timeout == other.timeout && + attempts == other.attempts && doh_attempts == other.doh_attempts && + rotate == other.rotate && use_local_ipv6 == other.use_local_ipv6 && dns_over_https_servers == other.dns_over_https_servers && secure_dns_mode == other.secure_dns_mode && allow_dns_over_https_upgrade == other.allow_dns_over_https_upgrade && @@ -49,7 +48,6 @@ DnsConfigOverrides::CreateOverridingEverythingWithDefaults() { overrides.search = defaults.search; overrides.hosts = defaults.hosts; overrides.append_to_multi_label_name = defaults.append_to_multi_label_name; - overrides.randomize_ports = defaults.randomize_ports; overrides.ndots = defaults.ndots; overrides.timeout = defaults.timeout; overrides.attempts = defaults.attempts; @@ -67,10 +65,9 @@ DnsConfigOverrides::CreateOverridingEverythingWithDefaults() { bool DnsConfigOverrides::OverridesEverything() const { return nameservers && search && hosts && append_to_multi_label_name && - randomize_ports && ndots && timeout && attempts && doh_attempts && - rotate && use_local_ipv6 && dns_over_https_servers && - secure_dns_mode && allow_dns_over_https_upgrade && - disabled_upgrade_providers; + ndots && timeout && attempts && doh_attempts && rotate && + use_local_ipv6 && dns_over_https_servers && secure_dns_mode && + allow_dns_over_https_upgrade && disabled_upgrade_providers; } DnsConfig DnsConfigOverrides::ApplyOverrides(const DnsConfig& config) const { @@ -87,8 +84,6 @@ DnsConfig DnsConfigOverrides::ApplyOverrides(const DnsConfig& config) const { overridden.hosts = hosts.value(); if (append_to_multi_label_name) overridden.append_to_multi_label_name = append_to_multi_label_name.value(); - if (randomize_ports) - overridden.randomize_ports = randomize_ports.value(); if (ndots) overridden.ndots = ndots.value(); if (timeout) diff --git a/chromium/net/dns/dns_config_overrides.h b/chromium/net/dns/dns_config_overrides.h index e09a6ee82fd..a87d0e503f4 100644 --- a/chromium/net/dns/dns_config_overrides.h +++ b/chromium/net/dns/dns_config_overrides.h @@ -50,7 +50,6 @@ struct NET_EXPORT DnsConfigOverrides { base::Optional> search; base::Optional hosts; base::Optional append_to_multi_label_name; - base::Optional randomize_ports; base::Optional ndots; base::Optional timeout; base::Optional attempts; diff --git a/chromium/net/dns/dns_config_service_posix.cc b/chromium/net/dns/dns_config_service_posix.cc index d8224724a89..5a4aead0acf 100644 --- a/chromium/net/dns/dns_config_service_posix.cc +++ b/chromium/net/dns/dns_config_service_posix.cc @@ -30,7 +30,7 @@ #include "net/dns/public/dns_protocol.h" #include "net/dns/serial_worker.h" -#if defined(OS_MACOSX) && !defined(OS_IOS) +#if defined(OS_MAC) #include "net/dns/dns_config_watcher_mac.h" #endif @@ -96,11 +96,11 @@ class DnsConfigWatcher : public NetworkChangeNotifier::NetworkChangeObserver { CallbackType callback_; }; -#elif defined(OS_MACOSX) +#elif defined(OS_MAC) -// DnsConfigWatcher for OS_MACOSX is in dns_config_watcher_mac.{hh,cc}. +// DnsConfigWatcher for OS_MAC is in dns_config_watcher_mac.{hh,cc}. -#else // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) +#else // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MAC) #ifndef _PATH_RESCONF // Normally defined in #define _PATH_RESCONF "/etc/resolv.conf" @@ -169,14 +169,14 @@ ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) { result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; } // Prefer res_ndestroy where available. -#if defined(OS_MACOSX) || defined(OS_FREEBSD) +#if defined(OS_APPLE) || defined(OS_FREEBSD) res_ndestroy(&res); #else res_nclose(&res); -#endif // defined(OS_MACOSX) || defined(OS_FREEBSD) +#endif // defined(OS_APPLE) || defined(OS_FREEBSD) #endif // defined(OS_OPENBSD) -#if defined(OS_MACOSX) && !defined(OS_IOS) +#if defined(OS_MAC) ConfigParsePosixResult error = DnsConfigWatcher::CheckDnsConfig(); switch (error) { case CONFIG_PARSE_POSIX_OK: @@ -188,7 +188,7 @@ ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) { default: return error; } -#endif // defined(OS_MACOSX) && !defined(OS_IOS) +#endif // defined(OS_MAC) // Override timeout value to match default setting on Windows. dns_config->timeout = kDnsDefaultTimeout; return result; @@ -478,7 +478,7 @@ ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, dns_config->nameservers.clear(); -#if defined(OS_MACOSX) || defined(OS_FREEBSD) +#if defined(OS_APPLE) || defined(OS_FREEBSD) union res_sockaddr_union addresses[MAXNS]; int nscount = res_getservers(const_cast(&res), addresses, MAXNS); DCHECK_GE(nscount, 0); @@ -492,7 +492,7 @@ ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, } dns_config->nameservers.push_back(ipe); } -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || defined(OS_CHROMEOS) static_assert(std::extent() >= MAXNS && std::extent() >= MAXNS, "incompatible libresolv res_state"); @@ -517,7 +517,8 @@ ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, return CONFIG_PARSE_POSIX_BAD_ADDRESS; dns_config->nameservers.push_back(ipe); } -#else // !(defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FREEBSD)) +#else // !(defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_APPLE) || + // defined(OS_FREEBSD)) DCHECK_LE(res.nscount, MAXNS); for (int i = 0; i < res.nscount; ++i) { IPEndPoint ipe; @@ -528,7 +529,7 @@ ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, } dns_config->nameservers.push_back(ipe); } -#endif // defined(OS_MACOSX) || defined(OS_FREEBSD) +#endif // defined(OS_APPLE) || defined(OS_FREEBSD) dns_config->search.clear(); for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) { diff --git a/chromium/net/dns/dns_config_service_posix_unittest.cc b/chromium/net/dns/dns_config_service_posix_unittest.cc index 89892406263..a98dffb783f 100644 --- a/chromium/net/dns/dns_config_service_posix_unittest.cc +++ b/chromium/net/dns/dns_config_service_posix_unittest.cc @@ -51,7 +51,7 @@ const char* const kNameserversIPv4[] = { "1.0.0.1", }; -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) const char* const kNameserversIPv6[] = { NULL, "2001:DB8:0::42", @@ -87,7 +87,7 @@ void InitializeResState(res_state res) { ++res->nscount; } -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) // Install IPv6 addresses, replacing the corresponding IPv4 addresses. unsigned nscount6 = 0; for (unsigned i = 0; i < base::size(kNameserversIPv6) && i < MAXNS; ++i) { @@ -108,7 +108,7 @@ void InitializeResState(res_state res) { } void CloseResState(res_state res) { -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) for (int i = 0; i < res->nscount; ++i) { if (res->_u._ext.nsaddrs[i] != NULL) free(res->_u._ext.nsaddrs[i]); @@ -133,7 +133,7 @@ void InitializeExpectedConfig(DnsConfig* config) { config->nameservers.push_back(IPEndPoint(ip, NS_DEFAULTPORT + i)); } -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) for (unsigned i = 0; i < base::size(kNameserversIPv6) && i < MAXNS; ++i) { if (!kNameserversIPv6[i]) continue; @@ -241,7 +241,7 @@ class DnsConfigServicePosixTest : public testing::Test { service_.reset(new DnsConfigServicePosix()); } - void TearDown() override { ASSERT_TRUE(base::DeleteFile(temp_file_, false)); } + void TearDown() override { ASSERT_TRUE(base::DeleteFile(temp_file_)); } base::test::TaskEnvironment task_environment_; bool seen_config_; diff --git a/chromium/net/dns/dns_config_service_win.cc b/chromium/net/dns/dns_config_service_win.cc index 9cd9d76f6bb..37fd844c1de 100644 --- a/chromium/net/dns/dns_config_service_win.cc +++ b/chromium/net/dns/dns_config_service_win.cc @@ -20,6 +20,7 @@ #include "base/metrics/histogram_macros.h" #include "base/sequence_checker.h" #include "base/single_thread_task_runner.h" +#include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -46,27 +47,27 @@ namespace { const int kRetryIntervalSeconds = 5; // Registry key paths. -const base::char16 kTcpipPath[] = - STRING16_LITERAL("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"); -const base::char16 kTcpip6Path[] = - STRING16_LITERAL("SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"); -const base::char16 kDnscachePath[] = STRING16_LITERAL( - "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"); -const base::char16 kPolicyPath[] = - STRING16_LITERAL("SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"); -const base::char16 kPrimaryDnsSuffixPath[] = - STRING16_LITERAL("SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"); -const base::char16 kNrptPath[] = STRING16_LITERAL( - "SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig"); -const base::char16 kControlSetNrptPath[] = STRING16_LITERAL( - "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters" - "\\DnsPolicyConfig"); -const base::char16 kDnsConnectionsPath[] = STRING16_LITERAL( - "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters" - "\\DnsConnections"); -const base::char16 kDnsConnectionsProxies[] = STRING16_LITERAL( - "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters" - "\\DnsConnectionsProxies"); +const wchar_t kTcpipPath[] = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; +const wchar_t kTcpip6Path[] = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; +const wchar_t kDnscachePath[] = + L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"; +const wchar_t kPolicyPath[] = + L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"; +const wchar_t kPrimaryDnsSuffixPath[] = + L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"; +const wchar_t kNrptPath[] = + L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig"; +const wchar_t kControlSetNrptPath[] = + L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\" + L"DnsPolicyConfig"; +const wchar_t kDnsConnectionsPath[] = + L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\" + L"DnsConnections"; +const wchar_t kDnsConnectionsProxies[] = + L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\" + L"DnsConnectionsProxies"; enum HostsParseWinResult { HOSTS_PARSE_WIN_OK = 0, @@ -80,14 +81,14 @@ enum HostsParseWinResult { // Convenience for reading values using RegKey. class RegistryReader { public: - explicit RegistryReader(const base::char16* key) { + explicit RegistryReader(const wchar_t* key) { // Ignoring the result. |key_.Valid()| will catch failures. key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); } ~RegistryReader() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - bool ReadString(const base::char16* name, + bool ReadString(const wchar_t* name, DnsSystemSettings::RegString* out) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); out->set = false; @@ -103,8 +104,7 @@ class RegistryReader { return (result == ERROR_FILE_NOT_FOUND); } - bool ReadDword(const base::char16* name, - DnsSystemSettings::RegDword* out) const { + bool ReadDword(const wchar_t* name, DnsSystemSettings::RegDword* out) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); out->set = false; if (!key_.Valid()) { @@ -150,10 +150,8 @@ std::unique_ptr ReadIpHelper( bool ReadDevolutionSetting(const RegistryReader& reader, DnsSystemSettings::DevolutionSetting* setting) { - return reader.ReadDword(STRING16_LITERAL("UseDomainNameDevolution"), - &setting->enabled) && - reader.ReadDword(STRING16_LITERAL("DomainNameDevolutionLevel"), - &setting->level); + return reader.ReadDword(L"UseDomainNameDevolution", &setting->enabled) && + reader.ReadDword(L"DomainNameDevolutionLevel", &setting->level); } // Reads DnsSystemSettings from IpHelper and registry. @@ -173,17 +171,14 @@ ConfigParseWinResult ReadSystemSettings(DnsSystemSettings* settings) { RegistryReader policy_reader(kPolicyPath); RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath); - if (!policy_reader.ReadString(STRING16_LITERAL("SearchList"), - &settings->policy_search_list)) { + if (!policy_reader.ReadString(L"SearchList", &settings->policy_search_list)) { return CONFIG_PARSE_WIN_READ_POLICY_SEARCHLIST; } - if (!tcpip_reader.ReadString(STRING16_LITERAL("SearchList"), - &settings->tcpip_search_list)) + if (!tcpip_reader.ReadString(L"SearchList", &settings->tcpip_search_list)) return CONFIG_PARSE_WIN_READ_TCPIP_SEARCHLIST; - if (!tcpip_reader.ReadString(STRING16_LITERAL("Domain"), - &settings->tcpip_domain)) + if (!tcpip_reader.ReadString(L"Domain", &settings->tcpip_domain)) return CONFIG_PARSE_WIN_READ_DOMAIN; if (!ReadDevolutionSetting(policy_reader, &settings->policy_devolution)) @@ -195,14 +190,13 @@ ConfigParseWinResult ReadSystemSettings(DnsSystemSettings* settings) { if (!ReadDevolutionSetting(tcpip_reader, &settings->tcpip_devolution)) return CONFIG_PARSE_WIN_READ_TCPIP_DEVOLUTION; - if (!policy_reader.ReadDword(STRING16_LITERAL("AppendToMultiLabelName"), + if (!policy_reader.ReadDword(L"AppendToMultiLabelName", &settings->append_to_multi_label_name)) { return CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL; } - if (!primary_dns_suffix_reader.ReadString( - STRING16_LITERAL("PrimaryDnsSuffix"), - &settings->primary_dns_suffix)) { + if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", + &settings->primary_dns_suffix)) { return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX; } @@ -234,11 +228,10 @@ HostsParseWinResult AddLocalhostEntries(DnsHosts* hosts) { hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), loopback_ipv6)); - base::char16 buffer[MAX_PATH]; + wchar_t buffer[MAX_PATH]; DWORD size = MAX_PATH; std::string localname; - if (!GetComputerNameExW(ComputerNameDnsHostname, - base::as_writable_wcstr(buffer), &size) || + if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || !ParseDomainASCII(buffer, &localname)) { return HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED; } @@ -296,7 +289,7 @@ class RegistryWatcher { ~RegistryWatcher() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - bool Watch(const base::char16* key, const CallbackType& callback) { + bool Watch(const wchar_t* key, const CallbackType& callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); DCHECK(callback_.is_null()); @@ -342,8 +335,8 @@ bool IsStatelessDiscoveryAddress(const IPAddress& address) { // Returns the path to the HOSTS file. base::FilePath GetHostsPath() { - base::char16 buffer[MAX_PATH]; - UINT rc = GetSystemDirectory(base::as_writable_wcstr(buffer), MAX_PATH); + wchar_t buffer[MAX_PATH]; + UINT rc = GetSystemDirectory(buffer, MAX_PATH); DCHECK(0 < rc && rc < MAX_PATH); return base::FilePath(buffer).Append( FILE_PATH_LITERAL("drivers\\etc\\hosts")); @@ -462,13 +455,13 @@ DnsSystemSettings::DnsSystemSettings() DnsSystemSettings::~DnsSystemSettings() { } -bool ParseDomainASCII(base::StringPiece16 widestr, std::string* domain) { +bool ParseDomainASCII(base::WStringPiece widestr, std::string* domain) { DCHECK(domain); if (widestr.empty()) return false; // Check if already ASCII. - if (base::IsStringASCII(widestr)) { + if (base::IsStringASCII(base::AsStringPiece16(widestr))) { domain->assign(widestr.begin(), widestr.end()); return true; } @@ -476,7 +469,7 @@ bool ParseDomainASCII(base::StringPiece16 widestr, std::string* domain) { // Otherwise try to convert it from IDN to punycode. const int kInitialBufferSize = 256; url::RawCanonOutputT punycode; - if (!url::IDNToASCII(widestr.data(), widestr.length(), &punycode)) + if (!url::IDNToASCII(base::as_u16cstr(widestr), widestr.length(), &punycode)) return false; // |punycode_output| should now be ASCII; convert it to a std::string. @@ -488,7 +481,7 @@ bool ParseDomainASCII(base::StringPiece16 widestr, std::string* domain) { return success && !domain->empty(); } -bool ParseSearchList(const base::string16& value, +bool ParseSearchList(const std::wstring& value, std::vector* output) { DCHECK(output); if (value.empty()) @@ -500,9 +493,8 @@ bool ParseSearchList(const base::string16& value, // Although nslookup and network connection property tab ignore such // fragments ("a,b,,c" becomes ["a", "b", "c"]), our reference is getaddrinfo // (which sees ["a", "b"]). WMI queries also return a matching search list. - for (const base::StringPiece16& t : - base::SplitStringPiece(value, STRING16_LITERAL(","), - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { + for (base::WStringPiece t : base::SplitStringPiece( + value, L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { // Convert non-ASCII to punycode, although getaddrinfo does not properly // handle such suffixes. std::string parsed; @@ -561,7 +553,7 @@ ConfigParseWinResult ConvertSettingsToDnsConfig( // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) // or specified by the user (regkey: Tcpip\Parameters\Domain). std::string dns_suffix; - if (ParseDomainASCII(base::as_u16cstr(adapter->DnsSuffix), &dns_suffix)) + if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) config->search.push_back(dns_suffix); } diff --git a/chromium/net/dns/dns_config_service_win.h b/chromium/net/dns/dns_config_service_win.h index 8b64504a7c5..6c7e3df9e8a 100644 --- a/chromium/net/dns/dns_config_service_win.h +++ b/chromium/net/dns/dns_config_service_win.h @@ -19,6 +19,7 @@ #include "base/memory/free_deleter.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" +#include "base/strings/string_piece_forward.h" #include "net/base/net_export.h" #include "net/dns/dns_config_service.h" @@ -40,14 +41,14 @@ namespace internal { // Converts a UTF-16 domain name to ASCII, possibly using punycode. // Returns true if the conversion succeeds and output is not empty. In case of // failure, |domain| might become dirty. -bool NET_EXPORT_PRIVATE ParseDomainASCII(base::StringPiece16 widestr, +bool NET_EXPORT_PRIVATE ParseDomainASCII(base::WStringPiece widestr, std::string* domain); // Parses |value| as search list (comma-delimited list of domain names) from // a registry key and stores it in |out|. Returns true on success. Empty // entries (e.g., "chromium.org,,org") terminate the list. Non-ascii hostnames // are converted to punycode. -bool NET_EXPORT_PRIVATE ParseSearchList(const base::string16& value, +bool NET_EXPORT_PRIVATE ParseSearchList(const std::wstring& value, std::vector* out); // All relevant settings read from registry and IP Helper. This isolates our @@ -57,7 +58,7 @@ struct NET_EXPORT_PRIVATE DnsSystemSettings { // The |set| flag distinguishes between empty and unset values. struct RegString { bool set; - base::string16 value; + std::wstring value; }; struct RegDword { diff --git a/chromium/net/dns/dns_config_service_win_unittest.cc b/chromium/net/dns/dns_config_service_win_unittest.cc index cd34aa1a997..070df338e13 100644 --- a/chromium/net/dns/dns_config_service_win_unittest.cc +++ b/chromium/net/dns/dns_config_service_win_unittest.cc @@ -17,19 +17,19 @@ namespace { TEST(DnsConfigServiceWinTest, ParseSearchList) { const struct TestCase { - const base::char16* input; + const wchar_t* input; const char* output[4]; // NULL-terminated, empty if expected false } cases[] = { - {STRING16_LITERAL("chromium.org"), {"chromium.org", nullptr}}, - {STRING16_LITERAL("chromium.org,org"), {"chromium.org", "org", nullptr}}, + {L"chromium.org", {"chromium.org", nullptr}}, + {L"chromium.org,org", {"chromium.org", "org", nullptr}}, // Empty suffixes terminate the list - {STRING16_LITERAL("crbug.com,com,,org"), {"crbug.com", "com", nullptr}}, + {L"crbug.com,com,,org", {"crbug.com", "com", nullptr}}, // IDN are converted to punycode - {STRING16_LITERAL("\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl"), + {L"\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl", {"xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl", nullptr}}, // Empty search list is invalid - {STRING16_LITERAL(""), {nullptr}}, - {STRING16_LITERAL(",,"), {nullptr}}, + {L"", {nullptr}}, + {L",,", {nullptr}}, }; for (const auto& t : cases) { @@ -219,11 +219,10 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { // Policy SearchList override. { - {true, - STRING16_LITERAL("policy.searchlist.a,policy.searchlist.b")}, - {true, STRING16_LITERAL("tcpip.searchlist.a,tcpip.searchlist.b")}, - {true, STRING16_LITERAL("tcpip.domain")}, - {true, STRING16_LITERAL("primary.dns.suffix")}, + {true, L"policy.searchlist.a,policy.searchlist.b"}, + {true, L"tcpip.searchlist.a,tcpip.searchlist.b"}, + {true, L"tcpip.domain"}, + {true, L"primary.dns.suffix"}, }, {"policy.searchlist.a", "policy.searchlist.b"}, }, @@ -231,18 +230,18 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { // User-specified SearchList override. { {false}, - {true, STRING16_LITERAL("tcpip.searchlist.a,tcpip.searchlist.b")}, - {true, STRING16_LITERAL("tcpip.domain")}, - {true, STRING16_LITERAL("primary.dns.suffix")}, + {true, L"tcpip.searchlist.a,tcpip.searchlist.b"}, + {true, L"tcpip.domain"}, + {true, L"primary.dns.suffix"}, }, {"tcpip.searchlist.a", "tcpip.searchlist.b"}, }, { // Void SearchList. Using tcpip.domain { - {true, STRING16_LITERAL(",bad.searchlist,parsed.as.empty")}, - {true, STRING16_LITERAL("tcpip.searchlist,good.but.overridden")}, - {true, STRING16_LITERAL("tcpip.domain")}, + {true, L",bad.searchlist,parsed.as.empty"}, + {true, L"tcpip.searchlist,good.but.overridden"}, + {true, L"tcpip.domain"}, {false}, }, {"tcpip.domain", "connection.suffix"}, @@ -250,10 +249,10 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { // Void SearchList. Using primary.dns.suffix { - {true, STRING16_LITERAL(",bad.searchlist,parsed.as.empty")}, - {true, STRING16_LITERAL("tcpip.searchlist,good.but.overridden")}, - {true, STRING16_LITERAL("tcpip.domain")}, - {true, STRING16_LITERAL("primary.dns.suffix")}, + {true, L",bad.searchlist,parsed.as.empty"}, + {true, L"tcpip.searchlist,good.but.overridden"}, + {true, L"tcpip.domain"}, + {true, L"primary.dns.suffix"}, }, {"primary.dns.suffix", "connection.suffix"}, }, @@ -261,19 +260,19 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { // Void SearchList. Using tcpip.domain when primary.dns.suffix is // empty { - {true, STRING16_LITERAL(",bad.searchlist,parsed.as.empty")}, - {true, STRING16_LITERAL("tcpip.searchlist,good.but.overridden")}, - {true, STRING16_LITERAL("tcpip.domain")}, - {true, STRING16_LITERAL("")}, + {true, L",bad.searchlist,parsed.as.empty"}, + {true, L"tcpip.searchlist,good.but.overridden"}, + {true, L"tcpip.domain"}, + {true, L""}, }, {"tcpip.domain", "connection.suffix"}, }, { // Void SearchList. Using tcpip.domain when primary.dns.suffix is NULL { - {true, STRING16_LITERAL(",bad.searchlist,parsed.as.empty")}, - {true, STRING16_LITERAL("tcpip.searchlist,good.but.overridden")}, - {true, STRING16_LITERAL("tcpip.domain")}, + {true, L",bad.searchlist,parsed.as.empty"}, + {true, L"tcpip.searchlist,good.but.overridden"}, + {true, L"tcpip.domain"}, {true}, }, {"tcpip.domain", "connection.suffix"}, @@ -294,7 +293,7 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b.c.d.e")}, + {true, L"a.b.c.d.e"}, {false}, {{true, 1}, {false}}, // policy_devolution: enabled, level {{true, 0}, {true, 3}}, // dnscache_devolution @@ -307,8 +306,8 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b.c.d.e")}, - {true, STRING16_LITERAL("f.g.i.l.j")}, + {true, L"a.b.c.d.e"}, + {true, L"f.g.i.l.j"}, {{false}, {true, 4}}, {{true, 1}, {false}}, {{true, 0}, {true, 3}}, @@ -320,7 +319,7 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b.c.d.e")}, + {true, L"a.b.c.d.e"}, {false}, {{false}, {false}}, {{false}, {true, 3}}, @@ -333,7 +332,7 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b")}, + {true, L"a.b"}, {false}, {{false}, {false}}, {{false}, {true, 2}}, @@ -346,7 +345,7 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b.c.d.e")}, + {true, L"a.b.c.d.e"}, {false}, {{true, 1}, {false}}, {{true, 1}, {false}}, @@ -359,7 +358,7 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b.c.d.e")}, + {true, L"a.b.c.d.e"}, {false}, {{false}, {true, 1}}, {{true, 1}, {true, 3}}, @@ -372,7 +371,7 @@ TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { { {false}, {false}, - {true, STRING16_LITERAL("a.b.c.d.e")}, + {true, L"a.b.c.d.e"}, {false}, {{false}, {true, 3}}, {{false}, {true, 3}}, diff --git a/chromium/net/dns/dns_hosts.cc b/chromium/net/dns/dns_hosts.cc index 04b1596e613..42e40598e96 100644 --- a/chromium/net/dns/dns_hosts.cc +++ b/chromium/net/dns/dns_hosts.cc @@ -177,7 +177,7 @@ void ParseHostsWithCommaModeForTesting(const std::string& contents, void ParseHosts(const std::string& contents, DnsHosts* dns_hosts) { ParseHostsCommaMode comma_mode; -#if defined(OS_MACOSX) +#if defined(OS_APPLE) // Mac OS X allows commas to separate hostnames. comma_mode = PARSE_HOSTS_COMMA_IS_WHITESPACE; #else diff --git a/chromium/net/dns/dns_hosts_unittest.cc b/chromium/net/dns/dns_hosts_unittest.cc index 0b5476dc0eb..50353361d11 100644 --- a/chromium/net/dns/dns_hosts_unittest.cc +++ b/chromium/net/dns/dns_hosts_unittest.cc @@ -112,7 +112,7 @@ TEST(DnsHostsTest, ParseHosts_CommaModeByPlatform) { DnsHosts actual_hosts; ParseHosts(kContents, &actual_hosts); -#if defined(OS_MACOSX) +#if defined(OS_APPLE) const ExpectedHostsEntry kEntries[] = { { "comma1", ADDRESS_FAMILY_IPV4, "127.0.0.1" }, { "comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" }, diff --git a/chromium/net/dns/dns_query.cc b/chromium/net/dns/dns_query.cc index 90176623c05..2e33f4f3543 100644 --- a/chromium/net/dns/dns_query.cc +++ b/chromium/net/dns/dns_query.cc @@ -148,6 +148,15 @@ DnsQuery::DnsQuery(uint16_t id, DnsQuery::DnsQuery(scoped_refptr buffer) : io_buffer_(std::move(buffer)) {} +DnsQuery::DnsQuery(const DnsQuery& query) { + CopyFrom(query); +} + +DnsQuery& DnsQuery::operator=(const DnsQuery& query) { + CopyFrom(query); + return *this; +} + DnsQuery::~DnsQuery() = default; std::unique_ptr DnsQuery::CloneWithNewId(uint16_t id) const { @@ -221,12 +230,16 @@ void DnsQuery::set_flags(uint16_t flags) { } DnsQuery::DnsQuery(const DnsQuery& orig, uint16_t id) { + CopyFrom(orig); + header_->id = base::HostToNet16(id); +} + +void DnsQuery::CopyFrom(const DnsQuery& orig) { qname_size_ = orig.qname_size_; io_buffer_ = base::MakeRefCounted(orig.io_buffer()->size()); memcpy(io_buffer_.get()->data(), orig.io_buffer()->data(), io_buffer_.get()->size()); header_ = reinterpret_cast(io_buffer_->data()); - header_->id = base::HostToNet16(id); } bool DnsQuery::ReadHeader(base::BigEndianReader* reader, diff --git a/chromium/net/dns/dns_query.h b/chromium/net/dns/dns_query.h index 6ca6a1e93f0..ce3b71e2f74 100644 --- a/chromium/net/dns/dns_query.h +++ b/chromium/net/dns/dns_query.h @@ -59,6 +59,10 @@ class NET_EXPORT_PRIVATE DnsQuery { // populate the empty query. explicit DnsQuery(scoped_refptr buffer); + // Copies are constructed with an independent cloned, not mirrored, buffer. + DnsQuery(const DnsQuery& query); + DnsQuery& operator=(const DnsQuery& query); + ~DnsQuery(); // Clones |this| verbatim, with ID field of the header set to |id|. @@ -95,6 +99,7 @@ class NET_EXPORT_PRIVATE DnsQuery { private: DnsQuery(const DnsQuery& orig, uint16_t id); + void CopyFrom(const DnsQuery& orig); bool ReadHeader(base::BigEndianReader* reader, dns_protocol::Header* out); // After read, |out| is in the DNS format, e.g. @@ -111,8 +116,6 @@ class NET_EXPORT_PRIVATE DnsQuery { // Pointer to the dns header section. dns_protocol::Header* header_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(DnsQuery); }; } // namespace net diff --git a/chromium/net/dns/dns_query_unittest.cc b/chromium/net/dns/dns_query_unittest.cc index 3e5990887c0..dd9cd806a40 100644 --- a/chromium/net/dns/dns_query_unittest.cc +++ b/chromium/net/dns/dns_query_unittest.cc @@ -70,6 +70,17 @@ TEST(DnsQueryTest, Constructor) { EXPECT_EQ(question, q1.question()); } +TEST(DnsQueryTest, CopiesAreIndependent) { + DnsQuery q1(26 /* id */, kQName, dns_protocol::kTypeAAAA); + + DnsQuery q2(q1); + + EXPECT_EQ(q1.id(), q2.id()); + EXPECT_EQ(base::StringPiece(q1.io_buffer()->data(), q1.io_buffer()->size()), + base::StringPiece(q2.io_buffer()->data(), q2.io_buffer()->size())); + EXPECT_NE(q1.io_buffer(), q2.io_buffer()); +} + TEST(DnsQueryTest, Clone) { base::StringPiece qname(kQNameData, sizeof(kQNameData)); diff --git a/chromium/net/dns/dns_reloader.cc b/chromium/net/dns/dns_reloader.cc index 0c0d0d84325..0672e711afb 100644 --- a/chromium/net/dns/dns_reloader.cc +++ b/chromium/net/dns/dns_reloader.cc @@ -4,16 +4,16 @@ #include "net/dns/dns_reloader.h" -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \ +#if defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_OPENBSD) && \ !defined(OS_ANDROID) && !defined(OS_FUCHSIA) #include #include "base/lazy_instance.h" #include "base/macros.h" -#include "base/message_loop/message_loop_current.h" #include "base/notreached.h" #include "base/synchronization/lock.h" +#include "base/task/current_thread.h" #include "base/threading/thread_local.h" #include "net/base/network_change_notifier.h" @@ -111,5 +111,5 @@ void DnsReloaderMaybeReload() { } // namespace net -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && +#endif // defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_OPENBSD) && // !defined(OS_ANDROID) diff --git a/chromium/net/dns/dns_reloader.h b/chromium/net/dns/dns_reloader.h index 4317d9eaf63..cbc910e40e9 100644 --- a/chromium/net/dns/dns_reloader.h +++ b/chromium/net/dns/dns_reloader.h @@ -7,7 +7,7 @@ #include "build/build_config.h" -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) +#if defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_OPENBSD) namespace net { // Call on the network thread before calling DnsReloaderMaybeReload() anywhere. @@ -18,6 +18,6 @@ void EnsureDnsReloaderInit(); void DnsReloaderMaybeReload(); } // namespace net -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) +#endif // defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_OPENBSD) #endif // NET_DNS_DNS_RELOADER_H_ diff --git a/chromium/net/dns/dns_session.cc b/chromium/net/dns/dns_session.cc index c74c4bafae2..d6fed319f58 100644 --- a/chromium/net/dns/dns_session.cc +++ b/chromium/net/dns/dns_session.cc @@ -10,45 +10,25 @@ #include #include "base/bind.h" -#include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" #include "base/stl_util.h" -#include "net/base/ip_endpoint.h" -#include "net/base/net_errors.h" #include "net/dns/dns_config.h" -#include "net/dns/dns_socket_pool.h" -#include "net/log/net_log_event_type.h" -#include "net/log/net_log_source.h" -#include "net/log/net_log_with_source.h" -#include "net/socket/datagram_client_socket.h" -#include "net/socket/stream_socket.h" +#include "net/dns/dns_socket_allocator.h" +#include "net/log/net_log.h" namespace net { -DnsSession::SocketLease::SocketLease( - scoped_refptr session, - size_t server_index, - std::unique_ptr socket) - : session_(session), - server_index_(server_index), - socket_(std::move(socket)) {} - -DnsSession::SocketLease::~SocketLease() { - session_->FreeSocket(server_index_, std::move(socket_)); -} - DnsSession::DnsSession(const DnsConfig& config, - std::unique_ptr socket_pool, + std::unique_ptr socket_allocator, const RandIntCallback& rand_int_callback, NetLog* net_log) : config_(config), - socket_pool_(std::move(socket_pool)), + socket_allocator_(std::move(socket_allocator)), rand_callback_(base::BindRepeating(rand_int_callback, 0, std::numeric_limits::max())), net_log_(net_log) { - socket_pool_->Initialize(&config_.nameservers, net_log); UMA_HISTOGRAM_CUSTOM_COUNTS("AsyncDNS.ServerCount", config_.nameservers.size(), 1, 10, 11); } @@ -59,41 +39,8 @@ uint16_t DnsSession::NextQueryId() const { return static_cast(rand_callback_.Run()); } -// Allocate a socket, already connected to the server address. -std::unique_ptr DnsSession::AllocateSocket( - size_t server_index, - const NetLogSource& source) { - std::unique_ptr socket; - - socket = socket_pool_->AllocateSocket(server_index); - if (!socket.get()) - return std::unique_ptr(); - - socket->NetLog().BeginEventReferencingSource(NetLogEventType::SOCKET_IN_USE, - source); - - SocketLease* lease = new SocketLease(this, server_index, std::move(socket)); - return std::unique_ptr(lease); -} - -std::unique_ptr DnsSession::CreateTCPSocket( - size_t server_index, - const NetLogSource& source) { - return socket_pool_->CreateTCPSocket(server_index, source); -} - void DnsSession::InvalidateWeakPtrsForTesting() { weak_ptr_factory_.InvalidateWeakPtrs(); } -// Release a socket. -void DnsSession::FreeSocket(size_t server_index, - std::unique_ptr socket) { - DCHECK(socket.get()); - - socket->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE); - - socket_pool_->FreeSocket(server_index, std::move(socket)); -} - } // namespace net diff --git a/chromium/net/dns/dns_session.h b/chromium/net/dns/dns_session.h index d9830c28949..606d9877d8a 100644 --- a/chromium/net/dns/dns_session.h +++ b/chromium/net/dns/dns_session.h @@ -15,15 +15,12 @@ #include "net/base/net_export.h" #include "net/base/rand_callback.h" #include "net/dns/dns_config.h" -#include "net/dns/dns_socket_pool.h" #include "net/dns/dns_udp_tracker.h" namespace net { -class DatagramClientSocket; +class DnsSocketAllocator; class NetLog; -struct NetLogSource; -class StreamSocket; // Session parameters and state shared between DnsTransactions for a specific // instance/version of a DnsConfig. Also may be used as a key handle for @@ -38,47 +35,19 @@ class NET_EXPORT_PRIVATE DnsSession : public base::RefCounted { public: typedef base::RepeatingCallback RandCallback; - class NET_EXPORT_PRIVATE SocketLease { - public: - SocketLease(scoped_refptr session, - size_t server_index, - std::unique_ptr socket); - ~SocketLease(); - - size_t server_index() const { return server_index_; } - - DatagramClientSocket* socket() { return socket_.get(); } - - private: - scoped_refptr session_; - size_t server_index_; - std::unique_ptr socket_; - - DISALLOW_COPY_AND_ASSIGN(SocketLease); - }; - DnsSession(const DnsConfig& config, - std::unique_ptr socket_pool, + std::unique_ptr socket_allocator, const RandIntCallback& rand_int_callback, NetLog* net_log); const DnsConfig& config() const { return config_; } + DnsSocketAllocator* socket_allocator() { return socket_allocator_.get(); } DnsUdpTracker* udp_tracker() { return &udp_tracker_; } NetLog* net_log() const { return net_log_; } // Return the next random query ID. uint16_t NextQueryId() const; - // Allocate a socket, already connected to the server address. - // When the SocketLease is destroyed, the socket will be freed. - std::unique_ptr AllocateSocket(size_t server_index, - const NetLogSource& source); - - // Creates a StreamSocket from the factory for a transaction over TCP. These - // sockets are not pooled. - std::unique_ptr CreateTCPSocket(size_t server_index, - const NetLogSource& source); - base::WeakPtr GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } @@ -94,12 +63,8 @@ class NET_EXPORT_PRIVATE DnsSession : public base::RefCounted { ~DnsSession(); - // Release a socket. - void FreeSocket(size_t server_index, - std::unique_ptr socket); - const DnsConfig config_; - std::unique_ptr socket_pool_; + std::unique_ptr socket_allocator_; DnsUdpTracker udp_tracker_; RandCallback rand_callback_; NetLog* net_log_; diff --git a/chromium/net/dns/dns_session_unittest.cc b/chromium/net/dns/dns_session_unittest.cc deleted file mode 100644 index 60abd6f83b5..00000000000 --- a/chromium/net/dns/dns_session_unittest.cc +++ /dev/null @@ -1,243 +0,0 @@ -// 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/dns_session.h" - -#include -#include -#include -#include -#include - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "base/rand_util.h" -#include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "net/base/ip_address.h" -#include "net/base/mock_network_change_notifier.h" -#include "net/base/net_errors.h" -#include "net/dns/dns_socket_pool.h" -#include "net/dns/public/dns_protocol.h" -#include "net/dns/resolve_context.h" -#include "net/log/net_log_source.h" -#include "net/socket/socket_performance_watcher.h" -#include "net/socket/socket_test_util.h" -#include "net/socket/ssl_client_socket.h" -#include "net/socket/stream_socket.h" -#include "net/test/test_with_task_environment.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -namespace { - -class TestClientSocketFactory : public ClientSocketFactory { - public: - ~TestClientSocketFactory() override; - - std::unique_ptr CreateDatagramClientSocket( - DatagramSocket::BindType bind_type, - NetLog* net_log, - const NetLogSource& source) override; - - std::unique_ptr CreateTransportClientSocket( - const AddressList& addresses, - std::unique_ptr, - NetLog*, - const NetLogSource&) override { - NOTIMPLEMENTED(); - return nullptr; - } - - std::unique_ptr CreateSSLClientSocket( - SSLClientContext* context, - std::unique_ptr stream_socket, - const HostPortPair& host_and_port, - const SSLConfig& ssl_config) override { - NOTIMPLEMENTED(); - return nullptr; - } - - std::unique_ptr CreateProxyClientSocket( - std::unique_ptr stream_socket, - const std::string& user_agent, - const HostPortPair& endpoint, - const ProxyServer& proxy_server, - HttpAuthController* http_auth_controller, - bool tunnel, - bool using_spdy, - NextProto negotiated_protocol, - ProxyDelegate* proxy_delegate, - const NetworkTrafficAnnotationTag& traffic_annotation) override { - NOTIMPLEMENTED(); - return nullptr; - } - - private: - std::list> data_providers_; -}; - -struct PoolEvent { - enum { ALLOCATE, FREE } action; - size_t server_index; -}; - -class DnsSessionTest : public TestWithTaskEnvironment { - public: - void OnSocketAllocated(size_t server_index); - void OnSocketFreed(size_t server_index); - - protected: - void Initialize(size_t num_servers); - std::unique_ptr Allocate(size_t server_index); - bool DidAllocate(size_t server_index); - bool DidFree(size_t server_index); - bool NoMoreEvents(); - - DnsConfig config_; - std::unique_ptr test_client_socket_factory_; - scoped_refptr session_; - NetLogSource source_; - - private: - bool ExpectEvent(const PoolEvent& event); - std::list events_; -}; - -class MockDnsSocketPool : public DnsSocketPool { - public: - MockDnsSocketPool(ClientSocketFactory* factory, DnsSessionTest* test) - : DnsSocketPool(factory, base::Bind(&base::RandInt)), test_(test) {} - - ~MockDnsSocketPool() override = default; - - void Initialize(const std::vector* nameservers, - NetLog* net_log) override { - InitializeInternal(nameservers, net_log); - } - - std::unique_ptr AllocateSocket( - size_t server_index) override { - test_->OnSocketAllocated(server_index); - return CreateConnectedSocket(server_index); - } - - void FreeSocket(size_t server_index, - std::unique_ptr socket) override { - test_->OnSocketFreed(server_index); - } - - private: - DnsSessionTest* test_; -}; - -void DnsSessionTest::Initialize(size_t num_servers) { - CHECK_LT(num_servers, 256u); - config_.nameservers.clear(); - config_.dns_over_https_servers.clear(); - for (unsigned char i = 0; i < num_servers; ++i) { - IPEndPoint dns_endpoint(IPAddress(192, 168, 1, i), - dns_protocol::kDefaultPort); - config_.nameservers.push_back(dns_endpoint); - } - - test_client_socket_factory_.reset(new TestClientSocketFactory()); - - DnsSocketPool* dns_socket_pool = - new MockDnsSocketPool(test_client_socket_factory_.get(), this); - - session_ = - new DnsSession(config_, std::unique_ptr(dns_socket_pool), - base::Bind(&base::RandInt), nullptr /* NetLog */); - - events_.clear(); -} - -std::unique_ptr DnsSessionTest::Allocate( - size_t server_index) { - return session_->AllocateSocket(server_index, source_); -} - -bool DnsSessionTest::DidAllocate(size_t server_index) { - PoolEvent expected_event = { PoolEvent::ALLOCATE, server_index }; - return ExpectEvent(expected_event); -} - -bool DnsSessionTest::DidFree(size_t server_index) { - PoolEvent expected_event = { PoolEvent::FREE, server_index }; - return ExpectEvent(expected_event); -} - -bool DnsSessionTest::NoMoreEvents() { - return events_.empty(); -} - -void DnsSessionTest::OnSocketAllocated(size_t server_index) { - PoolEvent event = { PoolEvent::ALLOCATE, server_index }; - events_.push_back(event); -} - -void DnsSessionTest::OnSocketFreed(size_t server_index) { - PoolEvent event = { PoolEvent::FREE, server_index }; - events_.push_back(event); -} - -bool DnsSessionTest::ExpectEvent(const PoolEvent& expected) { - if (events_.empty()) { - return false; - } - - const PoolEvent actual = events_.front(); - if ((expected.action != actual.action) - || (expected.server_index != actual.server_index)) { - return false; - } - events_.pop_front(); - - return true; -} - -std::unique_ptr -TestClientSocketFactory::CreateDatagramClientSocket( - DatagramSocket::BindType bind_type, - NetLog* net_log, - const NetLogSource& source) { - // We're not actually expecting to send or receive any data, so use the - // simplest SocketDataProvider with no data supplied. - SocketDataProvider* data_provider = new StaticSocketDataProvider(); - data_providers_.push_back(base::WrapUnique(data_provider)); - std::unique_ptr socket( - new MockUDPClientSocket(data_provider, net_log)); - return std::move(socket); -} - -TestClientSocketFactory::~TestClientSocketFactory() = default; - -TEST_F(DnsSessionTest, AllocateFree) { - std::unique_ptr lease1, lease2; - - Initialize(2 /* num_servers */); - EXPECT_TRUE(NoMoreEvents()); - - lease1 = Allocate(0); - EXPECT_TRUE(DidAllocate(0)); - EXPECT_TRUE(NoMoreEvents()); - - lease2 = Allocate(1); - EXPECT_TRUE(DidAllocate(1)); - EXPECT_TRUE(NoMoreEvents()); - - lease1.reset(); - EXPECT_TRUE(DidFree(0)); - EXPECT_TRUE(NoMoreEvents()); - - lease2.reset(); - EXPECT_TRUE(DidFree(1)); - EXPECT_TRUE(NoMoreEvents()); -} - -} // namespace - -} // namespace net diff --git a/chromium/net/dns/dns_socket_allocator.cc b/chromium/net/dns/dns_socket_allocator.cc new file mode 100644 index 00000000000..0c1c9245577 --- /dev/null +++ b/chromium/net/dns/dns_socket_allocator.cc @@ -0,0 +1,75 @@ +// 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/dns_socket_allocator.h" + +#include "base/logging.h" +#include "base/rand_util.h" +#include "build/build_config.h" +#include "net/base/address_list.h" +#include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" +#include "net/log/net_log_source.h" +#include "net/socket/client_socket_factory.h" +#include "net/socket/datagram_client_socket.h" +#include "net/socket/stream_socket.h" + +namespace net { + +namespace { + +// On Windows, can't request specific (random) ports, since that will trigger +// firewall prompts, so request default ones (but experimentally, the OS appears +// to still allocate random ports). +#if defined(OS_WIN) +const DatagramSocket::BindType kBindType = DatagramSocket::DEFAULT_BIND; +#else +const DatagramSocket::BindType kBindType = DatagramSocket::RANDOM_BIND; +#endif + +} // namespace + +DnsSocketAllocator::DnsSocketAllocator(ClientSocketFactory* socket_factory, + std::vector nameservers, + NetLog* net_log) + : socket_factory_(socket_factory), + net_log_(net_log), + nameservers_(std::move(nameservers)) { + DCHECK(socket_factory_); +} + +DnsSocketAllocator::~DnsSocketAllocator() = default; + +std::unique_ptr +DnsSocketAllocator::CreateConnectedUdpSocket(size_t server_index, + int* out_connection_error) { + DCHECK_LT(server_index, nameservers_.size()); + DCHECK(out_connection_error); + + std::unique_ptr socket; + + NetLogSource no_source; + socket = socket_factory_->CreateDatagramClientSocket(kBindType, net_log_, + no_source); + DCHECK(socket); + + *out_connection_error = socket->Connect(nameservers_[server_index]); + if (*out_connection_error != OK) { + DVLOG(1) << "Failed to connect socket: " << *out_connection_error; + socket.reset(); + } + + return socket; +} + +std::unique_ptr DnsSocketAllocator::CreateTcpSocket( + size_t server_index, + const NetLogSource& source) { + DCHECK_LT(server_index, nameservers_.size()); + + return socket_factory_->CreateTransportClientSocket( + AddressList(nameservers_[server_index]), nullptr, net_log_, source); +} + +} // namespace net diff --git a/chromium/net/dns/dns_socket_allocator.h b/chromium/net/dns/dns_socket_allocator.h new file mode 100644 index 00000000000..9b8f986ef5e --- /dev/null +++ b/chromium/net/dns/dns_socket_allocator.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef NET_DNS_DNS_SOCKET_ALLOCATOR_H_ +#define NET_DNS_DNS_SOCKET_ALLOCATOR_H_ + +#include +#include + +#include "net/base/net_export.h" +#include "net/base/rand_callback.h" + +namespace net { + +class ClientSocketFactory; +class DatagramClientSocket; +class IPEndPoint; +class NetLog; +struct NetLogSource; +class StreamSocket; + +// Allocation logic for DNS UDP and TCP sockets. +class NET_EXPORT_PRIVATE DnsSocketAllocator { + public: + DnsSocketAllocator(ClientSocketFactory* factory, + std::vector nameservers, + NetLog* net_log); + ~DnsSocketAllocator(); + + DnsSocketAllocator(const DnsSocketAllocator&) = delete; + DnsSocketAllocator& operator=(const DnsSocketAllocator&) = delete; + + // Creates a UDP client socket that is already connected to the nameserver + // referenced by |server_index| and sets |out_connection_error| to the result + // of the connection. On error connecting the socket, returns null. + std::unique_ptr CreateConnectedUdpSocket( + size_t server_index, + int* out_connection_error); + + // Creates a StreamSocket for TCP to the nameserver referenced by + // |server_index|. Does not connect the seocket. + std::unique_ptr CreateTcpSocket(size_t server_index, + const NetLogSource& source); + + private: + ClientSocketFactory* const socket_factory_; + NetLog* const net_log_; + const std::vector nameservers_; +}; + +} // namespace net + +#endif // NET_DNS_DNS_SOCKET_ALLOCATOR_H_ diff --git a/chromium/net/dns/dns_socket_allocator_unittest.cc b/chromium/net/dns/dns_socket_allocator_unittest.cc new file mode 100644 index 00000000000..2b28ff32fee --- /dev/null +++ b/chromium/net/dns/dns_socket_allocator_unittest.cc @@ -0,0 +1,82 @@ +// Copyright 2017 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/dns_socket_allocator.h" + +#include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" +#include "net/log/net_log_source.h" +#include "net/socket/client_socket_factory.h" +#include "net/socket/datagram_client_socket.h" +#include "net/socket/socket_test_util.h" +#include "net/test/gtest_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace { + +const IPEndPoint kEndpoint0(IPAddress(1, 2, 3, 4), 578); +const IPEndPoint kEndpoint1(IPAddress(2, 3, 4, 5), 678); + +class DnsSocketAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + allocator_ = std::make_unique( + &socket_factory_, nameservers_, nullptr /* net_log */); + } + + MockClientSocketFactory socket_factory_; + std::vector nameservers_ = {kEndpoint0, kEndpoint1}; + std::unique_ptr allocator_; +}; + +TEST_F(DnsSocketAllocatorTest, CreateConnectedUdpSocket) { + // Prep socket factory for a single do-nothing socket. + StaticSocketDataProvider data_provider; + socket_factory_.AddSocketDataProvider(&data_provider); + + int connection_error = ERR_FAILED; + std::unique_ptr socket = + allocator_->CreateConnectedUdpSocket(1 /* server_index */, + &connection_error); + + ASSERT_TRUE(socket); + EXPECT_THAT(connection_error, test::IsOk()); + + IPEndPoint peer_address; + ASSERT_THAT(socket->GetPeerAddress(&peer_address), test::IsOk()); + EXPECT_EQ(peer_address, kEndpoint1); +} + +TEST_F(DnsSocketAllocatorTest, CreateConnectedUdpSocket_ConnectError) { + // Prep socket factory for a single socket with connection failure. + MockConnect connect_data; + connect_data.result = ERR_INSUFFICIENT_RESOURCES; + StaticSocketDataProvider data_provider; + data_provider.set_connect_data(connect_data); + socket_factory_.AddSocketDataProvider(&data_provider); + + int connection_error = OK; + std::unique_ptr socket = + allocator_->CreateConnectedUdpSocket(0 /* server_index */, + &connection_error); + + EXPECT_FALSE(socket); + EXPECT_THAT(connection_error, test::IsError(ERR_INSUFFICIENT_RESOURCES)); +} + +TEST_F(DnsSocketAllocatorTest, CreateTcpSocket) { + // Prep socket factory for a single do-nothing socket. + StaticSocketDataProvider data_provider; + socket_factory_.AddSocketDataProvider(&data_provider); + + std::unique_ptr socket = + allocator_->CreateTcpSocket(1 /* server_index */, NetLogSource()); + + EXPECT_TRUE(socket); +} + +} // namespace +} // namespace net diff --git a/chromium/net/dns/dns_socket_pool.cc b/chromium/net/dns/dns_socket_pool.cc deleted file mode 100644 index 177c79914b6..00000000000 --- a/chromium/net/dns/dns_socket_pool.cc +++ /dev/null @@ -1,223 +0,0 @@ -// 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/dns_socket_pool.h" - -#include "base/logging.h" -#include "base/macros.h" -#include "base/rand_util.h" -#include "net/base/address_list.h" -#include "net/base/ip_endpoint.h" -#include "net/base/net_errors.h" -#include "net/log/net_log_source.h" -#include "net/socket/client_socket_factory.h" -#include "net/socket/datagram_client_socket.h" -#include "net/socket/stream_socket.h" - -namespace net { - -namespace { - -// When we initialize the SocketPool, we allocate kInitialPoolSize sockets. -// When we allocate a socket, we ensure we have at least kAllocateMinSize -// sockets to choose from. Freed sockets are not retained. - -// On Windows, we can't request specific (random) ports, since that will -// trigger firewall prompts, so request default ones, but keep a pile of -// them. Everywhere else, request fresh, random ports each time. -#if defined(OS_WIN) -const DatagramSocket::BindType kBindType = DatagramSocket::DEFAULT_BIND; -const size_t kInitialPoolSize = 256; -const size_t kAllocateMinSize = 256; -#else -const DatagramSocket::BindType kBindType = DatagramSocket::RANDOM_BIND; -const size_t kInitialPoolSize = 0; -const size_t kAllocateMinSize = 1; -#endif - -} // namespace - -DnsSocketPool::DnsSocketPool(ClientSocketFactory* socket_factory, - const RandIntCallback& rand_int_callback) - : socket_factory_(socket_factory), - rand_int_callback_(rand_int_callback), - net_log_(nullptr), - nameservers_(nullptr), - initialized_(false) {} - -void DnsSocketPool::InitializeInternal( - const std::vector* nameservers, - NetLog* net_log) { - DCHECK(nameservers); - DCHECK(!initialized_); - - net_log_ = net_log; - nameservers_ = nameservers; - initialized_ = true; -} - -std::unique_ptr DnsSocketPool::CreateTCPSocket( - size_t server_index, - const NetLogSource& source) { - DCHECK_LT(server_index, nameservers_->size()); - - return std::unique_ptr( - socket_factory_->CreateTransportClientSocket( - AddressList((*nameservers_)[server_index]), nullptr, net_log_, - source)); -} - -std::unique_ptr DnsSocketPool::CreateConnectedSocket( - size_t server_index) { - DCHECK_LT(server_index, nameservers_->size()); - - std::unique_ptr socket; - - NetLogSource no_source; - socket = socket_factory_->CreateDatagramClientSocket(kBindType, net_log_, - no_source); - - if (socket.get()) { - int rv = socket->Connect((*nameservers_)[server_index]); - if (rv != OK) { - DVLOG(1) << "Failed to connect socket: " << rv; - socket.reset(); - } - } else { - DVLOG(1) << "Failed to create socket."; - } - - return socket; -} - -int DnsSocketPool::GetRandomInt(int min, int max) { - return rand_int_callback_.Run(min, max); -} - -class NullDnsSocketPool : public DnsSocketPool { - public: - NullDnsSocketPool(ClientSocketFactory* factory, - const RandIntCallback& rand_int_callback) - : DnsSocketPool(factory, rand_int_callback) {} - - void Initialize(const std::vector* nameservers, - NetLog* net_log) override { - InitializeInternal(nameservers, net_log); - } - - std::unique_ptr AllocateSocket( - size_t server_index) override { - return CreateConnectedSocket(server_index); - } - - void FreeSocket(size_t server_index, - std::unique_ptr socket) override {} - - private: - DISALLOW_COPY_AND_ASSIGN(NullDnsSocketPool); -}; - -// static -std::unique_ptr DnsSocketPool::CreateNull( - ClientSocketFactory* factory, - const RandIntCallback& rand_int_callback) { - return std::unique_ptr( - new NullDnsSocketPool(factory, rand_int_callback)); -} - -class DefaultDnsSocketPool : public DnsSocketPool { - public: - DefaultDnsSocketPool(ClientSocketFactory* factory, - const RandIntCallback& rand_int_callback) - : DnsSocketPool(factory, rand_int_callback) {} - - ~DefaultDnsSocketPool() override; - - void Initialize(const std::vector* nameservers, - NetLog* net_log) override; - - std::unique_ptr AllocateSocket( - size_t server_index) override; - - void FreeSocket(size_t server_index, - std::unique_ptr socket) override; - - private: - void FillPool(size_t server_index, size_t size); - - typedef std::vector> SocketVector; - - std::vector pools_; - - DISALLOW_COPY_AND_ASSIGN(DefaultDnsSocketPool); -}; - -DnsSocketPool::~DnsSocketPool() = default; - -// static -std::unique_ptr DnsSocketPool::CreateDefault( - ClientSocketFactory* factory, - const RandIntCallback& rand_int_callback) { - return std::unique_ptr( - new DefaultDnsSocketPool(factory, rand_int_callback)); -} - -void DefaultDnsSocketPool::Initialize( - const std::vector* nameservers, - NetLog* net_log) { - InitializeInternal(nameservers, net_log); - - DCHECK(pools_.empty()); - const size_t num_servers = nameservers->size(); - pools_.resize(num_servers); - for (size_t server_index = 0; server_index < num_servers; ++server_index) - FillPool(server_index, kInitialPoolSize); -} - -DefaultDnsSocketPool::~DefaultDnsSocketPool() = default; - -std::unique_ptr DefaultDnsSocketPool::AllocateSocket( - size_t server_index) { - DCHECK_LT(server_index, pools_.size()); - SocketVector& pool = pools_[server_index]; - - FillPool(server_index, kAllocateMinSize); - if (pool.size() == 0) { - DVLOG(1) << "No DNS sockets available in pool " << server_index << "!"; - return std::unique_ptr(); - } - - if (pool.size() < kAllocateMinSize) { - DVLOG(1) << "Low DNS port entropy: wanted " << kAllocateMinSize - << " sockets to choose from, but only have " << pool.size() - << " in pool " << server_index << "."; - } - - size_t socket_index = GetRandomInt(0, pool.size() - 1); - std::unique_ptr socket = std::move(pool[socket_index]); - pool[socket_index] = std::move(pool.back()); - pool.pop_back(); - - return socket; -} - -void DefaultDnsSocketPool::FreeSocket( - size_t server_index, - std::unique_ptr socket) { - DCHECK_LT(server_index, pools_.size()); -} - -void DefaultDnsSocketPool::FillPool(size_t server_index, size_t size) { - SocketVector& pool = pools_[server_index]; - - for (size_t pool_index = pool.size(); pool_index < size; ++pool_index) { - std::unique_ptr socket = - CreateConnectedSocket(server_index); - if (!socket) - break; - pool.push_back(std::move(socket)); - } -} - -} // namespace net diff --git a/chromium/net/dns/dns_socket_pool.h b/chromium/net/dns/dns_socket_pool.h deleted file mode 100644 index 054787a48b8..00000000000 --- a/chromium/net/dns/dns_socket_pool.h +++ /dev/null @@ -1,98 +0,0 @@ -// 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. - -#ifndef NET_DNS_DNS_SOCKET_POOL_H_ -#define NET_DNS_DNS_SOCKET_POOL_H_ - -#include -#include - -#include "base/macros.h" -#include "net/base/net_export.h" -#include "net/base/rand_callback.h" - -namespace net { - -class ClientSocketFactory; -class DatagramClientSocket; -class IPEndPoint; -class NetLog; -struct NetLogSource; -class StreamSocket; - -// A DnsSocketPool is an abstraction layer around a ClientSocketFactory that -// allows preallocation, reuse, or other strategies to manage sockets connected -// to DNS servers. -class NET_EXPORT_PRIVATE DnsSocketPool { - public: - virtual ~DnsSocketPool(); - - // Creates a DnsSocketPool that implements the default strategy for managing - // sockets. (This varies by platform; see DnsSocketPoolImpl in - // dns_socket_pool.cc for details.) - static std::unique_ptr CreateDefault( - ClientSocketFactory* factory, - const RandIntCallback& rand_int_callback); - - // Creates a DnsSocketPool that implements a "null" strategy -- no sockets are - // preallocated, allocation requests are satisfied by calling the factory - // directly, and returned sockets are deleted immediately. - static std::unique_ptr CreateNull( - ClientSocketFactory* factory, - const RandIntCallback& rand_int_callback); - - // Initializes the DnsSocketPool. |nameservers| is the list of nameservers - // for which the DnsSocketPool will manage sockets; |net_log| is the NetLog - // used when constructing sockets with the factory. - // - // Initialize may not be called more than once, and must be called before - // calling AllocateSocket or FreeSocket. - virtual void Initialize( - const std::vector* nameservers, - NetLog* net_log) = 0; - - // Allocates a socket that is already connected to the nameserver referenced - // by |server_index|. May return a std::unique_ptr to NULL if no sockets are - // available to reuse and the factory fails to produce a socket (or produces - // one on which Connect fails). - virtual std::unique_ptr AllocateSocket( - size_t server_index) = 0; - - // Frees a socket allocated by AllocateSocket. |server_index| must be the - // same index passed to AllocateSocket. - virtual void FreeSocket(size_t server_index, - std::unique_ptr socket) = 0; - - // Creates a StreamSocket from the factory for a transaction over TCP. These - // sockets are not pooled. - std::unique_ptr CreateTCPSocket(size_t server_index, - const NetLogSource& source); - - protected: - DnsSocketPool(ClientSocketFactory* socket_factory, - const RandIntCallback& rand_int_callback); - - void InitializeInternal( - const std::vector* nameservers, - NetLog* net_log); - - std::unique_ptr CreateConnectedSocket( - size_t server_index); - - // Returns a random int in the specified range. - int GetRandomInt(int min, int max); - - private: - ClientSocketFactory* socket_factory_; - const RandIntCallback rand_int_callback_; - NetLog* net_log_; - const std::vector* nameservers_; - bool initialized_; - - DISALLOW_COPY_AND_ASSIGN(DnsSocketPool); -}; - -} // namespace net - -#endif // NET_DNS_DNS_SOCKET_POOL_H_ diff --git a/chromium/net/dns/dns_socket_pool_unittest.cc b/chromium/net/dns/dns_socket_pool_unittest.cc deleted file mode 100644 index 2138518e5a1..00000000000 --- a/chromium/net/dns/dns_socket_pool_unittest.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2017 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/dns_socket_pool.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "net/base/rand_callback.h" -#include "net/socket/client_socket_factory.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace { - -class DummyObject { - public: - DummyObject() {} - - base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } - - bool HasWeakPtrs() const { return weak_factory_.HasWeakPtrs(); } - - private: - base::WeakPtrFactory weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(DummyObject); -}; - -class DummyRandIntCallback { - public: - DummyRandIntCallback() = default; - - RandIntCallback MakeCallback() { - return base::Bind(&DummyRandIntCallback::GetRandInt, dummy_.GetWeakPtr()); - } - - bool HasRefs() const { return dummy_.HasWeakPtrs(); } - - private: - static int GetRandInt(base::WeakPtr dummy, int from, int to) { - // Chosen by fair dice roll. Guaranteed to be random. - return 4; - } - - DummyObject dummy_; - - DISALLOW_COPY_AND_ASSIGN(DummyRandIntCallback); -}; - -// Since the below tests rely upon it, make sure that DummyRandIntCallback -// can reliably tell whether there are other refs to the callback it returns. - -// A const reference to the callback shouldn't keep the callback referenced. -TEST(DummyRandIntCallbackTest, Referenced) { - DummyRandIntCallback dummy; - - RandIntCallback original = dummy.MakeCallback(); - EXPECT_TRUE(dummy.HasRefs()); - const RandIntCallback& reference = original; - EXPECT_TRUE(dummy.HasRefs()); - - EXPECT_EQ(4, reference.Run(0, 6)); - - original.Reset(); - EXPECT_FALSE(dummy.HasRefs()); -} - -// A copy of the callback should keep the callback referenced. -TEST(DummyRandIntCallbackTest, Copied) { - DummyRandIntCallback dummy; - - RandIntCallback original = dummy.MakeCallback(); - EXPECT_TRUE(dummy.HasRefs()); - RandIntCallback copy = original; - EXPECT_TRUE(dummy.HasRefs()); - - EXPECT_EQ(4, copy.Run(0, 6)); - - original.Reset(); - EXPECT_TRUE(dummy.HasRefs()); -} - -class DnsSocketPoolTest : public ::testing::Test { - protected: - DummyRandIntCallback dummy_; - std::unique_ptr pool_; -}; - -// Make sure that the DnsSocketPools returned by CreateDefault and CreateNull -// both retain (by copying the RandIntCallback object, instead of taking a -// reference) the RandIntCallback used for creating sockets. - -TEST_F(DnsSocketPoolTest, DefaultCopiesCallback) { - pool_ = DnsSocketPool::CreateDefault(ClientSocketFactory::GetDefaultFactory(), - dummy_.MakeCallback()); - EXPECT_TRUE(dummy_.HasRefs()); -} - -TEST_F(DnsSocketPoolTest, NullCopiesCallback) { - pool_ = DnsSocketPool::CreateNull(ClientSocketFactory::GetDefaultFactory(), - dummy_.MakeCallback()); - EXPECT_TRUE(dummy_.HasRefs()); -} - -} // namespace -} // namespace net diff --git a/chromium/net/dns/dns_test_util.cc b/chromium/net/dns/dns_test_util.cc index efcec21579d..0ced88c66c3 100644 --- a/chromium/net/dns/dns_test_util.cc +++ b/chromium/net/dns/dns_test_util.cc @@ -18,6 +18,7 @@ #include "net/dns/dns_hosts.h" #include "net/dns/dns_query.h" #include "net/dns/dns_session.h" +#include "net/dns/dns_socket_allocator.h" #include "net/dns/dns_util.h" #include "net/dns/resolve_context.h" #include "testing/gtest/include/gtest/gtest.h" @@ -725,10 +726,13 @@ scoped_refptr MockDnsClient::BuildSession() { auto null_random_callback = base::BindRepeating([](int, int) -> int { IMMEDIATE_CRASH(); }); + auto socket_allocator = std::make_unique( + &socket_factory_, effective_config_.value().nameservers, + nullptr /* net_log */); + return base::MakeRefCounted( - effective_config_.value(), - DnsSocketPool::CreateNull(&socket_factory_, null_random_callback), - null_random_callback, nullptr /* NetLog */); + effective_config_.value(), std::move(socket_allocator), + null_random_callback, nullptr /* net_log */); } } // namespace net diff --git a/chromium/net/dns/dns_test_util.h b/chromium/net/dns/dns_test_util.h index 40c619976a0..3944541e7dc 100644 --- a/chromium/net/dns/dns_test_util.h +++ b/chromium/net/dns/dns_test_util.h @@ -164,7 +164,7 @@ static const int kT3TTL = 0x00000015; static const unsigned kT3RecordCount = base::size(kT3IpAddresses) + 3; //----------------------------------------------------------------------------- -// Query/response set for www.gstatic.com, ID is fixed to 4. +// Query/response set for www.gstatic.com, ID is fixed to 0. static const char kT4HostName[] = "www.gstatic.com"; static const uint16_t kT4Qtype = dns_protocol::kTypeA; static const char kT4DnsName[] = {0x03, 'w', 'w', 'w', 0x07, 'g', @@ -173,7 +173,7 @@ static const char kT4DnsName[] = {0x03, 'w', 'w', 'w', 0x07, 'g', static const size_t kT4QuerySize = 33; static const uint8_t kT4ResponseDatagram[] = { // response contains the following IP addresses: 172.217.6.195. - 0x00, 0x04, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x07, 0x67, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, diff --git a/chromium/net/dns/dns_transaction.cc b/chromium/net/dns/dns_transaction.cc index 60e97bf23f3..e1443c48bd2 100644 --- a/chromium/net/dns/dns_transaction.cc +++ b/chromium/net/dns/dns_transaction.cc @@ -48,6 +48,7 @@ #include "net/dns/dns_response.h" #include "net/dns/dns_server_iterator.h" #include "net/dns/dns_session.h" +#include "net/dns/dns_socket_allocator.h" #include "net/dns/dns_udp_tracker.h" #include "net/dns/dns_util.h" #include "net/dns/public/dns_over_https_server_config.h" @@ -187,12 +188,12 @@ class DnsAttempt { class DnsUDPAttempt : public DnsAttempt { public: DnsUDPAttempt(size_t server_index, - std::unique_ptr socket_lease, + std::unique_ptr socket, std::unique_ptr query, DnsUdpTracker* udp_tracker) : DnsAttempt(server_index), next_state_(STATE_NONE), - socket_lease_(std::move(socket_lease)), + socket_(std::move(socket)), query_(std::move(query)), udp_tracker_(udp_tracker) {} @@ -205,7 +206,7 @@ class DnsUDPAttempt : public DnsAttempt { next_state_ = STATE_SEND_QUERY; IPEndPoint local_address; - if (socket_lease_->socket()->GetLocalAddress(&local_address) == OK) + if (socket_->GetLocalAddress(&local_address) == OK) udp_tracker_->RecordQuery(local_address.port(), query_->id()); return DoLoop(OK); @@ -219,7 +220,7 @@ class DnsUDPAttempt : public DnsAttempt { } const NetLogWithSource& GetSocketNetLog() const override { - return socket_lease_->socket()->NetLog(); + return socket_->NetLog(); } private: @@ -231,8 +232,6 @@ class DnsUDPAttempt : public DnsAttempt { STATE_NONE, }; - DatagramClientSocket* socket() { return socket_lease_->socket(); } - int DoLoop(int result) { CHECK_NE(STATE_NONE, next_state_); int rv = result; @@ -270,7 +269,7 @@ class DnsUDPAttempt : public DnsAttempt { int DoSendQuery() { next_state_ = STATE_SEND_QUERY_COMPLETE; - return socket()->Write( + return socket_->Write( query_->io_buffer(), query_->io_buffer()->size(), base::BindOnce(&DnsUDPAttempt::OnIOComplete, base::Unretained(this)), kTrafficAnnotation); @@ -292,7 +291,7 @@ class DnsUDPAttempt : public DnsAttempt { int DoReadResponse() { next_state_ = STATE_READ_RESPONSE_COMPLETE; response_ = std::make_unique(); - return socket()->Read( + return socket_->Read( response_->io_buffer(), response_->io_buffer_size(), base::BindOnce(&DnsUDPAttempt::OnIOComplete, base::Unretained(this))); } @@ -328,7 +327,7 @@ class DnsUDPAttempt : public DnsAttempt { State next_state_; base::TimeTicks start_time_; - std::unique_ptr socket_lease_; + std::unique_ptr socket_; std::unique_ptr query_; // Should be owned by the DnsSession, to which the transaction should own a @@ -579,13 +578,13 @@ void ConstructDnsHTTPAttempt(DnsSession* session, RequestPriority request_priority) { DCHECK(url_request_context); - uint16_t id = session->NextQueryId(); std::unique_ptr query; if (attempts->empty()) { - query.reset(new DnsQuery(id, hostname, qtype, opt_rdata, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128)); + query = + std::make_unique(0 /* id */, hostname, qtype, opt_rdata, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); } else { - query = attempts->at(0)->GetQuery()->CloneWithNewId(id); + query = std::make_unique(*attempts->at(0)->GetQuery()); } DCHECK_LT(doh_server_index, session->config().dns_over_https_servers.size()); @@ -1056,7 +1055,7 @@ class DnsTransactionImpl : public DnsTransaction, net_log_(net_log), qnames_initial_size_(0), attempts_count_(0), - had_tcp_attempt_(false), + had_tcp_retry_(false), resolve_context_(resolve_context), request_priority_(DEFAULT_PRIORITY) { DCHECK(session_.get()); @@ -1112,6 +1111,7 @@ class DnsTransactionImpl : public DnsTransaction, private: // Wrapper for the result of a DnsUDPAttempt. struct AttemptResult { + AttemptResult() = default; AttemptResult(int rv, const DnsAttempt* attempt) : rv(rv), attempt(attempt) {} @@ -1119,6 +1119,15 @@ class DnsTransactionImpl : public DnsTransaction, const DnsAttempt* attempt; }; + // Used in UMA (DNS.AttemptType). Do not renumber or remove values. + enum class DnsAttemptType { + kUdp = 0, + kTcpLowEntropy = 1, + kTcpTruncationRetry = 2, + kHttp = 3, + kMaxValue = kHttp, + }; + // Prepares |qnames_| according to the DnsConfig. int PrepareSearch() { const DnsConfig& config = session_->config(); @@ -1194,23 +1203,24 @@ class DnsTransactionImpl : public DnsTransaction, std::move(callback_).Run(this, result.rv, response, doh_provider_id); } + void RecordAttemptUma(DnsAttemptType attempt_type) { + UMA_HISTOGRAM_ENUMERATION("Net.DNS.DnsTransaction.AttemptType", + attempt_type); + } + AttemptResult MakeAttempt() { DnsConfig config = session_->config(); if (secure_) { DCHECK_GT(config.dns_over_https_servers.size(), 0u); + RecordAttemptUma(DnsAttemptType::kHttp); return MakeHTTPAttempt(); } DCHECK_GT(config.nameservers.size(), 0u); - return MakeUDPAttempt(); + return MakeClassicDnsAttempt(); } - // Makes another attempt at the current name, |qnames_.front()|, using the - // next nameserver. - AttemptResult MakeUDPAttempt() { - DCHECK(!secure_); - size_t attempt_number = attempts_.size(); - + AttemptResult MakeClassicDnsAttempt() { uint16_t id = session_->NextQueryId(); std::unique_ptr query; if (attempts_.empty()) { @@ -1219,22 +1229,54 @@ class DnsTransactionImpl : public DnsTransaction, query = attempts_[0]->GetQuery()->CloneWithNewId(id); } DCHECK(dns_server_iterator_->AttemptAvailable()); - size_t non_doh_server_index = dns_server_iterator_->GetNextAttemptIndex(); + size_t server_index = dns_server_iterator_->GetNextAttemptIndex(); + + size_t attempt_number = attempts_.size(); + AttemptResult result; + if (session_->udp_tracker()->low_entropy()) { + result = MakeTcpAttempt(server_index, std::move(query)); + RecordAttemptUma(DnsAttemptType::kTcpLowEntropy); + } else { + result = MakeUdpAttempt(server_index, std::move(query)); + RecordAttemptUma(DnsAttemptType::kUdp); + } + + if (result.rv == ERR_IO_PENDING) { + base::TimeDelta timeout = resolve_context_->NextClassicTimeout( + server_index, attempt_number, session_.get()); + timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); + } + + return result; + } + + // Makes another attempt at the current name, |qnames_.front()|, using the + // next nameserver. + AttemptResult MakeUdpAttempt(size_t server_index, + std::unique_ptr query) { + DCHECK(!secure_); + DCHECK(!session_->udp_tracker()->low_entropy()); + size_t attempt_number = attempts_.size(); - std::unique_ptr lease = - session_->AllocateSocket(non_doh_server_index, net_log_.source()); + int connection_error = OK; + std::unique_ptr socket = + session_->socket_allocator()->CreateConnectedUdpSocket( + server_index, &connection_error); - bool got_socket = !!lease.get(); + bool got_socket = !!socket.get(); + DCHECK_EQ(got_socket, connection_error == OK); DnsUDPAttempt* attempt = - new DnsUDPAttempt(non_doh_server_index, std::move(lease), - std::move(query), session_->udp_tracker()); + new DnsUDPAttempt(server_index, std::move(socket), std::move(query), + session_->udp_tracker()); attempts_.push_back(base::WrapUnique(attempt)); ++attempts_count_; - if (!got_socket) + if (!got_socket) { + session_->udp_tracker()->RecordConnectionError(connection_error); return AttemptResult(ERR_CONNECTION_REFUSED, nullptr); + } net_log_.AddEventReferencingSource(NetLogEventType::DNS_TRANSACTION_ATTEMPT, attempt->GetSocketNetLog().source()); @@ -1242,11 +1284,6 @@ class DnsTransactionImpl : public DnsTransaction, int rv = attempt->Start(base::BindOnce( &DnsTransactionImpl::OnAttemptComplete, base::Unretained(this), attempt_number, true /* record_rtt */, base::TimeTicks::Now())); - if (rv == ERR_IO_PENDING) { - base::TimeDelta timeout = resolve_context_->NextClassicTimeout( - non_doh_server_index, attempt_number, session_.get()); - timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); - } return AttemptResult(rv, attempt); } @@ -1272,25 +1309,44 @@ class DnsTransactionImpl : public DnsTransaction, return AttemptResult(rv, attempts_.back().get()); } - AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) { - DCHECK(!secure_); + AttemptResult RetryUdpAttemptAsTcp(const DnsAttempt* previous_attempt) { DCHECK(previous_attempt); - DCHECK(!had_tcp_attempt_); - - size_t server_index = previous_attempt->server_index(); + DCHECK(!had_tcp_retry_); - std::unique_ptr socket( - session_->CreateTCPSocket(server_index, net_log_.source())); + // Only allow a single TCP retry per query. + had_tcp_retry_ = true; - // TODO(szym): Reuse the same id to help the server? - uint16_t id = session_->NextQueryId(); + size_t server_index = previous_attempt->server_index(); + // Use a new query ID instead of reusing the same one from the UDP attempt. + // RFC5452, section 9.2 requires an unpredictable ID for all outgoing + // queries, with no distinction made between queries made via TCP or UDP. std::unique_ptr query = - previous_attempt->GetQuery()->CloneWithNewId(id); + previous_attempt->GetQuery()->CloneWithNewId(session_->NextQueryId()); - // Cancel all attempts that have not received a response, no point waiting - // on them. + // Cancel all attempts that have not received a response, as they will + // likely similarly require TCP retry. ClearAttempts(nullptr); + AttemptResult result = MakeTcpAttempt(server_index, std::move(query)); + RecordAttemptUma(DnsAttemptType::kTcpTruncationRetry); + + if (result.rv == ERR_IO_PENDING) { + // On TCP upgrade, use 2x the upgraded timeout. + base::TimeDelta timeout = timer_.GetCurrentDelay() * 2; + timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); + } + + return result; + } + + AttemptResult MakeTcpAttempt(size_t server_index, + std::unique_ptr query) { + DCHECK(!secure_); + + std::unique_ptr socket( + session_->socket_allocator()->CreateTcpSocket(server_index, + net_log_.source())); + unsigned attempt_number = attempts_.size(); DnsTCPAttempt* attempt = @@ -1298,7 +1354,6 @@ class DnsTransactionImpl : public DnsTransaction, attempts_.push_back(base::WrapUnique(attempt)); ++attempts_count_; - had_tcp_attempt_ = true; net_log_.AddEventReferencingSource( NetLogEventType::DNS_TRANSACTION_TCP_ATTEMPT, @@ -1307,11 +1362,6 @@ class DnsTransactionImpl : public DnsTransaction, int rv = attempt->Start(base::BindOnce( &DnsTransactionImpl::OnAttemptComplete, base::Unretained(this), attempt_number, false /* record_rtt */, base::TimeTicks::Now())); - if (rv == ERR_IO_PENDING) { - // Custom timeout for TCP attempt. - base::TimeDelta timeout = timer_.GetCurrentDelay() * 2; - timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); - } return AttemptResult(rv, attempt); } @@ -1322,7 +1372,7 @@ class DnsTransactionImpl : public DnsTransaction, "qname", dotted_qname); attempts_.clear(); - had_tcp_attempt_ = false; + had_tcp_retry_ = false; if (secure_) { dns_server_iterator_ = resolve_context_->GetDohIterator( session_->config(), secure_dns_mode_, session_.get()); @@ -1365,7 +1415,7 @@ class DnsTransactionImpl : public DnsTransaction, } bool MoreAttemptsAllowed() const { - if (had_tcp_attempt_) + if (had_tcp_retry_) return false; return dns_server_iterator_->AttemptAvailable(); @@ -1419,7 +1469,7 @@ class DnsTransactionImpl : public DnsTransaction, } break; case ERR_DNS_SERVER_REQUIRES_TCP: - result = MakeTCPAttempt(result.attempt); + result = RetryUdpAttemptAsTcp(result.attempt); break; case ERR_BLOCKED_BY_CLIENT: net_log_.EndEventWithNetErrorCode( @@ -1493,7 +1543,9 @@ class DnsTransactionImpl : public DnsTransaction, std::vector> attempts_; // Count of attempts, not reset when |attempts_| vector is cleared. int attempts_count_; - bool had_tcp_attempt_; + + // Records when an attempt was retried via TCP due to a truncation error. + bool had_tcp_retry_; // Iterator to get the index of the DNS server for each search query. std::unique_ptr dns_server_iterator_; diff --git a/chromium/net/dns/dns_transaction_unittest.cc b/chromium/net/dns/dns_transaction_unittest.cc index 17f6bf62e72..274fea28a86 100644 --- a/chromium/net/dns/dns_transaction_unittest.cc +++ b/chromium/net/dns/dns_transaction_unittest.cc @@ -28,13 +28,14 @@ #include "net/base/port_util.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/url_util.h" -#include "net/cookies/cookie_inclusion_status.h" +#include "net/cookies/cookie_access_result.h" #include "net/cookies/cookie_util.h" #include "net/dns/dns_config.h" #include "net/dns/dns_query.h" #include "net/dns/dns_response.h" #include "net/dns/dns_server_iterator.h" #include "net/dns/dns_session.h" +#include "net/dns/dns_socket_allocator.h" #include "net/dns/dns_test_util.h" #include "net/dns/dns_util.h" #include "net/dns/public/dns_over_https_server_config.h" @@ -251,8 +252,19 @@ class TestSocketFactory : public MockClientSocketFactory { return std::unique_ptr( new FailingUDPClientSocket(&empty_data_, net_log)); } + SocketDataProvider* data_provider = mock_data().GetNext(); - return std::make_unique(this, data_provider, net_log); + auto socket = + std::make_unique(this, data_provider, net_log); + + // Even using DEFAULT_BIND, actual sockets have been measured to very rarely + // repeat the same source port multiple times in a row. Need to mimic that + // functionality here, so DnsUdpTracker doesn't misdiagnose repeated port + // as low entropy. + if (diverse_source_ports_) + socket->set_source_port(next_source_port_++); + + return socket; } void OnConnect(const IPEndPoint& endpoint) { @@ -271,9 +283,11 @@ class TestSocketFactory : public MockClientSocketFactory { std::vector remote_endpoints_; bool fail_next_socket_; + bool diverse_source_ports_ = true; private: StaticSocketDataProvider empty_data_; + uint16_t next_source_port_ = 123; DISALLOW_COPY_AND_ASSIGN(TestSocketFactory); }; @@ -573,7 +587,12 @@ class URLRequestMockDohJob : public URLRequestJob, public AsyncSocket { class DnsTransactionTestBase : public testing::Test { public: DnsTransactionTestBase() = default; - ~DnsTransactionTestBase() override = default; + + ~DnsTransactionTestBase() override { + // All queued transaction IDs should be used by a transaction calling + // GetNextId(). + CHECK(transaction_ids_.empty()); + } // Generates |nameservers| for DnsConfig. void ConfigureNumServers(size_t num_servers) { @@ -620,18 +639,21 @@ class DnsTransactionTestBase : public testing::Test { socket_factory_.reset(new TestSocketFactory()); session_ = new DnsSession( config_, - DnsSocketPool::CreateNull(socket_factory_.get(), - base::Bind(base::RandInt)), - base::Bind(&DnsTransactionTestBase::GetNextId, base::Unretained(this)), + std::make_unique( + socket_factory_.get(), config_.nameservers, nullptr /* net_log */), + base::BindRepeating(&DnsTransactionTestBase::GetNextId, + base::Unretained(this)), nullptr /* NetLog */); resolve_context_->InvalidateCachesAndPerSessionData( session_.get(), false /* network_change */); transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get()); } - void AddSocketData(std::unique_ptr data) { + void AddSocketData(std::unique_ptr data, + bool enqueue_transaction_id = true) { CHECK(socket_factory_.get()); - transaction_ids_.push_back(data->query_id()); + if (enqueue_transaction_id) + transaction_ids_.push_back(data->query_id()); socket_factory_->AddSocketDataProvider(data->GetProvider()); socket_data_.push_back(std::move(data)); } @@ -648,12 +670,13 @@ class DnsTransactionTestBase : public testing::Test { Transport transport, const OptRecordRdata* opt_rdata = nullptr, DnsQuery::PaddingStrategy padding_strategy = - DnsQuery::PaddingStrategy::NONE) { + DnsQuery::PaddingStrategy::NONE, + bool enqueue_transaction_id = true) { CHECK(socket_factory_.get()); std::unique_ptr data(new DnsSocketData( id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy)); data->AddResponseData(response_data, response_length, mode); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), enqueue_transaction_id); } void AddQueryAndErrorResponse(uint16_t id, @@ -664,12 +687,13 @@ class DnsTransactionTestBase : public testing::Test { Transport transport, const OptRecordRdata* opt_rdata = nullptr, DnsQuery::PaddingStrategy padding_strategy = - DnsQuery::PaddingStrategy::NONE) { + DnsQuery::PaddingStrategy::NONE, + bool enqueue_transaction_id = true) { CHECK(socket_factory_.get()); std::unique_ptr data(new DnsSocketData( id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy)); data->AddReadError(error, mode); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), enqueue_transaction_id); } void AddAsyncQueryAndResponse(uint16_t id, @@ -693,33 +717,37 @@ class DnsTransactionTestBase : public testing::Test { } // Add expected query of |dotted_name| and |qtype| and no response. - void AddQueryAndTimeout(const char* dotted_name, - uint16_t qtype, - DnsQuery::PaddingStrategy padding_strategy = - DnsQuery::PaddingStrategy::NONE) { - uint16_t id = base::RandInt(0, std::numeric_limits::max()); + void AddQueryAndTimeout( + const char* dotted_name, + uint16_t qtype, + DnsQuery::PaddingStrategy padding_strategy = + DnsQuery::PaddingStrategy::NONE, + uint16_t id = base::RandInt(0, std::numeric_limits::max()), + bool enqueue_transaction_id = true) { std::unique_ptr data( new DnsSocketData(id, dotted_name, qtype, ASYNC, Transport::UDP, nullptr /* opt_rdata */, padding_strategy)); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), enqueue_transaction_id); } // Add expected query of |dotted_name| and |qtype| and matching response with // no answer and RCODE set to |rcode|. The id will be generated randomly. - void AddQueryAndRcode(const char* dotted_name, - uint16_t qtype, - int rcode, - IoMode mode, - Transport trans, - DnsQuery::PaddingStrategy padding_strategy = - DnsQuery::PaddingStrategy::NONE) { + void AddQueryAndRcode( + const char* dotted_name, + uint16_t qtype, + int rcode, + IoMode mode, + Transport trans, + DnsQuery::PaddingStrategy padding_strategy = + DnsQuery::PaddingStrategy::NONE, + uint16_t id = base::RandInt(0, std::numeric_limits::max()), + bool enqueue_transaction_id = true) { CHECK_NE(dns_protocol::kRcodeNOERROR, rcode); - uint16_t id = base::RandInt(0, std::numeric_limits::max()); std::unique_ptr data( new DnsSocketData(id, dotted_name, qtype, mode, trans, nullptr /* opt_rdata */, padding_strategy)); data->AddRcode(rcode, mode); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), enqueue_transaction_id); } void AddAsyncQueryAndRcode(const char* dotted_name, @@ -1421,12 +1449,39 @@ TEST_F(DnsTransactionTest, SyncSearchQuery) { } TEST_F(DnsTransactionTest, ConnectFailure) { - socket_factory_->fail_next_socket_ = true; + // Prep socket factory for a single socket with connection failure. + MockConnect connect_data; + connect_data.result = ERR_FAILED; + StaticSocketDataProvider data_provider; + data_provider.set_connect_data(connect_data); + socket_factory_->AddSocketDataProvider(&data_provider); + transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA, false /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); + EXPECT_TRUE(helper0.Run(transaction_factory_.get())); + EXPECT_FALSE(helper0.response()); + EXPECT_FALSE(session_->udp_tracker()->low_entropy()); +} + +TEST_F(DnsTransactionTest, ConnectFailure_SocketLimitReached) { + // Prep socket factory for a single socket with connection failure. + MockConnect connect_data; + connect_data.result = ERR_INSUFFICIENT_RESOURCES; + StaticSocketDataProvider data_provider; + data_provider.set_connect_data(connect_data); + socket_factory_->AddSocketDataProvider(&data_provider); + + transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. + TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA, + false /* secure */, ERR_CONNECTION_REFUSED, + resolve_context_.get()); + + EXPECT_TRUE(helper0.Run(transaction_factory_.get())); + EXPECT_FALSE(helper0.response()); + EXPECT_TRUE(session_->udp_tracker()->low_entropy()); } TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) { @@ -1450,7 +1505,8 @@ TEST_F(DnsTransactionTest, HttpsGetLookup) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1460,7 +1516,8 @@ TEST_F(DnsTransactionTest, HttpsGetFailure) { ConfigureDohServers(false /* use_post */); AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, SYNCHRONOUS, Transport::HTTPS, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_SERVER_FAILED, resolve_context_.get()); @@ -1471,10 +1528,12 @@ TEST_F(DnsTransactionTest, HttpsGetFailure) { TEST_F(DnsTransactionTest, HttpsGetMalformed) { ConfigureDohServers(false /* use_post */); - AddQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, - base::size(kT0ResponseDatagram), SYNCHRONOUS, + // Use T1 response, which is malformed for a T0 request. + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram, + base::size(kT1ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1485,7 +1544,8 @@ TEST_F(DnsTransactionTest, HttpsPostLookup) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1495,7 +1555,8 @@ TEST_F(DnsTransactionTest, HttpsPostFailure) { ConfigureDohServers(true /* use_post */); AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, SYNCHRONOUS, Transport::HTTPS, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_SERVER_FAILED, resolve_context_.get()); @@ -1506,10 +1567,12 @@ TEST_F(DnsTransactionTest, HttpsPostFailure) { TEST_F(DnsTransactionTest, HttpsPostMalformed) { ConfigureDohServers(true /* use_post */); - AddQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, - base::size(kT0ResponseDatagram), SYNCHRONOUS, + // Use T1 response, which is malformed for a T0 request. + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram, + base::size(kT1ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); @@ -1521,7 +1584,8 @@ TEST_F(DnsTransactionTest, HttpsPostLookupAsync) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1541,7 +1605,8 @@ TEST_F(DnsTransactionTest, HttpsPostLookupFailDohServerLookup) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED, resolve_context_.get()); @@ -1562,7 +1627,8 @@ TEST_F(DnsTransactionTest, HttpsPostLookupFailStart) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_FAILED, resolve_context_.get()); SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart)); @@ -1583,7 +1649,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupFailSync) { 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128)); data->AddResponseWithLength(std::make_unique(), SYNCHRONOUS, 0); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailSync)); @@ -1603,7 +1669,8 @@ TEST_F(DnsTransactionTest, HttpsPostLookupFailAsync) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailAsync)); @@ -1618,7 +1685,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookup2Sync) { data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS); data->AddResponseData(kT0ResponseDatagram + 20, base::size(kT0ResponseDatagram) - 20, SYNCHRONOUS); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1632,7 +1699,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookup2Async) { data->AddResponseData(kT0ResponseDatagram, 20, ASYNC); data->AddResponseData(kT0ResponseDatagram + 20, base::size(kT0ResponseDatagram) - 20, ASYNC); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1646,7 +1713,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupAsyncWithAsyncZeroRead) { data->AddResponseData(kT0ResponseDatagram, base::size(kT0ResponseDatagram), ASYNC); data->AddResponseData(kT0ResponseDatagram, 0, ASYNC); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1660,7 +1727,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupSyncWithAsyncZeroRead) { data->AddResponseData(kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS); data->AddResponseData(kT0ResponseDatagram, 0, ASYNC); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1674,7 +1741,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSync) { data->AddResponseData(kT0ResponseDatagram, 20, ASYNC); data->AddResponseData(kT0ResponseDatagram + 20, base::size(kT0ResponseDatagram) - 20, SYNCHRONOUS); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1687,7 +1754,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSyncError) { nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128)); data->AddResponseData(kT0ResponseDatagram, 20, ASYNC); data->AddReadError(ERR_FAILED, SYNCHRONOUS); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_FAILED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1700,7 +1767,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenAsyncError) { nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128)); data->AddResponseData(kT0ResponseDatagram, 20, ASYNC); data->AddReadError(ERR_FAILED, ASYNC); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_FAILED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1713,7 +1780,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenAsyncError) { nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128)); data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS); data->AddReadError(ERR_FAILED, ASYNC); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_FAILED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1726,7 +1793,7 @@ TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenSyncError) { nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128)); data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS); data->AddReadError(ERR_FAILED, SYNCHRONOUS); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_FAILED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1749,31 +1816,37 @@ TEST_F(DnsTransactionTest, HttpsMarkHttpsBad) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(1, kT1HostName, kT1Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(1, kT1HostName, kT1Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(1, kT1HostName, kT1Qtype, kT1ResponseDatagram, - base::size(kT1ResponseDatagram), ASYNC, Transport::HTTPS, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, + base::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); - TransactionHelper helper1(kT1HostName, kT1Qtype, true /* secure */, - kT1RecordCount, resolve_context_.get()); + TransactionHelper helper1(kT0HostName, kT0Qtype, true /* secure */, + kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); // UDP server 0 is our only UDP server, so it will be good. HTTPS // servers 0 and 1 failed and will be marked bad. HTTPS server 2 succeeded @@ -1834,11 +1907,13 @@ TEST_F(DnsTransactionTest, HttpsPostFailThenHTTPFallback) { ConfigureDohServers(true /* use_post */, 2); AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, ASYNC, Transport::HTTPS, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */, + false /* enqueue_transaction_id */); AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1852,11 +1927,13 @@ TEST_F(DnsTransactionTest, HttpsPostFailTwice) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_FAILED, resolve_context_.get()); SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart)); @@ -1886,7 +1963,8 @@ TEST_F(DnsTransactionTest, HttpsNotAvailableThenHttpFallback) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1928,7 +2006,8 @@ TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Automatic) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -1978,15 +2057,18 @@ TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Secure) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -2025,7 +2107,8 @@ TEST_F(DnsTransactionTest, MaxHttpsFailures_NonConsecutive) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper failure(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); EXPECT_TRUE(failure.RunUntilDone(transaction_factory_.get())); @@ -2043,7 +2126,8 @@ TEST_F(DnsTransactionTest, MaxHttpsFailures_NonConsecutive) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper success(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); EXPECT_TRUE(success.RunUntilDone(transaction_factory_.get())); @@ -2061,7 +2145,8 @@ TEST_F(DnsTransactionTest, MaxHttpsFailures_NonConsecutive) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper last_failure(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); @@ -2094,7 +2179,8 @@ TEST_F(DnsTransactionTest, MaxHttpsFailures_Consecutive) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper failure(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); EXPECT_TRUE(failure.RunUntilDone(transaction_factory_.get())); @@ -2111,7 +2197,8 @@ TEST_F(DnsTransactionTest, MaxHttpsFailures_Consecutive) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper last_failure(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); @@ -2150,7 +2237,7 @@ TEST_F(DnsTransactionTest, SuccessfulTransactionStartedBeforeUnavailable) { data->AddResponseData(kT0ResponseDatagram, base::size(kT0ResponseDatagram), ASYNC); SequencedSocketData* sequenced_socket_data = data->GetProvider(); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); TransactionHelper delayed_success(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); @@ -2161,7 +2248,8 @@ TEST_F(DnsTransactionTest, SuccessfulTransactionStartedBeforeUnavailable) { AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper failure(kT0HostName, kT0Qtype, true /* secure */, ERR_CONNECTION_REFUSED, resolve_context_.get()); EXPECT_TRUE(failure.RunUntilDone(transaction_factory_.get())); @@ -2189,8 +2277,8 @@ class CookieCallback { CookieCallback() : result_(false), loop_to_quit_(std::make_unique()) {} - void SetCookieCallback(CookieInclusionStatus result) { - result_ = result.IsInclude(); + void SetCookieCallback(CookieAccessResult result) { + result_ = result.status.IsInclude(); loop_to_quit_->Quit(); } @@ -2219,15 +2307,17 @@ TEST_F(DnsTransactionTest, HttpsPostTestNoCookies) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(1, kT1HostName, kT1Qtype, kT1ResponseDatagram, - base::size(kT1ResponseDatagram), SYNCHRONOUS, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, + base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); - TransactionHelper helper1(kT1HostName, kT1Qtype, true /* secure */, - kT1RecordCount, resolve_context_.get()); + TransactionHelper helper1(kT0HostName, kT0Qtype, true /* secure */, + kT0RecordCount, resolve_context_.get()); SetResponseModifierCallback(base::BindRepeating(MakeResponseWithCookie)); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -2262,7 +2352,8 @@ TEST_F(DnsTransactionTest, HttpsPostNoContentLength) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); SetResponseModifierCallback(base::BindRepeating(MakeResponseWithoutLength)); @@ -2279,7 +2370,8 @@ TEST_F(DnsTransactionTest, HttpsPostWithBadRequestResponse) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); SetResponseModifierCallback( @@ -2297,7 +2389,8 @@ TEST_F(DnsTransactionTest, HttpsPostWithWrongType) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); SetResponseModifierCallback(base::BindRepeating(MakeResponseWrongType)); @@ -2317,11 +2410,13 @@ TEST_F(DnsTransactionTest, HttpsGetRedirect) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); SetResponseModifierCallback(base::BindRepeating(MakeResponseRedirect)); @@ -2337,7 +2432,8 @@ TEST_F(DnsTransactionTest, HttpsPostWithNoType) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_MALFORMED_RESPONSE, resolve_context_.get()); SetResponseModifierCallback(base::BindRepeating(MakeResponseNoType)); @@ -2350,7 +2446,8 @@ TEST_F(DnsTransactionTest, CanLookupDohServerName) { AddQueryAndErrorResponse(0, kMockHostname, dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED, SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0("mock", dns_protocol::kTypeA, true /* secure */, ERR_NAME_NOT_RESOLVED, resolve_context_.get()); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); @@ -2385,7 +2482,8 @@ TEST_F(DnsTransactionTest, HttpsPostLookupWithLog) { AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram, base::size(kT0ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TransactionHelper helper0(kT0HostName, kT0Qtype, true /* secure */, kT0RecordCount, resolve_context_.get()); CountingObserver observer; @@ -2403,7 +2501,8 @@ TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_SingleAttempt) { ConfigureDohServers(false /* use_post */); AddQueryAndTimeout(kT0HostName, kT0Qtype, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */, + false /* enqueue_transaction_id */); TransactionHelper helper(kT0HostName, kT0Qtype, true /* secure */, ERR_DNS_TIMED_OUT, resolve_context_.get()); @@ -2425,23 +2524,24 @@ TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_TwoAttempts) { // Simulate a slow response by using an ERR_IO_PENDING read error to delay // until SequencedSocketData::Resume() is called. auto data = std::make_unique( - 1 /* id */, kT1HostName, kT1Qtype, ASYNC, Transport::HTTPS, + 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); data->AddReadError(ERR_IO_PENDING, ASYNC); - data->AddResponseData(kT1ResponseDatagram, base::size(kT1ResponseDatagram), + data->AddResponseData(kT0ResponseDatagram, base::size(kT0ResponseDatagram), ASYNC); SequencedSocketData* sequenced_socket_data = data->GetProvider(); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); - TransactionHelper helper(kT1HostName, kT1Qtype, true /* secure */, - kT1RecordCount, resolve_context_.get()); + TransactionHelper helper(kT0HostName, kT0Qtype, true /* secure */, + kT0RecordCount, resolve_context_.get()); ASSERT_FALSE(helper.Run(transaction_factory_.get())); ASSERT_TRUE(sequenced_socket_data->IsPaused()); // Another attempt configured, so transaction should not fail after initial // timeout. Setup the second attempt to never receive a response. - AddQueryAndTimeout(kT1HostName, kT1Qtype, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + AddQueryAndTimeout(kT0HostName, kT0Qtype, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */, + false /* enqueue_transaction_id */); FastForwardBy(resolve_context_->NextDohTimeout(0 /* doh_server_index */, session_.get())); EXPECT_FALSE(helper.has_completed()); @@ -2453,7 +2553,7 @@ TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_TwoAttempts) { EXPECT_TRUE(helper.has_completed()); } -TEST_F(DnsTransactionTest, TCPLookup) { +TEST_F(DnsTransactionTest, TcpLookup_UdpRetry) { AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, @@ -2464,6 +2564,31 @@ TEST_F(DnsTransactionTest, TCPLookup) { EXPECT_TRUE(helper0.Run(transaction_factory_.get())); } +TEST_F(DnsTransactionTest, TcpLookup_LowEntropy) { + socket_factory_->diverse_source_ports_ = false; + + for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) { + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, + base::size(kT0ResponseDatagram), ASYNC, Transport::UDP); + } + + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, + base::size(kT0ResponseDatagram), ASYNC, Transport::TCP); + + for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) { + TransactionHelper udp_helper(kT0HostName, kT0Qtype, false /* secure */, + kT0RecordCount, resolve_context_.get()); + udp_helper.RunUntilDone(transaction_factory_.get()); + } + + ASSERT_TRUE(session_->udp_tracker()->low_entropy()); + + TransactionHelper helper0(kT0HostName, kT0Qtype, false /* secure */, + kT0RecordCount, resolve_context_.get()); + EXPECT_TRUE(helper0.Run(transaction_factory_.get())); + EXPECT_TRUE(session_->udp_tracker()->low_entropy()); +} + TEST_F(DnsTransactionTest, TCPFailure) { AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); @@ -2498,7 +2623,7 @@ TEST_F(DnsTransactionTest, TCPMalformed) { EXPECT_TRUE(helper0.Run(transaction_factory_.get())); } -TEST_F(DnsTransactionTestWithMockTime, TCPTimeout) { +TEST_F(DnsTransactionTestWithMockTime, TcpTimeout_UdpRetry) { ConfigureFactory(); AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); @@ -2512,6 +2637,33 @@ TEST_F(DnsTransactionTestWithMockTime, TCPTimeout) { EXPECT_TRUE(helper0.has_completed()); } +TEST_F(DnsTransactionTestWithMockTime, TcpTimeout_LowEntropy) { + ConfigureFactory(); + socket_factory_->diverse_source_ports_ = false; + + for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) { + AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram, + base::size(kT0ResponseDatagram), ASYNC, Transport::UDP); + } + + AddSocketData(std::make_unique( + 1 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::TCP)); + + for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) { + TransactionHelper udp_helper(kT0HostName, kT0Qtype, false /* secure */, + kT0RecordCount, resolve_context_.get()); + udp_helper.RunUntilDone(transaction_factory_.get()); + } + + ASSERT_TRUE(session_->udp_tracker()->low_entropy()); + + TransactionHelper helper0(kT0HostName, kT0Qtype, false /* secure */, + ERR_DNS_TIMED_OUT, resolve_context_.get()); + EXPECT_FALSE(helper0.Run(transaction_factory_.get())); + FastForwardUntilNoTasksRemain(); + EXPECT_TRUE(helper0.has_completed()); +} + TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) { AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); @@ -2676,18 +2828,21 @@ TEST_F(DnsTransactionTest, InvalidQuery) { TEST_F(DnsTransactionTestWithMockTime, ProbeUntilSuccess) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -2720,20 +2875,21 @@ TEST_F(DnsTransactionTestWithMockTime, HungProbe) { // probe and not return the error until SequencedSocketData::Resume() is // called. auto data = std::make_unique( - 4, kT4HostName, kT4Qtype, ASYNC, Transport::HTTPS, + 0 /* id */, kT4HostName, kT4Qtype, ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); data->AddReadError(ERR_IO_PENDING, ASYNC); data->AddReadError(ERR_CONNECTION_REFUSED, ASYNC); data->AddResponseData(kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC); SequencedSocketData* sequenced_socket_data = data->GetProvider(); - AddSocketData(std::move(data)); + AddSocketData(std::move(data), false /* enqueue_transaction_id */); // Add success for second probe. - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -2764,18 +2920,21 @@ TEST_F(DnsTransactionTestWithMockTime, HungProbe) { TEST_F(DnsTransactionTestWithMockTime, ProbeMultipleServers) { ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */, false /* make_available */); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); ASSERT_FALSE(resolve_context_->GetDohServerAvailability( 0u /* doh_server_index */, session_.get())); @@ -2812,14 +2971,16 @@ TEST_F(DnsTransactionTestWithMockTime, ProbeMultipleServers) { TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner1 = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -2856,18 +3017,21 @@ TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners_SeparateContexts) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); TestURLRequestContext request_context2; ResolveContext context2(&request_context2, false /* enable_caching */); @@ -2922,14 +3086,16 @@ TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners_SeparateContexts) { TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -2961,18 +3127,21 @@ TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe) { TEST_F(DnsTransactionTestWithMockTime, CancelOneOfMultipleProbeRunners) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner1 = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -3005,14 +3174,16 @@ TEST_F(DnsTransactionTestWithMockTime, CancelOneOfMultipleProbeRunners) { TEST_F(DnsTransactionTestWithMockTime, CancelAllOfMultipleProbeRunners) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner1 = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -3044,10 +3215,11 @@ TEST_F(DnsTransactionTestWithMockTime, CancelAllOfMultipleProbeRunners) { TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe_AfterSuccess) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), SYNCHRONOUS, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -3083,10 +3255,11 @@ TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe_AfterSuccess) { TEST_F(DnsTransactionTestWithMockTime, DestroyFactoryAfterStartingDohProbe) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -3112,14 +3285,16 @@ TEST_F(DnsTransactionTestWithMockTime, DestroyFactoryAfterStartingDohProbe) { TEST_F(DnsTransactionTestWithMockTime, StartWhileRunning) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndErrorResponse(4, kT4HostName, kT4Qtype, ERR_CONNECTION_REFUSED, - SYNCHRONOUS, Transport::HTTPS, - nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype, + ERR_CONNECTION_REFUSED, SYNCHRONOUS, + Transport::HTTPS, nullptr /* opt_rdata */, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -3145,14 +3320,16 @@ TEST_F(DnsTransactionTestWithMockTime, StartWhileRunning) { TEST_F(DnsTransactionTestWithMockTime, RestartFinishedProbe) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); @@ -3193,14 +3370,16 @@ TEST_F(DnsTransactionTestWithMockTime, RestartFinishedProbe) { TEST_F(DnsTransactionTestWithMockTime, FastProbeRestart) { ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */, false /* make_available */); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); - AddQueryAndResponse(4, kT4HostName, kT4Qtype, kT4ResponseDatagram, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); + AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram, base::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS, nullptr /* opt_rdata */, - DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, + false /* enqueue_transaction_id */); std::unique_ptr runner = transaction_factory_->CreateDohProbeRunner(resolve_context_.get()); diff --git a/chromium/net/dns/dns_udp_tracker.cc b/chromium/net/dns/dns_udp_tracker.cc index ffd50c6c471..d07a7ed8ecd 100644 --- a/chromium/net/dns/dns_udp_tracker.cc +++ b/chromium/net/dns/dns_udp_tracker.cc @@ -10,15 +10,45 @@ #include "base/metrics/histogram_macros.h" #include "base/numerics/safe_conversions.h" #include "base/time/tick_clock.h" +#include "net/base/net_errors.h" namespace net { +namespace { +// Used in UMA (DNS.UdpLowEntropyReason). Do not renumber or remove values. +enum class LowEntropyReason { + kPortReuse = 0, + kRecognizedIdMismatch = 1, + kUnrecognizedIdMismatch = 2, + kSocketLimitExhaustion = 3, + kMaxValue = kSocketLimitExhaustion, +}; + +void RecordLowEntropyUma(LowEntropyReason reason) { + UMA_HISTOGRAM_ENUMERATION("Net.DNS.DnsTransaction.UDP.LowEntropyReason", + reason); +} + +} // namespace + // static constexpr base::TimeDelta DnsUdpTracker::kMaxAge; // static constexpr size_t DnsUdpTracker::kMaxRecordedQueries; +// static +constexpr base::TimeDelta DnsUdpTracker::kMaxRecognizedIdAge; + +// static +constexpr size_t DnsUdpTracker::kUnrecognizedIdMismatchThreshold; + +// static +constexpr size_t DnsUdpTracker::kRecognizedIdMismatchThreshold; + +// static +constexpr int DnsUdpTracker::kPortReuseThreshold; + struct DnsUdpTracker::QueryData { uint16_t port; uint16_t query_id; @@ -31,7 +61,7 @@ DnsUdpTracker::DnsUdpTracker(DnsUdpTracker&&) = default; DnsUdpTracker& DnsUdpTracker::operator=(DnsUdpTracker&&) = default; void DnsUdpTracker::RecordQuery(uint16_t port, uint16_t query_id) { - PurgeOldQueries(); + PurgeOldRecords(); int reused_port_count = base::checked_cast(std::count_if( recent_queries_.cbegin(), recent_queries_.cend(), @@ -50,11 +80,16 @@ void DnsUdpTracker::RecordQuery(uint16_t port, uint16_t query_id) { now - most_recent_match->time); } + if (reused_port_count >= kPortReuseThreshold && !low_entropy_) { + low_entropy_ = true; + RecordLowEntropyUma(LowEntropyReason::kPortReuse); + } + SaveQuery({port, query_id, now}); } void DnsUdpTracker::RecordResponseId(uint16_t query_id, uint16_t response_id) { - PurgeOldQueries(); + PurgeOldRecords(); // Used in UMA (DNS.UdpIdMismatchStatus). Do not renumber or remove values. enum class MismatchStatus { @@ -68,6 +103,8 @@ void DnsUdpTracker::RecordResponseId(uint16_t query_id, uint16_t response_id) { if (query_id == response_id) { status = MismatchStatus::kSuccessfulParse; } else { + SaveIdMismatch(response_id); + auto oldest_matching_id = std::find_if(recent_queries_.cbegin(), recent_queries_.cend(), [&](const auto& recent_query) { @@ -87,12 +124,31 @@ void DnsUdpTracker::RecordResponseId(uint16_t query_id, uint16_t response_id) { UMA_HISTOGRAM_ENUMERATION("Net.DNS.DnsTransaction.UDP.IdMismatch", status); } -void DnsUdpTracker::PurgeOldQueries() { +void DnsUdpTracker::RecordConnectionError(int connection_error) { + if (!low_entropy_ && connection_error == ERR_INSUFFICIENT_RESOURCES) { + // On UDP connection, this error signifies that the process is using an + // unreasonably large number of UDP sockets, potentially a deliberate + // attack to reduce DNS port entropy. + low_entropy_ = true; + RecordLowEntropyUma(LowEntropyReason::kSocketLimitExhaustion); + } +} + +void DnsUdpTracker::PurgeOldRecords() { base::TimeTicks now = tick_clock_->NowTicks(); + while (!recent_queries_.empty() && (now - recent_queries_.front().time) > kMaxAge) { recent_queries_.pop_front(); } + while (!recent_unrecognized_id_hits_.empty() && + now - recent_unrecognized_id_hits_.front() > kMaxAge) { + recent_unrecognized_id_hits_.pop_front(); + } + while (!recent_recognized_id_hits_.empty() && + now - recent_recognized_id_hits_.front() > kMaxAge) { + recent_recognized_id_hits_.pop_front(); + } } void DnsUdpTracker::SaveQuery(QueryData query) { @@ -104,4 +160,46 @@ void DnsUdpTracker::SaveQuery(QueryData query) { recent_queries_.push_back(std::move(query)); } +void DnsUdpTracker::SaveIdMismatch(uint16_t id) { + // No need to track mismatches if already flagged for low entropy. + if (low_entropy_) + return; + + base::TimeTicks now = tick_clock_->NowTicks(); + base::TimeTicks time_cutoff = now - kMaxRecognizedIdAge; + bool is_recognized = std::any_of( + recent_queries_.cbegin(), recent_queries_.cend(), + [&](const auto& recent_query) { + return recent_query.query_id == id && recent_query.time >= time_cutoff; + }); + + if (is_recognized) { + DCHECK_LT(recent_recognized_id_hits_.size(), + kRecognizedIdMismatchThreshold); + if (recent_recognized_id_hits_.size() == + kRecognizedIdMismatchThreshold - 1) { + low_entropy_ = true; + RecordLowEntropyUma(LowEntropyReason::kRecognizedIdMismatch); + return; + } + + DCHECK(recent_recognized_id_hits_.empty() || + now >= recent_recognized_id_hits_.back()); + recent_recognized_id_hits_.push_back(now); + } else { + DCHECK_LT(recent_unrecognized_id_hits_.size(), + kUnrecognizedIdMismatchThreshold); + if (recent_unrecognized_id_hits_.size() == + kUnrecognizedIdMismatchThreshold - 1) { + low_entropy_ = true; + RecordLowEntropyUma(LowEntropyReason::kUnrecognizedIdMismatch); + return; + } + + DCHECK(recent_unrecognized_id_hits_.empty() || + now >= recent_unrecognized_id_hits_.back()); + recent_unrecognized_id_hits_.push_back(now); + } +} + } // namespace net diff --git a/chromium/net/dns/dns_udp_tracker.h b/chromium/net/dns/dns_udp_tracker.h index 6e58e64c104..597f0362028 100644 --- a/chromium/net/dns/dns_udp_tracker.h +++ b/chromium/net/dns/dns_udp_tracker.h @@ -29,6 +29,20 @@ class NET_EXPORT_PRIVATE DnsUdpTracker { static constexpr base::TimeDelta kMaxAge = base::TimeDelta::FromMinutes(10); static constexpr size_t kMaxRecordedQueries = 256; + // How recently an ID needs to be recorded in a recent query to be considered + // "recognized". + static constexpr base::TimeDelta kMaxRecognizedIdAge = + base::TimeDelta::FromSeconds(15); + + // Numbers of ID mismatches required to set the |low_entropy_| flag. Also + // serves as the max number of mismatches to be recorded, as no more entries + // are recorded after setting the flag. + static constexpr size_t kUnrecognizedIdMismatchThreshold = 8; + static constexpr size_t kRecognizedIdMismatchThreshold = 128; + + // Number of reuses of the same port required to set the |low_entropy_| flag. + static constexpr int kPortReuseThreshold = 2; + DnsUdpTracker(); ~DnsUdpTracker(); @@ -37,6 +51,12 @@ class NET_EXPORT_PRIVATE DnsUdpTracker { void RecordQuery(uint16_t port, uint16_t query_id); void RecordResponseId(uint16_t query_id, uint16_t response_id); + void RecordConnectionError(int connection_error); + + // If true, the entropy from random UDP port and DNS ID has been detected to + // potentially be low, e.g. due to exhaustion of the port pool or mismatches + // on IDs. + bool low_entropy() const { return low_entropy_; } void set_tick_clock_for_testing(base::TickClock* tick_clock) { tick_clock_ = tick_clock; @@ -45,11 +65,18 @@ class NET_EXPORT_PRIVATE DnsUdpTracker { private: struct QueryData; - void PurgeOldQueries(); + void PurgeOldRecords(); void SaveQuery(QueryData query); + void SaveIdMismatch(uint16_t it); + bool low_entropy_ = false; base::circular_deque recent_queries_; + // Times of recent ID mismatches, separated by whether or not the ID was + // recognized from recent queries. + base::circular_deque recent_unrecognized_id_hits_; + base::circular_deque recent_recognized_id_hits_; + const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance(); }; diff --git a/chromium/net/dns/dns_udp_tracker_unittest.cc b/chromium/net/dns/dns_udp_tracker_unittest.cc index 1b5681fde1d..8ed77b6dd98 100644 --- a/chromium/net/dns/dns_udp_tracker_unittest.cc +++ b/chromium/net/dns/dns_udp_tracker_unittest.cc @@ -5,6 +5,7 @@ #include "net/dns/dns_udp_tracker.h" #include "base/test/simple_test_tick_clock.h" +#include "net/base/net_errors.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -22,38 +23,75 @@ class DnsUdpTrackerTest : public testing::Test { base::SimpleTestTickClock test_tick_clock_; }; -// Just testing that nothing crashes given some standard calls. -// TODO(ericorth@chromium.org): Actually test behavior once interesting -// side effects or data access is added. - TEST_F(DnsUdpTrackerTest, MatchingId) { - static const uint16_t kId = 56; - tracker_.RecordQuery(416 /* port */, kId); - tracker_.RecordResponseId(kId /* query_id */, kId /* response_id */); + uint16_t port = 416; + uint16_t id = 56; + for (size_t i = 0; i < DnsUdpTracker::kRecognizedIdMismatchThreshold; ++i) { + tracker_.RecordQuery(++port, ++id); + tracker_.RecordResponseId(id /* query_id */, id /* response_id */); + EXPECT_FALSE(tracker_.low_entropy()); + } } -TEST_F(DnsUdpTrackerTest, ReusedMismatch) { +TEST_F(DnsUdpTrackerTest, ReusedMismatches) { static const uint16_t kOldId = 786; tracker_.RecordQuery(123 /* port */, kOldId); - static const uint16_t kNewId = 3456; - tracker_.RecordQuery(3889 /* port */, kNewId); - tracker_.RecordResponseId(kNewId /* query_id */, kOldId /* response_id */); + uint16_t port = 3889; + uint16_t id = 3456; + for (size_t i = 0; i < DnsUdpTracker::kRecognizedIdMismatchThreshold; ++i) { + EXPECT_FALSE(tracker_.low_entropy()); + tracker_.RecordQuery(++port, ++id); + tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */); + } + + EXPECT_TRUE(tracker_.low_entropy()); } -TEST_F(DnsUdpTrackerTest, ReusedMismatch_Expired) { +TEST_F(DnsUdpTrackerTest, ReusedMismatches_Expired) { static const uint16_t kOldId = 786; tracker_.RecordQuery(123 /* port */, kOldId); test_tick_clock_.Advance(DnsUdpTracker::kMaxAge + base::TimeDelta::FromMilliseconds(1)); - static const uint16_t kNewId = 3456; - tracker_.RecordQuery(3889 /* port */, kNewId); - tracker_.RecordResponseId(kNewId /* query_id */, kOldId /* response_id */); + uint16_t port = 3889; + uint16_t id = 3456; + + // Because the query record has expired, the ID should be treated as + // unrecognized. + for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) { + EXPECT_FALSE(tracker_.low_entropy()); + tracker_.RecordQuery(++port, ++id); + tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */); + } + + EXPECT_TRUE(tracker_.low_entropy()); } -TEST_F(DnsUdpTrackerTest, ReusedMismatch_Full) { +// Test for ID mismatches using an ID still kept in recorded queries, but not +// recent enough to be considered reognized. +TEST_F(DnsUdpTrackerTest, ReusedMismatches_Old) { + static const uint16_t kOldId = 786; + tracker_.RecordQuery(123 /* port */, kOldId); + + test_tick_clock_.Advance(DnsUdpTracker::kMaxRecognizedIdAge + + base::TimeDelta::FromMilliseconds(1)); + + uint16_t port = 3889; + uint16_t id = 3456; + + // Expect the ID to be treated as unrecognized. + for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) { + EXPECT_FALSE(tracker_.low_entropy()); + tracker_.RecordQuery(++port, ++id); + tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */); + } + + EXPECT_TRUE(tracker_.low_entropy()); +} + +TEST_F(DnsUdpTrackerTest, ReusedMismatches_Full) { static const uint16_t kOldId = 786; tracker_.RecordQuery(123 /* port */, kOldId); @@ -63,22 +101,39 @@ TEST_F(DnsUdpTrackerTest, ReusedMismatch_Full) { tracker_.RecordQuery(++port, ++id); } - tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */); + // Expect the ID to be treated as unrecognized. + for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) { + EXPECT_FALSE(tracker_.low_entropy()); + tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */); + } + + EXPECT_TRUE(tracker_.low_entropy()); } -TEST_F(DnsUdpTrackerTest, UnknownMismatch) { - static const uint16_t kId = 4332; - tracker_.RecordQuery(10014 /* port */, kId); - tracker_.RecordResponseId(kId /* query_id */, 743 /* response_id */); +TEST_F(DnsUdpTrackerTest, UnknownMismatches) { + uint16_t port = 10014; + uint16_t id = 4332; + for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) { + EXPECT_FALSE(tracker_.low_entropy()); + tracker_.RecordQuery(++port, ++id); + tracker_.RecordResponseId(id /* query_id */, 743 /* response_id */); + } + + EXPECT_TRUE(tracker_.low_entropy()); } TEST_F(DnsUdpTrackerTest, ReusedPort) { static const uint16_t kPort = 2135; tracker_.RecordQuery(kPort, 579 /* query_id */); - static const uint16_t kId = 580; - tracker_.RecordQuery(kPort, kId); - tracker_.RecordResponseId(kId /* query_id */, kId /* response_id */); + uint16_t id = 580; + for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) { + EXPECT_FALSE(tracker_.low_entropy()); + tracker_.RecordQuery(kPort, ++id); + tracker_.RecordResponseId(id /* query_id */, id /* response_id */); + } + + EXPECT_TRUE(tracker_.low_entropy()); } TEST_F(DnsUdpTrackerTest, ReusedPort_Expired) { @@ -87,9 +142,15 @@ TEST_F(DnsUdpTrackerTest, ReusedPort_Expired) { test_tick_clock_.Advance(DnsUdpTracker::kMaxAge + base::TimeDelta::FromMilliseconds(1)); - static const uint16_t kId = 580; - tracker_.RecordQuery(kPort, kId); - tracker_.RecordResponseId(kId /* query_id */, kId /* response_id */); + + EXPECT_FALSE(tracker_.low_entropy()); + + uint16_t id = 580; + for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) { + tracker_.RecordQuery(kPort, ++id); + tracker_.RecordResponseId(id /* query_id */, id /* response_id */); + EXPECT_FALSE(tracker_.low_entropy()); + } } TEST_F(DnsUdpTrackerTest, ReusedPort_Full) { @@ -102,8 +163,25 @@ TEST_F(DnsUdpTrackerTest, ReusedPort_Full) { tracker_.RecordQuery(++port, ++id); } - tracker_.RecordQuery(kPort, ++id); - tracker_.RecordResponseId(id /* query_id */, id /* response_id */); + EXPECT_FALSE(tracker_.low_entropy()); + + for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) { + tracker_.RecordQuery(kPort, ++id); + tracker_.RecordResponseId(id /* query_id */, id /* response_id */); + EXPECT_FALSE(tracker_.low_entropy()); + } +} + +TEST_F(DnsUdpTrackerTest, ConnectionError) { + tracker_.RecordConnectionError(ERR_FAILED); + + EXPECT_FALSE(tracker_.low_entropy()); +} + +TEST_F(DnsUdpTrackerTest, ConnectionError_InsufficientResources) { + tracker_.RecordConnectionError(ERR_INSUFFICIENT_RESOURCES); + + EXPECT_TRUE(tracker_.low_entropy()); } } // namespace diff --git a/chromium/net/dns/fuzzed_host_resolver_util.cc b/chromium/net/dns/fuzzed_host_resolver_util.cc index 0110c3d3194..feaaa6f5bee 100644 --- a/chromium/net/dns/fuzzed_host_resolver_util.cc +++ b/chromium/net/dns/fuzzed_host_resolver_util.cc @@ -129,7 +129,6 @@ DnsConfig GetFuzzedDnsConfig(FuzzedDataProvider* data_provider) { config.unhandled_options = data_provider->ConsumeBool(); config.append_to_multi_label_name = data_provider->ConsumeBool(); - config.randomize_ports = data_provider->ConsumeBool(); config.ndots = data_provider->ConsumeIntegralInRange(0, 3); config.attempts = data_provider->ConsumeIntegralInRange(1, 3); diff --git a/chromium/net/dns/host_resolver_manager.cc b/chromium/net/dns/host_resolver_manager.cc index 82347fd6bf8..05fd673974a 100644 --- a/chromium/net/dns/host_resolver_manager.cc +++ b/chromium/net/dns/host_resolver_manager.cc @@ -2771,7 +2771,7 @@ HostResolverManager::HostResolverManager( #if defined(OS_WIN) EnsureWinsockInit(); #endif -#if (defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)) || \ +#if (defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_ANDROID)) || \ defined(OS_FUCHSIA) RunLoopbackProbeJob(); #endif @@ -2779,7 +2779,7 @@ HostResolverManager::HostResolverManager( NetworkChangeNotifier::AddConnectionTypeObserver(this); if (system_dns_config_notifier_) system_dns_config_notifier_->AddObserver(this); -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \ +#if defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_OPENBSD) && \ !defined(OS_ANDROID) EnsureDnsReloaderInit(); #endif @@ -3716,7 +3716,7 @@ void HostResolverManager::OnIPAddressChanged() { // Abandon all ProbeJobs. probe_weak_ptr_factory_.InvalidateWeakPtrs(); InvalidateCaches(); -#if (defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)) || \ +#if (defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_ANDROID)) || \ defined(OS_FUCHSIA) RunLoopbackProbeJob(); #endif diff --git a/chromium/net/dns/host_resolver_manager_unittest.cc b/chromium/net/dns/host_resolver_manager_unittest.cc index f467b8e1eac..1fa2b651dcf 100644 --- a/chromium/net/dns/host_resolver_manager_unittest.cc +++ b/chromium/net/dns/host_resolver_manager_unittest.cc @@ -7075,7 +7075,6 @@ TEST_F(HostResolverManagerDnsTest, SetDnsConfigOverrides) { {DnsHostsKey("host", ADDRESS_FAMILY_IPV4), IPAddress(192, 168, 1, 1)}}; overrides.hosts = hosts; overrides.append_to_multi_label_name = false; - overrides.randomize_ports = true; const int ndots = 5; overrides.ndots = ndots; const base::TimeDelta timeout = base::TimeDelta::FromSeconds(10); @@ -7109,7 +7108,6 @@ TEST_F(HostResolverManagerDnsTest, SetDnsConfigOverrides) { EXPECT_EQ(search, overridden_config->search); EXPECT_EQ(hosts, overridden_config->hosts); EXPECT_FALSE(overridden_config->append_to_multi_label_name); - EXPECT_TRUE(overridden_config->randomize_ports); EXPECT_EQ(ndots, overridden_config->ndots); EXPECT_EQ(timeout, overridden_config->timeout); EXPECT_EQ(attempts, overridden_config->attempts); @@ -7191,7 +7189,6 @@ TEST_F(HostResolverManagerDnsTest, SetDnsConfigOverrides_PartialOverride) { EXPECT_EQ(original_config.search, overridden_config->search); EXPECT_EQ(original_config.hosts, overridden_config->hosts); EXPECT_TRUE(overridden_config->append_to_multi_label_name); - EXPECT_FALSE(overridden_config->randomize_ports); EXPECT_EQ(original_config.ndots, overridden_config->ndots); EXPECT_EQ(original_config.timeout, overridden_config->timeout); EXPECT_EQ(original_config.attempts, overridden_config->attempts); diff --git a/chromium/net/dns/host_resolver_proc.cc b/chromium/net/dns/host_resolver_proc.cc index 9b8f30eda6f..9fc966797bd 100644 --- a/chromium/net/dns/host_resolver_proc.cc +++ b/chromium/net/dns/host_resolver_proc.cc @@ -159,7 +159,7 @@ int SystemHostResolverCall(const std::string& host, base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::WILL_BLOCK); -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \ +#if defined(OS_POSIX) && !defined(OS_APPLE) && !defined(OS_OPENBSD) && \ !defined(OS_ANDROID) && !defined(OS_FUCHSIA) DnsReloaderMaybeReload(); #endif diff --git a/chromium/net/dns/httpssvc_metrics.cc b/chromium/net/dns/httpssvc_metrics.cc index 453e2a32ed2..58a033aa3b5 100644 --- a/chromium/net/dns/httpssvc_metrics.cc +++ b/chromium/net/dns/httpssvc_metrics.cc @@ -59,7 +59,6 @@ bool HttpssvcExperimentDomainCache::IsExperimental(base::StringPiece domain) { } bool HttpssvcExperimentDomainCache::IsControl(base::StringPiece domain) { - std::vector control_domains; if (!base::FeatureList::IsEnabled(features::kDnsHttpssvc)) return false; if (features::kDnsHttpssvcControlDomainWildcard.Get()) @@ -153,8 +152,8 @@ void HttpssvcMetrics::RecordIntegrityMetrics() { DCHECK(base::FeatureList::IsEnabled(features::kDnsHttpssvc)); DCHECK(features::kDnsHttpssvcUseIntegrity.Get()); - DCHECK(in_progress_); - in_progress_ = false; + DCHECK(!already_recorded_); + already_recorded_ = true; // We really have no metrics to record without |integrity_resolve_time_| and // |non_integrity_resolve_times_|. If this HttpssvcMetrics is in an @@ -198,14 +197,19 @@ void HttpssvcMetrics::RecordIntegrityCommonMetrics() { non_integrity_resolve_times_.end()); DCHECK(slowest_non_integrity_resolve != non_integrity_resolve_times_.end()); + // It's possible to get here with a zero resolve time in tests. Avoid + // divide-by-zero below by returning early; this data point is invalid anyway. + if (slowest_non_integrity_resolve->is_zero()) + return; + // Compute a percentage showing how much larger the INTEGRITY resolve time was // compared to the slowest A or AAAA query. // // Computation happens on TimeDelta objects, which use CheckedNumeric. This // will crash if the system clock leaps forward several hundred millennia // (numeric_limits::max() microseconds ~= 292,000 years). - const int64_t resolve_time_percent = - (100 * *integrity_resolve_time_) / *slowest_non_integrity_resolve; + const int64_t resolve_time_percent = base::ClampFloor( + *integrity_resolve_time_ / *slowest_non_integrity_resolve * 100); // Scale the value of |resolve_time_percent| by dividing by |kPercentScale|. // Sample values are bounded between 1 and 20. A recorded sample of 10 means diff --git a/chromium/net/dns/httpssvc_metrics.h b/chromium/net/dns/httpssvc_metrics.h index 76e4795cafc..8594b7c54da 100644 --- a/chromium/net/dns/httpssvc_metrics.h +++ b/chromium/net/dns/httpssvc_metrics.h @@ -93,10 +93,10 @@ class NET_EXPORT_PRIVATE HttpssvcMetrics { void set_doh_provider_id(base::Optional doh_provider_id); + const bool expect_intact_; // RecordIntegrityMetrics() will do nothing when |disqualified_| is true. bool disqualified_ = false; - const bool expect_intact_; - bool in_progress_ = true; + bool already_recorded_ = false; base::Optional doh_provider_id_; base::Optional rcode_integrity_; size_t num_integrity_records_ = 0; diff --git a/chromium/net/dns/mdns_cache.cc b/chromium/net/dns/mdns_cache.cc index 53cb2c61982..b23a5a610e8 100644 --- a/chromium/net/dns/mdns_cache.cc +++ b/chromium/net/dns/mdns_cache.cc @@ -9,6 +9,7 @@ #include #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "net/dns/public/dns_protocol.h" #include "net/dns/record_parsed.h" #include "net/dns/record_rdata.h" @@ -26,10 +27,12 @@ constexpr size_t kDefaultEntryLimit = 100'000; // Section 10.1. static const unsigned kZeroTTLSeconds = 1; -MDnsCache::Key::Key(unsigned type, const std::string& name, +MDnsCache::Key::Key(unsigned type, + const std::string& name, const std::string& optional) - : type_(type), name_(name), optional_(optional) { -} + : type_(type), + name_lowercase_(base::ToLowerASCII(name)), + optional_(optional) {} MDnsCache::Key::Key(const MDnsCache::Key& other) = default; @@ -39,12 +42,13 @@ MDnsCache::Key& MDnsCache::Key::operator=(const MDnsCache::Key& other) = MDnsCache::Key::~Key() = default; bool MDnsCache::Key::operator<(const MDnsCache::Key& other) const { - return std::tie(name_, type_, optional_) < - std::tie(other.name_, other.type_, other.optional_); + return std::tie(name_lowercase_, type_, optional_) < + std::tie(other.name_lowercase_, other.type_, other.optional_); } bool MDnsCache::Key::operator==(const MDnsCache::Key& key) const { - return type_ == key.type_ && name_ == key.name_ && optional_ == key.optional_; + return type_ == key.type_ && name_lowercase_ == key.name_lowercase_ && + optional_ == key.optional_; } // static @@ -133,9 +137,10 @@ void MDnsCache::FindDnsRecords(unsigned type, DCHECK(results); results->clear(); + const std::string name_lowercase = base::ToLowerASCII(name); auto i = mdns_cache_.lower_bound(Key(type, name, "")); for (; i != mdns_cache_.end(); ++i) { - if (i->first.name() != name || + if (i->first.name_lowercase() != name_lowercase || (type != 0 && i->first.type() != type)) { break; } diff --git a/chromium/net/dns/mdns_cache.h b/chromium/net/dns/mdns_cache.h index 6e91a9c067d..0dfaa163b39 100644 --- a/chromium/net/dns/mdns_cache.h +++ b/chromium/net/dns/mdns_cache.h @@ -39,14 +39,14 @@ class NET_EXPORT_PRIVATE MDnsCache { bool operator==(const Key& key) const; unsigned type() const { return type_; } - const std::string& name() const { return name_; } + const std::string& name_lowercase() const { return name_lowercase_; } const std::string& optional() const { return optional_; } // Create the cache key corresponding to |record|. static Key CreateFor(const RecordParsed* record); private: unsigned type_; - std::string name_; + std::string name_lowercase_; std::string optional_; }; diff --git a/chromium/net/dns/mdns_cache_unittest.cc b/chromium/net/dns/mdns_cache_unittest.cc index aa83e615097..b7fed7518df 100644 --- a/chromium/net/dns/mdns_cache_unittest.cc +++ b/chromium/net/dns/mdns_cache_unittest.cc @@ -99,6 +99,26 @@ static const uint8_t kTestResponsesGoodbyePacket[] = { 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121 }; +static const uint8_t kTestResponsesDifferentCapitalization[] = { + // Answer 1 + // GHS.l.google.com in DNS format. + 3, 'G', 'H', 'S', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm', + 0x00, 0x00, 0x01, // TYPE is A. + 0x00, 0x01, // CLASS is IN. + 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds. + 0, 4, // RDLENGTH is 4 bytes. + 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121 + + // Answer 2 + // ghs.l.GOOGLE.com in DNS format. + 3, 'g', 'h', 's', 1, 'l', 6, 'G', 'O', 'O', 'G', 'L', 'E', 3, 'c', 'o', 'm', + 0x00, 0x00, 0x01, // TYPE is A. + 0x00, 0x01, // CLASS is IN. + 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds. + 0, 4, // RDLENGTH is 4 bytes. + 74, 125, 95, 122, // RDATA is the IP: 74.125.95.122 +}; + class RecordRemovalMock { public: MOCK_METHOD1(OnRecordRemoved, void(const RecordParsed*)); @@ -402,4 +422,28 @@ TEST_F(MDnsCacheTest, ClearOnOverfilledCleanup) { EXPECT_TRUE(results.empty()); } +TEST_F(MDnsCacheTest, CaseInsensitive) { + DnsRecordParser parser(kTestResponsesDifferentCapitalization, + sizeof(kTestResponsesDifferentCapitalization), 0); + + std::unique_ptr record1; + std::unique_ptr record2; + std::vector results; + + record1 = RecordParsed::CreateFrom(&parser, default_time_); + record2 = RecordParsed::CreateFrom(&parser, default_time_); + EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1))); + EXPECT_EQ(MDnsCache::RecordChanged, + cache_.UpdateDnsRecord(std::move(record2))); + + cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_); + + EXPECT_EQ(1u, results.size()); + EXPECT_EQ("ghs.l.GOOGLE.com", results[0]->name()); + + std::vector results2; + cache_.FindDnsRecords(0, "GHS.L.google.COM", &results2, default_time_); + EXPECT_EQ(results, results2); +} + } // namespace net diff --git a/chromium/net/dns/mdns_client_impl.cc b/chromium/net/dns/mdns_client_impl.cc index 65adb27f93a..89f2c9337ef 100644 --- a/chromium/net/dns/mdns_client_impl.cc +++ b/chromium/net/dns/mdns_client_impl.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/location.h" #include "base/single_thread_task_runner.h" +#include "base/strings/string_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/clock.h" #include "base/time/default_clock.h" @@ -316,9 +317,12 @@ void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) { } // Alert all listeners waiting for the nonexistent RR types. - auto i = listeners_.upper_bound(ListenerKey(record->name(), 0)); - for (; i != listeners_.end() && i->first.first == record->name(); i++) { - if (!rdata->GetBit(i->first.second)) { + ListenerKey key(record->name(), 0); + auto i = listeners_.upper_bound(key); + for (; i != listeners_.end() && + i->first.name_lowercase() == key.name_lowercase(); + i++) { + if (!rdata->GetBit(i->first.type())) { for (auto& observer : *i->second) observer.AlertNsecRecord(); } @@ -330,6 +334,17 @@ void MDnsClientImpl::Core::OnConnectionError(int error) { VLOG(1) << "MDNS OnConnectionError (code: " << error << ")"; } +MDnsClientImpl::Core::ListenerKey::ListenerKey(const std::string& name, + uint16_t type) + : name_lowercase_(base::ToLowerASCII(name)), type_(type) {} + +bool MDnsClientImpl::Core::ListenerKey::operator<( + const MDnsClientImpl::Core::ListenerKey& key) const { + if (name_lowercase_ == key.name_lowercase_) + return type_ < key.type_; + return name_lowercase_ < key.name_lowercase_; +} + void MDnsClientImpl::Core::AlertListeners( MDnsCache::UpdateType update_type, const ListenerKey& key, @@ -574,8 +589,8 @@ void MDnsListenerImpl::ScheduleNextRefresh() { return; } - next_refresh_.Reset(base::Bind(&MDnsListenerImpl::DoRefresh, - AsWeakPtr())); + next_refresh_.Reset( + base::BindRepeating(&MDnsListenerImpl::DoRefresh, AsWeakPtr())); // Schedule refreshes at both 85% and 95% of the original TTL. These will both // be canceled and rescheduled if the record's TTL is updated due to a @@ -731,8 +746,8 @@ bool MDnsTransactionImpl::QueryAndListen() { if (!client_->core()->SendQuery(rrtype_, name_)) return false; - timeout_.Reset(base::Bind(&MDnsTransactionImpl::SignalTransactionOver, - AsWeakPtr())); + timeout_.Reset( + base::BindOnce(&MDnsTransactionImpl::SignalTransactionOver, AsWeakPtr())); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, timeout_.callback(), kTransactionTimeout); diff --git a/chromium/net/dns/mdns_client_impl.h b/chromium/net/dns/mdns_client_impl.h index 0efda0b9a42..39606f970a0 100644 --- a/chromium/net/dns/mdns_client_impl.h +++ b/chromium/net/dns/mdns_client_impl.h @@ -154,7 +154,19 @@ class NET_EXPORT_PRIVATE MDnsClientImpl : public MDnsClient { private: FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL); - typedef std::pair ListenerKey; + class ListenerKey { + public: + ListenerKey(const std::string& name, uint16_t type); + ListenerKey(const ListenerKey&) = default; + ListenerKey(ListenerKey&&) = default; + bool operator<(const ListenerKey& key) const; + const std::string& name_lowercase() const { return name_lowercase_; } + uint16_t type() const { return type_; } + + private: + std::string name_lowercase_; + uint16_t type_; + }; typedef base::ObserverList::Unchecked ObserverListType; typedef std::map> ListenerMap; @@ -328,7 +340,7 @@ class MDnsTransactionImpl : public base::SupportsWeakPtr, MDnsTransaction::ResultCallback callback_; std::unique_ptr listener_; - base::CancelableCallback timeout_; + base::CancelableOnceCallback timeout_; MDnsClientImpl* client_; diff --git a/chromium/net/dns/mdns_client_unittest.cc b/chromium/net/dns/mdns_client_unittest.cc index 35342711af0..6ddb5c58eb8 100644 --- a/chromium/net/dns/mdns_client_unittest.cc +++ b/chromium/net/dns/mdns_client_unittest.cc @@ -76,6 +76,32 @@ const uint8_t kSamplePacket1[] = { 0x24, 0x75, 0x00, 0x08, // RDLENGTH is 8 bytes. 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x32}; +const uint8_t kSamplePacket1WithCapitalization[] = { + // Header + 0x00, 0x00, // ID is zeroed out + 0x81, 0x80, // Standard query response, RA, no error + 0x00, 0x00, // No questions (for simplicity) + 0x00, 0x02, // 2 RRs (answers) + 0x00, 0x00, // 0 authority RRs + 0x00, 0x00, // 0 additional RRs + + // Answer 1 + 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 'T', 'C', 'P', 0x05, + 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR. + 0x00, 0x01, // CLASS is IN. + 0x00, 0x00, // TTL (4 bytes) is 1 second; + 0x00, 0x01, 0x00, 0x08, // RDLENGTH is 8 bytes. + 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x0c, + + // Answer 2 + 0x08, '_', 'P', 'r', 'i', 'n', 't', 'e', 'R', 0xc0, + 0x14, // Pointer to "._tcp.local" + 0x00, 0x0c, // TYPE is PTR. + 0x00, 0x01, // CLASS is IN. + 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds. + 0x24, 0x75, 0x00, 0x08, // RDLENGTH is 8 bytes. + 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x32}; + const uint8_t kCorruptedPacketBadQuestion[] = { // Header 0x00, 0x00, // ID is zeroed out @@ -248,6 +274,22 @@ const uint8_t kQueryPacketPrivet[] = { 0x00, 0x01, // CLASS is IN. }; +const uint8_t kQueryPacketPrivetWithCapitalization[] = { + // Header + 0x00, 0x00, // ID is zeroed out + 0x00, 0x00, // No flags. + 0x00, 0x01, // One question. + 0x00, 0x00, // 0 RRs (answers) + 0x00, 0x00, // 0 authority RRs + 0x00, 0x00, // 0 additional RRs + + // Question + // This part is echoed back from the respective query. + 0x07, '_', 'P', 'R', 'I', 'V', 'E', 'T', 0x04, '_', 't', 'c', 'p', 0x05, + 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR. + 0x00, 0x01, // CLASS is IN. +}; + const uint8_t kQueryPacketPrivetA[] = { // Header 0x00, 0x00, // ID is zeroed out @@ -469,8 +511,8 @@ void MDnsTest::DeleteBothListeners() { } void MDnsTest::RunFor(base::TimeDelta time_period) { - base::CancelableCallback callback(base::Bind(&MDnsTest::Stop, - base::Unretained(this))); + base::CancelableOnceCallback callback( + base::BindOnce(&MDnsTest::Stop, base::Unretained(this))); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, callback.callback(), time_period); @@ -525,6 +567,48 @@ TEST_F(MDnsTest, PassiveListeners) { listener_printer.reset(); } +TEST_F(MDnsTest, PassiveListenersWithCapitalization) { + StrictMock delegate_privet; + StrictMock delegate_printer; + + PtrRecordCopyContainer record_privet; + PtrRecordCopyContainer record_printer; + + std::unique_ptr listener_privet = test_client_->CreateListener( + dns_protocol::kTypePTR, "_privet._tcp.LOCAL", &delegate_privet); + std::unique_ptr listener_printer = test_client_->CreateListener( + dns_protocol::kTypePTR, "_prinTER._Tcp.Local", &delegate_printer); + + ASSERT_TRUE(listener_privet->Start()); + ASSERT_TRUE(listener_printer->Start()); + + // Send the same packet twice to ensure no records are double-counted. + + EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) + .Times(Exactly(1)) + .WillOnce( + Invoke(&record_privet, &PtrRecordCopyContainer::SaveWithDummyArg)); + + EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) + .Times(Exactly(1)) + .WillOnce( + Invoke(&record_printer, &PtrRecordCopyContainer::SaveWithDummyArg)); + + SimulatePacketReceive(kSamplePacket1WithCapitalization, + sizeof(kSamplePacket1WithCapitalization)); + SimulatePacketReceive(kSamplePacket1WithCapitalization, + sizeof(kSamplePacket1WithCapitalization)); + + EXPECT_TRUE(record_privet.IsRecordWith("_privet._TCP.local", + "hello._privet._TCP.local")); + + EXPECT_TRUE(record_printer.IsRecordWith("_PrinteR._TCP.local", + "hello._PrinteR._TCP.local")); + + listener_privet.reset(); + listener_printer.reset(); +} + TEST_F(MDnsTest, PassiveListenersCacheCleanup) { StrictMock delegate_privet; @@ -709,6 +793,34 @@ TEST_F(MDnsTest, TransactionWithEmptyCache) { "hello._privet._tcp.local")); } +TEST_F(MDnsTest, TransactionWithEmptyCacheAndCapitalization) { + ExpectPacket(kQueryPacketPrivetWithCapitalization, + sizeof(kQueryPacketPrivetWithCapitalization)); + + std::unique_ptr transaction_privet = + test_client_->CreateTransaction( + dns_protocol::kTypePTR, "_PRIVET._tcp.local", + MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE | + MDnsTransaction::SINGLE_RESULT, + base::BindRepeating(&MDnsTest::MockableRecordCallback, + base::Unretained(this))); + + ASSERT_TRUE(transaction_privet->Start()); + + PtrRecordCopyContainer record_privet; + + EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) + .Times(Exactly(1)) + .WillOnce( + Invoke(&record_privet, &PtrRecordCopyContainer::SaveWithDummyArg)); + + SimulatePacketReceive(kSamplePacket1WithCapitalization, + sizeof(kSamplePacket1WithCapitalization)); + + EXPECT_TRUE(record_privet.IsRecordWith("_privet._TCP.local", + "hello._privet._TCP.local")); +} + TEST_F(MDnsTest, TransactionCacheOnlyNoResult) { std::unique_ptr transaction_privet = test_client_->CreateTransaction( diff --git a/chromium/net/dns/public/util.cc b/chromium/net/dns/public/util.cc index 5aab840a2b3..d93cf0de961 100644 --- a/chromium/net/dns/public/util.cc +++ b/chromium/net/dns/public/util.cc @@ -77,7 +77,7 @@ IPEndPoint GetMdnsReceiveEndPoint(AddressFamily address_family) { // CrOS as described in crbug.com/931916, and the following is a temporary // mitigation to reconcile the two issues. Remove this after closing // crbug.com/899310. -#if defined(OS_WIN) || defined(OS_FUCHSIA) || defined(OS_MACOSX) +#if defined(OS_WIN) || defined(OS_FUCHSIA) || defined(OS_APPLE) // With Windows, binding to a mulitcast group address is not allowed. // Multicast messages will be received appropriate to the multicast groups the // socket has joined. Sockets intending to receive multicast messages should @@ -93,12 +93,12 @@ IPEndPoint GetMdnsReceiveEndPoint(AddressFamily address_family) { NOTREACHED(); return IPEndPoint(); } -#else // !(defined(OS_WIN) || defined(OS_FUCHSIA)) || defined(OS_MACOSX) +#else // !(defined(OS_WIN) || defined(OS_FUCHSIA)) || defined(OS_APPLE) // With POSIX, any socket can receive messages for multicast groups joined by // any socket on the system. Sockets intending to receive messages for a // specific multicast group should bind to that group address. return GetMdnsGroupEndPoint(address_family); -#endif // !(defined(OS_WIN) || defined(OS_FUCHSIA)) || defined(OS_MACOSX) +#endif // !(defined(OS_WIN) || defined(OS_FUCHSIA)) || defined(OS_APPLE) } } // namespace dns_util diff --git a/chromium/net/dns/resolve_context.cc b/chromium/net/dns/resolve_context.cc index 3b15cf320ec..57b75f6566a 100644 --- a/chromium/net/dns/resolve_context.cc +++ b/chromium/net/dns/resolve_context.cc @@ -408,7 +408,7 @@ void ResolveContext::RecordRttForUma(size_t server_index, // continue in parallel with new attempts made by the transaction. Scale // the ratio up by 10 for sub-integer granularity. // TODO(crbug.com/1105138): Remove after determining good timeout logic. - int timeout_ratio = 10 * rtt / base_timeout; + int timeout_ratio = base::ClampFloor(rtt / base_timeout * 10); UMA_HISTOGRAM_COUNTS_1000( "Net.DNS.DnsTransaction.SecureValidated.SuccessTimeoutRatio", timeout_ratio); diff --git a/chromium/net/dns/resolve_context_unittest.cc b/chromium/net/dns/resolve_context_unittest.cc index 5de6a10e3f3..2b432fc378a 100644 --- a/chromium/net/dns/resolve_context_unittest.cc +++ b/chromium/net/dns/resolve_context_unittest.cc @@ -23,7 +23,7 @@ #include "net/dns/dns_config.h" #include "net/dns/dns_server_iterator.h" #include "net/dns/dns_session.h" -#include "net/dns/dns_socket_pool.h" +#include "net/dns/dns_socket_allocator.h" #include "net/dns/host_cache.h" #include "net/dns/host_resolver_source.h" #include "net/dns/public/dns_over_https_server_config.h" @@ -46,12 +46,12 @@ class ResolveContextTest : public TestWithTaskEnvironment { scoped_refptr CreateDnsSession(const DnsConfig& config) { auto null_random_callback = base::BindRepeating([](int, int) -> int { IMMEDIATE_CRASH(); }); - std::unique_ptr dns_socket_pool = - DnsSocketPool::CreateNull(socket_factory_.get(), null_random_callback); + auto dns_socket_allocator = std::make_unique( + socket_factory_.get(), config.nameservers, nullptr /* net_log */); - return base::MakeRefCounted(config, std::move(dns_socket_pool), - null_random_callback, - nullptr /* netlog */); + return base::MakeRefCounted( + config, std::move(dns_socket_allocator), null_random_callback, + nullptr /* netlog */); } protected: diff --git a/chromium/net/dns/serial_worker_unittest.cc b/chromium/net/dns/serial_worker_unittest.cc index d7ce1f8fc23..061b54a0f29 100644 --- a/chromium/net/dns/serial_worker_unittest.cc +++ b/chromium/net/dns/serial_worker_unittest.cc @@ -6,11 +6,11 @@ #include "base/bind.h" #include "base/location.h" -#include "base/message_loop/message_loop_current.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" +#include "base/task/current_thread.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "net/test/test_with_task_environment.h" @@ -158,7 +158,7 @@ TEST_F(SerialWorkerTest, ExecuteAndSerializeReads) { WaitForWork(); RunUntilBreak("OnWorkFinished"); - EXPECT_TRUE(base::MessageLoopCurrent::Get()->IsIdleForTesting()); + EXPECT_TRUE(base::CurrentThread::Get()->IsIdleForTesting()); } // Schedule two calls. OnWork checks if it is called serially. @@ -171,7 +171,7 @@ TEST_F(SerialWorkerTest, ExecuteAndSerializeReads) { RunUntilBreak("OnWorkFinished"); // No more tasks should remain. - EXPECT_TRUE(base::MessageLoopCurrent::Get()->IsIdleForTesting()); + EXPECT_TRUE(base::CurrentThread::Get()->IsIdleForTesting()); } } // namespace -- cgit v1.2.1