From 54d28862f3a2d766188df5f10dde5205d8c14bc7 Mon Sep 17 00:00:00 2001 From: cd-amn Date: Mon, 8 Jun 2026 13:41:02 +0000 Subject: [PATCH] refactor: TrafficGuard owns xray DNS and uplink routes --- client/core/protocols/xrayProtocol.cpp | 19 ---------- client/core/protocols/xrayProtocol.h | 1 - client/core/vpnTrafficGuard.cpp | 50 ++++++++++++++++++++++++- ipc/ipc_interface.rep | 2 + ipc/ipcserver.cpp | 51 ++++++++++++++------------ ipc/ipcserver.h | 6 +-- 6 files changed, 80 insertions(+), 49 deletions(-) diff --git a/client/core/protocols/xrayProtocol.cpp b/client/core/protocols/xrayProtocol.cpp index 835b2f5fd..9a12cc0f7 100644 --- a/client/core/protocols/xrayProtocol.cpp +++ b/client/core/protocols/xrayProtocol.cpp @@ -39,12 +39,6 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) : m_tunName = QStringLiteral("tun2"); #endif } - const QString primaryDns = configuration.value(amnezia::configKey::dns1).toString(); - m_dnsServers.push_back(QHostAddress(primaryDns)); - if (primaryDns != amnezia::protocols::dns::amneziaDnsIp) { - const QString secondaryDns = configuration.value(amnezia::configKey::dns2).toString(); - m_dnsServers.push_back(QHostAddress(secondaryDns)); - } QJsonObject xrayConfiguration = configuration.value(ProtocolUtils::key_proto_config_data(Proto::Xray)).toObject(); if (xrayConfiguration.isEmpty()) { @@ -133,10 +127,6 @@ void XrayProtocol::stop() m_phase = Phase::Stopping; IpcClient::withInterface([this](QSharedPointer iface) { - auto restoreResolvers = iface->restoreResolvers(); - if (!restoreResolvers.waitForFinished() || !restoreResolvers.returnValue()) - qWarning() << "Failed to restore resolvers"; - auto deleteTun = iface->deleteTun(m_tunName); if (!deleteTun.waitForFinished() || !deleteTun.returnValue()) qWarning() << "Failed to delete tun"; @@ -282,21 +272,12 @@ ErrorCode XrayProtocol::setupRouting() { return IpcClient::withInterface( [this](QSharedPointer iface) -> ErrorCode { -#ifdef Q_OS_WIN - const int inetAdapterIndex = NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)); -#endif auto createTun = iface->createTun(m_tunName, amnezia::protocols::xray::defaultLocalAddr); if (!createTun.waitForFinished() || !createTun.returnValue()) { qCritical() << "Failed to assign IP address for TUN"; return ErrorCode::InternalError; } - auto updateResolvers = iface->updateResolvers(m_tunName, m_dnsServers); - if (!updateResolvers.waitForFinished() || !updateResolvers.returnValue()) { - qCritical() << "Failed to set DNS resolvers for TUN"; - return ErrorCode::InternalError; - } - emit tunnelAddressesUpdated(m_vpnGateway, m_vpnLocalAddress); return ErrorCode::NoError; }, diff --git a/client/core/protocols/xrayProtocol.h b/client/core/protocols/xrayProtocol.h index d80542aac..fc64ce3a6 100644 --- a/client/core/protocols/xrayProtocol.h +++ b/client/core/protocols/xrayProtocol.h @@ -34,7 +34,6 @@ private: QJsonObject m_xrayConfig; amnezia::RouteMode m_routeMode; - QList m_dnsServers; QString m_remoteAddress; QString m_socksUser; diff --git a/client/core/vpnTrafficGuard.cpp b/client/core/vpnTrafficGuard.cpp index b45c44f97..97cc6af1a 100644 --- a/client/core/vpnTrafficGuard.cpp +++ b/client/core/vpnTrafficGuard.cpp @@ -13,6 +13,7 @@ #endif #include "core/utils/networkUtilities.h" +#include "core/utils/constants/protocolConstants.h" #include "core/tunnel.h" #include "mozilla/localsocketcontroller.h" @@ -352,11 +353,40 @@ void VpnTrafficGuard::applyPolicy(Tunnel* tunnel) { if (!tunnel) return; #ifdef AMNEZIA_DESKTOP + const QString ifname = tunnel->ifname(); + + if (VpnProtocol::isXrayBased(tunnel->container())) { + const QJsonObject cfg = tunnel->config(); + const QString primary = cfg.value(amnezia::configKey::dns1).toString(); + const QString secondary = cfg.value(amnezia::configKey::dns2).toString(); + QList dns; + if (!primary.isEmpty()) dns.append(QHostAddress(primary)); + if (!secondary.isEmpty() && secondary != primary) dns.append(QHostAddress(secondary)); + + IpcClient::withInterface([&](QSharedPointer iface) { + auto updateRes = iface->updateResolvers(ifname, dns); + if (!updateRes.waitForFinished() || !updateRes.returnValue()) { + qWarning() << "VpnTrafficGuard::applyPolicy: updateResolvers failed for" << ifname; + } +#ifdef Q_OS_MAC + const auto gw = NetworkUtilities::getGatewayAndIface(); + const QString uplinkIface = gw.second.name(); + const QString uplinkGateway = gw.first; + if (!uplinkIface.isEmpty() && !uplinkGateway.isEmpty()) { + auto add = iface->xrayAddUplinkRoutes(uplinkIface, uplinkGateway); + if (!add.waitForFinished() || !add.returnValue()) { + qWarning() << "VpnTrafficGuard::applyPolicy: xrayAddUplinkRoutes failed on" << uplinkIface; + } + } +#endif + }); + return; + } + const QJsonObject activate = LocalSocketController::buildActivateJson(tunnel->config(), tunnel->ifname()); const QStringList prefixes = allowedIpPrefixesFor(activate); const QStringList excluded = excludedAddressesFor(activate); const QStringList dns = resolversFor(activate); - const QString ifname = tunnel->ifname(); const QString peer = tunnel->remoteAddress(); IpcClient::withInterface([&](QSharedPointer iface) { @@ -379,10 +409,26 @@ void VpnTrafficGuard::revokePolicy(Tunnel* tunnel) { if (!tunnel) return; #ifdef AMNEZIA_DESKTOP + const QString ifname = tunnel->ifname(); + + if (VpnProtocol::isXrayBased(tunnel->container())) { + IpcClient::withInterface([&](QSharedPointer iface) { + iface->restoreResolvers(); +#ifdef Q_OS_MAC + const auto gw = NetworkUtilities::getGatewayAndIface(); + const QString uplinkIface = gw.second.name(); + const QString uplinkGateway = gw.first; + if (!uplinkIface.isEmpty()) { + iface->xrayRemoveUplinkRoutes(uplinkIface, uplinkGateway); + } +#endif + }); + return; + } + const QJsonObject activate = LocalSocketController::buildActivateJson(tunnel->config(), tunnel->ifname()); const QStringList prefixes = allowedIpPrefixesFor(activate); const QStringList excluded = excludedAddressesFor(activate); - const QString ifname = tunnel->ifname(); const QString peer = tunnel->remoteAddress(); IpcClient::withInterface([&](QSharedPointer iface) { diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 793c7bd0c..3e61e8c1e 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -47,6 +47,8 @@ class IpcInterface SLOT(bool xrayStart(const QString &ifname, const QString &config)); SLOT(bool xrayStop(const QString &ifname)); + SLOT(bool xrayAddUplinkRoutes(const QString &uplinkIface, const QString &uplinkGateway)); + SLOT(bool xrayRemoveUplinkRoutes(const QString &uplinkIface, const QString &uplinkGateway)); SLOT( bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) ); SLOT( bool stopNetworkCheck() ); diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index b1a6d4893..94750b10c 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -437,17 +437,6 @@ bool IpcServer::xrayStart(const QString& ifname, const QString& cfg) } } -#ifdef Q_OS_MAC - const auto gatewayAndIface = NetworkUtilities::getGatewayAndIface(); - w.uplinkGateway = gatewayAndIface.first; - w.uplinkIface = gatewayAndIface.second.name(); - if (!w.uplinkIface.isEmpty() && !w.uplinkGateway.isEmpty()) { - if (!RouterMac::Instance().routeAddXray(w.uplinkIface, w.uplinkGateway)) { - qWarning() << "[xray] failed to install xray routes on" << w.uplinkIface; - } - } -#endif - const QJsonObject startCmd{{QStringLiteral("op"), QStringLiteral("start")}, {QStringLiteral("config"), cfg}}; w.process->write(QJsonDocument(startCmd).toJson(QJsonDocument::Compact) + '\n'); @@ -457,7 +446,6 @@ bool IpcServer::xrayStart(const QString& ifname, const QString& cfg) w.startResult = false; loop.exec(); - // Re-fetch: the worker entry may have been removed during the loop (e.g. process finished). auto it = m_xrayWorkers.find(ifname); if (it == m_xrayWorkers.end()) { return false; @@ -466,11 +454,6 @@ bool IpcServer::xrayStart(const QString& ifname, const QString& cfg) const bool ok = it->startResult; if (!ok) { -#ifdef Q_OS_MAC - if (!it->uplinkIface.isEmpty()) { - RouterMac::Instance().routeDeleteXray(it->uplinkIface, it->uplinkGateway); - } -#endif m_xrayWorkers.remove(ifname); } @@ -499,12 +482,34 @@ bool IpcServer::xrayStop(const QString& ifname) } } -#ifdef Q_OS_MAC - if (!it->uplinkIface.isEmpty()) { - RouterMac::Instance().routeDeleteXray(it->uplinkIface, it->uplinkGateway); - } -#endif - m_xrayWorkers.remove(ifname); return true; } + +bool IpcServer::xrayAddUplinkRoutes(const QString& uplinkIface, const QString& uplinkGateway) +{ +#ifdef Q_OS_MAC + if (uplinkIface.isEmpty() || uplinkGateway.isEmpty()) { + return false; + } + return RouterMac::Instance().routeAddXray(uplinkIface, uplinkGateway); +#else + Q_UNUSED(uplinkIface) + Q_UNUSED(uplinkGateway) + return true; +#endif +} + +bool IpcServer::xrayRemoveUplinkRoutes(const QString& uplinkIface, const QString& uplinkGateway) +{ +#ifdef Q_OS_MAC + if (uplinkIface.isEmpty()) { + return false; + } + return RouterMac::Instance().routeDeleteXray(uplinkIface, uplinkGateway); +#else + Q_UNUSED(uplinkIface) + Q_UNUSED(uplinkGateway) + return true; +#endif +} diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index bcbad35c1..e7c37215e 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -57,6 +57,8 @@ public: virtual bool restoreResolvers() override; virtual bool xrayStart(const QString& ifname, const QString& cfg) override; virtual bool xrayStop(const QString& ifname) override; + virtual bool xrayAddUplinkRoutes(const QString& uplinkIface, const QString& uplinkGateway) override; + virtual bool xrayRemoveUplinkRoutes(const QString& uplinkIface, const QString& uplinkGateway) override; virtual bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) override; virtual bool stopNetworkCheck() override; @@ -83,10 +85,6 @@ private: QByteArray stdoutBuf; QPointer startLoop; bool startResult = false; -#ifdef Q_OS_MAC - QString uplinkIface; - QString uplinkGateway; -#endif }; QHash m_xrayWorkers;