From 48d549fd147b56cf2d4a047ef7a440932e8e2728 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Wed, 7 Jan 2026 16:21:20 +0800 Subject: [PATCH] Support group config type --- .../Manager/ProfileGroupItemManager.cs | 67 +++++++++++++++++++ .../Singbox/CoreConfigSingboxService.cs | 4 +- .../CoreConfig/Singbox/SingboxDnsService.cs | 23 ++++++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs b/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs index 499ad3de..c75b43ce 100644 --- a/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs +++ b/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs @@ -316,5 +316,72 @@ public class ProfileGroupItemManager return childAddresses; } + public static async Task> GetAllChildEchQuerySni(string indexId) + { + // include grand children + var childAddresses = new HashSet(); + if (!Instance.TryGet(indexId, out var groupItem) || groupItem == null) + { + return childAddresses; + } + + if (groupItem.SubChildItems.IsNotEmpty()) + { + var subItems = await GetSubChildProfileItems(groupItem); + foreach (var childNode in subItems) + { + if (childNode.EchConfigList.IsNullOrEmpty()) + { + continue; + } + 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 childIds = Utils.String2List(groupItem.ChildItems) ?? []; + + foreach (var childId in childIds) + { + var childNode = await AppManager.Instance.GetProfileItem(childId); + if (childNode == null) + { + continue; + } + + if (!childNode.IsComplex() && !childNode.EchConfigList.IsNullOrEmpty()) + { + 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); + } + } + else if (childNode.ConfigType.IsGroupType()) + { + var subAddresses = await GetAllChildDomainAddresses(childNode.IndexId); + foreach (var addr in subAddresses) + { + childAddresses.Add(addr); + } + } + } + + return childAddresses; + } + #endregion Helper } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs index 71f25acd..397e9340 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs @@ -371,7 +371,7 @@ public partial class CoreConfigSingboxService(Config config) await GenRouting(singboxConfig); await GenExperimental(singboxConfig); - await GenDns(null, singboxConfig); + await GenDns(parentNode, singboxConfig); await ConvertGeo2Ruleset(singboxConfig); ret.Success = true; @@ -428,7 +428,7 @@ public partial class CoreConfigSingboxService(Config config) await GenRouting(singboxConfig); await GenExperimental(singboxConfig); - await GenDns(null, singboxConfig); + await GenDns(parentNode, singboxConfig); await ConvertGeo2Ruleset(singboxConfig); ret.Success = true; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index 4d173372..1375d760 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -153,6 +153,12 @@ public partial class CoreConfigSingboxService } singboxConfig.dns.servers.Add(echDnsObject); } + 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); } @@ -193,14 +199,27 @@ public partial class CoreConfigSingboxService && node?.EchConfigList?.Contains("://") == true) { var idx = node.EchConfigList.IndexOf('+'); - var queryServerName = idx > 0 ? node.EchConfigList[..idx] : node.Sni; + List queryServerNames = [(idx > 0 ? node.EchConfigList[..idx] : node.Sni)]; singboxConfig.dns.rules.Add(new() { query_type = new List { 64, 65 }, server = Global.SingboxEchDNSTag, - domain = [queryServerName], + domain = queryServerNames, }); } + else if (node?.ConfigType.IsGroupType() == true) + { + var queryServerNames = (await ProfileGroupItemManager.GetAllChildEchQuerySni(node.IndexId)).ToList(); + if (queryServerNames.Count > 0) + { + singboxConfig.dns.rules.Add(new() + { + query_type = new List { 64, 65 }, + server = Global.SingboxEchDNSTag, + domain = queryServerNames, + }); + } + } if (simpleDNSItem.BlockBindingQuery == true) {