diff --git a/build/patches/Partition-dns-requests-by-topframe-nik.patch b/build/patches/Partition-dns-requests-by-topframe-nik.patch new file mode 100644 index 00000000..8c81eebb --- /dev/null +++ b/build/patches/Partition-dns-requests-by-topframe-nik.patch @@ -0,0 +1,472 @@ +From: uazo +Date: Wed, 23 Mar 2022 08:37:47 +0000 +Subject: Partition dns requests by top-frame nik + +--- + chrome/browser/about_flags.cc | 12 ++++++++++++ + chrome/browser/flag_descriptions.cc | 9 +++++++++ + chrome/browser/flag_descriptions.h | 6 ++++++ + net/base/features.cc | 6 ++++++ + net/base/features.h | 6 ++++++ + net/base/isolation_info.cc | 24 +++++++++++++++++++++++- + net/base/isolation_info.h | 7 +++++++ + net/base/isolation_info.proto | 4 +++- + net/base/network_isolation_key.cc | 16 ++++++++++++++++ + net/base/network_isolation_key.h | 19 +++++++++++++++---- + net/dns/dns_transaction.cc | 24 ++++++++++++++++++++---- + net/dns/dns_transaction.h | 4 +++- + net/dns/host_resolver_manager.cc | 21 +++++++++++++++++---- + net/socket/ssl_client_socket_impl.cc | 6 ++++++ + 14 files changed, 149 insertions(+), 15 deletions(-) + +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -7332,6 +7332,18 @@ const FeatureEntry kFeatureEntries[] = { + FEATURE_VALUE_TYPE(features::kUIDebugTools), + }, + #endif ++ {"dns-request-partitioning", ++ flag_descriptions::kSplitDnsByNetworkIsolationKeyName, ++ flag_descriptions::kSplitDnsByNetworkIsolationKeyDescription, ++ kOsWin | kOsLinux | kOsMac | kOsCrOS | kOsAndroid | kOsFuchsia, ++ FEATURE_VALUE_TYPE(net::features::kSplitDnsByNetworkIsolationKey)}, ++ ++ {"dns-request-partitioning-log", ++ flag_descriptions::kLogSplitDnsByNetworkIsolationKeyName, ++ flag_descriptions::kLogSplitDnsByNetworkIsolationKeyDescription, ++ kOsWin | kOsLinux | kOsMac | kOsCrOS | kOsAndroid | kOsFuchsia, ++ FEATURE_VALUE_TYPE(net::features::kLogSplitDnsByNetworkIsolationKey)}, ++ + {"http-cache-partitioning", + flag_descriptions::kSplitCacheByNetworkIsolationKeyName, + flag_descriptions::kSplitCacheByNetworkIsolationKeyDescription, +diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc +--- a/chrome/browser/flag_descriptions.cc ++++ b/chrome/browser/flag_descriptions.cc +@@ -2448,6 +2448,15 @@ const char kWebOTPCrossDeviceName[] = "WebOTP Cross Device"; + const char kWebOTPCrossDeviceDescription[] = + "Enable the WebOTP API to work across devices"; + ++const char kSplitDnsByNetworkIsolationKeyName[] = "DNS Requests Partitioning"; ++const char kSplitDnsByNetworkIsolationKeyDescription[] = ++ "Partitions the dns requests by (top-level site) to " ++ "disallow dns cross-site tracking."; ++ ++const char kLogSplitDnsByNetworkIsolationKeyName[] = "Log DNS Requests Partitioning"; ++const char kLogSplitDnsByNetworkIsolationKeyDescription[] = ++ "Log requests done by dns"; ++ + const char kSplitCacheByNetworkIsolationKeyName[] = "HTTP Cache Partitioning"; + const char kSplitCacheByNetworkIsolationKeyDescription[] = + "Partitions the HTTP Cache by (top-level site, current-frame site) to " +diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h +--- a/chrome/browser/flag_descriptions.h ++++ b/chrome/browser/flag_descriptions.h +@@ -1408,6 +1408,12 @@ extern const char kSmoothScrollingDescription[]; + extern const char kWebOTPCrossDeviceName[]; + extern const char kWebOTPCrossDeviceDescription[]; + ++extern const char kSplitDnsByNetworkIsolationKeyName[]; ++extern const char kSplitDnsByNetworkIsolationKeyDescription[]; ++ ++extern const char kLogSplitDnsByNetworkIsolationKeyName[]; ++extern const char kLogSplitDnsByNetworkIsolationKeyDescription[]; ++ + extern const char kSplitCacheByNetworkIsolationKeyName[]; + extern const char kSplitCacheByNetworkIsolationKeyDescription[]; + +diff --git a/net/base/features.cc b/net/base/features.cc +--- a/net/base/features.cc ++++ b/net/base/features.cc +@@ -107,6 +107,12 @@ const base::Feature kIsCleartextPermitted{"IsCleartextPermitted", + const base::Feature kNetworkQualityEstimator{"NetworkQualityEstimator", + base::FEATURE_DISABLED_BY_DEFAULT}; + ++const base::Feature kSplitDnsByNetworkIsolationKey{"SplitDnsByNetworkIsolationKey", ++ base::FEATURE_ENABLED_BY_DEFAULT}; ++ ++const base::Feature kLogSplitDnsByNetworkIsolationKey{"LogSplitDnsByNetworkIsolationKey", ++ base::FEATURE_DISABLED_BY_DEFAULT}; ++ + const base::Feature kSplitCacheByIncludeCredentials{ + "SplitCacheByIncludeCredentials", base::FEATURE_DISABLED_BY_DEFAULT}; + +diff --git a/net/base/features.h b/net/base/features.h +--- a/net/base/features.h ++++ b/net/base/features.h +@@ -170,6 +170,12 @@ NET_EXPORT extern const base::Feature kEncryptedClientHello; + // quality estimator (NQE). + NET_EXPORT extern const base::Feature kNetworkQualityEstimator; + ++// Splits dns requests by the request's NetworkIsolationKey. ++NET_EXPORT extern const base::Feature kSplitDnsByNetworkIsolationKey; ++ ++// Log dns requests by request ++NET_EXPORT extern const base::Feature kLogSplitDnsByNetworkIsolationKey; ++ + // Splits cache entries by the request's includeCredentials. + NET_EXPORT extern const base::Feature kSplitCacheByIncludeCredentials; + +diff --git a/net/base/isolation_info.cc b/net/base/isolation_info.cc +--- a/net/base/isolation_info.cc ++++ b/net/base/isolation_info.cc +@@ -115,6 +115,23 @@ IsolationInfo IsolationInfo::CreateTransient() { + absl::nullopt /* party_context */); + } + ++IsolationInfo IsolationInfo::CreateTransientForDNS() { ++ IsolationInfo info = CreateTransient(); ++ info.network_isolation_key_ = ++ NetworkIsolationKey::CreateForDNS(info.network_isolation_key_); ++ info.is_dns_ = true; ++ return info; ++} ++ ++IsolationInfo IsolationInfo::CreateTransientForDNS( ++ const net::NetworkIsolationKey network_isolation_key) { ++ IsolationInfo info = CreateTransient(); ++ info.network_isolation_key_ = ++ NetworkIsolationKey::CreateForDNS(network_isolation_key); ++ info.is_dns_ = true; ++ return info; ++} ++ + absl::optional IsolationInfo::Deserialize( + const std::string& serialized) { + proto::IsolationInfo proto; +@@ -137,11 +154,14 @@ absl::optional IsolationInfo::Deserialize( + } + } + +- return IsolationInfo::CreateIfConsistent( ++ absl::optional info = IsolationInfo::CreateIfConsistent( + static_cast(proto.request_type()), + std::move(top_frame_origin), std::move(frame_origin), + SiteForCookies::FromUrl(GURL(proto.site_for_cookies())), + std::move(party_context), nullptr); ++ if (info && proto.has_is_for_dns()) ++ info->is_dns_ = proto.is_for_dns(); ++ return info; + } + + IsolationInfo IsolationInfo::Create( +@@ -259,6 +279,8 @@ std::string IsolationInfo::Serialize() const { + } + } + ++ info.set_is_for_dns(is_dns_); ++ + return info.SerializeAsString(); + } + +diff --git a/net/base/isolation_info.h b/net/base/isolation_info.h +--- a/net/base/isolation_info.h ++++ b/net/base/isolation_info.h +@@ -206,6 +206,10 @@ class NET_EXPORT IsolationInfo { + // an empty string. + std::string Serialize() const; + ++ static IsolationInfo CreateTransientForDNS(); ++ static IsolationInfo CreateTransientForDNS(net::NetworkIsolationKey network_isolation_key); ++ bool IsDns() { return is_dns_; } ++ + private: + IsolationInfo(RequestType request_type, + const absl::optional& top_frame_origin, +@@ -248,6 +252,9 @@ class NET_EXPORT IsolationInfo { + // excluded to make it easier to update on subframe redirects. + absl::optional> party_context_; + ++ // Mark isolation info for use in dns requests ++ bool is_dns_ = false; ++ + // Mojo serialization code needs to access internal party_context_ field. + friend struct mojo::StructTraits; +diff --git a/net/base/isolation_info.proto b/net/base/isolation_info.proto +--- a/net/base/isolation_info.proto ++++ b/net/base/isolation_info.proto +@@ -16,4 +16,6 @@ message IsolationInfo { + + message PartyContext { repeated string site = 1; } + optional PartyContext party_context = 5; +-} +\ No newline at end of file ++ ++ optional bool is_for_dns = 6; ++} +diff --git a/net/base/network_isolation_key.cc b/net/base/network_isolation_key.cc +--- a/net/base/network_isolation_key.cc ++++ b/net/base/network_isolation_key.cc +@@ -60,6 +60,18 @@ NetworkIsolationKey& NetworkIsolationKey::operator=( + NetworkIsolationKey& NetworkIsolationKey::operator=( + NetworkIsolationKey&& network_isolation_key) = default; + ++/* static */ ++NetworkIsolationKey NetworkIsolationKey::CreateForDNS( ++ const NetworkIsolationKey& network_isolation_key) { ++ SchemefulSite top_frame_site; ++ if(network_isolation_key.top_frame_site_.has_value()) ++ top_frame_site = SchemefulSite(network_isolation_key.top_frame_site_.value()); ++ NetworkIsolationKey key(top_frame_site, top_frame_site); ++ key.nonce_ = network_isolation_key.nonce_; ++ key.is_dns_ = true; ++ return key; ++} ++ + NetworkIsolationKey NetworkIsolationKey::CreateTransient() { + SchemefulSite site_with_opaque_origin; + return NetworkIsolationKey(site_with_opaque_origin, site_with_opaque_origin); +@@ -91,6 +103,10 @@ std::string NetworkIsolationKey::ToDebugString() const { + return_string += " (with nonce " + nonce_->ToString() + ")"; + } + ++ if (is_dns_) { ++ return_string += " (dns)"; ++ } ++ + return return_string; + } + +diff --git a/net/base/network_isolation_key.h b/net/base/network_isolation_key.h +--- a/net/base/network_isolation_key.h ++++ b/net/base/network_isolation_key.h +@@ -79,8 +79,8 @@ class NET_EXPORT NetworkIsolationKey { + + // Compare keys for equality, true if all enabled fields are equal. + bool operator==(const NetworkIsolationKey& other) const { +- return std::tie(top_frame_site_, frame_site_, nonce_) == +- std::tie(other.top_frame_site_, other.frame_site_, other.nonce_); ++ return std::tie(top_frame_site_, frame_site_, nonce_, is_dns_) == ++ std::tie(other.top_frame_site_, other.frame_site_, other.nonce_, other.is_dns_); + } + + // Compare keys for inequality, true if any enabled field varies. +@@ -90,8 +90,8 @@ class NET_EXPORT NetworkIsolationKey { + + // Provide an ordering for keys based on all enabled fields. + bool operator<(const NetworkIsolationKey& other) const { +- return std::tie(top_frame_site_, frame_site_, nonce_) < +- std::tie(other.top_frame_site_, other.frame_site_, other.nonce_); ++ return std::tie(top_frame_site_, frame_site_, nonce_, is_dns_) < ++ std::tie(other.top_frame_site_, other.frame_site_, other.nonce_, other.is_dns_); + } + + // Returns the string representation of the key, which is the string +@@ -141,6 +141,15 @@ class NET_EXPORT NetworkIsolationKey { + const base::Value& value, + NetworkIsolationKey* out_network_isolation_key); + ++ // Create a network isolation key for the dns subsystem ++ // only with top_frame_site of source, so subframes ++ // will use the same dns connection of the top frame ++ // different top frames will use different nik ++ static NetworkIsolationKey CreateForDNS(const NetworkIsolationKey& network_isolation_key); ++ ++ // Returns true if the nik is created for dns requests ++ bool IsDns() const { return is_dns_; } ++ + private: + // Whether this key has opaque origins or a nonce. + bool IsOpaque() const; +@@ -150,6 +159,8 @@ class NET_EXPORT NetworkIsolationKey { + static absl::optional SerializeSiteWithNonce( + const SchemefulSite& site); + ++ bool is_dns_ = false; ++ + // The origin/etld+1 of the top frame of the page making the request. + absl::optional top_frame_site_; + +diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc +--- a/net/dns/dns_transaction.cc ++++ b/net/dns/dns_transaction.cc +@@ -38,6 +38,7 @@ + #include "net/base/backoff_entry.h" + #include "net/base/completion_once_callback.h" + #include "net/base/elements_upload_data_stream.h" ++#include "net/base/features.h" + #include "net/base/idempotency.h" + #include "net/base/io_buffer.h" + #include "net/base/ip_address.h" +@@ -442,6 +443,12 @@ class DnsHTTPAttempt : public DnsAttempt, public URLRequest::Delegate { + LOAD_MINIMAL_HEADERS | LOAD_BYPASS_PROXY); + request_->set_allow_credentials(false); + request_->set_isolation_info(isolation_info); ++ if (base::FeatureList::IsEnabled(net::features::kLogSplitDnsByNetworkIsolationKey)) { ++ LOG(INFO) << "DNS: Request " ++ << DnsDomainToString(query_->qname()).value_or("") ++ << " nik: " ++ << isolation_info.network_isolation_key().ToDebugString(); ++ } + } + + DnsHTTPAttempt(const DnsHTTPAttempt&) = delete; +@@ -1012,6 +1019,8 @@ class DnsOverHttpsProbeRunner : public DnsProbeRunner { + session_.get(), doh_server_index, formatted_probe_hostname_, + dns_protocol::kTypeA, nullptr /* opt_rdata */, + &probe_stats->probe_attempts, context_->url_request_context(), ++ base::FeatureList::IsEnabled(net::features::kSplitDnsByNetworkIsolationKey) ? ++ IsolationInfo::CreateTransientForDNS() : + context_->isolation_info(), RequestPriority::DEFAULT_PRIORITY); + + DnsAttempt* probe_attempt = probe_stats->probe_attempts.back().get(); +@@ -1103,7 +1112,8 @@ class DnsTransactionImpl : public DnsTransaction, + bool secure, + SecureDnsMode secure_dns_mode, + ResolveContext* resolve_context, +- bool fast_timeout) ++ bool fast_timeout, ++ const NetworkIsolationKey& network_isolation_key) + : session_(session), + hostname_(std::move(hostname)), + qtype_(qtype), +@@ -1117,7 +1127,8 @@ class DnsTransactionImpl : public DnsTransaction, + attempts_count_(0), + had_tcp_retry_(false), + resolve_context_(resolve_context->AsSafeRef()), +- request_priority_(DEFAULT_PRIORITY) { ++ request_priority_(DEFAULT_PRIORITY), ++ network_isolation_key_(network_isolation_key) { + DCHECK(session_.get()); + DCHECK(!hostname_.empty()); + DCHECK(!callback_.is_null()); +@@ -1365,6 +1376,8 @@ class DnsTransactionImpl : public DnsTransaction, + ConstructDnsHTTPAttempt( + session_.get(), doh_server_index, qnames_.front(), qtype_, opt_rdata_, + &attempts_, resolve_context_->url_request_context(), ++ base::FeatureList::IsEnabled(net::features::kSplitDnsByNetworkIsolationKey) ? ++ IsolationInfo::CreateTransientForDNS(network_isolation_key_) : + resolve_context_->isolation_info(), request_priority_); + ++attempts_count_; + int rv = attempts_.back()->Start(base::BindOnce( +@@ -1691,6 +1704,8 @@ class DnsTransactionImpl : public DnsTransaction, + base::SafeRef resolve_context_; + RequestPriority request_priority_; + ++ const NetworkIsolationKey& network_isolation_key_; ++ + THREAD_CHECKER(thread_checker_); + }; + +@@ -1712,11 +1727,12 @@ class DnsTransactionFactoryImpl : public DnsTransactionFactory { + bool secure, + SecureDnsMode secure_dns_mode, + ResolveContext* resolve_context, +- bool fast_timeout) override { ++ bool fast_timeout, ++ const NetworkIsolationKey& network_isolation_key) override { + return std::make_unique( + session_.get(), std::move(hostname), qtype, std::move(callback), + net_log, opt_rdata_.get(), secure, secure_dns_mode, resolve_context, +- fast_timeout); ++ fast_timeout, network_isolation_key); + } + + std::unique_ptr CreateDohProbeRunner( +diff --git a/net/dns/dns_transaction.h b/net/dns/dns_transaction.h +--- a/net/dns/dns_transaction.h ++++ b/net/dns/dns_transaction.h +@@ -14,6 +14,7 @@ + #include "base/memory/weak_ptr.h" + #include "base/time/time.h" + #include "net/base/request_priority.h" ++#include "net/base/network_isolation_key.h" + #include "net/dns/public/secure_dns_mode.h" + #include "net/dns/record_rdata.h" + #include "third_party/abseil-cpp/absl/types/optional.h" +@@ -119,7 +120,8 @@ class NET_EXPORT_PRIVATE DnsTransactionFactory { + bool secure, + SecureDnsMode secure_dns_mode, + ResolveContext* resolve_context, +- bool fast_timeout) = 0; ++ bool fast_timeout, ++ const NetworkIsolationKey& network_isolation_key) = 0; + + // Creates a runner to run the DoH probe sequence for all configured DoH + // resolvers. +diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc +--- a/net/dns/host_resolver_manager.cc ++++ b/net/dns/host_resolver_manager.cc +@@ -1332,7 +1332,8 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr { + Delegate* delegate, + const NetLogWithSource& job_net_log, + const base::TickClock* tick_clock, +- bool fallback_available) ++ bool fallback_available, ++ const NetworkIsolationKey& network_isolation_key) + : client_(client), + host_(std::move(host)), + resolve_context_(resolve_context->AsSafeRef()), +@@ -1342,7 +1343,8 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr { + net_log_(job_net_log), + tick_clock_(tick_clock), + task_start_time_(tick_clock_->NowTicks()), +- fallback_available_(fallback_available) { ++ fallback_available_(fallback_available), ++ network_isolation_key_(network_isolation_key) { + DCHECK(client_); + DCHECK(delegate_); + +@@ -1471,7 +1473,8 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr { + base::Unretained(this), tick_clock_->NowTicks(), + dns_query_type), + net_log_, secure_, secure_dns_mode_, &*resolve_context_, +- fallback_available_ /* fast_timeout */); ++ fallback_available_ /* fast_timeout */, ++ network_isolation_key_); + trans->SetRequestPriority(delegate_->priority()); + return trans; + } +@@ -1978,6 +1981,8 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr { + // task completes unsuccessfully. Used as a signal that underlying + // transactions should timeout more quickly. + bool fallback_available_; ++ ++ const NetworkIsolationKey network_isolation_key_; + }; + + //----------------------------------------------------------------------------- +@@ -2538,7 +2543,8 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, + dns_task_ = std::make_unique( + resolver_->dns_client_.get(), key_.host, key_.query_types, + &*key_.resolve_context, secure, key_.secure_dns_mode, this, net_log_, +- tick_clock_, !tasks_.empty() /* fallback_available */); ++ tick_clock_, !tasks_.empty() /* fallback_available */, ++ key_.network_isolation_key); + dns_task_->StartNextTransaction(); + // Schedule a second transaction, if needed. DoH queries can bypass the + // dispatcher and start all of their transactions immediately. +@@ -2809,6 +2815,13 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, + net_log_.EndEventWithNetErrorCode( + NetLogEventType::HOST_RESOLVER_MANAGER_JOB, results.error()); + ++ if (base::FeatureList::IsEnabled(net::features::kLogSplitDnsByNetworkIsolationKey)) { ++ LOG(INFO) << "DNS: CompleteRequests " ++ << GetHostname(key_.host) ++ << " key=" ++ << key_.network_isolation_key.ToDebugString(); ++ } ++ + // Handle all caching before completing requests as completing requests may + // start new requests that rely on cached results. + if (allow_cache) +diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc +--- a/net/socket/ssl_client_socket_impl.cc ++++ b/net/socket/ssl_client_socket_impl.cc +@@ -432,6 +432,12 @@ void SSLClientSocketImpl::Log_ssl_session_data(const std::string& tag, SSL_SESSI + SSLClientSocketImpl::~SSLClientSocketImpl() { + if (base::FeatureList::IsEnabled(net::features::kLogTLSResumption)) + Log_ssl_session_data("Disconnect", NULL); ++ if (base::FeatureList::IsEnabled(net::features::kLogSplitDnsByNetworkIsolationKey) && ++ ssl_config_.network_isolation_key.IsDns()) { ++ LOG(INFO) << "DNS: Disconnected " ++ << host_and_port_.ToString() << " " ++ << ssl_config_.network_isolation_key.ToDebugString(); ++ } + Disconnect(); + } + +-- +2.25.1