Compare commits

..

41 commits

Author SHA1 Message Date
DHR60
aba816425d Avoids detour for private networks 2025-08-07 17:45:28 +08:00
DHR60
7f6399933a Add Detour Feature 2025-08-07 17:45:28 +08:00
DHR60
1a27599d28 Adjust Avalonia UI 2025-08-07 17:45:28 +08:00
DHR60
f4d6ac24af Fixes 2025-08-07 17:45:28 +08:00
DHR60
50706a13c7 Adjust UI 2025-08-07 17:45:28 +08:00
DHR60
5f5da59573 Fixes TypeInfoResolver Exception 2025-08-07 17:45:28 +08:00
DHR60
a5735895c6 Feat. custom config 2025-08-07 17:45:28 +08:00
DHR60
47779e433d Updates translations 2025-08-07 17:38:00 +08:00
DHR60
c5f222bf58 Updates sing-box documentation link 2025-08-07 17:38:00 +08:00
DHR60
1945d9b798 Fixes 2025-08-07 17:38:00 +08:00
DHR60
2e283eb00e Adds anytls reality support 2025-08-07 17:38:00 +08:00
DHR60
00505c7c17 Deletes Duplicate Rules 2025-08-07 17:38:00 +08:00
DHR60
9229b491c5 Adds sing-box DomainStrategy support 2025-08-07 17:38:00 +08:00
DHR60
d9b0aff8da Adds tag resolver supports 2025-08-07 17:38:00 +08:00
DHR60
8ea39d7475 Support sing-box hosts 2025-08-07 17:38:00 +08:00
DHR60
f14f39f5a1 Removes Wireguard listen port 2025-08-07 17:38:00 +08:00
DHR60
228069f499 Adds properties to Rule4Sbox class 2025-08-07 17:38:00 +08:00
DHR60
645e4e7711 Improves DNS address parsing in Singbox
DNS type, host, port, and path
2025-08-07 17:38:00 +08:00
DHR60
d1c16ecb72 Removes direct clash_mode domain strategy 2025-08-07 17:38:00 +08:00
DHR60
dca737bdad Fixes wrong field 2025-08-07 17:38:00 +08:00
DHR60
7f5489c5f7 fix singbox endpoints proxy chain not work 2025-08-07 17:38:00 +08:00
DHR60
3be0b312d6 Fixes config generation 2025-08-07 17:38:00 +08:00
DHR60
b290a38ef4 Refactors DNS address parsing 2025-08-07 17:38:00 +08:00
DHR60
70bdb3de16 Adds IPv4 preference to DNS configurations
对应原dns.servers[].strategy = prefer_ipv4
2025-08-07 17:38:00 +08:00
DHR60
8f9d1951a2 Adds Sing-box legacy DNS config support 2025-08-07 17:38:00 +08:00
DHR60
e2faf61a8b Utils.GetFreePort() default port to be zero 2025-08-07 17:38:00 +08:00
DHR60
3824879d38 support Wireguard endpoint
Refactors Singbox config classes for dial fields
2025-08-07 17:38:00 +08:00
DHR60
d54433aeb3 Fetches DNS strategy for domain resolution 2025-08-07 17:37:59 +08:00
DHR60
26b2240779 Enables dhcp interface configuration 2025-08-07 17:37:59 +08:00
DHR60
98a5caa47f Simplifies local DNS address handling 2025-08-07 17:37:59 +08:00
DHR60
d77c25aef5 add anytls support 2025-08-07 17:37:59 +08:00
DHR60
7affcf97b1 Improves geoip rule handling in singbox 2025-08-07 17:37:59 +08:00
DHR60
9e1e5eb2aa Adds Google cn dns rules 2025-08-07 17:37:59 +08:00
DHR60
d1928d80c7 Migrating to singbox 1.12 support 2025-08-07 17:37:59 +08:00
DHR60
ea55dfb6c5 Removes unnecessary sniffer 2025-08-07 17:37:59 +08:00
DHR60
b3acb89c29 Migrating to singbox 1.11 support 2025-08-07 17:37:59 +08:00
DHR60
922cf54d93 Revert "Temporary addition to support proper use of sing-box v1.12"
This reverts commit 508eb24fc3.
2025-08-07 17:37:48 +08:00
2dust
c669e72189 up 7.13.7
Some checks failed
release Linux / build (Release) (push) Has been cancelled
release macOS / build (Release) (push) Has been cancelled
release Windows desktop (Avalonia UI) / build (Release) (push) Has been cancelled
release Windows / build (Release) (push) Has been cancelled
2025-08-07 13:35:16 +08:00
2dust
46db5efef3 Update Directory.Packages.props 2025-08-07 13:30:36 +08:00
2dust
610418b42b In the Desktop version, the information box uses SelectableTextBlock to replace TextBox
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
https://github.com/2dust/v2rayN/issues/7644
2025-08-06 21:01:06 +08:00
2dust
508eb24fc3 Temporary addition to support proper use of sing-box v1.12
Some checks failed
release Linux / build (Release) (push) Has been cancelled
release macOS / build (Release) (push) Has been cancelled
release Windows desktop (Avalonia UI) / build (Release) (push) Has been cancelled
release Windows / build (Release) (push) Has been cancelled
https://github.com/2dust/v2rayN/issues/7698
2025-08-05 19:31:48 +08:00
27 changed files with 422 additions and 2354 deletions

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.13.6</Version> <Version>7.13.7</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -5,10 +5,10 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled> <CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.2" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.3" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.2" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.3" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.2" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.3" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.2" /> <PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.3" />
<PackageVersion Include="CliWrap" Version="3.9.0" /> <PackageVersion Include="CliWrap" Version="3.9.0" />
<PackageVersion Include="Downloader" Version="4.0.2" /> <PackageVersion Include="Downloader" Version="4.0.2" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />

View file

@ -128,8 +128,5 @@ public class JsonUtils
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <returns></returns>
public static JsonNode? SerializeToNode(object? obj, JsonSerializerOptions? options = null) public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
{
return JsonSerializer.SerializeToNode(obj, options);
}
} }

View file

@ -76,13 +76,6 @@ public class Global
public const int SpeedTestPageSize = 1000; public const int SpeedTestPageSize = 1000;
public const string LinuxBash = "/bin/bash"; public const string LinuxBash = "/bin/bash";
public const string SingboxDirectDNSTag = "direct_dns";
public const string SingboxRemoteDNSTag = "remote_dns";
public const string SingboxOutboundResolverTag = "outbound_resolver";
public const string SingboxFinalResolverTag = "final_resolver";
public const string SingboxHostsDNSTag = "hosts_dns";
public const string SingboxFakeDNSTag = "fake_dns";
public static readonly List<string> IEProxyProtocols = public static readonly List<string> IEProxyProtocols =
[ [
"{ip}:{http_port}", "{ip}:{http_port}",
@ -358,44 +351,27 @@ 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> DomainDirectDNSAddress = public static readonly List<string> DomainDNSAddress =
[
"https://dns.alidns.com/dns-query",
"https://doh.pub/dns-query",
"223.5.5.5",
"119.29.29.29",
"localhost"
];
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",
"119.29.29.29", "223.6.6.6",
"localhost" "localhost"
]; ];
public static readonly List<string> SingboxDomainDNSAddress =
[
"223.5.5.5",
"223.6.6.6",
"dhcp://auto"
];
public static readonly List<string> Languages = public static readonly List<string> Languages =
[ [
"zh-Hans", "zh-Hans",
@ -563,30 +539,5 @@ 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" } }
};
public static readonly List<string> ExpectedIPs =
[
"geoip:cn",
"geoip:ir",
"geoip:ru",
""
];
#endregion const #endregion const
} }

View file

@ -112,11 +112,6 @@ public class ConfigHandler
config.ConstItem ??= new ConstItem(); config.ConstItem ??= new ConstItem();
if (config.SimpleDNSItem == null)
{
InitBuiltinSimpleDNS(config);
}
config.SpeedTestItem ??= new(); config.SpeedTestItem ??= new();
if (config.SpeedTestItem.SpeedTestTimeout < 10) if (config.SpeedTestItem.SpeedTestTimeout < 10)
{ {
@ -2099,38 +2094,18 @@ public class ConfigHandler
/// <summary> /// <summary>
/// Initialize built-in DNS configurations /// Initialize built-in DNS configurations
/// Creates default DNS items for V2Ray and sing-box /// Creates default DNS items for V2Ray and sing-box
/// Also checks existing DNS items and disables those with empty NormalDNS
/// </summary> /// </summary>
/// <param name="config">Current configuration</param> /// <param name="config">Current configuration</param>
/// <returns>0 if successful</returns> /// <returns>0 if successful</returns>
public static async Task<int> InitBuiltinDNS(Config config) public static async Task<int> InitBuiltinDNS(Config config)
{ {
var items = await AppHandler.Instance.DNSItems(); var items = await AppHandler.Instance.DNSItems();
// Check existing DNS items and disable those with empty NormalDNS
var needsUpdate = false;
foreach (var existingItem in items)
{
if (existingItem.NormalDNS.IsNullOrEmpty() && existingItem.Enabled)
{
existingItem.Enabled = false;
needsUpdate = true;
}
}
// Update items if any changes were made
if (needsUpdate)
{
await SQLiteHelper.Instance.UpdateAllAsync(items);
}
if (items.Count <= 0) if (items.Count <= 0)
{ {
var item = new DNSItem() var item = new DNSItem()
{ {
Remarks = "V2ray", Remarks = "V2ray",
CoreType = ECoreType.Xray, CoreType = ECoreType.Xray,
Enabled = false,
}; };
await SaveDNSItems(config, item); await SaveDNSItems(config, item);
@ -2138,7 +2113,6 @@ public class ConfigHandler
{ {
Remarks = "sing-box", Remarks = "sing-box",
CoreType = ECoreType.sing_box, CoreType = ECoreType.sing_box,
Enabled = false,
}; };
await SaveDNSItems(config, item2); await SaveDNSItems(config, item2);
} }
@ -2210,38 +2184,6 @@ public class ConfigHandler
#endregion DNS #endregion DNS
#region Simple DNS
public static int InitBuiltinSimpleDNS(Config config)
{
config.SimpleDNSItem = new SimpleDNSItem()
{
UseSystemHosts = false,
AddCommonHosts = true,
FakeIP = false,
BlockBindingQuery = true,
DirectDNS = Global.DomainDirectDNSAddress.FirstOrDefault(),
RemoteDNS = Global.DomainRemoteDNSAddress.FirstOrDefault(),
SingboxOutboundsResolveDNS = Global.DomainDirectDNSAddress.FirstOrDefault(),
SingboxFinalResolveDNS = Global.DomainPureIPDNSAddress.FirstOrDefault()
};
return 0;
}
public static async Task<SimpleDNSItem> GetExternalSimpleDNSItem(string url)
{
var downloadHandle = new DownloadService();
var templateContent = await downloadHandle.TryDownloadString(url, true, "");
if (templateContent.IsNullOrEmpty())
return null;
var template = JsonUtils.Deserialize<SimpleDNSItem>(templateContent);
if (template == null)
return null;
return template;
}
#endregion Simple DNS
#region Custom Config #region Custom Config
public static async Task<int> InitBuiltinCustomConfig(Config config) public static async Task<int> InitBuiltinCustomConfig(Config config)
@ -2311,8 +2253,6 @@ public class ConfigHandler
await SQLiteHelper.Instance.DeleteAllAsync<DNSItem>(); await SQLiteHelper.Instance.DeleteAllAsync<DNSItem>();
await InitBuiltinDNS(config); await InitBuiltinDNS(config);
InitBuiltinSimpleDNS(config);
return true; return true;
case EPresetType.Russia: case EPresetType.Russia:
@ -2323,8 +2263,6 @@ public class ConfigHandler
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"));
config.SimpleDNSItem = await GetExternalSimpleDNSItem(Global.DNSTemplateSources[1] + "simple_dns.json");
return true; return true;
case EPresetType.Iran: case EPresetType.Iran:
@ -2335,8 +2273,6 @@ public class ConfigHandler
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"));
config.SimpleDNSItem = await GetExternalSimpleDNSItem(Global.DNSTemplateSources[2] + "simple_dns.json");
return true; return true;
} }

View file

@ -48,7 +48,6 @@ 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 SimpleDNSItem SimpleDNSItem { get; set; }
#endregion other entities #endregion other entities
} }

