Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GoodByeDPI support #1045

Draft
wants to merge 9 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,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}
Expand All @@ -267,10 +273,12 @@ if(WIN32)

set(HEADERS ${HEADERS}
${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/ikev2_vpn_protocol_windows.cpp
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.cpp
)

set(RESOURCES ${RESOURCES}
Expand Down
10 changes: 10 additions & 0 deletions client/amnezia_application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ void AmneziaApplication::registerTypes()

Vpn::declareQmlVpnConnectionStateEnum();
PageLoader::declareQmlPageEnum();
PageLoader::declareQmlFolderEnum();
}

void AmneziaApplication::loadFonts()
Expand Down Expand Up @@ -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 changes: 2 additions & 0 deletions client/amnezia_application.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -136,6 +137,7 @@ class AmneziaApplication : public AMNEZIA_BASE_CLASS
QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
QScopedPointer<LocalServicesController> m_localServicesController;

QNetworkAccessManager *m_nam;

Expand Down
48 changes: 24 additions & 24 deletions client/containers/containers_defs.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "containers_defs.h"

#include "QJsonObject"
#include "QJsonDocument"
#include "QJsonObject"

QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
{
Expand Down Expand Up @@ -96,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{ DockerContainer::Awg, "AmneziaWG" },
{ DockerContainer::Xray, "XRay" },
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
{ DockerContainer::SSXray, "Shadowsocks"},
{ DockerContainer::SSXray, "Shadowsocks" },

{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
Expand Down Expand Up @@ -124,27 +124,24 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
"but very resistant to blockages. "
"Recommended for regions with high levels of censorship.") },
{ DockerContainer::Xray,
QObject::tr("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.") },
QObject::tr(
"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,
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.") },

{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
{ DockerContainer::Dns,
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::Socks5Proxy,
QObject::tr("") } };
{ DockerContainer::Dns, 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::Socks5Proxy, QObject::tr("") } };
}

QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
{
return {
{ DockerContainer::OpenVpn,
QObject::tr(
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
QObject::tr("OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
"It employs its unique security protocol, "
"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, "
Expand All @@ -160,7 +157,8 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
"* Can operate over both TCP and UDP network protocols.") },
{ DockerContainer::ShadowSocks,
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. "
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
"* Available in the AmneziaVPN only on desktop platforms\n"
Expand Down Expand Up @@ -217,15 +215,18 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
"* Works over UDP network protocol.") },
{ DockerContainer::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"
"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, "
"is specifically designed to counteract the highest levels of internet censorship through its novel approach to "
"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"
"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"
"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. "
"This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.")
},
"REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection "
"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,
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, "
Expand Down Expand Up @@ -287,7 +288,8 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
case DockerContainer::Awg: return true;
case DockerContainer::Xray: return true;
case DockerContainer::Cloak: return true;
case DockerContainer::SSXray: return true;
case DockerContainer::SSXray:
return true;
// case DockerContainer::ShadowSocks: return true;
default: return false;
}
Expand Down Expand Up @@ -383,10 +385,8 @@ bool ContainerProps::isShareable(DockerContainer container)

QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
{
QString protocolConfigString = containerConfig.value(ProtocolProps::protoToString(protocol))
.toObject()
.value(config_key::last_config)
.toString();
QString protocolConfigString =
containerConfig.value(ProtocolProps::protoToString(protocol)).toObject().value(config_key::last_config).toString();

return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
}
Expand Down
1 change: 1 addition & 0 deletions client/core/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ namespace amnezia
ExecutableMissing = 604,
XrayExecutableMissing = 605,
Tun2SockExecutableMissing = 606,
GoodByeDPIExecutableMissing = 607,

// VPN errors
OpenVpnAdaptersInUseError = 700,
Expand Down
1 change: 1 addition & 0 deletions client/core/errorstrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
62 changes: 62 additions & 0 deletions client/localServices/goodByeDpi.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 25 additions & 0 deletions client/localServices/goodByeDpi.h
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion client/protocols/protocols_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ namespace amnezia

constexpr char clientId[] = "clientId";

constexpr char isGoodbyeDpi[] = "is_goodbye_dpi";

}

namespace protocols
Expand Down Expand Up @@ -254,7 +256,8 @@ namespace amnezia
TorWebSite,
Dns,
Sftp,
Socks5Proxy
Socks5Proxy,
GoodyeDPI
};
Q_ENUM_NS(Proto)

Expand Down
1 change: 1 addition & 0 deletions client/resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
30 changes: 30 additions & 0 deletions client/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,3 +538,33 @@ void Settings::toggleDevGatewayEnv(bool 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();
}
14 changes: 13 additions & 1 deletion client/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ class Settings : public QObject
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);
Expand Down Expand Up @@ -222,6 +225,15 @@ class Settings : public QObject
bool isDevGatewayEnv();
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:
void saveLogsChanged(bool enabled);
void screenshotsEnabledChanged(bool enabled);
Expand Down
Loading
Loading