Compare commits

..

2 commits

Author SHA1 Message Date
DHR60
780ba84393 Fix DNS routing 2026-02-25 11:18:39 +08:00
DHR60
8b47a90c07 Fix routing 2026-02-25 10:18:47 +08:00
29 changed files with 187 additions and 294 deletions

View file

@ -5,10 +5,10 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled> <CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.1" /> <PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.0" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.12" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.11" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.11" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.11" />
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" /> <PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" />
<PackageVersion Include="CliWrap" Version="3.10.0" /> <PackageVersion Include="CliWrap" Version="3.10.0" />
<PackageVersion Include="Downloader" Version="4.0.3" /> <PackageVersion Include="Downloader" Version="4.0.3" />
@ -19,9 +19,9 @@
<PackageVersion Include="ReactiveUI" Version="22.3.1" /> <PackageVersion Include="ReactiveUI" Version="22.3.1" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" /> <PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" />
<PackageVersion Include="Semi.Avalonia" Version="11.3.7.3" /> <PackageVersion Include="Semi.Avalonia" Version="11.3.7.2" />
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" /> <PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.3" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.2" />
<PackageVersion Include="NLog" Version="6.1.0" /> <PackageVersion Include="NLog" Version="6.1.0" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" /> <PackageVersion Include="TaskScheduler" Version="2.12.2" />
@ -29,4 +29,4 @@
<PackageVersion Include="YamlDotNet" Version="16.3.0" /> <PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" /> <PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1235,63 +1235,31 @@ public static class ConfigHandler
/// <returns>A SOCKS profile item or null if not needed</returns> /// <returns>A SOCKS profile item or null if not needed</returns>
public static ProfileItem? 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; ProfileItem? itemSocks = null;
var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray; if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
itemSocks = new ProfileItem()
{ {
CoreType = preCoreType, itemSocks = new ProfileItem()
ConfigType = EConfigType.SOCKS, {
Address = Global.Loopback, CoreType = ECoreType.sing_box,
Port = node.PreSocksPort.Value, ConfigType = EConfigType.SOCKS,
}; Address = Global.Loopback,
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,
};
}
return itemSocks; return itemSocks;
} }
public static CoreConfigContext? GetPreSocksCoreConfigContext(CoreConfigContext nodeContext)
{
var config = nodeContext.AppConfig;
var node = nodeContext.Node;
var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
var preSocksItem = GetPreSocksItem(config, node, coreType);
if (preSocksItem != null)
{
return nodeContext with { Node = preSocksItem, };
}
if ((!nodeContext.IsTunEnabled)
|| coreType != ECoreType.Xray
|| node.ConfigType == EConfigType.Custom)
{
return null;
}
var tunProtectSsPort = Utils.GetFreePort();
var proxyRelaySsPort = Utils.GetFreePort();
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,
});
var preContext = nodeContext with
{
Node = preItem,
TunProtectSsPort = tunProtectSsPort,
ProxyRelaySsPort = proxyRelaySsPort,
};
return preContext;
}
/// <summary> /// <summary>
/// Remove servers with invalid test results (timeout) /// Remove servers with invalid test results (timeout)
/// Useful for cleaning up subscription lists /// Useful for cleaning up subscription lists

View file

@ -99,12 +99,7 @@ public static class CoreConfigHandler
var nodes = await AppManager.Instance.GetProfileItemsByIndexIds(ids); var nodes = await AppManager.Instance.GetProfileItemsByIndexIds(ids);
foreach (var node in nodes) foreach (var node in nodes)
{ {
var actNode = await FillNodeContext(context, node, true); await FillNodeContext(context, node, false);
if (node.IndexId == actNode.IndexId)
{
continue;
}
context.ServerTestItemMap[node.IndexId] = actNode.IndexId;
} }
if (coreType == ECoreType.sing_box) if (coreType == ECoreType.sing_box)
{ {
@ -159,8 +154,7 @@ public static class CoreConfigHandler
IsTunEnabled = config.TunModeItem.EnableTun, IsTunEnabled = config.TunModeItem.EnableTun,
SimpleDnsItem = config.SimpleDNSItem, SimpleDnsItem = config.SimpleDNSItem,
ProtectDomainList = [], ProtectDomainList = [],
TunProtectSsPort = 0, ProtectSocksPort = 0,
ProxyRelaySsPort = 0,
RawDnsItem = await AppManager.Instance.GetDNSItem(coreType), RawDnsItem = await AppManager.Instance.GetDNSItem(coreType),
RoutingItem = await ConfigHandler.GetDefaultRouting(config), RoutingItem = await ConfigHandler.GetDefaultRouting(config),
}; };

View file

@ -66,7 +66,7 @@ public class Hysteria2Fmt : BaseFmt
if (!item.CertSha.IsNullOrEmpty()) if (!item.CertSha.IsNullOrEmpty())
{ {
var sha = item.CertSha; var sha = item.CertSha;
var idx = sha.IndexOf(','); var idx = sha.IndexOf('~');
if (idx > 0) if (idx > 0)
{ {
sha = sha[..idx]; sha = sha[..idx];

View file

@ -67,14 +67,7 @@ public class CoreManager
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName); var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
var context = await CoreConfigHandler.BuildCoreConfigContext(_config, node); var context = await CoreConfigHandler.BuildCoreConfigContext(_config, node);
var preContext = ConfigHandler.GetPreSocksCoreConfigContext(context); context = context with { IsTunEnabled = _config.TunModeItem.EnableTun };
if (preContext is not null)
{
context = context with
{
TunProtectSsPort = preContext.TunProtectSsPort, ProxyRelaySsPort = preContext.ProxyRelaySsPort,
};
}
var result = await CoreConfigHandler.GenerateClientConfig(context, fileName); var result = await CoreConfigHandler.GenerateClientConfig(context, fileName);
if (result.Success != true) if (result.Success != true)
{ {
@ -95,7 +88,7 @@ public class CoreManager
} }
await CoreStart(context); await CoreStart(context);
await CoreStartPreService(preContext); await CoreStartPreService(context);
if (_processService != null) if (_processService != null)
{ {
await UpdateFunc(true, $"{node.GetSummary()}"); await UpdateFunc(true, $"{node.GetSummary()}");
@ -190,22 +183,30 @@ public class CoreManager
_processService = proc; _processService = proc;
} }
private async Task CoreStartPreService(CoreConfigContext? preContext) private async Task CoreStartPreService(CoreConfigContext context)
{ {
if (_processService is { HasExited: false } && preContext != null) var node = context.Node;
if (_processService != null && !_processService.HasExited)
{ {
var preCoreType = preContext?.Node?.CoreType ?? ECoreType.sing_box; var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName); var itemSocks = ConfigHandler.GetPreSocksItem(_config, node, coreType);
var result = await CoreConfigHandler.GenerateClientConfig(preContext, fileName); if (itemSocks != null)
if (result.Success)
{ {
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType); var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true); var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
if (proc is null) var itemSocksContext = await CoreConfigHandler.BuildCoreConfigContext(_config, itemSocks);
itemSocksContext.ProtectDomainList.AddRangeSafe(context.ProtectDomainList);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocksContext, fileName);
if (result.Success)
{ {
return; var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
if (proc is null)
{
return;
}
_processPreService = proc;
} }
_processPreService = proc;
} }
} }
} }

View file

@ -144,6 +144,7 @@ public class TunModeItem
public bool StrictRoute { get; set; } = true; public bool StrictRoute { get; set; } = true;
public string Stack { get; set; } public string Stack { get; set; }
public int Mtu { get; set; } public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; } public bool EnableIPv6Address { get; set; }
} }

View file

@ -10,15 +10,8 @@ public record CoreConfigContext
public Config AppConfig { get; init; } = new(); public Config AppConfig { get; init; } = new();
public FullConfigTemplateItem? FullConfigTemplate { get; init; } = new(); public FullConfigTemplateItem? FullConfigTemplate { get; init; } = new();
// Test ServerTestItem Map
public Dictionary<string, string> ServerTestItemMap { get; init; } = new();
// TUN Compatibility // TUN Compatibility
public bool IsTunEnabled { get; init; } = false; public bool IsTunEnabled { get; init; } = false;
public HashSet<string> ProtectDomainList { get; init; } = new(); public HashSet<string> ProtectDomainList { get; init; } = new();
// -> tun inbound --(if routing proxy)--> relay outbound public int ProtectSocksPort { get; init; } = 0;
// -> 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;
} }

View file

@ -466,7 +466,7 @@ public class HysteriaSettings4Ray
public class HysteriaUdpHop4Ray public class HysteriaUdpHop4Ray
{ {
public string? port { get; set; } public string? ports { get; set; }
public string? interval { get; set; } public string? interval { get; set; }
} }

View file

@ -3780,6 +3780,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable additional Inbound 的本地化字符串。
/// </summary>
public static string TbSettingsEnableExInbound {
get {
return ResourceManager.GetString("TbSettingsEnableExInbound", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Enable fragment 的本地化字符串。 /// 查找类似 Enable fragment 的本地化字符串。
/// </summary> /// </summary>
@ -3789,6 +3798,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 which conflicts with the group previous proxy 的本地化字符串。
/// </summary>
public static string TbSettingsEnableFragmentTips {
get {
return ResourceManager.GetString("TbSettingsEnableFragmentTips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Enable hardware acceleration (requires restart) 的本地化字符串。 /// 查找类似 Enable hardware acceleration (requires restart) 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1071,6 +1071,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>فعال سازی additional Inbound</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>فعال سازی آدرس IPv6</value> <value>فعال سازی آدرس IPv6</value>
</data> </data>
@ -1110,6 +1113,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>افزودن سرور [HTTP]</value> <value>افزودن سرور [HTTP]</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>which conflicts with the group previous proxy</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>فعال کردن فرگمنت</value> <value>فعال کردن فرگمنت</value>
</data> </data>

View file

@ -1068,6 +1068,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Activer un port découte supplémentaire</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Activer IPv6</value> <value>Activer IPv6</value>
</data> </data>
@ -1107,6 +1110,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>Ajouter [HTTP]</value> <value>Ajouter [HTTP]</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>En conflit avec le proxy amont de groupe</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Activer le fragmentation (Fragment)</value> <value>Activer le fragmentation (Fragment)</value>
</data> </data>

View file

@ -1071,6 +1071,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>További bejövő engedélyezése</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>IPv6 cím engedélyezése</value> <value>IPv6 cím engedélyezése</value>
</data> </data>
@ -1110,6 +1113,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>HTTP konfiguráció hozzáadása</value> <value>HTTP konfiguráció hozzáadása</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>which conflicts with the group previous proxy</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Fragment engedélyezése</value> <value>Fragment engedélyezése</value>
</data> </data>

View file

@ -1071,6 +1071,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value> <value>Enable IPv6 Address</value>
</data> </data>
@ -1110,6 +1113,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP]</value> <value>Add [HTTP]</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>which conflicts with the group previous proxy</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value> <value>Enable fragment</value>
</data> </data>

View file

@ -1071,6 +1071,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Включить дополнительный входящий канал</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Включить IPv6 адреса</value> <value>Включить IPv6 адреса</value>
</data> </data>
@ -1110,6 +1113,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>Добавить сервер [HTTP]</value> <value>Добавить сервер [HTTP]</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>что конфликтует с предыдущим прокси группы</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Включить фрагментацию (Fragment)</value> <value>Включить фрагментацию (Fragment)</value>
</data> </data>

View file

@ -1068,6 +1068,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>启用额外监听端口</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>启用 IPv6</value> <value>启用 IPv6</value>
</data> </data>
@ -1107,6 +1110,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>添加 [HTTP] </value> <value>添加 [HTTP] </value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>和分组前置代理冲突</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>启用分片 (Fragment)</value> <value>启用分片 (Fragment)</value>
</data> </data>

View file

@ -1068,6 +1068,9 @@
<data name="TbSettingsTunMtu" xml:space="preserve"> <data name="TbSettingsTunMtu" xml:space="preserve">
<value>MTU</value> <value>MTU</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外偵聽連接埠</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用 IPv6</value> <value>啟用 IPv6</value>
</data> </data>
@ -1107,6 +1110,9 @@
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>新增 [HTTP] 節點</value> <value>新增 [HTTP] 節點</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>和分組前置代理衝突</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>啟用分片Fragment</value> <value>啟用分片Fragment</value>
</data> </data>

View file

@ -61,51 +61,6 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
ret.Success = true; ret.Success = true;
ret.Data = ApplyFullConfigTemplate(); 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<string> { 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; return ret;
} }
catch (Exception ex) catch (Exception ex)
@ -167,9 +122,8 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
{ {
continue; continue;
} }
var actIndexId = context.ServerTestItemMap.GetValueOrDefault(it.IndexId, it.IndexId); var item = context.AllProxiesMap.GetValueOrDefault(it.IndexId);
var item = context.AllProxiesMap.GetValueOrDefault(actIndexId); if (item is null || item.IsComplex() || !item.IsValid())
if (item is null || item.ConfigType is EConfigType.Custom || !item.IsValid())
{ {
continue; continue;
} }

View file

@ -26,15 +26,11 @@ public partial class CoreConfigSingboxService
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? []; var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
if (rules?.LastOrDefault() is { } lastRule && lastRule.OutboundTag == Global.DirectTag) useDirectDns = rules?.LastOrDefault() is { } lastRule &&
{ lastRule.OutboundTag == Global.DirectTag &&
var noDomain = lastRule.Domain == null || lastRule.Domain.Count == 0; (lastRule.Port == "0-65535" ||
var noProcess = lastRule.Process == null || lastRule.Process.Count == 0; lastRule.Network == "tcp,udp" ||
var isAnyIp = lastRule.Ip == null || lastRule.Ip.Count == 0 || lastRule.Ip.Contains("0.0.0.0/0"); lastRule.Ip?.Contains("0.0.0.0/0") == true);
var isAnyPort = string.IsNullOrEmpty(lastRule.Port) || lastRule.Port == "0-65535";
var isAnyNetwork = string.IsNullOrEmpty(lastRule.Network) || lastRule.Network == "tcp,udp";
useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork;
}
} }
_coreConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag; _coreConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag;
var simpleDnsItem = context.SimpleDnsItem; var simpleDnsItem = context.SimpleDnsItem;

View file

@ -7,11 +7,10 @@ public partial class CoreConfigSingboxService
try try
{ {
var listen = "0.0.0.0"; var listen = "0.0.0.0";
var listenPort = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
_coreConfig.inbounds = []; _coreConfig.inbounds = [];
if (!context.IsTunEnabled if (!_config.TunModeItem.EnableTun
|| (context.IsTunEnabled && _node.Port != listenPort)) || (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box))
{ {
var inbound = new Inbound4Sbox() var inbound = new Inbound4Sbox()
{ {
@ -21,7 +20,7 @@ public partial class CoreConfigSingboxService
}; };
_coreConfig.inbounds.Add(inbound); _coreConfig.inbounds.Add(inbound);
inbound.listen_port = listenPort; inbound.listen_port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
if (_config.Inbound.First().SecondLocalPortEnabled) if (_config.Inbound.First().SecondLocalPortEnabled)
{ {
@ -50,7 +49,7 @@ public partial class CoreConfigSingboxService
} }
} }
if (context.IsTunEnabled) if (_config.TunModeItem.EnableTun)
{ {
if (_config.TunModeItem.Mtu <= 0) if (_config.TunModeItem.Mtu <= 0)
{ {

View file

@ -15,10 +15,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
var ret = new RetResult(); var ret = new RetResult();
try try
{ {
if (context.IsTunEnabled && context.TunProtectSsPort > 0 && context.ProxyRelaySsPort > 0)
{
return GenerateClientProxyRelayConfig();
}
if (_node == null if (_node == null
|| !_node.IsValid()) || !_node.IsValid())
{ {
@ -60,12 +56,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
GenStatistic(); GenStatistic();
var finalRule = BuildFinalRule();
if (!string.IsNullOrEmpty(finalRule?.balancerTag))
{
_coreConfig.routing.rules.Add(finalRule);
}
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true; ret.Success = true;
ret.Data = ApplyFullConfigTemplate(); ret.Data = ApplyFullConfigTemplate();
@ -130,9 +120,8 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
{ {
continue; continue;
} }
var actIndexId = context.ServerTestItemMap.GetValueOrDefault(it.IndexId, it.IndexId); var item = context.AllProxiesMap.GetValueOrDefault(it.IndexId);
var item = context.AllProxiesMap.GetValueOrDefault(actIndexId); if (item is null || item.IsComplex() || !item.IsValid())
if (item is null || item.ConfigType is EConfigType.Custom || !item.IsValid())
{ {
continue; continue;
} }
@ -276,106 +265,5 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
} }
} }
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<V2rayConfig>(result);
if (_coreConfig == null)
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
GenLog();
_coreConfig.outbounds.Clear();
GenOutbounds();
var protectNode = new ProfileItem()
{
CoreType = ECoreType.Xray,
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<string> { "proxy-relay-ss" },
outboundTag = hasBalancer ? null : Global.ProxyTag,
balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix: 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)
{
Logging.SaveLog(_tag, ex);
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
}
#endregion public gen function #endregion public gen function
} }

View file

@ -243,17 +243,11 @@ public partial class CoreConfigV2rayService
AddDnsServers(bootstrapDNSAddress, dnsServerDomains); AddDnsServers(bootstrapDNSAddress, dnsServerDomains);
} }
var useDirectDns = false; var useDirectDns = rules?.LastOrDefault() is { } lastRule
&& lastRule.OutboundTag == Global.DirectTag
if (rules?.LastOrDefault() is { } lastRule && lastRule.OutboundTag == Global.DirectTag) && (lastRule.Port == "0-65535"
{ || lastRule.Network == "tcp,udp"
var noDomain = lastRule.Domain == null || lastRule.Domain.Count == 0; || lastRule.Ip?.Contains("0.0.0.0/0") == true);
var noProcess = lastRule.Process == null || lastRule.Process.Count == 0;
var isAnyIp = lastRule.Ip == null || lastRule.Ip.Count == 0 || lastRule.Ip.Contains("0.0.0.0/0");
var isAnyPort = string.IsNullOrEmpty(lastRule.Port) || lastRule.Port == "0-65535";
var isAnyNetwork = string.IsNullOrEmpty(lastRule.Network) || lastRule.Network == "tcp,udp";
useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork;
}
if (!useDirectDns) if (!useDirectDns)
{ {

View file

@ -31,7 +31,7 @@ public partial class CoreConfigV2rayService
var fragmentOutbound = new Outbounds4Ray var fragmentOutbound = new Outbounds4Ray
{ {
protocol = "freedom", protocol = "freedom",
tag = $"frag-{baseTagName}", tag = $"frag-{Global.ProxyTag}",
settings = new() settings = new()
{ {
fragment = new() fragment = new()
@ -44,17 +44,16 @@ public partial class CoreConfigV2rayService
}; };
var actOutboundWithTlsList = var actOutboundWithTlsList =
proxyOutboundList.Where(n => n.streamSettings?.security.IsNullOrEmpty() == false proxyOutboundList.Where(n => n.streamSettings?.security.IsNullOrEmpty() == false
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true)).ToList(); && (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true));
if (actOutboundWithTlsList.Count > 0)
{
proxyOutboundList.Add(fragmentOutbound);
}
foreach (var outbound in actOutboundWithTlsList) foreach (var outbound in actOutboundWithTlsList)
{ {
var fragmentOutboundClone = JsonUtils.DeepCopy(fragmentOutbound);
fragmentOutboundClone.tag = $"frag-{outbound.tag}";
outbound.streamSettings.sockopt = new() outbound.streamSettings.sockopt = new()
{ {
dialerProxy = fragmentOutbound.tag dialerProxy = fragmentOutboundClone.tag
}; };
proxyOutboundList.Add(fragmentOutboundClone);
} }
} }
return proxyOutboundList; return proxyOutboundList;
@ -602,7 +601,7 @@ public partial class CoreConfigV2rayService
{ {
udpHop = new HysteriaUdpHop4Ray udpHop = new HysteriaUdpHop4Ray
{ {
port = ports.Replace(':', '-'), ports = ports.Replace(':', '-'),
interval = hopInterval, interval = hopInterval,
}; };
} }

View file

@ -45,6 +45,7 @@ public partial class CoreConfigV2rayService
rulesItem.outboundTag = null; rulesItem.outboundTag = null;
} }
} }
_coreConfig.routing.rules.Add(BuildFinalRule());
} }
} }
catch (Exception ex) catch (Exception ex)

