mirror of
https://github.com/2dust/v2rayN.git
synced 2026-03-12 11:23:01 +00:00
Fix hosts matching (#8890)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
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
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
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
* Fix hosts matching * Fix hosts resolve rule * Fix
This commit is contained in:
parent
81da72bb39
commit
b8f7cc0768
2 changed files with 123 additions and 33 deletions
|
|
@ -93,7 +93,23 @@ public partial class CoreConfigSingboxService
|
|||
|
||||
foreach (var kvp in Utils.ParseHostsToDictionary(simpleDnsItem.Hosts))
|
||||
{
|
||||
hostsDns.predefined[kvp.Key] = kvp.Value.Where(Utils.IsIpAddress).ToList();
|
||||
// only allow full match
|
||||
// like example.com and full:example.com,
|
||||
// but not domain:example.com, keyword:example.com or regex:example.com etc.
|
||||
var testRule = new Rule4Sbox();
|
||||
if (!ParseV2Domain(kvp.Key, testRule))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (testRule.domain_keyword?.Count > 0 && !kvp.Key.Contains(':'))
|
||||
{
|
||||
testRule.domain = testRule.domain_keyword;
|
||||
testRule.domain_keyword = null;
|
||||
}
|
||||
if (testRule.domain?.Count == 1)
|
||||
{
|
||||
hostsDns.predefined[testRule.domain.First()] = kvp.Value.Where(Utils.IsIpAddress).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var host in hostsDns.predefined)
|
||||
|
|
@ -179,20 +195,33 @@ public partial class CoreConfigSingboxService
|
|||
foreach (var kvp in Utils.ParseHostsToDictionary(simpleDnsItem.Hosts))
|
||||
{
|
||||
var predefined = kvp.Value.First();
|
||||
if (predefined.IsNullOrEmpty() || Utils.IsIpAddress(predefined))
|
||||
if (predefined.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var rule = new Rule4Sbox()
|
||||
{
|
||||
query_type = [1, 5, 28], // A, CNAME and AAAA
|
||||
action = "predefined",
|
||||
rcode = "NOERROR",
|
||||
};
|
||||
if (!ParseV2Domain(kvp.Key, rule))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// see: https://xtls.github.io/en/config/dns.html#dnsobject
|
||||
// The matching format (domain:, full:, etc.) is the same as the domain
|
||||
// in the commonly used Routing System. The difference is that without a prefix,
|
||||
// it defaults to using the full: prefix (similar to the common hosts file syntax).
|
||||
if (rule.domain_keyword?.Count > 0 && !kvp.Key.Contains(':'))
|
||||
{
|
||||
rule.domain = rule.domain_keyword;
|
||||
rule.domain_keyword = null;
|
||||
}
|
||||
// example.com #0 -> example.com with NOERROR
|
||||
if (predefined.StartsWith('#') && int.TryParse(predefined.AsSpan(1), out var rcode))
|
||||
{
|
||||
// xray syntactic sugar for predefined
|
||||
// etc. #0 -> NOERROR
|
||||
_coreConfig.dns.rules.Add(new()
|
||||
{
|
||||
query_type = [1, 28],
|
||||
domain = [kvp.Key],
|
||||
action = "predefined",
|
||||
rcode = rcode switch
|
||||
rule.rcode = rcode switch
|
||||
{
|
||||
0 => "NOERROR",
|
||||
1 => "FORMERR",
|
||||
|
|
@ -201,23 +230,32 @@ public partial class CoreConfigSingboxService
|
|||
4 => "NOTIMP",
|
||||
5 => "REFUSED",
|
||||
_ => "NOERROR",
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
else if (Utils.IsDomain(predefined))
|
||||
{
|
||||
// example.com CNAME target.com -> example.com with CNAME target.com
|
||||
rule.answer = new List<string> { $"*. IN CNAME {predefined}." };
|
||||
}
|
||||
else if (Utils.IsIpAddress(predefined) && (rule.domain?.Count ?? 0) == 0)
|
||||
{
|
||||
// not full match, but an IP address, treat it as predefined answer
|
||||
if (Utils.IsIpv6(predefined))
|
||||
{
|
||||
rule.answer = new List<string> { $"*. IN AAAA {predefined}" };
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
rule.answer = new List<string> { $"*. IN A {predefined}" };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// CNAME record
|
||||
Rule4Sbox rule = new()
|
||||
{
|
||||
query_type = [1, 28],
|
||||
action = "predefined",
|
||||
rcode = "NOERROR",
|
||||
answer = [$"*. IN CNAME {predefined}."],
|
||||
};
|
||||
if (ParseV2Domain(kvp.Key, rule))
|
||||
{
|
||||
_coreConfig.dns.rules.Add(rule);
|
||||
}
|
||||
}
|
||||
|
||||
if (simpleDnsItem.BlockBindingQuery == true)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,11 +84,58 @@ public partial class CoreConfigSingboxService
|
|||
}
|
||||
if (hostsDomains.Count > 0)
|
||||
{
|
||||
_coreConfig.route.rules.Add(new()
|
||||
var hostsResolveRule = new Rule4Sbox
|
||||
{
|
||||
action = "resolve",
|
||||
domain = hostsDomains,
|
||||
});
|
||||
};
|
||||
var hostsCounter = 0;
|
||||
foreach (var host in hostsDomains)
|
||||
{
|
||||
var domainRule = new Rule4Sbox();
|
||||
if (!ParseV2Domain(host, domainRule))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (domainRule.domain_keyword?.Count > 0 && !host.Contains(':'))
|
||||
{
|
||||
domainRule.domain = domainRule.domain_keyword;
|
||||
domainRule.domain_keyword = null;
|
||||
}
|
||||
if (domainRule.domain?.Count > 0)
|
||||
{
|
||||
hostsResolveRule.domain ??= [];
|
||||
hostsResolveRule.domain.AddRange(domainRule.domain);
|
||||
hostsCounter++;
|
||||
}
|
||||
else if (domainRule.domain_keyword?.Count > 0)
|
||||
{
|
||||
hostsResolveRule.domain_keyword ??= [];
|
||||
hostsResolveRule.domain_keyword.AddRange(domainRule.domain_keyword);
|
||||
hostsCounter++;
|
||||
}
|
||||
else if (domainRule.domain_suffix?.Count > 0)
|
||||
{
|
||||
hostsResolveRule.domain_suffix ??= [];
|
||||
hostsResolveRule.domain_suffix.AddRange(domainRule.domain_suffix);
|
||||
hostsCounter++;
|
||||
}
|
||||
else if (domainRule.domain_regex?.Count > 0)
|
||||
{
|
||||
hostsResolveRule.domain_regex ??= [];
|
||||
hostsResolveRule.domain_regex.AddRange(domainRule.domain_regex);
|
||||
hostsCounter++;
|
||||
}
|
||||
else if (domainRule.geosite?.Count > 0)
|
||||
{
|
||||
hostsResolveRule.geosite ??= [];
|
||||
hostsResolveRule.geosite.AddRange(domainRule.geosite);
|
||||
hostsCounter++;
|
||||
}
|
||||
}
|
||||
if (hostsCounter > 0)
|
||||
{
|
||||
_coreConfig.route.rules.Add(hostsResolveRule);
|
||||
}
|
||||
}
|
||||
|
||||
_coreConfig.route.rules.Add(new()
|
||||
|
|
@ -355,6 +402,11 @@ public partial class CoreConfigSingboxService
|
|||
rule.domain_keyword ??= [];
|
||||
rule.domain_keyword?.Add(domain.Substring(8));
|
||||
}
|
||||
else if (domain.StartsWith("dotless:"))
|
||||
{
|
||||
rule.domain_keyword ??= [];
|
||||
rule.domain_keyword?.Add(domain.Substring(8));
|
||||
}
|
||||
else
|
||||
{
|
||||
rule.domain_keyword ??= [];
|
||||
|
|
|
|||
Loading…
Reference in a new issue