View file

@ -253,21 +253,3 @@ 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 SimpleDNSItem
{
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; }
public string? DirectExpectedIPs { get; set; }
}

View file

@ -9,7 +9,7 @@ public class DNSItem
public string Id { get; set; } public string Id { get; set; }
public string Remarks { get; set; } public string Remarks { get; set; }
public bool Enabled { get; set; } = false; public bool Enabled { get; set; } = true;
public ECoreType CoreType { get; set; } public ECoreType CoreType { get; set; }
public bool UseSystemHosts { get; set; } public bool UseSystemHosts { get; set; }
public string? NormalDNS { get; set; } public string? NormalDNS { get; set; }

View file

@ -36,7 +36,6 @@ 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; }
@ -76,7 +75,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<int>? query_type { get; set; } public List<object>? 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; }
@ -238,7 +237,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, List<string>>? predefined { get; set; } public Dictionary<string, object>? predefined { get; set; }
// Deprecated // Deprecated
public string? address { get; set; } public string? address { get; set; }
public string? address_resolver { get; set; } public string? address_resolver { get; set; }

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 Dns4Ray dns { get; set; } public object 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,8 +203,7 @@ public class Response4Ray
public class Dns4Ray public class Dns4Ray
{ {
public Dictionary<string, List<string>>? hosts { get; set; } public List<string> servers { get; set; }
public List<object> servers { get; set; }
} }
public class DnsServer4Ray public class DnsServer4Ray
@ -212,8 +211,6 @@ public class DnsServer4Ray
public string? address { get; set; } public string? address { get; set; }
public List<string>? domains { get; set; } public List<string>? domains { get; set; }
public bool? skipFallback { get; set; } public bool? skipFallback { get; set; }
public List<string>? expectedIPs { get; set; }
public List<string>? unexpectedIPs { get; set; }
} }
public class Routing4Ray public class Routing4Ray

View file

