feature: added a ui with the feature to configure goodbye dpi

- added configuration file selection
- added modset selection
This commit is contained in:
vladimir.kuznetsov
2024-09-10 17:31:44 +04:00
parent c7a48aeabc
commit 5e27f0c8f0
34 changed files with 589 additions and 169 deletions
+10 -4
View File
@@ -236,8 +236,14 @@ file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
${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_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS
${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}
${COMMON_FILES_H}
@@ -261,13 +267,13 @@ if(WIN32)
)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/protocols/goodbyedpi.h
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.h
)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/protocols/goodbyedpi.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.cpp
)
set(RESOURCES ${RESOURCES}
+10
View File
@@ -235,6 +235,7 @@ void AmneziaApplication::registerTypes()
Vpn::declareQmlVpnConnectionStateEnum();
PageLoader::declareQmlPageEnum();
PageLoader::declareQmlFolderEnum();
}
void AmneziaApplication::loadFonts()
@@ -455,4 +456,13 @@ void AmneziaApplication::initControllers()
m_systemController.reset(new SystemController(m_settings));
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/systemController.h"
#include "ui/controllers/appSplitTunnelingController.h"
#include "ui/controllers/localServicesController.h"
#include "ui/models/containers_model.h"
#include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h"
@@ -136,6 +137,7 @@ private:
QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
QScopedPointer<LocalServicesController> m_localServicesController;
QNetworkAccessManager *m_nam;
+2 -13
View File
@@ -53,8 +53,6 @@ QVector<amnezia::Proto> ContainerProps::protocolsForContainer(amnezia::DockerCon
switch (container) {
case DockerContainer::None: return {};
case DockerContainer::GoodbyeDPI: return { Proto::GoodyeDPI };
case DockerContainer::OpenVpn: return { Proto::OpenVpn };
case DockerContainer::ShadowSocks: return { Proto::OpenVpn, Proto::ShadowSocks };
@@ -99,7 +97,6 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{ DockerContainer::Xray, "XRay" },
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
{ DockerContainer::SSXray, "Shadowsocks"},
{ DockerContainer::GoodbyeDPI, "GoodbyeDPI"},
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
@@ -139,9 +136,7 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
{ DockerContainer::Sftp,
QObject::tr("Create a file vault on your server to securely store and transfer files.") },
{ DockerContainer::Socks5Proxy,
QObject::tr("") } ,
{ DockerContainer::GoodbyeDPI,
QObject::tr("GoodbyeDPI — Deep Packet Inspection circumvention utility") }};
QObject::tr("") } };
}
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
@@ -250,10 +245,7 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
"You will be able to access it using\n FileZilla or other SFTP clients, "
"as well as mount the disk on your device to access\n it directly from your device.\n\n"
"For more detailed information, you can\n find it in the support section under \"Create SFTP file storage.\" ") },
{ DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") },
{ DockerContainer::GoodbyeDPI, QObject::tr("This software designed to bypass Deep Packet Inspection systems found in many Internet Service Providers which block access to certain websites. \n"
"It handles DPI connected using optical splitter or port mirroring (Passive DPI) which do not block any data but just replying faster than requested destination,"
"and Active DPI connected in sequence.") }
{ DockerContainer::Socks5Proxy, QObject::tr("SOCKS5 proxy server") } }
};
}
@@ -280,7 +272,6 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
case DockerContainer::Dns: return Proto::Dns;
case DockerContainer::Sftp: return Proto::Sftp;
case DockerContainer::Socks5Proxy: return Proto::Socks5Proxy;
case DockerContainer::GoodbyeDPI: return Proto::GoodyeDPI;
default: return Proto::Any;
}
}
@@ -387,7 +378,6 @@ bool ContainerProps::isShareable(DockerContainer container)
case DockerContainer::Dns: return false;
case DockerContainer::Sftp: return false;
case DockerContainer::Socks5Proxy: return false;
case DockerContainer::GoodbyeDPI: return false;
default: return true;
}
}
@@ -413,7 +403,6 @@ int ContainerProps::installPageOrder(DockerContainer container)
case DockerContainer::Xray: return 3;
case DockerContainer::Ipsec: return 7;
case DockerContainer::SSXray: return 8;
case DockerContainer::GoodbyeDPI: return 9;
default: return 0;
}
}
-1
View File
@@ -24,7 +24,6 @@ namespace amnezia
Ipsec,
Xray,
SSXray,
GoodbyeDPI,
// non-vpn
TorWebSite,
@@ -34,8 +34,7 @@ ErrorCode VpnConfigurationsController::createProtocolConfigForContainer(const Se
{
ErrorCode errorCode = ErrorCode::NoError;
if (ContainerProps::containerService(container) == ServiceType::Other ||
container == DockerContainer::GoodbyeDPI) {
if (ContainerProps::containerService(container) == ServiceType::Other) {
return errorCode;
}
@@ -62,8 +61,7 @@ ErrorCode VpnConfigurationsController::createProtocolConfigString(const bool isA
{
ErrorCode errorCode = ErrorCode::NoError;
if (ContainerProps::containerService(container) == ServiceType::Other ||
container == DockerContainer::GoodbyeDPI) {
if (ContainerProps::containerService(container) == ServiceType::Other) {
return errorCode;
}
@@ -84,8 +82,7 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QStr
{
QJsonObject vpnConfiguration {};
if (ContainerProps::containerService(container) == ServiceType::Other ||
container == DockerContainer::GoodbyeDPI) {
if (ContainerProps::containerService(container) == ServiceType::Other) {
return vpnConfiguration;
}
+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::AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break;
case (ErrorCode::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break;
case (ErrorCode::GoodByeDPIExecutableMissing): errorMessage = QObject::tr("GoodbyeDPI executable missing"); break;
// VPN errors
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
-85
View File
@@ -1,85 +0,0 @@
#include <QCoreApplication>
#include <QFileInfo>
#include <QProcess>
#include <QThread>
#include <chrono>
#include "logger.h"
#include "goodbyedpi.h"
#include "utilities.h"
GoodbyeDPIProtocol::GoodbyeDPIProtocol(const QJsonObject &configuration, QObject* parent) :
VpnProtocol(configuration, parent)
{
qDebug() << "GoodbyeDPIProtocol::GoodbyeDPIProtocol()";
}
GoodbyeDPIProtocol::~GoodbyeDPIProtocol()
{
qDebug() << "GoodbyeDPIProtocol::~GoodbyeDPIProtocol()";
GoodbyeDPIProtocol::stop();
}
void GoodbyeDPIProtocol::stop()
{
if (m_goodbyeDPIProcess) {
m_goodbyeDPIProcess->close();
}
setConnectionState(Vpn::ConnectionState::Disconnected);
}
ErrorCode GoodbyeDPIProtocol::start()
{
qDebug() << "GoodbyeDPIProtocol::start()";
if (!QFileInfo::exists(Utils::goodbyedpiPath())) {
setLastError(ErrorCode::GoodByeDPIExecutableMissing);
return lastError();
}
m_goodbyeDPIProcess = IpcClient::CreatePrivilegedProcess();
if (!m_goodbyeDPIProcess) {
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
m_goodbyeDPIProcess->waitForSource(1000);
if (!m_goodbyeDPIProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
m_goodbyeDPIProcess->setProgram(PermittedProcess::GoodbyeDPI);
QStringList arguments({"-9", "--blacklist", QCoreApplication::applicationDirPath() + "/goodbyedpi/russia-blacklist.txt",
"--blacklist", QCoreApplication::applicationDirPath() + "/goodbyedpi/russia-youtube.txt"});
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)
{
setConnectionState(Vpn::ConnectionState::Connected);
}
});
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::finished, this,
[&]() {
setConnectionState(Vpn::ConnectionState::Disconnected);
});
m_goodbyeDPIProcess->start();
return ErrorCode::NoError;
}
-28
View File
@@ -1,28 +0,0 @@
#ifndef GOODBYEDPI_H
#define GOODBYEDPI_H
#include <QObject>
#include <QProcess>
#include <QString>
#include <QTemporaryFile>
#include <QTimer>
#include "vpnprotocol.h"
#include "core/ipcclient.h"
class GoodbyeDPIProtocol : public VpnProtocol
{
Q_OBJECT
public:
explicit GoodbyeDPIProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
virtual ~GoodbyeDPIProtocol() override;
ErrorCode start() override;
void stop() override;
private:
QSharedPointer<PrivilegedProcess> m_goodbyeDPIProcess;
};
#endif // GOODBYEDPI_H
-2
View File
@@ -75,7 +75,6 @@ QMap<amnezia::Proto, QString> ProtocolProps::protocolHumanNames()
{ Proto::SSXray, "Shadowsocks"},
{ Proto::GoodyeDPI, "GoodbyeDPI"},
{ Proto::TorWebSite, "Website in Tor network" },
{ Proto::Dns, "DNS Service" },
{ Proto::Sftp, QObject::tr("SFTP service") },
@@ -100,7 +99,6 @@ amnezia::ServiceType ProtocolProps::protocolService(Proto p)
case Proto::Awg: return ServiceType::Vpn;
case Proto::Ikev2: return ServiceType::Vpn;
case Proto::Xray: return ServiceType::Vpn;
case Proto::GoodyeDPI: return ServiceType::Vpn;
case Proto::TorWebSite: return ServiceType::Other;
case Proto::Dns: return ServiceType::Other;
+2
View File
@@ -100,6 +100,8 @@ namespace amnezia
constexpr char clientId[] = "clientId";
constexpr char isGoodbyeDpi[] = "is_goodbye_dpi";
}
namespace protocols
-2
View File
@@ -14,7 +14,6 @@
#ifdef Q_OS_WINDOWS
#include "ikev2_vpn_protocol_windows.h"
#include "goodbyedpi.h"
#endif
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
@@ -109,7 +108,6 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &
switch (container) {
#if defined(Q_OS_WINDOWS)
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
case DockerContainer::GoodbyeDPI: return new GoodbyeDPIProtocol(configuration);
#endif
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
+1
View File
@@ -218,6 +218,7 @@
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
<file>images/controls/archive-restore.svg</file>
<file>images/controls/help-circle.svg</file>
<file>ui/qml/Pages2/LocalServices/PageGoodByeDpiSettings.qml</file>
</qresource>
<qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file>
+30
View File
@@ -523,3 +523,33 @@ QString Settings::getGatewayEndpoint()
{
return m_gatewayEndpoint;
}
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;
RouteMode routeMode() const;
void setRouteMode(RouteMode mode) { setValue("Conf/routeMode", mode); }
void setRouteMode(RouteMode mode)
{
setValue("Conf/routeMode", mode);
}
bool isSitesSplitTunnelingEnabled() const;
void setSitesSplitTunnelingEnabled(bool enabled);
@@ -219,6 +222,15 @@ public:
void setGatewayEndpoint(const QString &endpoint);
QString getGatewayEndpoint();
void setGoodbyeDpiBlackListFile(const QString &file);
QString getGoodbyeDpiBlackListFile() const;
void toggleGoodbyeDpi(bool enable);
bool isGoodbyeDpiEnabled() const;
void setGoodbyeDpiModset(const int modset);
int getGoodbyeDpiModset() const;
signals:
void saveLogsChanged(bool enabled);
void screenshotsEnabledChanged(bool enabled);
@@ -44,6 +44,13 @@ void ConnectionController::openConnection()
int serverIndex = m_serversModel->getDefaultServerIndex();
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();
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
@@ -65,6 +72,15 @@ void ConnectionController::openConnection()
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();
}
@@ -61,6 +61,9 @@ signals:
void updateApiConfigFromTelegram();
void configFromApiUpdated();
void startLocalService();
void stopLocalService();
private:
Vpn::ConnectionState getCurrentConnectionState();
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
@@ -0,0 +1,101 @@
#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)
{
connect(&m_goodbyeDpiService, &GoodByeDpi::serviceStateChanged, this, &LocalServicesController::serviceStateChanged);
}
LocalServicesController::~LocalServicesController()
{
m_goodbyeDpiService.stop();
}
void LocalServicesController::toggleGoodbyeDpi(bool enable)
{
if (enable) {
// auto file = getGoodbyeDpiBlackListFile();
// auto modset = getGoodbyeDpiModset();
// auto errorCode = ErrorCode::NoError;//m_goodbyeDpiService.start(file, modset);
// if (errorCode != ErrorCode::NoError) {
// emit errorOccurred(errorCode);
// } else {
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 {
// m_goodbyeDpiService.stop();
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()
{
auto errorCode = m_goodbyeDpiService.start(getGoodbyeDpiBlackListFile(), getGoodbyeDpiModset());
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
}
}
void LocalServicesController::stop()
{
m_goodbyeDpiService.stop();
}
@@ -0,0 +1,50 @@
#ifndef LOCALSERVICESCONTROLLER_H
#define LOCALSERVICESCONTROLLER_H
#include <QObject>
#include "localServices/goodByeDpi.h"
#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;
GoodByeDpi m_goodbyeDpiService;
bool m_isGoodbyeDpiServiceEnabled = false;
QString m_defaultBlackListFile = QCoreApplication::applicationDirPath() + "/goodbyedpi/blacklist.txt";
};
#endif // LOCALSERVICESCONTROLLER_H
+10 -2
View File
@@ -59,11 +59,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>();
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()
+18 -3
View File
@@ -61,7 +61,9 @@ namespace PageLoader
PageShareFullAccess,
PageDevMenu
PageDevMenu,
PageGoodByeDpiSettings
};
Q_ENUM_NS(PageEnum)
@@ -69,6 +71,19 @@ namespace PageLoader
{
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
@@ -80,7 +95,7 @@ public:
public slots:
bool isStartPageVisible();
QString getPagePath(PageLoader::PageEnum page);
QString getPagePath(PageLoader::PageEnum page, PageLoader::FolderEnum folder = PageLoader::FolderEnum::Root);
void closeWindow();
void hideWindow();
@@ -103,7 +118,7 @@ public slots:
void onShowErrorMessage(amnezia::ErrorCode errorCode);
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 goToPageHome();
void goToPageSettings();
+5 -7
View File
@@ -16,8 +16,7 @@
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<LanguageModel> &languageModel,
const QSharedPointer<SitesModel> &sitesModel,
const QSharedPointer<LanguageModel> &languageModel, const QSharedPointer<SitesModel> &sitesModel,
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
const std::shared_ptr<Settings> &settings, 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);
checkIfNeedDisableLogs();
#ifdef Q_OS_ANDROID
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged);
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this,
&SettingsController::onNotificationStateChanged);
#endif
}
@@ -131,8 +131,7 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
bool ok = m_settings->restoreAppConfig(data);
if (ok) {
m_serversModel->resetModel();
m_languageModel->changeLanguage(
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
emit restoreBackupFinished();
} else {
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
@@ -148,8 +147,7 @@ void SettingsController::clearSettings()
{
m_settings->clearSettings();
m_serversModel->resetModel();
m_languageModel->changeLanguage(
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
m_sitesModel->toggleSplitTunneling(false);
@@ -8,6 +8,7 @@
#include "ui/models/servers_model.h"
#include "ui/models/sites_model.h"
#include "ui/models/appSplitTunnelingModel.h"
#include "localServices/goodByeDpi.h"
class SettingsController : public QObject
{
@@ -112,6 +113,8 @@ private:
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
std::shared_ptr<Settings> m_settings;
GoodByeDpi m_goodbyeDpiService;
QString m_appVersion;
QDateTime m_loggingDisableDate;
+1 -7
View File
@@ -37,13 +37,7 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
case EasySetupHeaderRole: return ContainerProps::easySetupHeader(container);
case EasySetupDescriptionRole: return ContainerProps::easySetupDescription(container);
case EasySetupOrderRole: return ContainerProps::easySetupOrder(container);
case IsInstalledRole: {
#ifdef Q_OS_WIN
if (container == DockerContainer::GoodbyeDPI)
return true;
#endif
return m_containers.contains(container);
}
case IsInstalledRole: return m_containers.contains(container);
case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_processedContainerIndex);
case IsSupportedRole: return ContainerProps::isSupportedByCurrentPlatform(container);
case IsShareableRole: return ContainerProps::isShareable(container);
+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 auto apiConfig = server.value(configKey::apiConfig).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt();
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
switch (role) {
case NameRole: {
if (configVersion) {
if (configVersion || isGoodbyeDpi) {
return server.value(config_key::name).toString();
}
auto name = server.value(config_key::description).toString();
@@ -100,6 +101,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
return name;
}
case ServerDescriptionRole: {
if (isGoodbyeDpi) {
return server.value(config_key::description).toString();
}
auto description = getServerDescription(server, index.row());
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();
return primaryDns == protocols::dns::amneziaDnsIp;
}
case IsGoodByeDpiRole: {
return isGoodbyeDpi;
}
}
return QVariant();
@@ -208,6 +216,12 @@ QString ServersModel::getServerDescription(const QJsonObject &server, const int
const QString ServersModel::getDefaultServerDescriptionCollapsed()
{
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();
auto description = getServerDescription(server, m_defaultServerIndex);
if (configVersion) {
@@ -222,6 +236,12 @@ const QString ServersModel::getDefaultServerDescriptionCollapsed()
const QString ServersModel::getDefaultServerDescriptionExpanded()
{
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();
auto description = getServerDescription(server, m_defaultServerIndex);
if (configVersion) {
@@ -370,6 +390,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable";
roles[ApiAvailableCountriesRole] = "apiAvailableCountries";
roles[ApiServerCountryCodeRole] = "apiServerCountryCode";
roles[IsGoodByeDpiRole] = "isGoodbyeDpi";
return roles;
}
+3 -1
View File
@@ -38,7 +38,9 @@ public:
ApiAvailableCountriesRole,
ApiServerCountryCodeRole,
HasAmneziaDns
HasAmneziaDns,
IsGoodByeDpiRole
};
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")
}
}
}
}
}
+7 -1
View File
@@ -105,6 +105,8 @@ PageType {
buttonTextLabel.font.pixelSize: 14
buttonTextLabel.font.weight: 500
visible: !ServersModel.getDefaultServerData("isGoodbyeDpi")
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
@@ -304,7 +306,7 @@ PageType {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8
visible: !ServersModel.isDefaultServerFromApi
visible: !ServersModel.isDefaultServerFromApi && !ServersModel.getDefaultServerData("isGoodbyeDpi")
Item {
id: focusItem1
@@ -535,8 +537,12 @@ PageType {
Keys.onReturnPressed: serverInfoButton.clicked()
onClicked: function() {
if (ServersModel.getDefaultServerData("isGoodbyeDpi")) {
PageController.goToPage(PageEnum.PageGoodByeDpiSettings, PageEnum.LocalServices)
} else {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
drawer.close()
}
}
+14
View File
@@ -95,6 +95,20 @@ PageType {
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
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 {
id: backup
Layout.fillWidth: true
@@ -111,6 +111,8 @@ PageType {
id: server
Layout.fillWidth: true
visible: !isGoodbyeDpi
text: name
parentFlickable: fl
descriptionText: {
@@ -54,7 +54,7 @@ PageType {
function onServerAlreadyExists(serverIndex) {
PageController.goToStartPage()
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"))
}
+10 -2
View File
@@ -60,8 +60,8 @@ PageType {
tabBarStackView.pop()
}
function onGoToPage(page, slide) {
var pagePath = PageController.getPagePath(page)
function onGoToPage(page, folder, slide) {
var pagePath = PageController.getPagePath(page, folder)
if (slide) {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
@@ -204,6 +204,14 @@ PageType {
}
}
Connections {
target: LocalServicesController
function onErrorOccurred(error) {
PageController.showErrorMessage(error)
}
}
StackViewType {
id: tabBarStackView