chore: rework xray routing

* get rid of redundant delays
* check if remote calls are successful
This commit is contained in:
Yaroslav Gurov
2026-02-03 02:16:12 +01:00
parent 2276e55fdf
commit 32374ad4cc
5 changed files with 121 additions and 60 deletions

View File

@@ -42,6 +42,66 @@ ErrorCode XrayProtocol::start()
return startTun2Sock();
}
void XrayProtocol::tun2socksConnectionStateChanged(int vpnState) {
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (vpnState == Vpn::ConnectionState::Connected) {
setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_primaryDNS));
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) {
dnsAddr.push_back(QHostAddress(m_secondaryDNS));
}
QRemoteObjectPendingReply<bool> res;
#ifdef AMNEZIA_DESKTOP
#ifdef Q_OS_MACOS
const QString tunName = "utun22";
#else
const QString tunName = "tun2";
#endif
res = iface->createTun(tunName, amnezia::protocols::xray::defaultLocalAddr);
if (!res.waitForFinished(10000)) {
qDebug() << "Failed to assign IP address for TUN";
}
res = iface->updateResolvers(tunName, dnsAddr);
if (!res.waitForFinished(1000)) {
qDebug() << "Failed to set DNS resolvers for TUN";
}
#endif
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
iface->routeAddList(m_vpnGateway, QStringList() << "1.0.0.0/8" << "2.0.0.0/7" << "4.0.0.0/6" << "8.0.0.0/5" << "16.0.0.0/4" << "32.0.0.0/3" << "64.0.0.0/2" << "128.0.0.0/1");
}
res = iface->StopRoutingIpv6();
if (!res.waitForFinished(1000)) {
qDebug() << "Failed to stop routing IPv6";
}
#ifdef Q_OS_WIN
res = iface->enablePeerTraffic(m_xrayConfig);
if (!res.waitForFinished()) {
qDebug() << "Failed to enable peer traffic";
}
#endif
setConnectionState(Vpn::ConnectionState::Connected);
}
#if !defined(Q_OS_MACOS)
if (vpnState == Vpn::ConnectionState::Disconnected) {
setConnectionState(Vpn::ConnectionState::Disconnected);
iface->deleteTun("tun2");
iface->StartRoutingIpv6();
iface->clearSavedRoutes();
}
#endif
});
}
ErrorCode XrayProtocol::startTun2Sock()
{
m_t2sProcess->start();
@@ -50,48 +110,10 @@ ErrorCode XrayProtocol::startTun2Sock()
[&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; });
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this, [&](int vpnState) {
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (vpnState == Vpn::ConnectionState::Connected) {
setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_primaryDNS));
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) {
dnsAddr.push_back(QHostAddress(m_secondaryDNS));
}
#ifdef Q_OS_WIN
iface->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
iface->updateResolvers("tun2", dnsAddr);
#endif
#ifdef Q_OS_MACOS
iface->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
iface->updateResolvers("utun22", dnsAddr);
#endif
#ifdef Q_OS_LINUX
iface->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
iface->updateResolvers("tun2", dnsAddr);
#endif
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
iface->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/0");
}
iface->StopRoutingIpv6();
#ifdef Q_OS_WIN
iface->enablePeerTraffic(m_xrayConfig);
#endif
setConnectionState(Vpn::ConnectionState::Connected);
}
#if !defined(Q_OS_MACOS)
if (vpnState == Vpn::ConnectionState::Disconnected) {
setConnectionState(Vpn::ConnectionState::Disconnected);
iface->deleteTun("tun2");
iface->StartRoutingIpv6();
iface->clearSavedRoutes();
}
#endif
});
QMetaObject::invokeMethod(this, [this, vpnState]() {
QThread::msleep(5000);
tun2socksConnectionStateChanged(vpnState);
}, Qt::QueuedConnection);
});
return ErrorCode::NoError;

View File

@@ -14,10 +14,11 @@ public:
virtual ~XrayProtocol() override;
ErrorCode start() override;
ErrorCode startTun2Sock();
void stop() override;
private:
void tun2socksConnectionStateChanged(int vpnState);
ErrorCode startTun2Sock();
void readXrayConfiguration(const QJsonObject &configuration);
QJsonObject m_xrayConfig;

View File

