Simplify DNS Settings

DHR60 2025-07-10 21:42:53 +08:00
parent 2b32f37057
commit dff67e9d78
23 changed files with 1532 additions and 812 deletions

View File

@ -349,25 +349,42 @@ public class Global
public static readonly List<string> SingboxDomainStrategy4Out = public static readonly List<string> SingboxDomainStrategy4Out =
[ [
"ipv4_only", "",
"ipv4_only",
"prefer_ipv4", "prefer_ipv4",
"prefer_ipv6", "prefer_ipv6",
"ipv6_only", "ipv6_only"
""
]; ];
public static readonly List<string> DomainDNSAddress = public static readonly List<string> DomainDirectDNSAddress =
[ [
"223.5.5.5", "https://dns.alidns.com/dns-query",
"223.6.6.6", "https://doh.pub/dns-query",
"223.5.5.5",
"119.29.29.29",
"localhost" "localhost"
]; ];
public static readonly List<string> SingboxDomainDNSAddress = public static readonly List<string> 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<string> DomainPureIPDNSAddress =
[ [
"223.5.5.5", "223.5.5.5",
"223.6.6.6", "119.29.29.29",
"dhcp://auto" "localhost"
]; ];
public static readonly List<string> Languages = public static readonly List<string> Languages =
@ -537,5 +554,22 @@ public class Global
BlockTag BlockTag
]; ];
public static readonly Dictionary<string, List<string>> PredefinedHosts = new()
{
{ "dns.google", new List<string> { "8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844" } },
{ "dns.alidns.com", new List<string> { "223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1" } },
{ "one.one.one.one", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
{ "1dot1dot1dot1.cloudflare-dns.com", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
{ "cloudflare-dns.com", new List<string> { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } },
{ "dns.cloudflare.com", new List<string> { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } },
{ "dot.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
{ "dns.quad9.net", new List<string> { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } },
{ "dns.yandex.net", new List<string> { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } },
{ "dns.sb", new List<string> { "185.222.222.222", "2a09::" } },
{ "dns.umbrella.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
{ "dns.sse.cisco.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
{ "engage.cloudflareclient.com", new List<string> { "162.159.192.1", "2606:4700:d0::a29f:c001" } }
};
#endregion const #endregion const
} }

View File

@ -193,16 +193,6 @@ public sealed class AppHandler
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id); return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id);
} }
public async Task<List<DNSItem>?> DNSItems()
{
return await SQLiteHelper.Instance.TableAsync<DNSItem>().ToListAsync();
}
public async Task<DNSItem?> GetDNSItem(ECoreType eCoreType)
{
return await SQLiteHelper.Instance.TableAsync<DNSItem>().FirstOrDefaultAsync(it => it.CoreType == eCoreType);
}
#endregion SqliteHelper #endregion SqliteHelper
#region Core Type #region Core Type

View File

@ -112,6 +112,18 @@ public class ConfigHandler
config.ConstItem ??= new ConstItem(); 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(); config.SpeedTestItem ??= new();
if (config.SpeedTestItem.SpeedTestTimeout < 10) if (config.SpeedTestItem.SpeedTestTimeout < 10)
{ {
@ -2088,101 +2100,6 @@ public class ConfigHandler
#endregion Routing #endregion Routing
#region DNS
/// <summary>
/// Initialize built-in DNS configurations
/// Creates default DNS items for V2Ray and sing-box
/// </summary>
/// <param name="config">Current configuration</param>
/// <returns>0 if successful</returns>
public static async Task<int> 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;
}
/// <summary>
/// Save a DNS item to the database
/// </summary>
/// <param name="config">Current configuration</param>
/// <param name="item">DNS item to save</param>
/// <returns>0 if successful, -1 if failed</returns>
public static async Task<int> 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;
}
}
/// <summary>
/// Get an external DNS configuration from URL
/// Downloads and processes DNS templates
/// </summary>
/// <param name="type">Core type (Xray or sing-box)</param>
/// <param name="url">URL of the DNS template</param>
/// <returns>DNS item with configuration from the URL</returns>
public static async Task<DNSItem> 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<DNSItem>(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 #region Regional Presets
/// <summary> /// <summary>
@ -2202,7 +2119,6 @@ public class ConfigHandler
config.ConstItem.RouteRulesTemplateSourceUrl = ""; config.ConstItem.RouteRulesTemplateSourceUrl = "";
await SQLiteHelper.Instance.DeleteAllAsync<DNSItem>(); await SQLiteHelper.Instance.DeleteAllAsync<DNSItem>();
await InitBuiltinDNS(config);
return true; return true;
@ -2211,8 +2127,8 @@ public class ConfigHandler
config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[1]; config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[1];
config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[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.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.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
return true; return true;
@ -2221,8 +2137,8 @@ public class ConfigHandler
config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2]; config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2];
config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[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.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.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
return true; return true;
} }

View File

@ -48,6 +48,7 @@ public class Config
public List<InItem> Inbound { get; set; } public List<InItem> Inbound { get; set; }
public List<KeyEventItem> GlobalHotkeys { get; set; } public List<KeyEventItem> GlobalHotkeys { get; set; }
public List<CoreTypeItem> CoreTypeItem { get; set; } public List<CoreTypeItem> CoreTypeItem { get; set; }
public DNSItem DNSItem { get; set; }
#endregion other entities #endregion other entities
} }

View File

@ -253,3 +253,20 @@ public class WindowSizeItem
public int Width { get; set; } public int Width { get; set; }
public int Height { 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; }
}

View File

@ -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; }
}

View File