@ -1,4 +1,4 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// 此代码由工具生成。 // 此代码由工具生成。
// 运行时版本:4.0.30319.42000 // 运行时版本:4.0.30319.42000
@ -2238,15 +2238,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Add Common DNS Hosts 的本地化字符串。
/// </summary>
public static string TbAddCommonDNSHosts {
get {
return ResourceManager.GetString("TbAddCommonDNSHosts", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Do Not Add Non-Proxy Protocol Outbound 的本地化字符串。 /// 查找类似 Do Not Add Non-Proxy Protocol Outbound 的本地化字符串。
/// </summary> /// </summary>
@ -2292,15 +2283,6 @@ 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>
@ -2328,15 +2310,6 @@ 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>
@ -2445,15 +2418,6 @@ 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>
@ -2499,15 +2463,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Domestic DNS 的本地化字符串。
/// </summary>
public static string TbDomesticDNS {
get {
return ResourceManager.GetString("TbDomesticDNS", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Edit 的本地化字符串。 /// 查找类似 Edit 的本地化字符串。
/// </summary> /// </summary>
@ -2526,15 +2481,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 FakeIP 的本地化字符串。
/// </summary>
public static string TbFakeIP {
get {
return ResourceManager.GetString("TbFakeIP", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Fingerprint 的本地化字符串。 /// 查找类似 Fingerprint 的本地化字符串。
/// </summary> /// </summary>
@ -2733,15 +2679,6 @@ 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>
@ -2796,15 +2733,6 @@ 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>
@ -3939,33 +3867,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Validate Regional Domain IPs 的本地化字符串。
/// </summary>
public static string TbValidateDirectExpectedIPs {
get {
return ResourceManager.GetString("TbValidateDirectExpectedIPs", resourceCulture);
}
}
/// <summary>
/// 查找类似 When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs 的本地化字符串。
/// </summary>
public static string TbValidateDirectExpectedIPsDesc {
get {
return ResourceManager.GetString("TbValidateDirectExpectedIPsDesc", resourceCulture);
}
}
/// <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>
@ -3975,24 +3876,6 @@ 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

@ -1404,75 +1404,6 @@
<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>The sing-box DoH resolution server can be overwritten</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>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Regional Domain IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="FillCorrectConfigText" xml:space="preserve">
<value>Please fill in the correct custom config</value>
</data>
<data name="menuCustomConfig" xml:space="preserve"> <data name="menuCustomConfig" xml:space="preserve">
<value>Custom Config</value> <value>Custom Config</value>
</data> </data>

View file

@ -1404,75 +1404,6 @@
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>[Anytls] konfiguráció hozzáadása</value> <value>[Anytls] konfiguráció hozzáadása</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>The sing-box DoH resolution server can be overwritten</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>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Regional Domain IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="FillCorrectConfigText" xml:space="preserve">
<value>Please fill in the correct custom config</value>
</data>
<data name="menuCustomConfig" xml:space="preserve"> <data name="menuCustomConfig" xml:space="preserve">
<value>Custom Config</value> <value>Custom Config</value>
</data> </data>

View file

@ -1404,75 +1404,6 @@
<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>The sing-box DoH resolution server can be overwritten</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>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Regional Domain IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="FillCorrectConfigText" xml:space="preserve">
<value>Please fill in the correct custom config</value>
</data>
<data name="menuCustomConfig" xml:space="preserve"> <data name="menuCustomConfig" xml:space="preserve">
<value>Custom Config</value> <value>Custom Config</value>
</data> </data>

View file

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
Version 2.0 Version 2.0
The primary goals of this format is to allow a simple XML format The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes various data types are done through the TypeConverter classes
associated with the data types. associated with the data types.
Example: Example:
... ado.net/XML headers & schema ... ... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader> <resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader> <resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment> <comment>This is a comment</comment>
</data> </data>
There are any number of "resheader" rows that contain simple There are any number of "resheader" rows that contain simple
name/value pairs. name/value pairs.
Each data row contains a name, and value. The row also contains a Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture. text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the Classes that don't support this are serialized and stored with the
mimetype set. mimetype set.
The mimetype is used for serialized objects, and tells the The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly: extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below. read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64 mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64 mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64 mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
--> -->
@ -807,6 +807,9 @@
<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>
@ -966,9 +969,6 @@
<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>
@ -1404,75 +1404,6 @@
<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>The sing-box DoH resolution server can be overwritten</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>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Regional Domain IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="FillCorrectConfigText" xml:space="preserve">
<value>Please fill in the correct custom config</value>
</data>
<data name="menuCustomConfig" xml:space="preserve"> <data name="menuCustomConfig" xml:space="preserve">
<value>Custom Config</value> <value>Custom Config</value>
</data> </data>

View file

@ -1401,75 +1401,6 @@
<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 解析sing-box</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>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>校验相应地区域名 IP</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>配置后,会对相应地区域名(如 geosite:cn的返回 IP 进行校验,仅返回期望 IP</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>启用自定义 DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>自定义 DNS 已启用,此页面配置将无效</value>
</data>
<data name="FillCorrectConfigText" xml:space="preserve">
<value>请填写正确的自定义配置</value>
</data>
<data name="menuCustomConfig" xml:space="preserve"> <data name="menuCustomConfig" xml:space="preserve">
<value>自定义配置</value> <value>自定义配置</value>
</data> </data>

View file

@ -1401,75 +1401,6 @@
<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>The sing-box DoH resolution server can be overwritten</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>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Regional Domain IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="FillCorrectConfigText" xml:space="preserve">
<value>Please fill in the correct custom config</value>
</data>
<data name="menuCustomConfig" xml:space="preserve"> <data name="menuCustomConfig" xml:space="preserve">
<value>Custom Config</value> <value>Custom Config</value>
</data> </data>

View file

@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Data; using System.Data;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
@ -76,7 +75,7 @@ public class CoreConfigSingboxService
await GenRouting(singboxConfig); await GenRouting(singboxConfig);
await GenDns(singboxConfig); await GenDns(node, singboxConfig);
await GenExperimental(singboxConfig); await GenExperimental(singboxConfig);
@ -248,20 +247,20 @@ public class CoreConfigSingboxService
singboxConfig.route.rules.Add(rule); singboxConfig.route.rules.Add(rule);
} }
var rawDNSItem = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); await GenDnsDomains(null, singboxConfig, null);
if (rawDNSItem != null && rawDNSItem.Enabled == true) //var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
{ //if (dnsServer != null)
await GenDnsDomainsCompatible(singboxConfig, rawDNSItem); //{
} // dnsServer.detour = singboxConfig.route.rules.LastOrDefault()?.outbound;
else //}
{ //var dnsRule = singboxConfig.dns?.rules.Where(t => t.outbound != null).FirstOrDefault();
await GenDnsDomains(singboxConfig, _config.SimpleDNSItem); //if (dnsRule != null)
} //{
singboxConfig.route.default_domain_resolver = new() // singboxConfig.dns.rules = [];
{ // singboxConfig.dns.rules.Add(dnsRule);
server = Global.SingboxFinalResolverTag //}
};
//ret.Msg =string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
ret.Success = true; ret.Success = true;
ret.Data = JsonUtils.Serialize(singboxConfig); ret.Data = JsonUtils.Serialize(singboxConfig);
return ret; return ret;
@ -320,19 +319,7 @@ public class CoreConfigSingboxService
await GenOutbound(node, singboxConfig.outbounds.First()); await GenOutbound(node, singboxConfig.outbounds.First());
} }
await GenMoreOutbounds(node, singboxConfig); await GenMoreOutbounds(node, singboxConfig);
var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); await GenDnsDomains(null, singboxConfig, null);
if (item != null && item.Enabled == true)
{
await GenDnsDomainsCompatible(singboxConfig, item);
}
else
{
await GenDnsDomains(singboxConfig, _config.SimpleDNSItem);
}
singboxConfig.route.default_domain_resolver = new()
{
server = Global.SingboxFinalResolverTag
};
singboxConfig.route.rules.Clear(); singboxConfig.route.rules.Clear();
singboxConfig.inbounds.Clear(); singboxConfig.inbounds.Clear();
@ -434,7 +421,7 @@ public class CoreConfigSingboxService
} }
await GenOutboundsList(proxyProfiles, singboxConfig); await GenOutboundsList(proxyProfiles, singboxConfig);
await GenDns(singboxConfig); await GenDns(null, singboxConfig);
await ConvertGeo2Ruleset(singboxConfig); await ConvertGeo2Ruleset(singboxConfig);
ret.Success = true; ret.Success = true;
@ -667,6 +654,17 @@ 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:
@ -801,6 +799,17 @@ 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:
@ -1247,22 +1256,6 @@ public class CoreConfigSingboxService
try try
{ {
singboxConfig.route.final = Global.ProxyTag; singboxConfig.route.final = Global.ProxyTag;
var item = _config.SimpleDNSItem;
var defaultDomainResolverTag = Global.SingboxOutboundResolverTag;
var directDNSStrategy = item.SingboxStrategy4Direct.IsNullOrEmpty() ? Global.SingboxDomainStrategy4Out.FirstOrDefault() : item.SingboxStrategy4Direct;
var rawDNSItem = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
if (rawDNSItem != null && rawDNSItem.Enabled == true)
{
defaultDomainResolverTag = Global.SingboxFinalResolverTag;
directDNSStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? Global.SingboxDomainStrategy4Out.FirstOrDefault() : rawDNSItem.DomainStrategy4Freedom;
}
singboxConfig.route.default_domain_resolver = new()
{
server = defaultDomainResolverTag,
strategy = directDNSStrategy
};
if (_config.TunModeItem.EnableTun) if (_config.TunModeItem.EnableTun)
{ {
@ -1343,14 +1336,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 item1 in rules ?? []) foreach (var item in rules ?? [])
{ {
if (item1.Enabled) if (item.Enabled)
{ {
await GenRoutingUserRule(item1, singboxConfig); await GenRoutingUserRule(item, singboxConfig);
if (item1.Ip != null && item1.Ip.Count > 0) if (item.Ip != null && item.Ip.Count > 0)
{ {
ipRules.Add(item1); ipRules.Add(item);
} }
} }
} }
@ -1358,9 +1351,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 item2 in ipRules) foreach (var item in ipRules)
{ {
await GenRoutingUserRule(item2, singboxConfig); await GenRoutingUserRule(item, singboxConfig);
} }
} }
} }
@ -1603,278 +1596,7 @@ public class CoreConfigSingboxService
return server.tag; return server.tag;
} }
private async Task<int> GenDns(SingboxConfig singboxConfig) private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
{
try
{
var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
if (item != null && item.Enabled == true)
{
return await GenDnsCompatible(singboxConfig);
}
var simpleDNSItem = _config.SimpleDNSItem;
await GenDnsServers(singboxConfig, simpleDNSItem);
await GenDnsRules(singboxConfig, simpleDNSItem);
singboxConfig.dns ??= new Dns4Sbox();
singboxConfig.dns.independent_cache = true;
var routing = await ConfigHandler.GetDefaultRouting(_config);
var useDirectDns = false;
if (routing != null)
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
useDirectDns = rules?.LastOrDefault() is { } lastRule &&
lastRule.OutboundTag == Global.DirectTag &&
(lastRule.Port == "0-65535" ||
lastRule.Network == "tcp,udp" ||
lastRule.Ip?.Contains("0.0.0.0/0") == true);
}
singboxConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return 0;
}
private async Task<int> GenDnsServers(SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem)
{
var finalDns = await GenDnsDomains(singboxConfig, simpleDNSItem);
var directDns = ParseDnsAddress(simpleDNSItem.DirectDNS);
directDns.tag = Global.SingboxDirectDNSTag;
directDns.domain_resolver = Global.SingboxFinalResolverTag;
var remoteDns = ParseDnsAddress(simpleDNSItem.RemoteDNS);
remoteDns.tag = Global.SingboxRemoteDNSTag;
remoteDns.detour = Global.ProxyTag;
remoteDns.domain_resolver = Global.SingboxFinalResolverTag;
var resolverDns = ParseDnsAddress(simpleDNSItem.SingboxOutboundsResolveDNS);
resolverDns.tag = Global.SingboxOutboundResolverTag;
resolverDns.domain_resolver = Global.SingboxFinalResolverTag;
var hostsDns = new Server4Sbox
{
tag = Global.SingboxHostsDNSTag,
type = "hosts",
};
if (simpleDNSItem.AddCommonHosts == true)
{
hostsDns.predefined = Global.PredefinedHosts;
}
var userHostsMap = simpleDNSItem.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)
{
foreach (var kvp in userHostsMap)
{
hostsDns.predefined[kvp.Key] = kvp.Value;
}
}
foreach (var host in hostsDns.predefined)
{
if (finalDns.server == host.Key)
{
finalDns.domain_resolver = Global.SingboxHostsDNSTag;
}
if (remoteDns.server == host.Key)
{
remoteDns.domain_resolver = Global.SingboxHostsDNSTag;
}
if (resolverDns.server == host.Key)
{
resolverDns.domain_resolver = Global.SingboxHostsDNSTag;
}
if (directDns.server == host.Key)
{
directDns.domain_resolver = Global.SingboxHostsDNSTag;
}
}
singboxConfig.dns ??= new Dns4Sbox();
singboxConfig.dns.servers ??= new List<Server4Sbox>();
singboxConfig.dns.servers.Add(remoteDns);
singboxConfig.dns.servers.Add(directDns);
singboxConfig.dns.servers.Add(resolverDns);
singboxConfig.dns.servers.Add(hostsDns);
// fake ip
if (simpleDNSItem.FakeIP == true)
{
var fakeip = new Server4Sbox
{
tag = Global.SingboxFakeDNSTag,
type = "fakeip",
inet4_range = "198.18.0.0/15",
inet6_range = "fc00::/18",
};
singboxConfig.dns.servers.Add(fakeip);
}
return await Task.FromResult(0);
}
private async Task<Server4Sbox> GenDnsDomains(SingboxConfig singboxConfig, SimpleDNSItem? simpleDNSItem)
{
var finalDns = ParseDnsAddress(simpleDNSItem.SingboxFinalResolveDNS);
finalDns.tag = Global.SingboxFinalResolverTag;
singboxConfig.dns ??= new Dns4Sbox();
singboxConfig.dns.servers ??= new List<Server4Sbox>();
singboxConfig.dns.servers.Add(finalDns);
return await Task.FromResult(finalDns);
}
private async Task<int> GenDnsRules(SingboxConfig singboxConfig, SimpleDNSItem simpleDNSItem)
{
singboxConfig.dns ??= new Dns4Sbox();
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
singboxConfig.dns.rules.AddRange(new[]
{
new Rule4Sbox { ip_accept_any = true, server = Global.SingboxHostsDNSTag },
new Rule4Sbox
{
server = Global.SingboxRemoteDNSTag,
strategy = simpleDNSItem.SingboxStrategy4Proxy.IsNullOrEmpty() ? null : simpleDNSItem.SingboxStrategy4Proxy,
clash_mode = ERuleMode.Global.ToString()
},
new Rule4Sbox
{
server = Global.SingboxDirectDNSTag,
strategy = simpleDNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : simpleDNSItem.SingboxStrategy4Direct,
clash_mode = ERuleMode.Direct.ToString()
}
});
if (simpleDNSItem.BlockBindingQuery == true)
{
singboxConfig.dns.rules.Add(new()
{
query_type = new List<int> { 64, 65 },
action = "predefined",
rcode = "NOTIMP"
});
}
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing == null)
return 0;
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
var expectedIPCidr = new List<string>();
var expectedIPsRegions = new List<string>();
var regionNames = new HashSet<string>();
if (!string.IsNullOrEmpty(simpleDNSItem?.DirectExpectedIPs))
{
var ipItems = simpleDNSItem.DirectExpectedIPs
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim())
.Where(s => !string.IsNullOrEmpty(s))
.ToList();
foreach (var ip in ipItems)
{
if (ip.StartsWith("geoip:", StringComparison.OrdinalIgnoreCase))
{
var region = ip["geoip:".Length..];
if (!string.IsNullOrEmpty(region))
{
expectedIPsRegions.Add(region);
regionNames.Add(region);
regionNames.Add($"geolocation-{region}");
regionNames.Add($"tld-{region}");
}
}
else
{
expectedIPCidr.Add(ip);
}
}
}
foreach (var item in rules)
{
if (!item.Enabled || item.Domain is null || item.Domain.Count == 0)
{
continue;
}
var rule = new Rule4Sbox();
var validDomains = item.Domain.Count(it => ParseV2Domain(it, rule));
if (validDomains <= 0)
{
continue;
}
if (item.OutboundTag == Global.DirectTag)
{
rule.server = Global.SingboxDirectDNSTag;
rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Direct) ? null : simpleDNSItem.SingboxStrategy4Direct;
if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0)
{
var geositeSet = new HashSet<string>(rule.geosite);
if (regionNames.Intersect(geositeSet).Any())
{
if (expectedIPsRegions.Count > 0)
{
rule.geoip = expectedIPsRegions;
}
if (expectedIPCidr.Count > 0)
{
rule.ip_cidr = expectedIPCidr;
}
}
}
}
else if (item.OutboundTag == Global.ProxyTag)
{
if (simpleDNSItem.FakeIP == true)
{
var rule4Fake = JsonUtils.DeepCopy(rule);
rule4Fake.server = Global.SingboxFakeDNSTag;
singboxConfig.dns.rules.Add(rule4Fake);
}
rule.server = Global.SingboxRemoteDNSTag;
rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Proxy) ? null : simpleDNSItem.SingboxStrategy4Proxy;
}
else if (item.OutboundTag == Global.BlockTag)
{
rule.action = "predefined";
rule.rcode = "NOERROR";
rule.answer = new List<string> { "A" };
}
singboxConfig.dns.rules.Add(rule);
}
return 0;
}
private async Task<int> GenDnsCompatible(SingboxConfig singboxConfig)
{ {
try try
{ {
@ -1898,11 +1620,11 @@ public class CoreConfigSingboxService
if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty()) if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty())
{ {
await GenDnsDomainsCompatible(singboxConfig, item); await GenDnsDomains(node, singboxConfig, item);
} }
else else
{ {
await GenDnsDomainsLegacyCompatible(singboxConfig, item); await GenDnsDomainsLegacy(node, singboxConfig, item);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -1912,35 +1634,86 @@ public class CoreConfigSingboxService
return 0; return 0;
} }
private async Task<int> GenDnsDomainsCompatible(SingboxConfig singboxConfig, DNSItem? dNSItem) private async Task<int> GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
{ {
var dns4Sbox = singboxConfig.dns ?? new(); var dns4Sbox = singboxConfig.dns ?? new();
dns4Sbox.servers ??= []; dns4Sbox.servers ??= [];
dns4Sbox.rules ??= []; dns4Sbox.rules ??= [];
var tag = Global.SingboxFinalResolverTag; var tag = "local_resolver";
var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress; var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress;
var localDnsServer = ParseDnsAddress(localDnsAddress); if (localDnsAddress.StartsWith("tag://"))
localDnsServer.tag = tag; {
tag = localDnsAddress.Substring(6);
dns4Sbox.servers.Add(localDnsServer); var localDnsTag = "local_local";
dns4Sbox.servers.Add(new()
{
tag = localDnsTag,
type = "local"
});
dns4Sbox.rules.Insert(0, new()
{
server = localDnsTag,
clash_mode = ERuleMode.Direct.ToString()
});
}
else
{
var (dnsType, dnsHost, dnsPort, dnsPath) = ParseDnsAddress(localDnsAddress);
dns4Sbox.servers.Add(new()
{
tag = tag,
type = dnsType,
server = dnsHost,
Interface = dnsType == "dhcp" ? dnsHost : null,
server_port = dnsPort,
path = dnsPath
});
dns4Sbox.rules.Insert(0, new()
{
server = tag,
clash_mode = ERuleMode.Direct.ToString()
});
}
dns4Sbox.rules.Insert(0, new()
{
server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote",
clash_mode = ERuleMode.Global.ToString()
});
//Tun2SocksAddress
if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni))
{
dns4Sbox.rules.Insert(0, new()
{
server = tag,
domain = [node?.Sni],
strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom
});
}
singboxConfig.dns = dns4Sbox; singboxConfig.dns = dns4Sbox;
return await Task.FromResult(0); return await Task.FromResult(0);
} }
private async Task<int> GenDnsDomainsLegacyCompatible(SingboxConfig singboxConfig, DNSItem? dNSItem) private async Task<int> GenDnsDomainsLegacy(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
{ {
var dns4Sbox = singboxConfig.dns ?? new(); var dns4Sbox = singboxConfig.dns ?? new();
dns4Sbox.servers ??= []; dns4Sbox.servers ??= [];
dns4Sbox.rules ??= []; dns4Sbox.rules ??= [];
var tag = Global.SingboxFinalResolverTag; var tag = "local_local";
dns4Sbox.servers.Add(new() dns4Sbox.servers.Add(new()
{ {
tag = tag, tag = tag,
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
detour = Global.DirectTag, detour = Global.DirectTag,
strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom, strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom,
}); });
@ -1969,100 +1742,103 @@ public class CoreConfigSingboxService
}); });
} }
//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; singboxConfig.dns = dns4Sbox;
return await Task.FromResult(0); return await Task.FromResult(0);
} }
private static Server4Sbox? ParseDnsAddress(string address) private (string type, string? host, int? port, string? path) ParseDnsAddress(string address)
{ {
var addressFirst = address?.Split(address.Contains(',') ? ',' : ';').FirstOrDefault()?.Trim(); string type = "udp";
if (string.IsNullOrEmpty(addressFirst)) string? host = null;
int? port = null;
string? path = null;
if (address is "local" or "localhost")
{ {
return null; return ("local", null, null, null);
} }
var server = new Server4Sbox(); if (address.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase))
if (addressFirst is "local" or "localhost")
{ {
server.type = "local"; string interface_name = address.Substring(7);
return server; return ("dhcp", interface_name == "auto" ? null : interface_name, null, null);
} }
if (addressFirst.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase)) if (!address.Contains("://"))
{
var interface_name = addressFirst.Substring(7);
server.type = "dhcp";
server.Interface = interface_name == "auto" ? null : interface_name;
return server;
}
if (!addressFirst.Contains("://"))
{ {
// udp dns // udp dns
server.type = "udp"; host = address;
server.server = addressFirst; return (type, host, port, path);
return server;
} }
try try
{ {
var protocolEndIndex = addressFirst.IndexOf("://", StringComparison.Ordinal); int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal);
server.type = addressFirst.Substring(0, protocolEndIndex).ToLower(); type = address.Substring(0, protocolEndIndex).ToLower();
var uri = new Uri(addressFirst); var uri = new Uri(address);
server.server = uri.Host; host = uri.Host;
if (!uri.IsDefaultPort) if (!uri.IsDefaultPort)
{ {
server.server_port = uri.Port; port = uri.Port;
} }
if ((server.type == "https" || server.type == "h3") && !string.IsNullOrEmpty(uri.AbsolutePath) && uri.AbsolutePath != "/") if ((type == "https" || type == "h3") && !string.IsNullOrEmpty(uri.AbsolutePath) && uri.AbsolutePath != "/")
{ {
server.path = uri.AbsolutePath; path = uri.AbsolutePath;
} }
} }
catch (UriFormatException) catch (UriFormatException)
{ {
var protocolEndIndex = addressFirst.IndexOf("://", StringComparison.Ordinal); int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal);
if (protocolEndIndex > 0) if (protocolEndIndex > 0)
{ {
server.type = addressFirst.Substring(0, protocolEndIndex).ToLower(); type = address.Substring(0, protocolEndIndex).ToLower();
var remaining = addressFirst.Substring(protocolEndIndex + 3); string remaining = address.Substring(protocolEndIndex + 3);
var portIndex = remaining.IndexOf(':'); int portIndex = remaining.IndexOf(':');
var pathIndex = remaining.IndexOf('/'); int pathIndex = remaining.IndexOf('/');
if (portIndex > 0) if (portIndex > 0)
{ {
server.server = remaining.Substring(0, portIndex); host = remaining.Substring(0, portIndex);
var portPart = pathIndex > portIndex string 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 var parsedPort)) if (int.TryParse(portPart, out int parsedPort))
{ {
server.server_port = parsedPort; port = parsedPort;
} }
} }
else if (pathIndex > 0) else if (pathIndex > 0)
{ {
server.server = remaining.Substring(0, pathIndex); host = remaining.Substring(0, pathIndex);
} }
else else
{ {
server.server = remaining; host = remaining;
} }
if (pathIndex > 0 && (server.type == "https" || server.type == "h3")) if (pathIndex > 0 && (type == "https" || type == "h3"))
{ {
server.path = remaining.Substring(pathIndex); path = remaining.Substring(pathIndex);
} }
} }
} }
return server; return (type, host, port, path);
} }
private async Task<int> GenExperimental(SingboxConfig singboxConfig) private async Task<int> GenExperimental(SingboxConfig singboxConfig)
@ -2082,8 +1858,7 @@ public class CoreConfigSingboxService
singboxConfig.experimental.cache_file = new CacheFile4Sbox() singboxConfig.experimental.cache_file = new CacheFile4Sbox()
{ {
enabled = true, enabled = true,
path = Utils.GetBinPath("cache.db"), path = Utils.GetBinPath("cache.db")
store_fakeip = _config.SimpleDNSItem.FakeIP == true
}; };
} }
@ -2104,15 +1879,13 @@ public class CoreConfigSingboxService
//convert route geosite & geoip to ruleset //convert route geosite & geoip to ruleset
foreach (var rule in singboxConfig.route.rules.Where(t => t.geosite?.Count > 0).ToList() ?? []) foreach (var rule in singboxConfig.route.rules.Where(t => t.geosite?.Count > 0).ToList() ?? [])
{ {
rule.rule_set ??= new List<string>(); rule.rule_set = rule?.geosite?.Select(t => $"{geosite}-{t}").ToList();
rule.rule_set.AddRange(rule?.geosite?.Select(t => $"{geosite}-{t}").ToList());
rule.geosite = null; rule.geosite = null;
AddRuleSets(ruleSets, rule.rule_set); AddRuleSets(ruleSets, rule.rule_set);
} }
foreach (var rule in singboxConfig.route.rules.Where(t => t.geoip?.Count > 0).ToList() ?? []) foreach (var rule in singboxConfig.route.rules.Where(t => t.geoip?.Count > 0).ToList() ?? [])
{ {
rule.rule_set ??= new List<string>(); rule.rule_set = rule?.geoip?.Select(t => $"{geoip}-{t}").ToList();
rule.rule_set.AddRange(rule?.geoip?.Select(t => $"{geoip}-{t}").ToList());
rule.geoip = null; rule.geoip = null;
AddRuleSets(ruleSets, rule.rule_set); AddRuleSets(ruleSets, rule.rule_set);
} }
@ -2120,14 +1893,12 @@ public class CoreConfigSingboxService
//convert dns geosite & geoip to ruleset //convert dns geosite & geoip to ruleset
foreach (var rule in singboxConfig.dns?.rules.Where(t => t.geosite?.Count > 0).ToList() ?? []) foreach (var rule in singboxConfig.dns?.rules.Where(t => t.geosite?.Count > 0).ToList() ?? [])
{ {
rule.rule_set ??= new List<string>(); rule.rule_set = rule?.geosite?.Select(t => $"{geosite}-{t}").ToList();
rule.rule_set.AddRange(rule?.geosite?.Select(t => $"{geosite}-{t}").ToList());
rule.geosite = null; rule.geosite = null;
} }
foreach (var rule in singboxConfig.dns?.rules.Where(t => t.geoip?.Count > 0).ToList() ?? []) foreach (var rule in singboxConfig.dns?.rules.Where(t => t.geoip?.Count > 0).ToList() ?? [])
{ {
rule.rule_set ??= new List<string>(); rule.rule_set = rule?.geoip?.Select(t => $"{geoip}-{t}").ToList();
rule.rule_set.AddRange(rule?.geoip?.Select(t => $"{geoip}-{t}").ToList());
rule.geoip = null; rule.geoip = null;
} }
foreach (var dnsRule in singboxConfig.dns?.rules.Where(t => t.rule_set?.Count > 0).ToList() ?? []) foreach (var dnsRule in singboxConfig.dns?.rules.Where(t => t.rule_set?.Count > 0).ToList() ?? [])

