From f55d8b25652e990d431c78e4dacc68148692da5a Mon Sep 17 00:00:00 2001 From: DHR60 <192860629+DHR60@users.noreply.github.com> Date: Thu, 16 Jul 2026 10:55:06 +0000 Subject: [PATCH] Sync xray (#9708) * Sync xray fragment * Sync xray freedom domainStrategy * Add Strategy4ProxyDial --- .../CoreConfig/CoreConfigTestFactory.cs | 3 +- .../V2ray/CoreConfigV2rayServiceTests.cs | 2 +- v2rayN/ServiceLib/Common/Utils.cs | 13 ++-- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 12 +++- .../ServiceLib/Models/Configs/ConfigItems.cs | 8 ++- .../Models/CoreConfigs/V2rayConfig.cs | 6 +- v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 18 ++++++ v2rayN/ServiceLib/Resx/ResUI.resx | 6 ++ v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 6 ++ .../CoreConfig/Singbox/SingboxDnsService.cs | 2 +- .../Singbox/SingboxOutboundService.cs | 6 +- .../Singbox/SingboxRoutingService.cs | 15 ++++- .../CoreConfig/V2ray/V2rayDnsService.cs | 34 +++++++--- .../CoreConfig/V2ray/V2rayOutboundService.cs | 62 +++++++------------ .../ViewModels/DNSSettingViewModel.cs | 3 + .../ViewModels/OptionSettingViewModel.cs | 41 +++++------- .../Views/DNSSettingWindow.axaml | 36 ++++++++--- .../Views/DNSSettingWindow.axaml.cs | 2 + .../Views/OptionSettingWindow.axaml | 4 +- .../Views/OptionSettingWindow.axaml.cs | 4 +- v2rayN/v2rayN/Views/DNSSettingWindow.xaml | 35 +++++++++-- v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs | 2 + v2rayN/v2rayN/Views/OptionSettingWindow.xaml | 4 +- .../v2rayN/Views/OptionSettingWindow.xaml.cs | 4 +- 24 files changed, 217 insertions(+), 111 deletions(-) diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs b/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs index 8e158bef..0c6e9bae 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs @@ -59,7 +59,7 @@ internal static class CoreConfigTestFactory }, WebDavItem = new WebDavItem(), CheckUpdateItem = new CheckUpdateItem(), - Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Length = "100-200", Interval = "10-20" }, + Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Lengths = ["100-200"], Delays = ["10-20"] }, Inbound = [ new InItem @@ -84,6 +84,7 @@ internal static class CoreConfigTestFactory ParallelQuery = false, Strategy4Freedom = Global.AsIs, Strategy4Proxy = Global.AsIs, + Strategy4ProxyDial = Global.AsIs, }, IndexId = string.Empty, SubIndexId = string.Empty, diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs index 576f0b1e..983aaf96 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/V2ray/CoreConfigV2rayServiceTests.cs @@ -567,7 +567,7 @@ public class CoreConfigV2rayServiceTests var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom"); directOutbound.Should().NotBeNull(); - directOutbound!.settings.domainStrategy.Should().Be("UseIPv4"); + directOutbound!.streamSettings.sockopt!.domainStrategy.Should().Be("UseIPv4"); } [Fact] diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index 7318114b..57a42c80 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -485,12 +485,17 @@ public class Utils public static string? DomainStrategy4Sbox(string? strategy) { + if (strategy is null) + { + return null; + } + return strategy switch { - not null when strategy.StartsWith("UseIPv4") => "prefer_ipv4", - not null when strategy.StartsWith("UseIPv6") => "prefer_ipv6", - not null when strategy.StartsWith("ForceIPv4") => "ipv4_only", - not null when strategy.StartsWith("ForceIPv6") => "ipv6_only", + _ when strategy.StartsWith("UseIPv6") => "prefer_ipv6", + _ when strategy.StartsWith("UseIP") => "prefer_ipv4", + _ when strategy.StartsWith("ForceIPv6") => "ipv6_only", + _ when strategy.StartsWith("ForceIP") => "ipv4_only", _ => null }; } diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 89b8b2f6..f7a163d3 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -168,10 +168,16 @@ public static class ConfigHandler config.Fragment4RayItem ??= new() { Packets = "tlshello", - Length = "50-100", - Interval = "10-20", - MaxSplit = "0" }; + config.Fragment4RayItem.MaxSplit ??= "0"; + if ((config.Fragment4RayItem.Lengths ?? []).Count == 0) + { + config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"]; + } + if ((config.Fragment4RayItem.Delays ?? []).Count == 0) + { + config.Fragment4RayItem.Delays = [config.Fragment4RayItem.Interval ?? "10-20"]; + } config.GlobalHotkeys ??= []; if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty()) diff --git a/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs b/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs index 6771d6b0..4c5570a1 100644 --- a/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs @@ -249,9 +249,14 @@ public class CheckUpdateItem public class Fragment4RayItem { public string? Packets { get; set; } + public List? Lengths { get; set; } + public List? Delays { get; set; } + public string? MaxSplit { get; set; } + + // For migration from old version, remove those properties in the future public string? Length { get; set; } public string? Interval { get; set; } - public string? MaxSplit { get; set; } + // migration end } [Serializable] @@ -275,6 +280,7 @@ public class SimpleDNSItem public string? BootstrapDNS { get; set; } public string? Strategy4Freedom { get; set; } public string? Strategy4Proxy { get; set; } + public string? Strategy4ProxyDial { get; set; } public bool? ServeStale { get; set; } public bool? ParallelQuery { get; set; } public string? Hosts { get; set; } diff --git a/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs b/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs index b63eff76..d13518e9 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs @@ -136,8 +136,6 @@ public class Outboundsettings4Ray public Response4Ray? response { get; set; } - public string? domainStrategy { get; set; } - public int? userLevel { get; set; } public string? secretKey { get; set; } @@ -516,6 +514,8 @@ public class MaskSettings4Ray public string? length { get; set; } public string? delay { get; set; } + public List? lengths { get; set; } + public List? delays { get; set; } public int? maxSplit { get; set; } // noise @@ -547,6 +547,8 @@ public class AccountsItem4Ray public class Sockopt4Ray { + public string? domainStrategy { get; set; } + public string? dialerProxy { get; set; } [JsonPropertyName("interface")] diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 18403692..33308576 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -3528,6 +3528,24 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Proxy Dial Resolution Strategy 的本地化字符串。 + /// + public static string TbProxyDialResolveStrategy { + get { + return ResourceManager.GetString("TbProxyDialResolveStrategy", resourceCulture); + } + } + + /// + /// 查找类似 Not recommended; may cause routing loops. 的本地化字符串。 + /// + public static string TbProxyDialResolveStrategyTip { + get { + return ResourceManager.GetString("TbProxyDialResolveStrategyTip", resourceCulture); + } + } + /// /// 查找类似 Public Key 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 67a6e43c..5ddf108d 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1830,4 +1830,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation. + + Proxy Dial Resolution Strategy + + + Not recommended; may cause routing loops. + diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 5f845da4..3ae2b752 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1827,4 +1827,10 @@ 仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。 + + 连接代理解析策略 + + + 不建议开启,特殊情况可能回环。 + diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index 25db8b1c..4e813c63 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -171,7 +171,7 @@ public partial class CoreConfigSingboxService _coreConfig.dns.rules.Add(new() { server = Global.SingboxDirectDNSTag, - strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom), + strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial), domain = context.ProtectDomainList.ToList(), }); } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 6e359fc0..99cdbd29 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -417,11 +417,15 @@ public partial class CoreConfigSingboxService var tls = new Tls4Sbox() { enabled = true, - record_fragment = _config.CoreBasicItem.EnableFragment ? true : null, server_name = serverName, insecure = _node.GetAllowInsecure(), alpn = _node.GetAlpn(), }; + if (_config.CoreBasicItem.EnableFragment == true) + { + tls.fragment = true; + tls.record_fragment = true; + } if (_node.Fingerprint.IsNotEmpty()) { tls.utls = new Utls4Sbox() diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs index 9c30ae61..0ba2d08f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs @@ -10,18 +10,27 @@ public partial class CoreConfigSingboxService var simpleDnsItem = context.SimpleDnsItem; var defaultDomainResolverTag = Global.SingboxDirectDNSTag; - var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); + var dialDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial); var rawDNSItem = context.RawDnsItem; if (rawDNSItem is { Enabled: true }) { defaultDomainResolverTag = Global.SingboxLocalDNSTag; - directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom; + dialDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom; + } + else if (!simpleDnsItem.Strategy4Freedom.IsNullOrEmpty()) + { + var directOutbound = _coreConfig.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag); + directOutbound?.domain_resolver = new() + { + server = defaultDomainResolverTag, + strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom), + }; } _coreConfig.route.default_domain_resolver = new() { server = defaultDomainResolverTag, - strategy = directDnsStrategy + strategy = dialDnsStrategy }; if (context.IsTunEnabled) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index 887d2c18..7a020096 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -43,11 +43,9 @@ public partial class CoreConfigV2rayService var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); if (outbound != null) { - outbound.settings = new() - { - domainStrategy = strategy4Freedom, - userLevel = 0 - }; + outbound.streamSettings ??= new(); + outbound.streamSettings.sockopt ??= new(); + outbound.streamSettings.sockopt.domainStrategy = strategy4Freedom; } } @@ -64,6 +62,24 @@ public partial class CoreConfigV2rayService .ForEach(outbound => outbound.targetStrategy = strategy4Proxy); } + var strategy4DialProxy = simpleDnsItem?.Strategy4ProxyDial ?? Global.AsIs; + //Outbound DialProxy domainStrategy + if (strategy4DialProxy.IsNotEmpty() && strategy4DialProxy != Global.AsIs) + { + var xraySupportConfigTypeNames = Global.XraySupportConfigType + .Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x]) + .ToHashSet(); + _coreConfig.outbounds + .Where(t => xraySupportConfigTypeNames.Contains(t.protocol)) + .ToList() + .ForEach(outbound => + { + outbound.streamSettings ??= new(); + outbound.streamSettings.sockopt ??= new(); + outbound.streamSettings.sockopt.domainStrategy = strategy4DialProxy; + }); + } + FillDnsServers(dnsItem); FillDnsHosts(dnsItem); @@ -384,11 +400,9 @@ public partial class CoreConfigV2rayService var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); if (outbound != null) { - outbound.settings = new() - { - domainStrategy = domainStrategy4Freedom, - userLevel = 0, - }; + outbound.streamSettings ??= new(); + outbound.streamSettings.sockopt ??= new(); + outbound.streamSettings.sockopt.domainStrategy = domainStrategy4Freedom; } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 8b98fe10..585bade1 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -865,21 +865,10 @@ public partial class CoreConfigV2rayService && (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true)) .ToList(); - var (fragmentMask, noiseMask) = BuildFragmentsMasks(); + var fragmentMask = BuildFragmentsMasks(); foreach (var outbound in actOutboundWithTlsList) { - //var packets = configPackets; - //if (outbound.streamSettings.security == Global.StreamSecurityReality - // && packets == "tlshello") - //{ - // packets = "1-3"; - //} - //else if (outbound.streamSettings.security == Global.StreamSecurity - // && packets != "tlshello") - //{ - // packets = "tlshello"; - //} var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject(); // tcp fragment var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? []; @@ -888,13 +877,6 @@ public partial class CoreConfigV2rayService tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask)); finalMaskJsonObj["tcp"] = tcpFinalmaskList; } - // udp noise - var udpFinalmaskList = finalMaskJsonObj["udp"] as JsonArray ?? []; - if (udpFinalmaskList.Count == 0) - { - udpFinalmaskList.Add(JsonUtils.SerializeToNode(noiseMask)); - finalMaskJsonObj["udp"] = udpFinalmaskList; - } // write back outbound.streamSettings.finalmask = finalMaskJsonObj; } @@ -902,7 +884,7 @@ public partial class CoreConfigV2rayService private void ApplyFinalFragment() { - var (fragmentMask, noiseMask) = BuildFragmentsMasks(); + var fragmentMask = BuildFragmentsMasks(); var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList(); var fragmentFreedom = new Outbounds4Ray() @@ -914,9 +896,8 @@ public partial class CoreConfigV2rayService finalmask = new Finalmask4Ray { tcp = [fragmentMask], - udp = [noiseMask], - } - } + }, + }, }; foreach (var outbound in actOutboundList) @@ -934,13 +915,22 @@ public partial class CoreConfigV2rayService } } - private (Mask4Ray tcpFragment, Mask4Ray udpNoise) BuildFragmentsMasks() + private Mask4Ray BuildFragmentsMasks() { var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello"; - var configLength = _config.Fragment4RayItem?.Length.NullIfEmpty() ?? "50-100"; - var configDelay = _config.Fragment4RayItem?.Interval.NullIfEmpty() ?? "10-20"; + var configLengths = _config.Fragment4RayItem?.Lengths ?? []; + var configDelays = _config.Fragment4RayItem?.Delays ?? []; var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0"; + if (configLengths.Count == 0) + { + configLengths = ["50-100"]; + } + if (configDelays.Count == 0) + { + configDelays = ["10-20"]; + } + var maxSplit = 0; var parts = configMaxSplit.Split('-'); if (parts.Length > 0 && int.TryParse(parts[0], out var ms)) @@ -954,21 +944,15 @@ public partial class CoreConfigV2rayService settings = new MaskSettings4Ray { packets = configPackets, - length = configLength, - delay = configDelay, + lengths = configLengths, + delays = configDelays, maxSplit = maxSplit, - } - }; - var noiseMask = new Mask4Ray - { - type = "noise", - settings = new MaskSettings4Ray - { - length = "10-20", - delay = "10-16", - } + // For legacy xray compatibility, remove this in the future + length = configLengths.FirstOrDefault(), + delay = configDelays.FirstOrDefault(), + }, }; - return (fragmentMask, noiseMask); + return fragmentMask; } } diff --git a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs index 4b389bff..d576f31d 100644 --- a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs @@ -13,6 +13,7 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable [Reactive] public string? BootstrapDNS { get; set; } [Reactive] public string? Strategy4Freedom { get; set; } [Reactive] public string? Strategy4Proxy { get; set; } + [Reactive] public string? Strategy4ProxyDial { get; set; } [Reactive] public string? Hosts { get; set; } [Reactive] public string? DirectExpectedIPs { get; set; } [Reactive] public bool? ParallelQuery { get; set; } @@ -76,6 +77,7 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable BootstrapDNS = item.BootstrapDNS; Strategy4Freedom = item.Strategy4Freedom; Strategy4Proxy = item.Strategy4Proxy; + Strategy4ProxyDial = item.Strategy4ProxyDial; Hosts = item.Hosts; DirectExpectedIPs = item.DirectExpectedIPs; ParallelQuery = item.ParallelQuery; @@ -108,6 +110,7 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable _config.SimpleDNSItem.BootstrapDNS = BootstrapDNS; _config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom; _config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy; + _config.SimpleDNSItem.Strategy4ProxyDial = Strategy4ProxyDial; _config.SimpleDNSItem.Hosts = Hosts; _config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs; _config.SimpleDNSItem.ParallelQuery = ParallelQuery; diff --git a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs index 885ebc52..3b47d290 100644 --- a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs @@ -29,8 +29,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable [Reactive] public bool EnableFragment { get; set; } [Reactive] public bool EnableFinalFragment { get; set; } [Reactive] public string FragmentPackets { get; set; } - [Reactive] public string FragmentLength { get; set; } - [Reactive] public string FragmentInterval { get; set; } + [Reactive] public string FragmentLengths { get; set; } + [Reactive] public string FragmentDelays { get; set; } [Reactive] public string FragmentMaxSplit { get; set; } #endregion Core @@ -168,8 +168,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable EnableFragment = _config.CoreBasicItem.EnableFragment; EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment; FragmentPackets = _config.Fragment4RayItem?.Packets; - FragmentLength = _config.Fragment4RayItem?.Length; - FragmentInterval = _config.Fragment4RayItem?.Interval; + FragmentLengths = Utils.List2String(_config.Fragment4RayItem?.Lengths); + FragmentDelays = Utils.List2String(_config.Fragment4RayItem?.Delays); FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit; #endregion Core @@ -309,6 +309,15 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort); return; } + var fragmentLengths = Utils.String2List(FragmentLengths) ?? []; + var fragmentDelays = Utils.String2List(FragmentDelays) ?? []; + if (fragmentLengths.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _)) + || fragmentDelays.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _)) + || (FragmentMaxSplit.IsNotEmpty() && !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _))) + { + NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError); + return; + } var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics || DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed || EnableDragDropSort != _config.UiItem.EnableDragDropSort @@ -351,30 +360,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable _config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox; _config.HysteriaItem.UpMbps = HyUpMbps ?? 0; _config.HysteriaItem.DownMbps = HyDownMbps ?? 0; - if (EnableFragment) - { - if (!Utils.TryParseRange(FragmentLength, 0, int.MaxValue, out _, out _)) - { - NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError); - return; - } - if (!Utils.TryParseRange(FragmentInterval, 1, 100, out _, out _)) - { - NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError); - return; - } - if (FragmentMaxSplit.IsNotEmpty() - && !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _)) - { - NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError); - return; - } - } _config.CoreBasicItem.EnableFragment = EnableFragment; _config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment; + _config.Fragment4RayItem ??= new(); _config.Fragment4RayItem.Packets = FragmentPackets; - _config.Fragment4RayItem.Length = FragmentLength; - _config.Fragment4RayItem.Interval = FragmentInterval; + _config.Fragment4RayItem.Lengths = fragmentLengths; + _config.Fragment4RayItem.Delays = fragmentDelays; _config.Fragment4RayItem.MaxSplit = FragmentMaxSplit; _config.GuiItem.AutoRun = AutoRun; diff --git a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml index 9228d37d..0e9b9c4b 100644 --- a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml @@ -42,7 +42,7 @@ x:Name="gridBasicDNSSettings" Margin="{StaticResource Margin8}" ColumnDefinitions="Auto,Auto,*" - RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> + RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> - + + VerticalAlignment="Center" + PlaceholderText="Default" /> + + + + cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; + cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; @@ -37,6 +38,7 @@ public partial class DNSSettingWindow : WindowBase this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables); diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml index 5b39896b..0dbee8b0 100644 --- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml @@ -347,7 +347,7 @@ VerticalAlignment="Center" Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" /> this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables); + 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.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml index d2bdcb9b..16769b02 100644 --- a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml +++ b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml @@ -52,6 +52,7 @@ + @@ -195,13 +196,23 @@ Margin="{StaticResource Margin8}" VerticalAlignment="Center" Style="{StaticResource ToolbarTextBlock}" - Text="{x:Static resx:ResUI.TbParallelQuery}" /> - + + materialDesign:HintAssist.Hint="Default" + Style="{StaticResource DefComboBox}" /> + + + + diff --git a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs index 255ee155..37c7376a 100644 --- a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs @@ -12,6 +12,7 @@ public partial class DNSSettingWindow cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; + cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; @@ -33,6 +34,7 @@ public partial class DNSSettingWindow this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml index be2e84c9..5b8c9a0e 100644 --- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml +++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml @@ -419,7 +419,7 @@ Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" TextWrapping="Wrap" /> vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables); + 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);