From 37ef25cbfe2e6e2a91506e50e187a095225b3ba4 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sun, 3 May 2026 08:09:47 +0000 Subject: [PATCH] Fix (#9235) * Perf routing * GeoPrefix move to Global * Fix negative rules * Fix --- v2rayN/ServiceLib/Global.cs | 2 + .../CoreConfig/Singbox/SingboxDnsService.cs | 32 +++++---- .../Singbox/SingboxRoutingService.cs | 71 +++++++++++++------ .../CoreConfig/V2ray/V2rayDnsService.cs | 31 ++++---- v2rayN/ServiceLib/Services/UpdateService.cs | 4 +- 5 files changed, 90 insertions(+), 50 deletions(-) diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 8de3d925..4d4f541a 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -67,6 +67,8 @@ public class Global public const string AsIs = "AsIs"; public const string IPIfNonMatch = "IPIfNonMatch"; public const string IPOnDemand = "IPOnDemand"; + public const string GeoSitePrefix = "geosite:"; + public const string GeoIPPrefix = "geoip:"; public const string UserEMail = "t@t.tt"; public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index a0d172ba..f5a7da4b 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -298,7 +298,7 @@ public partial class CoreConfigSingboxService var rules = JsonUtils.Deserialize>(routing.RuleSet) ?? []; var expectedIPCidr = new List(); var expectedIPsRegions = new List(); - var regionNames = new HashSet(); + var regionName = string.Empty; if (!string.IsNullOrEmpty(simpleDnsItem?.DirectExpectedIPs)) { @@ -310,16 +310,16 @@ public partial class CoreConfigSingboxService foreach (var ip in ipItems) { - if (ip.StartsWith("geoip:", StringComparison.OrdinalIgnoreCase)) + if (ip.StartsWith(Global.GeoIPPrefix, StringComparison.OrdinalIgnoreCase)) { - var region = ip["geoip:".Length..]; - if (!string.IsNullOrEmpty(region)) + var region = ip[Global.GeoIPPrefix.Length..]; + if (string.IsNullOrEmpty(region)) { - expectedIPsRegions.Add(region); - regionNames.Add(region); - regionNames.Add($"geolocation-{region}"); - regionNames.Add($"tld-{region}"); + continue; } + + expectedIPsRegions.Add(region); + regionName = region; } else { @@ -352,19 +352,25 @@ public partial class CoreConfigSingboxService rule.server = Global.SingboxDirectDNSTag; rule.strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); - if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0) + if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0 && !regionName.IsNullOrEmpty()) { - var geositeSet = new HashSet(rule.geosite); - if (regionNames.Intersect(geositeSet).Any()) + var regionGeosite = rule.geosite.Where(g => g.EndsWith($"-{regionName}", StringComparison.OrdinalIgnoreCase) + || g.EndsWith($"@{regionName}", StringComparison.OrdinalIgnoreCase) + || g == regionName).ToList(); + if (regionGeosite.Count > 0) { + rule.geosite.RemoveAll(regionGeosite.Contains); + var rule4ExpectedIPs = JsonUtils.DeepCopy(rule); + rule4ExpectedIPs.geosite = regionGeosite; if (expectedIPsRegions.Count > 0) { - rule.geoip = expectedIPsRegions; + rule4ExpectedIPs.geoip = expectedIPsRegions; } if (expectedIPCidr.Count > 0) { - rule.ip_cidr = expectedIPCidr; + rule4ExpectedIPs.ip_cidr = expectedIPCidr; } + _coreConfig.dns.rules.Add(rule4ExpectedIPs); } } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs index 92ee56a2..2b6bdf2b 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs @@ -329,11 +329,52 @@ public partial class CoreConfigSingboxService if (item.Ip?.Count > 0) { var countIp = 0; - foreach (var it in item.Ip) + var negativeIpList = item.Ip.Where(it => it.StartsWith('!')).ToList(); + if (negativeIpList.Count > 0) { - if (ParseV2Address(it, rule2)) + var positiveIpList = item.Ip.Except(negativeIpList).ToList(); + var positiveRule = rule2; + positiveRule = JsonUtils.DeepCopy(rule2); + positiveRule.outbound = null; + positiveRule.action = null; + foreach (var it in positiveIpList) { - countIp++; + if (ParseV2Address(it, positiveRule)) + { + countIp++; + } + } + var negativeRule = new Rule4Sbox(); + foreach (var it in negativeIpList) + { + // Remove first '!' and trim spaces + var ip = it[1..].Trim(); + if (ParseV2Address(ip, negativeRule)) + { + countIp++; + } + } + negativeRule.invert = true; + rule2 = new Rule4Sbox() + { + outbound = rule2.outbound, + action = rule2.action, + type = "logical", + mode = "or", + rules = [ + positiveRule, + negativeRule + ] + }; + } + else + { + foreach (var it in item.Ip) + { + if (ParseV2Address(it, rule2)) + { + countIp++; + } } } if (countIp > 0) @@ -406,10 +447,10 @@ public partial class CoreConfigSingboxService { return false; } - else if (domain.StartsWith("geosite:")) + else if (domain.StartsWith(Global.GeoSitePrefix)) { rule.geosite ??= []; - rule.geosite?.Add(domain.Substring(8)); + rule.geosite?.Add(domain[Global.GeoSitePrefix.Length..]); } else if (domain.StartsWith("regexp:")) { @@ -450,28 +491,18 @@ public partial class CoreConfigSingboxService { return false; } - else if (address.Equals("geoip:private")) + else if (address.Equals($"{Global.GeoIPPrefix}private")) { rule.ip_is_private = true; } - else if (address.StartsWith("geoip:")) + else if (address.StartsWith(Global.GeoIPPrefix)) { - rule.geoip ??= new(); - rule.geoip?.Add(address.Substring(6)); - } - else if (address.Equals("geoip:!private")) - { - rule.ip_is_private = false; - } - else if (address.StartsWith("geoip:!")) - { - rule.geoip ??= new(); - rule.geoip?.Add(address.Substring(6)); - rule.invert = true; + rule.geoip ??= []; + rule.geoip?.Add(address[Global.GeoIPPrefix.Length..]); } else { - rule.ip_cidr ??= new(); + rule.ip_cidr ??= []; rule.ip_cidr?.Add(address); } return true; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index 7faae5b1..1777d16a 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -121,7 +121,7 @@ public partial class CoreConfigV2rayService var proxyGeositeList = new List(); var expectedDomainList = new List(); var expectedIPs = new List(); - var regionNames = new HashSet(); + var regionName = string.Empty; var bootstrapDNSAddress = ParseDnsAddresses(simpleDNSItem?.BootstrapDNS, Global.DomainPureIPDNSAddress.First()); var dnsServerDomains = new List(); @@ -160,18 +160,14 @@ public partial class CoreConfigV2rayService .Where(s => !string.IsNullOrEmpty(s)) .ToList(); - foreach (var ip in expectedIPs) + foreach (var region in from ip in expectedIPs + where ip.StartsWith(Global.GeoIPPrefix, StringComparison.OrdinalIgnoreCase) + select ip[Global.GeoIPPrefix.Length..] + into region + where !string.IsNullOrEmpty(region) + select region) { - if (ip.StartsWith("geoip:", StringComparison.OrdinalIgnoreCase)) - { - var region = ip["geoip:".Length..]; - if (!string.IsNullOrEmpty(region)) - { - regionNames.Add($"geosite:{region}"); - regionNames.Add($"geosite:geolocation-{region}"); - regionNames.Add($"geosite:tld-{region}"); - } - } + regionName = region; } } @@ -201,9 +197,14 @@ public partial class CoreConfigV2rayService if (item.OutboundTag == Global.DirectTag) { - if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) + if (normalizedDomain.StartsWith(Global.GeoSitePrefix) || normalizedDomain.StartsWith("ext:")) { - (regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain); + var isExpectedDomain = !regionName.IsNullOrEmpty() + || normalizedDomain.EndsWith($"-{regionName}") + || normalizedDomain.EndsWith($"@{regionName}") + || normalizedDomain == Global.GeoSitePrefix + regionName; + var targetList = isExpectedDomain ? expectedDomainList : directGeositeList; + targetList.Add(normalizedDomain); } else { @@ -212,7 +213,7 @@ public partial class CoreConfigV2rayService } else if (item.OutboundTag != Global.BlockTag) { - if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) + if (normalizedDomain.StartsWith(Global.GeoSitePrefix) || normalizedDomain.StartsWith("ext:")) { proxyGeositeList.Add(normalizedDomain); } diff --git a/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayN/ServiceLib/Services/UpdateService.cs index 87281149..57f9d14b 100644 --- a/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayN/ServiceLib/Services/UpdateService.cs @@ -375,8 +375,8 @@ public class UpdateService(Config config, Func updateFunc) var rules = JsonUtils.Deserialize>(routing.RuleSet); foreach (var item in rules ?? []) { - AddPrefixedItems(item.Ip, "geoip:", geoipFiles); - AddPrefixedItems(item.Domain, "geosite:", geoSiteFiles); + AddPrefixedItems(item.Ip, Global.GeoIPPrefix, geoipFiles); + AddPrefixedItems(item.Domain, Global.GeoSitePrefix, geoSiteFiles); } }