From 4e575a4203b7703c2b30bb8a16cfcfad1f942aab Mon Sep 17 00:00:00 2001 From: Jonathan Martin Date: Mon, 20 Nov 2023 11:20:44 -0800 Subject: [PATCH] v2.7.9 --- client/CMakeLists.txt | 4 +- client/common/changelog.txt | 11 +++ client/common/types/enginesettings.cpp | 19 ++++- client/common/types/enginesettings.h | 6 +- client/common/utils/extraconfig.cpp | 27 ++++++- client/common/utils/extraconfig.h | 4 + client/common/utils/linuxutils.h | 3 +- client/common/utils/utils.cpp | 9 ++- client/common/version/windscribe_version.h | 2 +- .../engine/autoupdater/downloadhelper.cpp | 20 +++-- .../engine/autoupdater/downloadhelper.h | 6 +- .../connectionmanager/connectionmanager.cpp | 30 +++++++ .../connectionmanager/connectionmanager.h | 2 + .../engine/engine/dnsresolver/CMakeLists.txt | 8 +- .../engine/engine/dnsresolver/dnsrequest.cpp | 12 +-- ...solver_posix.cpp => dnsresolver_cares.cpp} | 25 +++--- ...nsresolver_posix.h => dnsresolver_cares.h} | 12 +-- .../dnsresolver/dnsserversconfiguration.cpp | 17 +++- .../dnsresolver/dnsserversconfiguration.h | 4 +- client/engine/engine/engine.cpp | 4 +- .../wireguardconfig/wireguardconfig.cpp | 12 ++- .../engine/wireguardconfig/wireguardconfig.h | 5 +- .../gui/backend/preferences/preferences.cpp | 17 ++++ client/gui/backend/preferences/preferences.h | 4 + client/gui/commongraphics/iconbutton.cpp | 2 +- .../connectstateprotocolport.cpp | 48 ++++++++--- .../connectstateprotocolport.h | 6 ++ .../gui/connectwindow/connectwindowitem.cpp | 1 + .../connectionwindow/connectionwindowitem.cpp | 21 +++++ .../connectionwindow/connectionwindowitem.h | 4 + .../generalwindow/generalwindowitem.cpp | 13 +-- client/gui/svg.qrc | 1 + .../svg/preferences/CIRCUMVENT_CENSORSHIP.svg | 3 + client/gui/translations/ws_desktop_ru.ts | 81 +++++++++++-------- client/gui/utils/authchecker_linux.cpp | 2 +- tools/requirements.txt | 2 +- 36 files changed, 334 insertions(+), 113 deletions(-) rename client/engine/engine/dnsresolver/{dnsresolver_posix.cpp => dnsresolver_cares.cpp} (87%) rename client/engine/engine/dnsresolver/{dnsresolver_posix.h => dnsresolver_cares.h} (64%) create mode 100644 client/gui/svg/preferences/CIRCUMVENT_CENSORSHIP.svg diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 6a1459a9a..12de3ff18 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -54,8 +54,8 @@ if (WIN32) ${WINDSCRIBE_BUILD_LIBS_PATH}/cares/lib ) - set (OS_SPECIFIC_LIBRARIES psapi.lib iphlpapi.lib dnsapi.lib rasapi32.lib pdh.lib Crypt32.lib Version.lib Ntdll.lib - libcurl_imp libssl libcrypto + set (OS_SPECIFIC_LIBRARIES psapi.lib iphlpapi.lib dnsapi.lib rasapi32.lib pdh.lib Crypt32.lib Version.lib + libcurl_imp libssl libcrypto cares ) list(APPEND PROJECT_SOURCES client.rc) # Generate debug information (symbol files) for Windows (release build only) diff --git a/client/common/changelog.txt b/client/common/changelog.txt index 2a80713c5..de701168c 100644 --- a/client/common/changelog.txt +++ b/client/common/changelog.txt @@ -1,3 +1,14 @@ +2.7.9 (08/08/2023) +All: + * Added anti-censorship toggle in preferences. #695 + * Added anti-censorship feature: WireGuard UDP stuffing. #696 + * Added an icon on the main screen to indicate anti-censorship mode is enabled. #700 +Windows: + * Fixed DNS resolver issue. #643 & #697 +Linux: + * Fixed app fails to download update package on Ubuntu arm64. #690 + + 2.7.8 (17/07/2023) All: * Fixed spinner animation on the ROBERT page continues after the website has already been opened. #480 diff --git a/client/common/types/enginesettings.cpp b/client/common/types/enginesettings.cpp index 6a9668016..22c35abb4 100644 --- a/client/common/types/enginesettings.cpp +++ b/client/common/types/enginesettings.cpp @@ -24,7 +24,8 @@ void EngineSettings::saveToSettings() ds << d->language << d->updateChannel << d->isIgnoreSslErrors << d->isTerminateSockets << d->isAllowLanTraffic << d->firewallSettings << d->connectionSettings << d->apiResolutionSettings << d->proxySettings << d->packetSize << d->macAddrSpoofing << d->dnsPolicy << d->tapAdapter << d->customOvpnConfigsPath << d->isKeepAliveEnabled << - d->connectedDnsInfo << d->dnsManager << d->networkPreferredProtocols << d->networkLastKnownGoodProtocols; + d->connectedDnsInfo << d->dnsManager << d->networkPreferredProtocols << d->networkLastKnownGoodProtocols << + d->isAntiCensorship; } QSettings settings; @@ -63,6 +64,10 @@ void EngineSettings::loadFromSettings() { ds >> d->networkLastKnownGoodProtocols; } + if (version >= 4) + { + ds >> d->isAntiCensorship; + } if (ds.status() == QDataStream::Ok) { bLoaded = true; @@ -125,6 +130,16 @@ void EngineSettings::setIsTerminateSockets(bool close) d->isTerminateSockets = close; } +bool EngineSettings::isAntiCensorship() const +{ + return d->isAntiCensorship; +} + +void EngineSettings::setIsAntiCensorship(bool enable) +{ + d->isAntiCensorship = enable; +} + bool EngineSettings::isAllowLanTraffic() const { return d->isAllowLanTraffic; @@ -322,6 +337,7 @@ bool EngineSettings::operator==(const EngineSettings &other) const other.d->updateChannel == d->updateChannel && other.d->isIgnoreSslErrors == d->isIgnoreSslErrors && other.d->isTerminateSockets == d->isTerminateSockets && + other.d->isAntiCensorship == d->isAntiCensorship && other.d->isAllowLanTraffic == d->isAllowLanTraffic && other.d->firewallSettings == d->firewallSettings && other.d->connectionSettings == d->connectionSettings && @@ -352,6 +368,7 @@ QDebug operator<<(QDebug dbg, const EngineSettings &es) dbg << "updateChannel:" << UPDATE_CHANNEL_toString(es.d->updateChannel) << "; "; dbg << "isIgnoreSslErrors:" << es.d->isIgnoreSslErrors << "; "; dbg << "isTerminateSockets:" << es.d->isTerminateSockets << "; "; + dbg << "isAntiCensorship:" << es.d->isAntiCensorship << "; "; dbg << "isAllowLanTraffic:" << es.d->isAllowLanTraffic << "; "; dbg << "firewallSettings: " << es.d->firewallSettings << "; "; dbg << "connectionSettings: " << es.d->connectionSettings << "; "; diff --git a/client/common/types/enginesettings.h b/client/common/types/enginesettings.h index 5a05d8fc2..206d76175 100644 --- a/client/common/types/enginesettings.h +++ b/client/common/types/enginesettings.h @@ -23,6 +23,7 @@ struct EngineSettingsData : public QSharedData updateChannel(UPDATE_CHANNEL_RELEASE), isIgnoreSslErrors(false), isTerminateSockets(true), + isAntiCensorship(false), isAllowLanTraffic(false), dnsPolicy(DNS_TYPE_CLOUDFLARE), tapAdapter(WINTUN_ADAPTER), @@ -34,6 +35,7 @@ struct EngineSettingsData : public QSharedData UPDATE_CHANNEL updateChannel; bool isIgnoreSslErrors; bool isTerminateSockets; + bool isAntiCensorship; bool isAllowLanTraffic; types::FirewallSettings firewallSettings; types::ConnectionSettings connectionSettings; @@ -70,6 +72,8 @@ class EngineSettings void setIsIgnoreSslErrors(bool ignore); bool isTerminateSockets() const; void setIsTerminateSockets(bool close); + bool isAntiCensorship() const; + void setIsAntiCensorship(bool enable); bool isAllowLanTraffic() const; void setIsAllowLanTraffic(bool isAllowLanTraffic); @@ -123,7 +127,7 @@ class EngineSettings // for serialization static constexpr quint32 magic_ = 0x7745C2AE; - static constexpr int versionForSerialization_ = 3; // should increment the version if the data format is changed + static constexpr int versionForSerialization_ = 4; // should increment the version if the data format is changed }; } // types namespace diff --git a/client/common/utils/extraconfig.cpp b/client/common/utils/extraconfig.cpp index 7ce76beb1..99f5a5d45 100644 --- a/client/common/utils/extraconfig.cpp +++ b/client/common/utils/extraconfig.cpp @@ -28,6 +28,7 @@ const QString WS_USE_ICMP_PINGS = WS_PREFIX + "use-icmp-pings"; const QString WS_STEALTH_EXTRA_TLS_PADDING = WS_PREFIX + "stealth-extra-tls-padding"; const QString WS_API_EXTRA_TLS_PADDING = WS_PREFIX + "api-extra-tls-padding"; +const QString WS_WG_UDP_STUFFING = WS_PREFIX + "wireguard-udp-stuffing"; void ExtraConfig::writeConfig(const QString &cfg) { @@ -75,6 +76,10 @@ QString ExtraConfig::getExtraConfigForOpenVpn() if (isLegalOpenVpnCommand(line)) result += line + "\n"; } + if (getAntiCensorship()) { + result += "udp-stuffing\n"; + result += "tcp-split-reset\n"; + } return result; } @@ -140,6 +145,11 @@ QString ExtraConfig::modifyVerbParameter(const QString &ovpnData, QString &strEx return strOvpn; } +void ExtraConfig::setAntiCensorship(bool bEnable) +{ + isAntiCensorship_ = bEnable; +} + int ExtraConfig::getMtuOffsetIkev2(bool &success) { return getIntFromExtraConfigLines(WS_MTU_OFFSET_IKEV_STR, success); @@ -230,14 +240,24 @@ bool ExtraConfig::getUseICMPPings() return getFlagFromExtraConfigLines(WS_USE_ICMP_PINGS); } +bool ExtraConfig::getAntiCensorship() +{ + return isAntiCensorship_; +} + bool ExtraConfig::getStealthExtraTLSPadding() { - return getFlagFromExtraConfigLines(WS_STEALTH_EXTRA_TLS_PADDING); + return getFlagFromExtraConfigLines(WS_STEALTH_EXTRA_TLS_PADDING) || getAntiCensorship(); } bool ExtraConfig::getAPIExtraTLSPadding() { - return getFlagFromExtraConfigLines(WS_API_EXTRA_TLS_PADDING); + return getFlagFromExtraConfigLines(WS_API_EXTRA_TLS_PADDING) || getAntiCensorship(); +} + +bool ExtraConfig::getWireGuardUdpStuffing() +{ + return getFlagFromExtraConfigLines(WS_WG_UDP_STUFFING) || getAntiCensorship(); } int ExtraConfig::getIntFromLineWithString(const QString &line, const QString &str, bool &success) @@ -319,7 +339,8 @@ bool ExtraConfig::isLegalOpenVpnCommand(const QString &command) const ExtraConfig::ExtraConfig() : path_(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/windscribe_extra.conf"), - regExp_("(?m)^(?i)(verb)(\\s+)(\\d+$)") + regExp_("(?m)^(?i)(verb)(\\s+)(\\d+$)"), + isAntiCensorship_(false) { } diff --git a/client/common/utils/extraconfig.h b/client/common/utils/extraconfig.h index d22d2fdb1..c6a235293 100644 --- a/client/common/utils/extraconfig.h +++ b/client/common/utils/extraconfig.h @@ -19,6 +19,8 @@ class ExtraConfig void logExtraConfig(); void writeConfig(const QString &cfg); + void setAntiCensorship(bool bEnable); + bool getAntiCensorship(); QString getExtraConfig(bool bWithLog = false); QString getExtraConfigForOpenVpn(); @@ -50,6 +52,7 @@ class ExtraConfig bool getUseICMPPings(); bool getStealthExtraTLSPadding(); bool getAPIExtraTLSPadding(); + bool getWireGuardUdpStuffing(); private: ExtraConfig(); @@ -58,6 +61,7 @@ class ExtraConfig QString path_; QRegularExpression regExp_; QString detectedIp_; + bool isAntiCensorship_; int getIntFromLineWithString(const QString &line, const QString &str, bool &success); int getIntFromExtraConfigLines(const QString &variableName, bool &success); diff --git a/client/common/utils/linuxutils.h b/client/common/utils/linuxutils.h index fa3b60aaf..8b1163ed4 100644 --- a/client/common/utils/linuxutils.h +++ b/client/common/utils/linuxutils.h @@ -15,7 +15,8 @@ namespace LinuxUtils bool isGuiAlreadyRunning(); const QString LAST_INSTALL_PLATFORM_FILE = "/etc/windscribe/platform"; - const QString DEB_PLATFORM_NAME = QString("linux_deb_x64"); + const QString DEB_PLATFORM_NAME_X64 = QString("linux_deb_x64"); + const QString DEB_PLATFORM_NAME_ARM64 = QString("linux_deb_arm64"); const QString RPM_PLATFORM_NAME = QString("linux_rpm_x64"); const QString ZST_PLATFORM_NAME = QString("linux_zst_x64"); diff --git a/client/common/utils/utils.cpp b/client/common/utils/utils.cpp index 316d4d964..f663e307e 100644 --- a/client/common/utils/utils.cpp +++ b/client/common/utils/utils.cpp @@ -426,7 +426,14 @@ QString Utils::getPlatformNameSafe() { QString platform = getPlatformName(); #ifdef Q_OS_LINUX - if (platform == "") return LinuxUtils::DEB_PLATFORM_NAME; // default to debian so most of our API calls don't fail if we cannot find the /etc/windscribe/platform file (someone would have to manually delete) + // Default to debian so most of our API calls don't fail if we cannot find the /etc/windscribe/platform + // file (someone would have to manually delete) + if (platform.isEmpty()) +#ifdef __aarch64__ + return LinuxUtils::DEB_PLATFORM_NAME_ARM64; +#else + return LinuxUtils::DEB_PLATFORM_NAME_X64; +#endif #endif return platform; } diff --git a/client/common/version/windscribe_version.h b/client/common/version/windscribe_version.h index 5fa186951..0d6231fb6 100644 --- a/client/common/version/windscribe_version.h +++ b/client/common/version/windscribe_version.h @@ -2,7 +2,7 @@ #define WINDSCRIBE_MAJOR_VERSION 2 #define WINDSCRIBE_MINOR_VERSION 7 -#define WINDSCRIBE_BUILD_VERSION 8 +#define WINDSCRIBE_BUILD_VERSION 9 // only one of these should be enabled; neither -> stable //#define WINDSCRIBE_IS_BETA diff --git a/client/engine/engine/autoupdater/downloadhelper.cpp b/client/engine/engine/autoupdater/downloadhelper.cpp index 21e977274..a3a2ac2a3 100644 --- a/client/engine/engine/autoupdater/downloadhelper.cpp +++ b/client/engine/engine/autoupdater/downloadhelper.cpp @@ -1,16 +1,19 @@ #include "downloadhelper.h" -#include "utils/logger.h" -#include -#include #include -#include "names.h" +#include +#include + #include "engine/networkaccessmanager/networkaccessmanager.h" #include "engine/networkaccessmanager/networkreply.h" -#include "utils/utils.h" +#include "names.h" +#include "utils/logger.h" +#include "utils/ws_assert.h" -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) #include "utils/linuxutils.h" +#elif defined(Q_OS_MAC) +#include "utils/utils.h" #endif DownloadHelper::DownloadHelper(QObject *parent, NetworkAccessManager *networkAccessManager, const QString &platform) : QObject(parent) @@ -39,7 +42,9 @@ const QString DownloadHelper::downloadInstallerPath() const QString path = downloadInstallerPathWithoutExtension() + ".dmg"; #elif defined Q_OS_LINUX QString path; - if (platform_ == LinuxUtils::DEB_PLATFORM_NAME) { // if getPlatformName() fails, we should never get this far anyway + // if getPlatformName() fails, we should never get this far anyway + if (platform_ == LinuxUtils::DEB_PLATFORM_NAME_X64 || + platform_ == LinuxUtils::DEB_PLATFORM_NAME_ARM64) { path = downloadInstallerPathWithoutExtension() + ".deb"; } else if (platform_ == LinuxUtils::RPM_PLATFORM_NAME) { @@ -49,6 +54,7 @@ const QString DownloadHelper::downloadInstallerPath() path = downloadInstallerPathWithoutExtension() + ".pkg.tar.zst"; } #endif + WS_ASSERT(!path.isEmpty()); return path; } diff --git a/client/engine/engine/autoupdater/downloadhelper.h b/client/engine/engine/autoupdater/downloadhelper.h index 2460b9a73..2319e1580 100644 --- a/client/engine/engine/autoupdater/downloadhelper.h +++ b/client/engine/engine/autoupdater/downloadhelper.h @@ -1,5 +1,4 @@ -#ifndef DOWNLOADHELPER_H -#define DOWNLOADHELPER_H +#pragma once #include #include @@ -64,7 +63,4 @@ private slots: bool allRepliesDone(); void abortAllReplies(); void deleteAllReplies(); - }; - -#endif // DOWNLOADHELPER_H diff --git a/client/engine/engine/connectionmanager/connectionmanager.cpp b/client/engine/engine/connectionmanager/connectionmanager.cpp index 11d1dfb5d..7db5bed70 100644 --- a/client/engine/engine/connectionmanager/connectionmanager.cpp +++ b/client/engine/engine/connectionmanager/connectionmanager.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include + #include "isleepevents.h" #include "openvpnconnection.h" #include "engine/crossplatformobjectfactory.h" @@ -117,6 +120,27 @@ ConnectionManager::~ConnectionManager() SAFE_DELETE(getWireGuardConfig_); } +QString ConnectionManager::udpStuffingWithNtp(const QString &ip, const quint16 port) +{ + char ntpBuf[48] = {0}; + // NTP client behavior as seen in Linux with chrony + ntpBuf[0] = 0x23; // ntp ver=4, mode=client + ntpBuf[2] = 0x09; // polling interval=9 + ntpBuf[3] = 0x20; // clock precision + quint64 *ntpRand = (quint64*)&ntpBuf[40]; + + QUdpSocket udpSocket = QUdpSocket(); + udpSocket.bind(QHostAddress::Any, 0); + const QString localPort = QString::number(udpSocket.localPort()); + // repeat up to 5 times. Bounded argument is exclusive. + for (int i=0; i<=QRandomGenerator::global()->bounded(5); i++) { + *ntpRand = QRandomGenerator::global()->generate64(); + udpSocket.writeDatagram(ntpBuf, sizeof(ntpBuf), QHostAddress(ip), port); + } + udpSocket.close(); + return localPort; +} + void ConnectionManager::clickConnect(const QString &ovpnConfig, const apiinfo::ServerCredentials &serverCredentials, QSharedPointer bli, const types::ConnectionSettings &connectionSettings, @@ -1127,6 +1151,12 @@ void ConnectionManager::doConnectPart3() QString endpointAndPort = QString("%1:%2").arg(currentConnectionDescr_.ip).arg(currentConnectionDescr_.port); wireGuardConfig_.setPeerPublicKey(currentConnectionDescr_.wgPeerPublicKey); wireGuardConfig_.setPeerEndpoint(endpointAndPort); + + if (ExtraConfig::instance().getWireGuardUdpStuffing()) { + QString localPort = udpStuffingWithNtp(currentConnectionDescr_.ip, currentConnectionDescr_.port); + wireGuardConfig_.setClientListenPort(localPort); + } + recreateConnector(types::Protocol::WIREGUARD); connector_->startConnect(QString(), currentConnectionDescr_.ip, currentConnectionDescr_.dnsHostName, QString(), QString(), lastProxySettings_, diff --git a/client/engine/engine/connectionmanager/connectionmanager.h b/client/engine/engine/connectionmanager/connectionmanager.h index d2cce7ac6..147dee214 100644 --- a/client/engine/engine/connectionmanager/connectionmanager.h +++ b/client/engine/engine/connectionmanager/connectionmanager.h @@ -51,6 +51,8 @@ class ConnectionManager : public QObject void blockingDisconnect(); bool isDisconnected(); + QString udpStuffingWithNtp(const QString &ip, const quint16 port); + QString getLastConnectedIp(); const AdapterGatewayInfo &getDefaultAdapterInfo() const; const AdapterGatewayInfo &getVpnAdapterInfo() const; diff --git a/client/engine/engine/dnsresolver/CMakeLists.txt b/client/engine/engine/dnsresolver/CMakeLists.txt index fc925ce82..fd0749fa6 100644 --- a/client/engine/engine/dnsresolver/CMakeLists.txt +++ b/client/engine/engine/dnsresolver/CMakeLists.txt @@ -1,6 +1,8 @@ target_sources(engine PRIVATE areslibraryinit.cpp areslibraryinit.h + dnsresolver_cares.cpp + dnsresolver_cares.h dnsrequest.cpp dnsrequest.h idnsresolver.h @@ -11,20 +13,14 @@ target_sources(engine PRIVATE if (WIN32) target_sources(engine PRIVATE - dnsresolver_win.cpp - dnsresolver_win.h dnsutils_win.cpp ) elseif(APPLE) target_sources(engine PRIVATE - dnsresolver_posix.cpp - dnsresolver_posix.h dnsutils_mac.cpp ) elseif(UNIX) target_sources(engine PRIVATE - dnsresolver_posix.cpp - dnsresolver_posix.h dnsutils_linux.cpp ) endif() diff --git a/client/engine/engine/dnsresolver/dnsrequest.cpp b/client/engine/engine/dnsresolver/dnsrequest.cpp index 039f88ffc..e248ae563 100644 --- a/client/engine/engine/dnsresolver/dnsrequest.cpp +++ b/client/engine/engine/dnsresolver/dnsrequest.cpp @@ -1,19 +1,11 @@ #include "dnsrequest.h" #include "idnsresolver.h" #include "utils/logger.h" -#ifdef Q_OS_WIN - #include "dnsresolver_win.h" -#else - #include "dnsresolver_posix.h" -#endif +#include "dnsresolver_cares.h" DnsRequest::DnsRequest(QObject *parent, const QString &hostname, const QStringList &dnsServers, int timeoutMs /*= 5000*/) : QObject(parent), -#ifdef Q_OS_WIN - dnsResolver_(DnsResolver_win::instance()), -#else - dnsResolver_(DnsResolver_posix::instance()), -#endif + dnsResolver_(DnsResolver_cares::instance()), hostname_(hostname), dnsServers_(dnsServers), timeoutMs_(timeoutMs) diff --git a/client/engine/engine/dnsresolver/dnsresolver_posix.cpp b/client/engine/engine/dnsresolver/dnsresolver_cares.cpp similarity index 87% rename from client/engine/engine/dnsresolver/dnsresolver_posix.cpp rename to client/engine/engine/dnsresolver/dnsresolver_cares.cpp index 3424eb71a..760cd0731 100644 --- a/client/engine/engine/dnsresolver/dnsresolver_posix.cpp +++ b/client/engine/engine/dnsresolver/dnsresolver_cares.cpp @@ -1,4 +1,4 @@ -#include "dnsresolver_posix.h" +#include "dnsresolver_cares.h" #include "dnsutils.h" #include "utils/ws_assert.h" #include "utils/logger.h" @@ -81,8 +81,11 @@ class LookupJob : public QRunnable int nfds = ares_fds(channel, &readers, &writers); if (nfds == 0) break; - timeval *tvp = ares_timeout(channel, NULL, &tv); - select(nfds, &readers, &writers, NULL, tvp); + // do not block for longer than kTimeoutMs interval + timeval tvp; + tvp.tv_sec = 0; + tvp.tv_usec = kTimeoutMs * 1000; + select(nfds, &readers, &writers, NULL, &tvp); ares_process(channel, &readers, &writers); if (elapsedTimer.elapsed() > timeoutMs_) { userArg.errorCode = ARES_ETIMEOUT; @@ -112,8 +115,12 @@ class LookupJob : public QRunnable qint64 elapsedMs() const { return elapsedMs_; } private: - static constexpr int kTimeoutMs = 2000; - static constexpr int kTries = 1; + // 200 ms settled for faster switching to the next try (next server) + // this does not mean that the current request will be limited to 200ms, + // but after 200 ms, the next one will start parallel to the first one + // (see discussion for details: https://lists.haxx.se/pipermail/c-ares/2022-January/000032.html + static constexpr int kTimeoutMs = 200; + static constexpr int kTries = 4; // default value in c-ares, let's leave it as it is QString hostname_; QSharedPointer object_; QStringList dnsServers_; @@ -180,13 +187,13 @@ class LookupJob : public QRunnable } // namespace -DnsResolver_posix::DnsResolver_posix() +DnsResolver_cares::DnsResolver_cares() { aresLibraryInit_.init(); threadPool_ = new QThreadPool(); } -DnsResolver_posix::~DnsResolver_posix() +DnsResolver_cares::~DnsResolver_cares() { g_FinishAll = true; threadPool_->waitForDone(); @@ -194,14 +201,14 @@ DnsResolver_posix::~DnsResolver_posix() qCDebug(LOG_BASIC) << "DnsResolver stopped"; } -void DnsResolver_posix::lookup(const QString &hostname, QSharedPointer object, const QStringList &dnsServers, int timeoutMs) +void DnsResolver_cares::lookup(const QString &hostname, QSharedPointer object, const QStringList &dnsServers, int timeoutMs) { LookupJob *job = new LookupJob(hostname, object, dnsServers, timeoutMs); threadPool_->start(job); WS_ASSERT(threadPool_->activeThreadCount() <= threadPool_->maxThreadCount()); // in this case, we probably need to redo the logic } -QStringList DnsResolver_posix::lookupBlocked(const QString &hostname, const QStringList &dnsServers, int timeoutMs, QString *outError) +QStringList DnsResolver_cares::lookupBlocked(const QString &hostname, const QStringList &dnsServers, int timeoutMs, QString *outError) { LookupJob job(hostname, nullptr, dnsServers, timeoutMs); job.run(); diff --git a/client/engine/engine/dnsresolver/dnsresolver_posix.h b/client/engine/engine/dnsresolver/dnsresolver_cares.h similarity index 64% rename from client/engine/engine/dnsresolver/dnsresolver_posix.h rename to client/engine/engine/dnsresolver/dnsresolver_cares.h index ebad7052d..853ad43cf 100644 --- a/client/engine/engine/dnsresolver/dnsresolver_posix.h +++ b/client/engine/engine/dnsresolver/dnsresolver_cares.h @@ -4,14 +4,14 @@ #include "idnsresolver.h" #include "areslibraryinit.h" -// DnsResolver implementation based on the cares library (for Mac/Linux) -class DnsResolver_posix : public IDnsResolver +// DnsResolver implementation based on the cares library +class DnsResolver_cares : public IDnsResolver { public: - static DnsResolver_posix &instance() + static DnsResolver_cares &instance() { - static DnsResolver_posix s; + static DnsResolver_cares s; return s; } @@ -19,8 +19,8 @@ class DnsResolver_posix : public IDnsResolver QStringList lookupBlocked(const QString &hostname, const QStringList &dnsServers, int timeoutMs, QString *outError) override; private: - explicit DnsResolver_posix(); - virtual ~DnsResolver_posix(); + explicit DnsResolver_cares(); + virtual ~DnsResolver_cares(); private: AresLibraryInit aresLibraryInit_; diff --git a/client/engine/engine/dnsresolver/dnsserversconfiguration.cpp b/client/engine/engine/dnsresolver/dnsserversconfiguration.cpp index b75f68ac0..a7e93c7f4 100644 --- a/client/engine/engine/dnsresolver/dnsserversconfiguration.cpp +++ b/client/engine/engine/dnsresolver/dnsserversconfiguration.cpp @@ -21,21 +21,32 @@ void DnsServersConfiguration::setDnsServersPolicy(DNS_POLICY_TYPE policy) QStringList DnsServersConfiguration::getCurrentDnsServers() const { QMutexLocker locker(&mutex_); - if (isConnectedToVpn_) + if (isConnectedToVpn_) { + // For windows c-ares library puts the loopback address in low priority and this + // creates unnecessary delay when executing a dns request + // As a workaround, we form a list of servers ourselves for a loopback adress, bypassing c-ares. +#ifdef Q_OS_WIN + if (vpnDnsServers_.size() == 1 && vpnDnsServers_[0].startsWith("127.0.0")) { + return vpnDnsServers_; + } +#endif return QStringList(); // use OS default DNS - else + } else { return ips; + } } -void DnsServersConfiguration::setConnectedState() +void DnsServersConfiguration::setConnectedState(const QStringList &vpnDnsServers) { QMutexLocker locker(&mutex_); + vpnDnsServers_ = vpnDnsServers; isConnectedToVpn_ = true; } void DnsServersConfiguration::setDisconnectedState() { QMutexLocker locker(&mutex_); + vpnDnsServers_.clear(); isConnectedToVpn_ = false; } diff --git a/client/engine/engine/dnsresolver/dnsserversconfiguration.h b/client/engine/engine/dnsresolver/dnsserversconfiguration.h index a76660933..9e93acbc0 100644 --- a/client/engine/engine/dnsresolver/dnsserversconfiguration.h +++ b/client/engine/engine/dnsresolver/dnsserversconfiguration.h @@ -21,11 +21,13 @@ class DnsServersConfiguration QStringList getCurrentDnsServers() const; - void setConnectedState(); + void setConnectedState(const QStringList &vpnDnsServers); void setDisconnectedState(); private: QStringList ips; + + QStringList vpnDnsServers_; bool isConnectedToVpn_ = false; mutable QMutex mutex_; diff --git a/client/engine/engine/engine.cpp b/client/engine/engine/engine.cpp index a409076ad..37d8a20be 100644 --- a/client/engine/engine/engine.cpp +++ b/client/engine/engine/engine.cpp @@ -1399,7 +1399,7 @@ void Engine::onConnectionManagerConnected() networkAccessManager_->disableProxy(); locationsModel_->disableProxy(); - DnsServersConfiguration::instance().setConnectedState(); + DnsServersConfiguration::instance().setConnectedState(connectionManager_->getVpnAdapterInfo().dnsServers()); if (engineSettings_.isTerminateSockets()) { @@ -1903,7 +1903,7 @@ void Engine::onEmergencyControllerConnected() #endif networkAccessManager_->disableProxy(); - DnsServersConfiguration::instance().setConnectedState(); + DnsServersConfiguration::instance().setConnectedState(emergencyController_->getVpnAdapterInfo().dnsServers()); emergencyConnectStateController_->setConnectedState(LocationID()); Q_EMIT emergencyConnected(); diff --git a/client/engine/engine/wireguardconfig/wireguardconfig.cpp b/client/engine/engine/wireguardconfig/wireguardconfig.cpp index 81e181b16..d09e1433f 100644 --- a/client/engine/engine/wireguardconfig/wireguardconfig.cpp +++ b/client/engine/engine/wireguardconfig/wireguardconfig.cpp @@ -20,6 +20,7 @@ WireGuardConfig::WireGuardConfig(const QString &privateKey, const QString &ipAdd client_.privateKey = privateKey; client_.ipAddress = ipAddress; client_.dnsAddress = dnsAddress; + client_.listenPort = QString(); peer_.publicKey = publicKey; peer_.presharedKey = presharedKey; peer_.endpoint = endpoint; @@ -59,6 +60,11 @@ bool WireGuardConfig::generateConfigFile(const QString &fileName) const ts << "PrivateKey = " << client_.privateKey << '\n'; ts << "Address = " << client_.ipAddress << '\n'; ts << "DNS = " << client_.dnsAddress << '\n'; + + if (!client_.listenPort.isEmpty()) { + ts << "ListenPort = " << client_.listenPort << '\n'; + } + ts << '\n'; ts << "[Peer]\n"; ts << "PublicKey = " << peer_.publicKey << '\n'; @@ -92,6 +98,7 @@ void WireGuardConfig::reset() client_.publicKey.clear(); client_.ipAddress.clear(); client_.dnsAddress.clear(); + client_.listenPort.clear(); peer_.publicKey.clear(); peer_.presharedKey.clear(); peer_.endpoint.clear(); @@ -170,7 +177,7 @@ bool WireGuardConfig::haveServerGeneratedPeerParams() const QDataStream& operator <<(QDataStream &stream, const WireGuardConfig &c) { stream << c.versionForSerialization_; - stream << c.client_.privateKey << c.client_.publicKey << c.client_.ipAddress << c.client_.dnsAddress; + stream << c.client_.privateKey << c.client_.publicKey << c.client_.ipAddress << c.client_.dnsAddress << c.client_.listenPort; stream << c.peer_.publicKey << c.peer_.presharedKey << c.peer_.endpoint << c.peer_.allowedIps; return stream; } @@ -185,6 +192,9 @@ QDataStream& operator >>(QDataStream &stream, WireGuardConfig &c) } stream >> c.client_.privateKey >> c.client_.publicKey >> c.client_.ipAddress >> c.client_.dnsAddress; + if (version >= 2) { + stream >> c.client_.listenPort; + } stream >> c.peer_.publicKey >> c.peer_.presharedKey >> c.peer_.endpoint >> c.peer_.allowedIps; return stream; } diff --git a/client/engine/engine/wireguardconfig/wireguardconfig.h b/client/engine/engine/wireguardconfig/wireguardconfig.h index 6e88a2dfe..f1c533f8c 100644 --- a/client/engine/engine/wireguardconfig/wireguardconfig.h +++ b/client/engine/engine/wireguardconfig/wireguardconfig.h @@ -16,6 +16,7 @@ class WireGuardConfig QString clientPublicKey() const { return client_.publicKey; } QString clientIpAddress() const { return client_.ipAddress; } QString clientDnsAddress() const { return client_.dnsAddress; } + QString clientListenPort() const { return client_.listenPort; } QString peerPublicKey() const { return peer_.publicKey; } QString peerPresharedKey() const { return peer_.presharedKey; } @@ -27,6 +28,7 @@ class WireGuardConfig void setPeerAllowedIPs(const QString &allowedIPs) { peer_.allowedIps = allowedIPs; } void setClientIpAddress(const QString &ip) { client_.ipAddress = ip; } void setClientDnsAddress(const QString &dns) { client_.dnsAddress = dns; } + void setClientListenPort(const QString &listenPort) { client_.listenPort = listenPort; } bool haveServerGeneratedPeerParams() const; bool generateConfigFile(const QString &fileName) const; @@ -47,6 +49,7 @@ class WireGuardConfig QString publicKey; QString ipAddress; QString dnsAddress; + QString listenPort; } client_; struct { QString publicKey; @@ -56,5 +59,5 @@ class WireGuardConfig } peer_; // for serialization - static constexpr quint32 versionForSerialization_ = 1; // should increment the version if the data format is changed + static constexpr quint32 versionForSerialization_ = 2; // should increment the version if the data format is changed }; diff --git a/client/gui/backend/preferences/preferences.cpp b/client/gui/backend/preferences/preferences.cpp index 57878fdce..893752cee 100644 --- a/client/gui/backend/preferences/preferences.cpp +++ b/client/gui/backend/preferences/preferences.cpp @@ -414,6 +414,22 @@ void Preferences::setTerminateSockets(bool b) } #endif +bool Preferences::isAntiCensorship() const +{ + return engineSettings_.isAntiCensorship(); +} + +void Preferences::setAntiCensorship(bool b) +{ + if (engineSettings_.isAntiCensorship() != b) + { + engineSettings_.setIsAntiCensorship(b); + ExtraConfig::instance().setAntiCensorship(b); + emitEngineSettingsChanged(); + emit isAntiCensorshipChanged(engineSettings_.isAntiCensorship()); + } +} + const types::ShareSecureHotspot &Preferences::shareSecureHotspot() const { return guiSettings_.shareSecureHotspot; @@ -682,6 +698,7 @@ void Preferences::setEngineSettings(const types::EngineSettings &es) #if defined(Q_OS_WIN) setTerminateSockets(es.isTerminateSockets()); #endif + setAntiCensorship(es.isAntiCensorship()); #if defined(Q_OS_WIN) setTapAdapter(es.tapAdapter()); #endif diff --git a/client/gui/backend/preferences/preferences.h b/client/gui/backend/preferences/preferences.h index d73de13f5..569e7bfa2 100644 --- a/client/gui/backend/preferences/preferences.h +++ b/client/gui/backend/preferences/preferences.h @@ -94,6 +94,9 @@ class Preferences : public QObject void setTerminateSockets(bool b); #endif + bool isAntiCensorship() const; + void setAntiCensorship(bool b); + const types::ShareSecureHotspot &shareSecureHotspot() const; void setShareSecureHotspot(const types::ShareSecureHotspot &ss); @@ -177,6 +180,7 @@ class Preferences : public QObject void isAutoSecureNetworksChanged(bool b); void minimizeAndCloseToTrayChanged(bool b); void isTerminateSocketsChanged(bool b); + void isAntiCensorshipChanged(bool b); void tapAdapterChanged(TAP_ADAPTER_TYPE tapAdapter); void hideFromDockChanged(bool b); void shareSecureHotspotChanged(const types::ShareSecureHotspot &ss); diff --git a/client/gui/commongraphics/iconbutton.cpp b/client/gui/commongraphics/iconbutton.cpp index a8d68c992..4535ffa1f 100644 --- a/client/gui/commongraphics/iconbutton.cpp +++ b/client/gui/commongraphics/iconbutton.cpp @@ -39,7 +39,7 @@ void IconButton::paint(QPainter *painter, const QStyleOptionGraphicsItem *option qreal initialOpacity = painter->opacity(); painter->setOpacity(curOpacity_ * initialOpacity); - int rcW = static_cast(boundingRect().width() ); + int rcW = static_cast(boundingRect().width()); int rcH = static_cast(boundingRect().height()); if (imageWithShadow_) diff --git a/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.cpp b/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.cpp index d03ac9f3f..253a317b2 100644 --- a/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.cpp +++ b/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.cpp @@ -40,6 +40,9 @@ ConnectStateProtocolPort::ConnectStateProtocolPort(ScalableGraphicsObject *paren preferredProtocolBadge_->setClickableHoverable(false, false); + antiCensorshipBadge_ = new IconButton(8, 16, "preferences/CIRCUMVENT_CENSORSHIP", "", this, OPACITY_FULL, OPACITY_FULL); + antiCensorshipBadge_->setClickableHoverable(false, false); + setClickableHoverable(true, false); recalcSize(); } @@ -140,9 +143,6 @@ void ConnectStateProtocolPort::updateStateDisplay(const types::ConnectState &con connectionBadgeDots_->hide(); connectionBadgeDots_->stop(); } - badgePixmap_.setColor(badgeBgColor_); - protocolArrow_->setTintColor(textColor_); - preferredProtocolBadge_->setTintColor(textColor_); } else { @@ -164,10 +164,13 @@ void ConnectStateProtocolPort::updateStateDisplay(const types::ConnectState &con textOpacity_ = 1.0; textColor_ = FontManager::instance().getBrightYellowColor(); } - badgePixmap_.setColor(badgeBgColor_); - protocolArrow_->setTintColor(textColor_); - preferredProtocolBadge_->setTintColor(textColor_); } + + badgePixmap_.setColor(badgeBgColor_); + protocolArrow_->setTintColor(textColor_); + preferredProtocolBadge_->setTintColor(textColor_); + antiCensorshipBadge_->setTintColor(textColor_); + recalcSize(); } @@ -290,12 +293,31 @@ void ConnectStateProtocolPort::recalcSize() if (isPreferredProtocol_) { width_ += preferredProtocolBadge_->boundingRect().width() + separatorWidth; } + if (isAntiCensorshipEnabled_) { + width_ += antiCensorshipBadge_->boundingRect().width() + separatorWidth; + } height_ = badgeHeight; protocolArrow_->setPos(width_ - protocolArrowWidth - 4*G_SCALE + arrowShift_*G_SCALE, 2*G_SCALE); + preferredProtocolBadge_->setVisible(isPreferredProtocol_); - preferredProtocolBadge_->setPos(protocolWidth + portWidth + badgeWidth + 4*separatorWidth + 4*G_SCALE, - boundingRect().height()/2 - preferredProtocolBadge_->boundingRect().height()/2); + if (isPreferredProtocol_) { + preferredProtocolBadge_->setPos(protocolWidth + portWidth + badgeWidth + 4*separatorWidth + 4*G_SCALE, + boundingRect().height()/2 - preferredProtocolBadge_->boundingRect().height()/2); + } + + antiCensorshipBadge_->setVisible(isAntiCensorshipEnabled_); + if (isAntiCensorshipEnabled_) { + qreal antiCensorshipBadgeLeft; + if (isPreferredProtocol_) { + antiCensorshipBadgeLeft = preferredProtocolBadge_->pos().x() + preferredProtocolBadge_->boundingRect().width() + separatorWidth; + } + else { + antiCensorshipBadgeLeft = protocolWidth + portWidth + badgeWidth + 4*separatorWidth + 4*G_SCALE; + } + + antiCensorshipBadge_->setPos(antiCensorshipBadgeLeft, boundingRect().height()/2 - antiCensorshipBadge_->boundingRect().height()/2); + } } types::ProtocolStatus ConnectStateProtocolPort::getProtocolStatus() @@ -324,13 +346,13 @@ void ConnectStateProtocolPort::setProtocolButtonVisible(bool visible) void ConnectStateProtocolPort::onHoverEnter() { - protocolArrow_->hoverEnter(); + protocolArrow_->hover(); startAnAnimation(protocolArrowAnimation_, arrowShift_, 4, ANIMATION_SPEED_FAST); } void ConnectStateProtocolPort::onHoverLeave() { - protocolArrow_->hoverLeave(); + protocolArrow_->unhover(); startAnAnimation(protocolArrowAnimation_, arrowShift_, 0, ANIMATION_SPEED_FAST); } @@ -340,4 +362,10 @@ void ConnectStateProtocolPort::setIsPreferredProtocol(bool on) recalcSize(); } +void ConnectStateProtocolPort::antiCensorshipChanged(bool enabled) +{ + isAntiCensorshipEnabled_ = enabled; + recalcSize(); +} + } //namespace ConnectWindow diff --git a/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.h b/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.h index 82e48eb03..fee3a65b3 100644 --- a/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.h +++ b/client/gui/connectwindow/connectstateprotocolport/connectstateprotocolport.h @@ -43,6 +43,9 @@ class ConnectStateProtocolPort : public ClickableGraphicsObject signals: void protocolsClick(); +public slots: + void antiCensorshipChanged(bool enabled); + private slots: void onProtocolTestTunnelTimerTick(); void onProtocolOpacityAnimationChanged(const QVariant &value); @@ -78,6 +81,9 @@ private slots: IconButton *protocolArrow_; int arrowShift_; + IconButton *antiCensorshipBadge_; + bool isAntiCensorshipEnabled_ = false; + int width_; int height_; void recalcSize(); diff --git a/client/gui/connectwindow/connectwindowitem.cpp b/client/gui/connectwindow/connectwindowitem.cpp index a2749dde1..df4d11d69 100644 --- a/client/gui/connectwindow/connectwindowitem.cpp +++ b/client/gui/connectwindow/connectwindowitem.cpp @@ -65,6 +65,7 @@ ConnectWindowItem::ConnectWindowItem(QGraphicsObject *parent, Preferences *prefe connect(connectStateProtocolPort_, &ClickableGraphicsObject::hoverEnter, this, &ConnectWindowItem::onConnectStateTextHoverEnter); connect(connectStateProtocolPort_, &ClickableGraphicsObject::hoverLeave, this, &ConnectWindowItem::onConnectStateTextHoverLeave); connect(connectStateProtocolPort_, &ClickableGraphicsObject::clicked, this, &ConnectWindowItem::onProtocolsClick); + connect(preferences_, &Preferences::isAntiCensorshipChanged, connectStateProtocolPort_, &ConnectStateProtocolPort::antiCensorshipChanged); cityName1Text_ = new CommonGraphics::TextButton("", FontDescr(28, true), Qt::white, true, this, 0, true); cityName1Text_->setUnhoverOpacity(OPACITY_FULL); diff --git a/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.cpp b/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.cpp index 3e241d8a2..f76b7ffff 100644 --- a/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.cpp +++ b/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.cpp @@ -38,6 +38,7 @@ ConnectionWindowItem::ConnectionWindowItem(ScalableGraphicsObject *parent, Prefe connect(preferencesHelper, &PreferencesHelper::isExternalConfigModeChanged, this, &ConnectionWindowItem::onIsExternalConfigModeChanged); connect(preferencesHelper, &PreferencesHelper::proxyGatewayAddressChanged, this, &ConnectionWindowItem::onProxyGatewayAddressChanged); connect(preferences, &Preferences::isTerminateSocketsChanged, this, &ConnectionWindowItem::onTerminateSocketsPreferencesChanged); + connect(preferences, &Preferences::isAntiCensorshipChanged, this, &ConnectionWindowItem::onAntiCensorshipPreferencesChanged); connect(preferences, &Preferences::isAutoConnectChanged, this, &ConnectionWindowItem::onIsAutoConnectPreferencesChanged); subpagesGroup_ = new PreferenceGroup(this); @@ -153,6 +154,14 @@ ConnectionWindowItem::ConnectionWindowItem(ScalableGraphicsObject *parent, Prefe proxyGatewayGroup_->setProxyGatewaySettings(preferences->shareProxyGateway()); addItem(proxyGatewayGroup_); + antiCensorshipGroup_ = new PreferenceGroup(this); + antiCensorshipItem_ = new ToggleItem(antiCensorshipGroup_, tr("Circumvent Censorship")); + antiCensorshipItem_->setIcon(ImageResourcesSvg::instance().getIndependentPixmap("preferences/CIRCUMVENT_CENSORSHIP")); + antiCensorshipItem_->setState(preferences->isAntiCensorship()); + connect(antiCensorshipItem_, &ToggleItem::stateChanged, this, &ConnectionWindowItem::onAntiCensorshipPreferencesChangedByUser); + antiCensorshipGroup_->addItem(antiCensorshipItem_); + addItem(antiCensorshipGroup_); + connect(&LanguageController::instance(), &LanguageController::languageChanged, this, &ConnectionWindowItem::onLanguageChanged); onLanguageChanged(); } @@ -230,6 +239,11 @@ void ConnectionWindowItem::onTerminateSocketsPreferencesChangedByUser(bool isChe #endif } +void ConnectionWindowItem::onAntiCensorshipPreferencesChangedByUser(bool isChecked) +{ + preferences_->setAntiCensorship(isChecked); +} + void ConnectionWindowItem::onSplitTunnelingPreferencesChanged(const types::SplitTunneling &st) { #ifndef Q_OS_LINUX @@ -286,6 +300,11 @@ void ConnectionWindowItem::onTerminateSocketsPreferencesChanged(bool b) #endif } +void ConnectionWindowItem::onAntiCensorshipPreferencesChanged(bool b) +{ + antiCensorshipItem_->setState(b); +} + void ConnectionWindowItem::onAllowLanTrafficButtonHoverLeave() { TooltipController::instance().hideTooltip(TOOLTIP_ID_INVALID_LAN_ADDRESS); @@ -355,6 +374,8 @@ void ConnectionWindowItem::onLanguageChanged() #endif proxyGatewayGroup_->setDescription(tr("Configure your TV, gaming console, or other devices that support proxy servers.")); + antiCensorshipItem_->setCaption(tr("Circumvent Censorship")); + antiCensorshipGroup_->setDescription(tr("Connect to the VPN even in hostile environment.")); } void ConnectionWindowItem::onIsAllowLanTrafficPreferencesChangedByUser(bool b) diff --git a/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.h b/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.h index 5123c6c48..5f666360a 100644 --- a/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.h +++ b/client/gui/preferenceswindow/connectionwindow/connectionwindowitem.h @@ -64,6 +64,7 @@ private slots: void onIsFirewallBlockedChanged(bool bFirewallBlocked); void onIsExternalConfigModeChanged(bool bIsExternalConfigMode); void onTerminateSocketsPreferencesChanged(bool b); + void onAntiCensorshipPreferencesChanged(bool b); void onIsAutoConnectPreferencesChanged(bool b); // slots for changes made by user @@ -76,6 +77,7 @@ private slots: void onSecureHotspotPreferencesChangedByUser(const types::ShareSecureHotspot &ss); void onProxyGatewayPreferencesChangedByUser(const types::ShareProxyGateway &sp); void onTerminateSocketsPreferencesChangedByUser(bool isChecked); + void onAntiCensorshipPreferencesChangedByUser(bool isChecked); void onIsAutoConnectPreferencesChangedByUser(bool b); void onLanguageChanged(); @@ -101,6 +103,8 @@ private slots: ConnectedDnsGroup *connectedDnsGroup_; PreferenceGroup *terminateSocketsGroup_; ToggleItem *terminateSocketsItem_; + PreferenceGroup *antiCensorshipGroup_; + ToggleItem *antiCensorshipItem_; SecureHotspotGroup *secureHotspotGroup_; ProxyGatewayGroup *proxyGatewayGroup_; diff --git a/client/gui/preferenceswindow/generalwindow/generalwindowitem.cpp b/client/gui/preferenceswindow/generalwindow/generalwindowitem.cpp index 6cbd4ffc9..a3bd363bd 100644 --- a/client/gui/preferenceswindow/generalwindow/generalwindowitem.cpp +++ b/client/gui/preferenceswindow/generalwindow/generalwindowitem.cpp @@ -368,16 +368,17 @@ void GeneralWindowItem::onAppSkinPreferencesChanged(APP_SKIN s) void GeneralWindowItem::onVersionInfoClicked() { - QString platform; #ifdef Q_OS_WIN - platform = "windows"; + QString platform = "windows"; #elif defined(Q_OS_MAC) - platform = "mac"; + QString platform = "mac"; #else - platform = LinuxUtils::getLastInstallPlatform(); - if (platform == LinuxUtils::DEB_PLATFORM_NAME) { + QString platform; + QString lastPlatform = LinuxUtils::getLastInstallPlatform(); + if (lastPlatform == LinuxUtils::DEB_PLATFORM_NAME_X64 || + lastPlatform == LinuxUtils::DEB_PLATFORM_NAME_ARM64) { platform = "linux_deb"; - } else if (platform == LinuxUtils::RPM_PLATFORM_NAME) { + } else if (lastPlatform == LinuxUtils::RPM_PLATFORM_NAME) { platform = "linux_rpm"; } else { // We don't have a website changelog for zst yet, go to top page instead diff --git a/client/gui/svg.qrc b/client/gui/svg.qrc index 96fd9d34b..cb5c29cee 100644 --- a/client/gui/svg.qrc +++ b/client/gui/svg.qrc @@ -146,6 +146,7 @@ svg/preferences/AUTOSECURE_NETWORKS.svg svg/preferences/CLEAR_ICON.svg svg/preferences/CLOSE_ICON.svg + svg/preferences/CIRCUMVENT_CENSORSHIP.svg svg/preferences/CNTXT_MENU_ICON.svg svg/preferences/COMMUNITY_SUPPORT.svg svg/preferences/CONFIRM_ICON.svg diff --git a/client/gui/svg/preferences/CIRCUMVENT_CENSORSHIP.svg b/client/gui/svg/preferences/CIRCUMVENT_CENSORSHIP.svg new file mode 100644 index 000000000..41152aec2 --- /dev/null +++ b/client/gui/svg/preferences/CIRCUMVENT_CENSORSHIP.svg @@ -0,0 +1,3 @@ + + + diff --git a/client/gui/translations/ws_desktop_ru.ts b/client/gui/translations/ws_desktop_ru.ts index b50cc6a5f..205cb8a3c 100644 --- a/client/gui/translations/ws_desktop_ru.ts +++ b/client/gui/translations/ws_desktop_ru.ts @@ -832,14 +832,14 @@ Пожалуйста, свяжитесь со службой поддержки - + Lost connection to the backend process. Recovering... Потеряно соединение с серверным процессом. Восстановление... - + Select an application Выберите приложение @@ -989,18 +989,18 @@ If the problem persists after a restart, please send a debug log and open a supp Preferences - - + + Invalid DNS Settings Недопустимые настройки DNS - + 'Connected DNS' was not configured with a valid Upstream 1 (IP/DNS-over-HTTPS/TLS). DNS was reverted to ROBERT (default). "Подключенный DNS" не был настроен с допустимым исходящим потоком 1 (IP/DNS-over-HTTPS/TLS). DNS был возвращен к ROBERT (по умолчанию). - + 'Connected DNS' was not configured with a valid Upstream 2 (IP/DNS-over-HTTPS/TLS). DNS was reverted to ROBERT (default). 'Подключенный DNS' не был настроен с допустимым апстримом 2 (IP/DNS-over-HTTPS/TLS). DNS был перенастроен на ROBERT (по умолчанию). @@ -1306,119 +1306,130 @@ If the problem persists after a restart, please send a debug log and open a supp PreferencesWindow::ConnectionWindowItem - - + + Allow LAN Traffic Разрешить трафик локальной сети - + Terminate Sockets Закрытие сокетов - + + + Circumvent Censorship + Обход блокировок + + + Connection Связь - + Exclusive Исключающий - + Inclusive Включающий - + Off Выкл. - + Network Options Параметры сети - + Split Tunneling Раздельное туннелирование - + Proxy Settings Настройки прокси-сервера - + Connects to last used location when the app launches or joins a network. Подключаться к последней используемой локации при запуске приложения или присоединении к сети. - + Auto-Connect Автоматическое подключение - + Control the mode of behavior of the Windscribe firewall. Управление режимом поведения брандмауэра Windscribe. - + Connection Mode Режим подключения - + Automatically choose the VPN protocol, or select one manually. Выбор VPN-протокола автоматически или вручную - + Automatically determine the MTU for your connection, or manually override. Автоматическое определение MTU для подключения или переопределение вручную. - + Select the DNS server while connected to Windscribe. Выберите DNS-сервер при подключении к Windscribe. - + Allow access to local services and printers while connected to Windscribe. Разрешить доступ к локальным службам и принтерам при подключении к Windscribe. - + Spoof your device's physical address (MAC address). Подделка физичесого адреса (MAC-адреса) устройства. - + Close all active TCP sockets when the VPN tunnel is established. Закрытие всех активных TCP-соединений при установке VPN-туннеля. - + Configure your TV, gaming console, or other devices that support proxy servers. Настройка телевизора, игровой консоли и других устройств, поддерживающих прокси-серверы. - - + + Connect to the VPN even in hostile environment. + Подключаться к VPN даже во враждебно настроенной сети. + + + + Settings Conflict Конфликт настроек - + Disabling Allow LAN Traffic will cause your proxy gateway to stop working. Do you want to disable the proxy? Отключение параметра "Разрешить трафик локальной сети" приведет к тому, что прокси-шлюз перестанет работать. Вы хотите отключить прокси? - + LAN traffic is currently blocked by the Windscribe firewall. Do you want to allow LAN traffic to bypass the firewall in order for this feature to work? Трафик локальной сети в настоящее время блокируется брандмауэром Windscribe. Вы хотите разрешить трафику локальной сети обходить брандмауэр, чтобы эта функция заработала? @@ -2141,9 +2152,13 @@ Connect to a network first Безопасная точка доступа не поддерживается сетевым адаптером. - Secure hotspot is not supported for IKEv2/WireGuard protocol and automatic connection mode. - Безопасная точка доступа не поддерживается для протокола IKEv2/WireGuard и режима автоматического подключения. + Безопасная точка доступа не поддерживается для протокола IKEv2/WireGuard и режима автоматического подключения. + + + + Secure hotspot is not supported for IKEv2 protocol. + diff --git a/client/gui/utils/authchecker_linux.cpp b/client/gui/utils/authchecker_linux.cpp index 8c622ef12..0fdfcfdef 100644 --- a/client/gui/utils/authchecker_linux.cpp +++ b/client/gui/utils/authchecker_linux.cpp @@ -45,6 +45,6 @@ AuthCheckerError AuthChecker_linux::authenticate() qCDebug(LOG_AUTH_HELPER) << "Failed to authenticate: " << process_->exitStatus() << ", code: " << process_->exitCode() << ", error: " << process_->error(); - return AuthCheckerError::AUTH_NO_ERROR; + return AuthCheckerError::AUTH_AUTHENTICATION_ERROR; } diff --git a/tools/requirements.txt b/tools/requirements.txt index a6ebaad22..d20b8c840 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,4 +1,4 @@ colorama -pyyaml +pyyaml==6.0 requests translate-toolkit[XML]