ExpectedIPs

DHR60 2025-07-12 21:24:34 +08:00
parent 97bd64ee9a
commit 78bc763cee
18 changed files with 151 additions and 18 deletions

View File

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

View File

@ -571,5 +571,13 @@ public class Global
{ "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
}

View File

@ -269,4 +269,5 @@ public class DNSItem
public string? SingboxStrategy4Direct { get; set; }
public string? SingboxStrategy4Proxy { get; set; }
public string? Hosts { get; set; }
public string? DirectExpectedIPs { get; set; }
}

View File

@ -212,6 +212,8 @@ public class DnsServer4Ray
public string? address { get; set; }
public List<string>? domains { get; set; }
public bool? skipFallback { get; set; }
public List<string>? expectedIPs { get; set; }
public List<string>? unexpectedIPs { get; set; }
}
public class Routing4Ray

View File

@ -2824,7 +2824,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 Enable to Override sing-box DoH Resolver 的本地化字符串。
/// 查找类似 The sing-box DoH resolution server can be overwritten 的本地化字符串。
/// </summary>
public static string TbSBDoHOverride {
get {
@ -3822,6 +3822,24 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Validate Direct Expected IPs 的本地化字符串。
/// </summary>
public static string TbValidateDirectExpectedIPs {
get {
return ResourceManager.GetString("TbValidateDirectExpectedIPs", resourceCulture);
}
}
/// <summary>
/// 查找类似 After configuration, validates returned IPs, returning only expected IPs 的本地化字符串。
/// </summary>
public static string TbValidateDirectExpectedIPsDesc {
get {
return ResourceManager.GetString("TbValidateDirectExpectedIPsDesc", resourceCulture);
}
}
/// <summary>
/// 查找类似 xray Freedom Resolution Strategy 的本地化字符串。
/// </summary>

View File

@ -1429,7 +1429,7 @@
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
<value>The sing-box DoH resolution server can be overwritten</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
@ -1452,4 +1452,10 @@
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Direct Expected IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>After configuration, validates returned IPs, returning only expected IPs</value>
</data>
</root>

View File

@ -1429,7 +1429,7 @@
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
<value>The sing-box DoH resolution server can be overwritten</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
@ -1452,4 +1452,10 @@
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Direct Expected IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>After configuration, validates returned IPs, returning only expected IPs</value>
</data>
</root>

View File

@ -1429,7 +1429,7 @@
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
<value>The sing-box DoH resolution server can be overwritten</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
@ -1452,4 +1452,10 @@
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Direct Expected IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>After configuration, validates returned IPs, returning only expected IPs</value>
</data>
</root>

View File

@ -1429,7 +1429,7 @@
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
<value>The sing-box DoH resolution server can be overwritten</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
@ -1452,4 +1452,10 @@
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Direct Expected IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>After configuration, validates returned IPs, returning only expected IPs</value>
</data>
</root>

View File

@ -1449,4 +1449,10 @@
<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>配置后,会对返回的 IP 的进行校验,只返回期望 IP</value>
</data>
</root>

View File

@ -1426,7 +1426,7 @@
<value>Add Common DNS Hosts</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>Enable to Override sing-box DoH Resolver</value>
<value>The sing-box DoH resolution server can be overwritten</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
@ -1449,4 +1449,10 @@
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
</data>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Direct Expected IPs</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>After configuration, validates returned IPs, returning only expected IPs</value>
</data>
</root>

View File

@ -1758,6 +1758,10 @@ public class CoreConfigSingboxService
{
rule.server = "dns_direct";
rule.strategy = dNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Direct;
if (!dNSItem.DirectExpectedIPs.IsNullOrEmpty())
{
rule.rule_set = new() { dNSItem.DirectExpectedIPs };
}
}
else if (item.OutboundTag == Global.ProxyTag)
{

View File

@ -1,6 +1,8 @@
using System.Net;
using System.Net.NetworkInformation;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ServiceLib.Services.CoreConfig;
@ -1282,30 +1284,37 @@ public class CoreConfigV2rayService
v2rayConfig.dns ??= new Dns4Ray();
v2rayConfig.dns.servers ??= new List<object>();
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
if (proxyDomainList.Count > 0)
{
foreach (var dnsDomain in remoteDNSAddress)
{
var dnsServer = new DnsServer4Ray()
var dnsServer = new DnsServer4Ray
{
address = dnsDomain,
skipFallback = true,
domains = proxyDomainList
};
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer));
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
}
}
if (directDomainList.Count > 0)
{
foreach (var dnsDomain in directDNSAddress)
{
var dnsServer = new DnsServer4Ray()
var dnsServer = new DnsServer4Ray
{
address = dnsDomain,
skipFallback = true,
domains = directDomainList
domains = directDomainList,
expectedIPs = dNSItem.DirectExpectedIPs.IsNullOrEmpty() ? null : new() { dNSItem.DirectExpectedIPs }
};
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer));
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
}
}
if (proxyGeositeList.Count > 0)
@ -1318,7 +1327,7 @@ public class CoreConfigV2rayService
skipFallback = true,
domains = proxyGeositeList
};
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer));
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
}
}
if (directGeositeList.Count > 0)
@ -1329,9 +1338,10 @@ public class CoreConfigV2rayService
{
address = dnsDomain,
skipFallback = true,
domains = directGeositeList
domains = directGeositeList,
expectedIPs = dNSItem.DirectExpectedIPs.IsNullOrEmpty() ? null : new() { dNSItem.DirectExpectedIPs }
};
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer));
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
}
}