View file

@ -1,6 +1,5 @@
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using ServiceLib.Models; using ServiceLib.Models;
@ -1141,264 +1140,6 @@ public class CoreConfigV2rayService
} }
private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig) private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
{
try
{
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
if (item != null && item.Enabled == true)
{
return await GenDnsCompatible(node, v2rayConfig);
}
var simpleDNSItem = _config.SimpleDNSItem;
var domainStrategy4Freedom = simpleDNSItem?.RayStrategy4Freedom;
//Outbound Freedom domainStrategy
if (domainStrategy4Freedom.IsNotEmpty())
{
var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
if (outbound != null)
{
outbound.settings = new()
{
domainStrategy = domainStrategy4Freedom,
userLevel = 0
};
}
}
await GenDnsServers(node, v2rayConfig, simpleDNSItem);
await GenDnsHosts(v2rayConfig, simpleDNSItem);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return 0;
}
private async Task<int> GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem)
{
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
{
var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';')
.Select(addr => addr.Trim())
.Where(addr => !string.IsNullOrEmpty(addr))
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
.Distinct()
.ToList() ?? new List<string> { defaultAddress };
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
}
static object CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
{
var dnsServer = new DnsServer4Ray
{
address = dnsAddress,
skipFallback = true,
domains = domains.Count > 0 ? domains : null,
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
};
return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
});
}
var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.FirstOrDefault());
var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.FirstOrDefault());
var directDomainList = new List<string>();
var directGeositeList = new List<string>();
var proxyDomainList = new List<string>();
var proxyGeositeList = new List<string>();
var expectedDomainList = new List<string>();
var expectedIPs = new List<string>();
var regionNames = new HashSet<string>();
if (!string.IsNullOrEmpty(simpleDNSItem?.DirectExpectedIPs))
{
expectedIPs = simpleDNSItem.DirectExpectedIPs
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim())
.Where(s => !string.IsNullOrEmpty(s))
.ToList();
foreach (var ip in expectedIPs)
{
if (ip.StartsWith("geoip:", StringComparison.OrdinalIgnoreCase))
{
var region = ip["geoip:".Length..];
if (!string.IsNullOrEmpty(region))
{
regionNames.Add($"geosite:{region}");
regionNames.Add($"geosite:geolocation-{region}");
regionNames.Add($"geosite:tld-{region}");
}
}
}
}
var routing = await ConfigHandler.GetDefaultRouting(_config);
List<RulesItem>? rules = null;
if (routing != null)
{
rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
foreach (var item in rules)
{
if (!item.Enabled || item.Domain is null || item.Domain.Count == 0)
{
continue;
}
foreach (var domain in item.Domain)
{
if (domain.StartsWith('#'))
continue;
var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ",");
if (item.OutboundTag == Global.DirectTag)
{
if (normalizedDomain.StartsWith("geosite:"))
{
(regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain);
}
else
{
directDomainList.Add(normalizedDomain);
}
}
else if (item.OutboundTag == Global.ProxyTag)
{
if (normalizedDomain.StartsWith("geosite:"))
{
proxyGeositeList.Add(normalizedDomain);
}
else
{
proxyDomainList.Add(normalizedDomain);
}
}
}
}
}
if (Utils.IsDomain(node?.Address))
{
directDomainList.Add(node.Address);
}
if (node?.Subid is not null)
{
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
if (subItem is not null)
{
foreach (var profile in new[] { subItem.PrevProfile, subItem.NextProfile })
{
var profileNode = await AppHandler.Instance.GetProfileItemViaRemarks(profile);
if (profileNode is not null &&
profileNode.ConfigType is not (EConfigType.Custom or EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls) &&
Utils.IsDomain(profileNode.Address))
{
directDomainList.Add(profileNode.Address);
}
}
}
}
v2rayConfig.dns ??= new Dns4Ray();
v2rayConfig.dns.servers ??= new List<object>();
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
{
if (domains.Count > 0)
{
foreach (var dnsAddress in dnsAddresses)
{
v2rayConfig.dns.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
}
}
}
AddDnsServers(remoteDNSAddress, proxyDomainList);
AddDnsServers(directDNSAddress, directDomainList);
AddDnsServers(remoteDNSAddress, proxyGeositeList);
AddDnsServers(directDNSAddress, directGeositeList);
AddDnsServers(directDNSAddress, expectedDomainList, expectedIPs);
var useDirectDns = rules?.LastOrDefault() is { } lastRule &&
lastRule.OutboundTag == Global.DirectTag &&
(lastRule.Port == "0-65535" ||
lastRule.Network == "tcp,udp" ||
lastRule.Ip?.Contains("0.0.0.0/0") == true);
var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress;
v2rayConfig.dns.servers.AddRange(defaultDnsServers);
return 0;
}
private async Task<int> GenDnsHosts(V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem)
{
if (simpleDNSItem.AddCommonHosts == false && simpleDNSItem.UseSystemHosts == false && simpleDNSItem.Hosts.IsNullOrEmpty())
{
return await Task.FromResult(0);
}
v2rayConfig.dns ??= new Dns4Ray();
v2rayConfig.dns.hosts ??= new Dictionary<string, List<string>>();
if (simpleDNSItem.AddCommonHosts == true)
{
v2rayConfig.dns.hosts = Global.PredefinedHosts;
}
if (simpleDNSItem.UseSystemHosts == true)
{
var systemHosts = Utils.GetSystemHosts();
if (systemHosts.Count > 0)
{
var normalHost = v2rayConfig.dns.hosts;
if (normalHost != null)
{
foreach (var host in systemHosts)
{
if (normalHost[host.Key] != null)
{
continue;
}
normalHost[host.Key] = new List<string> { host.Value };
}
}
}
}
var userHostsMap = simpleDNSItem.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)
{
foreach (var kvp in userHostsMap)
{
v2rayConfig.dns.hosts[kvp.Key] = kvp.Value;
}
}
return await Task.FromResult(0);
}
private async Task<int> GenDnsCompatible(ProfileItem? node, V2rayConfig v2rayConfig)
{ {
try try
{ {
@ -1441,33 +1182,22 @@ public class CoreConfigV2rayService
var systemHosts = Utils.GetSystemHosts(); var systemHosts = Utils.GetSystemHosts();
if (systemHosts.Count > 0) if (systemHosts.Count > 0)
{ {
var normalHost1 = obj["hosts"]; var normalHost = obj["hosts"];
if (normalHost1 != null) if (normalHost != null)
{ {
foreach (var host in systemHosts) foreach (var host in systemHosts)
{ {
if (normalHost1[host.Key] != null) if (normalHost[host.Key] != null)
continue; continue;
normalHost1[host.Key] = host.Value; normalHost[host.Key] = host.Value;
} }
} }
} }
} }
var normalHost = obj["hosts"];
if (normalHost != null)
{
foreach (var hostProp in normalHost.AsObject().ToList())
{
if (hostProp.Value is JsonValue value && value.TryGetValue<string>(out var ip))
{
normalHost[hostProp.Key] = new JsonArray(ip);
}
}
}
await GenDnsDomainsCompatible(node, obj, item); await GenDnsDomains(node, obj, item);
v2rayConfig.dns = JsonUtils.Deserialize<Dns4Ray>(JsonUtils.Serialize(obj)); v2rayConfig.dns = obj;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1476,7 +1206,7 @@ public class CoreConfigV2rayService
return 0; return 0;
} }
private async Task<int> GenDnsDomainsCompatible(ProfileItem? node, JsonNode dns, DNSItem? dNSItem) private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
{ {
if (node == null) if (node == null)
{ {
@ -1499,6 +1229,7 @@ public class CoreConfigV2rayService
&& prevNode.ConfigType != EConfigType.Custom && prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2 && prevNode.ConfigType != EConfigType.Hysteria2
&& prevNode.ConfigType != EConfigType.TUIC && prevNode.ConfigType != EConfigType.TUIC
&& prevNode.ConfigType != EConfigType.Anytls
&& Utils.IsDomain(prevNode.Address)) && Utils.IsDomain(prevNode.Address))
{ {
domainList.Add(prevNode.Address); domainList.Add(prevNode.Address);
@ -1510,6 +1241,7 @@ public class CoreConfigV2rayService
&& nextNode.ConfigType != EConfigType.Custom && nextNode.ConfigType != EConfigType.Custom
&& nextNode.ConfigType != EConfigType.Hysteria2 && nextNode.ConfigType != EConfigType.Hysteria2
&& nextNode.ConfigType != EConfigType.TUIC && nextNode.ConfigType != EConfigType.TUIC
&& nextNode.ConfigType != EConfigType.Anytls
&& Utils.IsDomain(nextNode.Address)) && Utils.IsDomain(nextNode.Address))
{ {
domainList.Add(nextNode.Address); domainList.Add(nextNode.Address);
@ -1519,7 +1251,7 @@ public class CoreConfigV2rayService
{ {
var dnsServer = new DnsServer4Ray() var dnsServer = new DnsServer4Ray()
{ {
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
skipFallback = true, skipFallback = true,
domains = domainList domains = domainList
}; };

View file

@ -6,52 +6,39 @@ 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 bool? AddCommonHosts { get; set; } [Reactive] public string DomainStrategy4Freedom { get; set; }
[Reactive] public bool? FakeIP { get; set; } [Reactive] public string DomainDNSAddress { get; set; }
[Reactive] public bool? BlockBindingQuery { get; set; } [Reactive] public string NormalDNS { get; set; }
[Reactive] public string? DirectDNS { get; set; }
[Reactive] public string? RemoteDNS { get; set; }
[Reactive] public string? SingboxOutboundsResolveDNS { get; set; }
[Reactive] public string? SingboxFinalResolveDNS { get; set; }
[Reactive] public string? RayStrategy4Freedom { get; set; }
[Reactive] public string? SingboxStrategy4Direct { get; set; }
[Reactive] public string? SingboxStrategy4Proxy { get; set; }
[Reactive] public string? Hosts { get; set; }
[Reactive] public string? DirectExpectedIPs { get; set; }
[Reactive] public bool UseSystemHostsCompatible { get; set; } [Reactive] public string DomainStrategy4Freedom2 { get; set; }
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } [Reactive] public string DomainDNSAddress2 { get; set; }
[Reactive] public string DomainDNSAddressCompatible { get; set; } [Reactive] public string NormalDNS2 { get; set; }
[Reactive] public string NormalDNSCompatible { get; set; } [Reactive] public string TunDNS2 { get; set; }
[Reactive] public string DomainStrategy4Freedom2Compatible { get; set; }
[Reactive] public string DomainDNSAddress2Compatible { get; set; }
[Reactive] public string NormalDNS2Compatible { get; set; }
[Reactive] public string TunDNS2Compatible { get; set; }
[Reactive] public bool RayCustomDNSEnableCompatible { get; set; }
[Reactive] public bool SBCustomDNSEnableCompatible { get; set; }
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCompatibleCmd { get; } public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
public ReactiveCommand<Unit, Unit> ImportDefConfig4SingboxCompatibleCmd { 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(SaveSettingAsync); SaveCmd = ReactiveCommand.CreateFromTask(async () =>
ImportDefConfig4V2rayCompatibleCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
NormalDNSCompatible = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName); await SaveSettingAsync();
});
ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () =>
{
NormalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
await Task.CompletedTask; await Task.CompletedTask;
}); });
ImportDefConfig4SingboxCompatibleCmd = ReactiveCommand.CreateFromTask(async () => ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
NormalDNS2Compatible = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName); NormalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName);
TunDNS2Compatible = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName); TunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName);
await Task.CompletedTask; await Task.CompletedTask;
}); });
@ -60,80 +47,48 @@ public class DNSSettingViewModel : MyReactiveObject
private async Task Init() private async Task Init()
{ {
_config = AppHandler.Instance.Config; var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
var item = _config.SimpleDNSItem;
UseSystemHosts = item.UseSystemHosts; UseSystemHosts = item.UseSystemHosts;
AddCommonHosts = item.AddCommonHosts; DomainStrategy4Freedom = item?.DomainStrategy4Freedom ?? string.Empty;
FakeIP = item.FakeIP; DomainDNSAddress = item?.DomainDNSAddress ?? string.Empty;
BlockBindingQuery = item.BlockBindingQuery; NormalDNS = item?.NormalDNS ?? string.Empty;
DirectDNS = item.DirectDNS;
RemoteDNS = item.RemoteDNS;
RayStrategy4Freedom = item.RayStrategy4Freedom;
SingboxOutboundsResolveDNS = item.SingboxOutboundsResolveDNS;
SingboxFinalResolveDNS = item.SingboxFinalResolveDNS;
SingboxStrategy4Direct = item.SingboxStrategy4Direct;
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
Hosts = item.Hosts;
DirectExpectedIPs = item.DirectExpectedIPs;
var item1 = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
RayCustomDNSEnableCompatible = item1.Enabled;
UseSystemHostsCompatible = item1.UseSystemHosts;
DomainStrategy4FreedomCompatible = item1?.DomainStrategy4Freedom ?? string.Empty;
DomainDNSAddressCompatible = item1?.DomainDNSAddress ?? string.Empty;
NormalDNSCompatible = item1?.NormalDNS ?? string.Empty;
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
SBCustomDNSEnableCompatible = item2.Enabled; DomainStrategy4Freedom2 = item2?.DomainStrategy4Freedom ?? string.Empty;
DomainStrategy4Freedom2Compatible = item2?.DomainStrategy4Freedom ?? string.Empty; DomainDNSAddress2 = item2?.DomainDNSAddress ?? string.Empty;
DomainDNSAddress2Compatible = item2?.DomainDNSAddress ?? string.Empty; NormalDNS2 = item2?.NormalDNS ?? string.Empty;
NormalDNS2Compatible = item2?.NormalDNS ?? string.Empty; TunDNS2 = item2?.TunDNS ?? string.Empty;
TunDNS2Compatible = item2?.TunDNS ?? string.Empty;
} }
private async Task SaveSettingAsync() private async Task SaveSettingAsync()
{ {
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts; if (NormalDNS.IsNotEmpty())
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
_config.SimpleDNSItem.FakeIP = FakeIP;
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
_config.SimpleDNSItem.DirectDNS = DirectDNS;
_config.SimpleDNSItem.RemoteDNS = RemoteDNS;
_config.SimpleDNSItem.RayStrategy4Freedom = RayStrategy4Freedom;
_config.SimpleDNSItem.SingboxOutboundsResolveDNS = SingboxOutboundsResolveDNS;
_config.SimpleDNSItem.SingboxFinalResolveDNS = SingboxFinalResolveDNS;
_config.SimpleDNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct;
_config.SimpleDNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy;
_config.SimpleDNSItem.Hosts = Hosts;
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
if (NormalDNSCompatible.IsNotEmpty())
{ {
var obj = JsonUtils.ParseJson(NormalDNSCompatible); var obj = JsonUtils.ParseJson(NormalDNS);
if (obj != null && obj["servers"] != null) if (obj != null && obj["servers"] != null)
{ {
} }
else else
{ {
if (NormalDNSCompatible.Contains('{') || NormalDNSCompatible.Contains('}')) if (NormalDNS.Contains('{') || NormalDNS.Contains('}'))
{ {
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText); NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
return; return;
} }
} }
} }
if (NormalDNS2Compatible.IsNotEmpty()) if (NormalDNS2.IsNotEmpty())
{ {
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(NormalDNS2Compatible); var obj2 = JsonUtils.Deserialize<Dns4Sbox>(NormalDNS2);
if (obj2 == null) if (obj2 == null)
{ {
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText); NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
return; return;
} }
} }
if (TunDNS2Compatible.IsNotEmpty()) if (TunDNS2.IsNotEmpty())
{ {
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(TunDNS2Compatible); var obj2 = JsonUtils.Deserialize<Dns4Sbox>(TunDNS2);
if (obj2 == null) if (obj2 == null)
{ {
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText); NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
@ -141,26 +96,21 @@ public class DNSSettingViewModel : MyReactiveObject
} }
} }
var item1 = await AppHandler.Instance.GetDNSItem(ECoreType.Xray); var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
item1.Enabled = RayCustomDNSEnableCompatible; item.DomainStrategy4Freedom = DomainStrategy4Freedom;
item1.DomainStrategy4Freedom = DomainStrategy4FreedomCompatible; item.DomainDNSAddress = DomainDNSAddress;
item1.DomainDNSAddress = DomainDNSAddressCompatible; item.UseSystemHosts = UseSystemHosts;
item1.UseSystemHosts = UseSystemHostsCompatible; item.NormalDNS = NormalDNS;
item1.NormalDNS = NormalDNSCompatible; await ConfigHandler.SaveDNSItems(_config, item);
await ConfigHandler.SaveDNSItems(_config, item1);
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
item2.Enabled = RayCustomDNSEnableCompatible; item2.DomainStrategy4Freedom = DomainStrategy4Freedom2;
item2.DomainStrategy4Freedom = DomainStrategy4Freedom2Compatible; item2.DomainDNSAddress = DomainDNSAddress2;
item2.DomainDNSAddress = DomainDNSAddress2Compatible; item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(NormalDNS2));
item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(NormalDNS2Compatible)); item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(TunDNS2));
item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(TunDNS2Compatible));
await ConfigHandler.SaveDNSItems(_config, item2); await ConfigHandler.SaveDNSItems(_config, item2);
await ConfigHandler.SaveConfig(_config); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
if (_updateView != null) _ = _updateView?.Invoke(EViewAction.CloseWindow, null);
{
await _updateView(EViewAction.CloseWindow, null);
}
} }
} }