@ -36,6 +36,7 @@ public class Dns4Sbox
public class Route4Sbox public class Route4Sbox
{ {
public Rule4Sbox? default_domain_resolver { get; set; } // or string
public bool? auto_detect_interface { get; set; } public bool? auto_detect_interface { get; set; }
public List<Rule4Sbox> rules { get; set; } public List<Rule4Sbox> rules { get; set; }
public List<Ruleset4Sbox>? rule_set { get; set; } public List<Ruleset4Sbox>? rule_set { get; set; }
@ -75,7 +76,7 @@ public class Rule4Sbox
public string? strategy { get; set; } public string? strategy { get; set; }
public List<string>? sniffer { get; set; } public List<string>? sniffer { get; set; }
public string? rcode { get; set; } public string? rcode { get; set; }
public List<object>? query_type { get; set; } public List<int>? query_type { get; set; }
public List<string>? answer { get; set; } public List<string>? answer { get; set; }
public List<string>? ns { get; set; } public List<string>? ns { get; set; }
public List<string>? extra { get; set; } public List<string>? extra { get; set; }
@ -237,13 +238,7 @@ public class Server4Sbox : BaseServer4Sbox
public string? path { get; set; } public string? path { get; set; }
public Headers4Sbox? headers { get; set; } public Headers4Sbox? headers { get; set; }
// public List<string>? path { get; set; } // hosts // public List<string>? path { get; set; } // hosts
public Dictionary<string, object>? predefined { get; set; } public Dictionary<string, List<string>>? 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 class Experimental4Sbox public class Experimental4Sbox

View File

@ -5,7 +5,7 @@ namespace ServiceLib.Models;
public class V2rayConfig public class V2rayConfig
{ {
public Log4Ray log { get; set; } public Log4Ray log { get; set; }
public object dns { get; set; } public Dns4Ray dns { get; set; }
public List<Inbounds4Ray> inbounds { get; set; } public List<Inbounds4Ray> inbounds { get; set; }
public List<Outbounds4Ray> outbounds { get; set; } public List<Outbounds4Ray> outbounds { get; set; }
public Routing4Ray routing { get; set; } public Routing4Ray routing { get; set; }
@ -203,7 +203,8 @@ public class Response4Ray
public class Dns4Ray public class Dns4Ray
{ {
public List<string> servers { get; set; } public Dictionary<string, List<string>>? hosts { get; set; }
public List<object> servers { get; set; }
} }
public class DnsServer4Ray public class DnsServer4Ray

View File

@ -1,4 +1,4 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// 此代码由工具生成。 // 此代码由工具生成。
// 运行时版本:4.0.30319.42000 // 运行时版本:4.0.30319.42000
@ -2211,6 +2211,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Add Common DNS Hosts 的本地化字符串。
/// </summary>
public static string TbAddCommonDNSHosts {
get {
return ResourceManager.GetString("TbAddCommonDNSHosts", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Address 的本地化字符串。 /// 查找类似 Address 的本地化字符串。
/// </summary> /// </summary>
@ -2247,6 +2256,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Apply to Proxy Domains Only 的本地化字符串。
/// </summary>
public static string TbApplyProxyDomainsOnly {
get {
return ResourceManager.GetString("TbApplyProxyDomainsOnly", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Auto refresh 的本地化字符串。 /// 查找类似 Auto refresh 的本地化字符串。
/// </summary> /// </summary>
@ -2274,6 +2292,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Block SVCB and HTTPS Queries 的本地化字符串。
/// </summary>
public static string TbBlockSVCBHTTPSQueries {
get {
return ResourceManager.GetString("TbBlockSVCBHTTPSQueries", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Browse 的本地化字符串。 /// 查找类似 Browse 的本地化字符串。
/// </summary> /// </summary>
@ -2346,6 +2373,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 DNS Hosts: (&quot;domain1 ip1 ip2&quot; per line) 的本地化字符串。
/// </summary>
public static string TbDNSHostsConfig {
get {
return ResourceManager.GetString("TbDNSHostsConfig", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。 /// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。
/// </summary> /// </summary>
@ -2391,6 +2427,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Domestic DNS 的本地化字符串。
/// </summary>
public static string TbDomesticDNS {
get {
return ResourceManager.GetString("TbDomesticDNS", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Edit 的本地化字符串。 /// 查找类似 Edit 的本地化字符串。
/// </summary> /// </summary>
@ -2409,6 +2454,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 FakeIP 的本地化字符串。
/// </summary>
public static string TbFakeIP {
get {
return ResourceManager.GetString("TbFakeIP", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Fingerprint 的本地化字符串。 /// 查找类似 Fingerprint 的本地化字符串。
/// </summary> /// </summary>
@ -2598,6 +2652,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Prevent DNS Leaks 的本地化字符串。
/// </summary>
public static string TbPreventDNSLeaks {
get {
return ResourceManager.GetString("TbPreventDNSLeaks", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Private Key 的本地化字符串。 /// 查找类似 Private Key 的本地化字符串。
/// </summary> /// </summary>
@ -2634,6 +2697,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Remote DNS 的本地化字符串。
/// </summary>
public static string TbRemoteDNS {
get {
return ResourceManager.GetString("TbRemoteDNS", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Camouflage domain(host) 的本地化字符串。 /// 查找类似 Camouflage domain(host) 的本地化字符串。
/// </summary> /// </summary>
@ -2742,6 +2814,69 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbSBDirectResolveStrategy {
get {
return ResourceManager.GetString("TbSBDirectResolveStrategy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable to Override sing-box DoH Resolver 的本地化字符串。
/// </summary>
public static string TbSBDoHOverride {
get {
return ResourceManager.GetString("TbSBDoHOverride", resourceCulture);
}
}
/// <summary>
/// 查找类似 sing-box DoH Resolver Server 的本地化字符串。
/// </summary>
public static string TbSBDoHResolverServer {
get {
return ResourceManager.GetString("TbSBDoHResolverServer", resourceCulture);
}
}
/// <summary>
/// 查找类似 Fallback DNS Resolution, Suggest IP 的本地化字符串。
/// </summary>
public static string TbSBFallbackDNSResolve {
get {
return ResourceManager.GetString("TbSBFallbackDNSResolve", resourceCulture);
}
}
/// <summary>
/// 查找类似 Resolve Outbound Domains 的本地化字符串。
/// </summary>
public static string TbSBOutboundDomainResolve {
get {
return ResourceManager.GetString("TbSBOutboundDomainResolve", resourceCulture);
}
}
/// <summary>
/// 查找类似 Outbound DNS Resolution (sing-box) 的本地化字符串。
/// </summary>
public static string TbSBOutboundsResolverDNS {
get {
return ResourceManager.GetString("TbSBOutboundsResolverDNS", resourceCulture);
}
}
/// <summary>
/// 查找类似 sing-box Remote Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbSBRemoteResolveStrategy {
get {
return ResourceManager.GetString("TbSBRemoteResolveStrategy", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Encryption method (security) 的本地化字符串。 /// 查找类似 Encryption method (security) 的本地化字符串。
/// </summary> /// </summary>
@ -3687,6 +3822,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 xray Freedom Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbXrayFreedomResolveStrategy {
get {
return ResourceManager.GetString("TbXrayFreedomResolveStrategy", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 The delay: {0} ms, {1} 的本地化字符串。 /// 查找类似 The delay: {0} ms, {1} 的本地化字符串。
/// </summary> /// </summary>
@ -3696,6 +3840,24 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Advanced DNS Settings 的本地化字符串。
/// </summary>
public static string ThAdvancedDNSSettings {
get {
return ResourceManager.GetString("ThAdvancedDNSSettings", resourceCulture);
}
}
/// <summary>
/// 查找类似 Basic DNS Settings 的本地化字符串。
/// </summary>
public static string ThBasicDNSSettings {
get {
return ResourceManager.GetString("ThBasicDNSSettings", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Active 的本地化字符串。 /// 查找类似 Active 的本地化字符串。
/// </summary> /// </summary>

View File

@ -1398,4 +1398,58 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value> <value>Add [Anytls] Configuration</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>Outbound DNS Resolution (sing-box)</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>Resolve Outbound Domains</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH Resolver Server</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>Fallback DNS Resolution, Suggest IP</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>Apply to Proxy Domains Only</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>Basic DNS Settings</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
</root> </root>

View File

@ -1398,4 +1398,58 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value> <value>Add [Anytls] Configuration</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>Outbound DNS Resolution (sing-box)</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>Resolve Outbound Domains</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH Resolver Server</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>Fallback DNS Resolution, Suggest IP</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>Apply to Proxy Domains Only</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>Basic DNS Settings</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
</root> </root>

View File

@ -1398,4 +1398,58 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value> <value>Add [Anytls] Configuration</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>Outbound DNS Resolution (sing-box)</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>Resolve Outbound Domains</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH Resolver Server</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>Fallback DNS Resolution, Suggest IP</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>Apply to Proxy Domains Only</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>Basic DNS Settings</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
</root> </root>

View File

@ -807,9 +807,6 @@
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>Вверх (U)</value> <value>Вверх (U)</value>
</data> </data>
<data name="menuMoveTo" xml:space="preserve">
<value>Переместить вверх/вниз</value>
</data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>Фильтр, поддерживает regex</value> <value>Фильтр, поддерживает regex</value>
</data> </data>
@ -969,6 +966,9 @@
<data name="TbSettingsSpeedTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>URL для тестирования скорости</value> <value>URL для тестирования скорости</value>
</data> </data>
<data name="menuMoveTo" xml:space="preserve">
<value>Переместить вверх/вниз</value>
</data>
<data name="TbPublicKey" xml:space="preserve"> <data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value> <value>PublicKey</value>
</data> </data>
@ -1398,4 +1398,58 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value> <value>Add [Anytls] Configuration</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>Outbound DNS Resolution (sing-box)</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>Resolve Outbound Domains</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH Resolver Server</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>Fallback DNS Resolution, Suggest IP</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>Apply to Proxy Domains Only</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>Basic DNS Settings</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
</root> </root>

View File

@ -1395,4 +1395,58 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>添加 [Anytls] 配置文件</value> <value>添加 [Anytls] 配置文件</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>远程 DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>直连 DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>出站 DNS 解析</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>解析出站域名</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH 解析服务器</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>兜底解析其他 DNS 域名,建议设为 ip</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray freedom 解析策略</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box 直连解析策略</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box 远程解析策略</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>添加常用 DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>开启后可覆盖 sing-box DoH 解析服务器</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>阻止 SVCB 和 HTTPS 查询</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>避免 DNS 泄漏</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts“域名1 ip1 ip2” 一行一个)</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>仅对代理域名生效</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>DNS 基础设置</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>DNS 进阶设置</value>
</data>
</root> </root>

View File

@ -1395,4 +1395,58 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>新增 [Anytls] 設定檔</value> <value>新增 [Anytls] 設定檔</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>Outbound DNS Resolution (sing-box)</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>Resolve Outbound Domains</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH Resolver Server</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>Fallback DNS Resolution, Suggest IP</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>Apply to Proxy Domains Only</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>Basic DNS Settings</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
</root> </root>

View File

@ -1,7 +1,9 @@
using System.Collections.Generic;
using System.Data; using System.Data;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Reactive; using System.Reactive;
using System.Text;
using DynamicData; using DynamicData;
using ServiceLib.Models; using ServiceLib.Models;
@ -73,7 +75,7 @@ public class CoreConfigSingboxService
await GenRouting(singboxConfig); await GenRouting(singboxConfig);
await GenDns(node, singboxConfig); await GenDns(singboxConfig);
await GenExperimental(singboxConfig); await GenExperimental(singboxConfig);
@ -243,7 +245,7 @@ public class CoreConfigSingboxService
singboxConfig.route.rules.Add(rule); singboxConfig.route.rules.Add(rule);
} }
await GenDnsDomains(null, singboxConfig, null); await GenDns(singboxConfig);
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault(); //var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
//if (dnsServer != null) //if (dnsServer != null)
//{ //{
@ -315,7 +317,7 @@ public class CoreConfigSingboxService
await GenOutbound(node, singboxConfig.outbounds.First()); await GenOutbound(node, singboxConfig.outbounds.First());
} }
await GenMoreOutbounds(node, singboxConfig); await GenMoreOutbounds(node, singboxConfig);
await GenDnsDomains(null, singboxConfig, null); await GenDns(singboxConfig);
singboxConfig.route.rules.Clear(); singboxConfig.route.rules.Clear();
singboxConfig.inbounds.Clear(); singboxConfig.inbounds.Clear();
@ -417,7 +419,7 @@ public class CoreConfigSingboxService
} }
await GenOutboundsList(proxyProfiles, singboxConfig); await GenOutboundsList(proxyProfiles, singboxConfig);
await GenDns(null, singboxConfig); await GenDns(singboxConfig);
await ConvertGeo2Ruleset(singboxConfig); await ConvertGeo2Ruleset(singboxConfig);
ret.Success = true; ret.Success = true;
@ -648,17 +650,6 @@ public class CoreConfigSingboxService
outbound.server_port = node.Port; outbound.server_port = node.Port;
outbound.type = Global.ProtocolTypes[node.ConfigType]; 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) switch (node.ConfigType)
{ {
case EConfigType.VMess: case EConfigType.VMess:
@ -788,17 +779,6 @@ public class CoreConfigSingboxService
endpoint.address = Utils.String2List(node.RequestHost); endpoint.address = Utils.String2List(node.RequestHost);
endpoint.type = Global.ProtocolTypes[node.ConfigType]; 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) switch (node.ConfigType)
{ {
case EConfigType.WireGuard: case EConfigType.WireGuard:
@ -1245,6 +1225,13 @@ public class CoreConfigSingboxService
try try
{ {
singboxConfig.route.final = Global.ProxyTag; 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) if (_config.TunModeItem.EnableTun)
{ {
@ -1325,14 +1312,14 @@ public class CoreConfigSingboxService
if (routing != null) if (routing != null)
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet); var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules ?? []) foreach (var item1 in rules ?? [])
{ {
if (item.Enabled) if (item1.Enabled)
{ {
await GenRoutingUserRule(item, singboxConfig); await GenRoutingUserRule(item1, singboxConfig);
if (item.Ip != null && item.Ip.Count > 0) 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") if (_config.RoutingBasicItem.DomainStrategy == "IPIfNonMatch")
{ {
singboxConfig.route.rules.Add(resolveRule); 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; return server.tag;
} }
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig) private async Task<int> GenDns(SingboxConfig singboxConfig)
{ {
try try
{ {
var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); var dNSItem = _config.DNSItem;
var strDNS = string.Empty; await GenDnsServers(singboxConfig, dNSItem);
if (_config.TunModeItem.EnableTun) await GenDnsRules(singboxConfig, dNSItem);
{
strDNS = string.IsNullOrEmpty(item?.TunDNS) ? EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName) : item?.TunDNS;
}
else
{
strDNS = string.IsNullOrEmpty(item?.NormalDNS) ? EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName) : item?.NormalDNS;
}
var dns4Sbox = JsonUtils.Deserialize<Dns4Sbox>(strDNS); singboxConfig.dns ??= new Dns4Sbox();
if (dns4Sbox is null) singboxConfig.dns.independent_cache = true;
{ singboxConfig.dns.final = "dns_remote"; // TODO
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);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1623,211 +1591,280 @@ public class CoreConfigSingboxService
return 0; return 0;
} }
private async Task<int> GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem) private async Task<int> GenDnsServers(SingboxConfig singboxConfig, DNSItem dNSItem)
{ {
var dns4Sbox = singboxConfig.dns ?? new(); var finalDns = ParseDnsAddress(dNSItem.SingboxFinalResolveDNS);
dns4Sbox.servers ??= []; finalDns.tag = "final_resolver";
dns4Sbox.rules ??= [];
var tag = "local_resolver"; var directDns = ParseDnsAddress(dNSItem.DirectDNS);
var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress; 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); tag = "dns_hosts",
type = "hosts",
var localDnsTag = "local_local"; };
if (dNSItem.AddCommonHosts == true)
dns4Sbox.servers.Add(new() {
{ hostsDns.predefined = Global.PredefinedHosts;
tag = localDnsTag,
type = "local"
});
dns4Sbox.rules.Insert(0, new()
{
server = localDnsTag,
clash_mode = ERuleMode.Direct.ToString()
});
} }
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); foreach (var kvp in userHostsMap)
dns4Sbox.servers.Add(new()
{ {
tag = tag, hostsDns.predefined[kvp.Key] = kvp.Value;
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()
});
} }
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", if (finalDns.server == host.Key)
clash_mode = ERuleMode.Global.ToString()
});
//Tun2SocksAddress
if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni))
{
dns4Sbox.rules.Insert(0, new()
{ {
server = tag, finalDns.domain_resolver = "dns_hosts";
domain = [node?.Sni], }
strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom 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<Server4Sbox>();
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); return await Task.FromResult(0);
} }
private async Task<int> GenDnsDomainsLegacy(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem) private async Task<int> GenDnsRules(SingboxConfig singboxConfig, DNSItem dNSItem)
{ {
var dns4Sbox = singboxConfig.dns ?? new(); singboxConfig.dns ??= new Dns4Sbox();
dns4Sbox.servers ??= []; singboxConfig.dns.rules ??= new List<Rule4Sbox>();
dns4Sbox.rules ??= []; // hosts
singboxConfig.dns.rules.Add(new Rule4Sbox
var tag = "local_local";
dns4Sbox.servers.Add(new()
{ {
tag = tag, ip_accept_any = true,
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, server = "dns_hosts",
detour = Global.DirectTag,
strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom,
}); });
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() 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", query_type = new List<int> { 64, 65 },
clash_mode = ERuleMode.Global.ToString() action = "predefined",
rcode = "NOTIMP"
}); });
var lstDomain = singboxConfig.outbounds var routing = await ConfigHandler.GetDefaultRouting(_config);
.Where(t => t.server.IsNotEmpty() && Utils.IsDomain(t.server)) if (routing != null)
.Select(t => t.server)
.Distinct()
.ToList();
if (lstDomain != null && lstDomain.Count > 0)
{ {
dns4Sbox.rules.Insert(0, new() var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules ?? [])
{ {
server = tag, if (!item.Enabled)
domain = lstDomain {
}); 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<string> { "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); 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"; if (string.IsNullOrEmpty(address))
string? host = null; {
int? port = null; return null;
string? path = null; }
var server = new Server4Sbox();
if (address is "local" or "localhost") if (address is "local" or "localhost")
{ {
return ("local", null, null, null); server.type = "local";
return server;
} }
if (address.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase)) if (address.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase))
{ {
string interface_name = address.Substring(7); var interface_name = address.Substring(7);
return ("dhcp", interface_name == "auto" ? null : interface_name, null, null); server.type = "dhcp";
server.Interface = interface_name == "auto" ? null : interface_name;
return server;
} }
if (!address.Contains("://")) if (!address.Contains("://"))
{ {
// udp dns // udp dns
host = address; server.type = "udp";
return (type, host, port, path); server.server = address;
return server;
} }
try try
{ {
int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal); var protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal);
type = address.Substring(0, protocolEndIndex).ToLower(); server.type = address.Substring(0, protocolEndIndex).ToLower();
var uri = new Uri(address); var uri = new Uri(address);
host = uri.Host; server.server = uri.Host;
if (!uri.IsDefaultPort) 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) catch (UriFormatException)
{ {
int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal); var protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal);
if (protocolEndIndex > 0) if (protocolEndIndex > 0)
{ {
type = address.Substring(0, protocolEndIndex).ToLower(); server.type = address.Substring(0, protocolEndIndex).ToLower();
string remaining = address.Substring(protocolEndIndex + 3); var remaining = address.Substring(protocolEndIndex + 3);
int portIndex = remaining.IndexOf(':'); var portIndex = remaining.IndexOf(':');
int pathIndex = remaining.IndexOf('/'); var pathIndex = remaining.IndexOf('/');
if (portIndex > 0) if (portIndex > 0)
{ {
host = remaining.Substring(0, portIndex); server.server = remaining.Substring(0, portIndex);
string portPart = pathIndex > portIndex var portPart = pathIndex > portIndex
? remaining.Substring(portIndex + 1, pathIndex - portIndex - 1) ? remaining.Substring(portIndex + 1, pathIndex - portIndex - 1)
: remaining.Substring(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) else if (pathIndex > 0)
{ {
host = remaining.Substring(0, pathIndex); server.server = remaining.Substring(0, pathIndex);
} }
else 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<int> GenExperimental(SingboxConfig singboxConfig) private async Task<int> GenExperimental(SingboxConfig singboxConfig)

View File

@ -1135,13 +1135,8 @@ public class CoreConfigV2rayService
{ {
try try
{ {
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray); var dNSItem = _config.DNSItem;
var normalDNS = item?.NormalDNS; var domainStrategy4Freedom = dNSItem?.RayStrategy4Freedom;
var domainStrategy4Freedom = item?.DomainStrategy4Freedom;
if (normalDNS.IsNullOrEmpty())
{
normalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
}
//Outbound Freedom domainStrategy //Outbound Freedom domainStrategy
if (domainStrategy4Freedom.IsNotEmpty()) if (domainStrategy4Freedom.IsNotEmpty())
@ -1149,47 +1144,16 @@ public class CoreConfigV2rayService
var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
if (outbound != null) if (outbound != null)
{ {
outbound.settings = new(); outbound.settings = new()
outbound.settings.domainStrategy = domainStrategy4Freedom;
outbound.settings.userLevel = 0;
}
}
var obj = JsonUtils.ParseJson(normalDNS);
if (obj is null)
{
List<string> 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)
{ {
foreach (var host in systemHosts) domainStrategy = domainStrategy4Freedom,
{ userLevel = 0
if (normalHost[host.Key] != null) };
continue;
normalHost[host.Key] = host.Value;
}
}
} }
} }
await GenDnsDomains(node, obj, item); await GenDnsServers(node, v2rayConfig, dNSItem);
await GenDnsHosts(v2rayConfig, dNSItem);
v2rayConfig.dns = obj;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1198,54 +1162,200 @@ public class CoreConfigV2rayService
return 0; return 0;
} }
private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem) private async Task<int> GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, DNSItem dNSItem)
{ {
if (node == null) var directDomainList = new List<string>();
var directGeositeList = new List<string>();
var proxyDomainList = new List<string>();
var proxyGeositeList = new List<string>();
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{ {
return 0; var rules = JsonUtils.Deserialize<List<RulesItem>>(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<string>();
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 if (Utils.IsDomain(node.Address))
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile); {
if (nextNode is not null directDomainList.Add(node.Address);
&& nextNode.ConfigType != EConfigType.Custom }
&& nextNode.ConfigType != EConfigType.Hysteria2 var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
&& nextNode.ConfigType != EConfigType.TUIC if (subItem is not null)
&& Utils.IsDomain(nextNode.Address)) {
// 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<object>();
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<int> 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<string, List<string>>();
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<string> { 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, var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
skipFallback = true, return parts[0];
domains = domainList },
}; line =>
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer)); {
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); return await Task.FromResult(0);

View File

@ -6,111 +6,81 @@ namespace ServiceLib.ViewModels;
public class DNSSettingViewModel : MyReactiveObject public class DNSSettingViewModel : MyReactiveObject
{ {
[Reactive] public bool UseSystemHosts { get; set; } [Reactive] public bool? UseSystemHosts { get; set; }
[Reactive] public string DomainStrategy4Freedom { get; set; } [Reactive] public bool? AddCommonHosts { get; set; }
[Reactive] public string DomainDNSAddress { get; set; } [Reactive] public bool? FakeIP { get; set; }
[Reactive] public string NormalDNS { get; set; } [Reactive] public bool? BlockBindingQuery { get; set; }
[Reactive] public string? DirectDNS { get; set; }
[Reactive] public string DomainStrategy4Freedom2 { get; set; } [Reactive] public string? RemoteDNS { get; set; }
[Reactive] public string DomainDNSAddress2 { get; set; } [Reactive] public string? SingboxOutboundsResolveDNS { get; set; }
[Reactive] public string NormalDNS2 { get; set; } [Reactive] public string? SingboxFinalResolveDNS { get; set; }
[Reactive] public string TunDNS2 { 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<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; } //public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
public ReactiveCommand<Unit, Unit> ImportDefConfig4SingboxCmd { get; } //public ReactiveCommand<Unit, Unit> ImportDefConfig4SingboxCmd { get; }
public DNSSettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView) public DNSSettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
{ {
_config = AppHandler.Instance.Config; _config = AppHandler.Instance.Config;
_updateView = updateView; _updateView = updateView;
SaveCmd = ReactiveCommand.CreateFromTask(async () => SaveCmd = ReactiveCommand.CreateFromTask(SaveSettingAsync);
{
await SaveSettingAsync();
});
ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () => //ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () =>
{ //{
NormalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName); // NormalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
await Task.CompletedTask; // await Task.CompletedTask;
}); //});
ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () => //ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () =>
{ //{
NormalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName); // NormalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName);
TunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName); // TunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName);
await Task.CompletedTask; // await Task.CompletedTask;
}); //});
_ = Init(); _ = Init();
} }
private async Task Init() private async Task Init()
{ {
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray); _config = AppHandler.Instance.Config;
var item = _config.DNSItem;
UseSystemHosts = item.UseSystemHosts; UseSystemHosts = item.UseSystemHosts;
DomainStrategy4Freedom = item?.DomainStrategy4Freedom ?? string.Empty; AddCommonHosts = item.AddCommonHosts;
DomainDNSAddress = item?.DomainDNSAddress ?? string.Empty; FakeIP = item.FakeIP;
NormalDNS = item?.NormalDNS ?? string.Empty; BlockBindingQuery = item.BlockBindingQuery;
DirectDNS = item.DirectDNS;
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); RemoteDNS = item.RemoteDNS;
DomainStrategy4Freedom2 = item2?.DomainStrategy4Freedom ?? string.Empty; RayStrategy4Freedom = item.RayStrategy4Freedom;
DomainDNSAddress2 = item2?.DomainDNSAddress ?? string.Empty; SingboxOutboundsResolveDNS = item.SingboxOutboundsResolveDNS;
NormalDNS2 = item2?.NormalDNS ?? string.Empty; SingboxFinalResolveDNS = item.SingboxFinalResolveDNS;
TunDNS2 = item2?.TunDNS ?? string.Empty; SingboxStrategy4Direct = item.SingboxStrategy4Direct;
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
Hosts = item.Hosts;
} }
private async Task SaveSettingAsync() 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); await _updateView(EViewAction.CloseWindow, null);
if (obj != null && obj["servers"] != null)
{
}
else
{
if (NormalDNS.Contains('{') || NormalDNS.Contains('}'))
{
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
return;
}
}
} }
if (NormalDNS2.IsNotEmpty())
{
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(NormalDNS2);
if (obj2 == null)
{
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
return;
}
}
if (TunDNS2.IsNotEmpty())
{
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(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);
} }
} }

View File

@ -219,7 +219,6 @@ public class MainWindowViewModel : MyReactiveObject
_config.UiItem.ShowInTaskbar = true; _config.UiItem.ShowInTaskbar = true;
await ConfigHandler.InitBuiltinRouting(_config); await ConfigHandler.InitBuiltinRouting(_config);
await ConfigHandler.InitBuiltinDNS(_config);
await ProfileExHandler.Instance.Init(); await ProfileExHandler.Instance.Init();
await CoreHandler.Instance.Init(_config, UpdateHandler); await CoreHandler.Instance.Init(_config, UpdateHandler);
TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler); TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler);

View File

@ -35,147 +35,220 @@
</StackPanel> </StackPanel>
<TabControl HorizontalContentAlignment="Stretch"> <TabControl HorizontalContentAlignment="Stretch">
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}"> <TabItem Header="{x:Static resx:ResUI.ThBasicDNSSettings}">
<DockPanel Margin="{StaticResource Margin8}"> <ScrollViewer VerticalScrollBarVisibility="Visible">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <Grid
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" /> Text="{x:Static resx:ResUI.TbDomesticDNS}" />
<ComboBox
x:Name="cmbDirectDNS"
Grid.Row="0"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center"> <TextBlock
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click"> Grid.Row="1"
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" /> Grid.Column="0"
</HyperlinkButton>
</TextBlock>
<Button
x:Name="btnImportDefConfig4V2ray"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}" VerticalAlignment="Center"
Cursor="Hand" /> Text="{x:Static resx:ResUI.TbRemoteDNS}" />
</StackPanel> <ComboBox
x:Name="cmbRemoteDNS"
Grid.Row="1"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <TextBlock
<StackPanel Orientation="Horizontal"> Grid.Row="2"
<TextBlock Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" /> Text="{x:Static resx:ResUI.TbSBOutboundsResolverDNS}" />
<ToggleSwitch <ComboBox
x:Name="togUseSystemHosts" x:Name="cmbSBResolverDNS"
Margin="{StaticResource Margin4}" Grid.Row="2"
HorizontalAlignment="Left" /> Grid.Column="1"
</StackPanel> Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="2"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}" />
<StackPanel Orientation="Horizontal"> <TextBlock
<TextBlock Grid.Row="3"
Margin="{StaticResource Margin4}" Grid.Column="0"
VerticalAlignment="Center" Margin="{StaticResource Margin4}"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" /> VerticalAlignment="Center"
<ComboBox Text="{x:Static resx:ResUI.TbSBDoHResolverServer}" />
x:Name="cmbdomainStrategy4Freedom" <ComboBox
Width="150" x:Name="cmbSBFinalResolverDNS"
Margin="{StaticResource Margin4}" /> Grid.Row="3"
</StackPanel> Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
<StackPanel Orientation="Horizontal"> <TextBlock
<TextBlock Grid.Row="4"
Margin="{StaticResource Margin4}" Grid.Column="0"
VerticalAlignment="Center" Margin="{StaticResource Margin4}"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" /> VerticalAlignment="Center"
<ComboBox Text="{x:Static resx:ResUI.TbXrayFreedomResolveStrategy}" />
x:Name="cmbdomainDNSAddress" <ComboBox
Width="150" x:Name="cmbRayFreedomDNSStrategy"
Margin="{StaticResource Margin4}" /> Grid.Row="4"
</StackPanel> Grid.Column="1"
</WrapPanel> Width="200"
Margin="{StaticResource Margin4}"
PlaceholderText="Default" />
<HeaderedContentControl <TextBlock
Margin="{StaticResource Margin4}" Grid.Row="5"
BorderBrush="Gray" Grid.Column="0"
BorderThickness="1" Margin="{StaticResource Margin4}"
Header="HTTP/SOCKS"> VerticalAlignment="Center"
<TextBox Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
Name="txtnormalDNS" <ComboBox
VerticalAlignment="Stretch" x:Name="cmbSBDirectDNSStrategy"
Classes="TextArea" Grid.Row="5"
MinLines="10" Grid.Column="1"
TextWrapping="Wrap" /> Width="200"
</HeaderedContentControl> Margin="{StaticResource Margin4}"
</DockPanel> PlaceholderText="Default" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
<ComboBox
x:Name="cmbSBRemoteDNSStrategy"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
PlaceholderText="Default" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleSwitch
x:Name="togAddCommonHosts"
Grid.Row="7"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBDoHOverride}" />
</Grid>
</ScrollViewer>
</TabItem> </TabItem>
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}"> <TabItem Header="{x:Static resx:ResUI.ThAdvancedDNSSettings}">
<DockPanel Margin="{StaticResource Margin8}"> <ScrollViewer VerticalScrollBarVisibility="Visible">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <Grid
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center"> Margin="{StaticResource Margin4}"
<HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click"> ColumnDefinitions="Auto,Auto,*"
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" /> RowDefinitions="Auto,Auto,Auto,Auto,*">
</HyperlinkButton>
</TextBlock>
<Button
x:Name="btnImportDefConfig4Singbox"
Margin="{StaticResource Margin4}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Cursor="Hand" />
</StackPanel>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <TextBlock
<StackPanel Orientation="Horizontal"> Grid.Row="0"
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
<ComboBox
x:Name="cmbdomainStrategy4Out"
Width="150"
Margin="{StaticResource Margin4}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
<ComboBox
x:Name="cmbdomainDNSAddress2"
Width="150"
Margin="{StaticResource Margin4}" />
</StackPanel>
</WrapPanel>
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
<HeaderedContentControl
Grid.Column="0" Grid.Column="0"
BorderBrush="Gray" Margin="{StaticResource Margin4}"
BorderThickness="1" VerticalAlignment="Center"
Header="HTTP/SOCKS"> Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
<TextBox <ToggleSwitch
Name="txtnormalDNS2" x:Name="togUseSystemHosts"
VerticalAlignment="Stretch" Grid.Row="0"
Classes="TextArea" Grid.Column="1"
MinLines="10" Margin="{StaticResource Margin4}"
TextWrapping="Wrap" /> HorizontalAlignment="Left" />
</HeaderedContentControl>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> <TextBlock
Grid.Row="1"
<HeaderedContentControl Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleSwitch
x:Name="togFakeIP"
Grid.Row="1"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="1"
Grid.Column="2" Grid.Column="2"
BorderBrush="Gray" Margin="{StaticResource Margin4}"
BorderThickness="1" VerticalAlignment="Center"
Header="{x:Static resx:ResUI.TbSettingsTunMode}"> Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}" />
<TextBox
Name="txttunDNS2"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl>
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
<ToggleSwitch
x:Name="togBlockBindingQuery"
Grid.Row="2"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="2"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
<TextBox
x:Name="txtHosts"
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}"
VerticalAlignment="Stretch"
Watermark="{x:Static resx:ResUI.TbDNSHostsConfig}"
BorderThickness="1"
Classes="TextArea"
TextWrapping="Wrap" />
</Grid> </Grid>
</DockPanel> </ScrollViewer>
</TabItem> </TabItem>
</TabControl> </TabControl>
</DockPanel> </DockPanel>

View File

@ -17,26 +17,30 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
btnCancel.Click += (s, e) => this.Close(); btnCancel.Click += (s, e) => this.Close();
ViewModel = new DNSSettingViewModel(UpdateViewHandler); ViewModel = new DNSSettingViewModel(UpdateViewHandler);
cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms; cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out; cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress; cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
cmbSBResolverDNS.ItemsSource = Global.DomainDirectDNSAddress.Concat(new[] { "dhcp://auto" });
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbSBFinalResolverDNS.ItemsSource = Global.DomainPureIPDNSAddress;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.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.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
}); });
} }

View File

@ -41,167 +41,269 @@
</StackPanel> </StackPanel>
<TabControl HorizontalContentAlignment="Left"> <TabControl HorizontalContentAlignment="Left">
<TabItem Header="{x:Static resx:ResUI.ThBasicDNSSettings}">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid Margin="{StaticResource Margin8}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
<DockPanel Margin="{StaticResource Margin8}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock <TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" /> Text="{x:Static resx:ResUI.TbDomesticDNS}" />
<ComboBox
x:Name="cmbDirectDNS"
Grid.Row="0"
Grid.Column="1"
Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"> Style="{StaticResource ToolbarTextBlock}"
<Hyperlink Click="linkDnsObjectDoc_Click"> Text="{x:Static resx:ResUI.TbRemoteDNS}" />
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" /> <ComboBox
<materialDesign:PackIcon Kind="Link" /> x:Name="cmbRemoteDNS"
</Hyperlink> Grid.Row="1"
</TextBlock> Grid.Column="1"
<Button Width="200"
x:Name="btnImportDefConfig4V2ray" IsEditable="True"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}" Style="{StaticResource DefComboBox}" />
Cursor="Hand"
Style="{StaticResource DefButton}" />
</StackPanel>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <TextBlock
<StackPanel Orientation="Horizontal"> Grid.Row="2"
<TextBlock Grid.Column="0"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" /> Text="{x:Static resx:ResUI.TbSBOutboundsResolverDNS}" />
<ToggleButton <ComboBox
x:Name="togUseSystemHosts" x:Name="cmbSBResolverDNS"
Margin="{StaticResource Margin8}" Grid.Row="2"
HorizontalAlignment="Left" /> Grid.Column="1"
</StackPanel> Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="2"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}" />
<StackPanel Orientation="Horizontal"> <TextBlock
<TextBlock Grid.Row="3"
Margin="{StaticResource Margin8}" Grid.Column="0"
VerticalAlignment="Center" Margin="{StaticResource Margin8}"
Style="{StaticResource ToolbarTextBlock}" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" /> Style="{StaticResource ToolbarTextBlock}"
<ComboBox Text="{x:Static resx:ResUI.TbSBDoHResolverServer}" />
x:Name="cmbdomainStrategy4Freedom" <ComboBox
Width="150" x:Name="cmbSBFinalResolverDNS"
Margin="{StaticResource Margin8}" Grid.Row="3"
Style="{StaticResource DefComboBox}" /> Grid.Column="1"
</StackPanel> Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
<StackPanel Orientation="Horizontal"> <TextBlock
<TextBlock Grid.Row="4"
Margin="{StaticResource Margin8}" Grid.Column="0"
VerticalAlignment="Center" Margin="{StaticResource Margin8}"
Style="{StaticResource ToolbarTextBlock}" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" /> Style="{StaticResource ToolbarTextBlock}"
<ComboBox Text="{x:Static resx:ResUI.TbXrayFreedomResolveStrategy}" />
x:Name="cmbdomainDNSAddress" <ComboBox
Width="150" x:Name="cmbRayFreedomDNSStrategy"
Margin="{StaticResource Margin8}" Grid.Row="4"
IsEditable="True" Grid.Column="1"
Style="{StaticResource DefComboBox}" /> Width="200"
</StackPanel> Margin="{StaticResource Margin8}"
</WrapPanel> materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" />
<TextBox <TextBlock
x:Name="txtnormalDNS" Grid.Row="5"
Margin="{StaticResource Margin8}" Grid.Column="0"
VerticalAlignment="Stretch" Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="HTTP/SOCKS" VerticalAlignment="Center"
AcceptsReturn="True" Style="{StaticResource ToolbarTextBlock}"
BorderThickness="1" Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
Style="{StaticResource MaterialDesignOutlinedTextBox}" <ComboBox
TextWrapping="Wrap" x:Name="cmbSBDirectDNSStrategy"
VerticalScrollBarVisibility="Auto" /> Grid.Row="5"
</DockPanel> Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
<ComboBox
x:Name="cmbSBRemoteDNSStrategy"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleButton
x:Name="togAddCommonHosts"
Grid.Row="7"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="7"
Grid.Column="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBDoHOverride}" />
</Grid>
</ScrollViewer>
</TabItem> </TabItem>
<TabItem Header="{x:Static resx:ResUI.ThAdvancedDNSSettings}">
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}"> <ScrollViewer VerticalScrollBarVisibility="Visible">
<DockPanel Margin="{StaticResource Margin8}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkDnsSingboxObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<Button
x:Name="btnImportDefConfig4Singbox"
Margin="{StaticResource Margin8}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Cursor="Hand"
Style="{StaticResource DefButton}" />
</StackPanel>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
<ComboBox
x:Name="cmbdomainStrategy4Out"
Width="150"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
<ComboBox
x:Name="cmbdomainDNSAddress2"
Width="150"
Margin="{StaticResource Margin8}"
IsEditable="True"
Style="{StaticResource DefComboBox}" />
</StackPanel>
</WrapPanel>
<Grid Margin="{StaticResource Margin8}"> <Grid Margin="{StaticResource Margin8}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox <TextBlock
x:Name="txtnormalDNS2" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Stretch" Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="HTTP/SOCKS" VerticalAlignment="Center"
AcceptsReturn="True" Style="{StaticResource ToolbarTextBlock}"
BorderThickness="1" Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
Style="{StaticResource MaterialDesignOutlinedTextBox}" <ToggleButton
TextWrapping="Wrap" x:Name="togUseSystemHosts"
VerticalScrollBarVisibility="Auto" /> Grid.Row="0"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> <TextBlock
Grid.Row="1"
<TextBox Grid.Column="0"
x:Name="txttunDNS2" Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleButton
x:Name="togFakeIP"
Grid.Row="1"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="1"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
<ToggleButton
x:Name="togBlockBindingQuery"
Grid.Row="2"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="2"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
<TextBox
x:Name="txtHosts"
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbSettingsTunMode}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbDNSHostsConfig}"
AcceptsReturn="True" AcceptsReturn="True"
BorderThickness="1" BorderThickness="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}" Style="{StaticResource MaterialDesignOutlinedTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</Grid> </Grid>
</DockPanel> </ScrollViewer>
</TabItem> </TabItem>
</TabControl> </TabControl>
</DockPanel> </DockPanel>

View File

@ -17,26 +17,30 @@ public partial class DNSSettingWindow
ViewModel = new DNSSettingViewModel(UpdateViewHandler); ViewModel = new DNSSettingViewModel(UpdateViewHandler);
cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms; cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out; cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress; cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
cmbSBResolverDNS.ItemsSource = Global.DomainDirectDNSAddress.Concat(new[] { "dhcp://auto" });
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbSBFinalResolverDNS.ItemsSource = Global.DomainPureIPDNSAddress;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.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.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme);
} }