feat: native split-tunneling for xray (#1899)

* feat: integrated xray as a library and added split-tunneling

* fix: added copying amnezia_xray.dll to build dir

* fix: changed path on darwin

* chore: clean up getting default device

* chore: removed WSAGetLastError from sockopt logging

* fix: get rid of debug logs in xray handlers

* fix: minor fixes and xray debugging capabilities

* fix: macos default interface fix

* fix: roll-back ipv6 sockopt for mac

* fix: bind IPv6 on Windows

* fix: (win) better IPv6 handling and router fixes

* feat: prebuilts uploaded

* fix: removed redundant cmake definitions

* feat: moved xray to service process, reworked errors

* fix: return values in networkUtilities

* fix: macos build fixes

* fix: (windows) cmake fixes

* fix: (windows) compilation fix

* fix: (windows) changed location of amnezia_xray.dll

* feat: xray logs added to system service

* chore: bump xray&tun2socks versions for android

* chore: cleanup of XrayProtocol class
* removed killswitch
* removed redundant members and basic cleanup

* feat: support split-tunneling in iOS and macOS NE

* chore: update active interface index based on network path and available interfaces

* refactor: update network path handling and logging in PacketTunnelProvider

* chore: bump xray deps

---------

Co-authored-by: Yaroslav Yashin <yaroslav.yashin@gmail.com>
This commit is contained in:
Yaroslav Gurov
2025-12-15 14:54:34 +01:00
committed by GitHub
parent d669adb707
commit 54f67b3d82
21 changed files with 455 additions and 207 deletions
+24 -35
View File
@@ -13,6 +13,8 @@ LONG (NTAPI * NtResumeProcess)(HANDLE ProcessHandle) = NULL;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
QList<QString> RouterWin::kIpv6Subnets = { "fc00::/7", "2000::/4", "3000::/4" };
RouterWin &RouterWin::Instance()
{
static RouterWin s;
@@ -448,49 +450,36 @@ bool RouterWin::restoreResolvers() {
return m_dnsUtil->restoreResolvers();
}
QNetworkInterface RouterWin::findLoopbackIface()
{
for (auto iface : QNetworkInterface::allInterfaces()) {
if (iface.flags() & QNetworkInterface::IsLoopBack) {
return iface;
}
}
return {};
}
bool RouterWin::StopRoutingIpv6()
{
{
QProcess p;
QString command = QString("interface ipv6 add route fc00::/7 interface={NetworkInterface.IPv6LoopbackInterfaceIndex} metric=0 store=active");
p.start(command);
p.waitForFinished();
}
{
QProcess p;
QString command = QString("interface ipv6 add route 2000::/4 interface={NetworkInterface.IPv6LoopbackInterfaceIndex} metric=0 store=active");
p.start(command);
p.waitForFinished();
}
{
QProcess p;
QString command = QString("interface ipv6 add route 3000::/4 interface={NetworkInterface.IPv6LoopbackInterfaceIndex} metric=0 store=active");
p.start(command);
p.waitForFinished();
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" });
}
}
return true;
}
bool RouterWin::StartRoutingIpv6()
{
{
QProcess p;
QString command = QString("interface ipv6 delete route fc00::/7 interface={NetworkInterface.IPv6LoopbackInterfaceIndex}");
p.start(command);
p.waitForFinished();
}
{
QProcess p;
QString command = QString("interface ipv6 delete route 2000::/4 interface={NetworkInterface.IPv6LoopbackInterfaceIndex}");
p.start(command);
p.waitForFinished();
}
{
QProcess p;
QString command = QString("interface ipv6 delete route 3000::/4 interface={NetworkInterface.IPv6LoopbackInterfaceIndex}");
p.start(command);
p.waitForFinished();
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()) });
}
}
return true;
}