From dff67e9d7811bd81bcd14ff7ab85adb3260effa3 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Thu, 10 Jul 2025 21:42:53 +0800 Subject: [PATCH] Simplify DNS Settings --- v2rayN/ServiceLib/Global.cs | 52 ++- v2rayN/ServiceLib/Handler/AppHandler.cs | 10 - v2rayN/ServiceLib/Handler/ConfigHandler.cs | 116 +---- v2rayN/ServiceLib/Models/Config.cs | 1 + v2rayN/ServiceLib/Models/ConfigItems.cs | 17 + v2rayN/ServiceLib/Models/DNSItem.cs | 19 - v2rayN/ServiceLib/Models/SingboxConfig.cs | 11 +- v2rayN/ServiceLib/Models/V2rayConfig.cs | 5 +- v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 164 +++++++- v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 54 +++ v2rayN/ServiceLib/Resx/ResUI.hu.resx | 54 +++ v2rayN/ServiceLib/Resx/ResUI.resx | 54 +++ v2rayN/ServiceLib/Resx/ResUI.ru.resx | 114 +++-- v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 54 +++ v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 54 +++ .../CoreConfig/CoreConfigSingboxService.cs | 395 ++++++++++-------- .../CoreConfig/CoreConfigV2rayService.cs | 278 ++++++++---- .../ViewModels/DNSSettingViewModel.cs | 138 +++--- .../ViewModels/MainWindowViewModel.cs | 1 - .../Views/DNSSettingWindow.axaml | 321 ++++++++------ .../Views/DNSSettingWindow.axaml.cs | 32 +- v2rayN/v2rayN/Views/DNSSettingWindow.xaml | 368 ++++++++++------ v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs | 32 +- 23 files changed, 1532 insertions(+), 812 deletions(-) delete mode 100644 v2rayN/ServiceLib/Models/DNSItem.cs diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 4948f111..a667a335 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -349,25 +349,42 @@ public class Global public static readonly List SingboxDomainStrategy4Out = [ - "ipv4_only", + "", + "ipv4_only", "prefer_ipv4", "prefer_ipv6", - "ipv6_only", - "" + "ipv6_only" ]; - public static readonly List DomainDNSAddress = + public static readonly List DomainDirectDNSAddress = [ - "223.5.5.5", - "223.6.6.6", + "https://dns.alidns.com/dns-query", + "https://doh.pub/dns-query", + "223.5.5.5", + "119.29.29.29", "localhost" ]; - public static readonly List SingboxDomainDNSAddress = + public static readonly List DomainRemoteDNSAddress = + [ + "https://cloudflare-dns.com/dns-query", + "https://dns.cloudflare.com/dns-query", + "https://dns.google/dns-query", + "https://doh.dns.sb/dns-query", + "https://doh.opendns.com/dns-query", + "https://common.dot.dns.yandex.net", + "8.8.8.8", + "1.1.1.1", + "185.222.222.222", + "208.67.222.222", + "77.88.8.8" + ]; + + public static readonly List DomainPureIPDNSAddress = [ "223.5.5.5", - "223.6.6.6", - "dhcp://auto" + "119.29.29.29", + "localhost" ]; public static readonly List Languages = @@ -537,5 +554,22 @@ public class Global BlockTag ]; + public static readonly Dictionary> PredefinedHosts = new() + { + { "dns.google", new List { "8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844" } }, + { "dns.alidns.com", new List { "223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1" } }, + { "one.one.one.one", new List { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } }, + { "1dot1dot1dot1.cloudflare-dns.com", new List { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } }, + { "cloudflare-dns.com", new List { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } }, + { "dns.cloudflare.com", new List { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } }, + { "dot.pub", new List { "1.12.12.12", "120.53.53.53" } }, + { "dns.quad9.net", new List { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } }, + { "dns.yandex.net", new List { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } }, + { "dns.sb", new List { "185.222.222.222", "2a09::" } }, + { "dns.umbrella.com", new List { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } }, + { "dns.sse.cisco.com", new List { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } }, + { "engage.cloudflareclient.com", new List { "162.159.192.1", "2606:4700:d0::a29f:c001" } } + }; + #endregion const } diff --git a/v2rayN/ServiceLib/Handler/AppHandler.cs b/v2rayN/ServiceLib/Handler/AppHandler.cs index ad9a4029..496173f3 100644 --- a/v2rayN/ServiceLib/Handler/AppHandler.cs +++ b/v2rayN/ServiceLib/Handler/AppHandler.cs @@ -193,16 +193,6 @@ public sealed class AppHandler return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Id == id); } - public async Task?> DNSItems() - { - return await SQLiteHelper.Instance.TableAsync().ToListAsync(); - } - - public async Task GetDNSItem(ECoreType eCoreType) - { - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); - } - #endregion SqliteHelper #region Core Type diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 6005e0c6..3667d7d2 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -112,6 +112,18 @@ public class ConfigHandler config.ConstItem ??= new ConstItem(); + config.DNSItem ??= new DNSItem() + { + UseSystemHosts = false, + AddCommonHosts = true, + FakeIP = false, + BlockBindingQuery = true, + DirectDNS = Global.DomainDirectDNSAddress.FirstOrDefault(), + RemoteDNS = Global.DomainRemoteDNSAddress.FirstOrDefault(), + SingboxOutboundsResolveDNS = Global.DomainDirectDNSAddress.FirstOrDefault(), + SingboxFinalResolveDNS = Global.DomainPureIPDNSAddress.FirstOrDefault() + }; + config.SpeedTestItem ??= new(); if (config.SpeedTestItem.SpeedTestTimeout < 10) { @@ -2088,101 +2100,6 @@ public class ConfigHandler #endregion Routing - #region DNS - - /// - /// Initialize built-in DNS configurations - /// Creates default DNS items for V2Ray and sing-box - /// - /// Current configuration - /// 0 if successful - public static async Task InitBuiltinDNS(Config config) - { - var items = await AppHandler.Instance.DNSItems(); - if (items.Count <= 0) - { - var item = new DNSItem() - { - Remarks = "V2ray", - CoreType = ECoreType.Xray, - }; - await SaveDNSItems(config, item); - - var item2 = new DNSItem() - { - Remarks = "sing-box", - CoreType = ECoreType.sing_box, - }; - await SaveDNSItems(config, item2); - } - - return 0; - } - - /// - /// Save a DNS item to the database - /// - /// Current configuration - /// DNS item to save - /// 0 if successful, -1 if failed - public static async Task SaveDNSItems(Config config, DNSItem item) - { - if (item == null) - { - return -1; - } - - if (item.Id.IsNullOrEmpty()) - { - item.Id = Utils.GetGuid(false); - } - - if (await SQLiteHelper.Instance.ReplaceAsync(item) > 0) - { - return 0; - } - else - { - return -1; - } - } - - /// - /// Get an external DNS configuration from URL - /// Downloads and processes DNS templates - /// - /// Core type (Xray or sing-box) - /// URL of the DNS template - /// DNS item with configuration from the URL - public static async Task GetExternalDNSItem(ECoreType type, string url) - { - var currentItem = await AppHandler.Instance.GetDNSItem(type); - - var downloadHandle = new DownloadService(); - var templateContent = await downloadHandle.TryDownloadString(url, true, ""); - if (templateContent.IsNullOrEmpty()) - return currentItem; - - var template = JsonUtils.Deserialize(templateContent); - if (template == null) - return currentItem; - - if (!template.NormalDNS.IsNullOrEmpty()) - template.NormalDNS = await downloadHandle.TryDownloadString(template.NormalDNS, true, ""); - - if (!template.TunDNS.IsNullOrEmpty()) - template.TunDNS = await downloadHandle.TryDownloadString(template.TunDNS, true, ""); - - template.Id = currentItem.Id; - template.Enabled = currentItem.Enabled; - template.Remarks = currentItem.Remarks; - template.CoreType = type; - - return template; - } - - #endregion DNS - #region Regional Presets /// @@ -2202,7 +2119,6 @@ public class ConfigHandler config.ConstItem.RouteRulesTemplateSourceUrl = ""; await SQLiteHelper.Instance.DeleteAllAsync(); - await InitBuiltinDNS(config); return true; @@ -2211,8 +2127,8 @@ public class ConfigHandler config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[1]; config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[1]; - await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json")); - await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json")); + //await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json")); + //await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json")); return true; @@ -2221,8 +2137,8 @@ public class ConfigHandler config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2]; config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[2]; - await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json")); - await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json")); + //await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json")); + //await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json")); return true; } diff --git a/v2rayN/ServiceLib/Models/Config.cs b/v2rayN/ServiceLib/Models/Config.cs index 15996608..ca032c2e 100644 --- a/v2rayN/ServiceLib/Models/Config.cs +++ b/v2rayN/ServiceLib/Models/Config.cs @@ -48,6 +48,7 @@ public class Config public List Inbound { get; set; } public List GlobalHotkeys { get; set; } public List CoreTypeItem { get; set; } + public DNSItem DNSItem { get; set; } #endregion other entities } diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs index c6254b9f..8847782b 100644 --- a/v2rayN/ServiceLib/Models/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/ConfigItems.cs @@ -253,3 +253,20 @@ public class WindowSizeItem public int Width { get; set; } public int Height { get; set; } } + +[Serializable] +public class DNSItem +{ + public bool? UseSystemHosts { get; set; } + public bool? AddCommonHosts { get; set; } + public bool? FakeIP { get; set; } + public bool? BlockBindingQuery { get; set; } + public string? DirectDNS { get; set; } + public string? RemoteDNS { get; set; } + public string? SingboxOutboundsResolveDNS { get; set; } + public string? SingboxFinalResolveDNS { get; set; } + public string? RayStrategy4Freedom { get; set; } + public string? SingboxStrategy4Direct { get; set; } + public string? SingboxStrategy4Proxy { get; set; } + public string? Hosts { get; set; } +} diff --git a/v2rayN/ServiceLib/Models/DNSItem.cs b/v2rayN/ServiceLib/Models/DNSItem.cs deleted file mode 100644 index 59ab9c9b..00000000 --- a/v2rayN/ServiceLib/Models/DNSItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using SQLite; - -namespace ServiceLib.Models; - -[Serializable] -public class DNSItem -{ - [PrimaryKey] - public string Id { get; set; } - - public string Remarks { get; set; } - public bool Enabled { get; set; } = true; - public ECoreType CoreType { get; set; } - public bool UseSystemHosts { get; set; } - public string? NormalDNS { get; set; } - public string? TunDNS { get; set; } - public string? DomainStrategy4Freedom { get; set; } - public string? DomainDNSAddress { get; set; } -} diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index c63acc4a..5fd91408 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -36,6 +36,7 @@ public class Dns4Sbox public class Route4Sbox { + public Rule4Sbox? default_domain_resolver { get; set; } // or string public bool? auto_detect_interface { get; set; } public List rules { get; set; } public List? rule_set { get; set; } @@ -75,7 +76,7 @@ public class Rule4Sbox public string? strategy { get; set; } public List? sniffer { get; set; } public string? rcode { get; set; } - public List? query_type { get; set; } + public List? query_type { get; set; } public List? answer { get; set; } public List? ns { get; set; } public List? extra { get; set; } @@ -237,13 +238,7 @@ public class Server4Sbox : BaseServer4Sbox public string? path { get; set; } public Headers4Sbox? headers { get; set; } // public List? path { get; set; } // hosts - public Dictionary? predefined { get; set; } - // Deprecated - public string? address { get; set; } - public string? address_resolver { get; set; } - public string? address_strategy { get; set; } - public string? strategy { get; set; } - // Deprecated End + public Dictionary>? predefined { get; set; } } public class Experimental4Sbox diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index 2e5ed4b4..a18c7e34 100644 --- a/v2rayN/ServiceLib/Models/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs @@ -5,7 +5,7 @@ namespace ServiceLib.Models; public class V2rayConfig { public Log4Ray log { get; set; } - public object dns { get; set; } + public Dns4Ray dns { get; set; } public List inbounds { get; set; } public List outbounds { get; set; } public Routing4Ray routing { get; set; } @@ -203,7 +203,8 @@ public class Response4Ray public class Dns4Ray { - public List servers { get; set; } + public Dictionary>? hosts { get; set; } + public List servers { get; set; } } public class DnsServer4Ray diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index b7d28383..589ff0a5 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 @@ -2211,6 +2211,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Add Common DNS Hosts 的本地化字符串。 + /// + public static string TbAddCommonDNSHosts { + get { + return ResourceManager.GetString("TbAddCommonDNSHosts", resourceCulture); + } + } + /// /// 查找类似 Address 的本地化字符串。 /// @@ -2247,6 +2256,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Apply to Proxy Domains Only 的本地化字符串。 + /// + public static string TbApplyProxyDomainsOnly { + get { + return ResourceManager.GetString("TbApplyProxyDomainsOnly", resourceCulture); + } + } + /// /// 查找类似 Auto refresh 的本地化字符串。 /// @@ -2274,6 +2292,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Block SVCB and HTTPS Queries 的本地化字符串。 + /// + public static string TbBlockSVCBHTTPSQueries { + get { + return ResourceManager.GetString("TbBlockSVCBHTTPSQueries", resourceCulture); + } + } + /// /// 查找类似 Browse 的本地化字符串。 /// @@ -2346,6 +2373,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 DNS Hosts: ("domain1 ip1 ip2" per line) 的本地化字符串。 + /// + public static string TbDNSHostsConfig { + get { + return ResourceManager.GetString("TbDNSHostsConfig", resourceCulture); + } + } + /// /// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。 /// @@ -2391,6 +2427,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Domestic DNS 的本地化字符串。 + /// + public static string TbDomesticDNS { + get { + return ResourceManager.GetString("TbDomesticDNS", resourceCulture); + } + } + /// /// 查找类似 Edit 的本地化字符串。 /// @@ -2409,6 +2454,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 FakeIP 的本地化字符串。 + /// + public static string TbFakeIP { + get { + return ResourceManager.GetString("TbFakeIP", resourceCulture); + } + } + /// /// 查找类似 Fingerprint 的本地化字符串。 /// @@ -2598,6 +2652,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Prevent DNS Leaks 的本地化字符串。 + /// + public static string TbPreventDNSLeaks { + get { + return ResourceManager.GetString("TbPreventDNSLeaks", resourceCulture); + } + } + /// /// 查找类似 Private Key 的本地化字符串。 /// @@ -2634,6 +2697,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Remote DNS 的本地化字符串。 + /// + public static string TbRemoteDNS { + get { + return ResourceManager.GetString("TbRemoteDNS", resourceCulture); + } + } + /// /// 查找类似 Camouflage domain(host) 的本地化字符串。 /// @@ -2742,6 +2814,69 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。 + /// + public static string TbSBDirectResolveStrategy { + get { + return ResourceManager.GetString("TbSBDirectResolveStrategy", resourceCulture); + } + } + + /// + /// 查找类似 Enable to Override sing-box DoH Resolver 的本地化字符串。 + /// + public static string TbSBDoHOverride { + get { + return ResourceManager.GetString("TbSBDoHOverride", resourceCulture); + } + } + + /// + /// 查找类似 sing-box DoH Resolver Server 的本地化字符串。 + /// + public static string TbSBDoHResolverServer { + get { + return ResourceManager.GetString("TbSBDoHResolverServer", resourceCulture); + } + } + + /// + /// 查找类似 Fallback DNS Resolution, Suggest IP 的本地化字符串。 + /// + public static string TbSBFallbackDNSResolve { + get { + return ResourceManager.GetString("TbSBFallbackDNSResolve", resourceCulture); + } + } + + /// + /// 查找类似 Resolve Outbound Domains 的本地化字符串。 + /// + public static string TbSBOutboundDomainResolve { + get { + return ResourceManager.GetString("TbSBOutboundDomainResolve", resourceCulture); + } + } + + /// + /// 查找类似 Outbound DNS Resolution (sing-box) 的本地化字符串。 + /// + public static string TbSBOutboundsResolverDNS { + get { + return ResourceManager.GetString("TbSBOutboundsResolverDNS", resourceCulture); + } + } + + /// + /// 查找类似 sing-box Remote Resolution Strategy 的本地化字符串。 + /// + public static string TbSBRemoteResolveStrategy { + get { + return ResourceManager.GetString("TbSBRemoteResolveStrategy", resourceCulture); + } + } + /// /// 查找类似 Encryption method (security) 的本地化字符串。 /// @@ -3687,6 +3822,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 xray Freedom Resolution Strategy 的本地化字符串。 + /// + public static string TbXrayFreedomResolveStrategy { + get { + return ResourceManager.GetString("TbXrayFreedomResolveStrategy", resourceCulture); + } + } + /// /// 查找类似 The delay: {0} ms, {1} 的本地化字符串。 /// @@ -3696,6 +3840,24 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Advanced DNS Settings 的本地化字符串。 + /// + public static string ThAdvancedDNSSettings { + get { + return ResourceManager.GetString("ThAdvancedDNSSettings", resourceCulture); + } + } + + /// + /// 查找类似 Basic DNS Settings 的本地化字符串。 + /// + public static string ThBasicDNSSettings { + get { + return ResourceManager.GetString("ThBasicDNSSettings", resourceCulture); + } + } + /// /// 查找类似 Active 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index d336da09..6ebf5697 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1398,4 +1398,58 @@ Add [Anytls] Configuration + + Remote DNS + + + Domestic DNS + + + Outbound DNS Resolution (sing-box) + + + Resolve Outbound Domains + + + sing-box DoH Resolver Server + + + Fallback DNS Resolution, Suggest IP + + + xray Freedom Resolution Strategy + + + sing-box Direct Resolution Strategy + + + sing-box Remote Resolution Strategy + + + Add Common DNS Hosts + + + Enable to Override sing-box DoH Resolver + + + FakeIP + + + Block SVCB and HTTPS Queries + + + Prevent DNS Leaks + + + DNS Hosts: ("domain1 ip1 ip2" per line) + + + Apply to Proxy Domains Only + + + Basic DNS Settings + + + Advanced DNS Settings + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index 48abd20c..44504ffd 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1398,4 +1398,58 @@ Add [Anytls] Configuration + + Remote DNS + + + Domestic DNS + + + Outbound DNS Resolution (sing-box) + + + Resolve Outbound Domains + + + sing-box DoH Resolver Server + + + Fallback DNS Resolution, Suggest IP + + + xray Freedom Resolution Strategy + + + sing-box Direct Resolution Strategy + + + sing-box Remote Resolution Strategy + + + Add Common DNS Hosts + + + Enable to Override sing-box DoH Resolver + + + FakeIP + + + Block SVCB and HTTPS Queries + + + Prevent DNS Leaks + + + DNS Hosts: ("domain1 ip1 ip2" per line) + + + Apply to Proxy Domains Only + + + Basic DNS Settings + + + Advanced DNS Settings + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 151e0998..54a24060 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1398,4 +1398,58 @@ Add [Anytls] Configuration + + Remote DNS + + + Domestic DNS + + + Outbound DNS Resolution (sing-box) + + + Resolve Outbound Domains + + + sing-box DoH Resolver Server + + + Fallback DNS Resolution, Suggest IP + + + xray Freedom Resolution Strategy + + + sing-box Direct Resolution Strategy + + + sing-box Remote Resolution Strategy + + + Add Common DNS Hosts + + + Enable to Override sing-box DoH Resolver + + + FakeIP + + + Block SVCB and HTTPS Queries + + + Prevent DNS Leaks + + + DNS Hosts: ("domain1 ip1 ip2" per line) + + + Apply to Proxy Domains Only + + + Basic DNS Settings + + + Advanced DNS Settings + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index a0ccb5b3..1eb7ed28 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1,17 +1,17 @@ - @@ -807,9 +807,6 @@ Вверх (U) - - Переместить вверх/вниз - Фильтр, поддерживает regex @@ -969,6 +966,9 @@ URL для тестирования скорости + + Переместить вверх/вниз + PublicKey @@ -1398,4 +1398,58 @@ Add [Anytls] Configuration + + Remote DNS + + + Domestic DNS + + + Outbound DNS Resolution (sing-box) + + + Resolve Outbound Domains + + + sing-box DoH Resolver Server + + + Fallback DNS Resolution, Suggest IP + + + xray Freedom Resolution Strategy + + + sing-box Direct Resolution Strategy + + + sing-box Remote Resolution Strategy + + + Add Common DNS Hosts + + + Enable to Override sing-box DoH Resolver + + + FakeIP + + + Block SVCB and HTTPS Queries + + + Prevent DNS Leaks + + + DNS Hosts: ("domain1 ip1 ip2" per line) + + + Apply to Proxy Domains Only + + + Basic DNS Settings + + + Advanced DNS Settings + \ 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 4d33a507..04d0b16f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1395,4 +1395,58 @@ 添加 [Anytls] 配置文件 + + 远程 DNS + + + 直连 DNS + + + 出站 DNS 解析 + + + 解析出站域名 + + + sing-box DoH 解析服务器 + + + 兜底解析其他 DNS 域名,建议设为 ip + + + xray freedom 解析策略 + + + sing-box 直连解析策略 + + + sing-box 远程解析策略 + + + 添加常用 DNS Hosts + + + 开启后可覆盖 sing-box DoH 解析服务器 + + + FakeIP + + + 阻止 SVCB 和 HTTPS 查询 + + + 避免 DNS 泄漏 + + + DNS Hosts:(“域名1 ip1 ip2” 一行一个) + + + 仅对代理域名生效 + + + DNS 基础设置 + + + DNS 进阶设置 + \ 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 1b7a647c..5a9e9a02 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1395,4 +1395,58 @@ 新增 [Anytls] 設定檔 + + Remote DNS + + + Domestic DNS + + + Outbound DNS Resolution (sing-box) + + + Resolve Outbound Domains + + + sing-box DoH Resolver Server + + + Fallback DNS Resolution, Suggest IP + + + xray Freedom Resolution Strategy + + + sing-box Direct Resolution Strategy + + + sing-box Remote Resolution Strategy + + + Add Common DNS Hosts + + + Enable to Override sing-box DoH Resolver + + + FakeIP + + + Block SVCB and HTTPS Queries + + + Prevent DNS Leaks + + + DNS Hosts: ("domain1 ip1 ip2" per line) + + + Apply to Proxy Domains Only + + + Basic DNS Settings + + + Advanced DNS Settings + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index d03288b6..7f29ce5d 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1,7 +1,9 @@ +using System.Collections.Generic; using System.Data; using System.Net; using System.Net.NetworkInformation; using System.Reactive; +using System.Text; using DynamicData; using ServiceLib.Models; @@ -73,7 +75,7 @@ public class CoreConfigSingboxService await GenRouting(singboxConfig); - await GenDns(node, singboxConfig); + await GenDns(singboxConfig); await GenExperimental(singboxConfig); @@ -243,7 +245,7 @@ public class CoreConfigSingboxService singboxConfig.route.rules.Add(rule); } - await GenDnsDomains(null, singboxConfig, null); + await GenDns(singboxConfig); //var dnsServer = singboxConfig.dns?.servers.FirstOrDefault(); //if (dnsServer != null) //{ @@ -315,7 +317,7 @@ public class CoreConfigSingboxService await GenOutbound(node, singboxConfig.outbounds.First()); } await GenMoreOutbounds(node, singboxConfig); - await GenDnsDomains(null, singboxConfig, null); + await GenDns(singboxConfig); singboxConfig.route.rules.Clear(); singboxConfig.inbounds.Clear(); @@ -417,7 +419,7 @@ public class CoreConfigSingboxService } await GenOutboundsList(proxyProfiles, singboxConfig); - await GenDns(null, singboxConfig); + await GenDns(singboxConfig); await ConvertGeo2Ruleset(singboxConfig); ret.Success = true; @@ -648,17 +650,6 @@ public class CoreConfigSingboxService outbound.server_port = node.Port; outbound.type = Global.ProtocolTypes[node.ConfigType]; - if (Utils.IsDomain(node.Address)) - { - var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); - var localDnsAddress = string.IsNullOrEmpty(item?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : item?.DomainDNSAddress; - outbound.domain_resolver = new() - { - server = localDnsAddress.StartsWith("tag://") ? localDnsAddress.Substring(6) : "local_resolver", - strategy = string.IsNullOrEmpty(item?.DomainStrategy4Freedom) ? null : item?.DomainStrategy4Freedom - }; - } - switch (node.ConfigType) { case EConfigType.VMess: @@ -788,17 +779,6 @@ public class CoreConfigSingboxService endpoint.address = Utils.String2List(node.RequestHost); endpoint.type = Global.ProtocolTypes[node.ConfigType]; - if (Utils.IsDomain(node.Address)) - { - var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); - var localDnsAddress = string.IsNullOrEmpty(item?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : item?.DomainDNSAddress; - endpoint.domain_resolver = new() - { - server = localDnsAddress.StartsWith("tag://") ? localDnsAddress.Substring(6) : "local_resolver", - strategy = string.IsNullOrEmpty(item?.DomainStrategy4Freedom) ? null : item?.DomainStrategy4Freedom - }; - } - switch (node.ConfigType) { case EConfigType.WireGuard: @@ -1245,6 +1225,13 @@ public class CoreConfigSingboxService try { singboxConfig.route.final = Global.ProxyTag; + var item = _config.DNSItem; + singboxConfig.route.default_domain_resolver = new() + { + server = "outbound_resolver", + strategy = item.SingboxStrategy4Direct + } + ; if (_config.TunModeItem.EnableTun) { @@ -1325,14 +1312,14 @@ public class CoreConfigSingboxService if (routing != null) { var rules = JsonUtils.Deserialize>(routing.RuleSet); - foreach (var item in rules ?? []) + foreach (var item1 in rules ?? []) { - if (item.Enabled) + if (item1.Enabled) { - await GenRoutingUserRule(item, singboxConfig); - if (item.Ip != null && item.Ip.Count > 0) + await GenRoutingUserRule(item1, singboxConfig); + if (item1.Ip != null && item1.Ip.Count > 0) { - ipRules.Add(item); + ipRules.Add(item1); } } } @@ -1340,9 +1327,9 @@ public class CoreConfigSingboxService if (_config.RoutingBasicItem.DomainStrategy == "IPIfNonMatch") { singboxConfig.route.rules.Add(resolveRule); - foreach (var item in ipRules) + foreach (var item2 in ipRules) { - await GenRoutingUserRule(item, singboxConfig); + await GenRoutingUserRule(item2, singboxConfig); } } } @@ -1585,36 +1572,17 @@ public class CoreConfigSingboxService return server.tag; } - private async Task GenDns(ProfileItem? node, SingboxConfig singboxConfig) + private async Task GenDns(SingboxConfig singboxConfig) { try { - var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); - var strDNS = string.Empty; - if (_config.TunModeItem.EnableTun) - { - strDNS = string.IsNullOrEmpty(item?.TunDNS) ? EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName) : item?.TunDNS; - } - else - { - strDNS = string.IsNullOrEmpty(item?.NormalDNS) ? EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName) : item?.NormalDNS; - } + var dNSItem = _config.DNSItem; + await GenDnsServers(singboxConfig, dNSItem); + await GenDnsRules(singboxConfig, dNSItem); - var dns4Sbox = JsonUtils.Deserialize(strDNS); - if (dns4Sbox is null) - { - return 0; - } - singboxConfig.dns = dns4Sbox; - - if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty()) - { - await GenDnsDomains(node, singboxConfig, item); - } - else - { - await GenDnsDomainsLegacy(node, singboxConfig, item); - } + singboxConfig.dns ??= new Dns4Sbox(); + singboxConfig.dns.independent_cache = true; + singboxConfig.dns.final = "dns_remote"; // TODO } catch (Exception ex) { @@ -1623,211 +1591,280 @@ public class CoreConfigSingboxService return 0; } - private async Task GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem) + private async Task GenDnsServers(SingboxConfig singboxConfig, DNSItem dNSItem) { - var dns4Sbox = singboxConfig.dns ?? new(); - dns4Sbox.servers ??= []; - dns4Sbox.rules ??= []; + var finalDns = ParseDnsAddress(dNSItem.SingboxFinalResolveDNS); + finalDns.tag = "final_resolver"; - var tag = "local_resolver"; - var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress; + var directDns = ParseDnsAddress(dNSItem.DirectDNS); + directDns.tag = "dns_direct"; + directDns.domain_resolver = "final_resolver"; - if (localDnsAddress.StartsWith("tag://")) + var remoteDns = ParseDnsAddress(dNSItem.RemoteDNS); + remoteDns.tag = "dns_remote"; + remoteDns.detour = Global.ProxyTag; + remoteDns.domain_resolver = "final_resolver"; + + var resolverDns = ParseDnsAddress(dNSItem.SingboxOutboundsResolveDNS); + resolverDns.tag = "outbound_resolver"; + resolverDns.domain_resolver = "final_resolver"; + + var hostsDns = new Server4Sbox { - tag = localDnsAddress.Substring(6); - - var localDnsTag = "local_local"; - - dns4Sbox.servers.Add(new() - { - tag = localDnsTag, - type = "local" - }); - - dns4Sbox.rules.Insert(0, new() - { - server = localDnsTag, - clash_mode = ERuleMode.Direct.ToString() - }); + tag = "dns_hosts", + type = "hosts", + }; + if (dNSItem.AddCommonHosts == true) + { + hostsDns.predefined = Global.PredefinedHosts; } - else + var userHostsMap = dNSItem.Hosts? + .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Where(line => line.Contains(' ')) + .ToDictionary( + line => + { + var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + return parts[0]; + }, + line => + { + var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + var values = parts.Skip(1).ToList(); + return values; + } + ); + + if (userHostsMap != null) { - var (dnsType, dnsHost, dnsPort, dnsPath) = ParseDnsAddress(localDnsAddress); - - dns4Sbox.servers.Add(new() + foreach (var kvp in userHostsMap) { - tag = tag, - type = dnsType, - server = dnsHost, - Interface = dnsType == "dhcp" ? dnsHost : null, - server_port = dnsPort, - path = dnsPath - }); - - dns4Sbox.rules.Insert(0, new() - { - server = tag, - clash_mode = ERuleMode.Direct.ToString() - }); + hostsDns.predefined[kvp.Key] = kvp.Value; + } } - dns4Sbox.rules.Insert(0, new() + foreach (var host in hostsDns.predefined) { - server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote", - clash_mode = ERuleMode.Global.ToString() - }); - - //Tun2SocksAddress - if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni)) - { - dns4Sbox.rules.Insert(0, new() + if (finalDns.server == host.Key) { - server = tag, - domain = [node?.Sni], - strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom - }); + finalDns.domain_resolver = "dns_hosts"; + } + if (remoteDns.server == host.Key) + { + remoteDns.domain_resolver = "dns_hosts"; + } + if (resolverDns.server == host.Key) + { + resolverDns.domain_resolver = "dns_hosts"; + } + if (directDns.server == host.Key) + { + directDns.domain_resolver = "dns_hosts"; + } + } + + singboxConfig.dns ??= new Dns4Sbox(); + singboxConfig.dns.servers ??= new List(); + singboxConfig.dns.servers.Add(remoteDns); + singboxConfig.dns.servers.Add(directDns); + singboxConfig.dns.servers.Add(finalDns); + singboxConfig.dns.servers.Add(resolverDns); + singboxConfig.dns.servers.Add(hostsDns); + + // fake ip + if (dNSItem.FakeIP == true) + { + var fakeip = new Server4Sbox + { + tag = "dns-fake", + type = "fakeip", + inet4_range = "198.18.0.0/15", + inet6_range = "fc00::/18", + }; + singboxConfig.dns.servers.Add(fakeip); } - singboxConfig.dns = dns4Sbox; return await Task.FromResult(0); } - private async Task GenDnsDomainsLegacy(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem) + private async Task GenDnsRules(SingboxConfig singboxConfig, DNSItem dNSItem) { - var dns4Sbox = singboxConfig.dns ?? new(); - dns4Sbox.servers ??= []; - dns4Sbox.rules ??= []; - - var tag = "local_local"; - dns4Sbox.servers.Add(new() + singboxConfig.dns ??= new Dns4Sbox(); + singboxConfig.dns.rules ??= new List(); + // hosts + singboxConfig.dns.rules.Add(new Rule4Sbox { - tag = tag, - address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, - detour = Global.DirectTag, - strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom, + ip_accept_any = true, + server = "dns_hosts", }); - dns4Sbox.rules.Insert(0, new() + // clash mode + singboxConfig.dns.rules.Add(new Rule4Sbox { - server = tag, + server = "dns_remote", + strategy = dNSItem.SingboxStrategy4Proxy.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Proxy, + clash_mode = ERuleMode.Global.ToString() + }); + singboxConfig.dns.rules.Add(new Rule4Sbox + { + server = "dns_direct", + strategy = dNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Direct, clash_mode = ERuleMode.Direct.ToString() }); - dns4Sbox.rules.Insert(0, new() + // block binding query + singboxConfig.dns.rules.Add(new Rule4Sbox { - server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote", - clash_mode = ERuleMode.Global.ToString() + query_type = new List { 64, 65 }, + action = "predefined", + rcode = "NOTIMP" }); - var lstDomain = singboxConfig.outbounds - .Where(t => t.server.IsNotEmpty() && Utils.IsDomain(t.server)) - .Select(t => t.server) - .Distinct() - .ToList(); - if (lstDomain != null && lstDomain.Count > 0) + var routing = await ConfigHandler.GetDefaultRouting(_config); + if (routing != null) { - dns4Sbox.rules.Insert(0, new() + var rules = JsonUtils.Deserialize>(routing.RuleSet); + foreach (var item in rules ?? []) { - server = tag, - domain = lstDomain - }); + if (!item.Enabled) + { + continue; + } + if (item.Domain == null || item.Domain.Count == 0) + { + continue; + } + var rule = new Rule4Sbox(); + + var countDomain = 0; + foreach (var it in item.Domain) + { + if (ParseV2Domain(it, rule)) + { + countDomain++; + } + } + if (countDomain <= 0) + { + continue; + } + if (item.OutboundTag == Global.DirectTag) + { + rule.server = "dns_direct"; + rule.strategy = dNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Direct; + } + else if (item.OutboundTag == Global.ProxyTag) + { + if (dNSItem.FakeIP == true) + { + var rule4Fake = JsonUtils.DeepCopy(rule); + rule4Fake.server = "dns-fake"; + singboxConfig.dns.rules.Add(rule4Fake); + } + rule.server = "dns_remote"; + rule.strategy = dNSItem.SingboxStrategy4Proxy.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Proxy; + } + else if (item.OutboundTag == Global.BlockTag) + { + rule.action = "predefined"; + rule.rcode = "NOERROR"; + rule.answer = new List { "A" }; + } + singboxConfig.dns.rules.Add(rule); + } } - //Tun2SocksAddress - if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni)) - { - dns4Sbox.rules.Insert(0, new() - { - server = tag, - domain = [node?.Sni] - }); - } - - singboxConfig.dns = dns4Sbox; return await Task.FromResult(0); } - private (string type, string? host, int? port, string? path) ParseDnsAddress(string address) + private static Server4Sbox? ParseDnsAddress(string address) { - string type = "udp"; - string? host = null; - int? port = null; - string? path = null; + if (string.IsNullOrEmpty(address)) + { + return null; + } + + var server = new Server4Sbox(); if (address is "local" or "localhost") { - return ("local", null, null, null); + server.type = "local"; + return server; } if (address.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase)) { - string interface_name = address.Substring(7); - return ("dhcp", interface_name == "auto" ? null : interface_name, null, null); + var interface_name = address.Substring(7); + server.type = "dhcp"; + server.Interface = interface_name == "auto" ? null : interface_name; + return server; } if (!address.Contains("://")) { // udp dns - host = address; - return (type, host, port, path); + server.type = "udp"; + server.server = address; + return server; } try { - int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal); - type = address.Substring(0, protocolEndIndex).ToLower(); + var protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal); + server.type = address.Substring(0, protocolEndIndex).ToLower(); var uri = new Uri(address); - host = uri.Host; + server.server = uri.Host; if (!uri.IsDefaultPort) { - port = uri.Port; + server.server_port = uri.Port; } - if ((type == "https" || type == "h3") && !string.IsNullOrEmpty(uri.AbsolutePath) && uri.AbsolutePath != "/") + if ((server.type == "https" || server.type == "h3") && !string.IsNullOrEmpty(uri.AbsolutePath) && uri.AbsolutePath != "/") { - path = uri.AbsolutePath; + server.path = uri.AbsolutePath; } } catch (UriFormatException) { - int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal); + var protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal); if (protocolEndIndex > 0) { - type = address.Substring(0, protocolEndIndex).ToLower(); - string remaining = address.Substring(protocolEndIndex + 3); + server.type = address.Substring(0, protocolEndIndex).ToLower(); + var remaining = address.Substring(protocolEndIndex + 3); - int portIndex = remaining.IndexOf(':'); - int pathIndex = remaining.IndexOf('/'); + var portIndex = remaining.IndexOf(':'); + var pathIndex = remaining.IndexOf('/'); if (portIndex > 0) { - host = remaining.Substring(0, portIndex); - string portPart = pathIndex > portIndex + server.server = remaining.Substring(0, portIndex); + var portPart = pathIndex > portIndex ? remaining.Substring(portIndex + 1, pathIndex - portIndex - 1) : remaining.Substring(portIndex + 1); - if (int.TryParse(portPart, out int parsedPort)) + if (int.TryParse(portPart, out var parsedPort)) { - port = parsedPort; + server.server_port = parsedPort; } } else if (pathIndex > 0) { - host = remaining.Substring(0, pathIndex); + server.server = remaining.Substring(0, pathIndex); } else { - host = remaining; + server.server = remaining; } - if (pathIndex > 0 && (type == "https" || type == "h3")) + if (pathIndex > 0 && (server.type == "https" || server.type == "h3")) { - path = remaining.Substring(pathIndex); + server.path = remaining.Substring(pathIndex); } } } - return (type, host, port, path); + return server; } private async Task GenExperimental(SingboxConfig singboxConfig) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index d4db6d8e..9f3c2b65 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -1135,13 +1135,8 @@ public class CoreConfigV2rayService { try { - var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray); - var normalDNS = item?.NormalDNS; - var domainStrategy4Freedom = item?.DomainStrategy4Freedom; - if (normalDNS.IsNullOrEmpty()) - { - normalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName); - } + var dNSItem = _config.DNSItem; + var domainStrategy4Freedom = dNSItem?.RayStrategy4Freedom; //Outbound Freedom domainStrategy if (domainStrategy4Freedom.IsNotEmpty()) @@ -1149,47 +1144,16 @@ public class CoreConfigV2rayService var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); if (outbound != null) { - outbound.settings = new(); - outbound.settings.domainStrategy = domainStrategy4Freedom; - outbound.settings.userLevel = 0; - } - } - - var obj = JsonUtils.ParseJson(normalDNS); - if (obj is null) - { - List servers = []; - string[] arrDNS = normalDNS.Split(','); - foreach (string str in arrDNS) - { - servers.Add(str); - } - obj = JsonUtils.ParseJson("{}"); - obj["servers"] = JsonUtils.SerializeToNode(servers); - } - - // Append to dns settings - if (item.UseSystemHosts) - { - var systemHosts = Utils.GetSystemHosts(); - if (systemHosts.Count > 0) - { - var normalHost = obj["hosts"]; - if (normalHost != null) + outbound.settings = new() { - foreach (var host in systemHosts) - { - if (normalHost[host.Key] != null) - continue; - normalHost[host.Key] = host.Value; - } - } + domainStrategy = domainStrategy4Freedom, + userLevel = 0 + }; } } - await GenDnsDomains(node, obj, item); - - v2rayConfig.dns = obj; + await GenDnsServers(node, v2rayConfig, dNSItem); + await GenDnsHosts(v2rayConfig, dNSItem); } catch (Exception ex) { @@ -1198,54 +1162,200 @@ public class CoreConfigV2rayService return 0; } - private async Task GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem) + private async Task GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, DNSItem dNSItem) { - if (node == null) + var directDomainList = new List(); + var directGeositeList = new List(); + var proxyDomainList = new List(); + var proxyGeositeList = new List(); + var routing = await ConfigHandler.GetDefaultRouting(_config); + if (routing != null) { - return 0; + var rules = JsonUtils.Deserialize>(routing.RuleSet); + foreach (var item in rules ?? []) + { + if (!item.Enabled) + { + continue; + } + if (item.Domain == null || item.Domain.Count == 0) + { + continue; + } + if (item.OutboundTag == Global.DirectTag) + { + foreach (var domain in item.Domain) + { + if (domain.StartsWith('#')) + { + continue; + } + var domain1 = domain.Replace(Global.RoutingRuleComma, ","); + if (domain1.StartsWith("geosite:")) + { + directGeositeList.Add(domain1); + } + else + { + directDomainList.Add(domain1); + } + } + } + else if (item.OutboundTag == Global.ProxyTag) + { + foreach (var domain in item.Domain) + { + if (domain.StartsWith('#')) + { + continue; + } + var domain1 = domain.Replace(Global.RoutingRuleComma, ","); + if (domain1.StartsWith("geosite:")) + { + proxyGeositeList.Add(domain1); + } + else + { + proxyDomainList.Add(domain1); + } + } + } + } } - var servers = dns["servers"]; - if (servers != null) - { - var domainList = new List(); - if (Utils.IsDomain(node.Address)) - { - domainList.Add(node.Address); - } - var subItem = await AppHandler.Instance.GetSubItem(node.Subid); - if (subItem is not null) - { - // Previous proxy - var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); - if (prevNode is not null - && prevNode.ConfigType != EConfigType.Custom - && prevNode.ConfigType != EConfigType.Hysteria2 - && prevNode.ConfigType != EConfigType.TUIC - && Utils.IsDomain(prevNode.Address)) - { - domainList.Add(prevNode.Address); - } - // Next proxy - var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); - if (nextNode is not null - && nextNode.ConfigType != EConfigType.Custom - && nextNode.ConfigType != EConfigType.Hysteria2 - && nextNode.ConfigType != EConfigType.TUIC - && Utils.IsDomain(nextNode.Address)) + if (Utils.IsDomain(node.Address)) + { + directDomainList.Add(node.Address); + } + var subItem = await AppHandler.Instance.GetSubItem(node.Subid); + if (subItem is not null) + { + // Previous proxy + var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); + if (prevNode is not null + && prevNode.ConfigType != EConfigType.Custom + && prevNode.ConfigType != EConfigType.Hysteria2 + && prevNode.ConfigType != EConfigType.TUIC + && Utils.IsDomain(prevNode.Address)) + { + directDomainList.Add(prevNode.Address); + } + + // Next proxy + var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); + if (nextNode is not null + && nextNode.ConfigType != EConfigType.Custom + && nextNode.ConfigType != EConfigType.Hysteria2 + && nextNode.ConfigType != EConfigType.TUIC + && Utils.IsDomain(nextNode.Address)) + { + directDomainList.Add(nextNode.Address); + } + } + + v2rayConfig.dns ??= new Dns4Ray(); + v2rayConfig.dns.servers ??= new List(); + + if (proxyDomainList.Count > 0) + { + var dnsServer = new DnsServer4Ray() + { + address = dNSItem.RemoteDNS, + skipFallback = true, + domains = proxyDomainList + }; + v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer)); + } + if (proxyGeositeList.Count > 0) + { + var dnsServer = new DnsServer4Ray() + { + address = dNSItem.RemoteDNS, + skipFallback = true, + domains = proxyGeositeList + }; + v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer)); + } + if (directDomainList.Count > 0) + { + var dnsServer = new DnsServer4Ray() + { + address = dNSItem.DirectDNS, + skipFallback = true, + domains = directDomainList + }; + v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer)); + } + if (directGeositeList.Count > 0) + { + var dnsServer = new DnsServer4Ray() + { + address = dNSItem.DirectDNS, + skipFallback = true, + domains = directGeositeList + }; + v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer)); + } + v2rayConfig.dns.servers.Add(dNSItem.RemoteDNS); // fallback DNS server + return await Task.FromResult(0); + } + + private async Task GenDnsHosts(V2rayConfig v2rayConfig, DNSItem dNSItem) + { + if (dNSItem.AddCommonHosts == false && dNSItem.UseSystemHosts == false && dNSItem.Hosts.IsNullOrEmpty()) + { + return await Task.FromResult(0); + } + v2rayConfig.dns ??= new Dns4Ray(); + v2rayConfig.dns.hosts ??= new Dictionary>(); + if (dNSItem.AddCommonHosts == true) + { + v2rayConfig.dns.hosts = Global.PredefinedHosts; + } + + if (dNSItem.UseSystemHosts == true) + { + var systemHosts = Utils.GetSystemHosts(); + if (systemHosts.Count > 0) + { + var normalHost = v2rayConfig.dns.hosts; + if (normalHost != null) { - domainList.Add(nextNode.Address); + foreach (var host in systemHosts) + { + if (normalHost[host.Key] != null) + { + continue; + } + normalHost[host.Key] = new List { host.Value }; + } } } - if (domainList.Count > 0) - { - var dnsServer = new DnsServer4Ray() + } + + var userHostsMap = dNSItem.Hosts? + .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Where(line => line.Contains(' ')) + .ToDictionary( + line => { - address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, - skipFallback = true, - domains = domainList - }; - servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer)); + var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + return parts[0]; + }, + line => + { + var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + var values = parts.Skip(1).ToList(); + return values; + } + ); + + if (userHostsMap != null) + { + foreach (var kvp in userHostsMap) + { + v2rayConfig.dns.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 1d6829b8..734d97bf 100644 --- a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs @@ -6,111 +6,81 @@ namespace ServiceLib.ViewModels; public class DNSSettingViewModel : MyReactiveObject { - [Reactive] public bool UseSystemHosts { get; set; } - [Reactive] public string DomainStrategy4Freedom { get; set; } - [Reactive] public string DomainDNSAddress { get; set; } - [Reactive] public string NormalDNS { get; set; } - - [Reactive] public string DomainStrategy4Freedom2 { get; set; } - [Reactive] public string DomainDNSAddress2 { get; set; } - [Reactive] public string NormalDNS2 { get; set; } - [Reactive] public string TunDNS2 { get; set; } + [Reactive] public bool? UseSystemHosts { get; set; } + [Reactive] public bool? AddCommonHosts { get; set; } + [Reactive] public bool? FakeIP { get; set; } + [Reactive] public bool? BlockBindingQuery { get; set; } + [Reactive] public string? DirectDNS { get; set; } + [Reactive] public string? RemoteDNS { get; set; } + [Reactive] public string? SingboxOutboundsResolveDNS { get; set; } + [Reactive] public string? SingboxFinalResolveDNS { get; set; } + [Reactive] public string? RayStrategy4Freedom { get; set; } + [Reactive] public string? SingboxStrategy4Direct { get; set; } + [Reactive] public string? SingboxStrategy4Proxy { get; set; } + [Reactive] public string? Hosts { get; set; } public ReactiveCommand SaveCmd { get; } - public ReactiveCommand ImportDefConfig4V2rayCmd { get; } - public ReactiveCommand ImportDefConfig4SingboxCmd { get; } + //public ReactiveCommand ImportDefConfig4V2rayCmd { get; } + //public ReactiveCommand ImportDefConfig4SingboxCmd { get; } public DNSSettingViewModel(Func>? updateView) { _config = AppHandler.Instance.Config; _updateView = updateView; - SaveCmd = ReactiveCommand.CreateFromTask(async () => - { - await SaveSettingAsync(); - }); + SaveCmd = ReactiveCommand.CreateFromTask(SaveSettingAsync); - ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () => - { - NormalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName); - await Task.CompletedTask; - }); + //ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () => + //{ + // NormalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName); + // await Task.CompletedTask; + //}); - ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () => - { - NormalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName); - TunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName); - await Task.CompletedTask; - }); + //ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () => + //{ + // NormalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName); + // TunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName); + // await Task.CompletedTask; + //}); _ = Init(); } private async Task Init() { - var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray); + _config = AppHandler.Instance.Config; + var item = _config.DNSItem; UseSystemHosts = item.UseSystemHosts; - DomainStrategy4Freedom = item?.DomainStrategy4Freedom ?? string.Empty; - DomainDNSAddress = item?.DomainDNSAddress ?? string.Empty; - NormalDNS = item?.NormalDNS ?? string.Empty; - - var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); - DomainStrategy4Freedom2 = item2?.DomainStrategy4Freedom ?? string.Empty; - DomainDNSAddress2 = item2?.DomainDNSAddress ?? string.Empty; - NormalDNS2 = item2?.NormalDNS ?? string.Empty; - TunDNS2 = item2?.TunDNS ?? string.Empty; + AddCommonHosts = item.AddCommonHosts; + FakeIP = item.FakeIP; + BlockBindingQuery = item.BlockBindingQuery; + DirectDNS = item.DirectDNS; + RemoteDNS = item.RemoteDNS; + RayStrategy4Freedom = item.RayStrategy4Freedom; + SingboxOutboundsResolveDNS = item.SingboxOutboundsResolveDNS; + SingboxFinalResolveDNS = item.SingboxFinalResolveDNS; + SingboxStrategy4Direct = item.SingboxStrategy4Direct; + SingboxStrategy4Proxy = item.SingboxStrategy4Proxy; + Hosts = item.Hosts; } private async Task SaveSettingAsync() { - if (NormalDNS.IsNotEmpty()) + _config.DNSItem.UseSystemHosts = UseSystemHosts; + _config.DNSItem.AddCommonHosts = AddCommonHosts; + _config.DNSItem.FakeIP = FakeIP; + _config.DNSItem.BlockBindingQuery = BlockBindingQuery; + _config.DNSItem.DirectDNS = DirectDNS; + _config.DNSItem.RemoteDNS = RemoteDNS; + _config.DNSItem.RayStrategy4Freedom = RayStrategy4Freedom; + _config.DNSItem.SingboxOutboundsResolveDNS = SingboxOutboundsResolveDNS; + _config.DNSItem.SingboxFinalResolveDNS = SingboxFinalResolveDNS; + _config.DNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct; + _config.DNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy; + _config.DNSItem.Hosts = Hosts; + await ConfigHandler.SaveConfig(_config); + if (_updateView != null) { - var obj = JsonUtils.ParseJson(NormalDNS); - if (obj != null && obj["servers"] != null) - { - } - else - { - if (NormalDNS.Contains('{') || NormalDNS.Contains('}')) - { - NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText); - return; - } - } + await _updateView(EViewAction.CloseWindow, null); } - if (NormalDNS2.IsNotEmpty()) - { - var obj2 = JsonUtils.Deserialize(NormalDNS2); - if (obj2 == null) - { - NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText); - return; - } - } - if (TunDNS2.IsNotEmpty()) - { - var obj2 = JsonUtils.Deserialize(TunDNS2); - if (obj2 == null) - { - NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText); - return; - } - } - - var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray); - item.DomainStrategy4Freedom = DomainStrategy4Freedom; - item.DomainDNSAddress = DomainDNSAddress; - item.UseSystemHosts = UseSystemHosts; - item.NormalDNS = NormalDNS; - await ConfigHandler.SaveDNSItems(_config, item); - - var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); - item2.DomainStrategy4Freedom = DomainStrategy4Freedom2; - item2.DomainDNSAddress = DomainDNSAddress2; - item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(NormalDNS2)); - item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(TunDNS2)); - await ConfigHandler.SaveDNSItems(_config, item2); - - NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); - _ = _updateView?.Invoke(EViewAction.CloseWindow, null); } } diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index 36e20a87..22d82895 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -219,7 +219,6 @@ public class MainWindowViewModel : MyReactiveObject _config.UiItem.ShowInTaskbar = true; await ConfigHandler.InitBuiltinRouting(_config); - await ConfigHandler.InitBuiltinDNS(_config); await ProfileExHandler.Instance.Init(); await CoreHandler.Instance.Init(_config, UpdateHandler); TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler); diff --git a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml index efdf4eda..59cffdc5 100644 --- a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml @@ -35,147 +35,220 @@ - - - + + + + + Text="{x:Static resx:ResUI.TbDomesticDNS}" /> + - - - - - -