diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs
index e502435f..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.";
@@ -88,7 +87,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..b9a369ec 100644
--- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs
+++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs
@@ -1231,41 +1231,21 @@ 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)
{
+ if (node.ConfigType != EConfigType.Custom || !(node.PreSocksPort > 0))
+ {
+ return null;
+ }
ProfileItem? itemSocks = null;
- if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
+ var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
+ itemSocks = new ProfileItem()
{
- 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)
- };
- }
- else if (node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0)
- {
- var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
- itemSocks = new ProfileItem()
- {
- CoreType = preCoreType,
- ConfigType = EConfigType.SOCKS,
- Address = Global.Loopback,
- Port = node.PreSocksPort.Value,
- };
- }
- await Task.CompletedTask;
+ CoreType = preCoreType,
+ ConfigType = EConfigType.SOCKS,
+ Address = Global.Loopback,
+ Port = node.PreSocksPort.Value,
+ };
return itemSocks;
}
diff --git a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs
index f51e2051..359aab3b 100644
--- a/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs
+++ b/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs
@@ -7,27 +7,27 @@ 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),
_ => 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 +93,21 @@ 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());
+ var ids = selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty())
+ .Select(serverTestItem => serverTestItem.IndexId);
+ var nodes = await AppManager.Instance.GetProfileItemsByIndexIds(ids);
+ foreach (var node in nodes)
+ {
+ 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 +117,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 +141,128 @@ 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 = [],
+ TunProtectSsPort = 0,
+ ProxyRelaySsPort = 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)
+ {
+ var ruleOutboundNodeAct = await FillNodeContext(context, ruleOutboundNode, false);
+ context.AllProxiesMap[$"remark:{ruleItem.OutboundTag}"] = ruleOutboundNodeAct;
+ }
+ }
+ }
+ return context;
+ }
+
+ private static async Task FillNodeContext(CoreConfigContext context, ProfileItem node, bool includeSubChain = true)
+ {
+ if (node.IndexId.IsNullOrEmpty())
+ {
+ return node;
+ }
+ var newItems = new List { node };
+ if (node.ConfigType.IsGroupType())
+ {
+ var (groupChildList, _) = await GroupProfileManager.GetChildProfileItems(node);
+ foreach (var childItem in groupChildList.Where(childItem => !context.AllProxiesMap.ContainsKey(childItem.IndexId)))
+ {
+ 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)
+ {
+ var address = item.Address;
+ if (Utils.IsDomain(address))
+ {
+ context.ProtectDomainList.Add(address);
+ }
+
+ if (item.EchConfigList.IsNullOrEmpty())
+ {
+ continue;
+ }
+
+ var echQuerySni = item.Sni;
+ if (item.StreamSecurity == Global.StreamSecurity
+ && item.EchConfigList?.Contains("://") == true)
+ {
+ var idx = item.EchConfigList.IndexOf('+');
+ echQuerySni = idx > 0 ? item.EchConfigList[..idx] : item.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/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs
index 0e471568..e773c2ef 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(IEnumerable indexIds)
+ {
+ var ids = indexIds.Where(id => !id.IsNullOrEmpty()).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())
diff --git a/v2rayN/ServiceLib/Manager/CoreManager.cs b/v2rayN/ServiceLib/Manager/CoreManager.cs
index 53240960..0e4c33d6 100644
--- a/v2rayN/ServiceLib/Manager/CoreManager.cs
+++ b/v2rayN/ServiceLib/Manager/CoreManager.cs
@@ -66,7 +66,40 @@ public class CoreManager
}
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
- var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
+ var context = await CoreConfigHandler.BuildCoreConfigContext(_config, node);
+ CoreConfigContext? preContext = null;
+ if (context.IsTunEnabled)
+ {
+ var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
+ if (coreType == ECoreType.Xray && node.ConfigType != EConfigType.Custom)
+ {
+ var tunProtectSsPort = Utils.GetFreePort();
+ var proxyRelaySsPort = Utils.GetFreePort();
+ context = context with { TunProtectSsPort = tunProtectSsPort, ProxyRelaySsPort = proxyRelaySsPort, };
+ var preItem = new ProfileItem()
+ {
+ CoreType = ECoreType.sing_box,
+ ConfigType = EConfigType.Shadowsocks,
+ Address = Global.Loopback,
+ Port = proxyRelaySsPort,
+ Password = Global.None,
+ };
+ preItem.SetProtocolExtra(preItem.GetProtocolExtra() with
+ {
+ SsMethod = Global.None,
+ });
+ preContext = context with { Node = preItem, };
+ }
+ else
+ {
+ var preItem = ConfigHandler.GetPreSocksItem(_config, node, coreType);
+ if (preItem is not null)
+ {
+ preContext = context with { Node = preItem, };
+ }
+ }
+ }
+ var result = await CoreConfigHandler.GenerateClientConfig(context, fileName);
if (result.Success != true)
{
await UpdateFunc(true, result.Msg);
@@ -85,8 +118,8 @@ public class CoreManager
await WindowsUtils.RemoveTunDevice();
}
- await CoreStart(node);
- await CoreStartPreService(node);
+ await CoreStart(context);
+ await CoreStartPreService(preContext);
if (_processService != null)
{
await UpdateFunc(true, $"{node.GetSummary()}");
@@ -122,7 +155,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 +199,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,27 +214,22 @@ public class CoreManager
_processService = proc;
}
- private async Task CoreStartPreService(ProfileItem node)
+ private async Task CoreStartPreService(CoreConfigContext? preContext)
{
- if (_processService != null && !_processService.HasExited)
+ if (_processService is { HasExited: false } && preContext != null)
{
- var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
- var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
- if (itemSocks != null)
+ var preCoreType = preContext?.Node?.CoreType ?? ECoreType.sing_box;
+ var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
+ var result = await CoreConfigHandler.GenerateClientConfig(preContext, fileName);
+ if (result.Success)
{
- var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
- var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
- var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
- if (result.Success)
+ var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
+ var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
+ if (proc is null)
{
- var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
- var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
- if (proc is null)
- {
- return;
- }
- _processPreService = proc;
+ return;
}
+ _processPreService = proc;
}
}
}
diff --git a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs
index 53ef0429..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,59 +140,30 @@ public class GroupProfileManager
!p.ConfigType.IsComplexType() &&
(extra.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extra.Filter))
)
- .ToList() ?? new();
+ .ToList() ?? [];
}
- public static async Task> GetAllChildDomainAddresses(ProfileItem profileItem)
+ public static async Task> GetAllChildProfileItems(ProfileItem profileItem)
{
- var childAddresses = new HashSet();
- var (childItems, _) = await GetChildProfileItems(profileItem);
- foreach (var child in childItems)
- {
- 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);
- }
- }
- }
- return childAddresses;
+ var allChildItems = new List();
+ var visited = new HashSet();
+
+ await CollectChildItems(profileItem, allChildItems, visited);
+
+ return allChildItems;
}
- public static async Task> GetAllChildEchQuerySni(ProfileItem profileItem)
+ private static async Task CollectChildItems(ProfileItem profileItem, List allChildItems, HashSet visited)
{
- var childAddresses = new HashSet();
var (childItems, _) = await GetChildProfileItems(profileItem);
- foreach (var childNode in childItems)
+ foreach (var child in childItems.Where(child => visited.Add(child.IndexId)))
{
- if (!childNode.IsComplex() && !childNode.EchConfigList.IsNullOrEmpty())
+ allChildItems.Add(child);
+
+ if (child.ConfigType.IsGroupType())
{
- 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);
- foreach (var addr in subAddresses)
- {
- childAddresses.Add(addr);
- }
+ await CollectChildItems(child, allChildItems, visited);
}
}
- return childAddresses;
}
}
diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs
index 46caee85..7dc8c266 100644
--- a/v2rayN/ServiceLib/Models/ConfigItems.cs
+++ b/v2rayN/ServiceLib/Models/ConfigItems.cs
@@ -144,7 +144,6 @@ public class TunModeItem
public bool StrictRoute { get; set; } = true;
public string Stack { get; set; }
public int Mtu { get; set; }
- public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
}
diff --git a/v2rayN/ServiceLib/Models/CoreConfigContext.cs b/v2rayN/ServiceLib/Models/CoreConfigContext.cs
new file mode 100644
index 00000000..59e9537e
--- /dev/null
+++ b/v2rayN/ServiceLib/Models/CoreConfigContext.cs
@@ -0,0 +1,21 @@
+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();
+ // -> tun inbound --(if routing proxy)--> relay outbound
+ // -> proxy core (relay inbound --> proxy outbound --(dialerProxy)--> protect outbound)
+ // -> protect inbound -> direct proxy outbound data -> internet
+ public int TunProtectSsPort { get; init; } = 0;
+ public int ProxyRelaySsPort { get; init; } = 0;
+}
diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs
index c0cd2e08..c1eaa3c8 100644
--- a/v2rayN/ServiceLib/Models/SingboxConfig.cs
+++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs
@@ -255,9 +255,8 @@ public class Server4Sbox : BaseServer4Sbox
// public List? path { get; set; } // hosts
public Dictionary>? predefined { get; set; }
- // Deprecated
+ // 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; }
diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index 6f223693..0f3a45a7 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -3771,15 +3771,6 @@ namespace ServiceLib.Resx {
}
}
- ///
- /// 查找类似 Enable additional Inbound 的本地化字符串。
- ///
- public static string TbSettingsEnableExInbound {
- get {
- return ResourceManager.GetString("TbSettingsEnableExInbound", resourceCulture);
- }
- }
-
///
/// 查找类似 Enable fragment 的本地化字符串。
///
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index dbce6ac4..8a05f2b3 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -1071,9 +1071,6 @@
MTU
-
- فعال سازی additional Inbound
-
فعال سازی آدرس IPv6
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
index 005a51d5..2b92417f 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
@@ -1068,9 +1068,6 @@
MTU
-
- Activer un port d’écoute supplémentaire
-
Activer IPv6
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index 3d169590..94711705 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -1071,9 +1071,6 @@
MTU
-
- További bejövő engedélyezése
-
IPv6 cím engedélyezése
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index 041a103b..756a9c93 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -1071,9 +1071,6 @@
MTU
-
- Enable additional Inbound
-
Enable IPv6 Address
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index 66ebef79..51a31851 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -1071,9 +1071,6 @@
MTU
-
- Включить дополнительный входящий канал
-
Включить IPv6 адреса
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
index c8936668..281c81e2 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -1068,9 +1068,6 @@
MTU
-
- 启用额外监听端口
-
启用 IPv6
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
index 2ee4dc4f..ce4198ce 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -1068,9 +1068,6 @@
MTU
-
- 啟用額外偵聽連接埠
-
啟用 IPv6
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..1c08fcc5 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs
@@ -1,43 +1,34 @@
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 readonly Config _config = context.AppConfig;
+ private readonly ProfileItem _node = context.Node;
+
+ private SingboxConfig _coreConfig = new();
#region public gen function
- public async Task GenerateClientConfigContent(ProfileItem node)
+ public RetResult GenerateClientConfigContent()
{
var ret = new RetResult();
try
{
- 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;
}
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 +36,76 @@ 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();
+ if (context.TunProtectSsPort is > 0 and <= 65535)
+ {
+ var ssInbound = new
+ {
+ type = "shadowsocks",
+ tag = "tun-protect-ss",
+ listen = Global.Loopback,
+ listen_port = context.TunProtectSsPort,
+ method = "none",
+ password = "none",
+ };
+ var directRule = new Rule4Sbox()
+ {
+ inbound = new List { ssInbound.tag },
+ outbound = Global.DirectTag,
+ };
+ var singboxConfigNode = JsonUtils.ParseJson(ret.Data.ToString())!.AsObject();
+ var inboundsNode = singboxConfigNode["inbounds"]!.AsArray();
+ inboundsNode.Add(JsonUtils.SerializeToNode(ssInbound, new JsonSerializerOptions
+ {
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
+ }));
+ var routeNode = singboxConfigNode["route"]?.AsObject();
+ var rulesNode = routeNode?["rules"]?.AsArray();
+ var protectRuleNode = JsonUtils.SerializeToNode(directRule,
+ new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
+ if (rulesNode != null)
+ {
+ rulesNode.Insert(0, protectRuleNode);
+ }
+ else
+ {
+ var newRulesNode = new JsonArray() { protectRuleNode };
+ if (routeNode is null)
+ {
+ var newRouteNode = new JsonObject() { ["rules"] = newRulesNode };
+ singboxConfigNode["route"] = newRouteNode;
+ }
+ else
+ {
+ routeNode["rules"] = newRulesNode;
+ }
+ }
+ ret.Data = JsonUtils.Serialize(singboxConfigNode);
+ }
return ret;
}
catch (Exception ex)
@@ -93,17 +116,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 +131,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 +150,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 +167,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 +207,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 +219,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,20 +234,20 @@ public partial class CoreConfigSingboxService(Config config)
}
}
- public async Task GenerateClientSpeedtestConfig(ProfileItem node, int port)
+ public RetResult GenerateClientSpeedtestConfig(int port)
{
var ret = new RetResult();
try
{
- 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;
}
@@ -272,44 +260,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,202 +283,7 @@ public partial class CoreConfigSingboxService(Config config)
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
- ret.Data = JsonUtils.Serialize(singboxConfig);
- return ret;
- }
- catch (Exception ex)
- {
- Logging.SaveLog(_tag, ex);
- ret.Msg = ResUI.FailedGenDefaultConfiguration;
- return ret;
- }
- }
-
- 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)
- {
- var ret = new RetResult();
- 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);
- var singboxConfig = JsonUtils.Deserialize(txtFile);
- if (singboxConfig == null)
- {
- File.Copy(addressFileName, fileName);
- }
- else
- {
- await GenInbounds(singboxConfig);
- await GenExperimental(singboxConfig);
-
- var content = JsonUtils.Serialize(singboxConfig, 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;
+ ret.Data = JsonUtils.Serialize(_coreConfig);
return ret;
}
catch (Exception ex)
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..72e64c46 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,46 @@ 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();
+ 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();
+ _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,61 +380,33 @@ public partial class CoreConfigSingboxService
var dns4Sbox = JsonUtils.Deserialize(strDNS);
if (dns4Sbox is null)
{
- return 0;
+ return;
}
- singboxConfig.dns = dns4Sbox;
-
- if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty())
+ _coreConfig.dns = dns4Sbox;
+ if (dns4Sbox.servers?.Count > 0 &&
+ dns4Sbox.servers.First().address.IsNullOrEmpty())
{
- await GenDnsDomainsCompatible(singboxConfig, item);
+ GenDnsProtectCustom();
}
else
{
- await GenDnsDomainsLegacyCompatible(singboxConfig, item);
+ GenDnsProtectCustomLegacy();
}
-
- await GenOutboundDnsRule(node, singboxConfig);
}
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 ??= [];
var tag = Global.SingboxLocalDNSTag;
-
- var finalDnsAddress = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress;
-
- var localDnsServer = ParseDnsAddress(finalDnsAddress);
- localDnsServer.tag = tag;
-
- dns4Sbox.servers.Add(localDnsServer);
-
- singboxConfig.dns = dns4Sbox;
- return await Task.FromResult(0);
- }
-
- private async Task GenDnsDomainsLegacyCompatible(SingboxConfig singboxConfig, DNSItem? dnsItem)
- {
- 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,
@@ -475,56 +418,39 @@ public partial class CoreConfigSingboxService
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
- });
- }
+ var finalDnsAddress = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress;
- singboxConfig.dns = dns4Sbox;
- return await Task.FromResult(0);
+ var localDnsServer = ParseDnsAddress(finalDnsAddress);
+ localDnsServer.tag = tag;
+
+ dns4Sbox.servers.Add(localDnsServer);
+ dns4Sbox.rules.Insert(0, BuildProtectDomainRule());
+
+ _coreConfig.dns = dns4Sbox;
}
- private async Task GenOutboundDnsRule(ProfileItem? node, SingboxConfig singboxConfig)
+ private void GenDnsProtectCustomLegacy()
{
- if (node == null)
- {
- return 0;
- }
+ GenDnsProtectCustom();
- List domain = new();
- if (Utils.IsDomain(node.Address)) // normal outbound
+ var localDnsServer = _coreConfig.dns?.servers?.FirstOrDefault(s => s.tag == Global.SingboxLocalDNSTag);
+ if (localDnsServer == null)
{
- 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;
+ return;
}
+ localDnsServer.type = null;
+ localDnsServer.server = null;
+ var dnsItem = context.RawDnsItem;
+ localDnsServer.address = string.IsNullOrEmpty(dnsItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dnsItem?.DomainDNSAddress;
+ }
- singboxConfig.dns.rules ??= new List();
- singboxConfig.dns.rules.Insert(0, new Rule4Sbox
+ private Rule4Sbox BuildProtectDomainRule()
+ {
+ 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..3a27c7da 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs
@@ -2,15 +2,16 @@ 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 = [];
+ var listenPort = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
+ _coreConfig.inbounds = [];
- if (!_config.TunModeItem.EnableTun
- || (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box))
+ if (!context.IsTunEnabled
+ || (context.IsTunEnabled && _node.Port != listenPort))
{
var inbound = new Inbound4Sbox()
{
@@ -18,23 +19,23 @@ 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);
+ inbound.listen_port = listenPort;
if (_config.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 (_config.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())
@@ -49,7 +50,7 @@ public partial class CoreConfigSingboxService
}
}
- if (_config.TunModeItem.EnableTun)
+ if (context.IsTunEnabled)
{
if (_config.TunModeItem.Mtu <= 0)
{
@@ -71,17 +72,16 @@ public partial class CoreConfigSingboxService
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..b438242c 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxLogService.cs
@@ -2,7 +2,7 @@ namespace ServiceLib.Services.CoreConfig;
public partial class CoreConfigSingboxService
{
- private async Task GenLog(SingboxConfig singboxConfig)
+ private void GenLog()
{
try
{
@@ -11,11 +11,11 @@ public partial class CoreConfigSingboxService
case "debug":
case "info":
case "error":
- singboxConfig.log.level = _config.CoreBasicItem.Loglevel;
+ _coreConfig.log.level = _config.CoreBasicItem.Loglevel;
break;
case "warning":
- singboxConfig.log.level = "warn";
+ _coreConfig.log.level = "warn";
break;
default:
@@ -23,18 +23,17 @@ public partial class CoreConfigSingboxService
}
if (_config.CoreBasicItem.Loglevel == Global.None)
{
- singboxConfig.log.disabled = true;
+ _coreConfig.log.disabled = true;
}
if (_config.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..23b331f6 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs
@@ -2,20 +2,93 @@ 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 (!_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 (_node.ConfigType)
+ {
+ case EConfigType.PolicyGroup:
+ proxyOutboundList = BuildOutboundsList(baseTagName);
+ break;
+ case EConfigType.ProxyChain:
+ proxyOutboundList = BuildChainOutboundsList(baseTagName);
+ break;
+ }
+ return proxyOutboundList;
+ }
+
+ private BaseServer4Sbox BuildProxyServer()
{
try
{
- var protocolExtra = node.GetProtocolExtra();
- outbound.server = node.Address;
- outbound.server_port = node.Port;
- outbound.type = Global.ProtocolTypes[node.ConfigType];
+ 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();
+ }
- switch (node.ConfigType)
+ private void FillOutbound(Outbound4Sbox outbound)
+ {
+ try
+ {
+ var protocolExtra = _node.GetProtocolExtra();
+ outbound.server = _node.Address;
+ outbound.server_port = _node.Port;
+ outbound.type = Global.ProtocolTypes[_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))
{
@@ -26,41 +99,41 @@ public partial class CoreConfigSingboxService
outbound.security = Global.DefaultSecurity;
}
- await GenOutboundMux(node, outbound);
- await GenOutboundTransport(node, outbound);
+ FillOutboundMux(outbound);
+ FillOutboundTransport(outbound);
break;
}
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();
@@ -84,33 +157,33 @@ public partial class CoreConfigSingboxService
}
}
- await GenOutboundMux(node, outbound);
+ FillOutboundMux(outbound);
break;
}
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";
@@ -120,23 +193,23 @@ 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;
+ outbound.password = _node.Password;
- await GenOutboundMux(node, outbound);
- await GenOutboundTransport(node, outbound);
+ FillOutboundMux(outbound);
+ FillOutboundTransport(outbound);
break;
}
case EConfigType.Hysteria2:
{
- outbound.password = node.Password;
+ outbound.password = _node.Password;
if (!protocolExtra.SalamanderPass.IsNullOrEmpty())
{
@@ -190,37 +263,36 @@ 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;
}
}
- 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 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:
{
@@ -229,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;
@@ -245,47 +317,13 @@ 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;
+ var muxEnabled = _node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
{
var mux = new Multiplex4Sbox()
@@ -302,66 +340,65 @@ 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
{
- if (node.StreamSecurity is not (Global.StreamSecurityReality or Global.StreamSecurity))
+ 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)
+ if (_node.ConfigType is EConfigType.Shadowsocks or EConfigType.SOCKS or EConfigType.WireGuard)
{
- return await Task.FromResult(0);
+ return;
}
- var server_name = string.Empty;
- if (node.Sni.IsNotEmpty())
+ var serverName = string.Empty;
+ if (_node.Sni.IsNotEmpty())
{
- server_name = node.Sni;
+ serverName = _node.Sni;
}
- else if (node.RequestHost.IsNotEmpty())
+ 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),
- alpn = node.GetAlpn(),
+ server_name = serverName,
+ 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() ? _config.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;
@@ -372,35 +409,34 @@ 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 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())
@@ -429,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;
@@ -451,7 +487,7 @@ public partial class CoreConfigSingboxService
case nameof(ETransport.grpc):
transport.type = nameof(ETransport.grpc);
- transport.service_name = node.Path;
+ 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;
@@ -469,458 +505,190 @@ 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 = _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 = $"{baseTagName}-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 = baseTagName,
+ 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(_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}";
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(_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}";
+ var dialerProxyTag = i != nodesReverse.Count - 1 ? $"chain-{baseTagName}-{i + 1}" : 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();
+ if (chainStartNodes.Count == 1)
+ {
+ foreach (var existedChainEndNode in resultOutbounds.Where(n => n.detour == currentTag))
+ {
+ 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++;
+ }
+ }
+ }
+ 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 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
{
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 +704,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..9bcb9adf 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs
@@ -2,23 +2,23 @@ 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.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
@@ -26,23 +26,23 @@ public partial class CoreConfigSingboxService
if (_config.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
@@ -51,66 +51,62 @@ public partial class CoreConfigSingboxService
if (_config.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 routing = context.RoutingItem;
+ if (routing.DomainStrategy4Singbox.IsNotEmpty())
{
- domainStrategy = defaultRouting.DomainStrategy4Singbox;
+ domainStrategy = routing.DomainStrategy4Singbox;
}
var resolveRule = new Rule4Sbox
{
@@ -119,10 +115,9 @@ public partial class CoreConfigSingboxService
};
if (_config.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)
{
@@ -149,10 +144,10 @@ public partial class CoreConfigSingboxService
}
if (_config.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.StartsWith(tag))
+ || (_coreConfig.endpoints != null && _coreConfig.endpoints.Any(e => e.tag.StartsWith(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..bb4c4b3a 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())
@@ -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..e2beff34 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxStatisticService.cs
@@ -2,12 +2,12 @@ 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}",
};
@@ -15,15 +15,13 @@ public partial class CoreConfigSingboxService
if (_config.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.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..8187f854 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs
@@ -1,44 +1,39 @@
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 readonly Config _config = context.AppConfig;
+ private readonly ProfileItem _node = context.Node;
+
+ private V2rayConfig _coreConfig = new();
#region public gen function
- public async Task GenerateClientConfigContent(ProfileItem node)
+ public RetResult GenerateClientConfigContent()
{
var ret = new RetResult();
try
{
- if (node == null
- || !node.IsValid())
+ if (context.IsTunEnabled && context.TunProtectSsPort > 0 && context.ProxyRelaySsPort > 0)
+ {
+ return GenerateClientProxyRelayConfig();
+ }
+ 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;
}
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 +41,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,18 +73,11 @@ public partial class CoreConfigV2rayService(Config config)
}
}
- public async Task GenerateClientMultipleLoadConfig(ProfileItem parentNode)
+ 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);
@@ -102,172 +88,8 @@ public partial class CoreConfigV2rayService(Config config)
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)
- {
- 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)
+ _coreConfig = JsonUtils.Deserialize(result);
+ if (_coreConfig == null)
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
@@ -285,10 +107,10 @@ public partial class CoreConfigV2rayService(Config config)
Logging.SaveLog(_tag, ex);
}
- await GenLog(v2rayConfig);
- v2rayConfig.inbounds.Clear();
- v2rayConfig.outbounds.Clear();
- v2rayConfig.routing.rules.Clear();
+ GenLog();
+ _coreConfig.inbounds.Clear();
+ _coreConfig.outbounds.Clear();
+ _coreConfig.routing.rules.Clear();
var initPort = AppManager.Instance.GetLocalPort(EInboundProtocol.speedtest);
@@ -302,7 +124,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;
@@ -342,27 +164,40 @@ public partial class CoreConfigV2rayService(Config config)
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 outbound = JsonUtils.Deserialize(txtOutbound);
- await GenOutbound(item, outbound);
- outbound.tag = Global.ProxyTag + inbound.port.ToString();
- v2rayConfig.outbounds.Add(outbound);
+ 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;
+ var multipleLoad = _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"
};
- v2rayConfig.routing.rules.Add(rule);
+ if (isBalancer)
+ {
+ rule.balancerTag = tag;
+ rule.outboundTag = null;
+ }
+ _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)
@@ -373,21 +208,21 @@ public partial class CoreConfigV2rayService(Config config)
}
}
- public async Task GenerateClientSpeedtestConfig(ProfileItem node, int port)
+ public RetResult GenerateClientSpeedtestConfig(int port)
{
var ret = new RetResult();
try
{
- 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;
}
@@ -398,20 +233,19 @@ 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);
- await GenOutbound(node, v2rayConfig.outbounds.First());
- await GenMoreOutbounds(node, v2rayConfig);
+ 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,
@@ -421,7 +255,108 @@ public partial class CoreConfigV2rayService(Config config)
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
- ret.Data = JsonUtils.Serialize(v2rayConfig);
+ ret.Data = JsonUtils.Serialize(_coreConfig);
+ return ret;
+ }
+ catch (Exception ex)
+ {
+ Logging.SaveLog(_tag, ex);
+ ret.Msg = ResUI.FailedGenDefaultConfiguration;
+ return ret;
+ }
+ }
+
+ public RetResult GenerateClientProxyRelayConfig()
+ {
+ var ret = new RetResult();
+ try
+ {
+ if (_node == null
+ || !_node.IsValid())
+ {
+ ret.Msg = ResUI.CheckServerSettings;
+ return ret;
+ }
+
+ if (_node.GetNetwork() is nameof(ETransport.quic))
+ {
+ ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}";
+ return ret;
+ }
+
+ var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
+ if (result.IsNullOrEmpty())
+ {
+ ret.Msg = ResUI.FailedGetDefaultConfiguration;
+ return ret;
+ }
+
+ _coreConfig = JsonUtils.Deserialize(result);
+ if (_coreConfig == null)
+ {
+ ret.Msg = ResUI.FailedGenDefaultConfiguration;
+ return ret;
+ }
+
+ GenLog();
+ _coreConfig.outbounds.Clear();
+ GenOutbounds();
+
+ var protectNode = new ProfileItem()
+ {
+ CoreType = ECoreType.sing_box,
+ ConfigType = EConfigType.Shadowsocks,
+ Address = Global.Loopback,
+ Port = context.TunProtectSsPort,
+ Password = Global.None,
+ };
+ protectNode.SetProtocolExtra(protectNode.GetProtocolExtra() with
+ {
+ SsMethod = Global.None,
+ });
+
+ foreach (var outbound in _coreConfig.outbounds.Where(outbound => outbound.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
+ {
+ outbound.streamSettings ??= new StreamSettings4Ray();
+ outbound.streamSettings.sockopt ??= new Sockopt4Ray();
+ outbound.streamSettings.sockopt.dialerProxy = "tun-project-ss";
+ }
+ _coreConfig.outbounds.Add(new CoreConfigV2rayService(context with
+ {
+ Node = protectNode,
+ }).BuildProxyOutbound("tun-project-ss"));
+
+ var hasBalancer = _coreConfig.routing.balancers is { Count: > 0 };
+ _coreConfig.routing.rules =
+ [
+ new()
+ {
+ inboundTag = new List { "proxy-relay-ss" },
+ outboundTag = hasBalancer ? null : Global.ProxyTag,
+ balancerTag = hasBalancer ? Global.ProxyTag : null,
+ type = "field"
+ }
+ ];
+ _coreConfig.inbounds.Clear();
+
+ var configNode = JsonUtils.ParseJson(JsonUtils.Serialize(_coreConfig))!;
+ configNode["inbounds"]!.AsArray().Add(new
+ {
+ listen = Global.Loopback,
+ port = context.ProxyRelaySsPort,
+ protocol = "shadowsocks",
+ settings = new
+ {
+ network = "tcp,udp",
+ method = Global.None,
+ password = Global.None,
+ },
+ tag = "proxy-relay-ss",
+ });
+
+ ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
+ ret.Success = true;
+ ret.Data = JsonUtils.Serialize(configNode);
return ret;
}
catch (Exception ex)
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..10cd905b 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,17 @@ 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 simpleDNSItem = context.SimpleDnsItem;
static List ParseDnsAddresses(string? dnsInput, string defaultAddress)
{
var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';')
@@ -197,9 +196,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)
@@ -246,27 +245,9 @@ public partial class CoreConfigV2rayService
}
}
- if (Utils.IsDomain(node?.Address))
+ if (context.ProtectDomainList.Count > 0)
{
- directDomainList.Add(node.Address);
- }
-
- if (node?.Subid is not null)
- {
- 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 +281,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 +317,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 +334,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 +389,37 @@ 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 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..7ae12c7c 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs
@@ -2,35 +2,35 @@ namespace ServiceLib.Services.CoreConfig;
public partial class CoreConfigV2rayService
{
- private async Task GenInbounds(V2rayConfig v2rayConfig)
+ private void GenInbounds()
{
try
{
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)
{
- 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().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())
{
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 +43,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..86f4b2c2 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayLogService.cs
@@ -2,28 +2,27 @@ namespace ServiceLib.Services.CoreConfig;
public partial class CoreConfigV2rayService
{
- private async Task GenLog(V2rayConfig v2rayConfig)
+ private void GenLog()
{
try
{
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..3526fe29 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
@@ -2,13 +2,94 @@ 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 = _node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing;
+ GenObservatory(multipleLoad);
+ GenBalancer(multipleLoad);
+ }
+ }
+
+ private List BuildAllProxyOutbounds(string baseTagName = Global.ProxyTag)
+ {
+ var proxyOutboundList = new List();
+ if (_node.ConfigType.IsGroupType())
+ {
+ proxyOutboundList.AddRange(BuildGroupProxyOutbounds(baseTagName));
+ }
+ else
+ {
+ proxyOutboundList.Add(BuildProxyOutbound(baseTagName));
+ }
+
+ if (_config.CoreBasicItem.EnableFragment)
+ {
+ 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
+ }
+ }
+ };
+ 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();
+ 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 protocolExtra = node.GetProtocolExtra();
- var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
- switch (node.ConfigType)
+ var protocolExtra = _node.GetProtocolExtra();
+ var muxEnabled = _node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
+ switch (_node.ConfigType)
{
case EConfigType.VMess:
{
@@ -22,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)
@@ -36,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))
@@ -48,7 +129,7 @@ public partial class CoreConfigV2rayService
usersItem.security = Global.DefaultSecurity;
}
- await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
+ FillOutboundMux(outbound, muxEnabled, muxEnabled);
outbound.settings.servers = null;
break;
@@ -65,16 +146,16 @@ 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;
serversItem.level = 1;
- await GenOutboundMux(node, outbound);
+ FillOutboundMux(outbound);
outbound.settings.vnext = null;
break;
@@ -92,25 +173,25 @@ 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
};
serversItem.users = new List() { socksUsersItem };
}
- await GenOutboundMux(node, outbound);
+ FillOutboundMux(outbound);
outbound.settings.vnext = null;
break;
@@ -127,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)
@@ -140,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;
@@ -150,7 +231,7 @@ public partial class CoreConfigV2rayService
}
else
{
- await GenOutboundMux(node, outbound, false, muxEnabled);
+ FillOutboundMux(outbound, false, muxEnabled);
}
outbound.settings.servers = null;
break;
@@ -167,14 +248,14 @@ 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;
- await GenOutboundMux(node, outbound);
+ FillOutboundMux(outbound);
outbound.settings.vnext = null;
break;
@@ -184,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;
@@ -193,7 +274,7 @@ public partial class CoreConfigV2rayService
}
case EConfigType.WireGuard:
{
- var address = node.Address;
+ var address = _node.Address;
if (Utils.IsIpv6(address))
{
address = $"[{address}]";
@@ -201,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]
@@ -218,21 +299,20 @@ 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";
}
- 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
{
@@ -255,23 +335,22 @@ public partial class CoreConfigV2rayService
{
Logging.SaveLog(_tag, ex);
}
- return await Task.FromResult(0);
}
- private async Task GenBoundStreamSettings(ProfileItem node, Outbounds4Ray outbound)
+ private void FillBoundStreamSettings(Outbounds4Ray outbound)
{
try
{
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())
{
@@ -286,17 +365,17 @@ public partial class CoreConfigV2rayService
}
//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())
{
@@ -306,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();
@@ -323,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,
};
@@ -367,14 +446,14 @@ public partial class CoreConfigV2rayService
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
}
];
}
@@ -444,17 +523,17 @@ 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;
- await GenOutboundMux(node, outbound);
+ FillOutboundMux(outbound);
break;
//h2
@@ -478,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())
{
@@ -490,7 +569,7 @@ public partial class CoreConfigV2rayService
}
else
{
- streamSettings.tlsSettings.serverName = node.Address;
+ streamSettings.tlsSettings.serverName = _node.Address;
}
}
break;
@@ -500,7 +579,7 @@ public partial class CoreConfigV2rayService
{
authority = host.NullIfEmpty(),
serviceName = path,
- multiMode = node.HeaderType == Global.GrpcMultiMode,
+ multiMode = _node.HeaderType == Global.GrpcMultiMode,
idle_timeout = _config.GrpcItem.IdleTimeout,
health_check_timeout = _config.GrpcItem.HealthCheckTimeout,
permit_without_stream = _config.GrpcItem.PermitWithoutStream,
@@ -510,7 +589,7 @@ public partial class CoreConfigV2rayService
break;
case "hysteria":
- var protocolExtra = node.GetProtocolExtra();
+ var protocolExtra = _node.GetProtocolExtra();
var ports = protocolExtra?.Ports;
int? upMbps = protocolExtra?.UpMbps is { } su and >= 0
? su
@@ -536,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,
@@ -557,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
}
};
@@ -592,410 +671,132 @@ 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(_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}";
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(_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}";
+ var dialerProxyTag = i != nodesReverse.Count - 1 ? $"chain-{baseTagName}-{i + 1}" : 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();
+ if (chainStartNodes.Count == 1)
+ {
+ foreach (var existedChainEndNode in resultOutbounds.Where(n => n.streamSettings?.sockopt?.dialerProxy == currentTag))
+ {
+ existedChainEndNode.streamSettings.sockopt = new()
+ {
+ dialerProxy = chainStartNodes.First().tag
+ };
+ }
+ }
+ 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++;
+ }
+ }
+ }
+ 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..3d824102 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 = _config.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.StartsWith(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..6364b7bd 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayStatisticService.cs
@@ -2,7 +2,7 @@ namespace ServiceLib.Services.CoreConfig;
public partial class CoreConfigV2rayService
{
- private async Task GenStatistic(V2rayConfig v2rayConfig)
+ private void GenStatistic()
{
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
{
@@ -11,17 +11,17 @@ public partial class CoreConfigV2rayService
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/OptionSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
index 86251873..8462a2c3 100644
--- a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
+++ b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
@@ -95,7 +95,6 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; }
- [Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; }
#endregion Tun mode
@@ -220,7 +219,6 @@ public class OptionSettingViewModel : MyReactiveObject
TunStrictRoute = _config.TunModeItem.StrictRoute;
TunStack = _config.TunModeItem.Stack;
TunMtu = _config.TunModeItem.Mtu;
- TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
#endregion Tun mode
@@ -380,7 +378,6 @@ public class OptionSettingViewModel : MyReactiveObject
_config.TunModeItem.StrictRoute = TunStrictRoute;
_config.TunModeItem.Stack = TunStack;
_config.TunModeItem.Mtu = TunMtu;
- _config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
//coreType
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);
diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
index 65218738..6160cfad 100644
--- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
@@ -843,19 +843,6 @@
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
-
-
-
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
- this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml
index 00b2dc9e..ed82860d 100644
--- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml
+++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml
@@ -1097,20 +1097,6 @@
HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" />
-
-
-
vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
- this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);