mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-04 19:45:00 +03:00
feat(dns): support optional IPv6 FakeIP pools (#10464)
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
namespace ServiceLib.Tests.CoreConfig;
|
||||
|
||||
public class DualStackFakeIPTests
|
||||
{
|
||||
[Test]
|
||||
[Arguments(null, "fc00::/18", 65535L)]
|
||||
[Arguments(" 2001:2::/48 ", "2001:2::/48", 65535L)]
|
||||
[Arguments("fc00::/120", "fc00::/120", 255L)]
|
||||
[Arguments("fc00::/127", "fc00::/127", 1L)]
|
||||
public async Task IPv6Range_ShouldUseAnXrayCompatiblePoolSize(string? input, string expectedRange, long expectedSize)
|
||||
{
|
||||
var valid = FakeIPUtils.TryParseIPv6Range(input, out var range, out var size);
|
||||
|
||||
await valid.Should().BeTrue();
|
||||
await range.Should().BeEqualTo(expectedRange);
|
||||
await size.Should().BeEqualTo(expectedSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Arguments("198.18.0.0/15")]
|
||||
[Arguments("not-a-network")]
|
||||
[Arguments("fc00::/128")]
|
||||
public async Task IPv6Range_ShouldRejectInvalidOrSingleAddressPools(string input)
|
||||
{
|
||||
await FakeIPUtils.TryParseIPv6Range(input, out _, out _).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task OldDnsSettings_ShouldKeepIPv6FakeIPDisabled()
|
||||
{
|
||||
var settings = JsonUtils.Deserialize<SimpleDNSItem>("""
|
||||
{ "FakeIP": true, "FakeIPRange": "198.18.0.0/15" }
|
||||
""")!;
|
||||
|
||||
await (settings.FakeIPv6 == true).Should().BeFalse();
|
||||
await settings.FakeIPRange.Should().BeEqualTo("198.18.0.0/15");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DnsSettings_ShouldRoundTripBothAddressRanges()
|
||||
{
|
||||
var settings = new SimpleDNSItem
|
||||
{
|
||||
FakeIP = true,
|
||||
FakeIPRange = "198.18.0.0/15",
|
||||
FakeIPv6 = true,
|
||||
FakeIPv6Range = "2001:2::/48",
|
||||
};
|
||||
|
||||
var restored = JsonUtils.Deserialize<SimpleDNSItem>(JsonUtils.Serialize(settings))!;
|
||||
|
||||
await restored.FakeIP.Should().BeEqualTo(true);
|
||||
await restored.FakeIPRange.Should().BeEqualTo(settings.FakeIPRange);
|
||||
await restored.FakeIPv6.Should().BeEqualTo(true);
|
||||
await restored.FakeIPv6Range.Should().BeEqualTo(settings.FakeIPv6Range);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AppConfig_ShouldRoundTripIPv6Settings()
|
||||
{
|
||||
var config = CoreConfigTestFactory.CreateConfig();
|
||||
config.SimpleDNSItem.FakeIPv6 = true;
|
||||
config.SimpleDNSItem.FakeIPv6Range = "2001:2::/48";
|
||||
|
||||
var restored = JsonUtils.Deserialize<Config>(JsonUtils.Serialize(config))!;
|
||||
|
||||
await restored.Should().NotBeNull();
|
||||
await restored.SimpleDNSItem.FakeIPv6.Should().BeEqualTo(true);
|
||||
await restored.SimpleDNSItem.FakeIPv6Range.Should().BeEqualTo("2001:2::/48");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Arguments(false)]
|
||||
[Arguments(true)]
|
||||
public async Task Xray_ShouldRoundTripSingleAndDualPools(bool enableIPv6)
|
||||
{
|
||||
var context = CreateContext(ECoreType.Xray, enableIPv6, false);
|
||||
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||
|
||||
await result.Success.Should().BeTrue();
|
||||
var restored = JsonUtils.Deserialize<V2rayConfig>(result.Data!.ToString())!;
|
||||
await restored.Should().NotBeNull();
|
||||
var roundTrip = JsonUtils.ParseJson(JsonUtils.Serialize(restored))!;
|
||||
var original = JsonUtils.ParseJson(result.Data!.ToString())!;
|
||||
await JsonNode.DeepEquals(original["fakedns"], roundTrip["fakedns"]).Should().BeTrue();
|
||||
await (restored.fakedns is JsonArray).Should().BeEqualTo(enableIPv6);
|
||||
await restored.fakedns.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Arguments(false, false)]
|
||||
[Arguments(true, false)]
|
||||
[Arguments(true, true)]
|
||||
public async Task Xray_ShouldAddIPv6OnlyWhenEnabledAndAAAAAllowed(bool enableIPv6, bool blockAAAA)
|
||||
{
|
||||
var context = CreateContext(ECoreType.Xray, enableIPv6, blockAAAA);
|
||||
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||
|
||||
await result.Success.Should().BeTrue();
|
||||
var root = JsonUtils.ParseJson(result.Data!.ToString())!;
|
||||
var dualStack = enableIPv6 && !blockAAAA;
|
||||
await (root["fakedns"] is JsonArray).Should().BeEqualTo(dualStack);
|
||||
var pool = dualStack ? root["fakedns"]![0]! : root["fakedns"]!;
|
||||
await pool["ipPool"]!.GetValue<string>().Should().BeEqualTo("198.18.0.0/15");
|
||||
if (dualStack)
|
||||
{
|
||||
await root["fakedns"]!.AsArray().Count.Should().BeEqualTo(2);
|
||||
await root["fakedns"]![1]!["ipPool"]!.GetValue<string>().Should().BeEqualTo("2001:2::/48");
|
||||
await root["fakedns"]![1]!["poolSize"]!.GetValue<long>().Should().BeEqualTo(65535L);
|
||||
}
|
||||
if (blockAAAA)
|
||||
{
|
||||
await root["dns"]!["queryStrategy"]!.GetValue<string>().Should().BeEqualTo("UseIPv4");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Arguments(false, false)]
|
||||
[Arguments(true, false)]
|
||||
[Arguments(true, true)]
|
||||
public async Task Singbox_ShouldAddIPv6OnlyWhenEnabledAndAAAAAllowed(bool enableIPv6, bool blockAAAA)
|
||||
{
|
||||
var context = CreateContext(ECoreType.sing_box, enableIPv6, blockAAAA);
|
||||
var result = new CoreConfigSingboxService(context).GenerateClientConfigContent();
|
||||
|
||||
await result.Success.Should().BeTrue();
|
||||
var config = JsonUtils.Deserialize<SingboxConfig>(result.Data!.ToString())!;
|
||||
var fakeDns = config.dns.servers.Single(server => server.type == "fakeip");
|
||||
|
||||
await fakeDns.inet4_range.Should().BeEqualTo("198.18.0.0/15");
|
||||
await fakeDns.inet6_range.Should().BeEqualTo(enableIPv6 && !blockAAAA ? "2001:2::/48" : null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DisabledFakeIP_ShouldNotCreateEitherPool()
|
||||
{
|
||||
foreach (var coreType in new[] { ECoreType.Xray, ECoreType.sing_box })
|
||||
{
|
||||
var context = CreateContext(coreType, true, false);
|
||||
context.AppConfig.SimpleDNSItem.FakeIP = false;
|
||||
var result = coreType == ECoreType.Xray
|
||||
? new CoreConfigV2rayService(context).GenerateClientConfigContent()
|
||||
: new CoreConfigSingboxService(context).GenerateClientConfigContent();
|
||||
|
||||
await result.Success.Should().BeTrue();
|
||||
var root = JsonUtils.ParseJson(result.Data!.ToString())!;
|
||||
await root["fakedns"].Should().BeNull();
|
||||
await root["dns"]!["servers"]!.AsArray()
|
||||
.Any(server => server is JsonObject obj && obj["type"]?.GetValue<string>() == "fakeip")
|
||||
.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
||||
private static CoreConfigContext CreateContext(ECoreType coreType, bool enableIPv6, bool blockAAAA)
|
||||
{
|
||||
var config = CoreConfigTestFactory.CreateConfig(coreType);
|
||||
config.SimpleDNSItem.FakeIP = true;
|
||||
config.SimpleDNSItem.FakeIPRange = "198.18.0.0/15";
|
||||
config.SimpleDNSItem.FakeIPv6 = enableIPv6;
|
||||
config.SimpleDNSItem.FakeIPv6Range = "2001:2::/48";
|
||||
config.SimpleDNSItem.BlockAAAAQuery = blockAAAA;
|
||||
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||
var node = CoreConfigTestFactory.CreateVmessNode(coreType);
|
||||
return CoreConfigTestFactory.CreateContext(config, node, coreType) with
|
||||
{
|
||||
RoutingItem = new RoutingItem
|
||||
{
|
||||
Id = "fakeip-test",
|
||||
Remarks = "FakeIP test",
|
||||
DomainStrategy = Global.AsIs,
|
||||
DomainStrategy4Singbox = string.Empty,
|
||||
RuleSet = JsonUtils.Serialize(new List<RulesItem>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Enabled = true,
|
||||
RuleType = ERuleType.DNS,
|
||||
OutboundTag = Global.ProxyTag,
|
||||
Domain = ["full:example.com"],
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -109,8 +109,8 @@ public class CoreConfigV2rayIPNetworkTests
|
||||
var generated = JsonUtils.Deserialize<V2rayConfig>(result.Data!.ToString())!;
|
||||
|
||||
await generated.fakedns.Should().NotBeNull();
|
||||
await generated.fakedns!.ipPool.Should().BeEqualTo(range);
|
||||
await generated.fakedns.poolSize.Should().BeEqualTo(expectedPoolSize);
|
||||
await generated.fakedns!["ipPool"]!.GetValue<string>().Should().BeEqualTo(range);
|
||||
await generated.fakedns["poolSize"]!.GetValue<long>().Should().BeEqualTo(expectedPoolSize);
|
||||
}
|
||||
|
||||
private static async Task<V2rayConfig> GenerateConfig(Config config)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace ServiceLib.Common;
|
||||
|
||||
public static class FakeIPUtils
|
||||
{
|
||||
public static bool TryParseIPv6Range(string? value, out string range, out long poolSize)
|
||||
{
|
||||
range = string.IsNullOrWhiteSpace(value) ? Global.FakeIPv6Ranges.First() : value.Trim();
|
||||
poolSize = 65535;
|
||||
if (!System.Net.IPNetwork.TryParse(range, out var network)
|
||||
|| network.BaseAddress.AddressFamily != AddressFamily.InterNetworkV6
|
||||
|| network.PrefixLength == 128)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
range = network.ToString();
|
||||
var hostBits = 128 - network.PrefixLength;
|
||||
if (hostBits < 16)
|
||||
{
|
||||
// Xray requires the mapping capacity to be smaller than the address pool.
|
||||
poolSize = (1L << hostBits) - 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -240,6 +240,7 @@ public class JsonUtils
|
||||
[JsonSerializable(typeof(List<Rule4Sbox>))]
|
||||
[JsonSerializable(typeof(List<Ruleset4Sbox>))]
|
||||
[JsonSerializable(typeof(V2rayConfig))]
|
||||
[JsonSerializable(typeof(FakeDns4Ray))]
|
||||
[JsonSerializable(typeof(Dns4Ray))]
|
||||
[JsonSerializable(typeof(DnsServer4Ray))]
|
||||
[JsonSerializable(typeof(Inbounds4Ray))]
|
||||
|
||||
@@ -773,6 +773,12 @@ public class Global
|
||||
"11.0.0.0/8",
|
||||
];
|
||||
|
||||
public static readonly List<string> FakeIPv6Ranges =
|
||||
[
|
||||
"fc00::/18",
|
||||
"2001:2::/48",
|
||||
];
|
||||
|
||||
public static readonly List<string> RootCertProviders =
|
||||
[
|
||||
"system",
|
||||
|
||||
@@ -115,6 +115,8 @@ public static class ConfigHandler
|
||||
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
||||
config.SimpleDNSItem.BlockAAAAQuery ??= false;
|
||||
config.SimpleDNSItem.FakeIPRange ??= Global.FakeIPRanges.FirstOrDefault();
|
||||
config.SimpleDNSItem.FakeIPv6 ??= false;
|
||||
config.SimpleDNSItem.FakeIPv6Range ??= Global.FakeIPv6Ranges.First();
|
||||
config.SimpleDNSItem.GlobalFakeIp ??= true;
|
||||
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
||||
config.SimpleDNSItem.ServeStale ??= false;
|
||||
|
||||
@@ -254,6 +254,8 @@ public class SimpleDNSItem
|
||||
public bool? FakeIP { get; set; }
|
||||
public bool? GlobalFakeIp { get; set; }
|
||||
public string? FakeIPRange { get; set; }
|
||||
public bool? FakeIPv6 { get; set; }
|
||||
public string? FakeIPv6Range { get; set; }
|
||||
public bool? BlockBindingQuery { get; set; }
|
||||
public bool? BlockAAAAQuery { get; set; }
|
||||
public string? DirectDNS { get; set; }
|
||||
|
||||
@@ -4,7 +4,7 @@ public class V2rayConfig
|
||||
{
|
||||
public Log4Ray log { get; set; }
|
||||
public JsonObject? dns { get; set; }
|
||||
public FakeDns4Ray? fakedns { get; set; }
|
||||
public JsonNode? fakedns { get; set; }
|
||||
public List<Inbounds4Ray> inbounds { get; set; }
|
||||
public List<Outbounds4Ray> outbounds { get; set; }
|
||||
public Routing4Ray routing { get; set; }
|
||||
|
||||
Generated
+28
-1
@@ -1,4 +1,4 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
@@ -5444,5 +5444,32 @@ namespace ServiceLib.Resx {
|
||||
return ResourceManager.GetString("UpgradeAppNotExistTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// IPv6 FakeIP
|
||||
/// </summary>
|
||||
public static string TbFakeIPv6 {
|
||||
get {
|
||||
return ResourceManager.GetString("TbFakeIPv6", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return fake IPv6 addresses as well. Requires FakeIP to be enabled and AAAA queries to be allowed.
|
||||
/// </summary>
|
||||
public static string TbFakeIPv6Tips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbFakeIPv6Tips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enter a valid IPv6 CIDR range with at least two addresses, for example fc00::/18.
|
||||
/// </summary>
|
||||
public static string FillCorrectFakeIPv6Range {
|
||||
get {
|
||||
return ResourceManager.GetString("FillCorrectFakeIPv6Range", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1905,6 +1905,15 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="menuAddMasqueServer" xml:space="preserve">
|
||||
<value>Add [MASQUE]</value>
|
||||
</data>
|
||||
<data name="TbFakeIPv6" xml:space="preserve">
|
||||
<value>IPv6 FakeIP</value>
|
||||
</data>
|
||||
<data name="TbFakeIPv6Tips" xml:space="preserve">
|
||||
<value>Return fake IPv6 addresses as well. Requires FakeIP to be enabled and AAAA queries to be allowed.</value>
|
||||
</data>
|
||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||
<value>Enter a valid IPv6 CIDR range with at least two addresses, for example fc00::/18.</value>
|
||||
</data>
|
||||
<data name="menuColumns" xml:space="preserve">
|
||||
<value>Columns</value>
|
||||
</data>
|
||||
@@ -1914,4 +1923,4 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||
<data name="LvPreResolve" xml:space="preserve">
|
||||
<value>Pre-resolve server domains</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -1897,6 +1897,15 @@
|
||||
<data name="menuAddMasqueServer" xml:space="preserve">
|
||||
<value>添加 [MASQUE]</value>
|
||||
</data>
|
||||
<data name="TbFakeIPv6" xml:space="preserve">
|
||||
<value>IPv6 FakeIP</value>
|
||||
</data>
|
||||
<data name="TbFakeIPv6Tips" xml:space="preserve">
|
||||
<value>同时返回 IPv6 假地址,需启用 FakeIP 且未屏蔽 AAAA 查询。</value>
|
||||
</data>
|
||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||
<value>请输入至少包含两个地址的有效 IPv6 网段,例如 fc00::/18。</value>
|
||||
</data>
|
||||
<data name="menuColumns" xml:space="preserve">
|
||||
<value>列</value>
|
||||
</data>
|
||||
@@ -1906,4 +1915,4 @@
|
||||
<data name="LvPreResolve" xml:space="preserve">
|
||||
<value>预解析节点域名</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -1903,4 +1903,13 @@
|
||||
<data name="TbSortingProcess" xml:space="preserve">
|
||||
<value>行程</value>
|
||||
</data>
|
||||
<data name="TbFakeIPv6" xml:space="preserve">
|
||||
<value>IPv6 FakeIP</value>
|
||||
</data>
|
||||
<data name="TbFakeIPv6Tips" xml:space="preserve">
|
||||
<value>同時傳回 IPv6 假位址,需啟用 FakeIP 且未封鎖 AAAA 查詢。</value>
|
||||
</data>
|
||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||
<value>請輸入至少包含兩個位址的有效 IPv6 網段,例如 fc00::/18。</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -131,6 +131,14 @@ public partial class CoreConfigSingboxService
|
||||
type = "fakeip",
|
||||
inet4_range = fakeipRange,
|
||||
};
|
||||
if (simpleDnsItem.FakeIPv6 == true && simpleDnsItem.BlockAAAAQuery != true)
|
||||
{
|
||||
if (!FakeIPUtils.TryParseIPv6Range(simpleDnsItem.FakeIPv6Range, out var range6, out _))
|
||||
{
|
||||
throw new ArgumentException("Invalid IPv6 FakeIP range.");
|
||||
}
|
||||
fakeip.inet6_range = range6;
|
||||
}
|
||||
_coreConfig.dns.servers.Add(fakeip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +145,22 @@ public partial class CoreConfigV2rayService
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
_coreConfig.fakedns = new()
|
||||
var fakeDns = new FakeDns4Ray
|
||||
{
|
||||
ipPool = fakeipRange,
|
||||
poolSize = poolSize,
|
||||
};
|
||||
_coreConfig.fakedns = JsonUtils.SerializeToNode(fakeDns);
|
||||
if (_config.SimpleDNSItem.FakeIPv6 == true && _config.SimpleDNSItem.BlockAAAAQuery != true)
|
||||
{
|
||||
if (!FakeIPUtils.TryParseIPv6Range(_config.SimpleDNSItem.FakeIPv6Range, out var range6, out var poolSize6))
|
||||
{
|
||||
throw new ArgumentException("Invalid IPv6 FakeIP range.");
|
||||
}
|
||||
_coreConfig.fakedns = new JsonArray(
|
||||
_coreConfig.fakedns,
|
||||
JsonUtils.SerializeToNode(new FakeDns4Ray { ipPool = range6, poolSize = poolSize6 }));
|
||||
}
|
||||
}
|
||||
|
||||
private void FillDnsServers(Dns4Ray dnsItem)
|
||||
|
||||
@@ -8,6 +8,8 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable
|
||||
[Reactive] public partial bool AddCommonHosts { get; set; }
|
||||
[Reactive] public partial bool FakeIP { get; set; }
|
||||
[Reactive] public partial string FakeIPRange { get; set; }
|
||||
[Reactive] public partial bool FakeIPv6 { get; set; }
|
||||
[Reactive] public partial string FakeIPv6Range { get; set; }
|
||||
[Reactive] public partial bool BlockBindingQuery { get; set; }
|
||||
[Reactive] public partial bool BlockAAAAQuery { get; set; }
|
||||
[Reactive] public partial string DirectDNS { get; set; }
|
||||
@@ -36,6 +38,7 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable
|
||||
[Reactive] public partial bool SBCustomDNSEnableCompatible { get; set; }
|
||||
|
||||
[ObservableAsProperty] public partial bool IsSimpleDNSEnabled { get; }
|
||||
[ObservableAsProperty] public partial bool IsFakeIPv6Available { get; }
|
||||
|
||||
public ReactiveCommand<RxVoid, RxVoid> SaveCmd { get; }
|
||||
public ReactiveCommand<RxVoid, RxVoid> ImportDefConfig4V2rayCompatibleCmd { get; }
|
||||
@@ -66,6 +69,12 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable
|
||||
(a, b) => !(a && b))
|
||||
.ToProperty(this, nameof(IsSimpleDNSEnabled));
|
||||
|
||||
_isFakeIPv6AvailableHelper = this.WhenAnyValue(
|
||||
x => x.FakeIP,
|
||||
x => x.BlockAAAAQuery,
|
||||
(fakeIP, blockAAAA) => fakeIP && !blockAAAA)
|
||||
.ToProperty(this, nameof(IsFakeIPv6Available));
|
||||
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
@@ -77,6 +86,8 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable
|
||||
AddCommonHosts = item.AddCommonHosts ?? false;
|
||||
FakeIP = item.FakeIP ?? false;
|
||||
FakeIPRange = item.FakeIPRange ?? string.Empty;
|
||||
FakeIPv6 = item.FakeIPv6 ?? false;
|
||||
FakeIPv6Range = item.FakeIPv6Range ?? Global.FakeIPv6Ranges.First();
|
||||
BlockBindingQuery = item.BlockBindingQuery ?? false;
|
||||
BlockAAAAQuery = item.BlockAAAAQuery ?? false;
|
||||
DirectDNS = item.DirectDNS ?? string.Empty;
|
||||
@@ -108,10 +119,19 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable
|
||||
|
||||
private async Task SaveSettingAsync()
|
||||
{
|
||||
if (IsSimpleDNSEnabled && IsFakeIPv6Available && FakeIPv6
|
||||
&& !FakeIPUtils.TryParseIPv6Range(FakeIPv6Range, out _, out _))
|
||||
{
|
||||
NoticeManager.Instance.Enqueue(ResUI.FillCorrectFakeIPv6Range);
|
||||
return;
|
||||
}
|
||||
|
||||
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts;
|
||||
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
|
||||
_config.SimpleDNSItem.FakeIP = FakeIP;
|
||||
_config.SimpleDNSItem.FakeIPRange = FakeIPRange;
|
||||
_config.SimpleDNSItem.FakeIPv6 = FakeIPv6;
|
||||
_config.SimpleDNSItem.FakeIPv6Range = FakeIPv6Range;
|
||||
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
|
||||
_config.SimpleDNSItem.BlockAAAAQuery = BlockAAAAQuery;
|
||||
_config.SimpleDNSItem.DirectDNS = DirectDNS;
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
x:Name="gridAdvancedDNSSettings"
|
||||
Margin="{StaticResource Margin8}"
|
||||
ColumnDefinitions="Auto,Auto,*"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,*">
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,*">
|
||||
|
||||
<TextBlock
|
||||
x:Name="txtAdvancedDNSSettingsInvalid"
|
||||
@@ -317,16 +317,49 @@
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbFakeIPv6}" />
|
||||
<Grid x:Name="gridFakeIPv6" Grid.Row="4" Grid.Column="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToggleSwitch
|
||||
x:Name="togFakeIPv6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox
|
||||
x:Name="cmbFakeIPv6Range"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
IsEditable="True" />
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbFakeIPv6Tips}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togBlockBindingQuery"
|
||||
Grid.Row="4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -334,20 +367,20 @@
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbBlockAAAAQueries}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togBlockAAAAQuery"
|
||||
Grid.Row="5"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Row="6"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -355,21 +388,21 @@
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
|
||||
<ComboBox
|
||||
x:Name="cmbDirectExpectedIPs"
|
||||
Grid.Row="6"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
IsEditable="True" />
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Row="7"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -377,7 +410,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="{StaticResource Margin4}"
|
||||
@@ -386,7 +419,7 @@
|
||||
|
||||
<TextBox
|
||||
x:Name="txtHosts"
|
||||
Grid.Row="8"
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="{StaticResource Margin4}"
|
||||
|
||||
@@ -21,6 +21,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||
cmbFakeIPRange.ItemsSource = Global.FakeIPRanges;
|
||||
cmbFakeIPv6Range.ItemsSource = Global.FakeIPv6Ranges;
|
||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||
|
||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
||||
@@ -34,6 +35,9 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIPRange, v => v.cmbFakeIPRange.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIPv6, v => v.togFakeIPv6.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIPv6Range, v => v.cmbFakeIPv6Range.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.IsFakeIPv6Available, v => v.gridFakeIPv6.IsEnabled).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockAAAAQuery, v => v.togBlockAAAAQuery.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||
|
||||
@@ -279,6 +279,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -366,15 +367,51 @@
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbFakeIPv6}" />
|
||||
<Grid x:Name="gridFakeIPv6" Grid.Row="4" Grid.Column="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToggleButton
|
||||
x:Name="togFakeIPv6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox
|
||||
x:Name="cmbFakeIPv6Range"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbFakeIPv6Tips}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
|
||||
<ToggleButton
|
||||
x:Name="togBlockBindingQuery"
|
||||
Grid.Row="4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -383,7 +420,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -391,12 +428,12 @@
|
||||
Text="{x:Static resx:ResUI.TbBlockAAAAQueries}" />
|
||||
<ToggleButton
|
||||
x:Name="togBlockAAAAQuery"
|
||||
Grid.Row="5"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Row="6"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -405,7 +442,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -413,14 +450,14 @@
|
||||
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
|
||||
<ComboBox
|
||||
x:Name="cmbDirectExpectedIPs"
|
||||
Grid.Row="6"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin8}"
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Row="7"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -429,7 +466,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="{StaticResource Margin8}"
|
||||
@@ -438,7 +475,7 @@
|
||||
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
|
||||
<TextBox
|
||||
x:Name="txtHosts"
|
||||
Grid.Row="8"
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="{StaticResource Margin8}"
|
||||
|
||||
@@ -17,6 +17,7 @@ public partial class DNSSettingWindow
|
||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||
cmbFakeIPRange.ItemsSource = Global.FakeIPRanges;
|
||||
cmbFakeIPv6Range.ItemsSource = Global.FakeIPv6Ranges;
|
||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||
|
||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
||||
@@ -30,6 +31,9 @@ public partial class DNSSettingWindow
|
||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIPRange, v => v.cmbFakeIPRange.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIPv6, v => v.togFakeIPv6.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIPv6Range, v => v.cmbFakeIPv6Range.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.IsFakeIPv6Available, v => v.gridFakeIPv6.IsEnabled).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockAAAAQuery, v => v.togBlockAAAAQuery.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||
|
||||
Reference in New Issue
Block a user