mirror of https://github.com/2dust/v2rayN
Optimize ExpectedIPs Logic
parent
5331e2eeff
commit
4105031446
|
@ -1,4 +1,4 @@
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// 此代码由工具生成。
|
// 此代码由工具生成。
|
||||||
// 运行时版本:4.0.30319.42000
|
// 运行时版本:4.0.30319.42000
|
||||||
|
@ -3832,7 +3832,7 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Validate Direct Expected IPs 的本地化字符串。
|
/// 查找类似 Validate Regional Domain IPs 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbValidateDirectExpectedIPs {
|
public static string TbValidateDirectExpectedIPs {
|
||||||
get {
|
get {
|
||||||
|
@ -3841,7 +3841,7 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 After configuration, validates returned IPs, returning only expected IPs 的本地化字符串。
|
/// 查找类似 When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbValidateDirectExpectedIPsDesc {
|
public static string TbValidateDirectExpectedIPsDesc {
|
||||||
get {
|
get {
|
||||||
|
|
|
@ -1456,9 +1456,9 @@
|
||||||
<value>Advanced DNS Settings</value>
|
<value>Advanced DNS Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>Validate Direct Expected IPs</value>
|
<value>Validate Regional Domain IPs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>After configuration, validates returned IPs, returning only expected IPs</value>
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1456,9 +1456,9 @@
|
||||||
<value>Advanced DNS Settings</value>
|
<value>Advanced DNS Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>Validate Direct Expected IPs</value>
|
<value>Validate Regional Domain IPs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>After configuration, validates returned IPs, returning only expected IPs</value>
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1456,9 +1456,9 @@
|
||||||
<value>Advanced DNS Settings</value>
|
<value>Advanced DNS Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>Validate Direct Expected IPs</value>
|
<value>Validate Regional Domain IPs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>After configuration, validates returned IPs, returning only expected IPs</value>
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1456,9 +1456,9 @@
|
||||||
<value>Advanced DNS Settings</value>
|
<value>Advanced DNS Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>Validate Direct Expected IPs</value>
|
<value>Validate Regional Domain IPs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>After configuration, validates returned IPs, returning only expected IPs</value>
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1453,9 +1453,9 @@
|
||||||
<value>DNS 进阶设置</value>
|
<value>DNS 进阶设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>校验直连期望 IP</value>
|
<value>校验相应地区域名 IP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>配置后,会对返回的 IP 的进行校验,只返回期望 IP</value>
|
<value>配置后,会对相应地区域名(如 geosite:cn)的返回 IP 进行校验,仅返回期望 IP</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1453,9 +1453,9 @@
|
||||||
<value>Advanced DNS Settings</value>
|
<value>Advanced DNS Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>Validate Direct Expected IPs</value>
|
<value>Validate Regional Domain IPs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>After configuration, validates returned IPs, returning only expected IPs</value>
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1704,68 +1704,100 @@ public class CoreConfigSingboxService
|
||||||
{
|
{
|
||||||
singboxConfig.dns ??= new Dns4Sbox();
|
singboxConfig.dns ??= new Dns4Sbox();
|
||||||
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
||||||
// hosts
|
|
||||||
singboxConfig.dns.rules.Add(new Rule4Sbox
|
singboxConfig.dns.rules.AddRange(new[]
|
||||||
{
|
{
|
||||||
ip_accept_any = true,
|
new Rule4Sbox { ip_accept_any = true, server = "dns_hosts" },
|
||||||
server = "dns_hosts",
|
new Rule4Sbox
|
||||||
});
|
|
||||||
// clash mode
|
|
||||||
singboxConfig.dns.rules.Add(new Rule4Sbox
|
|
||||||
{
|
{
|
||||||
server = "dns_remote",
|
server = "dns_remote",
|
||||||
strategy = dNSItem.SingboxStrategy4Proxy.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Proxy,
|
strategy = string.IsNullOrEmpty(dNSItem.SingboxStrategy4Proxy) ? null : dNSItem.SingboxStrategy4Proxy,
|
||||||
clash_mode = ERuleMode.Global.ToString()
|
clash_mode = ERuleMode.Global.ToString()
|
||||||
});
|
},
|
||||||
singboxConfig.dns.rules.Add(new Rule4Sbox
|
new Rule4Sbox
|
||||||
{
|
{
|
||||||
server = "dns_direct",
|
server = "dns_direct",
|
||||||
strategy = dNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Direct,
|
strategy = string.IsNullOrEmpty(dNSItem.SingboxStrategy4Direct) ? null : dNSItem.SingboxStrategy4Direct,
|
||||||
clash_mode = ERuleMode.Direct.ToString()
|
clash_mode = ERuleMode.Direct.ToString()
|
||||||
});
|
},
|
||||||
// block binding query
|
new Rule4Sbox
|
||||||
singboxConfig.dns.rules.Add(new Rule4Sbox
|
|
||||||
{
|
{
|
||||||
query_type = new List<int> { 64, 65 },
|
query_type = new List<int> { 64, 65 },
|
||||||
action = "predefined",
|
action = "predefined",
|
||||||
rcode = "NOTIMP"
|
rcode = "NOTIMP"
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||||
if (routing != null)
|
if (routing == null)
|
||||||
{
|
return 0;
|
||||||
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
|
|
||||||
foreach (var item in rules ?? [])
|
|
||||||
{
|
|
||||||
if (!item.Enabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.Domain == null || item.Domain.Count == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var rule = new Rule4Sbox();
|
|
||||||
|
|
||||||
var countDomain = 0;
|
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
|
||||||
foreach (var it in item.Domain)
|
var expectedIPCidr = new List<string>();
|
||||||
|
var expectedIPsRegions = new List<string>();
|
||||||
|
var regionNames = new HashSet<string>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(dNSItem?.DirectExpectedIPs))
|
||||||
{
|
{
|
||||||
if (ParseV2Domain(it, rule))
|
var ipItems = dNSItem.DirectExpectedIPs
|
||||||
|
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.Where(s => !string.IsNullOrEmpty(s))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var ip in ipItems)
|
||||||
{
|
{
|
||||||
countDomain++;
|
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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (countDomain <= 0)
|
else
|
||||||
|
{
|
||||||
|
expectedIPCidr.Add(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in rules)
|
||||||
|
{
|
||||||
|
if (!item.Enabled || item.Domain is null || item.Domain.Count == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rule = new Rule4Sbox();
|
||||||
|
var validDomains = item.Domain.Count(it => ParseV2Domain(it, rule));
|
||||||
|
if (validDomains <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.OutboundTag == Global.DirectTag)
|
if (item.OutboundTag == Global.DirectTag)
|
||||||
{
|
{
|
||||||
rule.server = "dns_direct";
|
rule.server = "dns_direct";
|
||||||
rule.strategy = dNSItem.SingboxStrategy4Direct.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Direct;
|
rule.strategy = string.IsNullOrEmpty(dNSItem.SingboxStrategy4Direct) ? null : dNSItem.SingboxStrategy4Direct;
|
||||||
if (!dNSItem.DirectExpectedIPs.IsNullOrEmpty())
|
|
||||||
|
if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0)
|
||||||
{
|
{
|
||||||
rule.rule_set = new() { dNSItem.DirectExpectedIPs };
|
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)
|
else if (item.OutboundTag == Global.ProxyTag)
|
||||||
|
@ -1777,7 +1809,7 @@ public class CoreConfigSingboxService
|
||||||
singboxConfig.dns.rules.Add(rule4Fake);
|
singboxConfig.dns.rules.Add(rule4Fake);
|
||||||
}
|
}
|
||||||
rule.server = "dns_remote";
|
rule.server = "dns_remote";
|
||||||
rule.strategy = dNSItem.SingboxStrategy4Proxy.IsNullOrEmpty() ? null : dNSItem.SingboxStrategy4Proxy;
|
rule.strategy = string.IsNullOrEmpty(dNSItem.SingboxStrategy4Proxy) ? null : dNSItem.SingboxStrategy4Proxy;
|
||||||
}
|
}
|
||||||
else if (item.OutboundTag == Global.BlockTag)
|
else if (item.OutboundTag == Global.BlockTag)
|
||||||
{
|
{
|
||||||
|
@ -1785,11 +1817,11 @@ public class CoreConfigSingboxService
|
||||||
rule.rcode = "NOERROR";
|
rule.rcode = "NOERROR";
|
||||||
rule.answer = new List<string> { "A" };
|
rule.answer = new List<string> { "A" };
|
||||||
}
|
}
|
||||||
|
|
||||||
singboxConfig.dns.rules.Add(rule);
|
singboxConfig.dns.rules.Add(rule);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return await Task.FromResult(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Server4Sbox? ParseDnsAddress(string address)
|
private static Server4Sbox? ParseDnsAddress(string address)
|
||||||
|
|
|
@ -1167,194 +1167,155 @@ public class CoreConfigV2rayService
|
||||||
|
|
||||||
private async Task<int> GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, DNSItem dNSItem)
|
private async Task<int> GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, DNSItem dNSItem)
|
||||||
{
|
{
|
||||||
var directDNSAddress = dNSItem?.DirectDNS?
|
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
|
||||||
.Split(dNSItem.DirectDNS?.Contains(',') == true ? ',' : ';')
|
{
|
||||||
|
var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';')
|
||||||
.Select(addr => addr.Trim())
|
.Select(addr => addr.Trim())
|
||||||
.Where(addr => !string.IsNullOrEmpty(addr))
|
.Where(addr => !string.IsNullOrEmpty(addr))
|
||||||
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
|
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList() ?? new List<string> { defaultAddress };
|
||||||
|
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
|
||||||
if (directDNSAddress != null && directDNSAddress.Count == 0)
|
|
||||||
{
|
|
||||||
directDNSAddress = new() { Global.DomainDirectDNSAddress.FirstOrDefault() };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var remoteDNSAddress = dNSItem?.RemoteDNS?
|
static object CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||||
.Split(dNSItem.RemoteDNS?.Contains(',') == true ? ',' : ';')
|
|
||||||
.Select(addr => addr.Trim())
|
|
||||||
.Where(addr => !string.IsNullOrEmpty(addr))
|
|
||||||
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
|
|
||||||
.Distinct()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (remoteDNSAddress != null && remoteDNSAddress.Count == 0)
|
|
||||||
{
|
{
|
||||||
remoteDNSAddress = new() { Global.DomainRemoteDNSAddress.FirstOrDefault() };
|
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(dNSItem?.DirectDNS, Global.DomainDirectDNSAddress.FirstOrDefault());
|
||||||
|
var remoteDNSAddress = ParseDnsAddresses(dNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.FirstOrDefault());
|
||||||
|
|
||||||
var directDomainList = new List<string>();
|
var directDomainList = new List<string>();
|
||||||
var directGeositeList = new List<string>();
|
var directGeositeList = new List<string>();
|
||||||
var proxyDomainList = new List<string>();
|
var proxyDomainList = new List<string>();
|
||||||
var proxyGeositeList = 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(dNSItem?.DirectExpectedIPs))
|
||||||
|
{
|
||||||
|
expectedIPs = dNSItem.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);
|
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||||
if (routing != null)
|
if (routing != null)
|
||||||
{
|
{
|
||||||
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
|
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
|
||||||
foreach (var item in rules ?? [])
|
foreach (var item in rules)
|
||||||
{
|
{
|
||||||
if (!item.Enabled)
|
if (!item.Enabled || item.Domain is null || item.Domain.Count == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (item.Domain == null || item.Domain.Count == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.OutboundTag == Global.DirectTag)
|
|
||||||
{
|
|
||||||
foreach (var domain in item.Domain)
|
foreach (var domain in item.Domain)
|
||||||
{
|
{
|
||||||
if (domain.StartsWith('#'))
|
if (domain.StartsWith('#'))
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ",");
|
||||||
var domain1 = domain.Replace(Global.RoutingRuleComma, ",");
|
|
||||||
if (domain1.StartsWith("geosite:"))
|
if (item.OutboundTag == Global.DirectTag)
|
||||||
{
|
{
|
||||||
directGeositeList.Add(domain1);
|
if (normalizedDomain.StartsWith("geosite:"))
|
||||||
|
{
|
||||||
|
(regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
directDomainList.Add(domain1);
|
directDomainList.Add(normalizedDomain);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.OutboundTag == Global.ProxyTag)
|
else if (item.OutboundTag == Global.ProxyTag)
|
||||||
{
|
{
|
||||||
foreach (var domain in item.Domain)
|
if (normalizedDomain.StartsWith("geosite:"))
|
||||||
{
|
{
|
||||||
if (domain.StartsWith('#'))
|
proxyGeositeList.Add(normalizedDomain);
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var domain1 = domain.Replace(Global.RoutingRuleComma, ",");
|
|
||||||
if (domain1.StartsWith("geosite:"))
|
|
||||||
{
|
|
||||||
proxyGeositeList.Add(domain1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
proxyDomainList.Add(domain1);
|
proxyDomainList.Add(normalizedDomain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsDomain(node.Address))
|
if (Utils.IsDomain(node?.Address))
|
||||||
{
|
{
|
||||||
directDomainList.Add(node.Address);
|
directDomainList.Add(node.Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node?.Subid is not null)
|
||||||
|
{
|
||||||
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
||||||
if (subItem is not null)
|
if (subItem is not null)
|
||||||
{
|
{
|
||||||
// Previous proxy
|
foreach (var profile in new[] { subItem.PrevProfile, subItem.NextProfile })
|
||||||
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
|
||||||
if (prevNode is not null
|
|
||||||
&& prevNode.ConfigType != EConfigType.Custom
|
|
||||||
&& prevNode.ConfigType != EConfigType.Hysteria2
|
|
||||||
&& prevNode.ConfigType != EConfigType.TUIC
|
|
||||||
&& prevNode.ConfigType != EConfigType.Anytls
|
|
||||||
&& Utils.IsDomain(prevNode.Address))
|
|
||||||
{
|
{
|
||||||
directDomainList.Add(prevNode.Address);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next proxy
|
|
||||||
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
|
||||||
if (nextNode is not null
|
|
||||||
&& nextNode.ConfigType != EConfigType.Custom
|
|
||||||
&& nextNode.ConfigType != EConfigType.Hysteria2
|
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC
|
|
||||||
&& nextNode.ConfigType != EConfigType.Anytls
|
|
||||||
&& Utils.IsDomain(nextNode.Address))
|
|
||||||
{
|
|
||||||
directDomainList.Add(nextNode.Address);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v2rayConfig.dns ??= new Dns4Ray();
|
v2rayConfig.dns ??= new Dns4Ray();
|
||||||
v2rayConfig.dns.servers ??= new List<object>();
|
v2rayConfig.dns.servers ??= new List<object>();
|
||||||
|
|
||||||
var options = new JsonSerializerOptions
|
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
|
||||||
{
|
{
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
if (domains.Count > 0)
|
||||||
};
|
|
||||||
|
|
||||||
if (proxyDomainList.Count > 0)
|
|
||||||
{
|
{
|
||||||
foreach (var dnsDomain in remoteDNSAddress)
|
foreach (var dnsAddress in dnsAddresses)
|
||||||
{
|
{
|
||||||
var dnsServer = new DnsServer4Ray
|
v2rayConfig.dns.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
|
||||||
{
|
}
|
||||||
address = dnsDomain,
|
|
||||||
skipFallback = true,
|
|
||||||
domains = proxyDomainList
|
|
||||||
};
|
|
||||||
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directDomainList.Count > 0)
|
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
||||||
{
|
AddDnsServers(directDNSAddress, directDomainList);
|
||||||
foreach (var dnsDomain in directDNSAddress)
|
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||||
{
|
AddDnsServers(directDNSAddress, directGeositeList);
|
||||||
var dnsServer = new DnsServer4Ray
|
AddDnsServers(directDNSAddress, expectedDomainList, expectedIPs);
|
||||||
{
|
|
||||||
address = dnsDomain,
|
|
||||||
skipFallback = true,
|
|
||||||
domains = directDomainList,
|
|
||||||
expectedIPs = dNSItem.DirectExpectedIPs.IsNullOrEmpty() ? null : new() { dNSItem.DirectExpectedIPs }
|
|
||||||
};
|
|
||||||
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (proxyGeositeList.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var dnsDomain in remoteDNSAddress)
|
|
||||||
{
|
|
||||||
var dnsServer = new DnsServer4Ray()
|
|
||||||
{
|
|
||||||
address = dnsDomain,
|
|
||||||
skipFallback = true,
|
|
||||||
domains = proxyGeositeList
|
|
||||||
};
|
|
||||||
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (directGeositeList.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var dnsDomain in directDNSAddress)
|
|
||||||
{
|
|
||||||
var dnsServer = new DnsServer4Ray()
|
|
||||||
{
|
|
||||||
address = dnsDomain,
|
|
||||||
skipFallback = true,
|
|
||||||
domains = directGeositeList,
|
|
||||||
expectedIPs = dNSItem.DirectExpectedIPs.IsNullOrEmpty() ? null : new() { dNSItem.DirectExpectedIPs }
|
|
||||||
};
|
|
||||||
v2rayConfig.dns.servers.Add(JsonUtils.SerializeToNode(dnsServer, options));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback DNS server
|
v2rayConfig.dns.servers.AddRange(remoteDNSAddress);
|
||||||
// TODO: Select fallback DNS server based on routing rules
|
|
||||||
foreach (var dnsDomain in remoteDNSAddress)
|
return 0;
|
||||||
{
|
|
||||||
v2rayConfig.dns.servers.Add(dnsDomain);
|
|
||||||
}
|
|
||||||
return await Task.FromResult(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenDnsHosts(V2rayConfig v2rayConfig, DNSItem dNSItem)
|
private async Task<int> GenDnsHosts(V2rayConfig v2rayConfig, DNSItem dNSItem)
|
||||||
|
|
|
@ -32,15 +32,15 @@ public partial class DNSSettingWindow
|
||||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
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.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.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.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.SelectedItem).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);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue