mirror of
https://github.com/2dust/v2rayN.git
synced 2026-10-30 09:05:01 +03:00
Compare commits
14 Commits
a37772f12b
...
7.24.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 92c3df45ae | |||
| ee7e21268a | |||
| dc216c2b02 | |||
| beffa919d3 | |||
| a654826231 | |||
| b01476d147 | |||
| cf8dd45abe | |||
| 9bba6f53f8 | |||
| cd77f1d882 | |||
| 0427037638 | |||
| e749b81ecf | |||
| fd2c942231 | |||
| fa42eb670f | |||
| 0d42996573 |
@@ -13,8 +13,8 @@ PKGROOT="v2rayN-publish"
|
||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||
OUTPUT_DIR="${HOME}/debbuild"
|
||||
DOTNET_TFM="net10.0"
|
||||
DOTNET_LOONGARCH_VERSION="10.0.109"
|
||||
DOTNET_LOONGARCH_TAG="v10.0.109-loongarch64"
|
||||
DOTNET_LOONGARCH_VERSION="10.0.110"
|
||||
DOTNET_LOONGARCH_TAG="v10.0.110-loongarch64"
|
||||
DOTNET_LOONGARCH_BASE="https://github.com/loongson/dotnet/releases/download"
|
||||
DOTNET_LOONGARCH_FILE="dotnet-sdk-${DOTNET_LOONGARCH_VERSION}-linux-loongarch64.tar.gz"
|
||||
DOTNET_SDK_URL="${DOTNET_LOONGARCH_BASE}/${DOTNET_LOONGARCH_TAG}/${DOTNET_LOONGARCH_FILE}"
|
||||
|
||||
@@ -12,8 +12,8 @@ MIN_KERNEL="6.12"
|
||||
PKGROOT="v2rayN-publish"
|
||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||
RPM_TOPDIR="${HOME}/rpmbuild"
|
||||
DOTNET_LOONGARCH_VERSION="10.0.109"
|
||||
DOTNET_LOONGARCH_TAG="v10.0.109-loongarch64"
|
||||
DOTNET_LOONGARCH_VERSION="10.0.110"
|
||||
DOTNET_LOONGARCH_TAG="v10.0.110-loongarch64"
|
||||
DOTNET_LOONGARCH_BASE="https://github.com/loongson/dotnet/releases/download"
|
||||
DOTNET_LOONGARCH_FILE="dotnet-sdk-${DOTNET_LOONGARCH_VERSION}-linux-loongarch64.tar.gz"
|
||||
DOTNET_SDK_URL="${DOTNET_LOONGARCH_BASE}/${DOTNET_LOONGARCH_TAG}/${DOTNET_LOONGARCH_FILE}"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.24.1</Version>
|
||||
<Version>7.24.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="12.1.0" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="12.1.0" />
|
||||
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.3" />
|
||||
<PackageVersion Include="AwesomeAssertions" Version="9.4.0" />
|
||||
<PackageVersion Include="DialogHost.Avalonia" Version="0.12.2" />
|
||||
<PackageVersion Include="AwesomeAssertions" Version="9.5.0" />
|
||||
<PackageVersion Include="DialogHost.Avalonia" Version="0.12.3" />
|
||||
<PackageVersion Include="IPNetwork2" Version="4.3.0" />
|
||||
<PackageVersion Include="ReactiveUI.Avalonia" Version="12.0.3" />
|
||||
<PackageVersion Include="CliWrap" Version="3.10.2" />
|
||||
<PackageVersion Include="Downloader" Version="5.9.4" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />
|
||||
<PackageVersion Include="Downloader" Version="5.9.5" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
|
||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
|
||||
<PackageVersion Include="MaterialDesignThemes" Version="5.3.2" />
|
||||
<PackageVersion Include="QRCoder" Version="1.8.0" />
|
||||
@@ -27,7 +27,7 @@
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="12.1.0" />
|
||||
<PackageVersion Include="NLog" Version="6.1.4" />
|
||||
<PackageVersion Include="sqlite-net-e" Version="1.11.285" />
|
||||
<PackageVersion Include="Repobot.SQLite.Unofficial" Version="3.53.3" />
|
||||
<PackageVersion Include="Repobot.SQLite.Unofficial" Version="3.53.3.10" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
@@ -36,4 +36,4 @@
|
||||
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.22" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -592,4 +592,38 @@ public class CoreConfigSingboxServiceTests
|
||||
proxy.realm.stun_servers.Should().Contain("turn.cloudflare.com:3478");
|
||||
proxy.server.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateClientConfigContent_TunSystemStackWithIpv6_ShouldUsePrefixWithPeerAddress()
|
||||
{
|
||||
// Regression test for #9820: sing-box fails with "need one more IPv6 address in
|
||||
// first prefix for system stack" when the TUN inbound uses a /128 IPv6 prefix.
|
||||
var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box);
|
||||
config.TunModeItem.EnableTun = true;
|
||||
config.TunModeItem.Stack = "system";
|
||||
config.TunModeItem.EnableIPv6Address = true;
|
||||
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||
|
||||
var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.sing_box);
|
||||
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.sing_box) with
|
||||
{
|
||||
IsTunEnabled = true,
|
||||
};
|
||||
|
||||
var result = new CoreConfigSingboxService(context).GenerateClientConfigContent();
|
||||
|
||||
result.Success.Should().BeTrue($"ret msg: {result.Msg}");
|
||||
var cfg = JsonUtils.Deserialize<SingboxConfig>(result.Data!.ToString())!;
|
||||
var tun = cfg.inbounds.First(i => i.type == "tun");
|
||||
|
||||
tun.address.Should().NotBeNullOrEmpty();
|
||||
foreach (var address in tun.address!)
|
||||
{
|
||||
var prefixLength = int.Parse(address[(address.LastIndexOf('/') + 1)..]);
|
||||
var isIpv6 = address.Contains(':');
|
||||
prefixLength.Should().BeLessThanOrEqualTo(isIpv6 ? 126 : 30,
|
||||
$"'{address}' must leave room for the peer address the system stack derives");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using AwesomeAssertions;
|
||||
using ServiceLib.Enums;
|
||||
using ServiceLib.Manager;
|
||||
using Xunit;
|
||||
|
||||
namespace ServiceLib.Tests.Manager;
|
||||
|
||||
public class CoreManagerTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(ECoreType.sing_box)]
|
||||
[InlineData(ECoreType.mihomo)]
|
||||
[InlineData(ECoreType.Xray)]
|
||||
public void ShouldRunAsSudo_TunLaunchOnNonWindows_RequiresElevation(ECoreType coreType)
|
||||
{
|
||||
CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRunAsSudo_NonTunLaunch_ShouldNotElevate()
|
||||
{
|
||||
// Regression guard for the macOS TUN failure: the elevation decision must follow
|
||||
// the context snapshot that generated the config. A launch whose snapshot has TUN
|
||||
// disabled must never elevate, and a launch whose snapshot has TUN enabled must
|
||||
// elevate regardless of later changes to the live config.
|
||||
CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.sing_box, isNonWindows: true).Should().BeFalse();
|
||||
CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.Xray, isNonWindows: true).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRunAsSudo_OnWindows_ShouldNotElevate()
|
||||
{
|
||||
CoreManager.ShouldRunAsSudo(isTunLaunch: true, ECoreType.sing_box, isNonWindows: false).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ECoreType.v2fly)]
|
||||
[InlineData(ECoreType.hysteria)]
|
||||
[InlineData(null)]
|
||||
public void ShouldRunAsSudo_UnsupportedCoreType_ShouldNotElevate(ECoreType? coreType)
|
||||
{
|
||||
CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeFalse();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ namespace ServiceLib;
|
||||
|
||||
public class Global
|
||||
{
|
||||
#region const
|
||||
|
||||
public const string AppName = "v2rayN";
|
||||
public const string GithubUrl = "https://github.com";
|
||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||
@@ -106,9 +104,7 @@ public class Global
|
||||
public const string SingboxFakeDNSTag = "fake_dns";
|
||||
|
||||
public const int Hysteria2DefaultHopInt = 30;
|
||||
|
||||
public const string PolicyGroupExcludeKeywords = @"剩余|过期|到期|重置|[Rr]emaining|[Ee]xpir|[Rr]eset";
|
||||
|
||||
public const string PolicyGroupDefaultAllFilter = $"^(?!.*(?:{PolicyGroupExcludeKeywords})).*$";
|
||||
|
||||
public static readonly List<string> PolicyGroupDefaultFilterList =
|
||||
@@ -749,5 +745,29 @@ public class Global
|
||||
MozillaRootProvider,
|
||||
];
|
||||
|
||||
#endregion const
|
||||
public static readonly IReadOnlyList<string> TunIPv4Address =
|
||||
[
|
||||
"172.18.0.1/30",
|
||||
"172.31.0.1/30",
|
||||
"172.20.0.1/30",
|
||||
"172.16.0.1/30",
|
||||
"192.168.100.1/30",
|
||||
"10.10.14.1/30",
|
||||
"10.1.0.1/30",
|
||||
"10.0.0.1/30",
|
||||
];
|
||||
|
||||
// Prefixes must leave room for a peer address (max /126); the sing-box system
|
||||
// stack derives a gateway from the first prefix and rejects single-address prefixes.
|
||||
public static readonly IReadOnlyList<string> TunIPv6Address =
|
||||
[
|
||||
"fc00::172:18:0:1/126",
|
||||
"fc00::172:31:0:1/126",
|
||||
"fc00::172:20:0:1/126",
|
||||
"fc00::172:16:0:1/126",
|
||||
"fc00::192:168:100:1/126",
|
||||
"fc00::10:10:14:1/126",
|
||||
"fc00::10:1:0:1/126",
|
||||
"fc00::10:0:0:1/126",
|
||||
];
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ global using ServiceLib.Handler.Fmt;
|
||||
global using ServiceLib.Handler.SysProxy;
|
||||
global using ServiceLib.Helper;
|
||||
global using ServiceLib.Manager;
|
||||
global using ServiceLib.Models.CoreConfigs;
|
||||
global using ServiceLib.Models.Configs;
|
||||
global using ServiceLib.Models.CoreConfigs;
|
||||
global using ServiceLib.Models.Dto;
|
||||
global using ServiceLib.Models.Entities;
|
||||
global using ServiceLib.Resx;
|
||||
|
||||
@@ -92,7 +92,7 @@ public static class ConfigHandler
|
||||
EnableTun = false,
|
||||
Mtu = 9000,
|
||||
IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
|
||||
EnableLegacyProtect = false,
|
||||
EnableLegacyProtect = true,
|
||||
};
|
||||
config.GuiItem ??= new();
|
||||
if (!Global.RootCertProviders.Contains(config.GuiItem.RootCertProvider))
|
||||
|
||||
@@ -16,7 +16,6 @@ public static class SysProxyHandler
|
||||
try
|
||||
{
|
||||
var port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||
if (port <= 0)
|
||||
{
|
||||
return false;
|
||||
@@ -24,17 +23,18 @@ public static class SysProxyHandler
|
||||
switch (type)
|
||||
{
|
||||
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
||||
{
|
||||
GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
|
||||
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
||||
break;
|
||||
}
|
||||
var (strProxy, strExceptions) = GetWindowsProxyString(config, port);
|
||||
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
||||
break;
|
||||
|
||||
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
||||
var exceptions = SanitizeExceptions(config);
|
||||
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
|
||||
break;
|
||||
|
||||
case ESysProxyType.ForcedChange when Utils.IsMacOS():
|
||||
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
|
||||
var exceptions2 = SanitizeExceptions(config);
|
||||
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions2);
|
||||
break;
|
||||
|
||||
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
||||
@@ -66,15 +66,31 @@ public static class SysProxyHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
|
||||
private static string SanitizeExceptions(Config config)
|
||||
{
|
||||
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||
var exceptions = config.SystemProxyItem.SystemProxyExceptions;
|
||||
if (exceptions.IsNullOrEmpty())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var items = exceptions
|
||||
.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(item => item.Replace(" ", string.Empty))
|
||||
.Where(item => item.Length > 0);
|
||||
|
||||
return string.Join(',', items);
|
||||
}
|
||||
|
||||
private static (string strProxy, string strExceptions) GetWindowsProxyString(Config config, int port)
|
||||
{
|
||||
var strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||
if (config.SystemProxyItem.NotProxyLocalAddress)
|
||||
{
|
||||
strExceptions = $"<local>;{strExceptions}";
|
||||
}
|
||||
|
||||
strProxy = string.Empty;
|
||||
var strProxy = string.Empty;
|
||||
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
|
||||
{
|
||||
strProxy = $"{Global.Loopback}:{port}";
|
||||
@@ -86,6 +102,8 @@ public static class SysProxyHandler
|
||||
.Replace("{http_port}", port.ToString())
|
||||
.Replace("{socks_port}", port.ToString());
|
||||
}
|
||||
|
||||
return (strProxy, strExceptions);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
|
||||
@@ -183,7 +183,7 @@ public class CoreManager
|
||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(coreType);
|
||||
|
||||
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
||||
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
|
||||
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true, context.IsTunEnabled);
|
||||
if (proc is null)
|
||||
{
|
||||
return;
|
||||
@@ -201,7 +201,7 @@ public class CoreManager
|
||||
if (result.Success)
|
||||
{
|
||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
|
||||
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
||||
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true, preContext.IsTunEnabled);
|
||||
if (proc is null)
|
||||
{
|
||||
return;
|
||||
@@ -289,7 +289,20 @@ public class CoreManager
|
||||
|
||||
#region Process
|
||||
|
||||
private async Task<ProcessService?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
|
||||
/// <summary>
|
||||
/// Decides whether a core launch must be elevated on non-Windows platforms.
|
||||
/// The TUN state comes from the immutable <see cref="CoreConfigContext" /> snapshot that
|
||||
/// generated the config, never from the live mutable config: the generated config and the
|
||||
/// launch mode must always agree, even if TUN is toggled while a reload is in flight.
|
||||
/// </summary>
|
||||
public static bool ShouldRunAsSudo(bool isTunLaunch, ECoreType? coreType, bool isNonWindows)
|
||||
{
|
||||
return isTunLaunch
|
||||
&& coreType is ECoreType.sing_box or ECoreType.mihomo or ECoreType.Xray
|
||||
&& isNonWindows;
|
||||
}
|
||||
|
||||
private async Task<ProcessService?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo, bool isTunLaunch = false)
|
||||
{
|
||||
var fileName = CoreInfoManager.Instance.GetCoreExecFile(coreInfo, out var msg);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
@@ -301,9 +314,7 @@ public class CoreManager
|
||||
try
|
||||
{
|
||||
if (mayNeedSudo
|
||||
&& _config.TunModeItem.EnableTun
|
||||
&& (coreInfo.CoreType is ECoreType.sing_box or ECoreType.mihomo or ECoreType.Xray)
|
||||
&& Utils.IsNonWindows())
|
||||
&& ShouldRunAsSudo(isTunLaunch, coreInfo.CoreType, Utils.IsNonWindows()))
|
||||
{
|
||||
_linuxSudo = true;
|
||||
await CoreAdminManager.Instance.Init(_config, _updateFunc);
|
||||
|
||||
@@ -147,8 +147,10 @@ public class TunModeItem
|
||||
public int Mtu { get; set; }
|
||||
public bool EnableIPv6Address { get; set; }
|
||||
public string IcmpRouting { get; set; }
|
||||
public bool EnableLegacyProtect { get; set; }
|
||||
public bool EnableLegacyProtect { get; set; } = true;
|
||||
public List<string>? RouteExcludeAddress { get; set; }
|
||||
public string IPv4Address { get; set; }
|
||||
public string IPv6Address { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -255,6 +257,7 @@ public class Fragment4RayItem
|
||||
|
||||
// For migration from old version, remove those properties in the future
|
||||
public string? Length { get; set; }
|
||||
|
||||
public string? Interval { get; set; }
|
||||
// migration end
|
||||
}
|
||||
|
||||
@@ -560,6 +560,7 @@ public class Sockopt4Ray
|
||||
|
||||
[JsonPropertyName("interface")]
|
||||
public string? Interface { get; set; }
|
||||
|
||||
public HappyEyeballs4Ray? happyEyeballs { get; set; }
|
||||
}
|
||||
|
||||
|
||||
Generated
+18
@@ -3348,6 +3348,24 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Ipv4 Address 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbIpv4Address {
|
||||
get {
|
||||
return ResourceManager.GetString("TbIpv4Address", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Ipv6 Address 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbIpv6Address {
|
||||
get {
|
||||
return ResourceManager.GetString("TbIpv6Address", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Most Stable 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1842,4 +1842,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||
<value>Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path.</value>
|
||||
</data>
|
||||
<data name="TbIpv6Address" xml:space="preserve">
|
||||
<value>Ipv6 Address</value>
|
||||
</data>
|
||||
<data name="TbIpv4Address" xml:space="preserve">
|
||||
<value>Ipv4 Address</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1839,4 +1839,10 @@
|
||||
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||
<value>需配合 UseIP 策略使用。启用后将同时尝试 IPv4 和 IPv6 连接,并自动选择更快可用的路径。</value>
|
||||
</data>
|
||||
<data name="TbIpv6Address" xml:space="preserve">
|
||||
<value>Ipv6 地址</value>
|
||||
</data>
|
||||
<data name="TbIpv4Address" xml:space="preserve">
|
||||
<value>Ipv4 地址</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1827,4 +1827,22 @@
|
||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||
<value>僅適用於 v2rayN GUI 的下載與網路請求,不影響核心的憑證驗證</value>
|
||||
</data>
|
||||
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
|
||||
<value>連線代理解析策略</value>
|
||||
</data>
|
||||
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||
<value>不建議啟用,特殊情況可能造成連線循環</value>
|
||||
</data>
|
||||
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||
<value>啟用 Happy Eyeballs</value>
|
||||
</data>
|
||||
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||
<value>需搭配 UseIP 策略,啟用後會同時嘗試 IPv4 與 IPv6 連線,並自動選擇速度較快的路徑</value>
|
||||
</data>
|
||||
<data name="TbIpv6Address" xml:space="preserve">
|
||||
<value>Ipv6 位址</value>
|
||||
</data>
|
||||
<data name="TbIpv4Address" xml:space="preserve">
|
||||
<value>Ipv4 位址</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,27 +1,28 @@
|
||||
{
|
||||
"tag": "tun",
|
||||
"protocol": "tun",
|
||||
"settings": {
|
||||
"name": "xray_tun",
|
||||
"MTU": 9000,
|
||||
"gateway": [
|
||||
"172.18.0.1/30",
|
||||
"fdfe:dcba:9876::1/126"
|
||||
],
|
||||
"dns": [
|
||||
"172.18.0.1"
|
||||
],
|
||||
"autoSystemRoutingTable": [
|
||||
"0.0.0.0/0",
|
||||
"::/0"
|
||||
],
|
||||
"autoOutboundsInterface": "auto"
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
}
|
||||
}
|
||||
"tag": "tun",
|
||||
"protocol": "tun",
|
||||
"settings": {
|
||||
"name": "xray_tun",
|
||||
"MTU": 9000,
|
||||
"gateway": [
|
||||
"172.18.0.1/30",
|
||||
"fdfe:dcba:9876::1/126"
|
||||
],
|
||||
"dns": [
|
||||
"1.1.1.1",
|
||||
"8.8.8.8"
|
||||
],
|
||||
"autoSystemRoutingTable": [
|
||||
"0.0.0.0/0",
|
||||
"::/0"
|
||||
],
|
||||
"autoOutboundsInterface": "auto"
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,13 @@ public partial class CoreConfigSingboxService
|
||||
tunInbound.auto_route = _config.TunModeItem.AutoRoute;
|
||||
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
|
||||
tunInbound.stack = _config.TunModeItem.Stack;
|
||||
if (_config.TunModeItem.EnableIPv6Address == false)
|
||||
|
||||
var address = _config.TunModeItem.IPv4Address.NullIfEmpty() ?? Global.TunIPv4Address.First();
|
||||
tunInbound.address = [address];
|
||||
if (_config.TunModeItem.EnableIPv6Address == true)
|
||||
{
|
||||
tunInbound.address = ["172.18.0.1/30"];
|
||||
var address6 = _config.TunModeItem.IPv6Address.NullIfEmpty() ?? Global.TunIPv6Address.First();
|
||||
tunInbound.address.Add(address6);
|
||||
}
|
||||
tunInbound.route_exclude_address = _config.TunModeItem.RouteExcludeAddress;
|
||||
|
||||
|
||||
@@ -63,11 +63,16 @@ public partial class CoreConfigV2rayService
|
||||
new Inbounds4Ray();
|
||||
tunInbound.settings.name = context.IsMacOS ? $"utun{new Random().Next(99)}" : "xray_tun";
|
||||
tunInbound.settings.MTU = _config.TunModeItem.Mtu;
|
||||
if (!_config.TunModeItem.EnableIPv6Address)
|
||||
|
||||
var address = _config.TunModeItem.IPv4Address.NullIfEmpty() ?? Global.TunIPv4Address.First();
|
||||
tunInbound.settings.gateway = [address];
|
||||
if (_config.TunModeItem.EnableIPv6Address == true)
|
||||
{
|
||||
tunInbound.settings.gateway = ["172.18.0.1/30"];
|
||||
tunInbound.settings.autoSystemRoutingTable = ["0.0.0.0/0"];
|
||||
var address6 = _config.TunModeItem.IPv6Address.NullIfEmpty() ?? Global.TunIPv6Address.First();
|
||||
tunInbound.settings.gateway.Add(address6);
|
||||
}
|
||||
|
||||
tunInbound.settings.autoSystemRoutingTable = ["0.0.0.0/0"];
|
||||
var bindInterface = _config.CoreBasicItem.BindInterface?.TrimEx();
|
||||
if (!bindInterface.IsNullOrEmpty())
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace ServiceLib.ViewModels;
|
||||
public class AddServer2ViewModel : MyReactiveObject, ICloseable
|
||||
{
|
||||
public event EventHandler? RequestClose;
|
||||
|
||||
public Interaction<Unit, string?> BrowseConfigFileInteraction { get; } = new();
|
||||
|
||||
[Reactive]
|
||||
|
||||
@@ -95,6 +95,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
||||
[Reactive] public string TunIcmpRouting { get; set; }
|
||||
[Reactive] public bool TunEnableLegacyProtect { get; set; }
|
||||
[Reactive] public string TunRouteExcludeAddress { get; set; }
|
||||
[Reactive] public string TunIPv4Address { get; set; }
|
||||
[Reactive] public string TunIPv6Address { get; set; }
|
||||
|
||||
#endregion Tun mode
|
||||
|
||||
@@ -214,6 +216,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
||||
TunIcmpRouting = _config.TunModeItem.IcmpRouting;
|
||||
TunEnableLegacyProtect = _config.TunModeItem.EnableLegacyProtect;
|
||||
TunRouteExcludeAddress = Utils.List2String(_config.TunModeItem.RouteExcludeAddress, true);
|
||||
TunIPv4Address = _config.TunModeItem.IPv4Address;
|
||||
TunIPv6Address = _config.TunModeItem.IPv6Address;
|
||||
|
||||
#endregion Tun mode
|
||||
|
||||
@@ -378,6 +382,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
||||
_config.TunModeItem.IcmpRouting = TunIcmpRouting;
|
||||
_config.TunModeItem.EnableLegacyProtect = TunEnableLegacyProtect;
|
||||
_config.TunModeItem.RouteExcludeAddress = Utils.String2List(TunRouteExcludeAddress);
|
||||
_config.TunModeItem.IPv4Address = TunIPv4Address;
|
||||
_config.TunModeItem.IPv6Address = TunIPv6Address;
|
||||
|
||||
//coreType
|
||||
await SaveCoreType();
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace ServiceLib.ViewModels;
|
||||
public class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||
{
|
||||
public event EventHandler? RequestClose;
|
||||
|
||||
public Interaction<Unit, Unit> ProfilesFocusInteraction { get; } = new();
|
||||
|
||||
#region private prop
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace ServiceLib.ViewModels;
|
||||
public class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable
|
||||
{
|
||||
public event EventHandler? RequestClose;
|
||||
|
||||
public Interaction<string, bool> ShowYesNoInteraction { get; } = new();
|
||||
public Interaction<string, Unit> SetClipboardDataInteraction { get; } = new();
|
||||
public Interaction<Unit, string?> ReadTextFromClipboardInteraction { get; } = new();
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
<StyleInclude Source="Assets/GlobalStyles.axaml" />
|
||||
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
||||
<dialogHost:DialogHostStyles />
|
||||
|
||||
<Style Selector="dialogHost|DialogHost">
|
||||
<Setter Property="OverlayBackground" Value="{DynamicResource SemiColorOverlayBackground}" />
|
||||
<Setter Property="Background" Value="{DynamicResource SemiColorFill0}" />
|
||||
|
||||
<Setter Property="dialogHost:DialogHostStyle.BoxShadow" Value="{DynamicResource SemiShadowElevated}" />
|
||||
<Setter Property="dialogHost:DialogHostStyle.CornerRadius" Value="6" />
|
||||
</Style>
|
||||
</Application.Styles>
|
||||
|
||||
<TrayIcon.Icons>
|
||||
|
||||
@@ -18,10 +18,7 @@
|
||||
ShowInTaskbar="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<dialogHost:DialogHost
|
||||
Background="Gray"
|
||||
CloseOnClickAway="True"
|
||||
DisableOpeningAnimation="True">
|
||||
<dialogHost:DialogHost CloseOnClickAway="True" DisableOpeningAnimation="True">
|
||||
<DockPanel>
|
||||
<DockPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
||||
<ContentControl x:Name="conTheme" DockPanel.Dock="Right" />
|
||||
|
||||
@@ -961,7 +961,7 @@
|
||||
Margin="{StaticResource Margin4}"
|
||||
ColumnDefinitions="Auto,Auto,Auto"
|
||||
DockPanel.Dock="Top"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -1087,6 +1087,34 @@
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbRouteExcludeAddressTip}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbIpv4Address}" />
|
||||
<ComboBox
|
||||
x:Name="cmbIpv4Address"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbIpv6Address}" />
|
||||
<ComboBox
|
||||
x:Name="cmbIpv6Address"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
@@ -33,6 +33,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||
cmbMtu.ItemsSource = Global.TunMtus;
|
||||
cmbStack.ItemsSource = Global.TunStacks;
|
||||
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
|
||||
cmbIpv4Address.ItemsSource = Global.TunIPv4Address;
|
||||
cmbIpv6Address.ItemsSource = Global.TunIPv6Address;
|
||||
cmbFragmentPackets.ItemsSource = Global.FragmentPacketsOptions;
|
||||
|
||||
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||
@@ -129,6 +131,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunRouteExcludeAddress, v => v.txtRouteExcludeAddress.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunIPv4Address, v => v.cmbIpv4Address.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunIPv6Address, v => v.cmbIpv6Address.SelectedValue).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<dialogHost:DialogHost
|
||||
Background="Gray"
|
||||
CloseOnClickAway="True"
|
||||
DisableOpeningAnimation="True"
|
||||
Identifier="dialogHostSub">
|
||||
|
||||
@@ -1198,6 +1198,8 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
@@ -1346,6 +1348,39 @@
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbRouteExcludeAddressTip}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbIpv4Address}" />
|
||||
<ComboBox
|
||||
x:Name="cmbIpv4Address"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbIpv6Address}" />
|
||||
<ComboBox
|
||||
x:Name="cmbIpv6Address"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
@@ -29,6 +29,8 @@ public partial class OptionSettingWindow
|
||||
cmbMtu.ItemsSource = Global.TunMtus;
|
||||
cmbStack.ItemsSource = Global.TunStacks;
|
||||
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
|
||||
cmbIpv4Address.ItemsSource = Global.TunIPv4Address;
|
||||
cmbIpv6Address.ItemsSource = Global.TunIPv6Address;
|
||||
cmbFragmentPackets.ItemsSource = Global.FragmentPacketsOptions;
|
||||
|
||||
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||
@@ -86,14 +88,6 @@ public partial class OptionSettingWindow
|
||||
this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
||||
|
||||
//this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables);
|
||||
//this.Bind(ViewModel, vm => vm.Kcptti, v => v.txtKcptti.Text).DisposeWith(disposables);
|
||||
//this.Bind(ViewModel, vm => vm.KcpuplinkCapacity, v => v.txtKcpuplinkCapacity.Text).DisposeWith(disposables);
|
||||
//this.Bind(ViewModel, vm => vm.KcpdownlinkCapacity, v => v.txtKcpdownlinkCapacity.Text).DisposeWith(disposables);
|
||||
//this.Bind(ViewModel, vm => vm.KcpreadBufferSize, v => v.txtKcpreadBufferSize.Text).DisposeWith(disposables);
|
||||
//this.Bind(ViewModel, vm => vm.KcpwriteBufferSize, v => v.txtKcpwriteBufferSize.Text).DisposeWith(disposables);
|
||||
//this.Bind(ViewModel, vm => vm.Kcpcongestion, v => v.togKcpcongestion.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DisplayRealTimeSpeed, v => v.togDisplayRealTimeSpeed.IsChecked).DisposeWith(disposables);
|
||||
@@ -132,6 +126,8 @@ public partial class OptionSettingWindow
|
||||
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunRouteExcludeAddress, v => v.txtRouteExcludeAddress.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunIPv4Address, v => v.cmbIpv4Address.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunIPv6Address, v => v.cmbIpv6Address.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables);
|
||||
|
||||
Reference in New Issue
Block a user