From 043608143638d237d953e6b90328db3293093976 Mon Sep 17 00:00:00 2001 From: DHR60 <192860629+DHR60@users.noreply.github.com> Date: Sat, 22 Aug 2026 07:02:24 +0000 Subject: [PATCH] Revert "fix(tun): automatically exclude proxy node IPs and resolved domains from TUN routing to prevent loops (#9974) (#10012)" (#10013) This reverts commit 2be63d1655bb9bd5a319b2c064a3a766e367a575. --- .../Context/CoreConfigContextBuilderTests.cs | 106 +----------------- .../Builder/CoreConfigContextBuilder.cs | 79 ++----------- 2 files changed, 12 insertions(+), 173 deletions(-) diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs index 65b47de2..73688f67 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs @@ -83,96 +83,6 @@ public class CoreConfigContextBuilderTests await groupA.GetProtocolExtra().ChildItems.Should().BeEqualTo(leaf.IndexId); } - [Test] - public async Task Build_WhenTunEnabled_ShouldAutoExcludeProxyServerAddress() - { - var config = CoreConfigTestFactory.CreateConfig(); - config.TunModeItem.EnableTun = true; - config.TunModeItem.RouteExcludeAddress = ["10.0.0.0/8"]; - CoreConfigTestFactory.BindAppManagerConfig(config); - - var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray, "vmess-node"); - node.Address = "1.2.3.4"; - await UpsertProfilesAsync(node); - - var result = await CoreConfigContextBuilder.Build(config, node); - - await result.Success.Should().BeTrue(); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().Contain("10.0.0.0/8"); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().Contain("1.2.3.4/32"); - } - - [Test] - public async Task Build_WhenTunEnabled_ShouldAutoExcludeProxyServerAddress_IPv6WithBrackets() - { - var config = CoreConfigTestFactory.CreateConfig(); - config.TunModeItem.EnableTun = true; - CoreConfigTestFactory.BindAppManagerConfig(config); - - var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray, "vmess-v6"); - node.Address = "[2001:db8::1]"; - await UpsertProfilesAsync(node); - - var result = await CoreConfigContextBuilder.Build(config, node); - - await result.Success.Should().BeTrue(); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().Contain("2001:db8::1/128"); - } - - [Test] - public async Task Build_WhenTunEnabled_ShouldNotExcludeLoopbackAddress() - { - var config = CoreConfigTestFactory.CreateConfig(); - config.TunModeItem.EnableTun = true; - CoreConfigTestFactory.BindAppManagerConfig(config); - - var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray, "vmess-loopback"); - node.Address = "127.0.0.1"; - await UpsertProfilesAsync(node); - - var result = await CoreConfigContextBuilder.Build(config, node); - - await result.Success.Should().BeTrue(); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().NotContain("127.0.0.1/32"); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().NotContain("127.0.0.1"); - } - - [Test] - public async Task Build_WhenTunEnabled_ShouldNotExcludeAnyOrNoneAddress() - { - var config = CoreConfigTestFactory.CreateConfig(); - config.TunModeItem.EnableTun = true; - CoreConfigTestFactory.BindAppManagerConfig(config); - - var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray, "vmess-any"); - node.Address = "0.0.0.0"; - await UpsertProfilesAsync(node); - - var result = await CoreConfigContextBuilder.Build(config, node); - - await result.Success.Should().BeTrue(); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().NotContain("0.0.0.0/32"); - } - - [Test] - public async Task Build_WhenTunEnabled_WithDomainNode_ShouldExcludeResolvedIPs() - { - var config = CoreConfigTestFactory.CreateConfig(); - config.TunModeItem.EnableTun = true; - CoreConfigTestFactory.BindAppManagerConfig(config); - - var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray, "vmess-domain"); - node.Address = "one.one.one.one"; - await UpsertProfilesAsync(node); - - var result = await CoreConfigContextBuilder.Build(config, node); - - await result.Success.Should().BeTrue(); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().NotBeNull(); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress!.Count.Should().BeGreaterThan(0); - await result.Context.AppConfig.TunModeItem.RouteExcludeAddress.Should().Contain(x => x.StartsWith("1.1.1.1") || x.StartsWith("1.0.0.1") || x.Contains(':')); - } - private static string NewId(string prefix) { return $"{prefix}-{Guid.NewGuid():N}"; @@ -186,22 +96,12 @@ public class CoreConfigContextBuilderTests || message.Contains("циклическую зависимость", StringComparison.OrdinalIgnoreCase); } - private static readonly SemaphoreSlim _dbLock = new(1, 1); - private static async Task UpsertProfilesAsync(params ProfileItem[] profiles) { - await _dbLock.WaitAsync(); - try + SQLiteHelper.Instance.CreateTable(); + foreach (var profile in profiles) { - SQLiteHelper.Instance.CreateTable(); - foreach (var profile in profiles) - { - await SQLiteHelper.Instance.ReplaceAsync(profile); - } - } - finally - { - _dbLock.Release(); + await SQLiteHelper.Instance.ReplaceAsync(profile); } } } diff --git a/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs b/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs index 987d1945..349aee00 100644 --- a/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs +++ b/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs @@ -96,74 +96,22 @@ public class CoreConfigContextBuilder } } - if (context.IsTunEnabled) + if (context.IsTunEnabled && context.AppConfig.TunModeItem.RouteExcludeAddress is { Count: > 0 }) { var appConfig = JsonUtils.DeepCopy(config); var routeExcludeAddressList = new List(); - if (context.AppConfig.TunModeItem.RouteExcludeAddress is { Count: > 0 }) + foreach (var addr in context.AppConfig.TunModeItem.RouteExcludeAddress) { - foreach (var addr in context.AppConfig.TunModeItem.RouteExcludeAddress) + try { - try - { - IPNetwork2.Parse(addr); - routeExcludeAddressList.Add(addr); - } - catch - { - validatorResult.Warnings.Add(string.Format(ResUI.MsgTunRouteExcludeInvalidAddress, addr)); - } + IPNetwork2.Parse(addr); + routeExcludeAddressList.Add(addr); + } + catch + { + validatorResult.Warnings.Add(string.Format(ResUI.MsgTunRouteExcludeInvalidAddress, addr)); } } - - // Exclude proxy server IP addresses from TUN to prevent routing loops - var allNodes = context.AllProxiesMap.Values - .Append(context.Node) - .Where(n => n != null && !n.ConfigType.IsGroupType() && n.ConfigType != EConfigType.Outbound); - - var uniqueAddresses = allNodes - .Select(n => n.Address?.Trim().Trim('[', ']')) - .Where(a => !string.IsNullOrEmpty(a)) - .Distinct(StringComparer.OrdinalIgnoreCase); - - foreach (var pAddr in uniqueAddresses) - { - if (IPAddress.TryParse(pAddr, out var ipAddr)) - { - if (IsValidExcludableIP(ipAddr)) - { - var cidr = ipAddr.AddressFamily == AddressFamily.InterNetworkV6 ? $"{ipAddr}/128" : $"{ipAddr}/32"; - if (!routeExcludeAddressList.Contains(cidr)) - { - routeExcludeAddressList.Add(cidr); - } - } - } - else if (Utils.IsDomain(pAddr)) - { - try - { - using var cts = new CancellationTokenSource(2000); - var addresses = await Dns.GetHostAddressesAsync(pAddr, cts.Token); - foreach (var addr in addresses) - { - if (IsValidExcludableIP(addr)) - { - var cidr = addr.AddressFamily == AddressFamily.InterNetworkV6 ? $"{addr}/128" : $"{addr}/32"; - if (!routeExcludeAddressList.Contains(cidr)) - { - routeExcludeAddressList.Add(cidr); - } - } - } - } - catch - { - // Ignore DNS resolution failures at config build time - } - } - } - appConfig.TunModeItem.RouteExcludeAddress = routeExcludeAddressList; context = context with { AppConfig = appConfig }; } @@ -557,13 +505,4 @@ public class CoreConfigContextBuilder context.AllProxiesMap[node.IndexId] = node; return childNodeValidatorResult; } - - private static bool IsValidExcludableIP(IPAddress ipAddr) - { - return !IPAddress.IsLoopback(ipAddr) - && !ipAddr.Equals(IPAddress.Any) - && !ipAddr.Equals(IPAddress.IPv6Any) - && !ipAddr.Equals(IPAddress.None) - && !ipAddr.Equals(IPAddress.IPv6None); - } }