From ad07f281c73a0ecdeb0bc4d455f84a5688c7539c Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 27 Feb 2026 03:04:00 +0000 Subject: [PATCH 1/4] Fix routing (#8849) Fix --- .../CoreConfig/Singbox/SingboxDnsService.cs | 14 +- .../Singbox/SingboxOutboundService.cs | 9 +- .../V2ray/CoreConfigV2rayService.cs | 9 ++ .../CoreConfig/V2ray/V2rayDnsService.cs | 138 +++++++++--------- .../CoreConfig/V2ray/V2rayRoutingService.cs | 24 +++ 5 files changed, 121 insertions(+), 73 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index b4ddaf7f..03f4e80c 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -26,11 +26,15 @@ public partial class CoreConfigSingboxService { var rules = JsonUtils.Deserialize>(routing.RuleSet) ?? []; - useDirectDns = rules?.LastOrDefault() is { } lastRule && - lastRule.OutboundTag == Global.DirectTag && - (lastRule.Port == "0-65535" || - lastRule.Network == "tcp,udp" || - lastRule.Ip?.Contains("0.0.0.0/0") == true); + if (rules?.LastOrDefault() is { } lastRule && lastRule.OutboundTag == Global.DirectTag) + { + var noDomain = lastRule.Domain == null || lastRule.Domain.Count == 0; + var noProcess = lastRule.Process == null || lastRule.Process.Count == 0; + var isAnyIp = lastRule.Ip == null || lastRule.Ip.Count == 0 || lastRule.Ip.Contains("0.0.0.0/0"); + var isAnyPort = string.IsNullOrEmpty(lastRule.Port) || lastRule.Port == "0-65535"; + var isAnyNetwork = string.IsNullOrEmpty(lastRule.Network) || lastRule.Network == "tcp,udp"; + useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork; + } } _coreConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag; var simpleDnsItem = context.SimpleDnsItem; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 40f8951d..b30c9c48 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -20,10 +20,13 @@ public partial class CoreConfigSingboxService { proxyOutboundList.AddRange(BuildGroupProxyOutbounds(baseTagName)); } - var proxyTags = proxyOutboundList.Where(n => n.tag.StartsWith(Global.ProxyTag)).Select(n => n.tag).ToList(); - if (proxyTags.Count > 1) + if (withSelector) { - proxyOutboundList.InsertRange(0, BuildSelectorOutbounds(proxyTags, baseTagName)); + var proxyTags = proxyOutboundList.Where(n => n.tag.StartsWith(Global.ProxyTag)).Select(n => n.tag).ToList(); + if (proxyTags.Count > 1) + { + proxyOutboundList.InsertRange(0, BuildSelectorOutbounds(proxyTags, baseTagName)); + } } return proxyOutboundList; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs index f4c9c852..e34dceb6 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs @@ -60,6 +60,12 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) GenStatistic(); + var finalRule = BuildFinalRule(); + if (!string.IsNullOrEmpty(finalRule?.balancerTag)) + { + _coreConfig.routing.rules.Add(finalRule); + } + ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Success = true; ret.Data = ApplyFullConfigTemplate(); @@ -234,6 +240,7 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) GenLog(); GenOutbounds(); + _coreConfig.routing.domainStrategy = Global.AsIs; _coreConfig.routing.rules.Clear(); _coreConfig.inbounds.Clear(); _coreConfig.inbounds.Add(new() @@ -244,6 +251,8 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) protocol = EInboundProtocol.mixed.ToString(), }); + _coreConfig.routing.rules.Add(BuildFinalRule()); + ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Success = true; ret.Data = JsonUtils.Serialize(_coreConfig); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index 10cd905b..1d31f7b2 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -70,17 +70,16 @@ public partial class CoreConfigV2rayService dnsItem.serveStale = simpleDnsItem?.ServeStale is true ? true : null; dnsItem.enableParallelQuery = simpleDnsItem?.ParallelQuery is true ? true : null; - if (_coreConfig.routing.domainStrategy == Global.IPIfNonMatch) + // DNS routing + var finalRule = BuildFinalRule(); + dnsItem.tag = Global.DnsTag; + _coreConfig.routing.rules.Add(new() { - // DNS routing - dnsItem.tag = Global.DnsTag; - _coreConfig.routing.rules.Add(new RulesItem4Ray - { - type = "field", - inboundTag = new List { Global.DnsTag }, - outboundTag = Global.ProxyTag, - }); - } + type = "field", + inboundTag = [Global.DnsTag], + outboundTag = finalRule.outboundTag, + balancerTag = finalRule.balancerTag + }); _coreConfig.dns = dnsItem; } @@ -93,45 +92,6 @@ public partial class CoreConfigV2rayService private void FillDnsServers(Dns4Ray dnsItem) { var simpleDNSItem = context.SimpleDnsItem; - static List ParseDnsAddresses(string? dnsInput, string defaultAddress) - { - var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';') - .Select(addr => addr.Trim()) - .Where(addr => !string.IsNullOrEmpty(addr)) - .Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr) - .Distinct() - .ToList() ?? new List { defaultAddress }; - return addresses.Count > 0 ? addresses : new List { defaultAddress }; - } - - static object? CreateDnsServer(string dnsAddress, List domains, List? expectedIPs = null) - { - var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress); - var domainFinal = dnsAddress; - int? portFinal = null; - if (scheme.IsNullOrEmpty() || scheme.StartsWith("udp", StringComparison.OrdinalIgnoreCase)) - { - domainFinal = domain; - portFinal = port > 0 ? port : null; - } - else if (scheme.StartsWith("tcp", StringComparison.OrdinalIgnoreCase)) - { - domainFinal = scheme + "://" + domain; - portFinal = port > 0 ? port : null; - } - var dnsServer = new DnsServer4Ray - { - address = domainFinal, - port = portFinal, - skipFallback = true, - domains = domains.Count > 0 ? domains : null, - expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null - }; - return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }); - } var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.First()); var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.First()); @@ -252,17 +212,6 @@ public partial class CoreConfigV2rayService dnsItem.servers ??= []; - void AddDnsServers(List dnsAddresses, List domains, List? expectedIPs = null) - { - if (domains.Count > 0) - { - foreach (var dnsAddress in dnsAddresses) - { - dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs)); - } - } - } - AddDnsServers(remoteDNSAddress, proxyDomainList); AddDnsServers(directDNSAddress, directDomainList); AddDnsServers(remoteDNSAddress, proxyGeositeList); @@ -273,14 +222,73 @@ public partial class CoreConfigV2rayService AddDnsServers(bootstrapDNSAddress, dnsServerDomains); } - var useDirectDns = rules?.LastOrDefault() is { } lastRule - && lastRule.OutboundTag == Global.DirectTag - && (lastRule.Port == "0-65535" - || lastRule.Network == "tcp,udp" - || lastRule.Ip?.Contains("0.0.0.0/0") == true); + var useDirectDns = false; + + if (rules?.LastOrDefault() is { } lastRule && lastRule.OutboundTag == Global.DirectTag) + { + var noDomain = lastRule.Domain == null || lastRule.Domain.Count == 0; + var noProcess = lastRule.Process == null || lastRule.Process.Count == 0; + var isAnyIp = lastRule.Ip == null || lastRule.Ip.Count == 0 || lastRule.Ip.Contains("0.0.0.0/0"); + var isAnyPort = string.IsNullOrEmpty(lastRule.Port) || lastRule.Port == "0-65535"; + var isAnyNetwork = string.IsNullOrEmpty(lastRule.Network) || lastRule.Network == "tcp,udp"; + useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork; + } var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress; dnsItem.servers.AddRange(defaultDnsServers); + return; + + static List ParseDnsAddresses(string? dnsInput, string defaultAddress) + { + var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';') + .Select(addr => addr.Trim()) + .Where(addr => !string.IsNullOrEmpty(addr)) + .Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr) + .Distinct() + .ToList() ?? [defaultAddress]; + return addresses.Count > 0 ? addresses : new List { defaultAddress }; + } + + static object? CreateDnsServer(string dnsAddress, List domains, List? expectedIPs = null) + { + var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress); + var domainFinal = dnsAddress; + int? portFinal = null; + if (scheme.IsNullOrEmpty() || scheme.StartsWith("udp", StringComparison.OrdinalIgnoreCase)) + { + domainFinal = domain; + portFinal = port > 0 ? port : null; + } + else if (scheme.StartsWith("tcp", StringComparison.OrdinalIgnoreCase)) + { + domainFinal = scheme + "://" + domain; + portFinal = port > 0 ? port : null; + } + var dnsServer = new DnsServer4Ray + { + address = domainFinal, + port = portFinal, + skipFallback = true, + domains = domains.Count > 0 ? domains : null, + expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null + }; + return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }); + } + + void AddDnsServers(List dnsAddresses, List domains, List? expectedIPs = null) + { + if (domains.Count <= 0) + { + return; + } + foreach (var dnsAddress in dnsAddresses) + { + dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs)); + } + } } private void FillDnsHosts(Dns4Ray dnsItem) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs index 1d3d1a37..76969297 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs @@ -181,4 +181,28 @@ public partial class CoreConfigV2rayService return tag; } + + private RulesItem4Ray BuildFinalRule() + { + var finalRule = new RulesItem4Ray() + { + type = "field", + network = "tcp,udp", + outboundTag = Global.ProxyTag, + }; + var balancer = + _coreConfig?.routing?.balancers?.FirstOrDefault(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix, null); + var domainStrategy = _coreConfig.routing?.domainStrategy ?? Global.AsIs; + if (balancer is not null) + { + finalRule.outboundTag = null; + finalRule.balancerTag = balancer.tag; + } + if (domainStrategy == Global.IPIfNonMatch) + { + finalRule.network = null; + finalRule.ip = ["0.0.0.0/0", "::/0"]; + } + return finalRule; + } } From 49e487886d758fe1d9faa014186fb4a183fdd541 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 11:04:16 +0800 Subject: [PATCH 2/4] Bump actions/upload-artifact from 6.0.0 to 7.0.0 (#8850) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6.0.0...v7.0.0) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-linux.yml | 4 ++-- .github/workflows/build-osx.yml | 2 +- .github/workflows/build-windows-desktop.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 394d2862..ee0aeb8d 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -50,7 +50,7 @@ jobs: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 -p:SelfContained=true -p:PublishTrimmed=true -o "$OutputPathArm64" - name: Upload build artifacts - uses: actions/upload-artifact@v6.0.0 + uses: actions/upload-artifact@v7.0.0 with: name: v2rayN-linux path: | @@ -190,7 +190,7 @@ jobs: ls -R "$GITHUB_WORKSPACE/dist/rpm" || true - name: Upload RPM artifacts - uses: actions/upload-artifact@v6.0.0 + uses: actions/upload-artifact@v7.0.0 with: name: v2rayN-rpm path: dist/rpm/**/*.rpm diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml index f36b2b0e..f16f28bf 100644 --- a/.github/workflows/build-osx.yml +++ b/.github/workflows/build-osx.yml @@ -45,7 +45,7 @@ jobs: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 -p:SelfContained=true -p:PublishTrimmed=true -o $OutputPathArm64 - name: Upload build artifacts - uses: actions/upload-artifact@v6.0.0 + uses: actions/upload-artifact@v7.0.0 with: name: v2rayN-macos path: | diff --git a/.github/workflows/build-windows-desktop.yml b/.github/workflows/build-windows-desktop.yml index 16f3771f..1a85e546 100644 --- a/.github/workflows/build-windows-desktop.yml +++ b/.github/workflows/build-windows-desktop.yml @@ -45,7 +45,7 @@ jobs: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64 - name: Upload build artifacts - uses: actions/upload-artifact@v6.0.0 + uses: actions/upload-artifact@v7.0.0 with: name: v2rayN-windows-desktop path: | diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index d1c2f66a..4c1ce3ea 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -42,7 +42,7 @@ jobs: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64 - name: Upload build artifacts - uses: actions/upload-artifact@v6.0.0 + uses: actions/upload-artifact@v7.0.0 with: name: v2rayN-windows path: | From 0cf07e925f1658d66fcbf6b16230e94ea88cd7b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 11:04:20 +0800 Subject: [PATCH 3/4] Bump actions/download-artifact from 7 to 8 (#8851) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index ee0aeb8d..a814b8e4 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -169,7 +169,7 @@ jobs: fetch-depth: '0' - name: Restore build artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: v2rayN-linux path: ${{ github.workspace }}/v2rayN/Release From ed1275e29f488ef23a3e02cf9c41c3f64be6e0ff Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Fri, 27 Feb 2026 11:21:51 +0800 Subject: [PATCH 4/4] Upgrade Downloader to 4.1.1 and update API usage --- v2rayN/Directory.Packages.props | 4 ++-- v2rayN/ServiceLib/Helper/DownloaderHelper.cs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/v2rayN/Directory.Packages.props b/v2rayN/Directory.Packages.props index 57dedb74..14b16776 100644 --- a/v2rayN/Directory.Packages.props +++ b/v2rayN/Directory.Packages.props @@ -11,7 +11,7 @@ - + @@ -29,4 +29,4 @@ - + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Helper/DownloaderHelper.cs b/v2rayN/ServiceLib/Helper/DownloaderHelper.cs index f4a7ae7f..71c3edbe 100644 --- a/v2rayN/ServiceLib/Helper/DownloaderHelper.cs +++ b/v2rayN/ServiceLib/Helper/DownloaderHelper.cs @@ -24,13 +24,13 @@ public class DownloaderHelper var downloadOpt = new DownloadConfiguration() { - Timeout = timeout * 1000, + BlockTimeout = timeout * 1000, MaxTryAgainOnFailure = 2, RequestConfiguration = { Headers = headers, UserAgent = userAgent, - Timeout = timeout * 1000, + ConnectTimeout = timeout * 1000, Proxy = webProxy } }; @@ -62,11 +62,11 @@ public class DownloaderHelper var downloadOpt = new DownloadConfiguration() { - Timeout = timeout * 1000, + BlockTimeout = timeout * 1000, MaxTryAgainOnFailure = 2, RequestConfiguration = { - Timeout= timeout * 1000, + ConnectTimeout= timeout * 1000, Proxy = webProxy } }; @@ -139,11 +139,11 @@ public class DownloaderHelper var downloadOpt = new DownloadConfiguration() { - Timeout = timeout * 1000, + BlockTimeout = timeout * 1000, MaxTryAgainOnFailure = 2, RequestConfiguration = { - Timeout= timeout * 1000, + ConnectTimeout= timeout * 1000, Proxy = webProxy } };