View file

@ -107,6 +107,7 @@ public class ThemeSettingViewModel : MyReactiveObject
x.OfType<Button>(), x.OfType<Button>(),
x.OfType<TextBox>(), x.OfType<TextBox>(),
x.OfType<TextBlock>(), x.OfType<TextBlock>(),
x.OfType<SelectableTextBlock>(),
x.OfType<Menu>(), x.OfType<Menu>(),
x.OfType<ContextMenu>(), x.OfType<ContextMenu>(),
x.OfType<DataGridRow>(), x.OfType<DataGridRow>(),
@ -146,6 +147,7 @@ public class ThemeSettingViewModel : MyReactiveObject
x.OfType<Button>(), x.OfType<Button>(),
x.OfType<TextBox>(), x.OfType<TextBox>(),
x.OfType<TextBlock>(), x.OfType<TextBlock>(),
x.OfType<SelectableTextBlock>(),
x.OfType<Menu>(), x.OfType<Menu>(),
x.OfType<ContextMenu>(), x.OfType<ContextMenu>(),
x.OfType<DataGridRow>(), x.OfType<DataGridRow>(),

View file

@ -2,7 +2,6 @@
x:Class="v2rayN.Desktop.Views.DNSSettingWindow" x:Class="v2rayN.Desktop.Views.DNSSettingWindow"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
@ -36,298 +35,25 @@
</StackPanel> </StackPanel>
<TabControl HorizontalContentAlignment="Stretch"> <TabControl HorizontalContentAlignment="Stretch">
<TabItem Header="{x:Static resx:ResUI.ThBasicDNSSettings}">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock
x:Name="txtBasicDNSSettingsInvalid"
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbCustomDNSEnabledPageInvalid}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDomesticDNS}" />
<ctrls:AutoCompleteBox
x:Name="cmbDirectDNS"
Grid.Row="1"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Text="{Binding DirectDNS, Mode=TwoWay}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRemoteDNS}" />
<ctrls:AutoCompleteBox
x:Name="cmbRemoteDNS"
Grid.Row="2"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Text="{Binding RemoteDNS, Mode=TwoWay}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBOutboundsResolverDNS}" />
<ctrls:AutoCompleteBox
x:Name="cmbSBResolverDNS"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Text="{Binding SingboxOutboundsResolveDNS, Mode=TwoWay}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBDoHResolverServer}" />
<ctrls:AutoCompleteBox
x:Name="cmbSBFinalResolverDNS"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Text="{Binding SingboxFinalResolveDNS, Mode=TwoWay}" />
<TextBlock
Grid.Row="4"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbXrayFreedomResolveStrategy}" />
<ComboBox
x:Name="cmbRayFreedomDNSStrategy"
Grid.Row="5"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
PlaceholderText="Default" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
<ComboBox
x:Name="cmbSBDirectDNSStrategy"
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.TbSBRemoteResolveStrategy}" />
<ComboBox
x:Name="cmbSBRemoteDNSStrategy"
Grid.Row="7"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
PlaceholderText="Default" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleSwitch
x:Name="togAddCommonHosts"
Grid.Row="8"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBDoHOverride}" />
</Grid>
</ScrollViewer>
</TabItem>
<TabItem Header="{x:Static resx:ResUI.ThAdvancedDNSSettings}">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,*">
<TextBlock
x:Name="txtAdvancedDNSSettingsInvalid"
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbCustomDNSEnabledPageInvalid}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
<ToggleSwitch
x:Name="togUseSystemHosts"
Grid.Row="1"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleSwitch
x:Name="togFakeIP"
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.TbApplyProxyDomainsOnly}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
<ToggleSwitch
x:Name="togBlockBindingQuery"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
<ctrls:AutoCompleteBox
x:Name="cmbDirectExpectedIPs"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Text="{Binding DirectExpectedIPs, Mode=TwoWay}" />
<TextBlock
Grid.Row="4"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
<TextBox
x:Name="txtHosts"
Grid.Row="6"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}"
VerticalAlignment="Stretch"
Watermark="{x:Static resx:ResUI.TbDNSHostsConfig}"
BorderThickness="1"
Classes="TextArea"
TextWrapping="Wrap" />
</Grid>
</ScrollViewer>
</TabItem>
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
<DockPanel Margin="{StaticResource Margin8}"> <DockPanel Margin="{StaticResource Margin8}">
<Grid DockPanel.Dock="Top"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Grid.RowDefinitions> <TextBlock
<RowDefinition Height="Auto" /> Margin="{StaticResource Margin4}"
<RowDefinition Height="Auto" /> VerticalAlignment="Center"
</Grid.RowDefinitions> Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbCustomDNSEnable}" />
<ToggleSwitch
x:Name="togRayCustomDNSEnableCompatible"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center"> <TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click"> <HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" /> <TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
</HyperlinkButton> </HyperlinkButton>
</TextBlock> </TextBlock>
<Button <Button
x:Name="btnImportDefConfig4V2rayCompatible" x:Name="btnImportDefConfig4V2ray"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}" Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Cursor="Hand" /> Cursor="Hand" />
</StackPanel> </StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@ -336,7 +62,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" /> Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
<ToggleSwitch <ToggleSwitch
x:Name="togUseSystemHostsCompatible" x:Name="togUseSystemHosts"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
</StackPanel> </StackPanel>
@ -347,7 +73,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" /> Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4FreedomCompatible" x:Name="cmbdomainStrategy4Freedom"
Width="150" Width="150"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}" />
</StackPanel> </StackPanel>
@ -357,11 +83,10 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" /> Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
<ctrls:AutoCompleteBox <ComboBox
x:Name="cmbdomainDNSAddressCompatible" x:Name="cmbdomainDNSAddress"
Width="150" Width="150"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}" />
Text="{Binding DomainDNSAddressCompatible, Mode=TwoWay}" />
</StackPanel> </StackPanel>
</WrapPanel> </WrapPanel>
@ -371,7 +96,7 @@
BorderThickness="1" BorderThickness="1"
Header="HTTP/SOCKS"> Header="HTTP/SOCKS">
<TextBox <TextBox
Name="txtnormalDNSCompatible" Name="txtnormalDNS"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Classes="TextArea" Classes="TextArea"
MinLines="10" MinLines="10"
@ -382,36 +107,18 @@
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}">
<DockPanel Margin="{StaticResource Margin8}"> <DockPanel Margin="{StaticResource Margin8}">
<Grid DockPanel.Dock="Top"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Grid.RowDefinitions> <TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
<RowDefinition Height="Auto" /> <HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click">
<RowDefinition Height="Auto" /> <TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
</Grid.RowDefinitions> </HyperlinkButton>
</TextBlock>
<StackPanel Grid.Row="0" Orientation="Horizontal"> <Button
<TextBlock x:Name="btnImportDefConfig4Singbox"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Text="{x:Static resx:ResUI.TbCustomDNSEnable}" /> Cursor="Hand" />
<ToggleSwitch </StackPanel>
x:Name="togSBCustomDNSEnableCompatible"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
</HyperlinkButton>
</TextBlock>
<Button
x:Name="btnImportDefConfig4SingboxCompatible"
Margin="{StaticResource Margin4}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Cursor="Hand" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@ -420,7 +127,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" /> Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4OutCompatible" x:Name="cmbdomainStrategy4Out"
Width="150" Width="150"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}" />
</StackPanel> </StackPanel>
@ -430,11 +137,10 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" /> Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
<ctrls:AutoCompleteBox <ComboBox
x:Name="cmbdomainDNSAddress2Compatible" x:Name="cmbdomainDNSAddress2"
Width="150" Width="150"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}" />
Text="{Binding DomainDNSAddress2Compatible, Mode=TwoWay}" />
</StackPanel> </StackPanel>
</WrapPanel> </WrapPanel>
@ -446,7 +152,7 @@
BorderThickness="1" BorderThickness="1"
Header="HTTP/SOCKS"> Header="HTTP/SOCKS">
<TextBox <TextBox
Name="txtnormalDNS2Compatible" Name="txtnormalDNS2"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Classes="TextArea" Classes="TextArea"
MinLines="10" MinLines="10"
@ -461,7 +167,7 @@
BorderThickness="1" BorderThickness="1"
Header="{x:Static resx:ResUI.TbSettingsTunMode}"> Header="{x:Static resx:ResUI.TbSettingsTunMode}">
<TextBox <TextBox
Name="txttunDNS2Compatible" Name="txttunDNS2"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Classes="TextArea" Classes="TextArea"
MinLines="10" MinLines="10"

