Compare commits

...

9 Commits

Author SHA1 Message Date
Mykola Baibuz f3b3e937e9 Update binaries 2024-09-11 00:29:07 +03:00
Mykola Baibuz 92492952e9 Update prebuilt 2024-09-10 21:45:46 +03:00
vladimir.kuznetsov 3d152adf5f chore: removed unused header 2024-09-10 22:25:06 +04:00
vladimir.kuznetsov 9be3221cbe Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/goodbyedpi 2024-09-10 21:53:14 +04:00
vladimir.kuznetsov d47e37e04f limited goodbyedpi to the windows platform 2024-09-10 21:40:46 +04:00
vladimir.kuznetsov 5e27f0c8f0 feature: added a ui with the feature to configure goodbye dpi
- added configuration file selection
- added modset selection
2024-09-10 17:31:44 +04:00
Mykola Baibuz c7a48aeabc Update GoodByeDPI description 2024-09-05 15:55:08 +03:00
Mykola Baibuz ca1bf0d6cd Setup correct blacklist path 2024-09-04 23:51:23 +03:00
Mykola Baibuz 96f26d5a01 GoodByeDPI support initial 2024-09-04 23:23:52 +03:00
31 changed files with 630 additions and 50 deletions
+10 -2
View File
@@ -241,8 +241,14 @@ file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp ${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
) )
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h) file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp) ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h
${CMAKE_CURRENT_LIST_DIR}/ui/models/localServices/*.h
)
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/models/localServices/*.cpp
)
set(HEADERS ${HEADERS} set(HEADERS ${HEADERS}
${COMMON_FILES_H} ${COMMON_FILES_H}
@@ -267,10 +273,12 @@ if(WIN32)
set(HEADERS ${HEADERS} set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h ${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.h
) )
set(SOURCES ${SOURCES} set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp ${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.cpp
) )
set(RESOURCES ${RESOURCES} set(RESOURCES ${RESOURCES}
+10
View File
@@ -235,6 +235,7 @@ void AmneziaApplication::registerTypes()
Vpn::declareQmlVpnConnectionStateEnum(); Vpn::declareQmlVpnConnectionStateEnum();
PageLoader::declareQmlPageEnum(); PageLoader::declareQmlPageEnum();
PageLoader::declareQmlFolderEnum();
} }
void AmneziaApplication::loadFonts() void AmneziaApplication::loadFonts()
@@ -455,4 +456,13 @@ void AmneziaApplication::initControllers()
m_systemController.reset(new SystemController(m_settings)); m_systemController.reset(new SystemController(m_settings));
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get()); m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
m_localServicesController.reset(new LocalServicesController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("LocalServicesController", m_localServicesController.get());
connect(m_connectionController.get(), &ConnectionController::startLocalService, m_localServicesController.get(),
&LocalServicesController::start);
connect(m_connectionController.get(), &ConnectionController::stopLocalService, m_localServicesController.get(),
&LocalServicesController::stop);
connect(m_localServicesController.get(), &LocalServicesController::serviceStateChanged, m_connectionController.get(),
&ConnectionController::connectionStateChanged);
} }
+2
View File
@@ -24,6 +24,7 @@
#include "ui/controllers/sitesController.h" #include "ui/controllers/sitesController.h"
#include "ui/controllers/systemController.h" #include "ui/controllers/systemController.h"
#include "ui/controllers/appSplitTunnelingController.h" #include "ui/controllers/appSplitTunnelingController.h"
#include "ui/controllers/localServicesController.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/languageModel.h" #include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h" #include "ui/models/protocols/cloakConfigModel.h"
@@ -136,6 +137,7 @@ private:
QScopedPointer<SitesController> m_sitesController; QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController; QScopedPointer<SystemController> m_systemController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController; QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
QScopedPointer<LocalServicesController> m_localServicesController;
QNetworkAccessManager *m_nam; QNetworkAccessManager *m_nam;
+24 -24
View File
@@ -1,7 +1,7 @@
#include "containers_defs.h" #include "containers_defs.h"
#include "QJsonObject"
#include "QJsonDocument" #include "QJsonDocument"
#include "QJsonObject"
QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c) QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
{ {
@@ -96,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{ DockerContainer::Awg, "AmneziaWG" }, { DockerContainer::Awg, "AmneziaWG" },
{ DockerContainer::Xray, "XRay" }, { DockerContainer::Xray, "XRay" },
{ DockerContainer::Ipsec, QObject::tr("IPsec") }, { DockerContainer::Ipsec, QObject::tr("IPsec") },
{ DockerContainer::SSXray, "Shadowsocks"}, { DockerContainer::SSXray, "Shadowsocks" },
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") }, { DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") }, { DockerContainer::Dns, QObject::tr("AmneziaDNS") },
@@ -124,27 +124,24 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
"but very resistant to blockages. " "but very resistant to blockages. "
"Recommended for regions with high levels of censorship.") }, "Recommended for regions with high levels of censorship.") },
{ DockerContainer::Xray, { DockerContainer::Xray,
QObject::tr("XRay with REALITY - Suitable for countries with the highest level of internet censorship. " QObject::tr(
"Traffic masking as web traffic at the TLS level, and protection against detection by active probing methods.") }, "XRay with REALITY - Suitable for countries with the highest level of internet censorship. "
"Traffic masking as web traffic at the TLS level, and protection against detection by active probing methods.") },
{ DockerContainer::Ipsec, { DockerContainer::Ipsec,
QObject::tr("IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after " QObject::tr("IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after "
"signal loss. It has native support on the latest versions of Android and iOS.") }, "signal loss. It has native support on the latest versions of Android and iOS.") },
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") }, { DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
{ DockerContainer::Dns, { DockerContainer::Dns, QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") }, { DockerContainer::Sftp, QObject::tr("Create a file vault on your server to securely store and transfer files.") },
{ DockerContainer::Sftp, { DockerContainer::Socks5Proxy, QObject::tr("") } };
QObject::tr("Create a file vault on your server to securely store and transfer files.") },
{ DockerContainer::Socks5Proxy,
QObject::tr("") } };
} }
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions() QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
{ {
return { return {
{ DockerContainer::OpenVpn, { DockerContainer::OpenVpn,
QObject::tr( QObject::tr("OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
"It employs its unique security protocol, " "It employs its unique security protocol, "
"leveraging the strength of SSL/TLS for encryption and key exchange. " "leveraging the strength of SSL/TLS for encryption and key exchange. "
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, " "Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
@@ -160,7 +157,8 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
"* Can operate over both TCP and UDP network protocols.") }, "* Can operate over both TCP and UDP network protocols.") },
{ DockerContainer::ShadowSocks, { DockerContainer::ShadowSocks,
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. " QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection." "Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS "
"connection."
"However, certain traffic analysis systems might still detect a Shadowsocks connection. " "However, certain traffic analysis systems might still detect a Shadowsocks connection. "
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n" "Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
"* Available in the AmneziaVPN only on desktop platforms\n" "* Available in the AmneziaVPN only on desktop platforms\n"
@@ -217,15 +215,18 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
"* Works over UDP network protocol.") }, "* Works over UDP network protocol.") },
{ DockerContainer::Xray, { DockerContainer::Xray,
QObject::tr("The REALITY protocol, a pioneering development by the creators of XRay, " QObject::tr("The REALITY protocol, a pioneering development by the creators of XRay, "
"is specifically designed to counteract the highest levels of internet censorship through its novel approach to evasion.\n" "is specifically designed to counteract the highest levels of internet censorship through its novel approach to "
"It uniquely identifies censors during the TLS handshake phase, seamlessly operating as a proxy for legitimate clients while diverting censors to genuine websites like google.com, " "evasion.\n"
"It uniquely identifies censors during the TLS handshake phase, seamlessly operating as a proxy for legitimate "
"clients while diverting censors to genuine websites like google.com, "
"thus presenting an authentic TLS certificate and data. \n" "thus presenting an authentic TLS certificate and data. \n"
"This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as coming from random, " "This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as "
"coming from random, "
"legitimate sites without the need for specific configurations. \n" "legitimate sites without the need for specific configurations. \n"
"Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, " "Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, "
"REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection by sophisticated DPI systems employing active probing techniques. " "REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection "
"This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.") "by sophisticated DPI systems employing active probing techniques. "
}, "This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.") },
{ DockerContainer::Ipsec, { DockerContainer::Ipsec,
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n" QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
"One of its distinguishing features is its ability to swiftly switch between networks and devices, " "One of its distinguishing features is its ability to swiftly switch between networks and devices, "
@@ -287,7 +288,8 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
case DockerContainer::Awg: return true; case DockerContainer::Awg: return true;
case DockerContainer::Xray: return true; case DockerContainer::Xray: return true;
case DockerContainer::Cloak: return true; case DockerContainer::Cloak: return true;
case DockerContainer::SSXray: return true; case DockerContainer::SSXray:
return true;
// case DockerContainer::ShadowSocks: return true; // case DockerContainer::ShadowSocks: return true;
default: return false; default: return false;
} }
@@ -383,10 +385,8 @@ bool ContainerProps::isShareable(DockerContainer container)
QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig) QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
{ {
QString protocolConfigString = containerConfig.value(ProtocolProps::protoToString(protocol)) QString protocolConfigString =
.toObject() containerConfig.value(ProtocolProps::protoToString(protocol)).toObject().value(config_key::last_config).toString();
.value(config_key::last_config)
.toString();
return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object(); return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
} }
+1
View File
@@ -80,6 +80,7 @@ namespace amnezia
ExecutableMissing = 604, ExecutableMissing = 604,
XrayExecutableMissing = 605, XrayExecutableMissing = 605,
Tun2SockExecutableMissing = 606, Tun2SockExecutableMissing = 606,
GoodByeDPIExecutableMissing = 607,
// VPN errors // VPN errors
OpenVpnAdaptersInUseError = 700, OpenVpnAdaptersInUseError = 700,
+1
View File
@@ -43,6 +43,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::CloakExecutableMissing): errorMessage = QObject::tr("Cloak (ck-client) executable missing"); break; case (ErrorCode::CloakExecutableMissing): errorMessage = QObject::tr("Cloak (ck-client) executable missing"); break;
case (ErrorCode::AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break; case (ErrorCode::AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break;
case (ErrorCode::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break; case (ErrorCode::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break;
case (ErrorCode::GoodByeDPIExecutableMissing): errorMessage = QObject::tr("GoodbyeDPI executable missing"); break;
// VPN errors // VPN errors
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break; case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
+62
View File
@@ -0,0 +1,62 @@
#include "goodByeDpi.h"
#include "core/ipcclient.h"
#include "utilities.h"
GoodByeDpi::GoodByeDpi(QObject *parent) : QObject { parent }
{
}
amnezia::ErrorCode GoodByeDpi::start(const QString &blackListFile, const int modset)
{
if (!QFileInfo::exists(Utils::goodbyedpiPath())) {
return amnezia::ErrorCode::GoodByeDPIExecutableMissing;
}
m_goodbyeDPIProcess = IpcClient::CreatePrivilegedProcess();
if (!m_goodbyeDPIProcess) {
return amnezia::ErrorCode::AmneziaServiceConnectionFailed;
}
m_goodbyeDPIProcess->waitForSource(1000);
if (!m_goodbyeDPIProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
return amnezia::ErrorCode::AmneziaServiceConnectionFailed;
}
m_goodbyeDPIProcess->setProgram(amnezia::PermittedProcess::GoodbyeDPI);
QStringList arguments;
arguments << QString("-%1").arg(modset);
arguments << QString("--blacklist %1").arg(blackListFile);
m_goodbyeDPIProcess->setArguments(arguments);
qDebug() << arguments.join(" ");
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::errorOccurred,
[&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; });
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::stateChanged, [&](QProcess::ProcessState newState) {
qDebug() << "PrivilegedProcess stateChanged" << newState;
if (newState == QProcess::Running) {
qDebug() << "PrivilegedProcess running";
emit serviceStateChanged(Vpn::ConnectionState::Connected);
}
});
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::finished, this, [&]() {
qDebug() << "PrivilegedProcess finished";
emit serviceStateChanged(Vpn::ConnectionState::Disconnected);
});
m_goodbyeDPIProcess->start();
return amnezia::ErrorCode::NoError;
}
void GoodByeDpi::stop()
{
if (m_goodbyeDPIProcess) {
m_goodbyeDPIProcess->close();
}
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef GOODBYEDPI_H
#define GOODBYEDPI_H
#include <QObject>
#include "core/defs.h"
#include "core/privileged_process.h"
#include "protocols/vpnprotocol.h"
class GoodByeDpi : public QObject
{
Q_OBJECT
public:
explicit GoodByeDpi(QObject *parent = nullptr);
amnezia::ErrorCode start(const QString &blackListFile, const int modset);
void stop();
private:
QSharedPointer<PrivilegedProcess> m_goodbyeDPIProcess;
signals:
void serviceStateChanged(Vpn::ConnectionState state);
};
#endif // GOODBYEDPI_H
+4 -1
View File
@@ -100,6 +100,8 @@ namespace amnezia
constexpr char clientId[] = "clientId"; constexpr char clientId[] = "clientId";
constexpr char isGoodbyeDpi[] = "is_goodbye_dpi";
} }
namespace protocols namespace protocols
@@ -254,7 +256,8 @@ namespace amnezia
TorWebSite, TorWebSite,
Dns, Dns,
Sftp, Sftp,
Socks5Proxy Socks5Proxy,
GoodyeDPI
}; };
Q_ENUM_NS(Proto) Q_ENUM_NS(Proto)
+1
View File
@@ -218,6 +218,7 @@
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file> <file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
<file>images/controls/archive-restore.svg</file> <file>images/controls/archive-restore.svg</file>
<file>images/controls/help-circle.svg</file> <file>images/controls/help-circle.svg</file>
<file>ui/qml/Pages2/LocalServices/PageGoodByeDpiSettings.qml</file>
</qresource> </qresource>
<qresource prefix="/countriesFlags"> <qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file> <file>images/flagKit/ZW.svg</file>
+30
View File
@@ -538,3 +538,33 @@ void Settings::toggleDevGatewayEnv(bool enabled)
{ {
m_isDevGatewayEnv = enabled; m_isDevGatewayEnv = enabled;
} }
void Settings::setGoodbyeDpiBlackListFile(const QString &file)
{
setValue("Conf/goodbyeDpiBlackListFile", file);
}
QString Settings::getGoodbyeDpiBlackListFile() const
{
return value("Conf/goodbyeDpiBlackListFile").toString();
}
void Settings::toggleGoodbyeDpi(bool enable)
{
setValue("Conf/isGoodbyeDpiEnabled", enable);
}
bool Settings::isGoodbyeDpiEnabled() const
{
return value("Conf/isGoodbyeDpiEnabled", false).toBool();
}
void Settings::setGoodbyeDpiModset(const int modset)
{
setValue("Conf/goodbyeDpiModset", modset);
}
int Settings::getGoodbyeDpiModset() const
{
return value("Conf/goodbyeDpiModset", 9).toInt();
}
+13 -1
View File
@@ -113,7 +113,10 @@ public:
QString routeModeString(RouteMode mode) const; QString routeModeString(RouteMode mode) const;
RouteMode routeMode() const; RouteMode routeMode() const;
void setRouteMode(RouteMode mode) { setValue("Conf/routeMode", mode); } void setRouteMode(RouteMode mode)
{
setValue("Conf/routeMode", mode);
}
bool isSitesSplitTunnelingEnabled() const; bool isSitesSplitTunnelingEnabled() const;
void setSitesSplitTunnelingEnabled(bool enabled); void setSitesSplitTunnelingEnabled(bool enabled);
@@ -222,6 +225,15 @@ public:
bool isDevGatewayEnv(); bool isDevGatewayEnv();
void toggleDevGatewayEnv(bool enabled); void toggleDevGatewayEnv(bool enabled);
void setGoodbyeDpiBlackListFile(const QString &file);
QString getGoodbyeDpiBlackListFile() const;
void toggleGoodbyeDpi(bool enable);
bool isGoodbyeDpiEnabled() const;
void setGoodbyeDpiModset(const int modset);
int getGoodbyeDpiModset() const;
signals: signals:
void saveLogsChanged(bool enabled); void saveLogsChanged(bool enabled);
void screenshotsEnabledChanged(bool enabled); void screenshotsEnabledChanged(bool enabled);
@@ -44,6 +44,13 @@ void ConnectionController::openConnection()
int serverIndex = m_serversModel->getDefaultServerIndex(); int serverIndex = m_serversModel->getDefaultServerIndex();
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex); QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
const auto isGoodbyeDpi = serverConfig.value(config_key::isGoodbyeDpi).toBool(false);
if (isGoodbyeDpi) {
emit startLocalService();
return;
}
auto configVersion = serverConfig.value(config_key::configVersion).toInt(); auto configVersion = serverConfig.value(config_key::configVersion).toInt();
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing); emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
@@ -65,6 +72,15 @@ void ConnectionController::openConnection()
void ConnectionController::closeConnection() void ConnectionController::closeConnection()
{ {
int serverIndex = m_serversModel->getDefaultServerIndex();
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
const auto isGoodbyeDpi = serverConfig.value(config_key::isGoodbyeDpi).toBool(false);
if (isGoodbyeDpi) {
emit stopLocalService();
return;
}
emit disconnectFromVpn(); emit disconnectFromVpn();
} }
@@ -61,6 +61,9 @@ signals:
void updateApiConfigFromTelegram(); void updateApiConfigFromTelegram();
void configFromApiUpdated(); void configFromApiUpdated();
void startLocalService();
void stopLocalService();
private: private:
Vpn::ConnectionState getCurrentConnectionState(); Vpn::ConnectionState getCurrentConnectionState();
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container); bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
@@ -0,0 +1,99 @@
#include "localServicesController.h"
namespace
{
// Logger logger("ServerController");
}
LocalServicesController::LocalServicesController(const QSharedPointer<ServersModel> &serversModel,
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
{
#ifdef Q_OS_WINDOWS
connect(&m_goodbyeDpiService, &GoodByeDpi::serviceStateChanged, this, &LocalServicesController::serviceStateChanged);
#endif
}
LocalServicesController::~LocalServicesController()
{
#ifdef Q_OS_WINDOWS
m_goodbyeDpiService.stop();
#endif
}
void LocalServicesController::toggleGoodbyeDpi(bool enable)
{
if (enable) {
QJsonObject server;
server.insert(config_key::isGoodbyeDpi, true);
server.insert(config_key::description, "GoodbyeDPI service");
server.insert(config_key::name, "GoodbyeDPI");
m_serversModel->addServer(server);
m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1);
m_settings->toggleGoodbyeDpi(true);
emit toggleGoodbyeDpiFinished(tr("GoodbyeDPI added to home page"));
} else {
for (int i = 0; i < m_serversModel->getServersCount(); i++) {
if (m_serversModel->getServerConfig(i).value(config_key::isGoodbyeDpi).toBool(false)) {
m_serversModel->setProcessedServerIndex(i);
m_serversModel->removeServer();
break;
}
}
m_settings->toggleGoodbyeDpi(false);
emit toggleGoodbyeDpiFinished("GoodbyeDPI removed from home page");
}
}
bool LocalServicesController::isGoodbyeDpiEnabled()
{
return m_settings->isGoodbyeDpiEnabled();
}
void LocalServicesController::setGoodbyeDpiBlackListFile(const QString &file)
{
m_settings->setGoodbyeDpiBlackListFile(file);
}
QString LocalServicesController::getGoodbyeDpiBlackListFile()
{
auto file = m_settings->getGoodbyeDpiBlackListFile();
if (file.isEmpty()) {
return m_defaultBlackListFile;
}
return file;
}
void LocalServicesController::resetGoodbyeDpiBlackListFile()
{
m_settings->setGoodbyeDpiBlackListFile(m_defaultBlackListFile);
}
void LocalServicesController::setGoodbyeDpiModset(const int modset)
{
m_settings->setGoodbyeDpiModset(modset);
}
int LocalServicesController::getGoodbyeDpiModset()
{
return m_settings->getGoodbyeDpiModset();
}
void LocalServicesController::start()
{
#ifdef Q_OS_WINDOWS
auto errorCode = m_goodbyeDpiService.start(getGoodbyeDpiBlackListFile(), getGoodbyeDpiModset());
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
}
#endif
}
void LocalServicesController::stop()
{
#ifdef Q_OS_WINDOWS
m_goodbyeDpiService.stop();
#endif
}
@@ -0,0 +1,58 @@
#ifndef LOCALSERVICESCONTROLLER_H
#define LOCALSERVICESCONTROLLER_H
#include <QObject>
#ifdef Q_OS_WINDOWS
#include "localServices/goodByeDpi.h"
#endif
#include "protocols/vpnprotocol.h"
#include "settings.h"
#include "ui/models/servers_model.h"
class LocalServicesController : public QObject
{
Q_OBJECT
public:
LocalServicesController(const QSharedPointer<ServersModel> &serversModel, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
~LocalServicesController();
Q_PROPERTY(bool isGoodbyeDpiEnabled READ isGoodbyeDpiEnabled NOTIFY toggleGoodbyeDpiFinished)
public slots:
void toggleGoodbyeDpi(bool enable);
bool isGoodbyeDpiEnabled();
void setGoodbyeDpiBlackListFile(const QString &file);
QString getGoodbyeDpiBlackListFile();
void resetGoodbyeDpiBlackListFile();
void setGoodbyeDpiModset(const int modset);
int getGoodbyeDpiModset();
void start();
void stop();
signals:
void errorOccurred(ErrorCode errorCode);
void toggleGoodbyeDpiFinished(const QString &message);
void serviceStateChanged(Vpn::ConnectionState state);
private:
std::shared_ptr<Settings> m_settings;
QSharedPointer<ServersModel> m_serversModel;
#ifdef Q_OS_WINDOWS
GoodByeDpi m_goodbyeDpiService;
#endif
bool m_isGoodbyeDpiServiceEnabled = false;
#ifdef Q_OS_WINDOWS
QString m_defaultBlackListFile = QCoreApplication::applicationDirPath() + "/goodbyedpi/blacklist.txt";
#else
QString m_defaultBlackListFile;
#endif
};
#endif // LOCALSERVICESCONTROLLER_H
+10 -2
View File
@@ -47,11 +47,19 @@ bool PageController::isStartPageVisible()
} }
} }
QString PageController::getPagePath(PageLoader::PageEnum page) QString PageController::getPagePath(PageLoader::PageEnum page, PageLoader::FolderEnum folder)
{ {
QMetaEnum metaEnum = QMetaEnum::fromType<PageLoader::PageEnum>(); QMetaEnum metaEnum = QMetaEnum::fromType<PageLoader::PageEnum>();
QString pageName = metaEnum.valueToKey(static_cast<int>(page)); QString pageName = metaEnum.valueToKey(static_cast<int>(page));
return "qrc:/ui/qml/Pages2/" + pageName + ".qml";
metaEnum = QMetaEnum::fromType<PageLoader::FolderEnum>();
QString folderName = "";
if (metaEnum.value(static_cast<int>(folder)) != static_cast<int>(PageLoader::FolderEnum::Root)) {
folderName = metaEnum.valueToKey(static_cast<int>(folder));
folderName += "/";
}
return "qrc:/ui/qml/Pages2/" + folderName + pageName + ".qml";
} }
void PageController::closeWindow() void PageController::closeWindow()
+18 -3
View File
@@ -61,7 +61,9 @@ namespace PageLoader
PageShareFullAccess, PageShareFullAccess,
PageDevMenu PageDevMenu,
PageGoodByeDpiSettings
}; };
Q_ENUM_NS(PageEnum) Q_ENUM_NS(PageEnum)
@@ -69,6 +71,19 @@ namespace PageLoader
{ {
qmlRegisterUncreatableMetaObject(PageLoader::staticMetaObject, "PageEnum", 1, 0, "PageEnum", "Error: only enums"); qmlRegisterUncreatableMetaObject(PageLoader::staticMetaObject, "PageEnum", 1, 0, "PageEnum", "Error: only enums");
} }
Q_NAMESPACE
enum class FolderEnum {
Root = 0,
LocalServices
};
Q_ENUM_NS(FolderEnum)
static void declareQmlFolderEnum()
{
qmlRegisterUncreatableMetaObject(PageLoader::staticMetaObject, "FolderEnum", 1, 0, "FolderEnum", "Error: only enums");
}
} }
class PageController : public QObject class PageController : public QObject
@@ -80,7 +95,7 @@ public:
public slots: public slots:
bool isStartPageVisible(); bool isStartPageVisible();
QString getPagePath(PageLoader::PageEnum page); QString getPagePath(PageLoader::PageEnum page, PageLoader::FolderEnum folder = PageLoader::FolderEnum::Root);
void closeWindow(); void closeWindow();
void hideWindow(); void hideWindow();
@@ -103,7 +118,7 @@ public slots:
void onShowErrorMessage(amnezia::ErrorCode errorCode); void onShowErrorMessage(amnezia::ErrorCode errorCode);
signals: signals:
void goToPage(PageLoader::PageEnum page, bool slide = true); void goToPage(PageLoader::PageEnum page, PageLoader::FolderEnum folder = PageLoader::FolderEnum::Root, bool slide = true);
void goToStartPage(); void goToStartPage();
void goToPageHome(); void goToPageHome();
void goToPageSettings(); void goToPageSettings();
+5 -7
View File
@@ -16,8 +16,7 @@
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel, SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<LanguageModel> &languageModel, const QSharedPointer<LanguageModel> &languageModel, const QSharedPointer<SitesModel> &sitesModel,
const QSharedPointer<SitesModel> &sitesModel,
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel, const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
const std::shared_ptr<Settings> &settings, QObject *parent) const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent), : QObject(parent),
@@ -31,7 +30,8 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH); m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
checkIfNeedDisableLogs(); checkIfNeedDisableLogs();
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged); connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this,
&SettingsController::onNotificationStateChanged);
#endif #endif
} }
@@ -145,8 +145,7 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
bool ok = m_settings->restoreAppConfig(data); bool ok = m_settings->restoreAppConfig(data);
if (ok) { if (ok) {
m_serversModel->resetModel(); m_serversModel->resetModel();
m_languageModel->changeLanguage( m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
emit restoreBackupFinished(); emit restoreBackupFinished();
} else { } else {
emit changeSettingsErrorOccurred(tr("Backup file is corrupted")); emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
@@ -162,8 +161,7 @@ void SettingsController::clearSettings()
{ {
m_settings->clearSettings(); m_settings->clearSettings();
m_serversModel->resetModel(); m_serversModel->resetModel();
m_languageModel->changeLanguage( m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites); m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
m_sitesModel->toggleSplitTunneling(false); m_sitesModel->toggleSplitTunneling(false);
+23 -1
View File
@@ -88,9 +88,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
const QJsonObject server = m_servers.at(index.row()).toObject(); const QJsonObject server = m_servers.at(index.row()).toObject();
const auto apiConfig = server.value(configKey::apiConfig).toObject(); const auto apiConfig = server.value(configKey::apiConfig).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt(); const auto configVersion = server.value(config_key::configVersion).toInt();
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
switch (role) { switch (role) {
case NameRole: { case NameRole: {
if (configVersion) { if (configVersion || isGoodbyeDpi) {
return server.value(config_key::name).toString(); return server.value(config_key::name).toString();
} }
auto name = server.value(config_key::description).toString(); auto name = server.value(config_key::description).toString();
@@ -100,6 +101,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
return name; return name;
} }
case ServerDescriptionRole: { case ServerDescriptionRole: {
if (isGoodbyeDpi) {
return server.value(config_key::description).toString();
}
auto description = getServerDescription(server, index.row()); auto description = getServerDescription(server, index.row());
return configVersion ? description : description + server.value(config_key::hostName).toString(); return configVersion ? description : description + server.value(config_key::hostName).toString();
} }
@@ -144,6 +149,9 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
QString primaryDns = server.value(config_key::dns1).toString(); QString primaryDns = server.value(config_key::dns1).toString();
return primaryDns == protocols::dns::amneziaDnsIp; return primaryDns == protocols::dns::amneziaDnsIp;
} }
case IsGoodByeDpiRole: {
return isGoodbyeDpi;
}
} }
return QVariant(); return QVariant();
@@ -208,6 +216,12 @@ QString ServersModel::getServerDescription(const QJsonObject &server, const int
const QString ServersModel::getDefaultServerDescriptionCollapsed() const QString ServersModel::getDefaultServerDescriptionCollapsed()
{ {
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject(); const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
if (isGoodbyeDpi) {
return server.value(config_key::description).toString();
}
const auto configVersion = server.value(config_key::configVersion).toInt(); const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getServerDescription(server, m_defaultServerIndex); auto description = getServerDescription(server, m_defaultServerIndex);
if (configVersion) { if (configVersion) {
@@ -222,6 +236,12 @@ const QString ServersModel::getDefaultServerDescriptionCollapsed()
const QString ServersModel::getDefaultServerDescriptionExpanded() const QString ServersModel::getDefaultServerDescriptionExpanded()
{ {
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject(); const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
if (isGoodbyeDpi) {
return server.value(config_key::description).toString();
}
const auto configVersion = server.value(config_key::configVersion).toInt(); const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getServerDescription(server, m_defaultServerIndex); auto description = getServerDescription(server, m_defaultServerIndex);
if (configVersion) { if (configVersion) {
@@ -370,6 +390,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable"; roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable";
roles[ApiAvailableCountriesRole] = "apiAvailableCountries"; roles[ApiAvailableCountriesRole] = "apiAvailableCountries";
roles[ApiServerCountryCodeRole] = "apiServerCountryCode"; roles[ApiServerCountryCodeRole] = "apiServerCountryCode";
roles[IsGoodByeDpiRole] = "isGoodbyeDpi";
return roles; return roles;
} }
+3 -1
View File
@@ -38,7 +38,9 @@ public:
ApiAvailableCountriesRole, ApiAvailableCountriesRole,
ApiServerCountryCodeRole, ApiServerCountryCodeRole,
HasAmneziaDns HasAmneziaDns,
IsGoodByeDpiRole
}; };
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr); ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
@@ -0,0 +1,159 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "./"
import "../../Controls2"
import "../../Config"
import "../../Controls2/TextTypes"
import "../../Components"
PageType {
id: root
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
}
FlickableType {
id: fl
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
property bool isGoodbyeDpiEnabled: LocalServicesController.isGoodbyeDpiEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16
HeaderType {
Layout.fillWidth: true
headerText: qsTr("GoodbyeDPI settings")
descriptionText: qsTr("Deep Packet Inspection circumvention utility")
}
SwitcherType {
Layout.fillWidth: true
text: qsTr("Enable GoodbyeDPI")
checked: LocalServicesController.isGoodbyeDpiEnabled
onCheckedChanged: {
if (checked !== LocalServicesController.isGoodbyeDpiEnabled) {
LocalServicesController.toggleGoodbyeDpi(checked)
}
}
}
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 16
enabled: !content.isGoodbyeDpiEnabled
ListItemTitleType {
Layout.fillWidth: true
text: LocalServicesController.getGoodbyeDpiBlackListFile()
}
ImageButtonType {
image: "qrc:/images/controls/folder-search-2.svg"
imageColor: AmneziaStyle.color.paleGray
onClicked: function() {
var fileName = SystemController.getFileName(qsTr("Open black list file"),
qsTr("Text files (*.txt)"))
LocalServicesController.setGoodbyeDpiBlackListFile(fileName)
}
}
ImageButtonType {
image: "qrc:/images/controls/trash.svg"
imageColor: AmneziaStyle.color.paleGray
onClicked: function() {
LocalServicesController.resetGoodbyeDpiBlackListFile()
}
}
}
DropDownType {
id: modsetDropDown
Layout.fillWidth: true
descriptionText: qsTr("Setup templates")
headerText: qsTr("Modset")
drawerParent: root
enabled: !content.isGoodbyeDpiEnabled
listView: ListViewWithRadioButtonType {
id: modsetListView
rootWidth: root.width
model: ListModel {
ListElement { name : "-p -r -s -f 2 -k 2 -n -e 2" }
ListElement { name : "-p -r -s -f 2 -k 2 -n -e 40" }
ListElement { name : "-p -r -s -e 40" }
ListElement { name : "-p -r -s" }
ListElement { name : "-f 2 -e 2 --auto-ttl --reverse-frag --max-payload" }
ListElement { name : "-f 2 -e 2 --wrong-seq --reverse-frag --max-payload" }
ListElement { name : "-f 2 -e 2 --wrong-chksum --reverse-frag --max-payload" }
ListElement { name : "-f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload" }
ListElement { name : "-f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload -q" }
}
clickedFunction: function() {
modsetDropDown.text = selectedText
LocalServicesController.setGoodbyeDpiModset(currentIndex + 1)
modsetDropDown.close()
}
Component.onCompleted: {
modsetListView.currentIndex = (LocalServicesController.getGoodbyeDpiModset() - 1)
modsetListView.triggerCurrentItem()
}
}
}
BasicButtonType {
id: detailedInstructionsButton
implicitHeight: 32
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
text: qsTr("Description of options")
clickedFunc: function() {
Qt.openUrlExternally("https://github.com/ValdikSS/GoodbyeDPI?tab=readme-ov-file#how-to-use")
}
}
}
}
}
+9 -3
View File
@@ -105,6 +105,8 @@ PageType {
buttonTextLabel.font.pixelSize: 14 buttonTextLabel.font.pixelSize: 14
buttonTextLabel.font.weight: 500 buttonTextLabel.font.weight: 500
visible: !ServersModel.getDefaultServerData("isGoodbyeDpi")
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled || property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
ServersModel.isDefaultServerDefaultContainerHasSplitTunneling ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
@@ -304,7 +306,7 @@ PageType {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8 spacing: 8
visible: !ServersModel.isDefaultServerFromApi visible: !ServersModel.isDefaultServerFromApi && !ServersModel.getDefaultServerData("isGoodbyeDpi")
Item { Item {
id: focusItem1 id: focusItem1
@@ -535,8 +537,12 @@ PageType {
Keys.onReturnPressed: serverInfoButton.clicked() Keys.onReturnPressed: serverInfoButton.clicked()
onClicked: function() { onClicked: function() {
ServersModel.processedIndex = index if (ServersModel.getDefaultServerData("isGoodbyeDpi")) {
PageController.goToPage(PageEnum.PageSettingsServerInfo) PageController.goToPage(PageEnum.PageGoodByeDpiSettings, PageEnum.LocalServices)
} else {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
drawer.close() drawer.close()
} }
} }
+16
View File
@@ -95,6 +95,22 @@ PageType {
DividerType {} DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
visible: Qt.platform.os === "windows"
text: qsTr("Local bypass services")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/app.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageGoodByeDpiSettings, PageEnum.LocalServices)
}
}
DividerType {}
LabelWithButtonType { LabelWithButtonType {
id: backup id: backup
Layout.fillWidth: true Layout.fillWidth: true
@@ -111,6 +111,8 @@ PageType {
id: server id: server
Layout.fillWidth: true Layout.fillWidth: true
visible: !isGoodbyeDpi
text: name text: name
parentFlickable: fl parentFlickable: fl
descriptionText: { descriptionText: {
@@ -54,7 +54,7 @@ PageType {
function onServerAlreadyExists(serverIndex) { function onServerAlreadyExists(serverIndex) {
PageController.goToStartPage() PageController.goToStartPage()
ServersModel.processedIndex = serverIndex ServersModel.processedIndex = serverIndex
PageController.goToPage(PageEnum.PageSettingsServerInfo, false) PageController.goToPage(PageEnum.PageSettingsServerInfo, PageEnum.LocalServices, false)
PageController.showErrorMessage(qsTr("The server has already been added to the application")) PageController.showErrorMessage(qsTr("The server has already been added to the application"))
} }
+10 -2
View File
@@ -60,8 +60,8 @@ PageType {
tabBarStackView.pop() tabBarStackView.pop()
} }
function onGoToPage(page, slide) { function onGoToPage(page, folder, slide) {
var pagePath = PageController.getPagePath(page) var pagePath = PageController.getPagePath(page, folder)
if (slide) { if (slide) {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition) tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
@@ -212,6 +212,14 @@ PageType {
} }
} }
Connections {
target: LocalServicesController
function onErrorOccurred(error) {
PageController.showErrorMessage(error)
}
}
StackViewType { StackViewType {
id: tabBarStackView id: tabBarStackView
+9
View File
@@ -198,6 +198,15 @@ QString Utils::certUtilPath()
#endif #endif
} }
QString Utils::goodbyedpiPath()
{
#ifdef Q_OS_WIN
return Utils::executable("goodbyedpi/goodbyedpi", true);
#else
return "";
#endif
}
QString Utils::tun2socksPath() QString Utils::tun2socksPath()
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
+1
View File
@@ -33,6 +33,7 @@ public:
static QString wireguardExecPath(); static QString wireguardExecPath();
static QString certUtilPath(); static QString certUtilPath();
static QString tun2socksPath(); static QString tun2socksPath();
static QString goodbyedpiPath();
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent); static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
+4 -1
View File
@@ -14,7 +14,8 @@ enum PermittedProcess {
OpenVPN, OpenVPN,
Wireguard, Wireguard,
Tun2Socks, Tun2Socks,
CertUtil CertUtil,
GoodbyeDPI
}; };
inline QString permittedProcessPath(PermittedProcess pid) inline QString permittedProcessPath(PermittedProcess pid)
@@ -27,6 +28,8 @@ inline QString permittedProcessPath(PermittedProcess pid)
return Utils::certUtilPath(); return Utils::certUtilPath();
} else if (pid == PermittedProcess::Tun2Socks) { } else if (pid == PermittedProcess::Tun2Socks) {
return Utils::tun2socksPath(); return Utils::tun2socksPath();
} else if (pid == PermittedProcess::GoodbyeDPI){
return Utils::goodbyedpiPath();
} }
return ""; return "";
} }