diff options
Diffstat (limited to 'src/core/net/system_network_context_manager.cpp')
-rw-r--r-- | src/core/net/system_network_context_manager.cpp | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/src/core/net/system_network_context_manager.cpp b/src/core/net/system_network_context_manager.cpp new file mode 100644 index 000000000..439d1066c --- /dev/null +++ b/src/core/net/system_network_context_manager.cpp @@ -0,0 +1,359 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// based on chrome/browser/net/system_network_context_manager.cc: +// 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/system_network_context_manager.h" + +#include "base/command_line.h" +#include "base/functional/bind.h" +#include "base/strings/string_split.h" +#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h" +#include "chrome/common/chrome_switches.h" +#include "components/certificate_transparency/ct_known_logs.h" +#include "components/network_session_configurator/common/network_switches.h" +#include "content/public/browser/network_service_instance.h" +#include "content/public/common/content_switches.h" +#include "crypto/sha2.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "net/base/port_util.h" +#include "net/net_buildflags.h" +#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h" +#include "services/network/network_service.h" +#include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h" +#include "services/network/public/cpp/features.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/mojom/cert_verifier_service.mojom.h" +#include "services/network/public/mojom/network_context.mojom.h" +#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h" +#include "api/qwebengineglobalsettings.h" +#include "api/qwebengineglobalsettings_p.h" + +#if BUILDFLAG(IS_WIN) +#include "chrome/browser/net/chrome_mojo_proxy_resolver_win.h" +#include "components/os_crypt/sync/os_crypt.h" +#include "content/public/browser/network_service_util.h" +#endif + +ASSERT_ENUMS_MATCH(net::SecureDnsMode::kSecure, QWebEngineGlobalSettings::SecureDnsMode::SecureOnly) +ASSERT_ENUMS_MATCH(net::SecureDnsMode::kAutomatic, + QWebEngineGlobalSettings::SecureDnsMode::SecureWithFallback) +ASSERT_ENUMS_MATCH(net::SecureDnsMode::kOff, QWebEngineGlobalSettings::SecureDnsMode::SystemOnly) + +namespace { + +network::mojom::HttpAuthStaticParamsPtr CreateHttpAuthStaticParams() +{ + network::mojom::HttpAuthStaticParamsPtr auth_static_params = + network::mojom::HttpAuthStaticParams::New(); + + return auth_static_params; +} + +network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams() +{ + network::mojom::HttpAuthDynamicParamsPtr auth_dynamic_params = network::mojom::HttpAuthDynamicParams::New(); + + auth_dynamic_params->allowed_schemes = { "basic", "digest", "ntlm", "negotiate" }; + + auto *command_line = base::CommandLine::ForCurrentProcess(); + auth_dynamic_params->server_allowlist = command_line->GetSwitchValueASCII(switches::kAuthServerAllowlist); +// auth_dynamic_params->delegate_allowlist = command_line->GetSwitchValueASCII(switches::kAuthNegotiateDelegateWhitelist); +// auth_dynamic_params->enable_negotiate_port = command_line->HasSwitch(switches::kEnableAuthNegotiatePort); + + return auth_dynamic_params; +} + +} // namespace + +namespace QtWebEngineCore { + +// The global instance of the SystemNetworkContextmanager. +SystemNetworkContextManager *g_system_network_context_manager = nullptr; + +// SharedURLLoaderFactory backed by a SystemNetworkContextManager and its +// network context. Transparently handles crashes. +class SystemNetworkContextManager::URLLoaderFactoryForSystem : public network::SharedURLLoaderFactory +{ +public: + explicit URLLoaderFactoryForSystem(SystemNetworkContextManager *manager) : manager_(manager) + { + DETACH_FROM_SEQUENCE(sequence_checker_); + } + + // mojom::URLLoaderFactory implementation: + + void CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> receiver, + int32_t request_id, + uint32_t options, + const network::ResourceRequest &url_request, + mojo::PendingRemote<network::mojom::URLLoaderClient> client, + const net::MutableNetworkTrafficAnnotationTag &traffic_annotation) override + { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!manager_) + return; + manager_->GetURLLoaderFactory()->CreateLoaderAndStart( + std::move(receiver), request_id, options, url_request, + std::move(client), traffic_annotation); + } + + void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) override + { + if (!manager_) + return; + manager_->GetURLLoaderFactory()->Clone(std::move(receiver)); + } + + // SharedURLLoaderFactory implementation: + std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override + { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(this); + } + + void Shutdown() { manager_ = nullptr; } + +private: + friend class base::RefCounted<URLLoaderFactoryForSystem>; + ~URLLoaderFactoryForSystem() override {} + + SEQUENCE_CHECKER(sequence_checker_); + SystemNetworkContextManager *manager_; +}; + +network::mojom::NetworkContext *SystemNetworkContextManager::GetContext() +{ + if (!network_service_network_context_ || + !network_service_network_context_.is_connected()) { + // This should call into OnNetworkServiceCreated(), which will re-create + // the network service, if needed. There's a chance that it won't be + // invoked, if the NetworkContext has encountered an error but the + // NetworkService has not yet noticed its pipe was closed. In that case, + // trying to create a new NetworkContext would fail, anyways, and hopefully + // a new NetworkContext will be created on the next GetContext() call. + content::GetNetworkService(); + DCHECK(network_service_network_context_); + } + return network_service_network_context_.get(); +} + +network::mojom::URLLoaderFactory *SystemNetworkContextManager::GetURLLoaderFactory() +{ + // Create the URLLoaderFactory as needed. + if (url_loader_factory_ && url_loader_factory_.is_connected()) { + return url_loader_factory_.get(); + } + + network::mojom::URLLoaderFactoryParamsPtr params = network::mojom::URLLoaderFactoryParams::New(); + params->process_id = network::mojom::kBrowserProcessId; + params->is_corb_enabled = false; + GetContext()->CreateURLLoaderFactory(url_loader_factory_.BindNewPipeAndPassReceiver(), std::move(params)); + return url_loader_factory_.get(); +} + +scoped_refptr<network::SharedURLLoaderFactory> SystemNetworkContextManager::GetSharedURLLoaderFactory() +{ + return shared_url_loader_factory_; +} + +// static +SystemNetworkContextManager *SystemNetworkContextManager::CreateInstance() +{ + DCHECK(!g_system_network_context_manager); + g_system_network_context_manager = new SystemNetworkContextManager(); + return g_system_network_context_manager; +} + +// static +SystemNetworkContextManager *SystemNetworkContextManager::GetInstance() +{ + return g_system_network_context_manager; +} + +// static +void SystemNetworkContextManager::DeleteInstance() +{ + DCHECK(g_system_network_context_manager); + delete g_system_network_context_manager; +} + +SystemNetworkContextManager::SystemNetworkContextManager() +{ + shared_url_loader_factory_ = new URLLoaderFactoryForSystem(this); +} + +SystemNetworkContextManager::~SystemNetworkContextManager() +{ + shared_url_loader_factory_->Shutdown(); +} + +void SystemNetworkContextManager::OnNetworkServiceCreated(network::mojom::NetworkService *network_service) +{ + bool is_quic_force_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableQuic); + // Disable QUIC globally + if (!is_quic_force_enabled) + network_service->DisableQuic(); + + network_service->SetUpHttpAuth(CreateHttpAuthStaticParams()); + network_service->ConfigureHttpAuthPrefs(CreateHttpAuthDynamicParams()); + +#if BUILDFLAG(IS_WIN) + if (content::IsOutOfProcessNetworkService()) + network_service->SetEncryptionKey(OSCrypt::GetRawEncryptionKey()); +#endif + + // Configure the Certificate Transparency logs. + std::vector<std::pair<std::string, base::Time>> disqualified_logs = + certificate_transparency::GetDisqualifiedLogs(); + std::vector<network::mojom::CTLogInfoPtr> log_list_mojo; + for (const auto &ct_log : certificate_transparency::GetKnownLogs()) { + network::mojom::CTLogInfoPtr log_info = network::mojom::CTLogInfo::New(); + log_info->public_key = std::string(ct_log.log_key, ct_log.log_key_length); + log_info->id = crypto::SHA256HashString(log_info->public_key); + log_info->name = ct_log.log_name; + log_info->current_operator = ct_log.current_operator; + + auto it = std::lower_bound( + std::begin(disqualified_logs), std::end(disqualified_logs), log_info->id, + [](const auto& disqualified_log, const std::string& log_id) { + return disqualified_log.first < log_id; + }); + if (it != std::end(disqualified_logs) && it->first == log_info->id) + log_info->disqualified_at = it->second; + + for (size_t i = 0; i < ct_log.previous_operators_length; i++) { + const auto& op = ct_log.previous_operators[i]; + network::mojom::PreviousOperatorEntryPtr previous_operator = + network::mojom::PreviousOperatorEntry::New(); + previous_operator->name = op.name; + previous_operator->end_time = op.end_time; + log_info->previous_operators.push_back(std::move(previous_operator)); + } + + log_list_mojo.push_back(std::move(log_info)); + } + network_service->UpdateCtLogList( + std::move(log_list_mojo), + certificate_transparency::GetLogListTimestamp(), + base::DoNothing()); + + // The system NetworkContext is created first + network_service_network_context_.reset(); + network_service->CreateNetworkContext( + network_service_network_context_.BindNewPipeAndPassReceiver(), + CreateNetworkContextParams()); + + // Handle --explicitly-allowed-ports + if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kExplicitlyAllowedPorts)) { + std::vector<uint16_t> explicitly_allowed_network_ports; + std::string switch_value = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); + const auto split = base::SplitStringPiece(switch_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + for (const auto &piece : split) { + int port; + if (!base::StringToInt(piece, &port)) + continue; + if (!net::IsPortValid(port)) + continue; + explicitly_allowed_network_ports.push_back(static_cast<uint16_t>(port)); + } + + network_service->SetExplicitlyAllowedPorts(explicitly_allowed_network_ports); + } + + // The network service is a singleton that can be reinstantiated for different reasons, + // e.g., when the network service crashes. Therefore, we configure the stub host + // resolver of the network service here, each time it is instantiated, with our global + // DNS-Over-HTTPS settings. This ensures that the global settings don't get lost + // on reinstantiation and are in effect upon initial instantiation. + QWebEngineGlobalSettingsPrivate::instance()->configureStubHostResolver(); +} + +void SystemNetworkContextManager::AddSSLConfigToNetworkContextParams(network::mojom::NetworkContextParams *network_context_params) +{ + network_context_params->initial_ssl_config = network::mojom::SSLConfig::New(); + network_context_params->initial_ssl_config->symantec_enforcement_disabled = true; +} + +void SystemNetworkContextManager::ConfigureDefaultNetworkContextParams(network::mojom::NetworkContextParams *network_context_params, + cert_verifier::mojom::CertVerifierCreationParams *cert_verifier_creation_params) +{ + network_context_params->enable_brotli = true; + + // Disable referrers by default. Any consumer that enables referrers should + // respect prefs::kEnableReferrers from the appropriate pref store. + network_context_params->enable_referrers = false; + + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + if (!command_line.HasSwitch(switches::kWinHttpProxyResolver)) { + if (command_line.HasSwitch(switches::kSingleProcess)) { + LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode."; + } else { + network_context_params->proxy_resolver_factory = + ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver(); + } + } +#if BUILDFLAG(IS_WIN) + if (command_line.HasSwitch(switches::kUseSystemProxyResolver)) { + network_context_params->windows_system_proxy_resolver = + ChromeMojoProxyResolverWin::CreateWithSelfOwnedReceiver(); + } +#endif + // Use the SystemNetworkContextManager to populate and update SSL + // configuration. The SystemNetworkContextManager is owned by the + // BrowserProcess itself, so will only be destroyed on shutdown, at which + // point, all NetworkContexts will be destroyed as well. + AddSSLConfigToNetworkContextParams(network_context_params); +} + +network::mojom::NetworkContextParamsPtr SystemNetworkContextManager::CreateNetworkContextParams() +{ + // TODO(mmenke): Set up parameters here (in memory cookie store, etc). + network::mojom::NetworkContextParamsPtr network_context_params = network::mojom::NetworkContextParams::New(); + cert_verifier::mojom::CertVerifierCreationParamsPtr + cert_verifier_creation_params = cert_verifier::mojom::CertVerifierCreationParams::New(); + ConfigureDefaultNetworkContextParams(network_context_params.get(), cert_verifier_creation_params.get()); + + network_context_params->enable_referrers = false; + + network_context_params->http_cache_enabled = false; + + proxy_config_monitor_.AddToNetworkContextParams(network_context_params.get()); + + network_context_params->cert_verifier_params = + content::GetCertVerifierParams(std::move(cert_verifier_creation_params)); + return network_context_params; +} + +bool isValidTemplates(std::string templates) +{ + absl::optional<net::DnsOverHttpsConfig> dnsOverHttpsConfig = + net::DnsOverHttpsConfig::FromString(templates); + return dnsOverHttpsConfig.has_value(); +} + + +void configureStubHostResolver(QWebEngineGlobalSettings::SecureDnsMode dnsMode, + std::string dnsOverHttpsTemplates, bool insecureDnsClientEnabled, + bool additionalInsecureDnsTypesEnabled) +{ + if (content::IsNetworkServiceCreated()) { + network::mojom::NetworkService *networkService = content::GetNetworkService(); + if (networkService) { + absl::optional<net::DnsOverHttpsConfig> dohConfig = dnsOverHttpsTemplates.empty() + ? net::DnsOverHttpsConfig() + : net::DnsOverHttpsConfig::FromString(dnsOverHttpsTemplates); + networkService->ConfigureStubHostResolver(insecureDnsClientEnabled, + net::SecureDnsMode(dnsMode), *dohConfig, + additionalInsecureDnsTypesEnabled); + } + } +} + +} // namespace QtWebEngineCore |