View File

@ -18,6 +18,7 @@ public class DNSSettingViewModel : MyReactiveObject
[Reactive] public string? SingboxStrategy4Direct { get; set; }
[Reactive] public string? SingboxStrategy4Proxy { get; set; }
[Reactive] public string? Hosts { get; set; }
[Reactive] public string? DirectExpectedIPs { get; set; }
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
//public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
@ -61,6 +62,7 @@ public class DNSSettingViewModel : MyReactiveObject
SingboxStrategy4Direct = item.SingboxStrategy4Direct;
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
Hosts = item.Hosts;
DirectExpectedIPs = item.DirectExpectedIPs;
}
private async Task SaveSettingAsync()
@ -77,6 +79,7 @@ public class DNSSettingViewModel : MyReactiveObject
_config.DNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct;
_config.DNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy;
_config.DNSItem.Hosts = Hosts;
_config.DNSItem.DirectExpectedIPs = DirectExpectedIPs;
await ConfigHandler.SaveConfig(_config);
if (_updateView != null)
{

View File

@ -175,7 +175,7 @@
<Grid
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,*">
RowDefinitions="Auto,Auto,Auto,Auto,Auto,*">
<TextBlock
Grid.Row="0"
@ -231,6 +231,25 @@
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
<ComboBox
x:Name="cmbDirectExpectedIPs"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
@ -238,7 +257,7 @@
<TextBox
x:Name="txtHosts"
Grid.Row="4"
Grid.Row="5"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}"

View File

@ -24,6 +24,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
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;
this.WhenActivated(disposables =>
{
@ -39,6 +40,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
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.SelectedItem).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});

View File

@ -217,6 +217,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@ -281,9 +282,33 @@
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
<ComboBox
x:Name="cmbDirectExpectedIPs"
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.TbValidateDirectExpectedIPsDesc}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
@ -291,7 +316,7 @@
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
<TextBox
x:Name="txtHosts"
Grid.Row="4"
Grid.Row="5"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}"

View File

@ -24,6 +24,7 @@ public partial class DNSSettingWindow
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;
this.WhenActivated(disposables =>
{
@ -39,6 +40,7 @@ public partial class DNSSettingWindow
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.SelectedItem).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});