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++; } } }