View file

@ -1,5 +1,4 @@
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using ReactiveUI; using ReactiveUI;
using v2rayN.Desktop.Base; using v2rayN.Desktop.Base;
@ -18,64 +17,26 @@ 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);
cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms; cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms;
cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out; cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out; cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress;
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress;
cmbSBResolverDNS.ItemsSource = Global.DomainDirectDNSAddress.Concat(new[] { "dhcp://auto,localhost" });
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbSBFinalResolverDNS.ItemsSource = Global.DomainPureIPDNSAddress.Concat(new[] { "dhcp://auto,localhost" });
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4OutCompatible.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress;
cmbdomainDNSAddress2Compatible.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.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.SelectedValue).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.SelectedValue).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.Text).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.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.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.Bind(ViewModel, vm => vm.RayCustomDNSEnableCompatible, v => v.togRayCustomDNSEnableCompatible.IsChecked).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SBCustomDNSEnableCompatible, v => v.togSBCustomDNSEnableCompatible.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.UseSystemHostsCompatible, v => v.togUseSystemHostsCompatible.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4FreedomCompatible, v => v.cmbdomainStrategy4FreedomCompatible.SelectedItem).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.DomainDNSAddressCompatible, v => v.cmbdomainDNSAddressCompatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNSCompatible, v => v.txtnormalDNSCompatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2Compatible, v => v.cmbdomainStrategy4OutCompatible.SelectedItem).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.DomainDNSAddress2Compatible, v => v.cmbdomainDNSAddress2Compatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNS2Compatible, v => v.txtnormalDNS2Compatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDNS2Compatible, v => v.txttunDNS2Compatible.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCompatibleCmd, v => v.btnImportDefConfig4V2rayCompatible).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCompatibleCmd, v => v.btnImportDefConfig4SingboxCompatible).DisposeWith(disposables);
this.WhenAnyValue(
x => x.ViewModel.RayCustomDNSEnableCompatible,
x => x.ViewModel.SBCustomDNSEnableCompatible,
(ray, sb) => ray && sb
).BindTo(this.FindControl<TextBlock>("txtBasicDNSSettingsInvalid"), t => t.IsVisible);
this.WhenAnyValue(
x => x.ViewModel.RayCustomDNSEnableCompatible,
x => x.ViewModel.SBCustomDNSEnableCompatible,
(ray, sb) => ray && sb
).BindTo(this.FindControl<TextBlock>("txtAdvancedDNSSettingsInvalid"), t => t.IsVisible);
}); });
} }

