Compare commits

..

1 Commits

Author SHA1 Message Date
NickVs2015 fc55457024 fix: up AGP version code 2026-06-05 18:41:13 +03:00
10 changed files with 41 additions and 278 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 2123)
set(APP_ANDROID_VERSION_CODE 2125)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
+37 -182
View File
@@ -9,13 +9,10 @@
#include "ipc.h"
#include <QCryptographicHash>
#include <QJsonArray>
#include <QJsonDocument>
#include <QTimer>
#include <QJsonObject>
#include <QNetworkInterface>
#include <QNetworkProxy>
#include <QTcpSocket>
#include <QtCore/qlogging.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qprocess.h>
@@ -59,28 +56,6 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) :
qWarning() << "Xray config string is not a valid JSON object";
m_xrayConfig = {};
}
m_serverPort = extractServerPort();
}
int XrayProtocol::extractServerPort() const
{
const QJsonArray outbounds = m_xrayConfig.value(amnezia::protocols::xray::outbounds).toArray();
if (outbounds.isEmpty())
return 0;
const QJsonObject settings = outbounds.first().toObject().value(amnezia::protocols::xray::settings).toObject();
QJsonArray servers;
if (settings.contains(amnezia::protocols::xray::vnext))
servers = settings.value(amnezia::protocols::xray::vnext).toArray();
else if (settings.contains(amnezia::protocols::xray::servers))
servers = settings.value(amnezia::protocols::xray::servers).toArray();
if (servers.isEmpty())
return 0;
return servers.first().toObject().value(amnezia::protocols::xray::port).toInt();
}
XrayProtocol::~XrayProtocol()
@@ -93,13 +68,6 @@ ErrorCode XrayProtocol::start()
{
qDebug() << "XrayProtocol::start()";
m_connectivityProbeStarted = false;
if (!probeServerReachable()) {
qCritical() << "XrayProtocol: VPN server" << m_remoteAddress << "is unreachable";
return ErrorCode::XrayServerUnreachable;
}
// Inject SOCKS5 auth into the inbound before starting xray.
// Re-uses existing credentials if the config already has them (e.g. imported config).
amnezia::serialization::inbounds::InboundCredentials creds;
@@ -136,50 +104,22 @@ ErrorCode XrayProtocol::start()
qDebug() << "XrayProtocol: patched legacy inbound listen address to 127.0.0.1";
}
startTimeoutTimer();
return IpcClient::withInterface(
[&](QSharedPointer<IpcInterfaceReplica> iface) {
auto xrayStart = iface->xrayStart(xrayConfigStr);
if (!xrayStart.waitForFinished() || !xrayStart.returnValue()) {
qCritical() << "Failed to start xray";
stopTimeoutTimer();
return ErrorCode::XrayExecutableCrashed;
}
return startTun2Socks();
},
[this]() {
stopTimeoutTimer();
return ErrorCode::AmneziaServiceConnectionFailed;
});
[]() { return ErrorCode::AmneziaServiceConnectionFailed; });
}
void XrayProtocol::stop()
{
qDebug() << "XrayProtocol::stop()";
stopTimeoutTimer();
stopLivenessMonitor();
if (m_tun2socksProcess) {
m_tun2socksProcess->blockSignals(true);
#ifndef Q_OS_WIN
m_tun2socksProcess->terminate();
auto waitForFinished = m_tun2socksProcess->waitForFinished(1000);
if (!waitForFinished.waitForFinished() || !waitForFinished.returnValue()) {
qWarning() << "Failed to terminate tun2socks. Killing the process...";
m_tun2socksProcess->kill();
m_tun2socksProcess->waitForFinished(1000);
}
#else
m_tun2socksProcess->kill();
#endif
m_tun2socksProcess->close();
m_tun2socksProcess.reset();
}
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
auto disableKillSwitch = iface->disableKillSwitch();
if (!disableKillSwitch.waitForFinished() || !disableKillSwitch.returnValue())
@@ -202,13 +142,31 @@ void XrayProtocol::stop()
qWarning() << "Failed to stop xray";
});
if (m_tun2socksProcess) {
m_tun2socksProcess->blockSignals(true);
#ifndef Q_OS_WIN
m_tun2socksProcess->terminate();
auto waitForFinished = m_tun2socksProcess->waitForFinished(1000);
if (!waitForFinished.waitForFinished() || !waitForFinished.returnValue()) {
qWarning() << "Failed to terminate tun2socks. Killing the process...";
m_tun2socksProcess->kill();
}
#else
// terminate does not do anything useful on Windows
// so just kill the process
m_tun2socksProcess->kill();
#endif
m_tun2socksProcess->close();
m_tun2socksProcess.reset();
}
setConnectionState(Vpn::ConnectionState::Disconnected);
}
ErrorCode XrayProtocol::startTun2Socks()
{
m_tunResourceBusy = false;
m_tun2socksProcess = IpcClient::CreatePrivilegedProcess();
if (!m_tun2socksProcess->waitForSource()) {
return ErrorCode::AmneziaServiceConnectionFailed;
@@ -233,31 +191,15 @@ ErrorCode XrayProtocol::startTun2Socks()
if (!line.contains("[TCP]") && !line.contains("[UDP]"))
qDebug() << "[tun2socks]:" << line;
if (line.contains("resource busy"))
m_tunResourceBusy = true;
if (line.contains("[STACK] tun://") && line.contains("<-> socks5://") && !m_connectivityProbeStarted) {
m_connectivityProbeStarted = true;
if (line.contains("[STACK] tun://") && line.contains("<-> socks5://")) {
disconnect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::readyReadStandardOutput, this, nullptr);
disconnect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::readyReadStandardError, this, nullptr);
runConnectivityProbe([this](bool ok) {
if (!ok) {
qCritical() << "Xray connectivity probe failed: no traffic flows through the tunnel";
stop();
setLastError(ErrorCode::XrayConnectivityCheckFailed);
return;
}
if (ErrorCode res = setupRouting(); res != ErrorCode::NoError) {
stop();
setLastError(res);
} else {
stopTimeoutTimer();
setConnectionState(Vpn::ConnectionState::Connected);
startLivenessMonitor();
}
});
if (ErrorCode res = setupRouting(); res != ErrorCode::NoError) {
stop();
setLastError(res);
} else {
setConnectionState(Vpn::ConnectionState::Connected);
}
}
},
Qt::QueuedConnection);
@@ -265,7 +207,15 @@ ErrorCode XrayProtocol::startTun2Socks()
connect(
m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::finished, this,
[this](int exitCode, QProcess::ExitStatus exitStatus) {
const bool resourceBusy = m_tunResourceBusy;
// Check stdout for "resource busy" — the TUN device was not yet released
// by the previous tun2socks instance. Retry after a short delay.
bool resourceBusy = false;
if (m_tun2socksProcess) {
auto readOut = m_tun2socksProcess->readAllStandardOutput();
if (readOut.waitForFinished()) {
resourceBusy = readOut.returnValue().contains("resource busy");
}
}
if (resourceBusy && m_tun2socksRetryCount < maxTun2SocksRetries) {
m_tun2socksRetryCount++;
@@ -381,98 +331,3 @@ ErrorCode XrayProtocol::setupRouting()
},
[]() { return ErrorCode::AmneziaServiceConnectionFailed; });
}
bool XrayProtocol::probeServerReachable()
{
if (m_remoteAddress.isEmpty() || m_serverPort <= 0) {
qWarning() << "XrayProtocol: skipping server reachability probe (address/port unknown)";
return true;
}
QTcpSocket sock;
sock.connectToHost(m_remoteAddress, static_cast<quint16>(m_serverPort));
const bool ok = sock.waitForConnected(m_serverProbeTimeoutMs);
if (!ok) {
qWarning() << "XrayProtocol: server" << m_remoteAddress << ":" << m_serverPort
<< "unreachable:" << sock.errorString();
}
sock.abort();
return ok;
}
void XrayProtocol::runConnectivityProbe(std::function<void(bool)> onResult)
{
if (m_remoteAddress.isEmpty() || m_serverPort <= 0) {
qWarning() << "XrayProtocol: connectivity probe skipped (server address/port unknown)";
onResult(true);
return;
}
auto *sock = new QTcpSocket(this);
QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QStringLiteral("127.0.0.1"),
static_cast<quint16>(m_socksPort), m_socksUser, m_socksPassword);
proxy.setCapabilities(QNetworkProxy::TunnelingCapability | QNetworkProxy::HostNameLookupCapability);
sock->setProxy(proxy);
auto *timeout = new QTimer(this);
timeout->setSingleShot(true);
auto done = QSharedPointer<bool>::create(false);
auto finish = [=](bool ok) {
if (*done)
return;
*done = true;
timeout->stop();
timeout->deleteLater();
sock->abort();
sock->deleteLater();
onResult(ok);
};
connect(sock, &QTcpSocket::connected, this, [=]() { finish(true); });
connect(sock, &QAbstractSocket::errorOccurred, this, [=](QAbstractSocket::SocketError) { finish(false); });
connect(timeout, &QTimer::timeout, this, [=]() { finish(false); });
timeout->start(m_connectivityProbeTimeoutMs);
sock->connectToHost(m_remoteAddress, static_cast<quint16>(m_serverPort));
}
void XrayProtocol::startLivenessMonitor()
{
if (!m_livenessTimer) {
m_livenessTimer = new QTimer(this);
connect(m_livenessTimer, &QTimer::timeout, this, [this]() {
if (connectionState() != Vpn::ConnectionState::Connected)
return;
runConnectivityProbe([this](bool ok) {
if (connectionState() != Vpn::ConnectionState::Connected)
return;
if (ok) {
m_livenessFailures = 0;
} else if (++m_livenessFailures >= m_maxLivenessFailures) {
qCritical() << "XrayProtocol: liveness check failed" << m_livenessFailures
<< "times in a row, the tunnel is dead";
stop();
setLastError(ErrorCode::XrayConnectionLost);
} else {
qWarning() << "XrayProtocol: liveness check failed (" << m_livenessFailures << "/"
<< m_maxLivenessFailures << ")";
}
});
});
}
m_livenessFailures = 0;
m_livenessTimer->start(m_livenessIntervalMs);
}
void XrayProtocol::stopLivenessMonitor()
{
if (m_livenessTimer)
m_livenessTimer->stop();
m_livenessFailures = 0;
}
-27
View File
@@ -6,16 +6,12 @@
#include <QHostAddress>
#include <QList>
#include <functional>
#include "core/utils/errorCodes.h"
#include "core/utils/routeModes.h"
#include "core/utils/commonStructs.h"
#include "core/utils/ipcClient.h"
#include "vpnProtocol.h"
class QTimer;
class XrayProtocol : public VpnProtocol
{
public:
@@ -29,17 +25,10 @@ private:
ErrorCode setupRouting();
ErrorCode startTun2Socks();
bool probeServerReachable();
void runConnectivityProbe(std::function<void(bool)> onResult);
void startLivenessMonitor();
void stopLivenessMonitor();
int extractServerPort() const;
QJsonObject m_xrayConfig;
amnezia::RouteMode m_routeMode;
QList<QHostAddress> m_dnsServers;
QString m_remoteAddress;
int m_serverPort = 0;
QString m_socksUser;
QString m_socksPassword;
@@ -49,22 +38,6 @@ private:
int m_tun2socksRetryCount = 0;
static constexpr int maxTun2SocksRetries = 5;
static constexpr int tun2socksRetryDelayMs = 400;
bool m_connectivityProbeStarted = false;
bool m_tunResourceBusy = false;
QTimer *m_livenessTimer = nullptr;
int m_livenessFailures = 0;
static constexpr int defaultServerProbeTimeoutMs = 5000;
static constexpr int defaultConnectivityProbeTimeoutMs = 7000;
static constexpr int defaultLivenessIntervalMs = 15000;
static constexpr int defaultMaxLivenessFailures = 3;
int m_serverProbeTimeoutMs = defaultServerProbeTimeoutMs;
int m_connectivityProbeTimeoutMs = defaultConnectivityProbeTimeoutMs;
int m_livenessIntervalMs = defaultLivenessIntervalMs;
int m_maxLivenessFailures = defaultMaxLivenessFailures;
};
#endif // XRAYPROTOCOL_H
-3
View File
@@ -71,9 +71,6 @@ namespace amnezia
OpenSslFailed = 800,
XrayExecutableCrashed = 803,
Tun2SockExecutableCrashed = 804,
XrayServerUnreachable = 805,
XrayConnectivityCheckFailed = 806,
XrayConnectionLost = 807,
// import and install errors
ImportInvalidConfigError = 900,
-3
View File
@@ -59,9 +59,6 @@ QString errorString(ErrorCode code) {
case (ErrorCode::OpenVpnExecutableMissing): errorMessage = QObject::tr("OpenVPN 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::XrayServerUnreachable): errorMessage = QObject::tr("Can't connect: the VPN server is unreachable"); break;
case (ErrorCode::XrayConnectivityCheckFailed): errorMessage = QObject::tr("Can't connect: no internet traffic flows through the tunnel"); break;
case (ErrorCode::XrayConnectionLost): errorMessage = QObject::tr("Connection lost: traffic stopped flowing through the tunnel"); break;
// VPN errors
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
+2 -6
View File
@@ -8,7 +8,6 @@
#include <QFileInfo>
#include <QLocalSocket>
#include "daemon.h"
#include "daemonlocalserverconnection.h"
#include "leakdetector.h"
#include "logger.h"
@@ -59,11 +58,8 @@ bool DaemonLocalServer::initialize() {
DaemonLocalServerConnection* connection =
new DaemonLocalServerConnection(&m_server, socket);
connect(socket, &QLocalSocket::disconnected, connection, [connection]() {
logger.debug() << "Client connection dropped, deactivating daemon";
Daemon::instance()->deactivate(true);
connection->deleteLater();
});
connect(socket, &QLocalSocket::disconnected, connection,
&DaemonLocalServerConnection::deleteLater);
});
return true;
-36
View File
@@ -28,42 +28,6 @@ IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent)
connect(&m_pingHelper, &PingHelper::connectionLose, this, &IpcServer::connectionLose);
}
IpcServer::~IpcServer()
{
}
void IpcServer::resetServiceState()
{
qDebug() << "IpcServer::resetServiceState — tearing down active VPN state";
Xray::getInstance().stopXray();
for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) {
const ProcessDescriptor &pd = it.value();
if (!pd.ipcProcess)
continue;
pd.ipcProcess->terminate();
if (!pd.ipcProcess->waitForFinished(1000)) {
pd.ipcProcess->kill();
pd.ipcProcess->waitForFinished(1000);
}
pd.ipcProcess->close();
}
m_processes.clear();
Utils::killProcessByName(Utils::tun2socksPath());
Utils::killProcessByName(Utils::openVpnExecPath());
KillSwitch::instance()->disableKillSwitch();
Router::restoreResolvers();
Router::clearSavedRoutes();
Router::StartRoutingIpv6();
Router::flushDns();
m_pingHelper.stop();
}
int IpcServer::createPrivilegedProcess()
{
#ifdef MZ_DEBUG
-4
View File
@@ -17,10 +17,6 @@ class IpcServer : public IpcInterfaceSource
{
public:
explicit IpcServer(QObject *parent = nullptr);
virtual ~IpcServer();
void resetServiceState();
virtual int createPrivilegedProcess() override;
virtual int routeAddList(const QString &gw, const QStringList &ips) override;
+1 -14
View File
@@ -35,20 +35,7 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent),
QObject::connect(m_server.data(), &QLocalServer::newConnection, this, [this]() {
qDebug() << "LocalServer new connection";
QLocalSocket *socket = m_server->nextPendingConnection();
if (!socket)
return;
m_activeClientSocket = socket;
QObject::connect(socket, &QLocalSocket::disconnected, this, [this, socket]() {
qDebug() << "LocalServer: client disconnected";
if (m_activeClientSocket == socket)
m_ipcServer.resetServiceState();
});
m_serverNode.addHostSideConnection(socket);
m_serverNode.addHostSideConnection(m_server->nextPendingConnection());
if (!m_isRemotingEnabled) {
m_isRemotingEnabled = true;
-2
View File
@@ -41,8 +41,6 @@ public:
QRemoteObjectHost m_serverNode;
bool m_isRemotingEnabled = false;
QPointer<QLocalSocket> m_activeClientSocket;
NetworkWatcher m_networkWatcher;
#ifdef Q_OS_LINUX
DaemonLocalServer server{qApp};