From 6b3e7f2baa17a5bff7051949f743f2ec6926ec06 Mon Sep 17 00:00:00 2001 From: Yigit Akcay Date: Tue, 14 Mar 2023 17:31:11 +0100 Subject: Allow configuration of DNS-over-HTTPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement QWebEngineGlobalSettings, a singleton class that contains global web engine settings (currently only for DoH). Allow the user to configure the stub host resolver to enable DNS-over-HTTPS. Fixes: QTBUG-98284 Change-Id: I1b06737c84e1b8d613aa257f4a891f82cac21013 Reviewed-by: Michael BrĂ¼ning --- src/core/api/CMakeLists.txt | 2 + src/core/api/qwebengineglobalsettings.cpp | 92 ++++++++++++++++++ src/core/api/qwebengineglobalsettings.h | 42 ++++++++ src/core/api/qwebengineglobalsettings_p.h | 43 +++++++++ src/core/net/system_network_context_manager.cpp | 36 +++++-- src/core/net/system_network_context_manager.h | 4 + tests/auto/core/CMakeLists.txt | 1 + .../core/qwebengineglobalsettings/CMakeLists.txt | 29 ++++++ .../core/qwebengineglobalsettings/cert/RootCA.pem | 20 ++++ .../qwebengineglobalsettings/cert/localhost.crt | 22 +++++ .../qwebengineglobalsettings/cert/localhost.key | 28 ++++++ .../tst_qwebengineglobalsettings.cpp | 107 +++++++++++++++++++++ tests/auto/httpserver/httpserver.h | 2 + tests/auto/httpserver/httpsserver.h | 12 ++- 14 files changed, 429 insertions(+), 11 deletions(-) create mode 100644 src/core/api/qwebengineglobalsettings.cpp create mode 100644 src/core/api/qwebengineglobalsettings.h create mode 100644 src/core/api/qwebengineglobalsettings_p.h create mode 100644 tests/auto/core/qwebengineglobalsettings/CMakeLists.txt create mode 100644 tests/auto/core/qwebengineglobalsettings/cert/RootCA.pem create mode 100644 tests/auto/core/qwebengineglobalsettings/cert/localhost.crt create mode 100644 tests/auto/core/qwebengineglobalsettings/cert/localhost.key create mode 100644 tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp diff --git a/src/core/api/CMakeLists.txt b/src/core/api/CMakeLists.txt index ba973fd32..32b3451bd 100644 --- a/src/core/api/CMakeLists.txt +++ b/src/core/api/CMakeLists.txt @@ -38,6 +38,7 @@ qt_internal_add_module(WebEngineCore qwebengineurlrequestjob.cpp qwebengineurlrequestjob.h qwebengineurlscheme.cpp qwebengineurlscheme.h qwebengineurlschemehandler.cpp qwebengineurlschemehandler.h + qwebengineglobalsettings.cpp qwebengineglobalsettings.h qwebengineglobalsettings_p.h DEFINES BUILDING_CHROMIUM NOMINMAX @@ -46,6 +47,7 @@ qt_internal_add_module(WebEngineCore ../../3rdparty/chromium ../../3rdparty/chromium/third_party/abseil-cpp ../../3rdparty/chromium/third_party/perfetto/include + ../../3rdparty/chromium/third_party/boringssl/src/include LIBRARIES Qt::CorePrivate Qt::GuiPrivate diff --git a/src/core/api/qwebengineglobalsettings.cpp b/src/core/api/qwebengineglobalsettings.cpp new file mode 100644 index 000000000..685d9d593 --- /dev/null +++ b/src/core/api/qwebengineglobalsettings.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2023 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 + +#include "services/network/network_service.h" +#include "content/public/browser/network_service_instance.h" + +#include "qwebengineglobalsettings.h" +#include "qwebengineglobalsettings_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineGlobalSettings + \brief The QWebEngineGlobalSettings class configures global properties of the web engine. + \since 6.6 + \inmodule QtWebEngineCore + + The QWebEngineGlobalSettings class is a singleton that configures global properties + of the web engine. + + Invoke configureDnsOverHttps() to configure DNS-over-HTTPS capabilities. + + \sa QWebEngineGlobalSettings::configureDnsOverHttps() +*/ + +QWebEngineGlobalSettings::QWebEngineGlobalSettings(QObject *p) + : QObject(p), d_ptr(new QWebEngineGlobalSettingsPrivate) +{ +} + +QWebEngineGlobalSettings::~QWebEngineGlobalSettings() { } + +/*! + \fn QWebEngineGlobalSettings *QWebEngineGlobalSettings::GetInstance() + + Gets the global instance of QWebEngineGlobalSettings. +*/ +QWebEngineGlobalSettings *QWebEngineGlobalSettings::GetInstance() +{ + static QWebEngineGlobalSettings settings; + return &settings; +} + +/*! + \enum QWebEngineGlobalSettings::DnsMode + + This enum sets the DNS-over-HTTPS mode: + + \value WithFallback Enable DNS-over-HTTPS with fallbacks. If a host + can't be resolved, try the insecure DNS client of Chromium. If that fails as + well, try the system DNS host resolution, which can be secure or insecure. + \value Secure Enable DNS-over-HTTPS and only allow the secure Chromium + DNS client to resolve hosts. +*/ + +/*! + \fn QWebEngineGlobalSettings::configureDnsOverHttps(const DnsMode dnsMode, + const QString &dnsOverHttpsTemplates) + + Configures the Chromium stub host resolver, thus allowing DNS-over-HTTPS functionality. + + Set \a dnsMode to QWebEngineGlobalSettings::DnsMode::WithFallback to enable secure DNS + host resolution with a fallback to insecure DNS host resolution and a final fallback to + the system DNS resolution, which can be secure or insecure. Set it to + QWebEngineGlobalSettings::DnsMode::Secure to only allow secure DNS host resolution via + the Chromium DNS client. + + Independently of \a {dnsMode}, \a dnsOverHttpsTemplates has to be set to one or multiple + valid \l{https://datatracker.ietf.org/doc/html/rfc6570}{URI templates} separated by + whitespace characters. One example URI template is https://dns.google/dns-query{?dns}. +*/ +void QWebEngineGlobalSettings::configureDnsOverHttps(const DnsMode dnsMode, + const QString &dnsOverHttpsTemplates) +{ + Q_D(QWebEngineGlobalSettings); + + d->dnsMode = dnsMode; + d->dnsOverHttpsTemplates = dnsOverHttpsTemplates.toStdString(); + d->isDnsOverHttpsUserConfigured = true; + + // Make sure that DoH settings are in effect immediately if the network service already exists, + // thus allowing to change DoH configuration at any point + network::mojom::NetworkService *networkService = content::GetNetworkService(); + if (networkService) { + networkService->ConfigureStubHostResolver( + d->insecureDnsClientEnabled, net::SecureDnsMode(d->dnsMode), + *net::DnsOverHttpsConfig::FromString(d->dnsOverHttpsTemplates), + d->additionalInsecureDnsTypesEnabled); + } +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebengineglobalsettings.h b/src/core/api/qwebengineglobalsettings.h new file mode 100644 index 000000000..a65a08359 --- /dev/null +++ b/src/core/api/qwebengineglobalsettings.h @@ -0,0 +1,42 @@ +// Copyright (C) 2023 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 + +#ifndef QWEBENGINEGLOBALSETTINGS_H +#define QWEBENGINEGLOBALSETTINGS_H + +#include +#include +#include + +namespace QtWebEngineCore { +class SystemNetworkContextManager; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineGlobalSettingsPrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineGlobalSettings : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QWebEngineGlobalSettings) +public: + static QWebEngineGlobalSettings *GetInstance(); + + // Mapping net::SecureDnsMode + enum class DnsMode { WithFallback = 1, Secure = 2 }; + + void configureDnsOverHttps(const DnsMode dnsMode, const QString &dnsOverHttpsTemplates); + +private: + QWebEngineGlobalSettings(QObject *p = nullptr); + ~QWebEngineGlobalSettings(); + + friend class QtWebEngineCore::SystemNetworkContextManager; + Q_DECLARE_PRIVATE(QWebEngineGlobalSettings) + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEGLOBALSETTINGS_H diff --git a/src/core/api/qwebengineglobalsettings_p.h b/src/core/api/qwebengineglobalsettings_p.h new file mode 100644 index 000000000..4c15f62b0 --- /dev/null +++ b/src/core/api/qwebengineglobalsettings_p.h @@ -0,0 +1,43 @@ +// Copyright (C) 2023 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 + +#ifndef QWEBENGINEGLOBALSETTINGS_P_H +#define QWEBENGINEGLOBALSETTINGS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtwebenginecoreglobal_p.h" +#include "qwebengineglobalsettings.h" +#include + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineGlobalSettingsPrivate +{ +public: + QWebEngineGlobalSettingsPrivate() + : dnsMode(QWebEngineGlobalSettings::DnsMode::WithFallback) + , dnsOverHttpsTemplates("") + , insecureDnsClientEnabled(true) + , additionalInsecureDnsTypesEnabled(true) + , isDnsOverHttpsUserConfigured(false){}; + + QWebEngineGlobalSettings::DnsMode dnsMode; + std::string dnsOverHttpsTemplates; + bool insecureDnsClientEnabled; + bool additionalInsecureDnsTypesEnabled; + bool isDnsOverHttpsUserConfigured; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEGLOBALSETTINGS_P_H diff --git a/src/core/net/system_network_context_manager.cpp b/src/core/net/system_network_context_manager.cpp index 83e122aab..8df65b7a5 100644 --- a/src/core/net/system_network_context_manager.cpp +++ b/src/core/net/system_network_context_manager.cpp @@ -29,6 +29,8 @@ #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" @@ -38,9 +40,6 @@ namespace { -// The global instance of the SystemNetworkContextmanager. -SystemNetworkContextManager *g_system_network_context_manager = nullptr; - network::mojom::HttpAuthStaticParamsPtr CreateHttpAuthStaticParams() { network::mojom::HttpAuthStaticParamsPtr auth_static_params = @@ -65,6 +64,11 @@ network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams() } // 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 @@ -255,12 +259,24 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(network::mojom::Networ network_service->SetExplicitlyAllowedPorts(explicitly_allowed_network_ports); } - // Configure the stub resolver. This must be done after the system - // NetworkContext is created, but before anything has the chance to use it. - // bool stub_resolver_enabled; - // absl::optional> dns_over_https_servers; - // GetStubResolverConfig(local_state_, &stub_resolver_enabled, &dns_over_https_servers); - // content::GetNetworkService()->ConfigureStubHostResolver(stub_resolver_enabled, std::move(dns_over_https_servers)); + + // 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. + QWebEngineGlobalSettings *const globalSettings = QWebEngineGlobalSettings::GetInstance(); + if (globalSettings->d_ptr->isDnsOverHttpsUserConfigured) { + const bool insecureDnsClientEnabled = globalSettings->d_ptr->insecureDnsClientEnabled; + const bool additionalInsecureDnsTypesEnabled = + globalSettings->d_ptr->additionalInsecureDnsTypesEnabled; + const net::SecureDnsMode dnsMode = net::SecureDnsMode(globalSettings->d_ptr->dnsMode); + const absl::optional dnsOverHttpsTemplates = + net::DnsOverHttpsConfig::FromString(globalSettings->d_ptr->dnsOverHttpsTemplates); + content::GetNetworkService()->ConfigureStubHostResolver(insecureDnsClientEnabled, dnsMode, + *dnsOverHttpsTemplates, + additionalInsecureDnsTypesEnabled); + } } void SystemNetworkContextManager::AddSSLConfigToNetworkContextParams(network::mojom::NetworkContextParams *network_context_params) @@ -320,3 +336,5 @@ network::mojom::NetworkContextParamsPtr SystemNetworkContextManager::CreateNetwo content::GetCertVerifierParams(std::move(cert_verifier_creation_params)); return network_context_params; } + +} // namespace QtWebEngineCore diff --git a/src/core/net/system_network_context_manager.h b/src/core/net/system_network_context_manager.h index fa761cb44..d56bdab78 100644 --- a/src/core/net/system_network_context_manager.h +++ b/src/core/net/system_network_context_manager.h @@ -28,6 +28,8 @@ class URLLoaderFactory; class SharedURLLoaderFactory; } // namespace network +namespace QtWebEngineCore { + // Responsible for creating and managing access to the system NetworkContext. // Lives on the UI thread. The NetworkContext this owns is intended for requests // not associated with a profile. It stores no data on disk, and has no HTTP @@ -114,4 +116,6 @@ private: ProxyConfigMonitor proxy_config_monitor_; }; +} // namespace QtWebEngineCore + #endif // SYSTEM_NETWORK_CONTEXT_MANAGER_H_ diff --git a/tests/auto/core/CMakeLists.txt b/tests/auto/core/CMakeLists.txt index 9d131da56..ae10d918b 100644 --- a/tests/auto/core/CMakeLists.txt +++ b/tests/auto/core/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(qwebenginecookiestore) add_subdirectory(qwebengineloadinginfo) add_subdirectory(qwebenginesettings) +add_subdirectory(qwebengineglobalsettings) add_subdirectory(qwebengineurlrequestinterceptor) add_subdirectory(qwebengineurlresponseinterceptor) add_subdirectory(qwebengineurlrequestjob) diff --git a/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt b/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt new file mode 100644 index 000000000..fa81ba8df --- /dev/null +++ b/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +include(../../httpserver/httpserver.cmake) +include(../../util/util.cmake) + +qt_internal_add_test(tst_qwebengineglobalsettings + SOURCES + tst_qwebengineglobalsettings.cpp + LIBRARIES + Qt::WebEngineCore + Test::HttpServer + Qt::WebEngineWidgets + Test::Util +) + +# Resources: +set(tst_qwebengineglobalsettings_resource_files + "cert/localhost.crt" + "cert/localhost.key" + "cert/RootCA.pem" +) + +qt_add_resources(tst_qwebengineglobalsettings "tst_qwebengineglobalsettings" + PREFIX + "/" + FILES + ${tst_qwebengineglobalsettings_resource_files} +) diff --git a/tests/auto/core/qwebengineglobalsettings/cert/RootCA.pem b/tests/auto/core/qwebengineglobalsettings/cert/RootCA.pem new file mode 100644 index 000000000..16be384bb --- /dev/null +++ b/tests/auto/core/qwebengineglobalsettings/cert/RootCA.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTzCCAjegAwIBAgIUNYpmREIW67Fh7WNzCwPL6nnSgRMwDQYJKoZIhvcNAQEL +BQAwNzELMAkGA1UEBhMCREUxKDAmBgNVBAMMH1dlYkVuZ2luZUdsb2JhbFNldHRp +bmdzLVRlc3QtQ0EwHhcNMjMwMzI5MTYwMzMzWhcNMjYwMTE2MTYwMzMzWjA3MQsw +CQYDVQQGEwJERTEoMCYGA1UEAwwfV2ViRW5naW5lR2xvYmFsU2V0dGluZ3MtVGVz +dC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJhZ9DwcdbVBzMyY +/nEqt5KUi74LFwEnS0G2ne8IYco9+Pbkpb8wV5u6n43IsQ2c3u8D/KVtu1Vy3tf2 +G3aKOwhFzaj7GWLE9FweZyMoL6ASOtWEa55myT5zAysVQtHAkePu0smAPP0gVq3E +vjSTwV1W1mVXv4wMwffR8AvNGhKrJIa3L2/uYKGbzEmaCk2kt0vIqfrx8095RlXC +lUcwTMJ6/d/e/DMDtqQ1ypUuz5QYQybIVKwuqkhojT2DXbitv0rE4HLQub8CxOZ+ +9GcQjeAt8Tzrlp1UP6c9OtlsMoo37gJYzb/XDE6OPnk42chQXDxGQjtVRs+60kcT +Dx/YHG0CAwEAAaNTMFEwHQYDVR0OBBYEFP1FK1U9CUHQEp7coaab7IdR18zDMB8G +A1UdIwQYMBaAFP1FK1U9CUHQEp7coaab7IdR18zDMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBAGTlcxmRsuwBeRW0CsjX/qbdcB0OWkIC857Jn8RU +6yGa7P9i6EQb1O/DEF+Z7dkASx5zfN6LPIrph6J56/mmcNBeqArovWJwxQUTNO9i +1kOU3xoH5n/ya+gdBr3reA90bAMKWXwa6uI3smPJKy+2hOkdDaSBa5KECYWhniH0 +yRxL7YdhQhuCc7Ijf+S6WzeHRwdLkdiV8c2vAGWdunDFuGT2iYVOZ1qbp6O/tmjv +TxWAnvP4+0ykFIlMor0vYWD8xbnq28263VmNh7mrFwkBYnHJiY/nTDwxaL+g6Uji +9n6+VuxUDgfQWX1YRHC4a89zI/Zvnn2z/92To7zRmNd73RQ= +-----END CERTIFICATE----- diff --git a/tests/auto/core/qwebengineglobalsettings/cert/localhost.crt b/tests/auto/core/qwebengineglobalsettings/cert/localhost.crt new file mode 100644 index 000000000..c063bf268 --- /dev/null +++ b/tests/auto/core/qwebengineglobalsettings/cert/localhost.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIURotPFTfDJxwaqhZsr0IpAahl2EMwDQYJKoZIhvcNAQEL +BQAwNzELMAkGA1UEBhMCREUxKDAmBgNVBAMMH1dlYkVuZ2luZUdsb2JhbFNldHRp +bmdzLVRlc3QtQ0EwHhcNMjMwMzI5MTYwNDI1WhcNMjYwMTE2MTYwNDI1WjB0MQsw +CQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xKTAn +BgNVBAoMIFFXZWJFbmdpbmVHbG9iYWxTZXR0aW5ncy1FeGFtcGxlMRgwFgYDVQQD +DA9sb2NhbGhvc3QubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCY9FX/8YetuJKSFSoYPxMKPvjt2zJ5g13DywqZtbDzLAIASCxn4iad3qgxaoWB +uI0g4ykzrhUa98YHU8fDH4T4Vwhwu72SRYW4+MgT9ohc1oCKBX05b+BWSuTSeuHy +leqdL78bj3bu5TtFs2dJt2t8eA6SNR9lDa5g4v7oA4xVp93gMo2YqZwaLONmxIKY +cI4lcETnHHsvc6+dB2UqWHJEN75UkdC/XnDLM/VbL3/4zxU+9x34nvvfSJwCHVnE +u+zYwrZXkbiDVDovT855phVC/K5skVgBL2miz3eygljuw1tIwnmVix/e/xHZyqMg +Lje/LZN53v5G61Wut6bbdkeVAgMBAAGjezB5MB8GA1UdIwQYMBaAFP1FK1U9CUHQ +Ep7coaab7IdR18zDMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMB8GA1UdEQQYMBaC +CWxvY2FsaG9zdIIJMTI3LjAuMC4xMB0GA1UdDgQWBBQv20ImViFtvMm5gHqTeML6 +pi5BtTANBgkqhkiG9w0BAQsFAAOCAQEAGsL7eOms30+IPdKQZ2pjtX22GfM6EiUs +xsQfsX/Q3bus30B2m9GJ6AVIwVUJimOGiMauDCLjDeXWCMZpihzodExhC0D/X1B+ +FsCLagcjlgfWwekKEo8sUWUZp0DNCyacPtTPxqoS2RA7foEzQhRLViLSvf+UXU8g +jZAwWGB/5V849zcbbNBcWKzRsPvNOqeENWEn1ByGcsWhas2V0KzRcUODuA9UHv1x ++eDlLZYsWV9c1MuL8a1VDEluIR19eR/Gl9axjPZY2oiPvlp2b7I4z1bY+wV2i6vh +NeDCAxAxJ42tXeb86vtnVXfSDbzedDbLv0l2kEhcywVN3MwhsEpmpg== +-----END CERTIFICATE----- diff --git a/tests/auto/core/qwebengineglobalsettings/cert/localhost.key b/tests/auto/core/qwebengineglobalsettings/cert/localhost.key new file mode 100644 index 000000000..49502ab9a --- /dev/null +++ b/tests/auto/core/qwebengineglobalsettings/cert/localhost.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCY9FX/8YetuJKS +FSoYPxMKPvjt2zJ5g13DywqZtbDzLAIASCxn4iad3qgxaoWBuI0g4ykzrhUa98YH +U8fDH4T4Vwhwu72SRYW4+MgT9ohc1oCKBX05b+BWSuTSeuHyleqdL78bj3bu5TtF +s2dJt2t8eA6SNR9lDa5g4v7oA4xVp93gMo2YqZwaLONmxIKYcI4lcETnHHsvc6+d +B2UqWHJEN75UkdC/XnDLM/VbL3/4zxU+9x34nvvfSJwCHVnEu+zYwrZXkbiDVDov +T855phVC/K5skVgBL2miz3eygljuw1tIwnmVix/e/xHZyqMgLje/LZN53v5G61Wu +t6bbdkeVAgMBAAECggEAF7ADX5NivUsv29LORZoDE1ukRoXjX8Ex9MANoLdsM4S1 +vKBwzBfQfjN83cZO7cOMi7LSby//EcGcmAboEXZgq+siof7ZQX1l07snlTvha2tG +1dk6xvnmBscrf9NLCbwg7P33fUevFhlHICjEDr0KtuiK7Sav+YDwaA3Ph1QBWERd +GO3sVlnuGsDpf/0GijlwqEGuDKUePEEANOhXcByh693VmvlKVf9SbrimYeunKW1O +FvvcAiBMzqurhZotb9/juiq+fIMID29OULCCxlZZSySRYw0REpnAAxgWvaSZqyWd +tGosSKEgc4SptPTmC8DzRDDfN/zqvXmkmYnN9o4qMwKBgQC3tVYdEPn3fHX973Df +Ukp55cRpZFuNxjOiV3Qo1aTAKqpbmJ4/x8tUL7rhsmJXSxlW7xdNQ/WIHM1PJlZx +UAIr5eBq1MUVd5OENP8PuVIdAIumHXICB5FioJR/WnXRXLJEbGxSRr5gwaTw3sXd +ObPRQEUOrJtK+W0aeBKePRtIiwKBgQDVJN7A26vy8PMcE4TcDp75vAY/qasZl6ES +oksaHf3c4/jsnr70wRoOXi3fPo/DpWmVFylttMSEnzh3nfnOkDXZD3mQx3sdVw8l +12++t59733hllJZlwqk5OAc990kE1X44UW/gPA+5Vb9kpo6ahpFtqwhDmqa4RjtZ +0R/1H/KUXwKBgGjR7Qq0rwwJVgHIZ2zlNV2MPp+sBZlFaBzPLZZHILQNJBsTX+gg +heHJQiaZdAc+8Hxr+624gxZg6LyqsVQCRNrrVTtfn/x5uBANdSNxqGqn7wafcne5 +/bh6y4BHC0akT4s/Gidv+hyXIRfW5Ksvy2wv8bdHwWvsGdaqgGUNlM21AoGAe9Vc +BbibAh6zYBCHFEL6YiW3i61L1yadUnIwKBBcucVJjk/8qb63ILne9OEoLYcg/Jnk +W/S2aEcJS5Xg2P44CtBO1KrRAI7gIiA0sB2G7zU6gen+J0kdgDzpGDtflQtktdu6 +oBDFIeyLsjKCj4y3WXwQ5RYo3s8PFHPHmWbiTQkCgYBViqAHaAaPJQZG7Q6/Xqhf +rFosC0DeZk5PHrEDbpAnuJbySafGZ4LxY5Oq05+aM8BeR+IuGopciBBDWXoh7msO +N8WItu7WI86lIu7JZRbeju2w59tgj0EA+GyU1udPjTjseP5qpB27X1JEGV6TYBNs +LMmQSgdGWqwteKsc50UrkA== +-----END PRIVATE KEY----- diff --git a/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp b/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp new file mode 100644 index 000000000..40bd525bc --- /dev/null +++ b/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include +#include +#include +#include +#include +#include + +#include "httpsserver.h" +#include "httpreqrep.h" + +class tst_QWebEngineGlobalSettings : public QObject +{ + Q_OBJECT + +public: + tst_QWebEngineGlobalSettings() { } + ~tst_QWebEngineGlobalSettings() { } + +public Q_SLOTS: + void init() { } + void cleanup() { } + +private Q_SLOTS: + void initTestCase() { } + void cleanupTestCase() { } + void dnsOverHttps_data(); + void dnsOverHttps(); +}; + +Q_LOGGING_CATEGORY(lc, "qt.webengine.tests") + +void tst_QWebEngineGlobalSettings::dnsOverHttps_data() +{ + QTest::addColumn("dnsMode"); + QTest::addColumn("uriTemplate"); + QTest::addColumn("isWithCustomDnsServer"); + QTest::addColumn("isDnsResolutionSuccessExpected"); + QTest::newRow("DnsMode::Secure (mock DNS)") + << QWebEngineGlobalSettings::DnsMode::Secure + << QStringLiteral("https://127.0.0.1:3000/dns-query{?dns}") << true << false; + QTest::newRow("DnsMode::Secure (real DNS)") + << QWebEngineGlobalSettings::DnsMode::Secure + << QStringLiteral("https://dns.google/dns-query{?dns}") << false << true; + + // Note: In the following test, we can't verify that the DoH server is called first and + // afterwards insecure DNS is tried, because for the DoH server to ever be used when the DNS + // mode is set to DnsMode::WithFallback, Chromium starts an asynchronous DoH server DnsProbe and + // requires that the connection is successful. That is, we'd have to implement a correct + // DNS response, which in turn requires that certificate errors aren't ignored and + // non-self-signed certificates are used for correct encryption. Instead of implementing + // all of that, this test verifies that Chromium tries probing the configured DoH server only. + QTest::newRow("DnsMode::WithFallback (mock DNS)") + << QWebEngineGlobalSettings::DnsMode::WithFallback + << QStringLiteral("https://127.0.0.1:3000/dns-query{?dns}") << true << true; +} + +void tst_QWebEngineGlobalSettings::dnsOverHttps() +{ + QFETCH(QWebEngineGlobalSettings::DnsMode, dnsMode); + QFETCH(QString, uriTemplate); + QFETCH(bool, isWithCustomDnsServer); + QFETCH(bool, isDnsResolutionSuccessExpected); + bool isDnsServerCalled = false; + bool isLoadSuccessful = false; + + HttpsServer *httpsServer; + if (isWithCustomDnsServer) { + httpsServer = new HttpsServer(":/cert/localhost.crt", ":/cert/localhost.key", + ":/cert/RootCA.pem", 3000, this); + QObject::connect( + httpsServer, &HttpsServer::newRequest, this, [&isDnsServerCalled](HttpReqRep *rr) { + QVERIFY(rr->requestPath().contains(QByteArrayLiteral("/dns-query?dns="))); + isDnsServerCalled = true; + rr->close(); + }); + QVERIFY(httpsServer->start()); + httpsServer->setExpectError(true); + httpsServer->setVerifyMode(QSslSocket::PeerVerifyMode::VerifyNone); + } + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + + connect(&page, &QWebEnginePage::loadFinished, this, + [&isLoadSuccessful](bool ok) { isLoadSuccessful = ok; }); + + QWebEngineGlobalSettings *globalSettings = QWebEngineGlobalSettings::GetInstance(); + globalSettings->configureDnsOverHttps(dnsMode, uriTemplate); + + page.load(QUrl("https://google.com/")); + QVERIFY(loadSpy.wait()); + + QTRY_COMPARE(isDnsServerCalled, isWithCustomDnsServer); + QCOMPARE(isLoadSuccessful, isDnsResolutionSuccessExpected); + + if (isWithCustomDnsServer) + QVERIFY(httpsServer->stop()); +} + +static QByteArrayList params = QByteArrayList() << "--ignore-certificate-errors"; + +W_QTEST_MAIN(tst_QWebEngineGlobalSettings, params) +#include "tst_qwebengineglobalsettings.moc" diff --git a/tests/auto/httpserver/httpserver.h b/tests/auto/httpserver/httpserver.h index 270b6265f..201eef4c6 100644 --- a/tests/auto/httpserver/httpserver.h +++ b/tests/auto/httpserver/httpserver.h @@ -59,6 +59,8 @@ public: Q_INVOKABLE void setHostDomain(const QString &host) { m_url.setHost(host); } + Q_INVOKABLE QTcpServer *getTcpServer() const { return m_tcpServer; } + Q_SIGNALS: // Emitted after a HTTP request has been successfully parsed. void newRequest(HttpReqRep *reqRep); diff --git a/tests/auto/httpserver/httpsserver.h b/tests/auto/httpserver/httpsserver.h index 10deeb322..d029851aa 100644 --- a/tests/auto/httpserver/httpsserver.h +++ b/tests/auto/httpserver/httpsserver.h @@ -55,11 +55,19 @@ static QSslServer *createServer(const QString &certificateFileName, const QStrin struct HttpsServer : HttpServer { HttpsServer(const QString &certPath, const QString &keyPath, const QString &ca, - QObject *parent = nullptr) - : HttpServer(createServer(certPath, keyPath, ca), "https", QHostAddress::LocalHost, 0, + quint16 port = 0, QObject *parent = nullptr) + : HttpServer(createServer(certPath, keyPath, ca), "https", QHostAddress::LocalHost, port, parent) { } + + void setVerifyMode(const QSslSocket::PeerVerifyMode verifyMode) + { + QSslServer *server = static_cast(getTcpServer()); + QSslConfiguration config = server->sslConfiguration(); + config.setPeerVerifyMode(verifyMode); + server->setSslConfiguration(config); + } }; #endif -- cgit v1.2.3