mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-15 17:05:03 +03:00
fix(xray): keep direct DNS ahead of catch-all proxy rules (#10599)
* fix(xray): keep direct DNS ahead of catch-all proxy rules * fix(xray): cover full nonzero port range in DNS routing
This commit is contained in:
@@ -2,6 +2,98 @@ namespace ServiceLib.Tests.CoreConfig.V2ray;
|
||||
|
||||
public class CoreConfigV2rayServiceTests
|
||||
{
|
||||
[Test]
|
||||
[Arguments(false, "0-65535", null, Global.ProxyTag)]
|
||||
[Arguments(false, "1-65535", null, Global.ProxyTag)]
|
||||
[Arguments(true, "0-65535", null, Global.ProxyTag)]
|
||||
[Arguments(true, null, "tcp,udp", Global.ProxyTag)]
|
||||
[Arguments(false, null, null, Global.ProxyTag)]
|
||||
[Arguments(false, "0-65535", null, Global.BlockTag)]
|
||||
public async Task DirectDnsRule_ShouldPrecedeCatchAllAndPreserveExplicitRules(bool tun, string? port, string? network, string outbound)
|
||||
{
|
||||
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
|
||||
config.TunModeItem.EnableTun = tun;
|
||||
config.SimpleDNSItem.DirectDNS = "8.8.8.8";
|
||||
config.SimpleDNSItem.RemoteDNS = "1.1.1.1";
|
||||
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||
var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.Xray);
|
||||
var userRules = new List<RulesItem>
|
||||
{
|
||||
new() { RuleType = ERuleType.DNS, Domain = ["domain:direct.example"], OutboundTag = Global.DirectTag },
|
||||
new() { InboundTag = ["direct-dns-1"], Ip = ["8.8.8.8"], Port = "53", OutboundTag = Global.BlockTag },
|
||||
new() { Port = "443", Network = "tcp", OutboundTag = Global.ProxyTag },
|
||||
};
|
||||
if (port != null || network != null)
|
||||
{
|
||||
userRules.Add(new() { Port = port, Network = network, OutboundTag = outbound });
|
||||
}
|
||||
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.Xray) with
|
||||
{
|
||||
RoutingItem = new RoutingItem { RuleSet = JsonUtils.Serialize(userRules), DomainStrategy = Global.IPOnDemand }
|
||||
};
|
||||
|
||||
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||
|
||||
await result.Success.Should().BeTrue();
|
||||
var rules = JsonUtils.Deserialize<V2rayConfig>(result.Data!.ToString())!.routing.rules;
|
||||
var direct = rules.FindIndex(r => r.outboundTag == Global.DirectTag && r.inboundTag?.Contains("direct-dns-1") == true);
|
||||
var explicitBlock = rules.FindIndex(r => r.outboundTag == Global.BlockTag && r.inboundTag?.Contains("direct-dns-1") == true);
|
||||
var https = rules.FindIndex(r => r.port == "443" && r.network == "tcp" && r.outboundTag == Global.ProxyTag);
|
||||
await (explicitBlock >= 0 && https > explicitBlock && direct > https).Should().BeTrue();
|
||||
if (port != null || network != null)
|
||||
{
|
||||
var catchAll = rules.FindIndex(r => r.port == port && r.network == network && r.inboundTag == null && r.outboundTag == outbound);
|
||||
await (catchAll >= 0 && (outbound == Global.ProxyTag ? catchAll > direct : catchAll < direct)).Should().BeTrue();
|
||||
}
|
||||
if (tun)
|
||||
{
|
||||
var intercept = rules.FindIndex(r => r.inboundTag?.Contains("tun") == true && r.port == "53" && r.outboundTag == Global.DnsOutboundTag);
|
||||
await (intercept >= 0 && intercept < direct).Should().BeTrue();
|
||||
}
|
||||
await rules.Should().Contain(r => r.inboundTag != null && r.inboundTag.Contains(Global.DnsTag) && r.outboundTag == Global.ProxyTag);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Arguments("0-65535", null)]
|
||||
[Arguments("1-65535", null)]
|
||||
[Arguments(null, "udp,tcp")]
|
||||
public async Task DirectDnsRule_ShouldPrecedeCatchAllBalancer(string? port, string? network)
|
||||
{
|
||||
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
|
||||
config.SimpleDNSItem.DirectDNS = "8.8.8.8,https://8.8.4.4/dns-query";
|
||||
config.SimpleDNSItem.RemoteDNS = "1.1.1.1";
|
||||
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||
var n1 = CoreConfigTestFactory.CreateSocksNode(ECoreType.Xray, "n1", "node-1");
|
||||
var n2 = CoreConfigTestFactory.CreateSocksNode(ECoreType.Xray, "n2", "node-2");
|
||||
var group = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, "g1", "group", [n1.IndexId, n2.IndexId]);
|
||||
var context = CoreConfigTestFactory.CreateContext(config, group, ECoreType.Xray) with
|
||||
{
|
||||
RoutingItem = new RoutingItem
|
||||
{
|
||||
RuleSet = JsonUtils.Serialize(new List<RulesItem>
|
||||
{
|
||||
new() { RuleType = ERuleType.DNS, Domain = ["domain:direct.example"], OutboundTag = Global.DirectTag },
|
||||
new() { Port = port, Network = network, OutboundTag = Global.ProxyTag },
|
||||
}),
|
||||
DomainStrategy = Global.AsIs,
|
||||
},
|
||||
};
|
||||
context.AllProxiesMap[n1.IndexId] = n1;
|
||||
context.AllProxiesMap[n2.IndexId] = n2;
|
||||
|
||||
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||
|
||||
await result.Success.Should().BeTrue();
|
||||
var rules = JsonUtils.Deserialize<V2rayConfig>(result.Data!.ToString())!.routing.rules;
|
||||
var direct = rules.FindIndex(r => r.outboundTag == Global.DirectTag && r.inboundTag?.Contains("direct-dns-1") == true);
|
||||
var catchAll = rules.FindIndex(r => r.port == port && r.network == network && r.inboundTag == null
|
||||
&& r.balancerTag == Global.ProxyTag + Global.BalancerTagSuffix);
|
||||
await (direct >= 0 && catchAll > direct).Should().BeTrue();
|
||||
await rules[direct].inboundTag.Should().Contain("direct-dns-2");
|
||||
await rules.Should().Contain(r => r.inboundTag != null && r.inboundTag.Contains(Global.DnsTag)
|
||||
&& r.balancerTag == Global.ProxyTag + Global.BalancerTagSuffix);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Arguments("demo-seed", "srtp", 2)]
|
||||
[Arguments(null, "srtp", 2)]
|
||||
|
||||
@@ -99,7 +99,9 @@ public partial class CoreConfigV2rayService
|
||||
.ToList();
|
||||
if (directDnsTags.Count > 0)
|
||||
{
|
||||
_coreConfig.routing.rules.Add(new()
|
||||
var rules = _coreConfig.routing.rules;
|
||||
var catchAllIndex = rules.FindIndex(IsDnsRoutingCatchAll);
|
||||
rules.Insert(catchAllIndex < 0 ? rules.Count : catchAllIndex, new()
|
||||
{
|
||||
type = "field",
|
||||
inboundTag = directDnsTags,
|
||||
@@ -125,6 +127,18 @@ public partial class CoreConfigV2rayService
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDnsRoutingCatchAll(RulesItem4Ray rule)
|
||||
{
|
||||
return (rule.outboundTag == Global.ProxyTag || rule.balancerTag == Global.ProxyTag + Global.BalancerTagSuffix)
|
||||
&& rule.inboundTag is not { Count: > 0 }
|
||||
&& rule.domain is not { Count: > 0 }
|
||||
&& rule.ip is not { Count: > 0 }
|
||||
&& rule.protocol is not { Count: > 0 }
|
||||
&& rule.process is not { Count: > 0 }
|
||||
&& rule.port is null or "0-65535" or "1-65535"
|
||||
&& rule.network is null or "tcp,udp" or "udp,tcp";
|
||||
}
|
||||
|
||||
private void GenFakeDns()
|
||||
{
|
||||
var fakeipRange = _config.SimpleDNSItem.FakeIPRange.IsNullOrEmpty() ? Global.FakeIPRanges.First() : _config.SimpleDNSItem.FakeIPRange;
|
||||
|
||||
Reference in New Issue
Block a user