diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index 0f4feda5..22d10304 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -462,6 +462,18 @@ public class Utils return (domain, port); } + public static string? DomainStrategy4Sbox(string? strategy) + { + 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", + _ => null + }; + } + #endregion Conversion Functions #region Data Checks diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 94a66fa5..a902bbdd 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -329,13 +329,13 @@ public class Global IPOnDemand ]; - public static readonly List DomainStrategies4Singbox = + public static readonly List DomainStrategies4Sbox = [ - "ipv4_only", - "ipv6_only", + "", "prefer_ipv4", "prefer_ipv6", - "" + "ipv4_only", + "ipv6_only" ]; public static readonly List Fingerprints = @@ -377,28 +377,22 @@ public class Global "" ]; - public static readonly List DomainStrategy4Freedoms = + public static readonly List DomainStrategy = [ "AsIs", "UseIP", + "UseIPv4v6", + "UseIPv6v4", "UseIPv4", "UseIPv6", "" ]; - public static readonly List SingboxDomainStrategy4Out = - [ - "", - "ipv4_only", - "prefer_ipv4", - "prefer_ipv6", - "ipv6_only" - ]; - public static readonly List DomainDirectDNSAddress = [ "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" @@ -407,8 +401,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 eeb88deb..46297e40 100644 --- a/v2rayN/ServiceLib/Models/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/ConfigItems.cs @@ -265,9 +265,10 @@ public class SimpleDNSItem public string? DirectDNS { get; set; } public string? RemoteDNS { get; set; } public string? BootstrapDNS { get; set; } - public string? RayStrategy4Freedom { get; set; } - public string? SingboxStrategy4Direct { get; set; } - public string? SingboxStrategy4Proxy { 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 d9575432..6a185670 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; } @@ -105,6 +105,8 @@ public class Outbounds4Ray public string protocol { get; set; } + public string? targetStrategy { get; set; } + public Outboundsettings4Ray settings { get; set; } public StreamSettings4Ray streamSettings { get; set; } @@ -206,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 bf30c985..9bfb77a9 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -2727,6 +2727,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Direct Resolution Strategy 的本地化字符串。 + /// + public static string TbDirectResolveStrategy { + get { + return ResourceManager.GetString("TbDirectResolveStrategy", resourceCulture); + } + } + /// /// 查找类似 Display GUI 的本地化字符串。 /// @@ -3060,6 +3069,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Parallel Query 的本地化字符串。 + /// + public static string TbParallelQuery { + get { + return ResourceManager.GetString("TbParallelQuery", resourceCulture); + } + } + /// /// 查找类似 Path 的本地化字符串。 /// @@ -3222,6 +3240,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Remote Resolution Strategy 的本地化字符串。 + /// + public static string TbRemoteResolveStrategy { + get { + return ResourceManager.GetString("TbRemoteResolveStrategy", resourceCulture); + } + } + /// /// 查找类似 Camouflage domain(host) 的本地化字符串。 /// @@ -3357,15 +3384,6 @@ namespace ServiceLib.Resx { } } - /// - /// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。 - /// - public static string TbSBDirectResolveStrategy { - get { - return ResourceManager.GetString("TbSBDirectResolveStrategy", resourceCulture); - } - } - /// /// 查找类似 sing-box Full Config Template 的本地化字符串。 /// @@ -3384,15 +3402,6 @@ namespace ServiceLib.Resx { } } - /// - /// 查找类似 sing-box Remote Resolution Strategy 的本地化字符串。 - /// - public static string TbSBRemoteResolveStrategy { - get { - return ResourceManager.GetString("TbSBRemoteResolveStrategy", resourceCulture); - } - } - /// /// 查找类似 Encryption method (security) 的本地化字符串。 /// @@ -3438,6 +3447,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Serve Stale 的本地化字符串。 + /// + public static string TbServeStale { + get { + return ResourceManager.GetString("TbServeStale", resourceCulture); + } + } + /// /// 查找类似 Set system proxy 的本地化字符串。 /// @@ -4419,15 +4437,6 @@ namespace ServiceLib.Resx { } } - /// - /// 查找类似 xray Freedom Resolution Strategy 的本地化字符串。 - /// - public static string TbXrayFreedomStrategy { - get { - return ResourceManager.GetString("TbXrayFreedomStrategy", resourceCulture); - } - } - /// /// 查找类似 The delay: {0} ms, {1} 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index 3a720cdd..70ee0c54 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1422,14 +1422,11 @@ Via proxy — please ensure remote availability - - xray Freedom Resolution Strategy + + Direct Resolution Strategy - - sing-box Direct Resolution Strategy - - - sing-box Remote Resolution Strategy + + Remote Resolution Strategy Add Common DNS Hosts @@ -1653,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 f1710de6..6c5e9fef 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -1419,14 +1419,11 @@ Via le proxy ; assurez-vous que le serveur distant est disponible - - Stratégie de résolution xray freedom + + Stratégie de résolution directe - - Stratégie de résolution directe sing-box - - - Stratégie de résolution distante sing-box + + Stratégie de résolution distante Ajouter des hôtes DNS courants @@ -1650,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 4787f0f1..aa8c0762 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1422,14 +1422,11 @@ Via proxy — please ensure remote availability - - xray Freedom Resolution Strategy + + Direct Resolution Strategy - - sing-box Direct Resolution Strategy - - - sing-box Remote Resolution Strategy + + Remote Resolution Strategy Add Common DNS Hosts @@ -1653,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 6ad8a6e4..da17f12f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1422,14 +1422,11 @@ Via proxy — please ensure remote availability - - xray Freedom Resolution Strategy + + Direct Resolution Strategy - - sing-box Direct Resolution Strategy - - - sing-box Remote Resolution Strategy + + Remote Resolution Strategy Add Common DNS Hosts @@ -1653,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 3a0f9fef..da856d97 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1422,14 +1422,11 @@ Via proxy — please ensure remote availability - - Стратегия резолвинга Freedom (Xray) + + Стратегия прямого резолвинга - - Стратегия прямого резолвинга (sing-box) - - - Стратегия удалённого резолвинга (sing-box) + + Стратегия удалённого резолвинга Добавить стандартные записи hosts (DNS) @@ -1653,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 b37e0ccb..82f1fd47 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1419,14 +1419,11 @@ 通过代理,请确保远程可用 - - xray freedom 解析策略 + + 直连解析策略 - - sing-box 直连解析策略 - - - sing-box 远程解析策略 + + 远程解析策略 添加常用 DNS Hosts @@ -1650,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 b5acd049..389f1719 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1419,14 +1419,11 @@ 通过代理,请确保远程可用 - - xray freedom 解析策略 + + 直連解析策略 - - sing-box 直連解析策略 - - - sing-box 遠程解析策略 + + 遠程解析策略 新增常用 DNS Hosts @@ -1650,4 +1647,10 @@ Certificate fingerprint (SHA-256) + + Serve Stale + + + Parallel Query + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index fa089140..6079b2fb 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -175,18 +175,18 @@ public partial class CoreConfigSingboxService singboxConfig.dns.rules ??= new List(); singboxConfig.dns.rules.AddRange(new[] - { + { new Rule4Sbox { ip_accept_any = true, server = Global.SingboxHostsDNSTag }, new Rule4Sbox { server = Global.SingboxRemoteDNSTag, - strategy = simpleDNSItem.SingboxStrategy4Proxy.NullIfEmpty(), + strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Proxy), clash_mode = ERuleMode.Global.ToString() }, new Rule4Sbox { server = Global.SingboxDirectDNSTag, - strategy = simpleDNSItem.SingboxStrategy4Direct.NullIfEmpty(), + strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Freedom), clash_mode = ERuleMode.Direct.ToString() } }); @@ -309,7 +309,7 @@ public partial class CoreConfigSingboxService if (item.OutboundTag == Global.DirectTag) { rule.server = Global.SingboxDirectDNSTag; - rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Direct) ? null : simpleDNSItem.SingboxStrategy4Direct; + rule.strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Freedom); if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0) { @@ -343,7 +343,7 @@ public partial class CoreConfigSingboxService singboxConfig.dns.rules.Add(rule4Fake); } rule.server = Global.SingboxRemoteDNSTag; - rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Proxy) ? null : simpleDNSItem.SingboxStrategy4Proxy; + rule.strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Proxy); } singboxConfig.dns.rules.Add(rule); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs index d53f29f8..cb4a2af1 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxRoutingService.cs @@ -7,21 +7,21 @@ public partial class CoreConfigSingboxService try { singboxConfig.route.final = Global.ProxyTag; - var item = _config.SimpleDNSItem; + var simpleDnsItem = _config.SimpleDNSItem; var defaultDomainResolverTag = Global.SingboxDirectDNSTag; - var directDNSStrategy = item.SingboxStrategy4Direct.IsNullOrEmpty() ? Global.SingboxDomainStrategy4Out.FirstOrDefault() : item.SingboxStrategy4Direct; + var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); var rawDNSItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); - if (rawDNSItem != null && rawDNSItem.Enabled == true) + if (rawDNSItem is { Enabled: true }) { defaultDomainResolverTag = Global.SingboxLocalDNSTag; - directDNSStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? Global.SingboxDomainStrategy4Out.FirstOrDefault() : rawDNSItem.DomainStrategy4Freedom; + directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom; } singboxConfig.route.default_domain_resolver = new() { server = defaultDomainResolverTag, - strategy = directDNSStrategy + strategy = directDnsStrategy }; if (_config.TunModeItem.EnableTun) @@ -73,18 +73,17 @@ public partial class CoreConfigSingboxService var hostsDomains = new List(); var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); - if (dnsItem == null || dnsItem.Enabled == false) + if (dnsItem == null || !dnsItem.Enabled) { - var simpleDNSItem = _config.SimpleDNSItem; - if (!simpleDNSItem.Hosts.IsNullOrEmpty()) + if (!simpleDnsItem.Hosts.IsNullOrEmpty()) { - var userHostsMap = Utils.ParseHostsToDictionary(simpleDNSItem.Hosts); + var userHostsMap = Utils.ParseHostsToDictionary(simpleDnsItem.Hosts); foreach (var kvp in userHostsMap) { hostsDomains.Add(kvp.Key); } } - if (simpleDNSItem.UseSystemHosts == true) + if (simpleDnsItem.UseSystemHosts == true) { var systemHostsMap = Utils.GetSystemHosts(); foreach (var kvp in systemHostsMap) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index 6ba45895..2329c395 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -7,48 +7,74 @@ 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 domainStrategy4Freedom = simpleDNSItem?.RayStrategy4Freedom; + var simpleDnsItem = _config.SimpleDNSItem; + var dnsItem = v2rayConfig.dns is Dns4Ray dns4Ray ? dns4Ray : new Dns4Ray(); + var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs; //Outbound Freedom domainStrategy - if (domainStrategy4Freedom.IsNotEmpty()) + if (strategy4Freedom.IsNotEmpty() && strategy4Freedom != Global.AsIs) { var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); if (outbound != null) { outbound.settings = new() { - domainStrategy = domainStrategy4Freedom, + domainStrategy = strategy4Freedom, userLevel = 0 }; } } - await GenDnsServers(node, v2rayConfig, simpleDNSItem); - await GenDnsHosts(v2rayConfig, simpleDNSItem); + var strategy4Proxy = simpleDnsItem?.Strategy4Proxy ?? Global.AsIs; + //Outbound Proxy domainStrategy + if (strategy4Proxy.IsNotEmpty() && strategy4Proxy != Global.AsIs) + { + var xraySupportConfigTypeNames = Global.XraySupportConfigType + .Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x]) + .ToHashSet(); + v2rayConfig.outbounds + .Where(t => xraySupportConfigTypeNames.Contains(t.protocol)) + .ToList() + .ForEach(outbound => outbound.targetStrategy = strategy4Proxy); + } + + 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", @@ -56,6 +82,8 @@ public partial class CoreConfigV2rayService outboundTag = Global.ProxyTag, }); } + + v2rayConfig.dns = dnsItem; } catch (Exception ex) { @@ -64,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) { @@ -77,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; @@ -106,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(); @@ -117,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) @@ -171,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); } } } @@ -244,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) { @@ -253,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)); } } } @@ -275,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 ); @@ -299,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) { @@ -316,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 d53b960d..00178d17 100644 --- a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs @@ -9,11 +9,12 @@ public class DNSSettingViewModel : MyReactiveObject [Reactive] public string? DirectDNS { get; set; } [Reactive] public string? RemoteDNS { get; set; } [Reactive] public string? BootstrapDNS { get; set; } - [Reactive] public string? RayStrategy4Freedom { get; set; } - [Reactive] public string? SingboxStrategy4Direct { get; set; } - [Reactive] public string? SingboxStrategy4Proxy { get; set; } + [Reactive] public string? Strategy4Freedom { get; set; } + [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; } @@ -70,11 +71,12 @@ public class DNSSettingViewModel : MyReactiveObject DirectDNS = item.DirectDNS; RemoteDNS = item.RemoteDNS; BootstrapDNS = item.BootstrapDNS; - RayStrategy4Freedom = item.RayStrategy4Freedom; - SingboxStrategy4Direct = item.SingboxStrategy4Direct; - SingboxStrategy4Proxy = item.SingboxStrategy4Proxy; + Strategy4Freedom = item.Strategy4Freedom; + 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; @@ -100,11 +102,12 @@ public class DNSSettingViewModel : MyReactiveObject _config.SimpleDNSItem.DirectDNS = DirectDNS; _config.SimpleDNSItem.RemoteDNS = RemoteDNS; _config.SimpleDNSItem.BootstrapDNS = BootstrapDNS; - _config.SimpleDNSItem.RayStrategy4Freedom = RayStrategy4Freedom; - _config.SimpleDNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct; - _config.SimpleDNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy; + _config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom; + _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 e5a785b7..0f839c58 100644 --- a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml @@ -105,28 +105,14 @@ Text="{x:Static resx:ResUI.TbBootstrapDNSTips}" TextWrapping="Wrap" /> - - - + Text="{x:Static resx:ResUI.TbDirectResolveStrategy}" /> + Text="{x:Static resx:ResUI.TbRemoteResolveStrategy}" /> - + + Text="{x:Static resx:ResUI.TbParallelQuery}" /> + + + @@ -169,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}" /> + + + btnCancel.Click += (s, e) => Close(); ViewModel = new DNSSettingViewModel(UpdateViewHandler); - cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms; - cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out; - cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out; + cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; + cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs; - cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms; - cmbdomainStrategy4OutCompatible.ItemsSource = Global.SingboxDomainStrategy4Out; + cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy; + cmbdomainStrategy4OutCompatible.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress; cmbdomainDNSAddress2Compatible.ItemsSource = Global.DomainPureIPDNSAddress; @@ -37,11 +36,12 @@ public partial class DNSSettingWindow : WindowBase this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.SelectedItem).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.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.Desktop/Views/RoutingRuleSettingWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml.cs index 076307ec..c2d90a33 100644 --- a/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml.cs @@ -26,7 +26,7 @@ public partial class RoutingRuleSettingWindow : WindowBase { diff --git a/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs index 719acf94..e25f7237 100644 --- a/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs @@ -22,7 +22,7 @@ public partial class RoutingSettingWindow : WindowBase ViewModel = new RoutingSettingViewModel(UpdateViewHandler); cmbdomainStrategy.ItemsSource = Global.DomainStrategies; - cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox; + cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; this.WhenActivated(disposables => { diff --git a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml index 7deb7c25..0a79ed8f 100644 --- a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml +++ b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml @@ -133,31 +133,15 @@ Text="{x:Static resx:ResUI.TbBootstrapDNSTips}" TextWrapping="Wrap" /> - - - + Text="{x:Static resx:ResUI.TbDirectResolveStrategy}" /> + Text="{x:Static resx:ResUI.TbRemoteResolveStrategy}" /> + Text="{x:Static resx:ResUI.TbParallelQuery}" /> + + + @@ -207,6 +205,7 @@ + @@ -245,15 +244,29 @@ Margin="{StaticResource Margin8}" VerticalAlignment="Center" Style="{StaticResource ToolbarTextBlock}" - Text="{x:Static resx:ResUI.TbFakeIP}" /> + Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" /> + + + vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => 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); diff --git a/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs index fd0cee6e..e736fb6b 100644 --- a/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs @@ -18,7 +18,7 @@ public partial class RoutingRuleSettingWindow ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler); cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty(); - cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox; + cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; this.WhenActivated(disposables => { diff --git a/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs index 98ccdc19..a9a781a4 100644 --- a/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs @@ -17,7 +17,7 @@ public partial class RoutingSettingWindow ViewModel = new RoutingSettingViewModel(UpdateViewHandler); cmbdomainStrategy.ItemsSource = Global.DomainStrategies; - cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox; + cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; this.WhenActivated(disposables => {