From 57ba378072b9cf056ddff3f449adc240d177c358 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sat, 31 Jan 2026 11:10:31 +0800 Subject: [PATCH] Add ParallelQuery and ServeStale features --- v2rayN/ServiceLib/Global.cs | 4 +- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 2 + v2rayN/ServiceLib/Models/ConfigItems.cs | 2 + v2rayN/ServiceLib/Models/V2rayConfig.cs | 10 +- v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 18 +++ v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 6 + v2rayN/ServiceLib/Resx/ResUI.fr.resx | 6 + v2rayN/ServiceLib/Resx/ResUI.hu.resx | 6 + v2rayN/ServiceLib/Resx/ResUI.resx | 6 + v2rayN/ServiceLib/Resx/ResUI.ru.resx | 6 + v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 6 + v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 6 + .../CoreConfig/V2ray/V2rayDnsService.cs | 132 ++++++++++-------- .../ViewModels/DNSSettingViewModel.cs | 6 + .../Views/DNSSettingWindow.axaml | 56 ++++++-- .../Views/DNSSettingWindow.axaml.cs | 2 + v2rayN/v2rayN/Views/DNSSettingWindow.xaml | 55 ++++++-- v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs | 2 + 18 files changed, 234 insertions(+), 97 deletions(-) diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 1fcd7b7c..c4bb8b80 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -409,6 +409,7 @@ public class Global [ "https://dns.alidns.com/dns-query", "https://doh.pub/dns-query", + "https://dns.alidns.com/dns-query,https://doh.pub/dns-query", "223.5.5.5", "119.29.29.29", "localhost" @@ -417,8 +418,9 @@ public class Global public static readonly List DomainRemoteDNSAddress = [ "https://cloudflare-dns.com/dns-query", - "https://dns.cloudflare.com/dns-query", "https://dns.google/dns-query", + "https://cloudflare-dns.com/dns-query,https://dns.google/dns-query,8.8.8.8", + "https://dns.cloudflare.com/dns-query", "https://doh.dns.sb/dns-query", "https://doh.opendns.com/dns-query", "https://common.dot.dns.yandex.net", diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 5877d012..f9ff4494 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -114,6 +114,8 @@ public static class ConfigHandler config.SimpleDNSItem ??= InitBuiltinSimpleDNS(); config.SimpleDNSItem.GlobalFakeIp ??= true; config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault(); + config.SimpleDNSItem.ServeStale ??= false; + config.SimpleDNSItem.ParallelQuery ??= false; config.SpeedTestItem ??= new(); if (config.SpeedTestItem.SpeedTestTimeout < 10) diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs index 04fc955b..46297e40 100644 --- a/v2rayN/ServiceLib/Models/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/ConfigItems.cs @@ -267,6 +267,8 @@ public class SimpleDNSItem public string? BootstrapDNS { get; set; } public string? Strategy4Freedom { get; set; } public string? Strategy4Proxy { get; set; } + public bool? ServeStale { get; set; } + public bool? ParallelQuery { get; set; } public string? Hosts { get; set; } public string? DirectExpectedIPs { get; set; } } diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index 09a145bc..c752168a 100644 --- a/v2rayN/ServiceLib/Models/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs @@ -3,7 +3,7 @@ namespace ServiceLib.Models; public class V2rayConfig { public Log4Ray log { get; set; } - public Dns4Ray dns { get; set; } + public object dns { get; set; } public List inbounds { get; set; } public List outbounds { get; set; } public Routing4Ray routing { get; set; } @@ -208,12 +208,8 @@ public class Dns4Ray { public Dictionary? hosts { get; set; } public List servers { get; set; } - public string? clientIp { get; set; } - public string? queryStrategy { get; set; } - public bool? disableCache { get; set; } - public bool? disableFallback { get; set; } - public bool? disableFallbackIfMatch { get; set; } - public bool? useSystemHosts { get; set; } + public bool? serveStale { get; set; } + public bool? enableParallelQuery { get; set; } public string? tag { get; set; } } diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 6d11f747..9bfb77a9 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -3069,6 +3069,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Parallel Query 的本地化字符串。 + /// + public static string TbParallelQuery { + get { + return ResourceManager.GetString("TbParallelQuery", resourceCulture); + } + } + /// /// 查找类似 Path 的本地化字符串。 /// @@ -3438,6 +3447,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Serve Stale 的本地化字符串。 + /// + public static string TbServeStale { + get { + return ResourceManager.GetString("TbServeStale", resourceCulture); + } + } + /// /// 查找类似 Set system proxy 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index fc69f970..70ee0c54 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1650,4 +1650,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx index 1f3b5096..6c5e9fef 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -1647,4 +1647,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index 2e3f4900..aa8c0762 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1650,4 +1650,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index f8710615..da17f12f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1650,4 +1650,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index 49e6203a..da856d97 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1650,4 +1650,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index ca6bb05d..82f1fd47 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1647,4 +1647,10 @@ 证书指纹(SHA-256) + + 乐观缓存 + + + 并行查询 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index ff0d4388..389f1719 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1647,4 +1647,10 @@ Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index 2369f1e2..2329c395 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -7,25 +7,35 @@ public partial class CoreConfigV2rayService try { var item = await AppManager.Instance.GetDNSItem(ECoreType.Xray); - if (item != null && item.Enabled == true) + if (item is { Enabled: true }) { var result = await GenDnsCompatible(node, v2rayConfig); - if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch) + if (v2rayConfig.routing.domainStrategy != Global.IPIfNonMatch) { - // DNS routing - v2rayConfig.dns.tag = Global.DnsTag; - v2rayConfig.routing.rules.Add(new RulesItem4Ray - { - type = "field", - inboundTag = new List { Global.DnsTag }, - outboundTag = Global.ProxyTag, - }); + return result; } + // DNS routing + var dnsObj = JsonUtils.SerializeToNode(v2rayConfig.dns); + if (dnsObj == null) + { + return result; + } + + dnsObj["tag"] = Global.DnsTag; + v2rayConfig.dns = JsonUtils.Deserialize(JsonUtils.Serialize(dnsObj)); + v2rayConfig.routing.rules.Add(new RulesItem4Ray + { + type = "field", + inboundTag = new List { Global.DnsTag }, + outboundTag = Global.ProxyTag, + }); + return result; } var simpleDnsItem = _config.SimpleDNSItem; + var dnsItem = v2rayConfig.dns is Dns4Ray dns4Ray ? dns4Ray : new Dns4Ray(); var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs; //Outbound Freedom domainStrategy @@ -55,13 +65,16 @@ public partial class CoreConfigV2rayService .ForEach(outbound => outbound.targetStrategy = strategy4Proxy); } - await GenDnsServers(node, v2rayConfig, simpleDnsItem); - await GenDnsHosts(v2rayConfig, simpleDnsItem); + await GenDnsServers(node, dnsItem, simpleDnsItem); + await GenDnsHosts(dnsItem, simpleDnsItem); + + dnsItem.serveStale = simpleDnsItem?.ServeStale is true ? true : null; + dnsItem.enableParallelQuery = simpleDnsItem?.ParallelQuery is true ? true : null; if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch) { // DNS routing - v2rayConfig.dns.tag = Global.DnsTag; + dnsItem.tag = Global.DnsTag; v2rayConfig.routing.rules.Add(new RulesItem4Ray { type = "field", @@ -69,6 +82,8 @@ public partial class CoreConfigV2rayService outboundTag = Global.ProxyTag, }); } + + v2rayConfig.dns = dnsItem; } catch (Exception ex) { @@ -77,7 +92,7 @@ public partial class CoreConfigV2rayService return 0; } - private async Task GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem) + private async Task GenDnsServers(ProfileItem? node, Dns4Ray dnsItem, SimpleDNSItem simpleDNSItem) { static List ParseDnsAddresses(string? dnsInput, string defaultAddress) { @@ -90,7 +105,7 @@ public partial class CoreConfigV2rayService return addresses.Count > 0 ? addresses : new List { defaultAddress }; } - static object CreateDnsServer(string dnsAddress, List domains, List? expectedIPs = null) + static object? CreateDnsServer(string dnsAddress, List domains, List? expectedIPs = null) { var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress); var domainFinal = dnsAddress; @@ -119,8 +134,8 @@ public partial class CoreConfigV2rayService }); } - var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.FirstOrDefault()); - var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.FirstOrDefault()); + var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.First()); + var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.First()); var directDomainList = new List(); var directGeositeList = new List(); @@ -130,7 +145,7 @@ public partial class CoreConfigV2rayService var expectedIPs = new List(); var regionNames = new HashSet(); - var bootstrapDNSAddress = ParseDnsAddresses(simpleDNSItem?.BootstrapDNS, Global.DomainPureIPDNSAddress.FirstOrDefault()); + var bootstrapDNSAddress = ParseDnsAddresses(simpleDNSItem?.BootstrapDNS, Global.DomainPureIPDNSAddress.First()); var dnsServerDomains = new List(); foreach (var dns in directDNSAddress) @@ -184,51 +199,48 @@ public partial class CoreConfigV2rayService var routing = await ConfigHandler.GetDefaultRouting(_config); List? rules = null; - if (routing != null) + rules = JsonUtils.Deserialize>(routing.RuleSet) ?? []; + foreach (var item in rules) { - rules = JsonUtils.Deserialize>(routing.RuleSet) ?? []; - foreach (var item in rules) + if (!item.Enabled || item.Domain is null || item.Domain.Count == 0) { - if (!item.Enabled || item.Domain is null || item.Domain.Count == 0) + continue; + } + + if (item.RuleType == ERuleType.Routing) + { + continue; + } + + foreach (var domain in item.Domain) + { + if (domain.StartsWith('#')) { continue; } - if (item.RuleType == ERuleType.Routing) + var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ","); + + if (item.OutboundTag == Global.DirectTag) { - continue; + if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) + { + (regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain); + } + else + { + directDomainList.Add(normalizedDomain); + } } - - foreach (var domain in item.Domain) + else if (item.OutboundTag != Global.BlockTag) { - if (domain.StartsWith('#')) + if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) { - continue; + proxyGeositeList.Add(normalizedDomain); } - - var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ","); - - if (item.OutboundTag == Global.DirectTag) + else { - if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) - { - (regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain); - } - else - { - directDomainList.Add(normalizedDomain); - } - } - else if (item.OutboundTag != Global.BlockTag) - { - if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) - { - proxyGeositeList.Add(normalizedDomain); - } - else - { - proxyDomainList.Add(normalizedDomain); - } + proxyDomainList.Add(normalizedDomain); } } } @@ -257,8 +269,7 @@ public partial class CoreConfigV2rayService } } - v2rayConfig.dns ??= new Dns4Ray(); - v2rayConfig.dns.servers ??= new List(); + dnsItem.servers ??= []; void AddDnsServers(List dnsAddresses, List domains, List? expectedIPs = null) { @@ -266,7 +277,7 @@ public partial class CoreConfigV2rayService { foreach (var dnsAddress in dnsAddresses) { - v2rayConfig.dns.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs)); + dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs)); } } } @@ -288,22 +299,21 @@ public partial class CoreConfigV2rayService || lastRule.Ip?.Contains("0.0.0.0/0") == true); var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress; - v2rayConfig.dns.servers.AddRange(defaultDnsServers); + dnsItem.servers.AddRange(defaultDnsServers); return 0; } - private async Task GenDnsHosts(V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem) + private async Task GenDnsHosts(Dns4Ray dnsItem, SimpleDNSItem simpleDNSItem) { if (simpleDNSItem.AddCommonHosts == false && simpleDNSItem.UseSystemHosts == false && simpleDNSItem.Hosts.IsNullOrEmpty()) { return await Task.FromResult(0); } - v2rayConfig.dns ??= new Dns4Ray(); - v2rayConfig.dns.hosts ??= new Dictionary(); + dnsItem.hosts ??= new Dictionary(); if (simpleDNSItem.AddCommonHosts == true) { - v2rayConfig.dns.hosts = Global.PredefinedHosts.ToDictionary( + dnsItem.hosts = Global.PredefinedHosts.ToDictionary( kvp => kvp.Key, kvp => (object)kvp.Value ); @@ -312,7 +322,7 @@ public partial class CoreConfigV2rayService if (simpleDNSItem.UseSystemHosts == true) { var systemHosts = Utils.GetSystemHosts(); - var normalHost = v2rayConfig?.dns?.hosts; + var normalHost = dnsItem.hosts; if (normalHost != null && systemHosts?.Count > 0) { @@ -329,7 +339,7 @@ public partial class CoreConfigV2rayService foreach (var kvp in userHostsMap) { - v2rayConfig.dns.hosts[kvp.Key] = kvp.Value; + dnsItem.hosts[kvp.Key] = kvp.Value; } } return await Task.FromResult(0); diff --git a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs index 914c3ac7..00178d17 100644 --- a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs @@ -13,6 +13,8 @@ public class DNSSettingViewModel : MyReactiveObject [Reactive] public string? Strategy4Proxy { get; set; } [Reactive] public string? Hosts { get; set; } [Reactive] public string? DirectExpectedIPs { get; set; } + [Reactive] public bool? ParallelQuery { get; set; } + [Reactive] public bool? ServeStale { get; set; } [Reactive] public bool UseSystemHostsCompatible { get; set; } [Reactive] public string DomainStrategy4FreedomCompatible { get; set; } @@ -73,6 +75,8 @@ public class DNSSettingViewModel : MyReactiveObject Strategy4Proxy = item.Strategy4Proxy; Hosts = item.Hosts; DirectExpectedIPs = item.DirectExpectedIPs; + ParallelQuery = item.ParallelQuery; + ServeStale = item.ServeStale; var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray); RayCustomDNSEnableCompatible = item1.Enabled; @@ -102,6 +106,8 @@ public class DNSSettingViewModel : MyReactiveObject _config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy; _config.SimpleDNSItem.Hosts = Hosts; _config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs; + _config.SimpleDNSItem.ParallelQuery = ParallelQuery; + _config.SimpleDNSItem.ServeStale = ServeStale; if (NormalDNSCompatible.IsNotEmpty()) { diff --git a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml index b41a0a99..0f839c58 100644 --- a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml @@ -132,19 +132,32 @@ Width="200" Margin="{StaticResource Margin4}" PlaceholderText="Default" /> - + + Text="{x:Static resx:ResUI.TbParallelQuery}" /> + + + @@ -155,7 +168,7 @@ x:Name="gridAdvancedDNSSettings" Margin="{StaticResource Margin8}" ColumnDefinitions="Auto,Auto,*" - RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,*"> + RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,*"> + Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" /> + + + this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.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); + this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml index 40753a37..0a79ed8f 100644 --- a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml +++ b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml @@ -171,13 +171,27 @@ Margin="{StaticResource Margin8}" VerticalAlignment="Center" Style="{StaticResource ToolbarTextBlock}" - Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" /> + Text="{x:Static resx:ResUI.TbParallelQuery}" /> + + + @@ -191,6 +205,7 @@ + @@ -229,15 +244,29 @@ Margin="{StaticResource Margin8}" VerticalAlignment="Center" Style="{StaticResource ToolbarTextBlock}" - Text="{x:Static resx:ResUI.TbFakeIP}" /> + Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" /> + + + vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.Text).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); + this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);