diff --git a/v2rayN/ServiceLib/Common/WindowsUtils.cs b/v2rayN/ServiceLib/Common/WindowsUtils.cs index 2215a3e3..d801c343 100644 --- a/v2rayN/ServiceLib/Common/WindowsUtils.cs +++ b/v2rayN/ServiceLib/Common/WindowsUtils.cs @@ -53,19 +53,23 @@ internal static class WindowsUtils public static async Task RemoveTunDevice() { - try + var tunNameList = new List { "singbox_tun", "xray_tun" }; + foreach (var tunName in tunNameList) { - var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun")); - var guid = new Guid(sum); - var pnpUtilPath = @"C:\Windows\System32\pnputil.exe"; - var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """; + try + { + var sum = MD5.HashData(Encoding.UTF8.GetBytes($"wintun{tunName}")); + var guid = new Guid(sum); + var pnpUtilPath = @"C:\Windows\System32\pnputil.exe"; + var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """; - // Try to remove the device - _ = await Utils.GetCliWrapOutput(pnpUtilPath, arg); - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); + // Try to remove the device + _ = await Utils.GetCliWrapOutput(pnpUtilPath, arg); + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } } } } diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index bf8dd7ab..ffb7c9c2 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -24,6 +24,8 @@ public class Global public const string V2raySampleHttpResponseFileName = NamespaceSample + "SampleHttpResponse"; public const string V2raySampleInbound = NamespaceSample + "SampleInbound"; public const string V2raySampleOutbound = NamespaceSample + "SampleOutbound"; + public const string V2raySampleTunInbound = NamespaceSample + "SampleTunInbound"; + public const string V2raySampleTunRules = NamespaceSample + "SampleTunRules"; public const string SingboxSampleOutbound = NamespaceSample + "SingboxSampleOutbound"; public const string CustomRoutingFileName = NamespaceSample + "custom_routing_"; public const string TunSingboxDNSFileName = NamespaceSample + "tun_singbox_dns"; @@ -48,6 +50,7 @@ public class Global public const string ProxyTag = "proxy"; public const string DirectTag = "direct"; public const string BlockTag = "block"; + public const string DnsOutboundTag = "dns"; public const string DnsTag = "dns-module"; public const string DirectDnsTag = "direct-dns"; public const string BalancerTagSuffix = "-round"; diff --git a/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs b/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs index 8d1d0eb7..8f316105 100644 --- a/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs +++ b/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs @@ -31,8 +31,6 @@ public record CoreConfigContextBuilderAllResult( public CoreConfigContext ResolvedMainContext => PreSocksResult is not null ? MainResult.Context with { - TunProtectSsPort = PreSocksResult.Context.TunProtectSsPort, - ProxyRelaySsPort = PreSocksResult.Context.ProxyRelaySsPort, ProtectDomainList = [.. MainResult.Context.ProtectDomainList ?? [], .. PreSocksResult.Context.ProtectDomainList ?? []], } : MainResult.Context; @@ -58,8 +56,6 @@ public class CoreConfigContextBuilder IsTunEnabled = config.TunModeItem.EnableTun, SimpleDnsItem = config.SimpleDNSItem, ProtectDomainList = [], - TunProtectSsPort = 0, - ProxyRelaySsPort = 0, RawDnsItem = await AppManager.Instance.GetDNSItem(coreType), RoutingItem = await ConfigHandler.GetDefaultRouting(config), }; @@ -148,37 +144,7 @@ public class CoreConfigContextBuilder }; } - if (!nodeContext.IsTunEnabled - || coreType != ECoreType.Xray - || node.ConfigType == EConfigType.Custom) - { - return null; - } - - var tunProtectSsPort = Utils.GetFreePort(); - var proxyRelaySsPort = Utils.GetFreePort(); - var preItem = new ProfileItem() - { - CoreType = ECoreType.sing_box, - ConfigType = EConfigType.Shadowsocks, - Address = Global.Loopback, - Port = proxyRelaySsPort, - Password = Global.None, - }; - preItem.SetProtocolExtra(preItem.GetProtocolExtra() with - { - SsMethod = Global.None, - }); - var preResult2 = await Build(nodeContext.AppConfig, preItem); - return preResult2 with - { - Context = preResult2.Context with - { - ProtectDomainList = [.. nodeContext.ProtectDomainList ?? [], .. preResult2.Context.ProtectDomainList ?? []], - TunProtectSsPort = tunProtectSsPort, - ProxyRelaySsPort = proxyRelaySsPort, - } - }; + return null; } /// diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 167820f0..3f22a770 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1416,20 +1416,7 @@ public static class ConfigHandler public static ProfileItem? GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType) { ProfileItem? itemSocks = null; - if (node.ConfigType != EConfigType.Custom - && coreType != ECoreType.sing_box - && config.TunModeItem.EnableTun - && config.TunModeItem.EnableLegacyProtect) - { - itemSocks = new ProfileItem() - { - CoreType = ECoreType.sing_box, - ConfigType = EConfigType.SOCKS, - Address = Global.Loopback, - Port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks) - }; - } - else if (node.ConfigType == EConfigType.Custom + if (node.ConfigType == EConfigType.Custom && node.PreSocksPort is > 0 and <= 65535) { var preCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray; diff --git a/v2rayN/ServiceLib/Models/CoreConfigContext.cs b/v2rayN/ServiceLib/Models/CoreConfigContext.cs index a9a49f96..78e09d76 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigContext.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigContext.cs @@ -17,9 +17,4 @@ public record CoreConfigContext // TUN Compatibility public bool IsTunEnabled { get; init; } = false; public HashSet ProtectDomainList { get; init; } = new(); - // -> tun inbound --(if routing proxy)--> relay outbound - // -> proxy core (relay inbound --> proxy outbound --(dialerProxy)--> protect outbound) - // -> protect inbound -> direct proxy outbound data -> internet - public int TunProtectSsPort { get; init; } = 0; - public int ProxyRelaySsPort { get; init; } = 0; } diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index 983cb4da..fc7c2300 100644 --- a/v2rayN/ServiceLib/Models/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs @@ -75,6 +75,18 @@ public class Inboundsettings4Ray public bool? allowTransparent { get; set; } public List? accounts { get; set; } + + public string? name { get; set; } + + public List? MTU { get; set; } + + public List? gateway { get; set; } + + public List? autoSystemRoutingTable { get; set; } + + public string? autoOutboundsInterface { get; set; } + + // public List? dns { get; set; } } public class UsersItem4Ray @@ -509,6 +521,8 @@ public class AccountsItem4Ray public class Sockopt4Ray { public string? dialerProxy { get; set; } + [JsonPropertyName("interface")] + public string? Interface { get; set; } } public class FragmentItem4Ray diff --git a/v2rayN/ServiceLib/Sample/SampleTunInbound b/v2rayN/ServiceLib/Sample/SampleTunInbound new file mode 100644 index 00000000..03467b3e --- /dev/null +++ b/v2rayN/ServiceLib/Sample/SampleTunInbound @@ -0,0 +1,26 @@ +{ + "tag": "tun", + "protocol": "tun", + "settings": { + "name": "xray_tun", + "MTU": [ + 9000 + ], + "gateway": [ + "172.18.0.1/30", + "fdfe:dcba:9876::1/126" + ], + "autoSystemRoutingTable": [ + "0.0.0.0/0", + "::/0" + ], + "autoOutboundsInterface": "auto" + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ] + } +} \ No newline at end of file diff --git a/v2rayN/ServiceLib/Sample/SampleTunRules b/v2rayN/ServiceLib/Sample/SampleTunRules new file mode 100644 index 00000000..ca6eb051 --- /dev/null +++ b/v2rayN/ServiceLib/Sample/SampleTunRules @@ -0,0 +1,14 @@ +[ + { + "network": "udp", + "port": "135,137-139,5353", + "outboundTag": "block" + }, + { + "ip": [ + "224.0.0.0/3", + "ff00::/8" + ], + "outboundTag": "block" + } +] \ No newline at end of file diff --git a/v2rayN/ServiceLib/ServiceLib.csproj b/v2rayN/ServiceLib/ServiceLib.csproj index 8cfbf8ca..169c1080 100644 --- a/v2rayN/ServiceLib/ServiceLib.csproj +++ b/v2rayN/ServiceLib/ServiceLib.csproj @@ -38,6 +38,8 @@ + + diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs index 9844c4f9..983a9ebb 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs @@ -61,52 +61,6 @@ public partial class CoreConfigSingboxService(CoreConfigContext context) ret.Success = true; ret.Data = ApplyFullConfigTemplate(); - if (!context.AppConfig.TunModeItem.EnableLegacyProtect - && context.TunProtectSsPort is > 0 and <= 65535) - { - var ssInbound = new - { - type = "shadowsocks", - tag = "tun-protect-ss", - listen = Global.Loopback, - listen_port = context.TunProtectSsPort, - method = "none", - password = "none", - }; - var directRule = new Rule4Sbox() - { - inbound = new List { ssInbound.tag }, - outbound = Global.DirectTag, - }; - var singboxConfigNode = JsonUtils.ParseJson(ret.Data.ToString())!.AsObject(); - var inboundsNode = singboxConfigNode["inbounds"]!.AsArray(); - inboundsNode.Add(JsonUtils.SerializeToNode(ssInbound, new JsonSerializerOptions - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - })); - var routeNode = singboxConfigNode["route"]?.AsObject(); - var rulesNode = routeNode?["rules"]?.AsArray(); - var protectRuleNode = JsonUtils.SerializeToNode(directRule, - new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }); - if (rulesNode != null) - { - rulesNode.Insert(0, protectRuleNode); - } - else - { - var newRulesNode = new JsonArray() { protectRuleNode }; - if (routeNode is null) - { - var newRouteNode = new JsonObject() { ["rules"] = newRulesNode }; - singboxConfigNode["route"] = newRouteNode; - } - else - { - routeNode["rules"] = newRulesNode; - } - } - ret.Data = JsonUtils.Serialize(singboxConfigNode); - } return ret; } catch (Exception ex) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index f422da96..7a86761f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -345,14 +345,6 @@ public partial class CoreConfigSingboxService { try { - // The synthetic TUN relay outbound talks to the local Xray shadowsocks relay. - // Xray cannot terminate sing-box h2mux, so muxing here turns local relay traffic - // into sp.mux.sing-box.arpa pseudo-destinations and breaks DNS over TUN. - if (IsTunRelayProxyOutbound()) - { - return; - } - var muxEnabled = _node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty()) { @@ -372,21 +364,6 @@ public partial class CoreConfigSingboxService } } - private bool IsTunRelayProxyOutbound() - { - if (!context.IsTunEnabled - || _node.ConfigType != EConfigType.Shadowsocks - || _node.Address != Global.Loopback - || _node.Port != context.ProxyRelaySsPort - || _node.Password != Global.None) - { - return false; - } - - var protocolExtra = _node.GetProtocolExtra(); - return protocolExtra.SsMethod == Global.None; - } - private void FillOutboundTls(Outbound4Sbox outbound) { try diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs index 71e30e45..0cece085 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs @@ -15,13 +15,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) var ret = new RetResult(); try { - if (!context.AppConfig.TunModeItem.EnableLegacyProtect - && context.IsTunEnabled - && context.TunProtectSsPort is > 0 and <= 65535 - && context.ProxyRelaySsPort is > 0 and <= 65535) - { - return GenerateClientProxyRelayConfig(); - } if (_node == null || !_node.IsValid()) { @@ -269,140 +262,5 @@ public partial class CoreConfigV2rayService(CoreConfigContext context) } } - public RetResult GenerateClientProxyRelayConfig() - { - var ret = new RetResult(); - try - { - if (_node == null - || !_node.IsValid()) - { - ret.Msg = ResUI.CheckServerSettings; - return ret; - } - - if (_node.GetNetwork() is nameof(ETransport.quic)) - { - ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}"; - return ret; - } - - var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient); - if (result.IsNullOrEmpty()) - { - ret.Msg = ResUI.FailedGetDefaultConfiguration; - return ret; - } - - _coreConfig = JsonUtils.Deserialize(result); - if (_coreConfig == null) - { - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - - GenLog(); - _coreConfig.outbounds.Clear(); - GenOutbounds(); - GenStatistic(); - - var protectNode = new ProfileItem() - { - CoreType = ECoreType.Xray, - ConfigType = EConfigType.Shadowsocks, - Address = Global.Loopback, - Port = context.TunProtectSsPort, - Password = Global.None, - }; - protectNode.SetProtocolExtra(protectNode.GetProtocolExtra() with - { - SsMethod = Global.None, - }); - - const string protectTag = "tun-protect-ss"; - foreach (var outbound in _coreConfig.outbounds - .Where(o => o.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true)) - { - outbound.streamSettings ??= new(); - outbound.streamSettings.sockopt ??= new(); - outbound.streamSettings.sockopt.dialerProxy = protectTag; - } - // ech protected - foreach (var outbound in _coreConfig.outbounds - .Where(outbound => outbound.streamSettings?.tlsSettings?.echConfigList?.IsNullOrEmpty() == false)) - { - outbound.streamSettings!.tlsSettings!.echSockopt ??= new(); - outbound.streamSettings.tlsSettings.echSockopt.dialerProxy = protectTag; - } - // xhttp download protected - foreach (var outbound in _coreConfig.outbounds - .Where(o => o.streamSettings?.xhttpSettings?.extra is not null)) - { - var xhttpExtra = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings.xhttpSettings!.extra)); - if (xhttpExtra is not JsonObject xhttpExtraObject - || xhttpExtraObject["downloadSettings"] is not JsonObject downloadSettings) - { - continue; - } - // dialerProxy - var sockopt = downloadSettings["sockopt"] as JsonObject ?? new JsonObject(); - sockopt["dialerProxy"] = protectTag; - downloadSettings["sockopt"] = sockopt; - // ech protected - if (downloadSettings["tlsSettings"] is JsonObject tlsSettings - && tlsSettings["echConfigList"] is not null) - { - tlsSettings["echSockopt"] = new JsonObject - { - ["dialerProxy"] = protectTag - }; - } - outbound.streamSettings.xhttpSettings.extra = xhttpExtraObject; - } - _coreConfig.outbounds.Add(new CoreConfigV2rayService(context with - { - Node = protectNode, - }).BuildProxyOutbound(protectTag)); - - _coreConfig.routing.rules ??= []; - var hasBalancer = _coreConfig.routing.balancers is { Count: > 0 }; - _coreConfig.routing.rules.Add(new() - { - inboundTag = ["proxy-relay-ss"], - outboundTag = hasBalancer ? null : Global.ProxyTag, - balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix : null, - type = "field" - }); - - //_coreConfig.inbounds.Clear(); - - var configNode = JsonUtils.ParseJson(JsonUtils.Serialize(_coreConfig))!; - configNode["inbounds"]!.AsArray().Add(new - { - listen = Global.Loopback, - port = context.ProxyRelaySsPort, - protocol = "shadowsocks", - settings = new - { - network = "tcp,udp", - method = Global.None, - password = Global.None, - }, - tag = "proxy-relay-ss", - }); - - ret.Msg = string.Format(ResUI.SuccessfulConfiguration, ""); - ret.Success = true; - ret.Data = JsonUtils.Serialize(configNode); - return ret; - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - ret.Msg = ResUI.FailedGenDefaultConfiguration; - return ret; - } - } - #endregion public gen function } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs index 7ae12c7c..29c12753 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs @@ -7,36 +7,61 @@ public partial class CoreConfigV2rayService try { var listen = "0.0.0.0"; + var listenPort = AppManager.Instance.GetLocalPort(EInboundProtocol.socks); _coreConfig.inbounds = []; - var inbound = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks, true); - _coreConfig.inbounds.Add(inbound); - if (_config.Inbound.First().SecondLocalPortEnabled) + if (!context.IsTunEnabled + || (context.IsTunEnabled && _node.Port != listenPort)) { - var inbound2 = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks2, true); - _coreConfig.inbounds.Add(inbound2); - } + _coreConfig.inbounds.Add(inbound); - if (_config.Inbound.First().AllowLANConn) - { - if (_config.Inbound.First().NewPort4LAN) + if (_config.Inbound.First().SecondLocalPortEnabled) { - var inbound3 = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks3, true); - inbound3.listen = listen; - _coreConfig.inbounds.Add(inbound3); + var inbound2 = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks2, true); + _coreConfig.inbounds.Add(inbound2); + } - //auth - if (_config.Inbound.First().User.IsNotEmpty() && _config.Inbound.First().Pass.IsNotEmpty()) + if (_config.Inbound.First().AllowLANConn) + { + if (_config.Inbound.First().NewPort4LAN) { - inbound3.settings.auth = "password"; - inbound3.settings.accounts = new List { new() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } }; + var inbound3 = BuildInbound(_config.Inbound.First(), EInboundProtocol.socks3, true); + inbound3.listen = listen; + _coreConfig.inbounds.Add(inbound3); + + //auth + if (_config.Inbound.First().User.IsNotEmpty() && _config.Inbound.First().Pass.IsNotEmpty()) + { + inbound3.settings.auth = "password"; + inbound3.settings.accounts = new List + { + new() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } + }; + } + } + else + { + inbound.listen = listen; } } - else + } + + if (context.IsTunEnabled) + { + if (_config.TunModeItem.Mtu <= 0) { - inbound.listen = listen; + _config.TunModeItem.Mtu = Global.TunMtus.First(); } + var tunInbound = JsonUtils.Deserialize(EmbedUtils.GetEmbedText(Global.V2raySampleTunInbound)) ?? new Inbounds4Ray { }; + tunInbound.settings.name = Utils.IsMacOS() ? $"utun{new Random().Next(99)}" : "xray_tun"; + tunInbound.settings.MTU = [_config.TunModeItem.Mtu]; + if (_config.TunModeItem.EnableIPv6Address == false) + { + tunInbound.settings.gateway = ["172.18.0.1/30"]; + } + tunInbound.sniffing = inbound.sniffing; + _coreConfig.inbounds.Add(tunInbound); } } catch (Exception ex) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 5bf3f1dd..a919e554 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -12,6 +12,10 @@ public partial class CoreConfigV2rayService GenObservatory(multipleLoad); GenBalancer(multipleLoad); } + if (context.IsTunEnabled) + { + _coreConfig.outbounds.Add(BuildDnsOutbound()); + } } private List BuildAllProxyOutbounds(string baseTagName = Global.ProxyTag) @@ -824,4 +828,10 @@ public partial class CoreConfigV2rayService } } } + + private static Outbounds4Ray BuildDnsOutbound() + { + var outbound = new Outbounds4Ray { tag = Global.DnsOutboundTag, protocol = "dns", }; + return outbound; + } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs index dd752a68..c6d61ab9 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs @@ -6,6 +6,31 @@ public partial class CoreConfigV2rayService { try { + if (_config.TunModeItem.EnableTun) + { + var tunRules = JsonUtils.Deserialize>(EmbedUtils.GetEmbedText(Global.V2raySampleTunRules)); + if (tunRules != null) + { + _coreConfig.routing.rules.AddRange(tunRules); + } + var (lstDnsExe, lstDirectExe) = BuildRoutingDirectExe(); + _coreConfig.routing.rules.Add(new() + { + port = "53", + process = lstDnsExe, + outboundTag = Global.DnsOutboundTag, + }); + _coreConfig.routing.rules.Add(new() + { + process = lstDirectExe, + outboundTag = Global.DirectTag, + }); + _coreConfig.routing.rules.Add(new() + { + port = "53", + outboundTag = Global.DnsOutboundTag, + }); + } if (_coreConfig.routing?.rules != null) { _coreConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy; @@ -205,4 +230,37 @@ public partial class CoreConfigV2rayService } return finalRule; } + + private static (List lstDnsExe, List lstDirectExe) BuildRoutingDirectExe() + { + var dnsExeSet = new HashSet(StringComparer.OrdinalIgnoreCase); + var directExeSet = new HashSet(StringComparer.OrdinalIgnoreCase); + + var coreInfoResult = CoreInfoManager.Instance.GetCoreInfo(); + + foreach (var coreConfig in coreInfoResult) + { + if (coreConfig.CoreType == ECoreType.v2rayN) + { + continue; + } + + foreach (var baseExeName in coreConfig.CoreExes) + { + if (coreConfig.CoreType != ECoreType.sing_box) + { + dnsExeSet.Add(Utils.GetExeName(baseExeName)); + } + directExeSet.Add(Utils.GetExeName(baseExeName)); + } + } + + directExeSet.Add("xray/"); + directExeSet.Add("self/"); + + var lstDnsExe = new List(dnsExeSet); + var lstDirectExe = new List(directExeSet); + + return (lstDnsExe, lstDirectExe); + } }