From c3223e1fc416577a45a20fc691436fe7bd2df750 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 6 Feb 2026 12:55:55 +0800 Subject: [PATCH 1/6] Refactor core config gen --- v2rayN/ServiceLib/Global.cs | 1 - v2rayN/ServiceLib/Handler/ConfigHandler.cs | 13 +- .../ServiceLib/Handler/CoreConfigHandler.cs | 145 +++- v2rayN/ServiceLib/Manager/CoreManager.cs | 23 +- .../ServiceLib/Manager/GroupProfileManager.cs | 71 +- v2rayN/ServiceLib/Models/CoreConfigContext.cs | 17 + v2rayN/ServiceLib/Models/SingboxConfig.cs | 8 - v2rayN/ServiceLib/Sample/SampleClientConfig | 30 +- .../Sample/SingboxSampleClientConfig | 9 +- .../Singbox/CoreConfigSingboxService.cs | 286 ++------ .../Singbox/SingboxConfigTemplateService.cs | 22 +- .../CoreConfig/Singbox/SingboxDnsService.cs | 295 +++----- .../Singbox/SingboxInboundService.cs | 53 +- .../CoreConfig/Singbox/SingboxLogService.cs | 17 +- .../Singbox/SingboxOutboundService.cs | 688 ++++++------------ .../Singbox/SingboxRoutingService.cs | 133 ++-- .../Singbox/SingboxRulesetService.cs | 26 +- .../Singbox/SingboxStatisticService.cs | 16 +- .../V2ray/CoreConfigV2rayService.cs | 247 +------ .../CoreConfig/V2ray/V2rayBalancerService.cs | 47 +- .../V2ray/V2rayConfigTemplateService.cs | 32 +- .../CoreConfig/V2ray/V2rayDnsService.cs | 146 ++-- .../CoreConfig/V2ray/V2rayInboundService.cs | 30 +- .../CoreConfig/V2ray/V2rayLogService.cs | 18 +- .../CoreConfig/V2ray/V2rayOutboundService.cs | 589 +++++---------- .../CoreConfig/V2ray/V2rayRoutingService.cs | 120 +-- .../CoreConfig/V2ray/V2rayStatisticService.cs | 19 +- .../ViewModels/ProfilesViewModel.cs | 6 +- 28 files changed, 1084 insertions(+), 2023 deletions(-) create mode 100644 v2rayN/ServiceLib/Models/CoreConfigContext.cs diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index e502435f..c2893a34 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -88,7 +88,6 @@ public class Global public const string SingboxLocalDNSTag = "local_local"; public const string SingboxHostsDNSTag = "hosts_dns"; public const string SingboxFakeDNSTag = "fake_dns"; - public const string SingboxEchDNSTag = "ech_dns"; public const int Hysteria2DefaultHopInt = 10; diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 37176608..26619666 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1231,26 +1231,16 @@ public static class ConfigHandler /// Server node that might need pre-SOCKS /// Core type being used /// A SOCKS profile item or null if not needed - public static async Task GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType) + public static ProfileItem? GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType) { ProfileItem? itemSocks = null; if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun) { - var tun2SocksAddress = node.Address; - if (node.ConfigType.IsGroupType()) - { - var lstAddresses = (await GroupProfileManager.GetAllChildDomainAddresses(node)).ToList(); - if (lstAddresses.Count > 0) - { - tun2SocksAddress = Utils.List2String(lstAddresses); - } - } itemSocks = new ProfileItem() { CoreType = ECoreType.sing_box, ConfigType = EConfigType.SOCKS, Address = Global.Loopback, - SpiderX = tun2SocksAddress, // Tun2SocksAddress Port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks) }; } @@ -1265,7 +1255,6 @@ public static class ConfigHandler Port = node.PreSocksPort.Value, }; } - await Task.CompletedTask; return itemSocks; } diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs index f51e2051..432e9319 100644 --- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs @@ -7,27 +7,28 @@ public static class CoreConfigHandler { private static readonly string _tag = "CoreConfigHandler"; - public static async Task GenerateClientConfig(ProfileItem node, string? fileName) + public static async Task GenerateClientConfig(CoreConfigContext context, string? fileName) { var config = AppManager.Instance.Config; var result = new RetResult(); + var node = context.Node; if (node.ConfigType == EConfigType.Custom) { result = node.CoreType switch { ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName), - ECoreType.sing_box => await new CoreConfigSingboxService(config).GenerateClientCustomConfig(node, fileName), + ECoreType.sing_box => await new CoreConfigSingboxService(context).GenerateClientCustomConfig(fileName), _ => await GenerateClientCustomConfig(node, fileName) }; } else if (AppManager.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box) { - result = await new CoreConfigSingboxService(config).GenerateClientConfigContent(node); + result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); } else { - result = await new CoreConfigV2rayService(config).GenerateClientConfigContent(node); + result = new CoreConfigV2rayService(context).GenerateClientConfigContent(); } if (result.Success != true) { @@ -93,13 +94,22 @@ public static class CoreConfigHandler public static async Task GenerateClientSpeedtestConfig(Config config, string fileName, List selecteds, ECoreType coreType) { var result = new RetResult(); + var context = await BuildCoreConfigContext(config, new()); + foreach (var serverTestItem in selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty())) + { + var node = await AppManager.Instance.GetProfileItem(serverTestItem.IndexId!); + if (node != null) + { + await FillNodeContext(context, node, false); + } + } if (coreType == ECoreType.sing_box) { - result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(selecteds); + result = new CoreConfigSingboxService(context).GenerateClientSpeedtestConfig(selecteds); } else if (coreType == ECoreType.Xray) { - result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(selecteds); + result = new CoreConfigV2rayService(context).GenerateClientSpeedtestConfig(selecteds); } if (result.Success != true) { @@ -109,20 +119,21 @@ public static class CoreConfigHandler return result; } - public static async Task GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName) + public static async Task GenerateClientSpeedtestConfig(Config config, CoreConfigContext context, ServerTestItem testItem, string fileName) { var result = new RetResult(); + var node = context.Node; var initPort = AppManager.Instance.GetLocalPort(EInboundProtocol.speedtest); var port = Utils.GetFreePort(initPort + testItem.QueueNum); testItem.Port = port; if (AppManager.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box) { - result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port); + result = new CoreConfigSingboxService(context).GenerateClientSpeedtestConfig(port); } else { - result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port); + result = new CoreConfigV2rayService(context).GenerateClientSpeedtestConfig(port); } if (result.Success != true) { @@ -132,4 +143,120 @@ public static class CoreConfigHandler await File.WriteAllTextAsync(fileName, result.Data.ToString()); return result; } + + public static async Task BuildCoreConfigContext(Config config, ProfileItem node) + { + var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box ? ECoreType.sing_box : ECoreType.Xray; + var context = new CoreConfigContext() + { + Node = node, + AllProxiesMap = [], + AppConfig = config, + FullConfigTemplate = await AppManager.Instance.GetFullConfigTemplateItem(coreType), + IsTunEnabled = config.TunModeItem.EnableTun, + SimpleDnsItem = config.SimpleDNSItem, + ProtectDomainList = [], + ProtectSocksPort = 0, + RawDnsItem = await AppManager.Instance.GetDNSItem(coreType), + RoutingItem = await ConfigHandler.GetDefaultRouting(config), + }; + context = context with + { + Node = await FillNodeContext(context, node) + }; + if (!(context.RoutingItem?.RuleSet.IsNullOrEmpty() ?? true)) + { + var rules = JsonUtils.Deserialize>(context.RoutingItem?.RuleSet); + foreach (var ruleItem in rules.Where(ruleItem => !Global.OutboundTags.Contains(ruleItem.OutboundTag))) + { + var ruleOutboundNode = await AppManager.Instance.GetProfileItemViaRemarks(ruleItem.OutboundTag); + if (ruleOutboundNode != null) + { + await FillNodeContext(context, ruleOutboundNode); + } + } + } + return context; + } + + private static async Task FillNodeContext(CoreConfigContext context, ProfileItem node, bool includeSubChain = true) + { + if (node.IndexId.IsNullOrEmpty()) + { + return node; + } + context.AllProxiesMap[node.IndexId] = node; + if (node.ConfigType.IsGroupType()) + { + var groupChildList = await GroupProfileManager.GetAllChildProfileItems(node); + foreach (var childItem in groupChildList) + { + context.AllProxiesMap[childItem.IndexId] = childItem; + } + } + + foreach (var profileItemPair in context.AllProxiesMap) + { + var address = profileItemPair.Value.Address; + if (Utils.IsDomain(address)) + { + context.ProtectDomainList.Add(address); + } + + if (profileItemPair.Value.EchConfigList.IsNullOrEmpty()) + { + continue; + } + + var echQuerySni = profileItemPair.Value.Sni; + if (profileItemPair.Value.StreamSecurity == Global.StreamSecurity + && profileItemPair.Value.EchConfigList?.Contains("://") == true) + { + var idx = profileItemPair.Value.EchConfigList.IndexOf('+'); + echQuerySni = idx > 0 ? profileItemPair.Value.EchConfigList[..idx] : profileItemPair.Value.Sni; + } + if (!Utils.IsDomain(echQuerySni)) + { + continue; + } + context.ProtectDomainList.Add(echQuerySni); + } + + if (!includeSubChain || node.Subid.IsNullOrEmpty()) + { + return node; + } + + var subItem = await AppManager.Instance.GetSubItem(node.Subid); + if (subItem == null) + { + return node; + } + var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); + var nextNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.NextProfile); + if (prevNode is null && nextNode is null) + { + return node; + } + + var prevNodeAct = prevNode is null ? null : await FillNodeContext(context, prevNode, false); + var nextNodeAct = nextNode is null ? null : await FillNodeContext(context, nextNode, false); + + // Build new proxy chain node + var chainNode = new ProfileItem() + { + IndexId = $"inner-{Utils.GetGuid(false)}", + ConfigType = EConfigType.ProxyChain, + CoreType = node.CoreType ?? ECoreType.Xray, + }; + List childItems = [prevNodeAct?.IndexId, node.IndexId, nextNodeAct?.IndexId]; + var chainExtraItem = chainNode.GetProtocolExtra() with + { + GroupType = chainNode.ConfigType.ToString(), + ChildItems = string.Join(",", childItems.Where(x => !x.IsNullOrEmpty())), + }; + chainNode.SetProtocolExtra(chainExtraItem); + context.AllProxiesMap[chainNode.IndexId] = chainNode; + return chainNode; + } } diff --git a/v2rayN/ServiceLib/Manager/CoreManager.cs b/v2rayN/ServiceLib/Manager/CoreManager.cs index 53240960..86934c45 100644 --- a/v2rayN/ServiceLib/Manager/CoreManager.cs +++ b/v2rayN/ServiceLib/Manager/CoreManager.cs @@ -66,7 +66,9 @@ public class CoreManager } var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName); - var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); + var context = await CoreConfigHandler.BuildCoreConfigContext(_config, node); + context = context with { IsTunEnabled = _config.TunModeItem.EnableTun }; + var result = await CoreConfigHandler.GenerateClientConfig(context, fileName); if (result.Success != true) { await UpdateFunc(true, result.Msg); @@ -85,8 +87,8 @@ public class CoreManager await WindowsUtils.RemoveTunDevice(); } - await CoreStart(node); - await CoreStartPreService(node); + await CoreStart(context); + await CoreStartPreService(context); if (_processService != null) { await UpdateFunc(true, $"{node.GetSummary()}"); @@ -122,7 +124,8 @@ public class CoreManager var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false)); var configPath = Utils.GetBinConfigPath(fileName); - var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath); + var context = await CoreConfigHandler.BuildCoreConfigContext(_config, node); + var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, context, testItem, configPath); if (result.Success != true) { return null; @@ -165,8 +168,9 @@ public class CoreManager #region Private - private async Task CoreStart(ProfileItem node) + private async Task CoreStart(CoreConfigContext context) { + var node = context.Node; var coreType = AppManager.Instance.RunningCoreType = AppManager.Instance.GetCoreType(node, node.ConfigType); var coreInfo = CoreInfoManager.Instance.GetCoreInfo(coreType); @@ -179,17 +183,20 @@ public class CoreManager _processService = proc; } - private async Task CoreStartPreService(ProfileItem node) + private async Task CoreStartPreService(CoreConfigContext context) { + var node = context.Node; if (_processService != null && !_processService.HasExited) { var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType); - var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType); + var itemSocks = ConfigHandler.GetPreSocksItem(_config, node, coreType); if (itemSocks != null) { var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box; var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName); - var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName); + var itemSocksContext = await CoreConfigHandler.BuildCoreConfigContext(_config, itemSocks); + itemSocksContext.ProtectDomainList.AddRangeSafe(context.ProtectDomainList); + var result = await CoreConfigHandler.GenerateClientConfig(itemSocksContext, fileName); if (result.Success) { var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType); diff --git a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs index 53ef0429..afd97f81 100644 --- a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs +++ b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs @@ -126,24 +126,38 @@ public class GroupProfileManager .ToList() ?? new(); } + public static async Task> GetAllChildProfileItems(ProfileItem profileItem) + { + var allChildItems = new List(); + var visited = new HashSet(); + + await CollectChildItems(profileItem, allChildItems, visited); + + return allChildItems; + } + + private static async Task CollectChildItems(ProfileItem profileItem, List allChildItems, HashSet visited) + { + var (childItems, _) = await GetChildProfileItems(profileItem); + foreach (var child in childItems.Where(child => visited.Add(child.IndexId))) + { + allChildItems.Add(child); + + if (child.ConfigType.IsGroupType()) + { + await CollectChildItems(child, allChildItems, visited); + } + } + } + + public static async Task> GetAllChildDomainAddresses(ProfileItem profileItem) { var childAddresses = new HashSet(); - var (childItems, _) = await GetChildProfileItems(profileItem); - foreach (var child in childItems) + var childItems = await GetAllChildProfileItems(profileItem); + foreach (var child in childItems.Where(child => !child.Address.IsNullOrEmpty()).Where(child => Utils.IsDomain(child.Address))) { - if (!child.IsComplex()) - { - childAddresses.Add(child.Address); - } - else if (child.ConfigType.IsGroupType()) - { - var subAddresses = await GetAllChildDomainAddresses(child); - foreach (var addr in subAddresses) - { - childAddresses.Add(addr); - } - } + childAddresses.Add(child.Address); } return childAddresses; } @@ -151,30 +165,21 @@ public class GroupProfileManager public static async Task> GetAllChildEchQuerySni(ProfileItem profileItem) { var childAddresses = new HashSet(); - var (childItems, _) = await GetChildProfileItems(profileItem); - foreach (var childNode in childItems) + var childItems = await GetAllChildProfileItems(profileItem); + foreach (var childNode in childItems.Where(childNode => !childNode.EchConfigList.IsNullOrEmpty())) { - if (!childNode.IsComplex() && !childNode.EchConfigList.IsNullOrEmpty()) + var sni = childNode.Sni; + if (childNode.StreamSecurity == Global.StreamSecurity + && childNode.EchConfigList?.Contains("://") == true) { - if (childNode.StreamSecurity == Global.StreamSecurity - && childNode.EchConfigList?.Contains("://") == true) - { - var idx = childNode.EchConfigList.IndexOf('+'); - childAddresses.Add(idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni); - } - else - { - childAddresses.Add(childNode.Sni); - } + var idx = childNode.EchConfigList.IndexOf('+'); + sni = idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni; } - else if (childNode.ConfigType.IsGroupType()) + if (!Utils.IsDomain(sni)) { - var subAddresses = await GetAllChildDomainAddresses(childNode); - foreach (var addr in subAddresses) - { - childAddresses.Add(addr); - } + continue; } + childAddresses.Add(sni); } return childAddresses; } diff --git a/v2rayN/ServiceLib/Models/CoreConfigContext.cs b/v2rayN/ServiceLib/Models/CoreConfigContext.cs new file mode 100644 index 00000000..9551d39d --- /dev/null +++ b/v2rayN/ServiceLib/Models/CoreConfigContext.cs @@ -0,0 +1,17 @@ +namespace ServiceLib.Models; + +public record CoreConfigContext +{ + public required ProfileItem Node { get; init; } + public RoutingItem? RoutingItem { get; init; } + public DNSItem? RawDnsItem { get; init; } + public SimpleDNSItem SimpleDnsItem { get; init; } = new(); + public Dictionary AllProxiesMap { get; init; } = new(); + public Config AppConfig { get; init; } = new(); + public FullConfigTemplateItem? FullConfigTemplate { get; init; } = new(); + + // TUN Compatibility + public bool IsTunEnabled { get; init; } = false; + public HashSet ProtectDomainList { get; init; } = new(); + public int ProtectSocksPort { get; init; } = 0; +} diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index c0cd2e08..0d0e3009 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -254,14 +254,6 @@ public class Server4Sbox : BaseServer4Sbox // public List? path { get; set; } // hosts public Dictionary>? predefined { get; set; } - - // Deprecated - public string? address { get; set; } - - public string? address_resolver { get; set; } - public string? address_strategy { get; set; } - public string? strategy { get; set; } - // Deprecated End } public class Experimental4Sbox diff --git a/v2rayN/ServiceLib/Sample/SampleClientConfig b/v2rayN/ServiceLib/Sample/SampleClientConfig index 407a1307..b4ebf491 100644 --- a/v2rayN/ServiceLib/Sample/SampleClientConfig +++ b/v2rayN/ServiceLib/Sample/SampleClientConfig @@ -1,4 +1,4 @@ -{ +{ "log": { "access": "Vaccess.log", "error": "Verror.log", @@ -6,34 +6,6 @@ }, "inbounds": [], "outbounds": [ - { - "tag": "proxy", - "protocol": "vmess", - "settings": { - "vnext": [{ - "address": "", - "port": 0, - "users": [{ - "id": "", - "security": "auto" - }] - }], - "servers": [{ - "address": "", - "method": "", - "ota": false, - "password": "", - "port": 0, - "level": 1 - }] - }, - "streamSettings": { - "network": "tcp" - }, - "mux": { - "enabled": false - } - }, { "protocol": "freedom", "tag": "direct" diff --git a/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig b/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig index b07fd72c..7ff36ec9 100644 --- a/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig +++ b/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig @@ -5,19 +5,12 @@ }, "inbounds": [], "outbounds": [ - { - "type": "vless", - "tag": "proxy", - "server": "", - "server_port": 443 - }, { "type": "direct", "tag": "direct" } ], "route": { - "rules": [ - ] + "rules": [] } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs index 397e9340..0653e98e 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs @@ -1,17 +1,19 @@ namespace ServiceLib.Services.CoreConfig; -public partial class CoreConfigSingboxService(Config config) +public partial class CoreConfigSingboxService(CoreConfigContext context) { - private readonly Config _config = config; private static readonly string _tag = "CoreConfigSingboxService"; + private SingboxConfig _coreConfig = new(); + #region public gen function - public async Task GenerateClientConfigContent(ProfileItem node) + public RetResult GenerateClientConfigContent() { var ret = new RetResult(); try { + var node = context.Node; if (node == null || !node.IsValid()) { @@ -26,18 +28,6 @@ public partial class CoreConfigSingboxService(Config config) ret.Msg = ResUI.InitialConfiguration; - if (node.ConfigType.IsGroupType()) - { - switch (node.ConfigType) - { - case EConfigType.PolicyGroup: - return await GenerateClientMultipleLoadConfig(node); - - case EConfigType.ProxyChain: - return await GenerateClientChainConfig(node); - } - } - var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient); if (result.IsNullOrEmpty()) { @@ -45,44 +35,31 @@ public partial class CoreConfigSingboxService(Config config) return ret; } - var singboxConfig = JsonUtils.Deserialize(result); - if (singboxConfig == null) + _coreConfig = JsonUtils.Deserialize(result); + if (_coreConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; } - await GenLog(singboxConfig); + GenLog(); - await GenInbounds(singboxConfig); + GenInbounds(); - if (node.ConfigType == EConfigType.WireGuard) - { - singboxConfig.outbounds.RemoveAt(0); - var endpoints = new Endpoints4Sbox(); - await GenEndpoint(node, endpoints); - endpoints.tag = Global.ProxyTag; - singboxConfig.endpoints = new() { endpoints }; - } - else - { - await GenOutbound(node, singboxConfig.outbounds.First()); - } + GenOutbounds(); - await GenMoreOutbounds(node, singboxConfig); + GenRouting(); - await GenRouting(singboxConfig); + GenDns(); - await GenDns(node, singboxConfig); + GenExperimental(); - await GenExperimental(singboxConfig); - - await ConvertGeo2Ruleset(singboxConfig); + ConvertGeo2Ruleset(); ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Success = true; - ret.Data = await ApplyFullConfigTemplate(singboxConfig); + ret.Data = ApplyFullConfigTemplate(); return ret; } catch (Exception ex) @@ -93,17 +70,11 @@ public partial class CoreConfigSingboxService(Config config) } } - public async Task GenerateClientSpeedtestConfig(List selecteds) + public RetResult GenerateClientSpeedtestConfig(List selecteds) { var ret = new RetResult(); try { - if (_config == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - ret.Msg = ResUI.InitialConfiguration; var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient); @@ -114,8 +85,8 @@ public partial class CoreConfigSingboxService(Config config) return ret; } - var singboxConfig = JsonUtils.Deserialize(result); - if (singboxConfig == null) + _coreConfig = JsonUtils.Deserialize(result); + if (_coreConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; @@ -133,10 +104,10 @@ public partial class CoreConfigSingboxService(Config config) Logging.SaveLog(_tag, ex); } - await GenLog(singboxConfig); - //GenDns(new(), singboxConfig); - singboxConfig.inbounds.Clear(); - singboxConfig.outbounds.RemoveAt(0); + GenLog(); + GenMinimizedDns(); + _coreConfig.inbounds.Clear(); + _coreConfig.outbounds.RemoveAt(0); var initPort = AppManager.Instance.GetLocalPort(EInboundProtocol.speedtest); @@ -150,7 +121,7 @@ public partial class CoreConfigSingboxService(Config config) { continue; } - var item = await AppManager.Instance.GetProfileItem(it.IndexId); + var item = context.AllProxiesMap.GetValueOrDefault(it.IndexId); if (item is null || item.IsComplex() || !item.IsValid()) { continue; @@ -190,26 +161,11 @@ public partial class CoreConfigSingboxService(Config config) type = EInboundProtocol.mixed.ToString(), }; inbound.tag = inbound.type + inbound.listen_port.ToString(); - singboxConfig.inbounds.Add(inbound); + _coreConfig.inbounds.Add(inbound); - //outbound - var server = await GenServer(item); - if (server is null) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } var tag = Global.ProxyTag + inbound.listen_port.ToString(); - server.tag = tag; - if (server is Endpoints4Sbox endpoint) - { - singboxConfig.endpoints ??= new(); - singboxConfig.endpoints.Add(endpoint); - } - else if (server is Outbound4Sbox outbound) - { - singboxConfig.outbounds.Add(outbound); - } + var serverList = new CoreConfigSingboxService(context with { Node = item }).BuildAllProxyOutbounds(tag); + FillRangeProxy(serverList, _coreConfig, false); //rule Rule4Sbox rule = new() @@ -217,25 +173,11 @@ public partial class CoreConfigSingboxService(Config config) inbound = new List { inbound.tag }, outbound = tag }; - singboxConfig.route.rules.Add(rule); + _coreConfig.route.rules.Add(rule); } - var rawDNSItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); - if (rawDNSItem != null && rawDNSItem.Enabled == true) - { - await GenDnsDomainsCompatible(singboxConfig, rawDNSItem); - } - else - { - await GenDnsDomains(singboxConfig, _config.SimpleDNSItem); - } - singboxConfig.route.default_domain_resolver = new() - { - server = Global.SingboxLocalDNSTag, - }; - ret.Success = true; - ret.Data = JsonUtils.Serialize(singboxConfig); + ret.Data = JsonUtils.Serialize(_coreConfig); return ret; } catch (Exception ex) @@ -246,11 +188,12 @@ public partial class CoreConfigSingboxService(Config config) } } - public async Task GenerateClientSpeedtestConfig(ProfileItem node, int port) + public RetResult GenerateClientSpeedtestConfig(int port) { var ret = new RetResult(); try { + var node = context.Node; if (node == null || !node.IsValid()) { @@ -272,44 +215,20 @@ public partial class CoreConfigSingboxService(Config config) return ret; } - var singboxConfig = JsonUtils.Deserialize(result); - if (singboxConfig == null) + _coreConfig = JsonUtils.Deserialize(result); + if (_coreConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; } - await GenLog(singboxConfig); - if (node.ConfigType == EConfigType.WireGuard) - { - singboxConfig.outbounds.RemoveAt(0); - var endpoints = new Endpoints4Sbox(); - await GenEndpoint(node, endpoints); - endpoints.tag = Global.ProxyTag; - singboxConfig.endpoints = new() { endpoints }; - } - else - { - await GenOutbound(node, singboxConfig.outbounds.First()); - } - await GenMoreOutbounds(node, singboxConfig); - var item = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); - if (item != null && item.Enabled == true) - { - await GenDnsDomainsCompatible(singboxConfig, item); - } - else - { - await GenDnsDomains(singboxConfig, _config.SimpleDNSItem); - } - singboxConfig.route.default_domain_resolver = new() - { - server = Global.SingboxLocalDNSTag, - }; + GenLog(); + GenOutbounds(); + GenMinimizedDns(); - singboxConfig.route.rules.Clear(); - singboxConfig.inbounds.Clear(); - singboxConfig.inbounds.Add(new() + _coreConfig.route.rules.Clear(); + _coreConfig.inbounds.Clear(); + _coreConfig.inbounds.Add(new() { tag = $"{EInboundProtocol.mixed}{port}", listen = Global.Loopback, @@ -319,7 +238,7 @@ public partial class CoreConfigSingboxService(Config config) ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Success = true; - ret.Data = JsonUtils.Serialize(singboxConfig); + ret.Data = JsonUtils.Serialize(_coreConfig); return ret; } catch (Exception ex) @@ -330,123 +249,10 @@ public partial class CoreConfigSingboxService(Config config) } } - public async Task GenerateClientMultipleLoadConfig(ProfileItem parentNode) - { - var ret = new RetResult(); - try - { - if (_config == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - ret.Msg = ResUI.InitialConfiguration; - - var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient); - var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty()) - { - ret.Msg = ResUI.FailedGetDefaultConfiguration; - return ret; - } - - var singboxConfig = JsonUtils.Deserialize(result); - if (singboxConfig == null) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - singboxConfig.outbounds.RemoveAt(0); - - await GenLog(singboxConfig); - await GenInbounds(singboxConfig); - - var groupRet = await GenGroupOutbound(parentNode, singboxConfig); - if (groupRet != 0) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - - await GenRouting(singboxConfig); - await GenExperimental(singboxConfig); - await GenDns(parentNode, singboxConfig); - await ConvertGeo2Ruleset(singboxConfig); - - ret.Success = true; - - ret.Data = await ApplyFullConfigTemplate(singboxConfig); - return ret; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - } - - public async Task GenerateClientChainConfig(ProfileItem parentNode) - { - var ret = new RetResult(); - try - { - if (_config == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - ret.Msg = ResUI.InitialConfiguration; - - var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient); - var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty()) - { - ret.Msg = ResUI.FailedGetDefaultConfiguration; - return ret; - } - - var singboxConfig = JsonUtils.Deserialize(result); - if (singboxConfig == null) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - singboxConfig.outbounds.RemoveAt(0); - - await GenLog(singboxConfig); - await GenInbounds(singboxConfig); - - var groupRet = await GenGroupOutbound(parentNode, singboxConfig); - if (groupRet != 0) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - - await GenRouting(singboxConfig); - await GenExperimental(singboxConfig); - await GenDns(parentNode, singboxConfig); - await ConvertGeo2Ruleset(singboxConfig); - - ret.Success = true; - - ret.Data = await ApplyFullConfigTemplate(singboxConfig); - return ret; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - } - - public async Task GenerateClientCustomConfig(ProfileItem node, string? fileName) + public async Task GenerateClientCustomConfig(string? fileName) { var ret = new RetResult(); + var node = context.Node; if (node == null || fileName is null) { ret.Msg = ResUI.CheckServerSettings; @@ -487,17 +293,17 @@ public partial class CoreConfigSingboxService(Config config) if (node.Address == Global.CoreMultipleLoadConfigFileName) { var txtFile = File.ReadAllText(addressFileName); - var singboxConfig = JsonUtils.Deserialize(txtFile); - if (singboxConfig == null) + _coreConfig = JsonUtils.Deserialize(txtFile); + if (_coreConfig == null) { File.Copy(addressFileName, fileName); } else { - await GenInbounds(singboxConfig); - await GenExperimental(singboxConfig); + GenInbounds(); + GenExperimental(); - var content = JsonUtils.Serialize(singboxConfig, true); + var content = JsonUtils.Serialize(_coreConfig, true); await File.WriteAllTextAsync(fileName, content); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs index 6fe9b35a..7dd54b1f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs @@ -2,29 +2,29 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task ApplyFullConfigTemplate(SingboxConfig singboxConfig) + private string ApplyFullConfigTemplate() { - var fullConfigTemplate = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.sing_box); - if (fullConfigTemplate == null || !fullConfigTemplate.Enabled) + var fullConfigTemplate = context.FullConfigTemplate; + if (fullConfigTemplate is not { Enabled: true }) { - return JsonUtils.Serialize(singboxConfig); + return JsonUtils.Serialize(_coreConfig); } - var fullConfigTemplateItem = _config.TunModeItem.EnableTun ? fullConfigTemplate.TunConfig : fullConfigTemplate.Config; + var fullConfigTemplateItem = context.IsTunEnabled ? fullConfigTemplate.TunConfig : fullConfigTemplate.Config; if (fullConfigTemplateItem.IsNullOrEmpty()) { - return JsonUtils.Serialize(singboxConfig); + return JsonUtils.Serialize(_coreConfig); } var fullConfigTemplateNode = JsonNode.Parse(fullConfigTemplateItem); if (fullConfigTemplateNode == null) { - return JsonUtils.Serialize(singboxConfig); + return JsonUtils.Serialize(_coreConfig); } // Process outbounds var customOutboundsNode = fullConfigTemplateNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray(); - foreach (var outbound in singboxConfig.outbounds) + foreach (var outbound in _coreConfig.outbounds) { if (outbound.type.ToLower() is "direct" or "block") { @@ -42,10 +42,10 @@ public partial class CoreConfigSingboxService fullConfigTemplateNode["outbounds"] = customOutboundsNode; // Process endpoints - if (singboxConfig.endpoints != null && singboxConfig.endpoints.Count > 0) + if (_coreConfig.endpoints != null && _coreConfig.endpoints.Count > 0) { var customEndpointsNode = fullConfigTemplateNode["endpoints"] is JsonArray endpoints ? endpoints : new JsonArray(); - foreach (var endpoint in singboxConfig.endpoints) + foreach (var endpoint in _coreConfig.endpoints) { if (endpoint.detour.IsNullOrEmpty() && !fullConfigTemplate.ProxyDetour.IsNullOrEmpty()) { @@ -56,6 +56,6 @@ public partial class CoreConfigSingboxService fullConfigTemplateNode["endpoints"] = customEndpointsNode; } - return await Task.FromResult(JsonUtils.Serialize(fullConfigTemplateNode)); + return JsonUtils.Serialize(fullConfigTemplateNode); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index 84df7538..dfce64f5 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -2,25 +2,25 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenDns(ProfileItem? node, SingboxConfig singboxConfig) + private void GenDns() { try { - var item = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); - if (item != null && item.Enabled == true) + var item = context.RawDnsItem; + if (item is { Enabled: true }) { - return await GenDnsCompatible(node, singboxConfig); + GenDnsCustom(); + return; } - var simpleDNSItem = _config.SimpleDNSItem; - await GenDnsServers(node, singboxConfig, simpleDNSItem); - await GenDnsRules(node, singboxConfig, simpleDNSItem); + GenDnsServers(); + GenDnsRules(); - singboxConfig.dns ??= new Dns4Sbox(); - singboxConfig.dns.independent_cache = true; + _coreConfig.dns ??= new Dns4Sbox(); + _coreConfig.dns.independent_cache = true; // final dns - var routing = await ConfigHandler.GetDefaultRouting(_config); + var routing = context.RoutingItem; var useDirectDns = false; if (routing != null) { @@ -32,35 +32,34 @@ public partial class CoreConfigSingboxService lastRule.Network == "tcp,udp" || lastRule.Ip?.Contains("0.0.0.0/0") == true); } - singboxConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag; - if ((!useDirectDns) && simpleDNSItem.FakeIP == true && simpleDNSItem.GlobalFakeIp == false) + _coreConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag; + var simpleDnsItem = context.SimpleDnsItem; + if ((!useDirectDns) && simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp == false) { - singboxConfig.dns.rules.Add(new() + _coreConfig.dns.rules.Add(new() { server = Global.SingboxFakeDNSTag, query_type = new List { 1, 28 }, // A and AAAA rewrite_ttl = 1, }); } - - await GenOutboundDnsRule(node, singboxConfig); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenDnsServers(ProfileItem? node, SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem) + private void GenDnsServers() { - var finalDns = await GenDnsDomains(singboxConfig, simpleDNSItem); + var simpleDnsItem = context.SimpleDnsItem; + var finalDns = GenBootstrapDns(); - var directDns = ParseDnsAddress(simpleDNSItem.DirectDNS); + var directDns = ParseDnsAddress(simpleDnsItem.DirectDNS ?? Global.DomainDirectDNSAddress.First()); directDns.tag = Global.SingboxDirectDNSTag; directDns.domain_resolver = Global.SingboxLocalDNSTag; - var remoteDns = ParseDnsAddress(simpleDNSItem.RemoteDNS); + var remoteDns = ParseDnsAddress(simpleDnsItem.RemoteDNS ?? Global.DomainRemoteDNSAddress.First()); remoteDns.tag = Global.SingboxRemoteDNSTag; remoteDns.detour = Global.ProxyTag; remoteDns.domain_resolver = Global.SingboxLocalDNSTag; @@ -71,12 +70,12 @@ public partial class CoreConfigSingboxService type = "hosts", predefined = new(), }; - if (simpleDNSItem.AddCommonHosts == true) + if (simpleDnsItem.AddCommonHosts == true) { hostsDns.predefined = Global.PredefinedHosts; } - if (simpleDNSItem.UseSystemHosts == true) + if (simpleDnsItem.UseSystemHosts == true) { var systemHosts = Utils.GetSystemHosts(); if (systemHosts != null && systemHosts.Count > 0) @@ -88,9 +87,9 @@ public partial class CoreConfigSingboxService } } - foreach (var kvp in Utils.ParseHostsToDictionary(simpleDNSItem.Hosts)) + foreach (var kvp in Utils.ParseHostsToDictionary(simpleDnsItem.Hosts)) { - hostsDns.predefined[kvp.Key] = kvp.Value.Where(s => Utils.IsIpAddress(s)).ToList(); + hostsDns.predefined[kvp.Key] = kvp.Value.Where(Utils.IsIpAddress).ToList(); } foreach (var host in hostsDns.predefined) @@ -109,14 +108,14 @@ public partial class CoreConfigSingboxService } } - singboxConfig.dns ??= new Dns4Sbox(); - singboxConfig.dns.servers ??= []; - singboxConfig.dns.servers.Add(remoteDns); - singboxConfig.dns.servers.Add(directDns); - singboxConfig.dns.servers.Add(hostsDns); + _coreConfig.dns ??= new Dns4Sbox(); + _coreConfig.dns.servers ??= []; + _coreConfig.dns.servers.Add(remoteDns); + _coreConfig.dns.servers.Add(directDns); + _coreConfig.dns.servers.Add(hostsDns); // fake ip - if (simpleDNSItem.FakeIP == true) + if (simpleDnsItem.FakeIP == true) { var fakeip = new Server4Sbox { @@ -125,68 +124,50 @@ public partial class CoreConfigSingboxService inet4_range = "198.18.0.0/15", inet6_range = "fc00::/18", }; - singboxConfig.dns.servers.Add(fakeip); + _coreConfig.dns.servers.Add(fakeip); } - - // ech - var (_, dnsServer) = ParseEchParam(node?.EchConfigList); - if (dnsServer is not null) - { - dnsServer.tag = Global.SingboxEchDNSTag; - if (dnsServer.server is not null - && hostsDns.predefined.ContainsKey(dnsServer.server)) - { - dnsServer.domain_resolver = Global.SingboxHostsDNSTag; - } - else - { - dnsServer.domain_resolver = Global.SingboxLocalDNSTag; - } - singboxConfig.dns.servers.Add(dnsServer); - } - else if (node?.ConfigType.IsGroupType() == true) - { - var echDnsObject = JsonUtils.DeepCopy(directDns); - echDnsObject.tag = Global.SingboxEchDNSTag; - singboxConfig.dns.servers.Add(echDnsObject); - } - - return await Task.FromResult(0); } - private async Task GenDnsDomains(SingboxConfig singboxConfig, SimpleDNSItem? simpleDNSItem) + private Server4Sbox GenBootstrapDns() { - var finalDns = ParseDnsAddress(simpleDNSItem.BootstrapDNS); + var finalDns = ParseDnsAddress(context.SimpleDnsItem?.BootstrapDNS ?? Global.DomainPureIPDNSAddress.First()); finalDns.tag = Global.SingboxLocalDNSTag; - singboxConfig.dns ??= new Dns4Sbox(); - singboxConfig.dns.servers ??= new List(); - singboxConfig.dns.servers.Add(finalDns); - return await Task.FromResult(finalDns); + _coreConfig.dns ??= new Dns4Sbox(); + _coreConfig.dns.servers ??= []; + _coreConfig.dns.servers.Add(finalDns); + return finalDns; } - private async Task GenDnsRules(ProfileItem? node, SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem) + private void GenDnsRules() { - singboxConfig.dns ??= new Dns4Sbox(); - singboxConfig.dns.rules ??= new List(); + var simpleDnsItem = context.SimpleDnsItem; + _coreConfig.dns ??= new Dns4Sbox(); + _coreConfig.dns.rules ??= []; - singboxConfig.dns.rules.AddRange(new[] + _coreConfig.dns.rules.AddRange(new[] { new Rule4Sbox { ip_accept_any = true, server = Global.SingboxHostsDNSTag }, new Rule4Sbox + { + server = Global.SingboxDirectDNSTag, + strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom), + domain = context.ProtectDomainList.ToList(), + }, + new Rule4Sbox { server = Global.SingboxRemoteDNSTag, - strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Proxy), + strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Proxy), clash_mode = ERuleMode.Global.ToString() }, new Rule4Sbox { server = Global.SingboxDirectDNSTag, - strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Freedom), + strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom), clash_mode = ERuleMode.Direct.ToString() } }); - foreach (var kvp in Utils.ParseHostsToDictionary(simpleDNSItem.Hosts)) + foreach (var kvp in Utils.ParseHostsToDictionary(simpleDnsItem.Hosts)) { var predefined = kvp.Value.First(); if (predefined.IsNullOrEmpty() || Utils.IsIpAddress(predefined)) @@ -197,7 +178,7 @@ public partial class CoreConfigSingboxService { // xray syntactic sugar for predefined // etc. #0 -> NOERROR - singboxConfig.dns.rules.Add(new() + _coreConfig.dns.rules.Add(new() { query_type = [1, 28], domain = [kvp.Key], @@ -225,38 +206,13 @@ public partial class CoreConfigSingboxService }; if (ParseV2Domain(kvp.Key, rule)) { - singboxConfig.dns.rules.Add(rule); + _coreConfig.dns.rules.Add(rule); } } - var (ech, _) = ParseEchParam(node?.EchConfigList); - if (ech is not null) + if (simpleDnsItem.BlockBindingQuery == true) { - var echDomain = ech.query_server_name ?? node?.Sni; - singboxConfig.dns.rules.Add(new() - { - query_type = [64, 65], - server = Global.SingboxEchDNSTag, - domain = echDomain is not null ? new List { echDomain } : null, - }); - } - else if (node?.ConfigType.IsGroupType() == true) - { - var queryServerNames = (await GroupProfileManager.GetAllChildEchQuerySni(node)).ToList(); - if (queryServerNames.Count > 0) - { - singboxConfig.dns.rules.Add(new() - { - query_type = [64, 65], - server = Global.SingboxEchDNSTag, - domain = queryServerNames, - }); - } - } - - if (simpleDNSItem.BlockBindingQuery == true) - { - singboxConfig.dns.rules.Add(new() + _coreConfig.dns.rules.Add(new() { query_type = [64, 65], action = "predefined", @@ -264,7 +220,7 @@ public partial class CoreConfigSingboxService }); } - if (simpleDNSItem.FakeIP == true && simpleDNSItem.GlobalFakeIp == true) + if (simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp == true) { var fakeipFilterRule = JsonUtils.Deserialize(EmbedUtils.GetEmbedText(Global.SingboxFakeIPFilterFileName)); fakeipFilterRule.invert = true; @@ -284,13 +240,13 @@ public partial class CoreConfigSingboxService ] }; - singboxConfig.dns.rules.Add(rule4Fake); + _coreConfig.dns.rules.Add(rule4Fake); } - var routing = await ConfigHandler.GetDefaultRouting(_config); + var routing = context.RoutingItem; if (routing == null) { - return 0; + return; } var rules = JsonUtils.Deserialize>(routing.RuleSet) ?? []; @@ -298,9 +254,9 @@ public partial class CoreConfigSingboxService var expectedIPsRegions = new List(); var regionNames = new HashSet(); - if (!string.IsNullOrEmpty(simpleDNSItem?.DirectExpectedIPs)) + if (!string.IsNullOrEmpty(simpleDnsItem?.DirectExpectedIPs)) { - var ipItems = simpleDNSItem.DirectExpectedIPs + var ipItems = simpleDnsItem.DirectExpectedIPs .Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()) .Where(s => !string.IsNullOrEmpty(s)) @@ -348,7 +304,7 @@ public partial class CoreConfigSingboxService if (item.OutboundTag == Global.DirectTag) { rule.server = Global.SingboxDirectDNSTag; - rule.strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Freedom); + rule.strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0) { @@ -373,31 +329,41 @@ public partial class CoreConfigSingboxService } else { - if (simpleDNSItem.FakeIP == true && simpleDNSItem.GlobalFakeIp == false) + if (simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp == false) { var rule4Fake = JsonUtils.DeepCopy(rule); rule4Fake.server = Global.SingboxFakeDNSTag; rule4Fake.query_type = new List { 1, 28 }; // A and AAAA rule4Fake.rewrite_ttl = 1; - singboxConfig.dns.rules.Add(rule4Fake); + _coreConfig.dns.rules.Add(rule4Fake); } rule.server = Global.SingboxRemoteDNSTag; - rule.strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Proxy); + rule.strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Proxy); } - singboxConfig.dns.rules.Add(rule); + _coreConfig.dns.rules.Add(rule); } - - return 0; } - private async Task GenDnsCompatible(ProfileItem? node, SingboxConfig singboxConfig) + private void GenMinimizedDns() + { + GenDnsServers(); + _coreConfig.dns ??= new(); + _coreConfig.dns.rules.Clear(); + _coreConfig.dns.final = Global.SingboxDirectDNSTag; + _coreConfig.route.default_domain_resolver = new() + { + server = Global.SingboxDirectDNSTag, + }; + } + + private void GenDnsCustom() { try { - var item = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); + var item = context.RawDnsItem; var strDNS = string.Empty; - if (_config.TunModeItem.EnableTun) + if (context.IsTunEnabled) { strDNS = string.IsNullOrEmpty(item?.TunDNS) ? EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName) : item?.TunDNS; } @@ -409,31 +375,22 @@ public partial class CoreConfigSingboxService var dns4Sbox = JsonUtils.Deserialize(strDNS); if (dns4Sbox is null) { - return 0; + return; } - singboxConfig.dns = dns4Sbox; + _coreConfig.dns = dns4Sbox; - if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty()) - { - await GenDnsDomainsCompatible(singboxConfig, item); - } - else - { - await GenDnsDomainsLegacyCompatible(singboxConfig, item); - } - - await GenOutboundDnsRule(node, singboxConfig); + GenDnsProtectCustom(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenDnsDomainsCompatible(SingboxConfig singboxConfig, DNSItem? dnsItem) + private void GenDnsProtectCustom() { - var dns4Sbox = singboxConfig.dns ?? new(); + var dnsItem = context.RawDnsItem; + var dns4Sbox = _coreConfig.dns ?? new(); dns4Sbox.servers ??= []; dns4Sbox.rules ??= []; @@ -445,86 +402,18 @@ public partial class CoreConfigSingboxService localDnsServer.tag = tag; dns4Sbox.servers.Add(localDnsServer); + dns4Sbox.rules.Insert(0, BuildProtectDomainRule()); - singboxConfig.dns = dns4Sbox; - return await Task.FromResult(0); + _coreConfig.dns = dns4Sbox; } - private async Task GenDnsDomainsLegacyCompatible(SingboxConfig singboxConfig, DNSItem? dnsItem) + private Rule4Sbox BuildProtectDomainRule() { - var dns4Sbox = singboxConfig.dns ?? new(); - dns4Sbox.servers ??= []; - dns4Sbox.rules ??= []; - - var tag = Global.SingboxLocalDNSTag; - dns4Sbox.servers.Add(new() - { - tag = tag, - address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress, - detour = Global.DirectTag, - strategy = string.IsNullOrEmpty(dnsItem?.DomainStrategy4Freedom) ? null : dnsItem?.DomainStrategy4Freedom, - }); - dns4Sbox.rules.Insert(0, new() - { - server = tag, - clash_mode = ERuleMode.Direct.ToString() - }); - dns4Sbox.rules.Insert(0, new() - { - server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote", - clash_mode = ERuleMode.Global.ToString() - }); - - var lstDomain = singboxConfig.outbounds - .Where(t => t.server.IsNotEmpty() && Utils.IsDomain(t.server)) - .Select(t => t.server) - .Distinct() - .ToList(); - if (lstDomain != null && lstDomain.Count > 0) - { - dns4Sbox.rules.Insert(0, new() - { - server = tag, - domain = lstDomain - }); - } - - singboxConfig.dns = dns4Sbox; - return await Task.FromResult(0); - } - - private async Task GenOutboundDnsRule(ProfileItem? node, SingboxConfig singboxConfig) - { - if (node == null) - { - return 0; - } - - List domain = new(); - if (Utils.IsDomain(node.Address)) // normal outbound - { - domain.Add(node.Address); - } - if (node.Address == Global.Loopback && node.SpiderX.IsNotEmpty()) // Tun2SocksAddress - { - domain.AddRange(Utils.String2List(node.SpiderX) - .Where(Utils.IsDomain) - .Distinct() - .ToList()); - } - if (domain.Count == 0) - { - return 0; - } - - singboxConfig.dns.rules ??= new List(); - singboxConfig.dns.rules.Insert(0, new Rule4Sbox + return new() { server = Global.SingboxLocalDNSTag, - domain = domain, - }); - - return await Task.FromResult(0); + domain = context.ProtectDomainList.ToList(), + }; } private static Server4Sbox? ParseDnsAddress(string address) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs index 4e14c688..ba9c26e7 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs @@ -2,15 +2,15 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenInbounds(SingboxConfig singboxConfig) + private void GenInbounds() { try { var listen = "0.0.0.0"; - singboxConfig.inbounds = []; + _coreConfig.inbounds = []; - if (!_config.TunModeItem.EnableTun - || (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box)) + if (!context.AppConfig.TunModeItem.EnableTun + || (context.AppConfig.TunModeItem.EnableTun && context.AppConfig.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box)) { var inbound = new Inbound4Sbox() { @@ -18,28 +18,28 @@ public partial class CoreConfigSingboxService tag = EInboundProtocol.socks.ToString(), listen = Global.Loopback, }; - singboxConfig.inbounds.Add(inbound); + _coreConfig.inbounds.Add(inbound); inbound.listen_port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks); - if (_config.Inbound.First().SecondLocalPortEnabled) + if (context.AppConfig.Inbound.First().SecondLocalPortEnabled) { - var inbound2 = GetInbound(inbound, EInboundProtocol.socks2, true); - singboxConfig.inbounds.Add(inbound2); + var inbound2 = BuildInbound(inbound, EInboundProtocol.socks2, true); + _coreConfig.inbounds.Add(inbound2); } - if (_config.Inbound.First().AllowLANConn) + if (context.AppConfig.Inbound.First().AllowLANConn) { - if (_config.Inbound.First().NewPort4LAN) + if (context.AppConfig.Inbound.First().NewPort4LAN) { - var inbound3 = GetInbound(inbound, EInboundProtocol.socks3, true); + var inbound3 = BuildInbound(inbound, EInboundProtocol.socks3, true); inbound3.listen = listen; - singboxConfig.inbounds.Add(inbound3); + _coreConfig.inbounds.Add(inbound3); //auth - if (_config.Inbound.First().User.IsNotEmpty() && _config.Inbound.First().Pass.IsNotEmpty()) + if (context.AppConfig.Inbound.First().User.IsNotEmpty() && context.AppConfig.Inbound.First().Pass.IsNotEmpty()) { - inbound3.users = new() { new() { username = _config.Inbound.First().User, password = _config.Inbound.First().Pass } }; + inbound3.users = new() { new() { username = context.AppConfig.Inbound.First().User, password = context.AppConfig.Inbound.First().Pass } }; } } else @@ -49,39 +49,38 @@ public partial class CoreConfigSingboxService } } - if (_config.TunModeItem.EnableTun) + if (context.AppConfig.TunModeItem.EnableTun) { - if (_config.TunModeItem.Mtu <= 0) + if (context.AppConfig.TunModeItem.Mtu <= 0) { - _config.TunModeItem.Mtu = Global.TunMtus.First(); + context.AppConfig.TunModeItem.Mtu = Global.TunMtus.First(); } - if (_config.TunModeItem.Stack.IsNullOrEmpty()) + if (context.AppConfig.TunModeItem.Stack.IsNullOrEmpty()) { - _config.TunModeItem.Stack = Global.TunStacks.First(); + context.AppConfig.TunModeItem.Stack = Global.TunStacks.First(); } var tunInbound = JsonUtils.Deserialize(EmbedUtils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { }; tunInbound.interface_name = Utils.IsMacOS() ? $"utun{new Random().Next(99)}" : "singbox_tun"; - tunInbound.mtu = _config.TunModeItem.Mtu; - tunInbound.auto_route = _config.TunModeItem.AutoRoute; - tunInbound.strict_route = _config.TunModeItem.StrictRoute; - tunInbound.stack = _config.TunModeItem.Stack; - if (_config.TunModeItem.EnableIPv6Address == false) + tunInbound.mtu = context.AppConfig.TunModeItem.Mtu; + tunInbound.auto_route = context.AppConfig.TunModeItem.AutoRoute; + tunInbound.strict_route = context.AppConfig.TunModeItem.StrictRoute; + tunInbound.stack = context.AppConfig.TunModeItem.Stack; + if (context.AppConfig.TunModeItem.EnableIPv6Address == false) { tunInbound.address = ["172.18.0.1/30"]; } - singboxConfig.inbounds.Add(tunInbound); + _coreConfig.inbounds.Add(tunInbound); } } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private Inbound4Sbox GetInbound(Inbound4Sbox inItem, EInboundProtocol protocol, bool bSocks) + private Inbound4Sbox BuildInbound(Inbound4Sbox inItem, EInboundProtocol protocol, bool bSocks) { var inbound = JsonUtils.DeepCopy(inItem); inbound.tag = protocol.ToString(); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs index 59e65471..052b1cdf 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs @@ -2,39 +2,38 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenLog(SingboxConfig singboxConfig) + private void GenLog() { try { - switch (_config.CoreBasicItem.Loglevel) + switch (context.AppConfig.CoreBasicItem.Loglevel) { case "debug": case "info": case "error": - singboxConfig.log.level = _config.CoreBasicItem.Loglevel; + _coreConfig.log.level = context.AppConfig.CoreBasicItem.Loglevel; break; case "warning": - singboxConfig.log.level = "warn"; + _coreConfig.log.level = "warn"; break; default: break; } - if (_config.CoreBasicItem.Loglevel == Global.None) + if (context.AppConfig.CoreBasicItem.Loglevel == Global.None) { - singboxConfig.log.disabled = true; + _coreConfig.log.disabled = true; } - if (_config.CoreBasicItem.LogEnabled) + if (context.AppConfig.CoreBasicItem.LogEnabled) { var dtNow = DateTime.Now; - singboxConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt"); + _coreConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt"); } } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 178350b3..ad7b4ad6 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -2,10 +2,85 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenOutbound(ProfileItem node, Outbound4Sbox outbound) + private void GenOutbounds() + { + var proxyOutbounds = BuildAllProxyOutbounds(); + FillRangeProxy(proxyOutbounds, _coreConfig, true); + } + + private List BuildAllProxyOutbounds(string baseTagName = Global.ProxyTag, bool withSelector = true) + { + var proxyOutboundList = new List(); + if (!context.Node.ConfigType.IsComplexType()) + { + var outbound = BuildProxyOutbound(baseTagName); + proxyOutboundList.Add(outbound); + } + else + { + proxyOutboundList.AddRange(BuildGroupProxyOutbounds(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; + } + + private BaseServer4Sbox BuildProxyOutbound(string baseTagName = Global.ProxyTag) + { + var outbound = BuildProxyServer(); + outbound.tag = baseTagName; + return outbound; + } + + private List BuildGroupProxyOutbounds(string baseTagName = Global.ProxyTag) + { + var proxyOutboundList = new List(); + switch (context.Node.ConfigType) + { + case EConfigType.PolicyGroup: + proxyOutboundList = BuildOutboundsList(baseTagName); + break; + case EConfigType.ProxyChain: + proxyOutboundList = BuildChainOutboundsList(baseTagName); + break; + } + return proxyOutboundList; + } + + private BaseServer4Sbox BuildProxyServer() { try { + var node = context.Node; + var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); + if (node.ConfigType == EConfigType.WireGuard) + { + var endpoint = JsonUtils.Deserialize(txtOutbound); + FillEndpoint(endpoint); + return endpoint; + } + else + { + var outbound = JsonUtils.Deserialize(txtOutbound); + FillOutbound(outbound); + return outbound; + } + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + throw new InvalidOperationException(); + } + + private void FillOutbound(Outbound4Sbox outbound) + { + try + { + var node = context.Node; var protocolExtra = node.GetProtocolExtra(); outbound.server = node.Address; outbound.server_port = node.Port; @@ -26,8 +101,8 @@ public partial class CoreConfigSingboxService outbound.security = Global.DefaultSecurity; } - await GenOutboundMux(node, outbound); - await GenOutboundTransport(node, outbound); + FillOutboundMux(outbound); + FillOutboundTransport(outbound); break; } case EConfigType.Shadowsocks: @@ -84,7 +159,7 @@ public partial class CoreConfigSingboxService } } - await GenOutboundMux(node, outbound); + FillOutboundMux(outbound); break; } case EConfigType.SOCKS: @@ -120,18 +195,18 @@ public partial class CoreConfigSingboxService } else { - await GenOutboundMux(node, outbound); + FillOutboundMux(outbound); } - await GenOutboundTransport(node, outbound); + FillOutboundTransport(outbound); break; } case EConfigType.Trojan: { outbound.password = node.Password; - await GenOutboundMux(node, outbound); - await GenOutboundTransport(node, outbound); + FillOutboundMux(outbound); + FillOutboundTransport(outbound); break; } case EConfigType.Hysteria2: @@ -149,10 +224,10 @@ public partial class CoreConfigSingboxService outbound.up_mbps = protocolExtra?.UpMbps is { } su and >= 0 ? su - : _config.HysteriaItem.UpMbps; + : context.AppConfig.HysteriaItem.UpMbps; outbound.down_mbps = protocolExtra?.DownMbps is { } sd and >= 0 ? sd - : _config.HysteriaItem.DownMbps; + : context.AppConfig.HysteriaItem.DownMbps; var ports = protocolExtra?.Ports?.IsNullOrEmpty() == false ? protocolExtra.Ports : null; if ((!ports.IsNullOrEmpty()) && (ports.Contains(':') || ports.Contains('-') || ports.Contains(','))) { @@ -166,8 +241,8 @@ public partial class CoreConfigSingboxService return port.Contains(':') ? port : $"{port}:{port}"; }) .ToList(); - outbound.hop_interval = _config.HysteriaItem.HopInterval >= 5 - ? $"{_config.HysteriaItem.HopInterval}s" + outbound.hop_interval = context.AppConfig.HysteriaItem.HopInterval >= 5 + ? $"{context.AppConfig.HysteriaItem.HopInterval}s" : $"{Global.Hysteria2DefaultHopInt}s"; if (int.TryParse(protocolExtra.HopInterval, out var hiResult)) { @@ -202,19 +277,19 @@ public partial class CoreConfigSingboxService } } - await GenOutboundTls(node, outbound); + FillOutboundTls(outbound); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenEndpoint(ProfileItem node, Endpoints4Sbox endpoint) + private void FillEndpoint(Endpoints4Sbox endpoint) { try { + var node = context.Node; var protocolExtra = node.GetProtocolExtra(); endpoint.address = Utils.String2List(protocolExtra.WgInterfaceAddress); @@ -245,55 +320,22 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private async Task GenServer(ProfileItem node) + private void FillOutboundMux(Outbound4Sbox outbound) { try { - var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - if (node.ConfigType == EConfigType.WireGuard) - { - var endpoint = JsonUtils.Deserialize(txtOutbound); - var ret = await GenEndpoint(node, endpoint); - if (ret != 0) - { - return null; - } - return endpoint; - } - else - { - var outbound = JsonUtils.Deserialize(txtOutbound); - var ret = await GenOutbound(node, outbound); - if (ret != 0) - { - return null; - } - return outbound; - } - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - return await Task.FromResult(null); - } - - private async Task GenOutboundMux(ProfileItem node, Outbound4Sbox outbound) - { - try - { - var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; - if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty()) + var config = context.AppConfig; + var muxEnabled = context.Node.MuxEnabled ?? config.CoreBasicItem.MuxEnabled; + if (muxEnabled && config.Mux4SboxItem.Protocol.IsNotEmpty()) { var mux = new Multiplex4Sbox() { enabled = true, - protocol = _config.Mux4SboxItem.Protocol, - max_connections = _config.Mux4SboxItem.MaxConnections, - padding = _config.Mux4SboxItem.Padding, + protocol = config.Mux4SboxItem.Protocol, + max_connections = config.Mux4SboxItem.MaxConnections, + padding = config.Mux4SboxItem.Padding, }; outbound.multiplex = mux; } @@ -302,36 +344,36 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private async Task GenOutboundTls(ProfileItem node, Outbound4Sbox outbound) + private void FillOutboundTls(Outbound4Sbox outbound) { try { + var node = context.Node; if (node.StreamSecurity is not (Global.StreamSecurityReality or Global.StreamSecurity)) { - return await Task.FromResult(0); + return; } if (node.ConfigType is EConfigType.Shadowsocks or EConfigType.SOCKS or EConfigType.WireGuard) { - return await Task.FromResult(0); + return; } - var server_name = string.Empty; + var serverName = string.Empty; if (node.Sni.IsNotEmpty()) { - server_name = node.Sni; + serverName = node.Sni; } else if (node.RequestHost.IsNotEmpty()) { - server_name = Utils.String2List(node.RequestHost)?.First(); + serverName = Utils.String2List(node.RequestHost)?.First(); } var tls = new Tls4Sbox() { enabled = true, - record_fragment = _config.CoreBasicItem.EnableFragment ? true : null, - server_name = server_name, - insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), + record_fragment = context.AppConfig.CoreBasicItem.EnableFragment ? true : null, + server_name = serverName, + insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? context.AppConfig.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), alpn = node.GetAlpn(), }; if (node.Fingerprint.IsNotEmpty()) @@ -339,7 +381,7 @@ public partial class CoreConfigSingboxService tls.utls = new Utls4Sbox() { enabled = true, - fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint + fingerprint = node.Fingerprint.IsNullOrEmpty() ? context.AppConfig.CoreBasicItem.DefFingerprint : node.Fingerprint }; } if (node.StreamSecurity == Global.StreamSecurity) @@ -372,13 +414,13 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private async Task GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound) + private void FillOutboundTransport(Outbound4Sbox outbound) { try { + var node = context.Node; var transport = new Transport4Sbox(); switch (node.GetNetwork()) @@ -452,9 +494,9 @@ public partial class CoreConfigSingboxService case nameof(ETransport.grpc): transport.type = nameof(ETransport.grpc); transport.service_name = node.Path; - transport.idle_timeout = _config.GrpcItem.IdleTimeout?.ToString("##s"); - transport.ping_timeout = _config.GrpcItem.HealthCheckTimeout?.ToString("##s"); - transport.permit_without_stream = _config.GrpcItem.PermitWithoutStream; + transport.idle_timeout = context.AppConfig.GrpcItem.IdleTimeout?.ToString("##s"); + transport.ping_timeout = context.AppConfig.GrpcItem.HealthCheckTimeout?.ToString("##s"); + transport.permit_without_stream = context.AppConfig.GrpcItem.PermitWithoutStream; break; default: @@ -469,458 +511,145 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private async Task GenGroupOutbound(ProfileItem node, SingboxConfig singboxConfig, string baseTagName = Global.ProxyTag, bool ignoreOriginChain = false) + private List BuildSelectorOutbounds(List proxyTags, string baseTagName = Global.ProxyTag) { - try + var multipleLoad = context.Node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + var outUrltest = new Outbound4Sbox { - if (!node.ConfigType.IsGroupType()) - { - return -1; - } - var hasCycle = await GroupProfileManager.HasCycle(node); - if (hasCycle) - { - return -1; - } + type = "urltest", + tag = $"{Global.ProxyTag}-auto", + outbounds = proxyTags, + interrupt_exist_connections = false, + }; - var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); - if (childProfiles.Count <= 0) - { - return -1; - } - switch (node.ConfigType) - { - case EConfigType.PolicyGroup: - var multipleLoad = profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing; - if (ignoreOriginChain) - { - await GenOutboundsList(childProfiles, singboxConfig, multipleLoad, baseTagName); - } - else - { - await GenOutboundsListWithChain(childProfiles, singboxConfig, multipleLoad, baseTagName); - } - - break; - - case EConfigType.ProxyChain: - await GenChainOutboundsList(childProfiles, singboxConfig, baseTagName); - break; - - default: - break; - } - } - catch (Exception ex) + if (multipleLoad == EMultipleLoad.Fallback) { - Logging.SaveLog(_tag, ex); + outUrltest.tolerance = 5000; } - return await Task.FromResult(0); + + // Add selector outbound (manual selection) + var outSelector = new Outbound4Sbox + { + type = "selector", + tag = Global.ProxyTag, + outbounds = JsonUtils.DeepCopy(proxyTags), + interrupt_exist_connections = false, + }; + outSelector.outbounds.Insert(0, outUrltest.tag); + + return [outSelector, outUrltest]; } - private async Task GenMoreOutbounds(ProfileItem node, SingboxConfig singboxConfig) + private List BuildOutboundsList(string baseTagName = Global.ProxyTag) { - if (node.Subid.IsNullOrEmpty()) + var nodes = new List(); + foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) { - return 0; - } - try - { - var subItem = await AppManager.Instance.GetSubItem(node.Subid); - if (subItem is null) + if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) { - return 0; - } - - //current proxy - BaseServer4Sbox? outbound = singboxConfig.endpoints?.FirstOrDefault(t => t.tag == Global.ProxyTag, null); - outbound ??= singboxConfig.outbounds.First(); - - var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - - //Previous proxy - var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); - string? prevOutboundTag = null; - if (prevNode is not null - && Global.SingboxSupportConfigType.Contains(prevNode.ConfigType)) - { - prevOutboundTag = $"prev-{Global.ProxyTag}"; - var prevServer = await GenServer(prevNode); - prevServer.tag = prevOutboundTag; - if (prevServer is Endpoints4Sbox endpoint) - { - singboxConfig.endpoints ??= new(); - singboxConfig.endpoints.Add(endpoint); - } - else if (prevServer is Outbound4Sbox outboundPrev) - { - singboxConfig.outbounds.Add(outboundPrev); - } - } - var nextServer = await GenChainOutbounds(subItem, outbound, prevOutboundTag); - - if (nextServer is not null) - { - if (nextServer is Endpoints4Sbox endpoint) - { - singboxConfig.endpoints ??= new(); - singboxConfig.endpoints.Insert(0, endpoint); - } - else if (nextServer is Outbound4Sbox outboundNext) - { - singboxConfig.outbounds.Insert(0, outboundNext); - } + nodes.Add(node); } } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - - return 0; - } - - private async Task GenOutboundsListWithChain(List nodes, SingboxConfig singboxConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag) - { - try - { - // Get outbound template and initialize lists - var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - if (txtOutbound.IsNullOrEmpty()) - { - return 0; - } - - var resultOutbounds = new List(); - var resultEndpoints = new List(); // For endpoints - var prevOutbounds = new List(); // Separate list for prev outbounds - var prevEndpoints = new List(); // Separate list for prev endpoints - var proxyTags = new List(); // For selector and urltest outbounds - - // Cache for chain proxies to avoid duplicate generation - var nextProxyCache = new Dictionary(); - var prevProxyTags = new Dictionary(); // Map from profile name to tag - var prevIndex = 0; // Index for prev outbounds - - // Process each node - var index = 0; - foreach (var node in nodes) - { - index++; - - if (node.ConfigType.IsGroupType()) - { - var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); - if (childProfiles.Count <= 0) - { - continue; - } - var childBaseTagName = $"{baseTagName}-{index}"; - var ret = node.ConfigType switch - { - EConfigType.PolicyGroup => - await GenOutboundsListWithChain(childProfiles, singboxConfig, - profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing, childBaseTagName), - EConfigType.ProxyChain => - await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName), - _ => throw new NotImplementedException() - }; - if (ret == 0) - { - proxyTags.Add(childBaseTagName); - } - continue; - } - - // Handle proxy chain - string? prevTag = null; - var currentServer = await GenServer(node); - var nextServer = nextProxyCache.GetValueOrDefault(node.Subid, null); - if (nextServer != null) - { - nextServer = JsonUtils.DeepCopy(nextServer); - } - - var subItem = await AppManager.Instance.GetSubItem(node.Subid); - - // current proxy - currentServer.tag = $"{baseTagName}-{index}"; - proxyTags.Add(currentServer.tag); - - if (!node.Subid.IsNullOrEmpty()) - { - if (prevProxyTags.TryGetValue(node.Subid, out var value)) - { - prevTag = value; // maybe null - } - else - { - var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); - if (prevNode is not null - && Global.SingboxSupportConfigType.Contains(prevNode.ConfigType)) - { - var prevOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(prevNode, prevOutbound); - prevTag = $"prev-{baseTagName}-{++prevIndex}"; - prevOutbound.tag = prevTag; - prevOutbounds.Add(prevOutbound); - } - prevProxyTags[node.Subid] = prevTag; - } - - nextServer = await GenChainOutbounds(subItem, currentServer, prevTag, nextServer); - if (!nextProxyCache.ContainsKey(node.Subid)) - { - nextProxyCache[node.Subid] = nextServer; - } - } - - if (nextServer is not null) - { - if (nextServer is Endpoints4Sbox nextEndpoint) - { - resultEndpoints.Add(nextEndpoint); - } - else if (nextServer is Outbound4Sbox nextOutbound) - { - resultOutbounds.Add(nextOutbound); - } - } - if (currentServer is Endpoints4Sbox currentEndpoint) - { - resultEndpoints.Add(currentEndpoint); - } - else if (currentServer is Outbound4Sbox currentOutbound) - { - resultOutbounds.Add(currentOutbound); - } - } - - // Add urltest outbound (auto selection based on latency) - if (proxyTags.Count > 0) - { - var outUrltest = new Outbound4Sbox - { - type = "urltest", - tag = $"{baseTagName}-auto", - outbounds = proxyTags, - interrupt_exist_connections = false, - }; - - if (multipleLoad == EMultipleLoad.Fallback) - { - outUrltest.tolerance = 5000; - } - - // Add selector outbound (manual selection) - var outSelector = new Outbound4Sbox - { - type = "selector", - tag = baseTagName, - outbounds = JsonUtils.DeepCopy(proxyTags), - interrupt_exist_connections = false, - }; - outSelector.outbounds.Insert(0, outUrltest.tag); - - // Insert these at the beginning - resultOutbounds.Insert(0, outUrltest); - resultOutbounds.Insert(0, outSelector); - } - - // Merge results: first the selector/urltest/proxies, then other outbounds, and finally prev outbounds - var serverList = new List(); - serverList = serverList.Concat(prevOutbounds) - .Concat(resultOutbounds) - .Concat(resultEndpoints) - .ToList(); - await AddRangeOutbounds(serverList, singboxConfig, baseTagName == Global.ProxyTag); - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - - return 0; - } - - private async Task GenChainOutbounds(SubItem subItem, BaseServer4Sbox outbound, string? prevOutboundTag, BaseServer4Sbox? nextOutbound = null) - { - try - { - var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - - if (!prevOutboundTag.IsNullOrEmpty()) - { - outbound.detour = prevOutboundTag; - } - - // Next proxy - var nextNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.NextProfile); - if (nextNode is not null - && Global.SingboxSupportConfigType.Contains(nextNode.ConfigType)) - { - nextOutbound ??= await GenServer(nextNode); - nextOutbound.tag = outbound.tag; - - outbound.tag = $"mid-{outbound.tag}"; - nextOutbound.detour = outbound.tag; - } - return nextOutbound; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - return null; - } - - private async Task GenOutboundsList(List nodes, SingboxConfig singboxConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag) - { - var resultOutbounds = new List(); - var resultEndpoints = new List(); // For endpoints - var proxyTags = new List(); // For selector and urltest outbounds + var resultOutbounds = new List(); for (var i = 0; i < nodes.Count; i++) { var node = nodes[i]; - if (node == null) - { - continue; - } + var currentTag = baseTagName + (i + 1).ToString(); if (node.ConfigType.IsGroupType()) { - var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); - if (childProfiles.Count <= 0) - { - continue; - } - var childBaseTagName = $"{baseTagName}-{i + 1}"; - var ret = node.ConfigType switch - { - EConfigType.PolicyGroup => - await GenOutboundsList(childProfiles, singboxConfig, profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing, childBaseTagName), - EConfigType.ProxyChain => - await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName), - _ => throw new NotImplementedException() - }; - if (ret == 0) - { - proxyTags.Add(childBaseTagName); - } + var childProfiles = new CoreConfigSingboxService(context with { Node = node, }).BuildGroupProxyOutbounds(currentTag); + resultOutbounds.AddRange(childProfiles); continue; } - var server = await GenServer(node); - if (server is null) - { - break; - } - server.tag = baseTagName + (i + 1).ToString(); - if (server is Endpoints4Sbox endpoint) - { - resultEndpoints.Add(endpoint); - } - else if (server is Outbound4Sbox outbound) - { - resultOutbounds.Add(outbound); - } - proxyTags.Add(server.tag); + var outbound = new CoreConfigSingboxService(context with { Node = node, }).BuildProxyOutbound(); + outbound.tag = currentTag; + resultOutbounds.Add(outbound); } - // Add urltest outbound (auto selection based on latency) - if (proxyTags.Count > 0) - { - var outUrltest = new Outbound4Sbox - { - type = "urltest", - tag = $"{baseTagName}-auto", - outbounds = proxyTags, - interrupt_exist_connections = false, - }; - if (multipleLoad == EMultipleLoad.Fallback) - { - outUrltest.tolerance = 5000; - } - // Add selector outbound (manual selection) - var outSelector = new Outbound4Sbox - { - type = "selector", - tag = baseTagName, - outbounds = JsonUtils.DeepCopy(proxyTags), - interrupt_exist_connections = false, - }; - outSelector.outbounds.Insert(0, outUrltest.tag); - // Insert these at the beginning - resultOutbounds.Insert(0, outUrltest); - resultOutbounds.Insert(0, outSelector); - } - var serverList = new List(); - serverList = serverList.Concat(resultOutbounds) - .Concat(resultEndpoints) - .ToList(); - await AddRangeOutbounds(serverList, singboxConfig, baseTagName == Global.ProxyTag); - return await Task.FromResult(0); + return resultOutbounds; } - private async Task GenChainOutboundsList(List nodes, SingboxConfig singboxConfig, string baseTagName = Global.ProxyTag) + private List BuildChainOutboundsList(string baseTagName = Global.ProxyTag) { + var nodes = new List(); + foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) + { + if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) + { + nodes.Add(node); + } + } // Based on actual network flow instead of data packets var nodesReverse = nodes.AsEnumerable().Reverse().ToList(); - var resultOutbounds = new List(); - var resultEndpoints = new List(); // For endpoints + var resultOutbounds = new List(); for (var i = 0; i < nodesReverse.Count; i++) { var node = nodesReverse[i]; - var server = await GenServer(node); - - if (server is null) + var currentTag = i == 0 ? baseTagName : "chain-" + baseTagName + i.ToString(); + var dialerProxyTag = i != nodesReverse.Count - 1 ? "chain-" + baseTagName + (i + 1).ToString() : null; + if (node.ConfigType.IsGroupType()) { - break; + var childProfiles = new CoreConfigSingboxService(context with { Node = node, }).BuildGroupProxyOutbounds(currentTag); + if (!dialerProxyTag.IsNullOrEmpty()) + { + var chainEndNodes = + childProfiles.Where(n => n?.detour.IsNullOrEmpty() ?? true); + foreach (var chainEndNode in chainEndNodes) + { + chainEndNode.detour = dialerProxyTag; + } + } + if (i != 0) + { + var chainStartNodes = childProfiles.Where(n => n.tag.StartsWith(currentTag)).ToList(); + var existedChainNodes = JsonUtils.DeepCopy(resultOutbounds); + resultOutbounds.Clear(); + foreach (var chainStartNode in chainStartNodes) + { + var existedChainNodesClone = JsonUtils.DeepCopy(existedChainNodes); + for (var j = 0; j < existedChainNodesClone.Count; j++) + { + var existedChainNode = existedChainNodesClone[j]; + var cloneTag = $"{existedChainNode.tag}-clone{j}"; + existedChainNode.tag = cloneTag; + var previousDialerProxyTag = existedChainNode.detour; + existedChainNode.detour = (previousDialerProxyTag == currentTag) + ? chainStartNode.tag + : existedChainNodesClone[j + 1].tag; + resultOutbounds.Add(existedChainNode); + } + } + } + resultOutbounds.AddRange(childProfiles); + continue; + } + var outbound = new CoreConfigSingboxService(context with { Node = node, }).BuildProxyOutbound(); + + outbound.tag = currentTag; + + if (!dialerProxyTag.IsNullOrEmpty()) + { + outbound.detour = dialerProxyTag; } - if (i == 0) - { - server.tag = baseTagName; - } - else - { - server.tag = baseTagName + i.ToString(); - } - - if (i != nodesReverse.Count - 1) - { - server.detour = baseTagName + (i + 1).ToString(); - } - - if (server is Endpoints4Sbox endpoint) - { - resultEndpoints.Add(endpoint); - } - else if (server is Outbound4Sbox outbound) - { - resultOutbounds.Add(outbound); - } + resultOutbounds.Add(outbound); } - var serverList = new List(); - serverList = serverList.Concat(resultOutbounds) - .Concat(resultEndpoints) - .ToList(); - await AddRangeOutbounds(serverList, singboxConfig, baseTagName == Global.ProxyTag); - return await Task.FromResult(0); + return resultOutbounds; } - private async Task AddRangeOutbounds(List servers, SingboxConfig singboxConfig, bool prepend = true) + private static void FillRangeProxy(List servers, SingboxConfig singboxConfig, bool prepend = true) { try { if (servers is null || servers.Count <= 0) { - return 0; + return; } var outbounds = servers.Where(s => s is Outbound4Sbox).Cast().ToList(); var endpoints = servers.Where(s => s is Endpoints4Sbox).Cast().ToList(); - singboxConfig.endpoints ??= new(); + singboxConfig.endpoints ??= []; if (prepend) { singboxConfig.outbounds.InsertRange(0, outbounds); @@ -936,10 +665,9 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private (Ech4Sbox? ech, Server4Sbox? dnsServer) ParseEchParam(string? echConfig) + private static (Ech4Sbox? ech, Server4Sbox? dnsServer) ParseEchParam(string? echConfig) { if (echConfig.IsNullOrEmpty()) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs index 6198d027..606a54df 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs @@ -2,127 +2,122 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenRouting(SingboxConfig singboxConfig) + private void GenRouting() { try { - singboxConfig.route.final = Global.ProxyTag; - var simpleDnsItem = _config.SimpleDNSItem; + _coreConfig.route.final = Global.ProxyTag; + var simpleDnsItem = context.AppConfig.SimpleDNSItem; var defaultDomainResolverTag = Global.SingboxDirectDNSTag; var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); - var rawDNSItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); + var rawDNSItem = context.RawDnsItem; if (rawDNSItem is { Enabled: true }) { defaultDomainResolverTag = Global.SingboxLocalDNSTag; directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom; } - singboxConfig.route.default_domain_resolver = new() + _coreConfig.route.default_domain_resolver = new() { server = defaultDomainResolverTag, strategy = directDnsStrategy }; - if (_config.TunModeItem.EnableTun) + if (context.AppConfig.TunModeItem.EnableTun) { - singboxConfig.route.auto_detect_interface = true; + _coreConfig.route.auto_detect_interface = true; var tunRules = JsonUtils.Deserialize>(EmbedUtils.GetEmbedText(Global.TunSingboxRulesFileName)); if (tunRules != null) { - singboxConfig.route.rules.AddRange(tunRules); + _coreConfig.route.rules.AddRange(tunRules); } - GenRoutingDirectExe(out var lstDnsExe, out var lstDirectExe); - singboxConfig.route.rules.Add(new() + var (lstDnsExe, lstDirectExe) = BuildRoutingDirectExe(); + _coreConfig.route.rules.Add(new() { - port = new() { 53 }, + port = [53], action = "hijack-dns", process_name = lstDnsExe }); - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { outbound = Global.DirectTag, process_name = lstDirectExe }); } - if (_config.Inbound.First().SniffingEnabled) + if (context.AppConfig.Inbound.First().SniffingEnabled) { - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { action = "sniff" }); - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { - protocol = new() { "dns" }, + protocol = ["dns"], action = "hijack-dns" }); } else { - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { - port = new() { 53 }, - network = new() { "udp" }, + port = [53], + network = ["udp"], action = "hijack-dns" }); } var hostsDomains = new List(); - var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); - if (dnsItem == null || !dnsItem.Enabled) + if (rawDNSItem is not { Enabled: true }) { var userHostsMap = Utils.ParseHostsToDictionary(simpleDnsItem.Hosts); hostsDomains.AddRange(userHostsMap.Select(kvp => kvp.Key)); if (simpleDnsItem.UseSystemHosts == true) { var systemHostsMap = Utils.GetSystemHosts(); - foreach (var kvp in systemHostsMap) - { - hostsDomains.Add(kvp.Key); - } + hostsDomains.AddRange(systemHostsMap.Select(kvp => kvp.Key)); } } if (hostsDomains.Count > 0) { - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { action = "resolve", domain = hostsDomains, }); } - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { outbound = Global.DirectTag, clash_mode = ERuleMode.Direct.ToString() }); - singboxConfig.route.rules.Add(new() + _coreConfig.route.rules.Add(new() { outbound = Global.ProxyTag, clash_mode = ERuleMode.Global.ToString() }); - var domainStrategy = _config.RoutingBasicItem.DomainStrategy4Singbox.NullIfEmpty(); - var defaultRouting = await ConfigHandler.GetDefaultRouting(_config); - if (defaultRouting.DomainStrategy4Singbox.IsNotEmpty()) + var domainStrategy = context.AppConfig.RoutingBasicItem.DomainStrategy4Singbox.NullIfEmpty(); + var routing = context.RoutingItem; + if (routing.DomainStrategy4Singbox.IsNotEmpty()) { - domainStrategy = defaultRouting.DomainStrategy4Singbox; + domainStrategy = routing.DomainStrategy4Singbox; } var resolveRule = new Rule4Sbox { action = "resolve", strategy = domainStrategy }; - if (_config.RoutingBasicItem.DomainStrategy == Global.IPOnDemand) + if (context.AppConfig.RoutingBasicItem.DomainStrategy == Global.IPOnDemand) { - singboxConfig.route.rules.Add(resolveRule); + _coreConfig.route.rules.Add(resolveRule); } - var routing = await ConfigHandler.GetDefaultRouting(_config); var ipRules = new List(); if (routing != null) { @@ -139,7 +134,7 @@ public partial class CoreConfigSingboxService continue; } - await GenRoutingUserRule(item1, singboxConfig); + GenRoutingUserRule(item1); if (item1.Ip?.Count > 0) { @@ -147,12 +142,12 @@ public partial class CoreConfigSingboxService } } } - if (_config.RoutingBasicItem.DomainStrategy == Global.IPIfNonMatch) + if (context.AppConfig.RoutingBasicItem.DomainStrategy == Global.IPIfNonMatch) { - singboxConfig.route.rules.Add(resolveRule); + _coreConfig.route.rules.Add(resolveRule); foreach (var item2 in ipRules) { - await GenRoutingUserRule(item2, singboxConfig); + GenRoutingUserRule(item2); } } } @@ -160,10 +155,9 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return 0; } - private void GenRoutingDirectExe(out List lstDnsExe, out List lstDirectExe) + private static (List lstDnsExe, List lstDirectExe) BuildRoutingDirectExe() { var dnsExeSet = new HashSet(StringComparer.OrdinalIgnoreCase); var directExeSet = new HashSet(StringComparer.OrdinalIgnoreCase); @@ -187,20 +181,22 @@ public partial class CoreConfigSingboxService } } - lstDnsExe = new List(dnsExeSet); - lstDirectExe = new List(directExeSet); + var lstDnsExe = new List(dnsExeSet); + var lstDirectExe = new List(directExeSet); + + return (lstDnsExe, lstDirectExe); } - private async Task GenRoutingUserRule(RulesItem item, SingboxConfig singboxConfig) + private void GenRoutingUserRule(RulesItem? item) { try { if (item == null) { - return 0; + return; } - item.OutboundTag = await GenRoutingUserRuleOutbound(item.OutboundTag, singboxConfig); - var rules = singboxConfig.route.rules; + item.OutboundTag = GenRoutingUserRuleOutbound(item.OutboundTag ?? Global.ProxyTag); + var rules = _coreConfig.route.rules; var rule = new Rule4Sbox(); if (item.OutboundTag == "block") @@ -326,10 +322,9 @@ public partial class CoreConfigSingboxService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private bool ParseV2Domain(string domain, Rule4Sbox rule) + private static bool ParseV2Domain(string domain, Rule4Sbox rule) { if (domain.StartsWith('#') || domain.StartsWith("ext:") || domain.StartsWith("ext-domain:")) { @@ -368,7 +363,7 @@ public partial class CoreConfigSingboxService return true; } - private bool ParseV2Address(string address, Rule4Sbox rule) + private static bool ParseV2Address(string address, Rule4Sbox rule) { if (address.StartsWith("ext:") || address.StartsWith("ext-ip:")) { @@ -401,14 +396,14 @@ public partial class CoreConfigSingboxService return true; } - private async Task GenRoutingUserRuleOutbound(string outboundTag, SingboxConfig singboxConfig) + private string GenRoutingUserRuleOutbound(string outboundTag) { if (Global.OutboundTags.Contains(outboundTag)) { return outboundTag; } - var node = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag); + var node = context.AllProxiesMap.GetValueOrDefault($"remark:{outboundTag}"); if (node == null || (!Global.SingboxSupportConfigType.Contains(node.ConfigType) @@ -418,39 +413,15 @@ public partial class CoreConfigSingboxService } var tag = $"{node.IndexId}-{Global.ProxyTag}"; - if (singboxConfig.outbounds.Any(o => o.tag == tag) - || (singboxConfig.endpoints != null && singboxConfig.endpoints.Any(e => e.tag == tag))) + if (_coreConfig.outbounds.Any(o => o.tag == tag) + || (_coreConfig.endpoints != null && _coreConfig.endpoints.Any(e => e.tag == tag))) { return tag; } - if (node.ConfigType.IsGroupType()) - { - var ret = await GenGroupOutbound(node, singboxConfig, tag); - if (ret == 0) - { - return tag; - } - return Global.ProxyTag; - } + var proxyOutbounds = new CoreConfigSingboxService(context with { Node = node, }).BuildAllProxyOutbounds(tag); + FillRangeProxy(proxyOutbounds, _coreConfig, false); - var server = await GenServer(node); - if (server is null) - { - return Global.ProxyTag; - } - - server.tag = tag; - if (server is Endpoints4Sbox endpoint) - { - singboxConfig.endpoints ??= new(); - singboxConfig.endpoints.Add(endpoint); - } - else if (server is Outbound4Sbox outbound) - { - singboxConfig.outbounds.Add(outbound); - } - - return server.tag; + return tag; } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs index 7d26ca2f..46240336 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs @@ -2,7 +2,7 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task ConvertGeo2Ruleset(SingboxConfig singboxConfig) + private void ConvertGeo2Ruleset() { static void AddRuleSets(List ruleSets, List? rule_set) { @@ -16,14 +16,14 @@ public partial class CoreConfigSingboxService var ruleSets = new List(); //convert route geosite & geoip to ruleset - foreach (var rule in singboxConfig.route.rules.Where(t => t.geosite?.Count > 0).ToList() ?? []) + foreach (var rule in _coreConfig.route.rules.Where(t => t.geosite?.Count > 0).ToList() ?? []) { rule.rule_set ??= new List(); rule.rule_set.AddRange(rule?.geosite?.Select(t => $"{geosite}-{t}").ToList()); rule.geosite = null; AddRuleSets(ruleSets, rule.rule_set); } - foreach (var rule in singboxConfig.route.rules.Where(t => t.geoip?.Count > 0).ToList() ?? []) + foreach (var rule in _coreConfig.route.rules.Where(t => t.geoip?.Count > 0).ToList() ?? []) { rule.rule_set ??= new List(); rule.rule_set.AddRange(rule?.geoip?.Select(t => $"{geoip}-{t}").ToList()); @@ -32,24 +32,24 @@ public partial class CoreConfigSingboxService } //convert dns geosite & geoip to ruleset - foreach (var rule in singboxConfig.dns?.rules.Where(t => t.geosite?.Count > 0).ToList() ?? []) + foreach (var rule in _coreConfig.dns?.rules.Where(t => t.geosite?.Count > 0).ToList() ?? []) { rule.rule_set ??= new List(); rule.rule_set.AddRange(rule?.geosite?.Select(t => $"{geosite}-{t}").ToList()); rule.geosite = null; } - foreach (var rule in singboxConfig.dns?.rules.Where(t => t.geoip?.Count > 0).ToList() ?? []) + foreach (var rule in _coreConfig.dns?.rules.Where(t => t.geoip?.Count > 0).ToList() ?? []) { rule.rule_set ??= new List(); rule.rule_set.AddRange(rule?.geoip?.Select(t => $"{geoip}-{t}").ToList()); rule.geoip = null; } - foreach (var dnsRule in singboxConfig.dns?.rules.Where(t => t.rule_set?.Count > 0).ToList() ?? []) + foreach (var dnsRule in _coreConfig.dns?.rules.Where(t => t.rule_set?.Count > 0).ToList() ?? []) { AddRuleSets(ruleSets, dnsRule.rule_set); } //rules in rules - foreach (var item in singboxConfig.dns?.rules.Where(t => t.rules?.Count > 0).Select(t => t.rules).ToList() ?? []) + foreach (var item in _coreConfig.dns?.rules.Where(t => t.rules?.Count > 0).Select(t => t.rules).ToList() ?? []) { foreach (var item2 in item ?? []) { @@ -60,7 +60,7 @@ public partial class CoreConfigSingboxService //load custom ruleset file List customRulesets = []; - var routing = await ConfigHandler.GetDefaultRouting(_config); + var routing = context.RoutingItem; if (routing.CustomRulesetPath4Singbox.IsNotEmpty()) { var result = EmbedUtils.LoadResource(routing.CustomRulesetPath4Singbox); @@ -78,7 +78,7 @@ public partial class CoreConfigSingboxService var localSrss = Utils.GetBinPath("srss"); //Add ruleset srs - singboxConfig.route.rule_set = []; + _coreConfig.route.rule_set = []; foreach (var item in new HashSet(ruleSets)) { if (item.IsNullOrEmpty()) @@ -99,9 +99,9 @@ public partial class CoreConfigSingboxService } else { - var srsUrl = string.IsNullOrEmpty(_config.ConstItem.SrsSourceUrl) + var srsUrl = string.IsNullOrEmpty(context.AppConfig.ConstItem.SrsSourceUrl) ? Global.SingboxRulesetUrl - : _config.ConstItem.SrsSourceUrl; + : context.AppConfig.ConstItem.SrsSourceUrl; customRuleset = new() { @@ -113,9 +113,7 @@ public partial class CoreConfigSingboxService }; } } - singboxConfig.route.rule_set.Add(customRuleset); + _coreConfig.route.rule_set.Add(customRuleset); } - - return 0; } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs index c3acd810..a44872ac 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs @@ -2,28 +2,26 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenExperimental(SingboxConfig singboxConfig) + private void GenExperimental() { //if (_config.guiItem.enableStatistics) { - singboxConfig.experimental ??= new Experimental4Sbox(); - singboxConfig.experimental.clash_api = new Clash_Api4Sbox() + _coreConfig.experimental ??= new Experimental4Sbox(); + _coreConfig.experimental.clash_api = new Clash_Api4Sbox() { external_controller = $"{Global.Loopback}:{AppManager.Instance.StatePort2}", }; } - if (_config.CoreBasicItem.EnableCacheFile4Sbox) + if (context.AppConfig.CoreBasicItem.EnableCacheFile4Sbox) { - singboxConfig.experimental ??= new Experimental4Sbox(); - singboxConfig.experimental.cache_file = new CacheFile4Sbox() + _coreConfig.experimental ??= new Experimental4Sbox(); + _coreConfig.experimental.cache_file = new CacheFile4Sbox() { enabled = true, path = Utils.GetBinPath("cache.db"), - store_fakeip = _config.SimpleDNSItem.FakeIP == true + store_fakeip = context.AppConfig.SimpleDNSItem.FakeIP == true }; } - - return await Task.FromResult(0); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs index d753fb3c..a74d850a 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs @@ -1,17 +1,19 @@ namespace ServiceLib.Services.CoreConfig; -public partial class CoreConfigV2rayService(Config config) +public partial class CoreConfigV2rayService(CoreConfigContext context) { - private readonly Config _config = config; private static readonly string _tag = "CoreConfigV2rayService"; + private V2rayConfig _coreConfig = new(); + #region public gen function - public async Task GenerateClientConfigContent(ProfileItem node) + public RetResult GenerateClientConfigContent() { var ret = new RetResult(); try { + var node = context?.Node; if (node == null || !node.IsValid()) { @@ -27,18 +29,6 @@ public partial class CoreConfigV2rayService(Config config) ret.Msg = ResUI.InitialConfiguration; - if (node.ConfigType.IsGroupType()) - { - switch (node.ConfigType) - { - case EConfigType.PolicyGroup: - return await GenerateClientMultipleLoadConfig(node); - - case EConfigType.ProxyChain: - return await GenerateClientChainConfig(node); - } - } - var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient); if (result.IsNullOrEmpty()) { @@ -46,30 +36,28 @@ public partial class CoreConfigV2rayService(Config config) return ret; } - var v2rayConfig = JsonUtils.Deserialize(result); - if (v2rayConfig == null) + _coreConfig = JsonUtils.Deserialize(result); + if (_coreConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; } - await GenLog(v2rayConfig); + GenLog(); - await GenInbounds(v2rayConfig); + GenInbounds(); - await GenOutbound(node, v2rayConfig.outbounds.First()); + GenOutbounds(); - await GenMoreOutbounds(node, v2rayConfig); + GenRouting(); - await GenRouting(v2rayConfig); + GenDns(); - await GenDns(node, v2rayConfig); - - await GenStatistic(v2rayConfig); + GenStatistic(); ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Success = true; - ret.Data = await ApplyFullConfigTemplate(v2rayConfig); + ret.Data = ApplyFullConfigTemplate(); return ret; } catch (Exception ex) @@ -80,182 +68,11 @@ public partial class CoreConfigV2rayService(Config config) } } - public async Task GenerateClientMultipleLoadConfig(ProfileItem parentNode) - { - var ret = new RetResult(); - - try - { - if (_config == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - ret.Msg = ResUI.InitialConfiguration; - - var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient); - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty()) - { - ret.Msg = ResUI.FailedGetDefaultConfiguration; - return ret; - } - - var v2rayConfig = JsonUtils.Deserialize(result); - if (v2rayConfig == null) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - v2rayConfig.outbounds.RemoveAt(0); - - await GenLog(v2rayConfig); - await GenInbounds(v2rayConfig); - - var groupRet = await GenGroupOutbound(parentNode, v2rayConfig); - if (groupRet != 0) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - - await GenRouting(v2rayConfig); - await GenDns(null, v2rayConfig); - await GenStatistic(v2rayConfig); - - var defaultBalancerTag = $"{Global.ProxyTag}{Global.BalancerTagSuffix}"; - - //add rule - var rules = v2rayConfig.routing.rules; - if (rules?.Count > 0 && ((v2rayConfig.routing.balancers?.Count ?? 0) > 0)) - { - var balancerTagSet = v2rayConfig.routing.balancers - .Select(b => b.tag) - .ToHashSet(); - - foreach (var rule in rules) - { - if (rule.outboundTag == null) - { - continue; - } - - if (balancerTagSet.Contains(rule.outboundTag)) - { - rule.balancerTag = rule.outboundTag; - rule.outboundTag = null; - continue; - } - - var outboundWithSuffix = rule.outboundTag + Global.BalancerTagSuffix; - if (balancerTagSet.Contains(outboundWithSuffix)) - { - rule.balancerTag = outboundWithSuffix; - rule.outboundTag = null; - } - } - } - if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch) - { - v2rayConfig.routing.rules.Add(new() - { - ip = ["0.0.0.0/0", "::/0"], - balancerTag = defaultBalancerTag, - type = "field" - }); - } - else - { - v2rayConfig.routing.rules.Add(new() - { - network = "tcp,udp", - balancerTag = defaultBalancerTag, - type = "field" - }); - } - - ret.Success = true; - - ret.Data = await ApplyFullConfigTemplate(v2rayConfig); - return ret; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - } - - public async Task GenerateClientChainConfig(ProfileItem parentNode) - { - var ret = new RetResult(); - - try - { - if (_config == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - ret.Msg = ResUI.InitialConfiguration; - - var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient); - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty()) - { - ret.Msg = ResUI.FailedGetDefaultConfiguration; - return ret; - } - - var v2rayConfig = JsonUtils.Deserialize(result); - if (v2rayConfig == null) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - v2rayConfig.outbounds.RemoveAt(0); - - await GenLog(v2rayConfig); - await GenInbounds(v2rayConfig); - - var groupRet = await GenGroupOutbound(parentNode, v2rayConfig); - if (groupRet != 0) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - - await GenRouting(v2rayConfig); - await GenDns(null, v2rayConfig); - await GenStatistic(v2rayConfig); - - ret.Success = true; - - ret.Data = await ApplyFullConfigTemplate(v2rayConfig); - return ret; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - } - - public async Task GenerateClientSpeedtestConfig(List selecteds) + public RetResult GenerateClientSpeedtestConfig(List selecteds) { var ret = new RetResult(); try { - if (_config == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - ret.Msg = ResUI.InitialConfiguration; var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient); @@ -285,7 +102,7 @@ public partial class CoreConfigV2rayService(Config config) Logging.SaveLog(_tag, ex); } - await GenLog(v2rayConfig); + GenLog(); v2rayConfig.inbounds.Clear(); v2rayConfig.outbounds.Clear(); v2rayConfig.routing.rules.Clear(); @@ -302,7 +119,7 @@ public partial class CoreConfigV2rayService(Config config) { continue; } - var item = await AppManager.Instance.GetProfileItem(it.IndexId); + var item = context.AllProxiesMap.GetValueOrDefault(it.IndexId); if (item is null || item.IsComplex() || !item.IsValid()) { continue; @@ -344,19 +161,31 @@ public partial class CoreConfigV2rayService(Config config) inbound.tag = inbound.protocol + inbound.port.ToString(); v2rayConfig.inbounds.Add(inbound); + var tag = Global.ProxyTag + inbound.port.ToString(); + var isBalancer = false; //outbound - var outbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(item, outbound); - outbound.tag = Global.ProxyTag + inbound.port.ToString(); - v2rayConfig.outbounds.Add(outbound); + var proxyOutbounds = BuildAllProxyOutbounds(tag); + v2rayConfig.outbounds.AddRange(proxyOutbounds); + if (proxyOutbounds.Count(n => n.tag.StartsWith(tag)) > 1) + { + isBalancer = true; + var multipleLoad = context.Node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + GenObservatory(multipleLoad, tag); + GenBalancer(multipleLoad, tag); + } //rule RulesItem4Ray rule = new() { inboundTag = new List { inbound.tag }, - outboundTag = outbound.tag, + outboundTag = tag, type = "field" }; + if (isBalancer) + { + rule.balancerTag = tag; + rule.outboundTag = null; + } v2rayConfig.routing.rules.Add(rule); } @@ -373,11 +202,12 @@ public partial class CoreConfigV2rayService(Config config) } } - public async Task GenerateClientSpeedtestConfig(ProfileItem node, int port) + public RetResult GenerateClientSpeedtestConfig(int port) { var ret = new RetResult(); try { + var node = context.Node; if (node == null || !node.IsValid()) { @@ -405,9 +235,8 @@ public partial class CoreConfigV2rayService(Config config) return ret; } - await GenLog(v2rayConfig); - await GenOutbound(node, v2rayConfig.outbounds.First()); - await GenMoreOutbounds(node, v2rayConfig); + GenLog(); + GenOutbounds(); v2rayConfig.routing.rules.Clear(); v2rayConfig.inbounds.Clear(); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs index 35a220c6..f294de46 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs @@ -2,17 +2,17 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenObservatory(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag) + private void GenObservatory(EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag) { // Collect all existing subject selectors from both observatories var subjectSelectors = new List(); - subjectSelectors.AddRange(v2rayConfig.burstObservatory?.subjectSelector ?? []); - subjectSelectors.AddRange(v2rayConfig.observatory?.subjectSelector ?? []); + subjectSelectors.AddRange(_coreConfig.burstObservatory?.subjectSelector ?? []); + subjectSelectors.AddRange(_coreConfig.observatory?.subjectSelector ?? []); // Case 1: exact match already exists -> nothing to do if (subjectSelectors.Any(baseTagName.StartsWith)) { - return await Task.FromResult(0); + return; } // Case 2: prefix match exists -> reuse it and move to the first position @@ -21,28 +21,28 @@ public partial class CoreConfigV2rayService { baseTagName = matched; - if (v2rayConfig.burstObservatory?.subjectSelector?.Contains(baseTagName) == true) + if (_coreConfig.burstObservatory?.subjectSelector?.Contains(baseTagName) == true) { - v2rayConfig.burstObservatory.subjectSelector.Remove(baseTagName); - v2rayConfig.burstObservatory.subjectSelector.Insert(0, baseTagName); + _coreConfig.burstObservatory.subjectSelector.Remove(baseTagName); + _coreConfig.burstObservatory.subjectSelector.Insert(0, baseTagName); } - if (v2rayConfig.observatory?.subjectSelector?.Contains(baseTagName) == true) + if (_coreConfig.observatory?.subjectSelector?.Contains(baseTagName) == true) { - v2rayConfig.observatory.subjectSelector.Remove(baseTagName); - v2rayConfig.observatory.subjectSelector.Insert(0, baseTagName); + _coreConfig.observatory.subjectSelector.Remove(baseTagName); + _coreConfig.observatory.subjectSelector.Insert(0, baseTagName); } - return await Task.FromResult(0); + return; } // Case 3: need to create or insert based on multipleLoad type if (multipleLoad is EMultipleLoad.LeastLoad or EMultipleLoad.Fallback) { - if (v2rayConfig.burstObservatory is null) + if (_coreConfig.burstObservatory is null) { // Create new burst observatory with default ping config - v2rayConfig.burstObservatory = new BurstObservatory4Ray + _coreConfig.burstObservatory = new BurstObservatory4Ray { subjectSelector = [baseTagName], pingConfig = new() @@ -56,16 +56,16 @@ public partial class CoreConfigV2rayService } else { - v2rayConfig.burstObservatory.subjectSelector ??= new(); - v2rayConfig.burstObservatory.subjectSelector.Add(baseTagName); + _coreConfig.burstObservatory.subjectSelector ??= new(); + _coreConfig.burstObservatory.subjectSelector.Add(baseTagName); } } else if (multipleLoad is EMultipleLoad.LeastPing) { - if (v2rayConfig.observatory is null) + if (_coreConfig.observatory is null) { // Create new observatory with default probe config - v2rayConfig.observatory = new Observatory4Ray + _coreConfig.observatory = new Observatory4Ray { subjectSelector = [baseTagName], probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl, @@ -75,15 +75,13 @@ public partial class CoreConfigV2rayService } else { - v2rayConfig.observatory.subjectSelector ??= new(); - v2rayConfig.observatory.subjectSelector.Add(baseTagName); + _coreConfig.observatory.subjectSelector ??= new(); + _coreConfig.observatory.subjectSelector.Add(baseTagName); } } - - return await Task.FromResult(0); } - private async Task GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad, string selector = Global.ProxyTag) + private void GenBalancer(EMultipleLoad multipleLoad, string selector = Global.ProxyTag) { var strategyType = multipleLoad switch { @@ -107,8 +105,7 @@ public partial class CoreConfigV2rayService }, tag = balancerTag, }; - v2rayConfig.routing.balancers ??= new(); - v2rayConfig.routing.balancers.Add(balancer); - return await Task.FromResult(balancerTag); + _coreConfig.routing.balancers ??= new(); + _coreConfig.routing.balancers.Add(balancer); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs index 1f2583ff..cec9b6ea 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs @@ -2,24 +2,24 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task ApplyFullConfigTemplate(V2rayConfig v2rayConfig) + private string ApplyFullConfigTemplate() { - var fullConfigTemplate = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.Xray); + var fullConfigTemplate = context.FullConfigTemplate; if (fullConfigTemplate == null || !fullConfigTemplate.Enabled || fullConfigTemplate.Config.IsNullOrEmpty()) { - return JsonUtils.Serialize(v2rayConfig); + return JsonUtils.Serialize(_coreConfig); } var fullConfigTemplateNode = JsonNode.Parse(fullConfigTemplate.Config); if (fullConfigTemplateNode == null) { - return JsonUtils.Serialize(v2rayConfig); + return JsonUtils.Serialize(_coreConfig); } // Handle balancer and rules modifications (for multiple load scenarios) - if (v2rayConfig.routing?.balancers?.Count > 0) + if (_coreConfig.routing?.balancers?.Count > 0) { - var balancer = v2rayConfig.routing.balancers.First(); + var balancer = _coreConfig.routing.balancers.First(); // Modify existing rules in custom config var rulesNode = fullConfigTemplateNode["routing"]?["rules"]; @@ -44,7 +44,7 @@ public partial class CoreConfigV2rayService // Handle balancers - append instead of override if (fullConfigTemplateNode["routing"]["balancers"] is JsonArray customBalancersNode) { - if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)) is JsonArray newBalancers) + if (JsonNode.Parse(JsonUtils.Serialize(_coreConfig.routing.balancers)) is JsonArray newBalancers) { foreach (var balancerNode in newBalancers) { @@ -54,33 +54,33 @@ public partial class CoreConfigV2rayService } else { - fullConfigTemplateNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)); + fullConfigTemplateNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(_coreConfig.routing.balancers)); } } - if (v2rayConfig.observatory != null) + if (_coreConfig.observatory != null) { if (fullConfigTemplateNode["observatory"] == null) { - fullConfigTemplateNode["observatory"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.observatory)); + fullConfigTemplateNode["observatory"] = JsonNode.Parse(JsonUtils.Serialize(_coreConfig.observatory)); } else { - var subjectSelector = v2rayConfig.observatory.subjectSelector; + var subjectSelector = _coreConfig.observatory.subjectSelector; subjectSelector.AddRange(fullConfigTemplateNode["observatory"]?["subjectSelector"]?.AsArray()?.Select(x => x?.GetValue()) ?? []); fullConfigTemplateNode["observatory"]["subjectSelector"] = JsonNode.Parse(JsonUtils.Serialize(subjectSelector.Distinct().ToList())); } } - if (v2rayConfig.burstObservatory != null) + if (_coreConfig.burstObservatory != null) { if (fullConfigTemplateNode["burstObservatory"] == null) { - fullConfigTemplateNode["burstObservatory"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.burstObservatory)); + fullConfigTemplateNode["burstObservatory"] = JsonNode.Parse(JsonUtils.Serialize(_coreConfig.burstObservatory)); } else { - var subjectSelector = v2rayConfig.burstObservatory.subjectSelector; + var subjectSelector = _coreConfig.burstObservatory.subjectSelector; subjectSelector.AddRange(fullConfigTemplateNode["burstObservatory"]?["subjectSelector"]?.AsArray()?.Select(x => x?.GetValue()) ?? []); fullConfigTemplateNode["burstObservatory"]["subjectSelector"] = JsonNode.Parse(JsonUtils.Serialize(subjectSelector.Distinct().ToList())); } @@ -88,7 +88,7 @@ public partial class CoreConfigV2rayService var customOutboundsNode = new JsonArray(); - foreach (var outbound in v2rayConfig.outbounds) + foreach (var outbound in _coreConfig.outbounds) { if (outbound.protocol.ToLower() is "blackhole" or "dns" or "freedom") { @@ -123,6 +123,6 @@ public partial class CoreConfigV2rayService fullConfigTemplateNode["outbounds"] = customOutboundsNode; - return await Task.FromResult(JsonUtils.Serialize(fullConfigTemplateNode)); + return JsonUtils.Serialize(fullConfigTemplateNode); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index 7de97240..e131af33 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -2,46 +2,45 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenDns(ProfileItem? node, V2rayConfig v2rayConfig) + private void GenDns() { try { - var item = await AppManager.Instance.GetDNSItem(ECoreType.Xray); + var item = context.RawDnsItem; if (item is { Enabled: true }) { - var result = await GenDnsCompatible(node, v2rayConfig); + GenDnsCustom(); - if (v2rayConfig.routing.domainStrategy != Global.IPIfNonMatch) + if (_coreConfig.routing.domainStrategy != Global.IPIfNonMatch) { - return result; + return; } // DNS routing - var dnsObj = JsonUtils.SerializeToNode(v2rayConfig.dns); + var dnsObj = JsonUtils.SerializeToNode(_coreConfig.dns); if (dnsObj == null) { - return result; + return; } dnsObj["tag"] = Global.DnsTag; - v2rayConfig.dns = JsonUtils.Deserialize(JsonUtils.Serialize(dnsObj)); - v2rayConfig.routing.rules.Add(new RulesItem4Ray + _coreConfig.dns = JsonUtils.Deserialize(JsonUtils.Serialize(dnsObj)); + _coreConfig.routing.rules.Add(new RulesItem4Ray { type = "field", inboundTag = new List { Global.DnsTag }, outboundTag = Global.ProxyTag, }); - - return result; + return; } - var simpleDnsItem = _config.SimpleDNSItem; - var dnsItem = v2rayConfig.dns is Dns4Ray dns4Ray ? dns4Ray : new Dns4Ray(); + var simpleDnsItem = context.SimpleDnsItem; + var dnsItem = _coreConfig.dns is Dns4Ray dns4Ray ? dns4Ray : new Dns4Ray(); var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs; //Outbound Freedom domainStrategy if (strategy4Freedom.IsNotEmpty() && strategy4Freedom != Global.AsIs) { - var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); + var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); if (outbound != null) { outbound.settings = new() @@ -59,23 +58,23 @@ public partial class CoreConfigV2rayService var xraySupportConfigTypeNames = Global.XraySupportConfigType .Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x]) .ToHashSet(); - v2rayConfig.outbounds + _coreConfig.outbounds .Where(t => xraySupportConfigTypeNames.Contains(t.protocol)) .ToList() .ForEach(outbound => outbound.targetStrategy = strategy4Proxy); } - await GenDnsServers(node, dnsItem, simpleDnsItem); - await GenDnsHosts(dnsItem, simpleDnsItem); + FillDnsServers(dnsItem); + FillDnsHosts(dnsItem); dnsItem.serveStale = simpleDnsItem?.ServeStale is true ? true : null; dnsItem.enableParallelQuery = simpleDnsItem?.ParallelQuery is true ? true : null; - if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch) + if (_coreConfig.routing.domainStrategy == Global.IPIfNonMatch) { // DNS routing dnsItem.tag = Global.DnsTag; - v2rayConfig.routing.rules.Add(new RulesItem4Ray + _coreConfig.routing.rules.Add(new RulesItem4Ray { type = "field", inboundTag = new List { Global.DnsTag }, @@ -83,17 +82,18 @@ public partial class CoreConfigV2rayService }); } - v2rayConfig.dns = dnsItem; + _coreConfig.dns = dnsItem; } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenDnsServers(ProfileItem? node, Dns4Ray dnsItem, SimpleDNSItem simpleDNSItem) + private void FillDnsServers(Dns4Ray dnsItem) { + var node = context.Node; + var simpleDNSItem = context.SimpleDnsItem; static List ParseDnsAddresses(string? dnsInput, string defaultAddress) { var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';') @@ -197,9 +197,9 @@ public partial class CoreConfigV2rayService } } - var routing = await ConfigHandler.GetDefaultRouting(_config); + var routing = context.RoutingItem; List? rules = null; - rules = JsonUtils.Deserialize>(routing.RuleSet) ?? []; + rules = JsonUtils.Deserialize>(routing?.RuleSet) ?? []; foreach (var item in rules) { if (!item.Enabled || item.Domain is null || item.Domain.Count == 0) @@ -251,22 +251,9 @@ public partial class CoreConfigV2rayService directDomainList.Add(node.Address); } - if (node?.Subid is not null) + if (context.ProtectDomainList.Count > 0) { - var subItem = await AppManager.Instance.GetSubItem(node.Subid); - if (subItem is not null) - { - foreach (var profile in new[] { subItem.PrevProfile, subItem.NextProfile }) - { - var profileNode = await AppManager.Instance.GetProfileItemViaRemarks(profile); - if (profileNode is not null - && Global.XraySupportConfigType.Contains(profileNode.ConfigType) - && Utils.IsDomain(profileNode.Address)) - { - directDomainList.Add(profileNode.Address); - } - } - } + directDomainList.AddRange(context.ProtectDomainList); } dnsItem.servers ??= []; @@ -300,15 +287,14 @@ public partial class CoreConfigV2rayService var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress; dnsItem.servers.AddRange(defaultDnsServers); - - return 0; } - private async Task GenDnsHosts(Dns4Ray dnsItem, SimpleDNSItem simpleDNSItem) + private void FillDnsHosts(Dns4Ray dnsItem) { + var simpleDNSItem = context.SimpleDnsItem; if (simpleDNSItem.AddCommonHosts == false && simpleDNSItem.UseSystemHosts == false && simpleDNSItem.Hosts.IsNullOrEmpty()) { - return await Task.FromResult(0); + return; } dnsItem.hosts ??= new Dictionary(); if (simpleDNSItem.AddCommonHosts == true) @@ -337,14 +323,13 @@ public partial class CoreConfigV2rayService { dnsItem.hosts[kvp.Key] = kvp.Value; } - return await Task.FromResult(0); } - private async Task GenDnsCompatible(ProfileItem? node, V2rayConfig v2rayConfig) + private void GenDnsCustom() { try { - var item = await AppManager.Instance.GetDNSItem(ECoreType.Xray); + var item = context.RawDnsItem; var normalDNS = item?.NormalDNS; var domainStrategy4Freedom = item?.DomainStrategy4Freedom; if (normalDNS.IsNullOrEmpty()) @@ -355,7 +340,7 @@ public partial class CoreConfigV2rayService //Outbound Freedom domainStrategy if (domainStrategy4Freedom.IsNotEmpty()) { - var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); + var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); if (outbound != null) { outbound.settings = new(); @@ -410,63 +395,38 @@ public partial class CoreConfigV2rayService } } - await GenDnsDomainsCompatible(node, obj, item); + FillDnsDomainsCustom(obj); - v2rayConfig.dns = JsonUtils.Deserialize(JsonUtils.Serialize(obj)); + _coreConfig.dns = JsonUtils.Deserialize(JsonUtils.Serialize(obj)); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenDnsDomainsCompatible(ProfileItem? node, JsonNode dns, DNSItem? dnsItem) + private void FillDnsDomainsCustom(JsonNode dns) { - if (node == null) - { - return 0; - } + var node = context.Node; var servers = dns["servers"]; - if (servers != null) + if (servers == null) { - var domainList = new List(); - if (Utils.IsDomain(node.Address)) - { - domainList.Add(node.Address); - } - var subItem = await AppManager.Instance.GetSubItem(node.Subid); - if (subItem is not null) - { - // Previous proxy - var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); - if (prevNode is not null - && Global.SingboxSupportConfigType.Contains(prevNode.ConfigType) - && Utils.IsDomain(prevNode.Address)) - { - domainList.Add(prevNode.Address); - } - - // Next proxy - var nextNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.NextProfile); - if (nextNode is not null - && Global.SingboxSupportConfigType.Contains(nextNode.ConfigType) - && Utils.IsDomain(nextNode.Address)) - { - domainList.Add(nextNode.Address); - } - } - if (domainList.Count > 0) - { - var dnsServer = new DnsServer4Ray() - { - address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress, - skipFallback = true, - domains = domainList - }; - servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer)); - } + return; } - return await Task.FromResult(0); + + var domainList = context.ProtectDomainList; + if (domainList.Count <= 0) + { + return; + } + + var dnsItem = context.RawDnsItem; + var dnsServer = new DnsServer4Ray() + { + address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress, + skipFallback = true, + domains = domainList.ToList(), + }; + servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer)); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs index 2cbdfe88..18771183 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs @@ -2,35 +2,36 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenInbounds(V2rayConfig v2rayConfig) + private void GenInbounds() { try { + var config = context.AppConfig; var listen = "0.0.0.0"; - v2rayConfig.inbounds = []; + _coreConfig.inbounds = []; - var inbound = GetInbound(_config.Inbound.First(), EInboundProtocol.socks, true); - v2rayConfig.inbounds.Add(inbound); + var inbound = BuildInbound(config.Inbound.First(), EInboundProtocol.socks, true); + _coreConfig.inbounds.Add(inbound); - if (_config.Inbound.First().SecondLocalPortEnabled) + if (config.Inbound.First().SecondLocalPortEnabled) { - var inbound2 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks2, true); - v2rayConfig.inbounds.Add(inbound2); + var inbound2 = BuildInbound(config.Inbound.First(), EInboundProtocol.socks2, true); + _coreConfig.inbounds.Add(inbound2); } - if (_config.Inbound.First().AllowLANConn) + if (config.Inbound.First().AllowLANConn) { - if (_config.Inbound.First().NewPort4LAN) + if (config.Inbound.First().NewPort4LAN) { - var inbound3 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks3, true); + var inbound3 = BuildInbound(config.Inbound.First(), EInboundProtocol.socks3, true); inbound3.listen = listen; - v2rayConfig.inbounds.Add(inbound3); + _coreConfig.inbounds.Add(inbound3); //auth - if (_config.Inbound.First().User.IsNotEmpty() && _config.Inbound.First().Pass.IsNotEmpty()) + if (config.Inbound.First().User.IsNotEmpty() && config.Inbound.First().Pass.IsNotEmpty()) { inbound3.settings.auth = "password"; - inbound3.settings.accounts = new List { new AccountsItem4Ray() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } }; + inbound3.settings.accounts = new List { new() { user = config.Inbound.First().User, pass = config.Inbound.First().Pass } }; } } else @@ -43,10 +44,9 @@ public partial class CoreConfigV2rayService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks) + private Inbounds4Ray BuildInbound(InItem inItem, EInboundProtocol protocol, bool bSocks) { var result = EmbedUtils.GetEmbedText(Global.V2raySampleInbound); if (result.IsNullOrEmpty()) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs index 5b9344fb..10cae6f1 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs @@ -2,28 +2,28 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenLog(V2rayConfig v2rayConfig) + private void GenLog() { try { - if (_config.CoreBasicItem.LogEnabled) + var config = context.AppConfig; + if (config.CoreBasicItem.LogEnabled) { var dtNow = DateTime.Now; - v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel; - v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt"); - v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt"); + _coreConfig.log.loglevel = config.CoreBasicItem.Loglevel; + _coreConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt"); + _coreConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt"); } else { - v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel; - v2rayConfig.log.access = null; - v2rayConfig.log.error = null; + _coreConfig.log.loglevel = config.CoreBasicItem.Loglevel; + _coreConfig.log.access = null; + _coreConfig.log.error = null; } } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 7f9c26ca..be41609d 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -2,12 +2,96 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenOutbound(ProfileItem node, Outbounds4Ray outbound) + private void GenOutbounds() + { + var proxyOutboundList = BuildAllProxyOutbounds(); + _coreConfig.outbounds.InsertRange(0, proxyOutboundList); + if (proxyOutboundList.Count(n => n.tag.StartsWith(Global.ProxyTag)) > 1) + { + var multipleLoad = context.Node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + GenObservatory(multipleLoad); + GenBalancer(multipleLoad); + } + } + + private List BuildAllProxyOutbounds(string baseTagName = Global.ProxyTag) + { + var proxyOutboundList = new List(); + var node = context.Node; + if (node.ConfigType.IsGroupType()) + { + proxyOutboundList.AddRange(BuildGroupProxyOutbounds(baseTagName)); + } + else + { + proxyOutboundList.Add(BuildProxyOutbound(baseTagName)); + } + + if (context.AppConfig.CoreBasicItem.EnableFragment) + { + var fragmentOutbound = new Outbounds4Ray + { + protocol = "freedom", + tag = $"frag-{Global.ProxyTag}", + settings = new() + { + fragment = new() + { + packets = context.AppConfig.Fragment4RayItem?.Packets, + length = context.AppConfig.Fragment4RayItem?.Length, + interval = context.AppConfig.Fragment4RayItem?.Interval + } + } + }; + var actOutboundWithTlsList = + proxyOutboundList.Where(n => n.streamSettings?.security.IsNullOrEmpty() == false + && (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true)); + foreach (var outbound in actOutboundWithTlsList) + { + var fragmentOutboundClone = JsonUtils.DeepCopy(fragmentOutbound); + fragmentOutboundClone.tag = $"frag-{outbound.tag}"; + outbound.streamSettings.sockopt = new() + { + dialerProxy = fragmentOutboundClone.tag + }; + proxyOutboundList.Add(fragmentOutboundClone); + } + } + return proxyOutboundList; + } + + private List BuildGroupProxyOutbounds(string baseTagName = Global.ProxyTag) + { + var proxyOutboundList = new List(); + var node = context.Node; + switch (node.ConfigType) + { + case EConfigType.PolicyGroup: + proxyOutboundList.AddRange(BuildOutboundsList(baseTagName)); + break; + case EConfigType.ProxyChain: + proxyOutboundList.AddRange(BuildChainOutboundsList(baseTagName)); + break; + } + return proxyOutboundList; + } + + private Outbounds4Ray BuildProxyOutbound(string baseTagName = Global.ProxyTag) + { + var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); + var outbound = JsonUtils.Deserialize(txtOutbound); + FillOutbound(outbound); + outbound.tag = baseTagName; + return outbound; + } + + private void FillOutbound(Outbounds4Ray outbound) { try { + var node = context.Node; var protocolExtra = node.GetProtocolExtra(); - var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; + var muxEnabled = node.MuxEnabled ?? context.AppConfig.CoreBasicItem.MuxEnabled; switch (node.ConfigType) { case EConfigType.VMess: @@ -48,7 +132,7 @@ public partial class CoreConfigV2rayService usersItem.security = Global.DefaultSecurity; } - await GenOutboundMux(node, outbound, muxEnabled, muxEnabled); + FillOutboundMux(outbound, muxEnabled, muxEnabled); outbound.settings.servers = null; break; @@ -74,7 +158,7 @@ public partial class CoreConfigV2rayService serversItem.ota = false; serversItem.level = 1; - await GenOutboundMux(node, outbound); + FillOutboundMux(outbound); outbound.settings.vnext = null; break; @@ -110,7 +194,7 @@ public partial class CoreConfigV2rayService serversItem.users = new List() { socksUsersItem }; } - await GenOutboundMux(node, outbound); + FillOutboundMux(outbound); outbound.settings.vnext = null; break; @@ -150,7 +234,7 @@ public partial class CoreConfigV2rayService } else { - await GenOutboundMux(node, outbound, false, muxEnabled); + FillOutboundMux(outbound, false, muxEnabled); } outbound.settings.servers = null; break; @@ -174,7 +258,7 @@ public partial class CoreConfigV2rayService serversItem.ota = false; serversItem.level = 1; - await GenOutboundMux(node, outbound); + FillOutboundMux(outbound); outbound.settings.vnext = null; break; @@ -223,16 +307,15 @@ public partial class CoreConfigV2rayService { outbound.protocol = "hysteria"; } - await GenBoundStreamSettings(node, outbound); + FillBoundStreamSettings(outbound); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabledTCP = false, bool enabledUDP = false) + private void FillOutboundMux(Outbounds4Ray outbound, bool enabledTCP = false, bool enabledUDP = false) { try { @@ -242,26 +325,27 @@ public partial class CoreConfigV2rayService if (enabledTCP) { outbound.mux.enabled = true; - outbound.mux.concurrency = _config.Mux4RayItem.Concurrency; + outbound.mux.concurrency = context.AppConfig.Mux4RayItem.Concurrency; } else if (enabledUDP) { outbound.mux.enabled = true; - outbound.mux.xudpConcurrency = _config.Mux4RayItem.XudpConcurrency; - outbound.mux.xudpProxyUDP443 = _config.Mux4RayItem.XudpProxyUDP443; + outbound.mux.xudpConcurrency = context.AppConfig.Mux4RayItem.XudpConcurrency; + outbound.mux.xudpProxyUDP443 = context.AppConfig.Mux4RayItem.XudpProxyUDP443; } } catch (Exception ex) { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private async Task GenBoundStreamSettings(ProfileItem node, Outbounds4Ray outbound) + private void FillBoundStreamSettings(Outbounds4Ray outbound) { try { + var node = context.Node; + var config = context.AppConfig; var streamSettings = outbound.streamSettings; var network = node.GetNetwork(); if (node.ConfigType == EConfigType.Hysteria2) @@ -273,15 +357,15 @@ public partial class CoreConfigV2rayService var path = node.Path.TrimEx(); var sni = node.Sni.TrimEx(); var useragent = ""; - if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty()) + if (!config.CoreBasicItem.DefUserAgent.IsNullOrEmpty()) { try { - useragent = Global.UserAgentTexts[_config.CoreBasicItem.DefUserAgent]; + useragent = Global.UserAgentTexts[config.CoreBasicItem.DefUserAgent]; } catch (KeyNotFoundException) { - useragent = _config.CoreBasicItem.DefUserAgent; + useragent = config.CoreBasicItem.DefUserAgent; } } @@ -292,9 +376,9 @@ public partial class CoreConfigV2rayService TlsSettings4Ray tlsSettings = new() { - allowInsecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), + allowInsecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), alpn = node.GetAlpn(), - fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint, + fingerprint = node.Fingerprint.IsNullOrEmpty() ? config.CoreBasicItem.DefFingerprint : node.Fingerprint, echConfigList = node.EchConfigList.NullIfEmpty(), echForceQuery = node.EchForceQuery.NullIfEmpty() }; @@ -338,7 +422,7 @@ public partial class CoreConfigV2rayService TlsSettings4Ray realitySettings = new() { - fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint, + fingerprint = node.Fingerprint.IsNullOrEmpty() ? config.CoreBasicItem.DefFingerprint : node.Fingerprint, serverName = sni, publicKey = node.PublicKey, shortId = node.ShortId, @@ -356,16 +440,16 @@ public partial class CoreConfigV2rayService case nameof(ETransport.kcp): KcpSettings4Ray kcpSettings = new() { - mtu = _config.KcpItem.Mtu, - tti = _config.KcpItem.Tti + mtu = config.KcpItem.Mtu, + tti = config.KcpItem.Tti }; - kcpSettings.uplinkCapacity = _config.KcpItem.UplinkCapacity; - kcpSettings.downlinkCapacity = _config.KcpItem.DownlinkCapacity; + kcpSettings.uplinkCapacity = config.KcpItem.UplinkCapacity; + kcpSettings.downlinkCapacity = config.KcpItem.DownlinkCapacity; - kcpSettings.congestion = _config.KcpItem.Congestion; - kcpSettings.readBufferSize = _config.KcpItem.ReadBufferSize; - kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize; + kcpSettings.congestion = config.KcpItem.Congestion; + kcpSettings.readBufferSize = config.KcpItem.ReadBufferSize; + kcpSettings.writeBufferSize = config.KcpItem.WriteBufferSize; streamSettings.finalmask ??= new(); if (Global.KcpHeaderMaskMap.TryGetValue(node.HeaderType, out var header)) { @@ -454,7 +538,7 @@ public partial class CoreConfigV2rayService } streamSettings.xhttpSettings = xhttpSettings; - await GenOutboundMux(node, outbound); + FillOutboundMux(outbound); break; //h2 @@ -501,10 +585,10 @@ public partial class CoreConfigV2rayService authority = host.NullIfEmpty(), serviceName = path, multiMode = node.HeaderType == Global.GrpcMultiMode, - idle_timeout = _config.GrpcItem.IdleTimeout, - health_check_timeout = _config.GrpcItem.HealthCheckTimeout, - permit_without_stream = _config.GrpcItem.PermitWithoutStream, - initial_windows_size = _config.GrpcItem.InitialWindowsSize, + idle_timeout = config.GrpcItem.IdleTimeout, + health_check_timeout = config.GrpcItem.HealthCheckTimeout, + permit_without_stream = config.GrpcItem.PermitWithoutStream, + initial_windows_size = config.GrpcItem.InitialWindowsSize, }; streamSettings.grpcSettings = grpcSettings; break; @@ -514,14 +598,14 @@ public partial class CoreConfigV2rayService var ports = protocolExtra?.Ports; int? upMbps = protocolExtra?.UpMbps is { } su and >= 0 ? su - : _config.HysteriaItem.UpMbps; + : config.HysteriaItem.UpMbps; int? downMbps = protocolExtra?.DownMbps is { } sd and >= 0 ? sd - : _config.HysteriaItem.UpMbps; + : config.HysteriaItem.UpMbps; var hopInterval = !protocolExtra.HopInterval.IsNullOrEmpty() ? protocolExtra.HopInterval - : (_config.HysteriaItem.HopInterval >= 5 - ? _config.HysteriaItem.HopInterval + : (config.HysteriaItem.HopInterval >= 5 + ? config.HysteriaItem.HopInterval : Global.Hysteria2DefaultHopInt).ToString(); HysteriaUdpHop4Ray? udpHop = null; if (!ports.IsNullOrEmpty() && @@ -592,410 +676,109 @@ public partial class CoreConfigV2rayService { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenGroupOutbound(ProfileItem node, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag, bool ignoreOriginChain = false) + private List BuildOutboundsList(string baseTagName = Global.ProxyTag) { - try + var nodes = new List(); + foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) { - if (!node.ConfigType.IsGroupType()) + if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) { - return -1; - } - var hasCycle = await GroupProfileManager.HasCycle(node); - if (hasCycle) - { - return -1; - } - - var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); - if (childProfiles.Count <= 0) - { - return -1; - } - switch (node.ConfigType) - { - case EConfigType.PolicyGroup: - if (ignoreOriginChain) - { - await GenOutboundsList(childProfiles, v2rayConfig, baseTagName); - } - else - { - await GenOutboundsListWithChain(childProfiles, v2rayConfig, baseTagName); - } - break; - - case EConfigType.ProxyChain: - await GenChainOutboundsList(childProfiles, v2rayConfig, baseTagName); - break; - - default: - break; - } - - //add balancers - if (node.ConfigType == EConfigType.PolicyGroup) - { - var multipleLoad = profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing; - await GenObservatory(v2rayConfig, multipleLoad, baseTagName); - await GenBalancer(v2rayConfig, multipleLoad, baseTagName); + nodes.Add(node); } } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - return await Task.FromResult(0); - } - - private async Task GenMoreOutbounds(ProfileItem node, V2rayConfig v2rayConfig) - { - //fragment proxy - if (_config.CoreBasicItem.EnableFragment - && v2rayConfig.outbounds.First().streamSettings?.security.IsNullOrEmpty() == false) - { - var fragmentOutbound = new Outbounds4Ray - { - protocol = "freedom", - tag = $"frag-{Global.ProxyTag}", - settings = new() - { - fragment = new() - { - packets = _config.Fragment4RayItem?.Packets, - length = _config.Fragment4RayItem?.Length, - interval = _config.Fragment4RayItem?.Interval - } - } - }; - - v2rayConfig.outbounds.Add(fragmentOutbound); - v2rayConfig.outbounds.First().streamSettings.sockopt = new() - { - dialerProxy = fragmentOutbound.tag - }; - return 0; - } - - if (node.Subid.IsNullOrEmpty()) - { - return 0; - } - try - { - var subItem = await AppManager.Instance.GetSubItem(node.Subid); - if (subItem is null) - { - return 0; - } - - //current proxy - var outbound = v2rayConfig.outbounds.First(); - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - - //Previous proxy - var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); - string? prevOutboundTag = null; - if (prevNode is not null - && Global.XraySupportConfigType.Contains(prevNode.ConfigType)) - { - var prevOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(prevNode, prevOutbound); - prevOutboundTag = $"prev-{Global.ProxyTag}"; - prevOutbound.tag = prevOutboundTag; - v2rayConfig.outbounds.Add(prevOutbound); - } - var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag); - - if (nextOutbound is not null) - { - v2rayConfig.outbounds.Insert(0, nextOutbound); - } - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - - return 0; - } - - private async Task GenOutboundsListWithChain(List nodes, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag) - { - try - { - // Get template and initialize list - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - if (txtOutbound.IsNullOrEmpty()) - { - return 0; - } - - var resultOutbounds = new List(); - var prevOutbounds = new List(); // Separate list for prev outbounds and fragment - - // Cache for chain proxies to avoid duplicate generation - var nextProxyCache = new Dictionary(); - var prevProxyTags = new Dictionary(); // Map from profile name to tag - var prevIndex = 0; // Index for prev outbounds - - // Process nodes - var index = 0; - foreach (var node in nodes) - { - index++; - - if (node.ConfigType.IsGroupType()) - { - var (childProfiles, _) = await GroupProfileManager.GetChildProfileItems(node); - if (childProfiles.Count <= 0) - { - continue; - } - var childBaseTagName = $"{baseTagName}-{index}"; - var ret = node.ConfigType switch - { - EConfigType.PolicyGroup => - await GenOutboundsListWithChain(childProfiles, v2rayConfig, childBaseTagName), - EConfigType.ProxyChain => - await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName), - _ => throw new NotImplementedException() - }; - continue; - } - - // Handle proxy chain - string? prevTag = null; - var currentOutbound = JsonUtils.Deserialize(txtOutbound); - var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null); - if (nextOutbound != null) - { - nextOutbound = JsonUtils.DeepCopy(nextOutbound); - } - - var subItem = await AppManager.Instance.GetSubItem(node.Subid); - - // current proxy - await GenOutbound(node, currentOutbound); - currentOutbound.tag = $"{baseTagName}-{index}"; - - if (!node.Subid.IsNullOrEmpty()) - { - if (prevProxyTags.TryGetValue(node.Subid, out var value)) - { - prevTag = value; // maybe null - } - else - { - var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); - if (prevNode is not null - && Global.XraySupportConfigType.Contains(prevNode.ConfigType)) - { - var prevOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(prevNode, prevOutbound); - prevTag = $"prev-{baseTagName}-{++prevIndex}"; - prevOutbound.tag = prevTag; - prevOutbounds.Add(prevOutbound); - } - prevProxyTags[node.Subid] = prevTag; - } - - nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound); - if (!nextProxyCache.ContainsKey(node.Subid)) - { - nextProxyCache[node.Subid] = nextOutbound; - } - } - - if (nextOutbound is not null) - { - resultOutbounds.Add(nextOutbound); - } - resultOutbounds.Add(currentOutbound); - } - - // Merge results: first the main chain outbounds, then other outbounds, and finally utility outbounds - if (baseTagName == Global.ProxyTag) - { - resultOutbounds.AddRange(prevOutbounds); - resultOutbounds.AddRange(v2rayConfig.outbounds); - v2rayConfig.outbounds = resultOutbounds; - } - else - { - v2rayConfig.outbounds.AddRange(prevOutbounds); - v2rayConfig.outbounds.AddRange(resultOutbounds); - } - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - - return 0; - } - - /// - /// Generates a chained outbound configuration for the given subItem and outbound. - /// The outbound's tag must be set before calling this method. - /// Returns the next proxy's outbound configuration, which may be null if no next proxy exists. - /// - /// The subscription item containing proxy chain information. - /// The current outbound configuration. Its tag must be set before calling this method. - /// The tag of the previous outbound in the chain, if any. - /// The outbound for the next proxy in the chain, if already created. If null, will be created inside. - /// - /// The outbound configuration for the next proxy in the chain, or null if no next proxy exists. - /// - private async Task GenChainOutbounds(SubItem subItem, Outbounds4Ray outbound, string? prevOutboundTag, Outbounds4Ray? nextOutbound = null) - { - try - { - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - - if (!prevOutboundTag.IsNullOrEmpty()) - { - outbound.streamSettings.sockopt = new() - { - dialerProxy = prevOutboundTag - }; - } - - // Next proxy - var nextNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.NextProfile); - if (nextNode is not null - && Global.XraySupportConfigType.Contains(nextNode.ConfigType)) - { - if (nextOutbound == null) - { - nextOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(nextNode, nextOutbound); - } - nextOutbound.tag = outbound.tag; - - outbound.tag = $"mid-{outbound.tag}"; - nextOutbound.streamSettings.sockopt = new() - { - dialerProxy = outbound.tag - }; - } - return nextOutbound; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - return null; - } - - private async Task GenOutboundsList(List nodes, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag) - { var resultOutbounds = new List(); for (var i = 0; i < nodes.Count; i++) { var node = nodes[i]; - if (node == null) - { - continue; - } + var currentTag = baseTagName + (i + 1).ToString(); if (node.ConfigType.IsGroupType()) { - var (childProfiles, _) = await GroupProfileManager.GetChildProfileItems(node); - if (childProfiles.Count <= 0) - { - continue; - } - var childBaseTagName = $"{baseTagName}-{i + 1}"; - var ret = node.ConfigType switch - { - EConfigType.PolicyGroup => - await GenOutboundsListWithChain(childProfiles, v2rayConfig, childBaseTagName), - EConfigType.ProxyChain => - await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName), - _ => throw new NotImplementedException() - }; + var childProfiles = new CoreConfigV2rayService(context with { Node = node, }).BuildGroupProxyOutbounds(currentTag); + resultOutbounds.AddRange(childProfiles); continue; } - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - if (txtOutbound.IsNullOrEmpty()) - { - break; - } - var outbound = JsonUtils.Deserialize(txtOutbound); - var result = await GenOutbound(node, outbound); - if (result != 0) - { - break; - } - outbound.tag = baseTagName + (i + 1).ToString(); + var outbound = new CoreConfigV2rayService(context with { Node = node, }).BuildProxyOutbound(); + outbound.tag = currentTag; resultOutbounds.Add(outbound); } - if (baseTagName == Global.ProxyTag) - { - resultOutbounds.AddRange(v2rayConfig.outbounds); - v2rayConfig.outbounds = resultOutbounds; - } - else - { - v2rayConfig.outbounds.AddRange(resultOutbounds); - } - return await Task.FromResult(0); + return resultOutbounds; } - private async Task GenChainOutboundsList(List nodes, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag) + private List BuildChainOutboundsList(string baseTagName = Global.ProxyTag) { + var nodes = new List(); + foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) + { + if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) + { + nodes.Add(node); + } + } // Based on actual network flow instead of data packets var nodesReverse = nodes.AsEnumerable().Reverse().ToList(); var resultOutbounds = new List(); for (var i = 0; i < nodesReverse.Count; i++) { var node = nodesReverse[i]; - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - if (txtOutbound.IsNullOrEmpty()) + var currentTag = i == 0 ? baseTagName : "chain-" + baseTagName + i.ToString(); + var dialerProxyTag = i != nodesReverse.Count - 1 ? "chain-" + baseTagName + (i + 1).ToString() : null; + if (node.ConfigType.IsGroupType()) { - break; + var childProfiles = new CoreConfigV2rayService(context with { Node = node, }).BuildGroupProxyOutbounds(currentTag); + if (!dialerProxyTag.IsNullOrEmpty()) + { + var chainEndNodes = + childProfiles.Where(n => n?.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true); + foreach (var chainEndNode in chainEndNodes) + { + chainEndNode.streamSettings.sockopt = new() + { + dialerProxy = dialerProxyTag + }; + } + } + if (i != 0) + { + var chainStartNodes = childProfiles.Where(n => n.tag.StartsWith(currentTag)).ToList(); + var existedChainNodes = JsonUtils.DeepCopy(resultOutbounds); + resultOutbounds.Clear(); + foreach (var chainStartNode in chainStartNodes) + { + var existedChainNodesClone = JsonUtils.DeepCopy(existedChainNodes); + for (var j = 0; j < existedChainNodesClone.Count; j++) + { + var existedChainNode = existedChainNodesClone[j]; + var cloneTag = $"{existedChainNode.tag}-clone{j}"; + existedChainNode.tag = cloneTag; + var previousDialerProxyTag = existedChainNode.streamSettings?.sockopt?.dialerProxy; + existedChainNode.streamSettings.sockopt = new() + { + dialerProxy = (previousDialerProxyTag == currentTag) ? chainStartNode.tag : existedChainNodesClone[j + 1].tag + }; + resultOutbounds.Add(existedChainNode); + } + } + } + resultOutbounds.AddRange(childProfiles); + continue; } - var outbound = JsonUtils.Deserialize(txtOutbound); - var result = await GenOutbound(node, outbound); + var outbound = new CoreConfigV2rayService(context with { Node = node, }).BuildProxyOutbound(); - if (result != 0) - { - break; - } + outbound.tag = currentTag; - if (i == 0) - { - outbound.tag = baseTagName; - } - else - { - // avoid v2ray observe - outbound.tag = "chain-" + baseTagName + i.ToString(); - } - - if (i != nodesReverse.Count - 1) + if (!dialerProxyTag.IsNullOrEmpty()) { outbound.streamSettings.sockopt = new() { - dialerProxy = "chain-" + baseTagName + (i + 1).ToString() + dialerProxy = dialerProxyTag }; } resultOutbounds.Add(outbound); } - if (baseTagName == Global.ProxyTag) - { - resultOutbounds.AddRange(v2rayConfig.outbounds); - v2rayConfig.outbounds = resultOutbounds; - } - else - { - v2rayConfig.outbounds.AddRange(resultOutbounds); - } - - return await Task.FromResult(0); + return resultOutbounds; } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs index 8691abb1..2bac1f37 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs @@ -2,20 +2,20 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenRouting(V2rayConfig v2rayConfig) + private void GenRouting() { try { - if (v2rayConfig.routing?.rules != null) + if (_coreConfig.routing?.rules != null) { - v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy; + _coreConfig.routing.domainStrategy = context.AppConfig.RoutingBasicItem.DomainStrategy; - var routing = await ConfigHandler.GetDefaultRouting(_config); + var routing = context.RoutingItem; if (routing != null) { if (routing.DomainStrategy.IsNotEmpty()) { - v2rayConfig.routing.domainStrategy = routing.DomainStrategy; + _coreConfig.routing.domainStrategy = routing.DomainStrategy; } var rules = JsonUtils.Deserialize>(routing.RuleSet); foreach (var item in rules) @@ -31,7 +31,18 @@ public partial class CoreConfigV2rayService } var item2 = JsonUtils.Deserialize(JsonUtils.Serialize(item)); - await GenRoutingUserRule(item2, v2rayConfig); + GenRoutingUserRule(item2); + } + } + var balancerTagList = _coreConfig.routing.balancers + ?.Select(p => p.tag) + .ToList() ?? []; + if (balancerTagList.Count > 0) + { + foreach (var rulesItem in _coreConfig.routing.rules.Where(r => balancerTagList.Contains(r.outboundTag))) + { + rulesItem.balancerTag = rulesItem.outboundTag; + rulesItem.outboundTag = null; } } } @@ -40,95 +51,94 @@ public partial class CoreConfigV2rayService { Logging.SaveLog(_tag, ex); } - return 0; } - private async Task GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig) + private void GenRoutingUserRule(RulesItem4Ray? userRule) { try { - if (rule == null) + if (userRule == null) { - return 0; + return; } - rule.outboundTag = await GenRoutingUserRuleOutbound(rule.outboundTag, v2rayConfig); + userRule.outboundTag = GenRoutingUserRuleOutbound(userRule.outboundTag ?? Global.ProxyTag); - if (rule.port.IsNullOrEmpty()) + if (userRule.port.IsNullOrEmpty()) { - rule.port = null; + userRule.port = null; } - if (rule.network.IsNullOrEmpty()) + if (userRule.network.IsNullOrEmpty()) { - rule.network = null; + userRule.network = null; } - if (rule.domain?.Count == 0) + if (userRule.domain?.Count == 0) { - rule.domain = null; + userRule.domain = null; } - if (rule.ip?.Count == 0) + if (userRule.ip?.Count == 0) { - rule.ip = null; + userRule.ip = null; } - if (rule.protocol?.Count == 0) + if (userRule.protocol?.Count == 0) { - rule.protocol = null; + userRule.protocol = null; } - if (rule.inboundTag?.Count == 0) + if (userRule.inboundTag?.Count == 0) { - rule.inboundTag = null; + userRule.inboundTag = null; } - if (rule.process?.Count == 0) + if (userRule.process?.Count == 0) { - rule.process = null; + userRule.process = null; } var hasDomainIp = false; - if (rule.domain?.Count > 0) + if (userRule.domain?.Count > 0) { - var it = JsonUtils.DeepCopy(rule); + var it = JsonUtils.DeepCopy(userRule); it.ip = null; it.process = null; it.type = "field"; for (var k = it.domain.Count - 1; k >= 0; k--) { - if (it.domain[k].StartsWith("#")) + if (it.domain[k].StartsWith('#')) { it.domain.RemoveAt(k); } it.domain[k] = it.domain[k].Replace(Global.RoutingRuleComma, ","); } - v2rayConfig.routing.rules.Add(it); + _coreConfig.routing.rules.Add(it); hasDomainIp = true; } - if (rule.ip?.Count > 0) + if (userRule.ip?.Count > 0) { - var it = JsonUtils.DeepCopy(rule); + var it = JsonUtils.DeepCopy(userRule); it.domain = null; it.process = null; it.type = "field"; - v2rayConfig.routing.rules.Add(it); + _coreConfig.routing.rules.Add(it); hasDomainIp = true; } - if (rule.process?.Count > 0) + if (userRule.process?.Count > 0) { - var it = JsonUtils.DeepCopy(rule); + var it = JsonUtils.DeepCopy(userRule); it.domain = null; it.ip = null; it.type = "field"; - v2rayConfig.routing.rules.Add(it); + _coreConfig.routing.rules.Add(it); hasDomainIp = true; } if (!hasDomainIp) { - if (rule.port.IsNotEmpty() - || rule.protocol?.Count > 0 - || rule.inboundTag?.Count > 0 - || rule.network != null + if (userRule.port.IsNotEmpty() + || userRule.protocol?.Count > 0 + || userRule.inboundTag?.Count > 0 + || userRule.network != null ) { - var it = JsonUtils.DeepCopy(rule); + var it = JsonUtils.DeepCopy(userRule); it.type = "field"; - v2rayConfig.routing.rules.Add(it); + _coreConfig.routing.rules.Add(it); } } } @@ -136,17 +146,16 @@ public partial class CoreConfigV2rayService { Logging.SaveLog(_tag, ex); } - return await Task.FromResult(0); } - private async Task GenRoutingUserRuleOutbound(string outboundTag, V2rayConfig v2rayConfig) + private string GenRoutingUserRuleOutbound(string outboundTag) { if (Global.OutboundTags.Contains(outboundTag)) { return outboundTag; } - var node = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag); + var node = context.AllProxiesMap.GetValueOrDefault($"remark:{outboundTag}"); if (node == null || (!Global.XraySupportConfigType.Contains(node.ConfigType) @@ -156,27 +165,20 @@ public partial class CoreConfigV2rayService } var tag = $"{node.IndexId}-{Global.ProxyTag}"; - if (v2rayConfig.outbounds.Any(p => p.tag == tag)) + if (_coreConfig.outbounds.Any(p => p.tag == tag)) { return tag; } - if (node.ConfigType.IsGroupType()) + var proxyOutbounds = new CoreConfigV2rayService(context with { Node = node, }).BuildAllProxyOutbounds(tag); + _coreConfig.outbounds.AddRange(proxyOutbounds); + if (proxyOutbounds.Count(n => n.tag.StartsWith(tag)) > 1) { - var ret = await GenGroupOutbound(node, v2rayConfig, tag); - if (ret == 0) - { - return tag; - } - return Global.ProxyTag; + var multipleLoad = node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + GenObservatory(multipleLoad, tag); + GenBalancer(multipleLoad, tag); } - var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound); - var outbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(node, outbound); - outbound.tag = tag; - v2rayConfig.outbounds.Add(outbound); - - return outbound.tag; + return tag; } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs index b2ec37b4..6b529f1f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs @@ -2,26 +2,26 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService { - private async Task GenStatistic(V2rayConfig v2rayConfig) + private void GenStatistic() { - if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed) + if (context.AppConfig.GuiItem.EnableStatistics || context.AppConfig.GuiItem.DisplayRealTimeSpeed) { var tag = EInboundProtocol.api.ToString(); Metrics4Ray apiObj = new(); Policy4Ray policyObj = new(); SystemPolicy4Ray policySystemSetting = new(); - v2rayConfig.stats = new Stats4Ray(); + _coreConfig.stats = new Stats4Ray(); apiObj.tag = tag; - v2rayConfig.metrics = apiObj; + _coreConfig.metrics = apiObj; policySystemSetting.statsOutboundDownlink = true; policySystemSetting.statsOutboundUplink = true; policyObj.system = policySystemSetting; - v2rayConfig.policy = policyObj; + _coreConfig.policy = policyObj; - if (!v2rayConfig.inbounds.Exists(item => item.tag == tag)) + if (!_coreConfig.inbounds.Exists(item => item.tag == tag)) { Inbounds4Ray apiInbound = new(); Inboundsettings4Ray apiInboundSettings = new(); @@ -31,10 +31,10 @@ public partial class CoreConfigV2rayService apiInbound.protocol = Global.InboundAPIProtocol; apiInboundSettings.address = Global.Loopback; apiInbound.settings = apiInboundSettings; - v2rayConfig.inbounds.Add(apiInbound); + _coreConfig.inbounds.Add(apiInbound); } - if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag)) + if (!_coreConfig.routing.rules.Exists(item => item.outboundTag == tag)) { RulesItem4Ray apiRoutingRule = new() { @@ -43,9 +43,8 @@ public partial class CoreConfigV2rayService type = "field" }; - v2rayConfig.routing.rules.Add(apiRoutingRule); + _coreConfig.routing.rules.Add(apiRoutingRule); } } - return await Task.FromResult(0); } } diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 2d838189..8b4e7eb0 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -801,7 +801,8 @@ public class ProfilesViewModel : MyReactiveObject if (blClipboard) { - var result = await CoreConfigHandler.GenerateClientConfig(item, null); + var context = await CoreConfigHandler.BuildCoreConfigContext(_config, item); + var result = await CoreConfigHandler.GenerateClientConfig(context, null); if (result.Success != true) { NoticeManager.Instance.Enqueue(result.Msg); @@ -824,7 +825,8 @@ public class ProfilesViewModel : MyReactiveObject { return; } - var result = await CoreConfigHandler.GenerateClientConfig(item, fileName); + var context = await CoreConfigHandler.BuildCoreConfigContext(_config, item); + var result = await CoreConfigHandler.GenerateClientConfig(context, fileName); if (result.Success != true) { NoticeManager.Instance.Enqueue(result.Msg); From b53101ce5803d7df8c844dcb3783ae5dedfc47ec Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 6 Feb 2026 14:47:29 +0800 Subject: [PATCH 2/6] Update tag naming --- .../Services/CoreConfig/Singbox/SingboxOutboundService.cs | 8 ++++---- .../Services/CoreConfig/V2ray/V2rayOutboundService.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index ad7b4ad6..4198acfa 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -556,7 +556,7 @@ public partial class CoreConfigSingboxService for (var i = 0; i < nodes.Count; i++) { var node = nodes[i]; - var currentTag = baseTagName + (i + 1).ToString(); + var currentTag = $"{baseTagName}-{i + 1}"; if (node.ConfigType.IsGroupType()) { @@ -587,8 +587,8 @@ public partial class CoreConfigSingboxService for (var i = 0; i < nodesReverse.Count; i++) { var node = nodesReverse[i]; - var currentTag = i == 0 ? baseTagName : "chain-" + baseTagName + i.ToString(); - var dialerProxyTag = i != nodesReverse.Count - 1 ? "chain-" + baseTagName + (i + 1).ToString() : null; + var currentTag = i == 0 ? baseTagName : $"chain-{baseTagName}-{i}"; + var dialerProxyTag = i != nodesReverse.Count - 1 ? $"chain-{baseTagName}-{i + 1}" : null; if (node.ConfigType.IsGroupType()) { var childProfiles = new CoreConfigSingboxService(context with { Node = node, }).BuildGroupProxyOutbounds(currentTag); @@ -612,7 +612,7 @@ public partial class CoreConfigSingboxService for (var j = 0; j < existedChainNodesClone.Count; j++) { var existedChainNode = existedChainNodesClone[j]; - var cloneTag = $"{existedChainNode.tag}-clone{j}"; + var cloneTag = $"{existedChainNode.tag}-clone-{j + 1}"; existedChainNode.tag = cloneTag; var previousDialerProxyTag = existedChainNode.detour; existedChainNode.detour = (previousDialerProxyTag == currentTag) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index be41609d..e50e4700 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -692,7 +692,7 @@ public partial class CoreConfigV2rayService for (var i = 0; i < nodes.Count; i++) { var node = nodes[i]; - var currentTag = baseTagName + (i + 1).ToString(); + var currentTag = $"{baseTagName}-{i + 1}"; if (node.ConfigType.IsGroupType()) { @@ -723,8 +723,8 @@ public partial class CoreConfigV2rayService for (var i = 0; i < nodesReverse.Count; i++) { var node = nodesReverse[i]; - var currentTag = i == 0 ? baseTagName : "chain-" + baseTagName + i.ToString(); - var dialerProxyTag = i != nodesReverse.Count - 1 ? "chain-" + baseTagName + (i + 1).ToString() : null; + var currentTag = i == 0 ? baseTagName : $"chain-{baseTagName}-{i}"; + var dialerProxyTag = i != nodesReverse.Count - 1 ? $"chain-{baseTagName}-{i + 1}" : null; if (node.ConfigType.IsGroupType()) { var childProfiles = new CoreConfigV2rayService(context with { Node = node, }).BuildGroupProxyOutbounds(currentTag); @@ -751,7 +751,7 @@ public partial class CoreConfigV2rayService for (var j = 0; j < existedChainNodesClone.Count; j++) { var existedChainNode = existedChainNodesClone[j]; - var cloneTag = $"{existedChainNode.tag}-clone{j}"; + var cloneTag = $"{existedChainNode.tag}-clone-{j + 1}"; existedChainNode.tag = cloneTag; var previousDialerProxyTag = existedChainNode.streamSettings?.sockopt?.dialerProxy; existedChainNode.streamSettings.sockopt = new() From a89471da926f3ecfa790f71991b201c04bebe893 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 6 Feb 2026 15:20:18 +0800 Subject: [PATCH 3/6] Support sing-box 1.11 DNS --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 7 ++++ .../CoreConfig/Singbox/SingboxDnsService.cs | 36 +++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index 0d0e3009..c1eaa3c8 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -254,6 +254,13 @@ public class Server4Sbox : BaseServer4Sbox // public List? path { get; set; } // hosts public Dictionary>? predefined { get; set; } + + // Deprecated in sing-box 1.12.0 , kept for backward compatibility + public string? address { get; set; } + public string? address_resolver { get; set; } + public string? address_strategy { get; set; } + public string? strategy { get; set; } + // Deprecated End } public class Experimental4Sbox diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index dfce64f5..00358a85 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -378,8 +378,15 @@ public partial class CoreConfigSingboxService return; } _coreConfig.dns = dns4Sbox; - - GenDnsProtectCustom(); + if (dns4Sbox.servers?.Count > 0 && + dns4Sbox.servers.First().address.IsNullOrEmpty()) + { + GenDnsProtectCustom(); + } + else + { + GenDnsProtectCustomLegacy(); + } } catch (Exception ex) { @@ -395,6 +402,16 @@ public partial class CoreConfigSingboxService dns4Sbox.rules ??= []; var tag = Global.SingboxLocalDNSTag; + dns4Sbox.rules.Insert(0, new() + { + server = tag, + clash_mode = ERuleMode.Direct.ToString() + }); + dns4Sbox.rules.Insert(0, new() + { + server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote", + clash_mode = ERuleMode.Global.ToString() + }); var finalDnsAddress = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress; @@ -407,6 +424,21 @@ public partial class CoreConfigSingboxService _coreConfig.dns = dns4Sbox; } + private void GenDnsProtectCustomLegacy() + { + GenDnsProtectCustom(); + + var localDnsServer = _coreConfig.dns?.servers?.FirstOrDefault(s => s.tag == Global.SingboxLocalDNSTag); + if (localDnsServer == null) + { + return; + } + localDnsServer.type = null; + localDnsServer.server = null; + var dnsItem = context.RawDnsItem; + localDnsServer.address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress; + } + private Rule4Sbox BuildProtectDomainRule() { return new() From f900ce7f3f2236f9130015c8e07c33a4a4ad47c5 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 6 Feb 2026 15:24:14 +0800 Subject: [PATCH 4/6] Fix --- .../ServiceLib/Handler/CoreConfigHandler.cs | 31 ++++---- .../CoreConfig/Singbox/SingboxDnsService.cs | 1 + .../Singbox/SingboxOutboundService.cs | 75 +++++++++++++++---- .../V2ray/CoreConfigV2rayService.cs | 33 ++++---- .../CoreConfig/V2ray/V2rayOutboundService.cs | 47 +++++++++--- 5 files changed, 130 insertions(+), 57 deletions(-) diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs index 432e9319..0db0b9b7 100644 --- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs @@ -95,13 +95,13 @@ public static class CoreConfigHandler { var result = new RetResult(); var context = await BuildCoreConfigContext(config, new()); - foreach (var serverTestItem in selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty())) + var ids = selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty()) + .Select(serverTestItem => serverTestItem.IndexId!) + .ToList(); + foreach (var id in ids) { - var node = await AppManager.Instance.GetProfileItem(serverTestItem.IndexId!); - if (node != null) - { - await FillNodeContext(context, node, false); - } + var node = await AppManager.Instance.GetProfileItem(id) ?? new(); + await FillNodeContext(context, node, false); } if (coreType == ECoreType.sing_box) { @@ -186,34 +186,37 @@ public static class CoreConfigHandler return node; } context.AllProxiesMap[node.IndexId] = node; + var newItems = new List { node }; + if (node.ConfigType.IsGroupType()) { var groupChildList = await GroupProfileManager.GetAllChildProfileItems(node); foreach (var childItem in groupChildList) { context.AllProxiesMap[childItem.IndexId] = childItem; + newItems.Add(childItem); } } - foreach (var profileItemPair in context.AllProxiesMap) + foreach (var item in newItems) { - var address = profileItemPair.Value.Address; + var address = item.Address; if (Utils.IsDomain(address)) { context.ProtectDomainList.Add(address); } - if (profileItemPair.Value.EchConfigList.IsNullOrEmpty()) + if (item.EchConfigList.IsNullOrEmpty()) { continue; } - var echQuerySni = profileItemPair.Value.Sni; - if (profileItemPair.Value.StreamSecurity == Global.StreamSecurity - && profileItemPair.Value.EchConfigList?.Contains("://") == true) + var echQuerySni = item.Sni; + if (item.StreamSecurity == Global.StreamSecurity + && item.EchConfigList?.Contains("://") == true) { - var idx = profileItemPair.Value.EchConfigList.IndexOf('+'); - echQuerySni = idx > 0 ? profileItemPair.Value.EchConfigList[..idx] : profileItemPair.Value.Sni; + var idx = item.EchConfigList.IndexOf('+'); + echQuerySni = idx > 0 ? item.EchConfigList[..idx] : item.Sni; } if (!Utils.IsDomain(echQuerySni)) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index 00358a85..9db73605 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -349,6 +349,7 @@ public partial class CoreConfigSingboxService { GenDnsServers(); _coreConfig.dns ??= new(); + _coreConfig.dns.rules ??= []; _coreConfig.dns.rules.Clear(); _coreConfig.dns.final = Global.SingboxDirectDNSTag; _coreConfig.route.default_domain_resolver = new() diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 4198acfa..2afc4f49 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -519,7 +519,7 @@ public partial class CoreConfigSingboxService var outUrltest = new Outbound4Sbox { type = "urltest", - tag = $"{Global.ProxyTag}-auto", + tag = $"{baseTagName}-auto", outbounds = proxyTags, interrupt_exist_connections = false, }; @@ -533,7 +533,7 @@ public partial class CoreConfigSingboxService var outSelector = new Outbound4Sbox { type = "selector", - tag = Global.ProxyTag, + tag = baseTagName, outbounds = JsonUtils.DeepCopy(proxyTags), interrupt_exist_connections = false, }; @@ -604,21 +604,39 @@ public partial class CoreConfigSingboxService if (i != 0) { var chainStartNodes = childProfiles.Where(n => n.tag.StartsWith(currentTag)).ToList(); - var existedChainNodes = JsonUtils.DeepCopy(resultOutbounds); - resultOutbounds.Clear(); - foreach (var chainStartNode in chainStartNodes) + if (chainStartNodes.Count == 1) { - var existedChainNodesClone = JsonUtils.DeepCopy(existedChainNodes); - for (var j = 0; j < existedChainNodesClone.Count; j++) + foreach (var existedChainEndNode in resultOutbounds.Where(n => n.detour == currentTag)) { - var existedChainNode = existedChainNodesClone[j]; - var cloneTag = $"{existedChainNode.tag}-clone-{j + 1}"; - existedChainNode.tag = cloneTag; - var previousDialerProxyTag = existedChainNode.detour; - existedChainNode.detour = (previousDialerProxyTag == currentTag) - ? chainStartNode.tag - : existedChainNodesClone[j + 1].tag; - resultOutbounds.Add(existedChainNode); + existedChainEndNode.detour = chainStartNodes.First().tag; + } + } + else if (chainStartNodes.Count > 1) + { + var existedChainNodes = CloneOutbounds(resultOutbounds); + resultOutbounds.Clear(); + var j = 0; + foreach (var chainStartNode in chainStartNodes) + { + var existedChainNodesClone = CloneOutbounds(existedChainNodes); + foreach (var existedChainNode in existedChainNodesClone) + { + var cloneTag = $"{existedChainNode.tag}-clone-{j + 1}"; + existedChainNode.tag = cloneTag; + } + for (var k = 0; k < existedChainNodesClone.Count; k++) + { + var existedChainNode = existedChainNodesClone[k]; + var previousDialerProxyTag = existedChainNode.detour; + var nextTag = k + 1 < existedChainNodesClone.Count + ? existedChainNodesClone[k + 1].tag + : chainStartNode.tag; + existedChainNode.detour = (previousDialerProxyTag == currentTag) + ? chainStartNode.tag + : nextTag; + resultOutbounds.Add(existedChainNode); + } + j++; } } } @@ -639,6 +657,33 @@ public partial class CoreConfigSingboxService return resultOutbounds; } + private static List CloneOutbounds(List source) + { + if (source is null || source.Count == 0) + { + return []; + } + + var result = new List(source.Count); + foreach (var item in source) + { + BaseServer4Sbox? clone = null; + if (item is Outbound4Sbox outbound) + { + clone = JsonUtils.DeepCopy(outbound); + } + else if (item is Endpoints4Sbox endpoint) + { + clone = JsonUtils.DeepCopy(endpoint); + } + if (clone is not null) + { + result.Add(clone); + } + } + return result; + } + private static void FillRangeProxy(List servers, SingboxConfig singboxConfig, bool prepend = true) { try diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs index a74d850a..762f5f4b 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs @@ -83,8 +83,8 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) return ret; } - var v2rayConfig = JsonUtils.Deserialize(result); - if (v2rayConfig == null) + _coreConfig = JsonUtils.Deserialize(result); + if (_coreConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; @@ -103,9 +103,9 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) } GenLog(); - v2rayConfig.inbounds.Clear(); - v2rayConfig.outbounds.Clear(); - v2rayConfig.routing.rules.Clear(); + _coreConfig.inbounds.Clear(); + _coreConfig.outbounds.Clear(); + _coreConfig.routing.rules.Clear(); var initPort = AppManager.Instance.GetLocalPort(EInboundProtocol.speedtest); @@ -159,13 +159,14 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) protocol = EInboundProtocol.mixed.ToString(), }; inbound.tag = inbound.protocol + inbound.port.ToString(); - v2rayConfig.inbounds.Add(inbound); + _coreConfig.inbounds.Add(inbound); var tag = Global.ProxyTag + inbound.port.ToString(); var isBalancer = false; //outbound - var proxyOutbounds = BuildAllProxyOutbounds(tag); - v2rayConfig.outbounds.AddRange(proxyOutbounds); + var proxyOutbounds = + new CoreConfigV2rayService(context with { Node = item }).BuildAllProxyOutbounds(tag); + _coreConfig.outbounds.AddRange(proxyOutbounds); if (proxyOutbounds.Count(n => n.tag.StartsWith(tag)) > 1) { isBalancer = true; @@ -186,12 +187,12 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) rule.balancerTag = tag; rule.outboundTag = null; } - v2rayConfig.routing.rules.Add(rule); + _coreConfig.routing.rules.Add(rule); } //ret.Msg =string.Format(ResUI.SuccessfulConfiguration"), node.getSummary()); ret.Success = true; - ret.Data = JsonUtils.Serialize(v2rayConfig); + ret.Data = JsonUtils.Serialize(_coreConfig); return ret; } catch (Exception ex) @@ -228,8 +229,8 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) return ret; } - var v2rayConfig = JsonUtils.Deserialize(result); - if (v2rayConfig == null) + _coreConfig = JsonUtils.Deserialize(result); + if (_coreConfig == null) { ret.Msg = ResUI.FailedGenDefaultConfiguration; return ret; @@ -238,9 +239,9 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) GenLog(); GenOutbounds(); - v2rayConfig.routing.rules.Clear(); - v2rayConfig.inbounds.Clear(); - v2rayConfig.inbounds.Add(new() + _coreConfig.routing.rules.Clear(); + _coreConfig.inbounds.Clear(); + _coreConfig.inbounds.Add(new() { tag = $"{EInboundProtocol.socks}{port}", listen = Global.Loopback, @@ -250,7 +251,7 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Success = true; - ret.Data = JsonUtils.Serialize(v2rayConfig); + ret.Data = JsonUtils.Serialize(_coreConfig); return ret; } catch (Exception ex) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index e50e4700..3f0ddb7a 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -743,22 +743,45 @@ public partial class CoreConfigV2rayService if (i != 0) { var chainStartNodes = childProfiles.Where(n => n.tag.StartsWith(currentTag)).ToList(); - var existedChainNodes = JsonUtils.DeepCopy(resultOutbounds); - resultOutbounds.Clear(); - foreach (var chainStartNode in chainStartNodes) + if (chainStartNodes.Count == 1) { - var existedChainNodesClone = JsonUtils.DeepCopy(existedChainNodes); - for (var j = 0; j < existedChainNodesClone.Count; j++) + foreach (var existedChainEndNode in resultOutbounds.Where(n => n.streamSettings?.sockopt?.dialerProxy == currentTag)) { - var existedChainNode = existedChainNodesClone[j]; - var cloneTag = $"{existedChainNode.tag}-clone-{j + 1}"; - existedChainNode.tag = cloneTag; - var previousDialerProxyTag = existedChainNode.streamSettings?.sockopt?.dialerProxy; - existedChainNode.streamSettings.sockopt = new() + existedChainEndNode.streamSettings.sockopt = new() { - dialerProxy = (previousDialerProxyTag == currentTag) ? chainStartNode.tag : existedChainNodesClone[j + 1].tag + dialerProxy = chainStartNodes.First().tag }; - resultOutbounds.Add(existedChainNode); + } + } + else if (chainStartNodes.Count > 1) + { + var existedChainNodes = JsonUtils.DeepCopy(resultOutbounds); + resultOutbounds.Clear(); + var j = 0; + foreach (var chainStartNode in chainStartNodes) + { + var existedChainNodesClone = JsonUtils.DeepCopy(existedChainNodes); + foreach (var existedChainNode in existedChainNodesClone) + { + var cloneTag = $"{existedChainNode.tag}-clone-{j + 1}"; + existedChainNode.tag = cloneTag; + } + for (var k = 0; k < existedChainNodesClone.Count; k++) + { + var existedChainNode = existedChainNodesClone[k]; + var previousDialerProxyTag = existedChainNode.streamSettings?.sockopt?.dialerProxy; + var nextTag = k + 1 < existedChainNodesClone.Count + ? existedChainNodesClone[k + 1].tag + : chainStartNode.tag; + existedChainNode.streamSettings.sockopt = new() + { + dialerProxy = (previousDialerProxyTag == currentTag) + ? chainStartNode.tag + : nextTag + }; + resultOutbounds.Add(existedChainNode); + } + j++; } } } From 84a1eb8445e9d99bd4d19352f50125f850b723f2 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sat, 7 Feb 2026 21:58:10 +0800 Subject: [PATCH 5/6] Optimize ProfileItem acquisition speed --- v2rayN/ServiceLib/Handler/CoreConfigHandler.cs | 4 ++-- v2rayN/ServiceLib/Manager/AppManager.cs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs index 0db0b9b7..9260fa11 100644 --- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs @@ -98,9 +98,9 @@ public static class CoreConfigHandler var ids = selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty()) .Select(serverTestItem => serverTestItem.IndexId!) .ToList(); - foreach (var id in ids) + var nodes = await AppManager.Instance.GetProfileItemsByIndexIds(ids); + foreach (var node in nodes) { - var node = await AppManager.Instance.GetProfileItem(id) ?? new(); await FillNodeContext(context, node, false); } if (coreType == ECoreType.sing_box) diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index 0e471568..82eec00e 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -230,6 +230,18 @@ public sealed class AppManager return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); } + public async Task> GetProfileItemsByIndexIds(List indexIds) + { + var ids = indexIds.Where(id => id.IsNotEmpty()).Distinct().ToList(); + if (ids.Count == 0) + { + return []; + } + return await SQLiteHelper.Instance.TableAsync() + .Where(it => ids.Contains(it.IndexId)) + .ToListAsync(); + } + public async Task GetProfileItemViaRemarks(string? remarks) { if (remarks.IsNullOrEmpty()) From 69d027840eff6e32e73ff8ca86b21adc3e300df2 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sun, 8 Feb 2026 14:26:39 +0800 Subject: [PATCH 6/6] Fix --- v2rayN/ServiceLib/Global.cs | 1 - .../ServiceLib/Handler/CoreConfigHandler.cs | 22 +- v2rayN/ServiceLib/Manager/AppManager.cs | 4 +- .../ServiceLib/Manager/GroupProfileManager.cs | 83 +++----- .../Singbox/CoreConfigSingboxService.cs | 102 +-------- .../CoreConfig/Singbox/SingboxDnsService.cs | 22 +- .../Singbox/SingboxInboundService.cs | 34 +-- .../CoreConfig/Singbox/SingboxLogService.cs | 8 +- .../Singbox/SingboxOutboundService.cs | 174 ++++++++-------- .../Singbox/SingboxRoutingService.cs | 16 +- .../Singbox/SingboxRulesetService.cs | 4 +- .../Singbox/SingboxStatisticService.cs | 4 +- .../V2ray/CoreConfigV2rayService.cs | 22 +- .../CoreConfig/V2ray/V2rayDnsService.cs | 7 - .../CoreConfig/V2ray/V2rayInboundService.cs | 17 +- .../CoreConfig/V2ray/V2rayLogService.cs | 7 +- .../CoreConfig/V2ray/V2rayOutboundService.cs | 195 +++++++++--------- .../CoreConfig/V2ray/V2rayRoutingService.cs | 4 +- .../CoreConfig/V2ray/V2rayStatisticService.cs | 2 +- 19 files changed, 308 insertions(+), 420 deletions(-) diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index c2893a34..90721217 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -15,7 +15,6 @@ public class Global public const string CoreConfigFileName = "config.json"; public const string CorePreConfigFileName = "configPre.json"; public const string CoreSpeedtestConfigFileName = "configTest{0}.json"; - public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json"; public const string ClashMixinConfigFileName = "Mixin.yaml"; public const string NamespaceSample = "ServiceLib.Sample."; diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs index 9260fa11..cebf2d3f 100644 --- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs @@ -18,7 +18,6 @@ public static class CoreConfigHandler result = node.CoreType switch { ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName), - ECoreType.sing_box => await new CoreConfigSingboxService(context).GenerateClientCustomConfig(fileName), _ => await GenerateClientCustomConfig(node, fileName) }; } @@ -96,8 +95,7 @@ public static class CoreConfigHandler var result = new RetResult(); var context = await BuildCoreConfigContext(config, new()); var ids = selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty()) - .Select(serverTestItem => serverTestItem.IndexId!) - .ToList(); + .Select(serverTestItem => serverTestItem.IndexId); var nodes = await AppManager.Instance.GetProfileItemsByIndexIds(ids); foreach (var node in nodes) { @@ -172,7 +170,8 @@ public static class CoreConfigHandler var ruleOutboundNode = await AppManager.Instance.GetProfileItemViaRemarks(ruleItem.OutboundTag); if (ruleOutboundNode != null) { - await FillNodeContext(context, ruleOutboundNode); + var ruleOutboundNodeAct = await FillNodeContext(context, ruleOutboundNode, false); + context.AllProxiesMap[$"remark:{ruleItem.OutboundTag}"] = ruleOutboundNodeAct; } } } @@ -185,18 +184,21 @@ public static class CoreConfigHandler { return node; } - context.AllProxiesMap[node.IndexId] = node; var newItems = new List { node }; - if (node.ConfigType.IsGroupType()) { - var groupChildList = await GroupProfileManager.GetAllChildProfileItems(node); - foreach (var childItem in groupChildList) + var (groupChildList, _) = await GroupProfileManager.GetChildProfileItems(node); + foreach (var childItem in groupChildList.Where(childItem => !context.AllProxiesMap.ContainsKey(childItem.IndexId))) { - context.AllProxiesMap[childItem.IndexId] = childItem; - newItems.Add(childItem); + await FillNodeContext(context, childItem, false); } + node.SetProtocolExtra(node.GetProtocolExtra() with + { + ChildItems = Utils.List2String(groupChildList.Select(n => n.IndexId).ToList()), + }); + newItems.AddRange(groupChildList); } + context.AllProxiesMap[node.IndexId] = node; foreach (var item in newItems) { diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index 82eec00e..e773c2ef 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -230,9 +230,9 @@ public sealed class AppManager return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); } - public async Task> GetProfileItemsByIndexIds(List indexIds) + public async Task> GetProfileItemsByIndexIds(IEnumerable indexIds) { - var ids = indexIds.Where(id => id.IsNotEmpty()).Distinct().ToList(); + var ids = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); if (ids.Count == 0) { return []; diff --git a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs index afd97f81..5e87f0e6 100644 --- a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs +++ b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs @@ -79,7 +79,7 @@ public class GroupProfileManager { if (protocolExtra == null) { - return new(); + return []; } var items = new List(); @@ -93,27 +93,44 @@ public class GroupProfileManager { if (extra == null || extra.ChildItems.IsNullOrEmpty()) { - return new(); + return []; } - var childProfiles = (await Task.WhenAll( - (Utils.String2List(extra.ChildItems) ?? new()) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )) - .Where(p => - p != null && - p.IsValid() && - p.ConfigType != EConfigType.Custom - ) - .ToList(); - return childProfiles ?? new(); + var childProfileIds = Utils.String2List(extra.ChildItems) + ?.Where(p => !string.IsNullOrEmpty(p)) + .ToList() ?? []; + if (childProfileIds.Count == 0) + { + return []; + } + + var childProfiles = await AppManager.Instance.GetProfileItemsByIndexIds(childProfileIds); + if (childProfiles == null || childProfiles.Count == 0) + { + return []; + } + + var profileMap = childProfiles + .Where(p => p != null && !p.IndexId.IsNullOrEmpty()) + .GroupBy(p => p!.IndexId!) + .ToDictionary(g => g.Key, g => g.First()); + + var ordered = new List(childProfileIds.Count); + foreach (var id in childProfileIds) + { + if (id != null && profileMap.TryGetValue(id, out var item) && item != null) + { + ordered.Add(item); + } + } + + return ordered; } private static async Task> GetSubChildProfileItems(ProtocolExtraItem? extra) { if (extra == null || extra.SubChildItems.IsNullOrEmpty()) { - return new(); + return []; } var childProfiles = await AppManager.Instance.ProfileItems(extra.SubChildItems ?? string.Empty); @@ -123,7 +140,7 @@ public class GroupProfileManager !p.ConfigType.IsComplexType() && (extra.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extra.Filter)) ) - .ToList() ?? new(); + .ToList() ?? []; } public static async Task> GetAllChildProfileItems(ProfileItem profileItem) @@ -149,38 +166,4 @@ public class GroupProfileManager } } } - - - public static async Task> GetAllChildDomainAddresses(ProfileItem profileItem) - { - var childAddresses = new HashSet(); - var childItems = await GetAllChildProfileItems(profileItem); - foreach (var child in childItems.Where(child => !child.Address.IsNullOrEmpty()).Where(child => Utils.IsDomain(child.Address))) - { - childAddresses.Add(child.Address); - } - return childAddresses; - } - - public static async Task> GetAllChildEchQuerySni(ProfileItem profileItem) - { - var childAddresses = new HashSet(); - var childItems = await GetAllChildProfileItems(profileItem); - foreach (var childNode in childItems.Where(childNode => !childNode.EchConfigList.IsNullOrEmpty())) - { - var sni = childNode.Sni; - if (childNode.StreamSecurity == Global.StreamSecurity - && childNode.EchConfigList?.Contains("://") == true) - { - var idx = childNode.EchConfigList.IndexOf('+'); - sni = idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni; - } - if (!Utils.IsDomain(sni)) - { - continue; - } - childAddresses.Add(sni); - } - return childAddresses; - } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs index 0653e98e..c0ce7154 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs @@ -3,6 +3,8 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService(CoreConfigContext context) { private static readonly string _tag = "CoreConfigSingboxService"; + private readonly Config _config = context.AppConfig; + private readonly ProfileItem _node = context.Node; private SingboxConfig _coreConfig = new(); @@ -13,16 +15,15 @@ public partial class CoreConfigSingboxService(CoreConfigContext context) var ret = new RetResult(); try { - var node = context.Node; - if (node == null - || !node.IsValid()) + if (_node == null + || !_node.IsValid()) { ret.Msg = ResUI.CheckServerSettings; return ret; } - if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp)) + if (_node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp)) { - ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; + ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}"; return ret; } @@ -193,16 +194,15 @@ public partial class CoreConfigSingboxService(CoreConfigContext context) var ret = new RetResult(); try { - var node = context.Node; - if (node == null - || !node.IsValid()) + if (_node == null + || !_node.IsValid()) { ret.Msg = ResUI.CheckServerSettings; return ret; } - if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp)) + if (_node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp)) { - ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; + ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}"; return ret; } @@ -249,87 +249,5 @@ public partial class CoreConfigSingboxService(CoreConfigContext context) } } - public async Task GenerateClientCustomConfig(string? fileName) - { - var ret = new RetResult(); - var node = context.Node; - if (node == null || fileName is null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - ret.Msg = ResUI.InitialConfiguration; - - try - { - if (node == null) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - if (File.Exists(fileName)) - { - File.Delete(fileName); - } - - var addressFileName = node.Address; - if (addressFileName.IsNullOrEmpty()) - { - ret.Msg = ResUI.FailedGetDefaultConfiguration; - return ret; - } - if (!File.Exists(addressFileName)) - { - addressFileName = Path.Combine(Utils.GetConfigPath(), addressFileName); - } - if (!File.Exists(addressFileName)) - { - ret.Msg = ResUI.FailedReadConfiguration + "1"; - return ret; - } - - if (node.Address == Global.CoreMultipleLoadConfigFileName) - { - var txtFile = File.ReadAllText(addressFileName); - _coreConfig = JsonUtils.Deserialize(txtFile); - if (_coreConfig == null) - { - File.Copy(addressFileName, fileName); - } - else - { - GenInbounds(); - GenExperimental(); - - var content = JsonUtils.Serialize(_coreConfig, true); - await File.WriteAllTextAsync(fileName, content); - } - } - else - { - File.Copy(addressFileName, fileName); - } - - //check again - if (!File.Exists(fileName)) - { - ret.Msg = ResUI.FailedReadConfiguration + "2"; - return ret; - } - - ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); - ret.Success = true; - return ret; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - } - #endregion public gen function } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index 9db73605..b4ddaf7f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -348,6 +348,10 @@ public partial class CoreConfigSingboxService private void GenMinimizedDns() { GenDnsServers(); + foreach (var server in _coreConfig.dns!.servers.Where(s => !string.IsNullOrEmpty(s.detour)).ToList()) + { + _coreConfig.dns.servers.Remove(server); + } _coreConfig.dns ??= new(); _coreConfig.dns.rules ??= []; _coreConfig.dns.rules.Clear(); @@ -429,15 +433,17 @@ public partial class CoreConfigSingboxService { GenDnsProtectCustom(); - var localDnsServer = _coreConfig.dns?.servers?.FirstOrDefault(s => s.tag == Global.SingboxLocalDNSTag); - if (localDnsServer == null) - { - return; - } - localDnsServer.type = null; - localDnsServer.server = null; + _coreConfig.dns?.servers?.RemoveAll(s => s.tag == Global.SingboxLocalDNSTag); var dnsItem = context.RawDnsItem; - localDnsServer.address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress; + var localDnsServer = new Server4Sbox() + { + address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) + ? Global.DomainPureIPDNSAddress.FirstOrDefault() + : dnsItem?.DomainDNSAddress, + tag = Global.SingboxLocalDNSTag, + detour = Global.DirectTag, + }; + _coreConfig.dns?.servers?.Add(localDnsServer); } private Rule4Sbox BuildProtectDomainRule() diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs index ba9c26e7..ab9a9d9f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs @@ -9,8 +9,8 @@ public partial class CoreConfigSingboxService var listen = "0.0.0.0"; _coreConfig.inbounds = []; - if (!context.AppConfig.TunModeItem.EnableTun - || (context.AppConfig.TunModeItem.EnableTun && context.AppConfig.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box)) + if (!_config.TunModeItem.EnableTun + || (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box)) { var inbound = new Inbound4Sbox() { @@ -22,24 +22,24 @@ public partial class CoreConfigSingboxService inbound.listen_port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks); - if (context.AppConfig.Inbound.First().SecondLocalPortEnabled) + if (_config.Inbound.First().SecondLocalPortEnabled) { var inbound2 = BuildInbound(inbound, EInboundProtocol.socks2, true); _coreConfig.inbounds.Add(inbound2); } - if (context.AppConfig.Inbound.First().AllowLANConn) + if (_config.Inbound.First().AllowLANConn) { - if (context.AppConfig.Inbound.First().NewPort4LAN) + if (_config.Inbound.First().NewPort4LAN) { var inbound3 = BuildInbound(inbound, EInboundProtocol.socks3, true); inbound3.listen = listen; _coreConfig.inbounds.Add(inbound3); //auth - if (context.AppConfig.Inbound.First().User.IsNotEmpty() && context.AppConfig.Inbound.First().Pass.IsNotEmpty()) + if (_config.Inbound.First().User.IsNotEmpty() && _config.Inbound.First().Pass.IsNotEmpty()) { - inbound3.users = new() { new() { username = context.AppConfig.Inbound.First().User, password = context.AppConfig.Inbound.First().Pass } }; + inbound3.users = new() { new() { username = _config.Inbound.First().User, password = _config.Inbound.First().Pass } }; } } else @@ -49,24 +49,24 @@ public partial class CoreConfigSingboxService } } - if (context.AppConfig.TunModeItem.EnableTun) + if (_config.TunModeItem.EnableTun) { - if (context.AppConfig.TunModeItem.Mtu <= 0) + if (_config.TunModeItem.Mtu <= 0) { - context.AppConfig.TunModeItem.Mtu = Global.TunMtus.First(); + _config.TunModeItem.Mtu = Global.TunMtus.First(); } - if (context.AppConfig.TunModeItem.Stack.IsNullOrEmpty()) + if (_config.TunModeItem.Stack.IsNullOrEmpty()) { - context.AppConfig.TunModeItem.Stack = Global.TunStacks.First(); + _config.TunModeItem.Stack = Global.TunStacks.First(); } var tunInbound = JsonUtils.Deserialize(EmbedUtils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { }; tunInbound.interface_name = Utils.IsMacOS() ? $"utun{new Random().Next(99)}" : "singbox_tun"; - tunInbound.mtu = context.AppConfig.TunModeItem.Mtu; - tunInbound.auto_route = context.AppConfig.TunModeItem.AutoRoute; - tunInbound.strict_route = context.AppConfig.TunModeItem.StrictRoute; - tunInbound.stack = context.AppConfig.TunModeItem.Stack; - if (context.AppConfig.TunModeItem.EnableIPv6Address == false) + tunInbound.mtu = _config.TunModeItem.Mtu; + tunInbound.auto_route = _config.TunModeItem.AutoRoute; + tunInbound.strict_route = _config.TunModeItem.StrictRoute; + tunInbound.stack = _config.TunModeItem.Stack; + if (_config.TunModeItem.EnableIPv6Address == false) { tunInbound.address = ["172.18.0.1/30"]; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs index 052b1cdf..b438242c 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs @@ -6,12 +6,12 @@ public partial class CoreConfigSingboxService { try { - switch (context.AppConfig.CoreBasicItem.Loglevel) + switch (_config.CoreBasicItem.Loglevel) { case "debug": case "info": case "error": - _coreConfig.log.level = context.AppConfig.CoreBasicItem.Loglevel; + _coreConfig.log.level = _config.CoreBasicItem.Loglevel; break; case "warning": @@ -21,11 +21,11 @@ public partial class CoreConfigSingboxService default: break; } - if (context.AppConfig.CoreBasicItem.Loglevel == Global.None) + if (_config.CoreBasicItem.Loglevel == Global.None) { _coreConfig.log.disabled = true; } - if (context.AppConfig.CoreBasicItem.LogEnabled) + if (_config.CoreBasicItem.LogEnabled) { var dtNow = DateTime.Now; _coreConfig.log.output = Utils.GetLogPath($"sbox_{dtNow:yyyy-MM-dd}.txt"); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 2afc4f49..23b331f6 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -11,7 +11,7 @@ public partial class CoreConfigSingboxService private List BuildAllProxyOutbounds(string baseTagName = Global.ProxyTag, bool withSelector = true) { var proxyOutboundList = new List(); - if (!context.Node.ConfigType.IsComplexType()) + if (!_node.ConfigType.IsComplexType()) { var outbound = BuildProxyOutbound(baseTagName); proxyOutboundList.Add(outbound); @@ -38,7 +38,7 @@ public partial class CoreConfigSingboxService private List BuildGroupProxyOutbounds(string baseTagName = Global.ProxyTag) { var proxyOutboundList = new List(); - switch (context.Node.ConfigType) + switch (_node.ConfigType) { case EConfigType.PolicyGroup: proxyOutboundList = BuildOutboundsList(baseTagName); @@ -54,9 +54,8 @@ public partial class CoreConfigSingboxService { try { - var node = context.Node; var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); - if (node.ConfigType == EConfigType.WireGuard) + if (_node.ConfigType == EConfigType.WireGuard) { var endpoint = JsonUtils.Deserialize(txtOutbound); FillEndpoint(endpoint); @@ -80,17 +79,16 @@ public partial class CoreConfigSingboxService { try { - var node = context.Node; - var protocolExtra = node.GetProtocolExtra(); - outbound.server = node.Address; - outbound.server_port = node.Port; - outbound.type = Global.ProtocolTypes[node.ConfigType]; + var protocolExtra = _node.GetProtocolExtra(); + outbound.server = _node.Address; + outbound.server_port = _node.Port; + outbound.type = Global.ProtocolTypes[_node.ConfigType]; - switch (node.ConfigType) + switch (_node.ConfigType) { case EConfigType.VMess: { - outbound.uuid = node.Password; + outbound.uuid = _node.Password; outbound.alter_id = int.TryParse(protocolExtra.AlterId, out var result) ? result : 0; if (Global.VmessSecurities.Contains(protocolExtra.VmessSecurity)) { @@ -107,35 +105,35 @@ public partial class CoreConfigSingboxService } case EConfigType.Shadowsocks: { - outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(protocolExtra.SsMethod) + outbound.method = AppManager.Instance.GetShadowsocksSecurities(_node).Contains(protocolExtra.SsMethod) ? protocolExtra.SsMethod : Global.None; - outbound.password = node.Password; + outbound.password = _node.Password; - if (node.Network == nameof(ETransport.tcp) && node.HeaderType == Global.TcpHeaderHttp) + if (_node.Network == nameof(ETransport.tcp) && _node.HeaderType == Global.TcpHeaderHttp) { outbound.plugin = "obfs-local"; - outbound.plugin_opts = $"obfs=http;obfs-host={node.RequestHost};"; + outbound.plugin_opts = $"obfs=http;obfs-host={_node.RequestHost};"; } else { var pluginArgs = string.Empty; - if (node.Network == nameof(ETransport.ws)) + if (_node.Network == nameof(ETransport.ws)) { pluginArgs += "mode=websocket;"; - pluginArgs += $"host={node.RequestHost};"; + pluginArgs += $"host={_node.RequestHost};"; // https://github.com/shadowsocks/v2ray-plugin/blob/e9af1cdd2549d528deb20a4ab8d61c5fbe51f306/args.go#L172 // Equal signs and commas [and backslashes] must be escaped with a backslash. - var path = node.Path.Replace("\\", "\\\\").Replace("=", "\\=").Replace(",", "\\,"); + var path = _node.Path.Replace("\\", "\\\\").Replace("=", "\\=").Replace(",", "\\,"); pluginArgs += $"path={path};"; } - else if (node.Network == nameof(ETransport.quic)) + else if (_node.Network == nameof(ETransport.quic)) { pluginArgs += "mode=quic;"; } - if (node.StreamSecurity == Global.StreamSecurity) + if (_node.StreamSecurity == Global.StreamSecurity) { pluginArgs += "tls;"; - var certs = CertPemManager.ParsePemChain(node.Cert); + var certs = CertPemManager.ParsePemChain(_node.Cert); if (certs.Count > 0) { var cert = certs.First(); @@ -165,27 +163,27 @@ public partial class CoreConfigSingboxService case EConfigType.SOCKS: { outbound.version = "5"; - if (node.Username.IsNotEmpty() - && node.Password.IsNotEmpty()) + if (_node.Username.IsNotEmpty() + && _node.Password.IsNotEmpty()) { - outbound.username = node.Username; - outbound.password = node.Password; + outbound.username = _node.Username; + outbound.password = _node.Password; } break; } case EConfigType.HTTP: { - if (node.Username.IsNotEmpty() - && node.Password.IsNotEmpty()) + if (_node.Username.IsNotEmpty() + && _node.Password.IsNotEmpty()) { - outbound.username = node.Username; - outbound.password = node.Password; + outbound.username = _node.Username; + outbound.password = _node.Password; } break; } case EConfigType.VLESS: { - outbound.uuid = node.Password; + outbound.uuid = _node.Password; outbound.packet_encoding = "xudp"; @@ -203,7 +201,7 @@ public partial class CoreConfigSingboxService } case EConfigType.Trojan: { - outbound.password = node.Password; + outbound.password = _node.Password; FillOutboundMux(outbound); FillOutboundTransport(outbound); @@ -211,7 +209,7 @@ public partial class CoreConfigSingboxService } case EConfigType.Hysteria2: { - outbound.password = node.Password; + outbound.password = _node.Password; if (!protocolExtra.SalamanderPass.IsNullOrEmpty()) { @@ -224,10 +222,10 @@ public partial class CoreConfigSingboxService outbound.up_mbps = protocolExtra?.UpMbps is { } su and >= 0 ? su - : context.AppConfig.HysteriaItem.UpMbps; + : _config.HysteriaItem.UpMbps; outbound.down_mbps = protocolExtra?.DownMbps is { } sd and >= 0 ? sd - : context.AppConfig.HysteriaItem.DownMbps; + : _config.HysteriaItem.DownMbps; var ports = protocolExtra?.Ports?.IsNullOrEmpty() == false ? protocolExtra.Ports : null; if ((!ports.IsNullOrEmpty()) && (ports.Contains(':') || ports.Contains('-') || ports.Contains(','))) { @@ -241,8 +239,8 @@ public partial class CoreConfigSingboxService return port.Contains(':') ? port : $"{port}:{port}"; }) .ToList(); - outbound.hop_interval = context.AppConfig.HysteriaItem.HopInterval >= 5 - ? $"{context.AppConfig.HysteriaItem.HopInterval}s" + outbound.hop_interval = _config.HysteriaItem.HopInterval >= 5 + ? $"{_config.HysteriaItem.HopInterval}s" : $"{Global.Hysteria2DefaultHopInt}s"; if (int.TryParse(protocolExtra.HopInterval, out var hiResult)) { @@ -265,14 +263,14 @@ public partial class CoreConfigSingboxService } case EConfigType.TUIC: { - outbound.uuid = node.Username; - outbound.password = node.Password; - outbound.congestion_control = node.HeaderType; + outbound.uuid = _node.Username; + outbound.password = _node.Password; + outbound.congestion_control = _node.HeaderType; break; } case EConfigType.Anytls: { - outbound.password = node.Password; + outbound.password = _node.Password; break; } } @@ -289,13 +287,12 @@ public partial class CoreConfigSingboxService { try { - var node = context.Node; - var protocolExtra = node.GetProtocolExtra(); + var protocolExtra = _node.GetProtocolExtra(); endpoint.address = Utils.String2List(protocolExtra.WgInterfaceAddress); - endpoint.type = Global.ProtocolTypes[node.ConfigType]; + endpoint.type = Global.ProtocolTypes[_node.ConfigType]; - switch (node.ConfigType) + switch (_node.ConfigType) { case EConfigType.WireGuard: { @@ -304,12 +301,12 @@ public partial class CoreConfigSingboxService public_key = protocolExtra.WgPublicKey, pre_shared_key = protocolExtra.WgPresharedKey, reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(int.Parse).ToList(), - address = node.Address, - port = node.Port, + address = _node.Address, + port = _node.Port, // TODO default ["0.0.0.0/0", "::/0"] allowed_ips = new() { "0.0.0.0/0", "::/0" }, }; - endpoint.private_key = node.Password; + endpoint.private_key = _node.Password; endpoint.mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First(); endpoint.peers = [peer]; break; @@ -326,16 +323,15 @@ public partial class CoreConfigSingboxService { try { - var config = context.AppConfig; - var muxEnabled = context.Node.MuxEnabled ?? config.CoreBasicItem.MuxEnabled; - if (muxEnabled && config.Mux4SboxItem.Protocol.IsNotEmpty()) + var muxEnabled = _node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; + if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty()) { var mux = new Multiplex4Sbox() { enabled = true, - protocol = config.Mux4SboxItem.Protocol, - max_connections = config.Mux4SboxItem.MaxConnections, - padding = config.Mux4SboxItem.Padding, + protocol = _config.Mux4SboxItem.Protocol, + max_connections = _config.Mux4SboxItem.MaxConnections, + padding = _config.Mux4SboxItem.Padding, }; outbound.multiplex = mux; } @@ -350,60 +346,59 @@ public partial class CoreConfigSingboxService { try { - var node = context.Node; - if (node.StreamSecurity is not (Global.StreamSecurityReality or Global.StreamSecurity)) + if (_node.StreamSecurity is not (Global.StreamSecurityReality or Global.StreamSecurity)) { return; } - if (node.ConfigType is EConfigType.Shadowsocks or EConfigType.SOCKS or EConfigType.WireGuard) + if (_node.ConfigType is EConfigType.Shadowsocks or EConfigType.SOCKS or EConfigType.WireGuard) { return; } var serverName = string.Empty; - if (node.Sni.IsNotEmpty()) + if (_node.Sni.IsNotEmpty()) { - serverName = node.Sni; + serverName = _node.Sni; } - else if (node.RequestHost.IsNotEmpty()) + else if (_node.RequestHost.IsNotEmpty()) { - serverName = Utils.String2List(node.RequestHost)?.First(); + serverName = Utils.String2List(_node.RequestHost)?.First(); } var tls = new Tls4Sbox() { enabled = true, - record_fragment = context.AppConfig.CoreBasicItem.EnableFragment ? true : null, + record_fragment = _config.CoreBasicItem.EnableFragment ? true : null, server_name = serverName, - insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? context.AppConfig.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), - alpn = node.GetAlpn(), + insecure = Utils.ToBool(_node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : _node.AllowInsecure), + alpn = _node.GetAlpn(), }; - if (node.Fingerprint.IsNotEmpty()) + if (_node.Fingerprint.IsNotEmpty()) { tls.utls = new Utls4Sbox() { enabled = true, - fingerprint = node.Fingerprint.IsNullOrEmpty() ? context.AppConfig.CoreBasicItem.DefFingerprint : node.Fingerprint + fingerprint = _node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : _node.Fingerprint }; } - if (node.StreamSecurity == Global.StreamSecurity) + if (_node.StreamSecurity == Global.StreamSecurity) { - var certs = CertPemManager.ParsePemChain(node.Cert); + var certs = CertPemManager.ParsePemChain(_node.Cert); if (certs.Count > 0) { tls.certificate = certs; tls.insecure = false; } } - else if (node.StreamSecurity == Global.StreamSecurityReality) + else if (_node.StreamSecurity == Global.StreamSecurityReality) { tls.reality = new Reality4Sbox() { enabled = true, - public_key = node.PublicKey, - short_id = node.ShortId + public_key = _node.PublicKey, + short_id = _node.ShortId }; tls.insecure = false; } - var (ech, _) = ParseEchParam(node.EchConfigList); + var (ech, _) = ParseEchParam(_node.EchConfigList); if (ech is not null) { tls.ech = ech; @@ -420,29 +415,28 @@ public partial class CoreConfigSingboxService { try { - var node = context.Node; var transport = new Transport4Sbox(); - switch (node.GetNetwork()) + switch (_node.GetNetwork()) { case nameof(ETransport.h2): transport.type = nameof(ETransport.http); - transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost); - transport.path = node.Path.NullIfEmpty(); + transport.host = _node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(_node.RequestHost); + transport.path = _node.Path.NullIfEmpty(); break; case nameof(ETransport.tcp): //http - if (node.HeaderType == Global.TcpHeaderHttp) + if (_node.HeaderType == Global.TcpHeaderHttp) { transport.type = nameof(ETransport.http); - transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost); - transport.path = node.Path.NullIfEmpty(); + transport.host = _node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(_node.RequestHost); + transport.path = _node.Path.NullIfEmpty(); } break; case nameof(ETransport.ws): transport.type = nameof(ETransport.ws); - var wsPath = node.Path; + var wsPath = _node.Path; // Parse eh and ed parameters from path using regex if (!wsPath.IsNullOrEmpty()) @@ -471,19 +465,19 @@ public partial class CoreConfigSingboxService } transport.path = wsPath.NullIfEmpty(); - if (node.RequestHost.IsNotEmpty()) + if (_node.RequestHost.IsNotEmpty()) { transport.headers = new() { - Host = node.RequestHost + Host = _node.RequestHost }; } break; case nameof(ETransport.httpupgrade): transport.type = nameof(ETransport.httpupgrade); - transport.path = node.Path.NullIfEmpty(); - transport.host = node.RequestHost.NullIfEmpty(); + transport.path = _node.Path.NullIfEmpty(); + transport.host = _node.RequestHost.NullIfEmpty(); break; @@ -493,10 +487,10 @@ public partial class CoreConfigSingboxService case nameof(ETransport.grpc): transport.type = nameof(ETransport.grpc); - transport.service_name = node.Path; - transport.idle_timeout = context.AppConfig.GrpcItem.IdleTimeout?.ToString("##s"); - transport.ping_timeout = context.AppConfig.GrpcItem.HealthCheckTimeout?.ToString("##s"); - transport.permit_without_stream = context.AppConfig.GrpcItem.PermitWithoutStream; + transport.service_name = _node.Path; + transport.idle_timeout = _config.GrpcItem.IdleTimeout?.ToString("##s"); + transport.ping_timeout = _config.GrpcItem.HealthCheckTimeout?.ToString("##s"); + transport.permit_without_stream = _config.GrpcItem.PermitWithoutStream; break; default: @@ -515,7 +509,7 @@ public partial class CoreConfigSingboxService private List BuildSelectorOutbounds(List proxyTags, string baseTagName = Global.ProxyTag) { - var multipleLoad = context.Node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + var multipleLoad = _node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; var outUrltest = new Outbound4Sbox { type = "urltest", @@ -545,7 +539,7 @@ public partial class CoreConfigSingboxService private List BuildOutboundsList(string baseTagName = Global.ProxyTag) { var nodes = new List(); - foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) + foreach (var nodeId in Utils.String2List(_node.GetProtocolExtra().ChildItems) ?? []) { if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) { @@ -574,7 +568,7 @@ public partial class CoreConfigSingboxService private List BuildChainOutboundsList(string baseTagName = Global.ProxyTag) { var nodes = new List(); - foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) + foreach (var nodeId in Utils.String2List(_node.GetProtocolExtra().ChildItems) ?? []) { if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs index 606a54df..9bcb9adf 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs @@ -7,7 +7,7 @@ public partial class CoreConfigSingboxService try { _coreConfig.route.final = Global.ProxyTag; - var simpleDnsItem = context.AppConfig.SimpleDNSItem; + var simpleDnsItem = context.SimpleDnsItem; var defaultDomainResolverTag = Global.SingboxDirectDNSTag; var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); @@ -24,7 +24,7 @@ public partial class CoreConfigSingboxService strategy = directDnsStrategy }; - if (context.AppConfig.TunModeItem.EnableTun) + if (_config.TunModeItem.EnableTun) { _coreConfig.route.auto_detect_interface = true; @@ -49,7 +49,7 @@ public partial class CoreConfigSingboxService }); } - if (context.AppConfig.Inbound.First().SniffingEnabled) + if (_config.Inbound.First().SniffingEnabled) { _coreConfig.route.rules.Add(new() { @@ -102,7 +102,7 @@ public partial class CoreConfigSingboxService clash_mode = ERuleMode.Global.ToString() }); - var domainStrategy = context.AppConfig.RoutingBasicItem.DomainStrategy4Singbox.NullIfEmpty(); + var domainStrategy = _config.RoutingBasicItem.DomainStrategy4Singbox.NullIfEmpty(); var routing = context.RoutingItem; if (routing.DomainStrategy4Singbox.IsNotEmpty()) { @@ -113,7 +113,7 @@ public partial class CoreConfigSingboxService action = "resolve", strategy = domainStrategy }; - if (context.AppConfig.RoutingBasicItem.DomainStrategy == Global.IPOnDemand) + if (_config.RoutingBasicItem.DomainStrategy == Global.IPOnDemand) { _coreConfig.route.rules.Add(resolveRule); } @@ -142,7 +142,7 @@ public partial class CoreConfigSingboxService } } } - if (context.AppConfig.RoutingBasicItem.DomainStrategy == Global.IPIfNonMatch) + if (_config.RoutingBasicItem.DomainStrategy == Global.IPIfNonMatch) { _coreConfig.route.rules.Add(resolveRule); foreach (var item2 in ipRules) @@ -413,8 +413,8 @@ public partial class CoreConfigSingboxService } var tag = $"{node.IndexId}-{Global.ProxyTag}"; - if (_coreConfig.outbounds.Any(o => o.tag == tag) - || (_coreConfig.endpoints != null && _coreConfig.endpoints.Any(e => e.tag == tag))) + if (_coreConfig.outbounds.Any(o => o.tag.StartsWith(tag)) + || (_coreConfig.endpoints != null && _coreConfig.endpoints.Any(e => e.tag.StartsWith(tag)))) { return tag; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs index 46240336..bb4c4b3a 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRulesetService.cs @@ -99,9 +99,9 @@ public partial class CoreConfigSingboxService } else { - var srsUrl = string.IsNullOrEmpty(context.AppConfig.ConstItem.SrsSourceUrl) + var srsUrl = string.IsNullOrEmpty(_config.ConstItem.SrsSourceUrl) ? Global.SingboxRulesetUrl - : context.AppConfig.ConstItem.SrsSourceUrl; + : _config.ConstItem.SrsSourceUrl; customRuleset = new() { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs index a44872ac..e2beff34 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs @@ -13,14 +13,14 @@ public partial class CoreConfigSingboxService }; } - if (context.AppConfig.CoreBasicItem.EnableCacheFile4Sbox) + if (_config.CoreBasicItem.EnableCacheFile4Sbox) { _coreConfig.experimental ??= new Experimental4Sbox(); _coreConfig.experimental.cache_file = new CacheFile4Sbox() { enabled = true, path = Utils.GetBinPath("cache.db"), - store_fakeip = context.AppConfig.SimpleDNSItem.FakeIP == true + store_fakeip = context.SimpleDnsItem.FakeIP == true }; } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs index 762f5f4b..3ad71592 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs @@ -3,6 +3,8 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigV2rayService(CoreConfigContext context) { private static readonly string _tag = "CoreConfigV2rayService"; + private readonly Config _config = context.AppConfig; + private readonly ProfileItem _node = context.Node; private V2rayConfig _coreConfig = new(); @@ -13,17 +15,16 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) var ret = new RetResult(); try { - var node = context?.Node; - if (node == null - || !node.IsValid()) + if (_node == null + || !_node.IsValid()) { ret.Msg = ResUI.CheckServerSettings; return ret; } - if (node.GetNetwork() is nameof(ETransport.quic)) + if (_node.GetNetwork() is nameof(ETransport.quic)) { - ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; + ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}"; return ret; } @@ -170,7 +171,7 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) if (proxyOutbounds.Count(n => n.tag.StartsWith(tag)) > 1) { isBalancer = true; - var multipleLoad = context.Node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + var multipleLoad = _node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; GenObservatory(multipleLoad, tag); GenBalancer(multipleLoad, tag); } @@ -208,17 +209,16 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) var ret = new RetResult(); try { - var node = context.Node; - if (node == null - || !node.IsValid()) + if (_node == null + || !_node.IsValid()) { ret.Msg = ResUI.CheckServerSettings; return ret; } - if (node.GetNetwork() is nameof(ETransport.quic)) + if (_node.GetNetwork() is nameof(ETransport.quic)) { - ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; + ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}"; return ret; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index e131af33..10cd905b 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -92,7 +92,6 @@ public partial class CoreConfigV2rayService private void FillDnsServers(Dns4Ray dnsItem) { - var node = context.Node; var simpleDNSItem = context.SimpleDnsItem; static List ParseDnsAddresses(string? dnsInput, string defaultAddress) { @@ -246,11 +245,6 @@ public partial class CoreConfigV2rayService } } - if (Utils.IsDomain(node?.Address)) - { - directDomainList.Add(node.Address); - } - if (context.ProtectDomainList.Count > 0) { directDomainList.AddRange(context.ProtectDomainList); @@ -407,7 +401,6 @@ public partial class CoreConfigV2rayService private void FillDnsDomainsCustom(JsonNode dns) { - var node = context.Node; var servers = dns["servers"]; if (servers == null) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs index 18771183..7ae12c7c 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs @@ -6,32 +6,31 @@ public partial class CoreConfigV2rayService { try { - var config = context.AppConfig; var listen = "0.0.0.0"; _coreConfig.inbounds = []; - var inbound = BuildInbound(config.Inbound.First(), EInboundProtocol.socks, true); + var inbound = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks, true); _coreConfig.inbounds.Add(inbound); - if (config.Inbound.First().SecondLocalPortEnabled) + if (_config.Inbound.First().SecondLocalPortEnabled) { - var inbound2 = BuildInbound(config.Inbound.First(), EInboundProtocol.socks2, true); + var inbound2 = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks2, true); _coreConfig.inbounds.Add(inbound2); } - if (config.Inbound.First().AllowLANConn) + if (_config.Inbound.First().AllowLANConn) { - if (config.Inbound.First().NewPort4LAN) + if (_config.Inbound.First().NewPort4LAN) { - var inbound3 = BuildInbound(config.Inbound.First(), EInboundProtocol.socks3, true); + var inbound3 = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks3, true); inbound3.listen = listen; _coreConfig.inbounds.Add(inbound3); //auth - if (config.Inbound.First().User.IsNotEmpty() && config.Inbound.First().Pass.IsNotEmpty()) + if (_config.Inbound.First().User.IsNotEmpty() && _config.Inbound.First().Pass.IsNotEmpty()) { inbound3.settings.auth = "password"; - inbound3.settings.accounts = new List { new() { user = config.Inbound.First().User, pass = config.Inbound.First().Pass } }; + inbound3.settings.accounts = new List { new() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } }; } } else diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs index 10cae6f1..86f4b2c2 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs @@ -6,17 +6,16 @@ public partial class CoreConfigV2rayService { try { - var config = context.AppConfig; - if (config.CoreBasicItem.LogEnabled) + if (_config.CoreBasicItem.LogEnabled) { var dtNow = DateTime.Now; - _coreConfig.log.loglevel = config.CoreBasicItem.Loglevel; + _coreConfig.log.loglevel = _config.CoreBasicItem.Loglevel; _coreConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt"); _coreConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt"); } else { - _coreConfig.log.loglevel = config.CoreBasicItem.Loglevel; + _coreConfig.log.loglevel = _config.CoreBasicItem.Loglevel; _coreConfig.log.access = null; _coreConfig.log.error = null; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 3f0ddb7a..3526fe29 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -8,7 +8,7 @@ public partial class CoreConfigV2rayService _coreConfig.outbounds.InsertRange(0, proxyOutboundList); if (proxyOutboundList.Count(n => n.tag.StartsWith(Global.ProxyTag)) > 1) { - var multipleLoad = context.Node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; + var multipleLoad = _node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing; GenObservatory(multipleLoad); GenBalancer(multipleLoad); } @@ -17,8 +17,7 @@ public partial class CoreConfigV2rayService private List BuildAllProxyOutbounds(string baseTagName = Global.ProxyTag) { var proxyOutboundList = new List(); - var node = context.Node; - if (node.ConfigType.IsGroupType()) + if (_node.ConfigType.IsGroupType()) { proxyOutboundList.AddRange(BuildGroupProxyOutbounds(baseTagName)); } @@ -27,7 +26,7 @@ public partial class CoreConfigV2rayService proxyOutboundList.Add(BuildProxyOutbound(baseTagName)); } - if (context.AppConfig.CoreBasicItem.EnableFragment) + if (_config.CoreBasicItem.EnableFragment) { var fragmentOutbound = new Outbounds4Ray { @@ -37,9 +36,9 @@ public partial class CoreConfigV2rayService { fragment = new() { - packets = context.AppConfig.Fragment4RayItem?.Packets, - length = context.AppConfig.Fragment4RayItem?.Length, - interval = context.AppConfig.Fragment4RayItem?.Interval + packets = _config.Fragment4RayItem?.Packets, + length = _config.Fragment4RayItem?.Length, + interval = _config.Fragment4RayItem?.Interval } } }; @@ -63,8 +62,7 @@ public partial class CoreConfigV2rayService private List BuildGroupProxyOutbounds(string baseTagName = Global.ProxyTag) { var proxyOutboundList = new List(); - var node = context.Node; - switch (node.ConfigType) + switch (_node.ConfigType) { case EConfigType.PolicyGroup: proxyOutboundList.AddRange(BuildOutboundsList(baseTagName)); @@ -89,10 +87,9 @@ public partial class CoreConfigV2rayService { try { - var node = context.Node; - var protocolExtra = node.GetProtocolExtra(); - var muxEnabled = node.MuxEnabled ?? context.AppConfig.CoreBasicItem.MuxEnabled; - switch (node.ConfigType) + var protocolExtra = _node.GetProtocolExtra(); + var muxEnabled = _node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; + switch (_node.ConfigType) { case EConfigType.VMess: { @@ -106,8 +103,8 @@ public partial class CoreConfigV2rayService { vnextItem = outbound.settings.vnext.First(); } - vnextItem.address = node.Address; - vnextItem.port = node.Port; + vnextItem.address = _node.Address; + vnextItem.port = _node.Port; UsersItem4Ray usersItem; if (vnextItem.users.Count <= 0) @@ -120,7 +117,7 @@ public partial class CoreConfigV2rayService usersItem = vnextItem.users.First(); } - usersItem.id = node.Password; + usersItem.id = _node.Password; usersItem.alterId = int.TryParse(protocolExtra?.AlterId, out var result) ? result : 0; usersItem.email = Global.UserEMail; if (Global.VmessSecurities.Contains(protocolExtra.VmessSecurity)) @@ -149,10 +146,10 @@ public partial class CoreConfigV2rayService { serversItem = outbound.settings.servers.First(); } - serversItem.address = node.Address; - serversItem.port = node.Port; - serversItem.password = node.Password; - serversItem.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(protocolExtra.SsMethod) + serversItem.address = _node.Address; + serversItem.port = _node.Port; + serversItem.password = _node.Password; + serversItem.method = AppManager.Instance.GetShadowsocksSecurities(_node).Contains(protocolExtra.SsMethod) ? protocolExtra.SsMethod : "none"; serversItem.ota = false; @@ -176,18 +173,18 @@ public partial class CoreConfigV2rayService { serversItem = outbound.settings.servers.First(); } - serversItem.address = node.Address; - serversItem.port = node.Port; + serversItem.address = _node.Address; + serversItem.port = _node.Port; serversItem.method = null; serversItem.password = null; - if (node.Username.IsNotEmpty() - && node.Password.IsNotEmpty()) + if (_node.Username.IsNotEmpty() + && _node.Password.IsNotEmpty()) { SocksUsersItem4Ray socksUsersItem = new() { - user = node.Username ?? "", - pass = node.Password, + user = _node.Username ?? "", + pass = _node.Password, level = 1 }; @@ -211,8 +208,8 @@ public partial class CoreConfigV2rayService { vnextItem = outbound.settings.vnext.First(); } - vnextItem.address = node.Address; - vnextItem.port = node.Port; + vnextItem.address = _node.Address; + vnextItem.port = _node.Port; UsersItem4Ray usersItem; if (vnextItem.users.Count <= 0) @@ -224,7 +221,7 @@ public partial class CoreConfigV2rayService { usersItem = vnextItem.users.First(); } - usersItem.id = node.Password; + usersItem.id = _node.Password; usersItem.email = Global.UserEMail; usersItem.encryption = protocolExtra.VlessEncryption; @@ -251,9 +248,9 @@ public partial class CoreConfigV2rayService { serversItem = outbound.settings.servers.First(); } - serversItem.address = node.Address; - serversItem.port = node.Port; - serversItem.password = node.Password; + serversItem.address = _node.Address; + serversItem.port = _node.Port; + serversItem.password = _node.Password; serversItem.ota = false; serversItem.level = 1; @@ -268,8 +265,8 @@ public partial class CoreConfigV2rayService outbound.settings = new() { version = 2, - address = node.Address, - port = node.Port, + address = _node.Address, + port = _node.Port, }; outbound.settings.vnext = null; outbound.settings.servers = null; @@ -277,7 +274,7 @@ public partial class CoreConfigV2rayService } case EConfigType.WireGuard: { - var address = node.Address; + var address = _node.Address; if (Utils.IsIpv6(address)) { address = $"[{address}]"; @@ -285,12 +282,12 @@ public partial class CoreConfigV2rayService var peer = new WireguardPeer4Ray { publicKey = protocolExtra.WgPublicKey ?? "", - endpoint = address + ":" + node.Port.ToString() + endpoint = address + ":" + _node.Port.ToString() }; var setting = new Outboundsettings4Ray { address = Utils.String2List(protocolExtra.WgInterfaceAddress), - secretKey = node.Password, + secretKey = _node.Password, reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(int.Parse).ToList(), mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First(), peers = [peer] @@ -302,8 +299,8 @@ public partial class CoreConfigV2rayService } } - outbound.protocol = Global.ProtocolTypes[node.ConfigType]; - if (node.ConfigType == EConfigType.Hysteria2) + outbound.protocol = Global.ProtocolTypes[_node.ConfigType]; + if (_node.ConfigType == EConfigType.Hysteria2) { outbound.protocol = "hysteria"; } @@ -325,13 +322,13 @@ public partial class CoreConfigV2rayService if (enabledTCP) { outbound.mux.enabled = true; - outbound.mux.concurrency = context.AppConfig.Mux4RayItem.Concurrency; + outbound.mux.concurrency = _config.Mux4RayItem.Concurrency; } else if (enabledUDP) { outbound.mux.enabled = true; - outbound.mux.xudpConcurrency = context.AppConfig.Mux4RayItem.XudpConcurrency; - outbound.mux.xudpProxyUDP443 = context.AppConfig.Mux4RayItem.XudpProxyUDP443; + outbound.mux.xudpConcurrency = _config.Mux4RayItem.XudpConcurrency; + outbound.mux.xudpProxyUDP443 = _config.Mux4RayItem.XudpProxyUDP443; } } catch (Exception ex) @@ -344,43 +341,41 @@ public partial class CoreConfigV2rayService { try { - var node = context.Node; - var config = context.AppConfig; var streamSettings = outbound.streamSettings; - var network = node.GetNetwork(); - if (node.ConfigType == EConfigType.Hysteria2) + var network = _node.GetNetwork(); + if (_node.ConfigType == EConfigType.Hysteria2) { network = "hysteria"; } streamSettings.network = network; - var host = node.RequestHost.TrimEx(); - var path = node.Path.TrimEx(); - var sni = node.Sni.TrimEx(); + var host = _node.RequestHost.TrimEx(); + var path = _node.Path.TrimEx(); + var sni = _node.Sni.TrimEx(); var useragent = ""; - if (!config.CoreBasicItem.DefUserAgent.IsNullOrEmpty()) + if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty()) { try { - useragent = Global.UserAgentTexts[config.CoreBasicItem.DefUserAgent]; + useragent = Global.UserAgentTexts[_config.CoreBasicItem.DefUserAgent]; } catch (KeyNotFoundException) { - useragent = config.CoreBasicItem.DefUserAgent; + useragent = _config.CoreBasicItem.DefUserAgent; } } //if tls - if (node.StreamSecurity == Global.StreamSecurity) + if (_node.StreamSecurity == Global.StreamSecurity) { - streamSettings.security = node.StreamSecurity; + streamSettings.security = _node.StreamSecurity; TlsSettings4Ray tlsSettings = new() { - allowInsecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure), - alpn = node.GetAlpn(), - fingerprint = node.Fingerprint.IsNullOrEmpty() ? config.CoreBasicItem.DefFingerprint : node.Fingerprint, - echConfigList = node.EchConfigList.NullIfEmpty(), - echForceQuery = node.EchForceQuery.NullIfEmpty() + allowInsecure = Utils.ToBool(_node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : _node.AllowInsecure), + alpn = _node.GetAlpn(), + fingerprint = _node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : _node.Fingerprint, + echConfigList = _node.EchConfigList.NullIfEmpty(), + echForceQuery = _node.EchForceQuery.NullIfEmpty() }; if (sni.IsNotEmpty()) { @@ -390,7 +385,7 @@ public partial class CoreConfigV2rayService { tlsSettings.serverName = Utils.String2List(host)?.First(); } - var certs = CertPemManager.ParsePemChain(node.Cert); + var certs = CertPemManager.ParsePemChain(_node.Cert); if (certs.Count > 0) { var certsettings = new List(); @@ -407,27 +402,27 @@ public partial class CoreConfigV2rayService tlsSettings.disableSystemRoot = true; tlsSettings.allowInsecure = false; } - else if (!node.CertSha.IsNullOrEmpty()) + else if (!_node.CertSha.IsNullOrEmpty()) { - tlsSettings.pinnedPeerCertSha256 = node.CertSha; + tlsSettings.pinnedPeerCertSha256 = _node.CertSha; tlsSettings.allowInsecure = false; } streamSettings.tlsSettings = tlsSettings; } //if Reality - if (node.StreamSecurity == Global.StreamSecurityReality) + if (_node.StreamSecurity == Global.StreamSecurityReality) { - streamSettings.security = node.StreamSecurity; + streamSettings.security = _node.StreamSecurity; TlsSettings4Ray realitySettings = new() { - fingerprint = node.Fingerprint.IsNullOrEmpty() ? config.CoreBasicItem.DefFingerprint : node.Fingerprint, + fingerprint = _node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : _node.Fingerprint, serverName = sni, - publicKey = node.PublicKey, - shortId = node.ShortId, - spiderX = node.SpiderX, - mldsa65Verify = node.Mldsa65Verify, + publicKey = _node.PublicKey, + shortId = _node.ShortId, + spiderX = _node.SpiderX, + mldsa65Verify = _node.Mldsa65Verify, show = false, }; @@ -440,25 +435,25 @@ public partial class CoreConfigV2rayService case nameof(ETransport.kcp): KcpSettings4Ray kcpSettings = new() { - mtu = config.KcpItem.Mtu, - tti = config.KcpItem.Tti + mtu = _config.KcpItem.Mtu, + tti = _config.KcpItem.Tti }; - kcpSettings.uplinkCapacity = config.KcpItem.UplinkCapacity; - kcpSettings.downlinkCapacity = config.KcpItem.DownlinkCapacity; + kcpSettings.uplinkCapacity = _config.KcpItem.UplinkCapacity; + kcpSettings.downlinkCapacity = _config.KcpItem.DownlinkCapacity; - kcpSettings.congestion = config.KcpItem.Congestion; - kcpSettings.readBufferSize = config.KcpItem.ReadBufferSize; - kcpSettings.writeBufferSize = config.KcpItem.WriteBufferSize; + kcpSettings.congestion = _config.KcpItem.Congestion; + kcpSettings.readBufferSize = _config.KcpItem.ReadBufferSize; + kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize; streamSettings.finalmask ??= new(); - if (Global.KcpHeaderMaskMap.TryGetValue(node.HeaderType, out var header)) + if (Global.KcpHeaderMaskMap.TryGetValue(_node.HeaderType, out var header)) { streamSettings.finalmask.udp = [ new Mask4Ray { type = header, - settings = node.HeaderType == "dns" && !host.IsNullOrEmpty() ? new MaskSettings4Ray { domain = host } : null + settings = _node.HeaderType == "dns" && !host.IsNullOrEmpty() ? new MaskSettings4Ray { domain = host } : null } ]; } @@ -528,13 +523,13 @@ public partial class CoreConfigV2rayService { xhttpSettings.host = host; } - if (node.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(node.HeaderType)) + if (_node.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(_node.HeaderType)) { - xhttpSettings.mode = node.HeaderType; + xhttpSettings.mode = _node.HeaderType; } - if (node.Extra.IsNotEmpty()) + if (_node.Extra.IsNotEmpty()) { - xhttpSettings.extra = JsonUtils.ParseJson(node.Extra); + xhttpSettings.extra = JsonUtils.ParseJson(_node.Extra); } streamSettings.xhttpSettings = xhttpSettings; @@ -562,11 +557,11 @@ public partial class CoreConfigV2rayService key = path, header = new Header4Ray { - type = node.HeaderType + type = _node.HeaderType } }; streamSettings.quicSettings = quicsettings; - if (node.StreamSecurity == Global.StreamSecurity) + if (_node.StreamSecurity == Global.StreamSecurity) { if (sni.IsNotEmpty()) { @@ -574,7 +569,7 @@ public partial class CoreConfigV2rayService } else { - streamSettings.tlsSettings.serverName = node.Address; + streamSettings.tlsSettings.serverName = _node.Address; } } break; @@ -584,28 +579,28 @@ public partial class CoreConfigV2rayService { authority = host.NullIfEmpty(), serviceName = path, - multiMode = node.HeaderType == Global.GrpcMultiMode, - idle_timeout = config.GrpcItem.IdleTimeout, - health_check_timeout = config.GrpcItem.HealthCheckTimeout, - permit_without_stream = config.GrpcItem.PermitWithoutStream, - initial_windows_size = config.GrpcItem.InitialWindowsSize, + multiMode = _node.HeaderType == Global.GrpcMultiMode, + idle_timeout = _config.GrpcItem.IdleTimeout, + health_check_timeout = _config.GrpcItem.HealthCheckTimeout, + permit_without_stream = _config.GrpcItem.PermitWithoutStream, + initial_windows_size = _config.GrpcItem.InitialWindowsSize, }; streamSettings.grpcSettings = grpcSettings; break; case "hysteria": - var protocolExtra = node.GetProtocolExtra(); + var protocolExtra = _node.GetProtocolExtra(); var ports = protocolExtra?.Ports; int? upMbps = protocolExtra?.UpMbps is { } su and >= 0 ? su - : config.HysteriaItem.UpMbps; + : _config.HysteriaItem.UpMbps; int? downMbps = protocolExtra?.DownMbps is { } sd and >= 0 ? sd - : config.HysteriaItem.UpMbps; + : _config.HysteriaItem.UpMbps; var hopInterval = !protocolExtra.HopInterval.IsNullOrEmpty() ? protocolExtra.HopInterval - : (config.HysteriaItem.HopInterval >= 5 - ? config.HysteriaItem.HopInterval + : (_config.HysteriaItem.HopInterval >= 5 + ? _config.HysteriaItem.HopInterval : Global.Hysteria2DefaultHopInt).ToString(); HysteriaUdpHop4Ray? udpHop = null; if (!ports.IsNullOrEmpty() && @@ -620,7 +615,7 @@ public partial class CoreConfigV2rayService streamSettings.hysteriaSettings = new() { version = 2, - auth = node.Password, + auth = _node.Password, up = upMbps > 0 ? $"{upMbps}mbps" : null, down = downMbps > 0 ? $"{downMbps}mbps" : null, udphop = udpHop, @@ -641,13 +636,13 @@ public partial class CoreConfigV2rayService default: //tcp - if (node.HeaderType == Global.TcpHeaderHttp) + if (_node.HeaderType == Global.TcpHeaderHttp) { TcpSettings4Ray tcpSettings = new() { header = new Header4Ray { - type = node.HeaderType + type = _node.HeaderType } }; @@ -681,7 +676,7 @@ public partial class CoreConfigV2rayService private List BuildOutboundsList(string baseTagName = Global.ProxyTag) { var nodes = new List(); - foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) + foreach (var nodeId in Utils.String2List(_node.GetProtocolExtra().ChildItems) ?? []) { if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) { @@ -710,7 +705,7 @@ public partial class CoreConfigV2rayService private List BuildChainOutboundsList(string baseTagName = Global.ProxyTag) { var nodes = new List(); - foreach (var nodeId in Utils.String2List(context.Node.GetProtocolExtra().ChildItems) ?? []) + foreach (var nodeId in Utils.String2List(_node.GetProtocolExtra().ChildItems) ?? []) { if (context.AllProxiesMap.TryGetValue(nodeId, out var node)) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs index 2bac1f37..3d824102 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs @@ -8,7 +8,7 @@ public partial class CoreConfigV2rayService { if (_coreConfig.routing?.rules != null) { - _coreConfig.routing.domainStrategy = context.AppConfig.RoutingBasicItem.DomainStrategy; + _coreConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy; var routing = context.RoutingItem; if (routing != null) @@ -165,7 +165,7 @@ public partial class CoreConfigV2rayService } var tag = $"{node.IndexId}-{Global.ProxyTag}"; - if (_coreConfig.outbounds.Any(p => p.tag == tag)) + if (_coreConfig.outbounds.Any(p => p.tag.StartsWith(tag))) { return tag; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs index 6b529f1f..6364b7bd 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs @@ -4,7 +4,7 @@ public partial class CoreConfigV2rayService { private void GenStatistic() { - if (context.AppConfig.GuiItem.EnableStatistics || context.AppConfig.GuiItem.DisplayRealTimeSpeed) + if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed) { var tag = EInboundProtocol.api.ToString(); Metrics4Ray apiObj = new();