@@ -29,7 +29,7 @@ void IpcProcessTun2Socks::start()
QString XrayConStr = "socks5://127.0.0.1:10808";
#ifdef Q_OS_WIN
QStringList arguments({"-device", "tun://tun2?guid={081A8A84-8D12-4DF5-B8C4-396D5B0053E4}", "-proxy", XrayConStr});
QStringList arguments({"-device", "tun://tun2?guid={081A8A84-8D12-4DF5-B8C4-396D5B0053E4}", "-proxy", XrayConStr });
#endif
#ifdef Q_OS_LINUX
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr});
@@ -45,8 +45,6 @@ void IpcProcessTun2Socks::start()
Utils::killProcessByName(Utils::executable("tun2socks", false));
}
m_t2sProcess->start();
connect(m_t2sProcess.data(), &QProcess::readyReadStandardOutput, this, [this]() {
QString line = m_t2sProcess.data()->readAllStandardOutput();
if (line.contains("[STACK] tun://") && line.contains("<-> socks5://127.0.0.1")) {

View File

@@ -6,7 +6,7 @@ project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION})
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS DBus Core Network Widgets RemoteObjects Core5Compat)
find_package(Qt6 REQUIRED COMPONENTS DBus Core Network Widgets RemoteObjects Core5Compat Concurrent)
qt_standard_project_setup()
@@ -353,7 +353,7 @@ include_directories(
add_executable(${PROJECT} ${SOURCES} ${HEADERS} ${RESOURCES})
target_link_libraries(${PROJECT} PRIVATE Qt6::Core Qt6::Widgets Qt6::Network Qt6::RemoteObjects Qt6::Core5Compat Qt6::DBus ${LIBS})
target_link_libraries(${PROJECT} PRIVATE Qt6::Core Qt6::Widgets Qt6::Network Qt6::RemoteObjects Qt6::Core5Compat Qt6::DBus Qt6::Concurrent ${LIBS})
target_compile_definitions(${PROJECT} PRIVATE "MZ_$<UPPER_CASE:${MZ_PLATFORM_NAME}>")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")

View File

@@ -5,6 +5,7 @@
#include <tchar.h>
#include <QProcess>
#include <QtConcurrent/QtConcurrent>
#include <core/networkUtilities.h>
@@ -310,11 +311,37 @@ void RouterWin::resetIpStack()
bool RouterWin::createTun(const QString &dev, const QString &subnet)
{
const QString command = QString("netsh interface ip set address name=\"tun2\" static %1 255.255.255.255").arg(subnet);
NET_LUID luid;
QProcess p;
p.start(command);
return p.waitForFinished();
DWORD result = ConvertInterfaceNameToLuidW(reinterpret_cast<const wchar_t*>(dev.utf16()), &luid);
if (result != NO_ERROR) {
qDebug() << "Failed to get device LUID:" << result;
return false;
}
MIB_UNICASTIPADDRESS_ROW row;
InitializeUnicastIpAddressEntry(&row);
row.InterfaceLuid = luid;
row.Address.si_family = AF_INET;
inet_pton(AF_INET, subnet.toStdString().c_str(),
&row.Address.Ipv4.sin_addr);
row.OnLinkPrefixLength = 32;
row.PrefixOrigin = IpPrefixOriginManual;
row.SuffixOrigin = IpSuffixOriginManual;
row.ValidLifetime = 0xffffffff;
row.PreferredLifetime = 0xffffffff;
row.SkipAsSource = false;
result = CreateUnicastIpAddressEntry(&row);
if (result != NO_ERROR && result != ERROR_OBJECT_ALREADY_EXISTS) {
qDebug() << "Failed to create IP address:" << result;
return false;
}
return true;
}
void RouterWin::suspendWcmSvc(bool suspend)
@@ -474,11 +501,19 @@ bool RouterWin::StopRoutingIpv6()
qDebug() << "RouterWin::StopRoutingIpv6";
if (auto loopback = findLoopbackIface(); loopback.isValid()) {
for (auto subnet : kIpv6Subnets) {
QProcess{}.execute("netsh", { "interface", "ipv6", "add", "route", subnet, QString("interface=%1").arg(loopback.index()), "metric=0", "store=active" });
}
QFuture<bool> res = QtConcurrent::mappedReduced(kIpv6Subnets, [loopback](const QString &subnet) -> bool {
int res = QProcess::execute("netsh", { "interface", "ipv6", "add", "route", subnet, QString("interface=%1").arg(loopback.index()), "metric=0", "store=active" });
return res == 0;
},
[](bool &result, bool success) {
result = result && success;
}, true);
res.waitForFinished();
return res.result();
}
return true;
return false;
}
bool RouterWin::StartRoutingIpv6()
@@ -486,9 +521,14 @@ bool RouterWin::StartRoutingIpv6()
qDebug() << "RouterWin::StartRoutingIpv6";
if (auto loopback = findLoopbackIface(); loopback.isValid()) {
for (auto subnet : kIpv6Subnets) {
QProcess{}.execute("netsh", { "interface", "ipv6", "delete", "route", subnet, QString("interface=%1").arg(loopback.index()) });
}
QFuture<bool> res = QtConcurrent::mappedReduced(kIpv6Subnets, [loopback](const QString &subnet) -> bool {
int res = QProcess::execute("netsh", { "interface", "ipv6", "delete", "route", subnet, QString("interface=%1").arg(loopback.index()) });
return res == 0;
},
[](bool &result, bool success) {
result = result && success;
}, true);
}
return true;
return false;
}