View file

@ -218,7 +218,7 @@ public class AddServerViewModel : MyReactiveObject
return; return;
} }
List<string> shaList = []; List<string> shaList = new();
foreach (var cert in certList) foreach (var cert in certList)
{ {
var sha = CertPemManager.GetCertSha256Thumbprint(cert); var sha = CertPemManager.GetCertSha256Thumbprint(cert);
@ -228,7 +228,7 @@ public class AddServerViewModel : MyReactiveObject
} }
shaList.Add(sha); shaList.Add(sha);
} }
CertSha = string.Join(',', shaList); CertSha = string.Join('~', shaList);
} }
private async Task FetchCert() private async Task FetchCert()

View file

@ -95,6 +95,7 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public bool TunStrictRoute { get; set; } [Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; } [Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; } [Reactive] public bool TunEnableIPv6Address { get; set; }
#endregion Tun mode #endregion Tun mode
@ -219,6 +220,7 @@ public class OptionSettingViewModel : MyReactiveObject
TunStrictRoute = _config.TunModeItem.StrictRoute; TunStrictRoute = _config.TunModeItem.StrictRoute;
TunStack = _config.TunModeItem.Stack; TunStack = _config.TunModeItem.Stack;
TunMtu = _config.TunModeItem.Mtu; TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
#endregion Tun mode #endregion Tun mode
@ -378,6 +380,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.TunModeItem.StrictRoute = TunStrictRoute; _config.TunModeItem.StrictRoute = TunStrictRoute;
_config.TunModeItem.Stack = TunStack; _config.TunModeItem.Stack = TunStack;
_config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
//coreType //coreType

View file

@ -325,6 +325,12 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="20"
Grid.Column="2"
Margin="{StaticResource Margin4}"
Text="{x:Static resx:ResUI.TbSettingsEnableFragmentTips}"
TextWrapping="Wrap" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@ -837,6 +843,19 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
<ToggleSwitch
x:Name="togEnableExInbound"
Grid.Row="6"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"

View file

@ -114,6 +114,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables); 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.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.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.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);

View file

@ -391,6 +391,13 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="20"
Grid.Column="2"
Margin="{StaticResource Margin8}"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsEnableFragmentTips}"
TextWrapping="Wrap" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@ -1090,6 +1097,20 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
<ToggleButton
x:Name="togEnableExInbound"
Grid.Row="6"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"

View file

@ -119,6 +119,7 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => 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.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.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.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);