View file

@ -69,34 +69,35 @@
IsChecked="True" IsChecked="True"
Theme="{DynamicResource SimpleToggleSwitch}" /> Theme="{DynamicResource SimpleToggleSwitch}" />
</WrapPanel> </WrapPanel>
<TextBox
Name="txtMsg" <ScrollViewer x:Name="msgScrollViewer" VerticalScrollBarVisibility="Auto">
VerticalAlignment="Stretch" <SelectableTextBlock
BorderThickness="0" Name="txtMsg"
Classes="TextArea" VerticalAlignment="Stretch"
IsReadOnly="True" Classes="TextArea"
TextAlignment="Left" TextAlignment="Left"
TextWrapping="Wrap"> TextWrapping="Wrap">
<TextBox.ContextMenu> <SelectableTextBlock.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem <MenuItem
x:Name="menuMsgViewSelectAll" x:Name="menuMsgViewSelectAll"
Click="menuMsgViewSelectAll_Click" Click="menuMsgViewSelectAll_Click"
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" /> Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopy" x:Name="menuMsgViewCopy"
Click="menuMsgViewCopy_Click" Click="menuMsgViewCopy_Click"
Header="{x:Static resx:ResUI.menuMsgViewCopy}" /> Header="{x:Static resx:ResUI.menuMsgViewCopy}" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopyAll" x:Name="menuMsgViewCopyAll"
Click="menuMsgViewCopyAll_Click" Click="menuMsgViewCopyAll_Click"
Header="{x:Static resx:ResUI.menuMsgViewCopyAll}" /> Header="{x:Static resx:ResUI.menuMsgViewCopyAll}" />
<MenuItem <MenuItem
x:Name="menuMsgViewClear" x:Name="menuMsgViewClear"
Click="menuMsgViewClear_Click" Click="menuMsgViewClear_Click"
Header="{x:Static resx:ResUI.menuMsgViewClear}" /> Header="{x:Static resx:ResUI.menuMsgViewClear}" />
</ContextMenu> </ContextMenu>
</TextBox.ContextMenu> </SelectableTextBlock.ContextMenu>
</TextBox> </SelectableTextBlock>
</ScrollViewer>
</DockPanel> </DockPanel>
</UserControl> </UserControl>

