Partition dns requests by top-frame nik

This commit is contained in:
Carmelo Messina 2022-04-13 16:36:38 +02:00
parent 2de7773a24
commit 784450cdd3
No known key found for this signature in database
GPG key ID: 968894BE688289FD

View file

@ -0,0 +1,472 @@
From: uazo <uazo@users.noreply.github.com>
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> IsolationInfo::Deserialize(
const std::string& serialized) {
proto::IsolationInfo proto;
@@ -137,11 +154,14 @@ absl::optional<IsolationInfo> IsolationInfo::Deserialize(
}
}
- return IsolationInfo::CreateIfConsistent(
+ absl::optional<IsolationInfo> info = IsolationInfo::CreateIfConsistent(
static_cast<RequestType>(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<url::Origin>& top_frame_origin,
@@ -248,6 +252,9 @@ class NET_EXPORT IsolationInfo {
// excluded to make it easier to update on subframe redirects.
absl::optional<std::set<SchemefulSite>> 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<network::mojom::IsolationInfoDataView,
IsolationInfo>;
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<std::string> SerializeSiteWithNonce(
const SchemefulSite& site);
+ bool is_dns_ = false;
+
// The origin/etld+1 of the top frame of the page making the request.
absl::optional<SchemefulSite> 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<ResolveContext> 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<DnsTransactionImpl>(
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<DnsProbeRunner> 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<DnsTask> {
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<DnsTask> {
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<DnsTask> {
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<DnsTask> {
// 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<DnsTask>(
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