View file

@ -1,4 +1,5 @@
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
@ -9,9 +10,12 @@ namespace v2rayN.Desktop.Views;
public partial class MsgView : ReactiveUserControl<MsgViewModel> public partial class MsgView : ReactiveUserControl<MsgViewModel>
{ {
private readonly ScrollViewer _scrollViewer;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
_scrollViewer = this.FindControl<ScrollViewer>("msgScrollViewer");
ViewModel = new MsgViewModel(UpdateViewHandler); ViewModel = new MsgViewModel(UpdateViewHandler);
@ -43,14 +47,14 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
txtMsg.Text = msg.ToString(); txtMsg.Text = msg.ToString();
if (togScrollToEnd.IsChecked ?? true) if (togScrollToEnd.IsChecked ?? true)
{ {
txtMsg.CaretIndex = int.MaxValue; _scrollViewer?.ScrollToEnd();
} }
} }
public void ClearMsg() public void ClearMsg()
{ {
ViewModel?.ClearMsg(); ViewModel?.ClearMsg();
txtMsg.Clear(); txtMsg.Text = "";
} }
private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e) private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e)

View file

@ -41,361 +41,31 @@
</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" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
x:Name="txtBasicDNSSettingsInvalid"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbCustomDNSEnabledPageInvalid}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDomesticDNS}" />
<ComboBox
x:Name="cmbDirectDNS"
Grid.Row="1"
Grid.Column="1"
Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRemoteDNS}" />
<ComboBox
x:Name="cmbRemoteDNS"
Grid.Row="2"
Grid.Column="1"
Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBOutboundsResolverDNS}" />
<ComboBox
x:Name="cmbSBResolverDNS"
Grid.Row="3"
Grid.Column="1"
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.TbSBOutboundDomainResolve}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBDoHResolverServer}" />
<ComboBox
x:Name="cmbSBFinalResolverDNS"
Grid.Row="4"
Grid.Column="1"
Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="4"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbXrayFreedomResolveStrategy}" />
<ComboBox
x:Name="cmbRayFreedomDNSStrategy"
Grid.Row="5"
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.TbSBDirectResolveStrategy}" />
<ComboBox
x:Name="cmbSBDirectDNSStrategy"
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.TbSBRemoteResolveStrategy}" />
<ComboBox
x:Name="cmbSBRemoteDNSStrategy"
Grid.Row="7"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleButton
x:Name="togAddCommonHosts"
Grid.Row="8"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBDoHOverride}" />
</Grid>
</ScrollViewer>
</TabItem>
<TabItem Header="{x:Static resx:ResUI.ThAdvancedDNSSettings}">
<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="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
x:Name="txtAdvancedDNSSettingsInvalid"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbCustomDNSEnabledPageInvalid}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
<ToggleButton
x:Name="togUseSystemHosts"
Grid.Row="1"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleButton
x:Name="togFakeIP"
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.TbApplyProxyDomainsOnly}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
<ToggleButton
x:Name="togBlockBindingQuery"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
<ComboBox
x:Name="cmbDirectExpectedIPs"
Grid.Row="4"
Grid.Column="1"
Width="200"
IsEditable="True"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="4"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}" />
<TextBlock
Grid.Row="5"
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="6"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbDNSHostsConfig}"
AcceptsReturn="True"
BorderThickness="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</Grid>
</ScrollViewer>
</TabItem>
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
<DockPanel Margin="{StaticResource Margin8}"> <DockPanel Margin="{StaticResource Margin8}">
<Grid DockPanel.Dock="Top"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Grid.RowDefinitions> <TextBlock
<RowDefinition Height="Auto" /> Margin="{StaticResource Margin8}"
<RowDefinition Height="Auto" /> VerticalAlignment="Center"
</Grid.RowDefinitions> Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<StackPanel Grid.Row="0" Orientation="Horizontal"> <TextBlock
<TextBlock 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.TbCustomDNSEnable}" /> <TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
<ToggleButton <materialDesign:PackIcon Kind="Link" />
x:Name="togRayCustomDNSEnableCompatible" </Hyperlink>
Margin="{StaticResource Margin8}" </TextBlock>
HorizontalAlignment="Left" /> <Button
</StackPanel> x:Name="btnImportDefConfig4V2ray"
Margin="{StaticResource Margin8}"
<StackPanel Grid.Row="1" Orientation="Horizontal"> Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
<TextBlock Cursor="Hand"
Margin="{StaticResource Margin8}" Style="{StaticResource DefButton}" />
VerticalAlignment="Center" </StackPanel>
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkDnsObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<Button
x:Name="btnImportDefConfig4V2rayCompatible"
Margin="{StaticResource Margin8}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Cursor="Hand"
Style="{StaticResource DefButton}" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@ -405,7 +75,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" /> Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
<ToggleButton <ToggleButton
x:Name="togUseSystemHostsCompatible" x:Name="togUseSystemHosts"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
</StackPanel> </StackPanel>
@ -417,7 +87,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" /> Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4FreedomCompatible" x:Name="cmbdomainStrategy4Freedom"
Width="150" Width="150"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
@ -430,7 +100,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" /> Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
<ComboBox <ComboBox
x:Name="cmbdomainDNSAddressCompatible" x:Name="cmbdomainDNSAddress"
Width="150" Width="150"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
IsEditable="True" IsEditable="True"
@ -439,7 +109,7 @@
</WrapPanel> </WrapPanel>
<TextBox <TextBox
x:Name="txtnormalDNSCompatible" x:Name="txtnormalDNS"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="HTTP/SOCKS" materialDesign:HintAssist.Hint="HTTP/SOCKS"
@ -453,42 +123,23 @@
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}">
<DockPanel Margin="{StaticResource Margin8}"> <DockPanel Margin="{StaticResource Margin8}">
<Grid DockPanel.Dock="Top"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Grid.RowDefinitions> <TextBlock
<RowDefinition Height="Auto" /> Margin="{StaticResource Margin8}"
<RowDefinition Height="Auto" /> VerticalAlignment="Center"
</Grid.RowDefinitions> Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkDnsSingboxObjectDoc_Click">
<StackPanel Grid.Row="0" Orientation="Horizontal"> <TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
<TextBlock <materialDesign:PackIcon Kind="Link" />
Margin="{StaticResource Margin8}" </Hyperlink>
VerticalAlignment="Center" </TextBlock>
Style="{StaticResource ToolbarTextBlock}" <Button
Text="{x:Static resx:ResUI.TbCustomDNSEnable}" /> x:Name="btnImportDefConfig4Singbox"
<ToggleButton Margin="{StaticResource Margin8}"
x:Name="togSBCustomDNSEnableCompatible" Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Margin="{StaticResource Margin8}" Cursor="Hand"
HorizontalAlignment="Left" /> Style="{StaticResource DefButton}" />
</StackPanel> </StackPanel>
<StackPanel Grid.Row="1" 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="btnImportDefConfig4SingboxCompatible"
Margin="{StaticResource Margin8}"
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
Cursor="Hand"
Style="{StaticResource DefButton}" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal"> <WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@ -498,7 +149,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" /> Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4OutCompatible" x:Name="cmbdomainStrategy4Out"
Width="150" Width="150"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
@ -511,7 +162,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" /> Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
<ComboBox <ComboBox
x:Name="cmbdomainDNSAddress2Compatible" x:Name="cmbdomainDNSAddress2"
Width="150" Width="150"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
IsEditable="True" IsEditable="True"
@ -527,7 +178,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox <TextBox
x:Name="txtnormalDNS2Compatible" x:Name="txtnormalDNS2"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="HTTP/SOCKS" materialDesign:HintAssist.Hint="HTTP/SOCKS"
@ -540,7 +191,7 @@
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<TextBox <TextBox
x:Name="txttunDNS2Compatible" x:Name="txttunDNS2"
Grid.Column="2" Grid.Column="2"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbSettingsTunMode}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbSettingsTunMode}"

View file

@ -17,66 +17,26 @@ public partial class DNSSettingWindow
ViewModel = new DNSSettingViewModel(UpdateViewHandler); ViewModel = new DNSSettingViewModel(UpdateViewHandler);
cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms; cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms;
cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out; cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out; cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress;
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress;
cmbSBResolverDNS.ItemsSource = Global.DomainDirectDNSAddress.Concat(new[] { "dhcp://auto,localhost" });
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbSBFinalResolverDNS.ItemsSource = Global.DomainPureIPDNSAddress.Concat(new[] { "dhcp://auto,localhost" });
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4OutCompatible.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress;
cmbdomainDNSAddress2Compatible.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.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.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.Bind(ViewModel, vm => vm.RayCustomDNSEnableCompatible, v => v.togRayCustomDNSEnableCompatible.IsChecked).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SBCustomDNSEnableCompatible, v => v.togSBCustomDNSEnableCompatible.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.UseSystemHostsCompatible, v => v.togUseSystemHostsCompatible.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4FreedomCompatible, v => v.cmbdomainStrategy4FreedomCompatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainDNSAddressCompatible, v => v.cmbdomainDNSAddressCompatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNSCompatible, v => v.txtnormalDNSCompatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2Compatible, v => v.cmbdomainStrategy4OutCompatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainDNSAddress2Compatible, v => v.cmbdomainDNSAddress2Compatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NormalDNS2Compatible, v => v.txtnormalDNS2Compatible.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDNS2Compatible, v => v.txttunDNS2Compatible.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCompatibleCmd, v => v.btnImportDefConfig4V2rayCompatible).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCompatibleCmd, v => v.btnImportDefConfig4SingboxCompatible).DisposeWith(disposables);
this.WhenAnyValue(
x => x.ViewModel.RayCustomDNSEnableCompatible,
x => x.ViewModel.SBCustomDNSEnableCompatible,
(ray, sb) => ray && sb ? Visibility.Visible : Visibility.Collapsed)
.BindTo(this, x => x.txtBasicDNSSettingsInvalid.Visibility)
.DisposeWith(disposables);
this.WhenAnyValue(
x => x.ViewModel.RayCustomDNSEnableCompatible,
x => x.ViewModel.SBCustomDNSEnableCompatible,
(ray, sb) => ray && sb ? Visibility.Visible : Visibility.Collapsed)
.BindTo(this, x => x.txtAdvancedDNSSettingsInvalid.Visibility)
.DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme);
} }