From dbd65e6f16f4a2e84c9df09770a8461d2c42b2fa Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sun, 6 Apr 2025 21:34:23 +0800 Subject: [PATCH 01/16] Migrating to singbox 1.11 support --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 32 +++++++- .../Sample/SingboxSampleClientConfig | 14 +--- v2rayN/ServiceLib/Sample/tun_singbox_rules | 4 +- .../CoreConfig/CoreConfigSingboxService.cs | 74 ++++++++++++------- 4 files changed, 80 insertions(+), 44 deletions(-) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index 9ea1157d..cbb2cb29 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -67,6 +67,9 @@ public class Rule4Sbox public List? process_name { get; set; } public List? rule_set { get; set; } public List? rules { get; set; } + public string? action { get; set; } + public string? strategy { get; set; } + public List? sniffer { get; set; } } [Serializable] @@ -76,7 +79,6 @@ public class Inbound4Sbox public string tag { get; set; } public string listen { get; set; } public int? listen_port { get; set; } - public string? domain_strategy { get; set; } public string interface_name { get; set; } public List? address { get; set; } public int? mtu { get; set; } @@ -84,8 +86,6 @@ public class Inbound4Sbox public bool? strict_route { get; set; } public bool? endpoint_independent_nat { get; set; } public string? stack { get; set; } - public bool? sniff { get; set; } - public bool? sniff_override_destination { get; set; } public List users { get; set; } } @@ -136,6 +136,32 @@ public class Outbound4Sbox public bool? interrupt_exist_connections { get; set; } } +public class Endpoints4Sbox +{ + public string type { get; set; } + public string tag { get; set; } + public bool? system { get; set; } + public string? name { get; set; } + public int? mtu { get; set; } + public List address { get; set; } + public string private_key { get; set; } + public int listen_port { get; set; } + public string? udp_timeout { get; set; } + public int? workers { get; set; } + public List peers { get; set; } +} + +public class Peer4Sbox +{ + public string address { get; set; } + public int port { get; set; } + public string public_key { get; set; } + public string? pre_shared_key { get; set; } + public List allowed_ips { get; set; } + public int? persistent_keepalive_interval { get; set; } + public List reserved { get; set; } +} + public class Tls4Sbox { public bool enabled { get; set; } diff --git a/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig b/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig index f88422a1..b07fd72c 100644 --- a/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig +++ b/v2rayN/ServiceLib/Sample/SingboxSampleClientConfig @@ -1,4 +1,4 @@ -{ +{ "log": { "level": "debug", "timestamp": true @@ -14,22 +14,10 @@ { "type": "direct", "tag": "direct" - }, - { - "type": "block", - "tag": "block" - }, - { - "tag": "dns_out", - "type": "dns" } ], "route": { "rules": [ - { - "protocol": [ "dns" ], - "outbound": "dns_out" - } ] } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/Sample/tun_singbox_rules b/v2rayN/ServiceLib/Sample/tun_singbox_rules index df1dc4ec..a4276134 100644 --- a/v2rayN/ServiceLib/Sample/tun_singbox_rules +++ b/v2rayN/ServiceLib/Sample/tun_singbox_rules @@ -8,13 +8,13 @@ 139, 5353 ], - "outbound": "block" + "action": "reject" }, { "ip_cidr": [ "224.0.0.0/3", "ff00::/8" ], - "outbound": "block" + "action": "reject" } ] \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 34ae6f79..3fc08556 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1,6 +1,7 @@ using System.Data; using System.Net; using System.Net.NetworkInformation; +using DynamicData; namespace ServiceLib.Services.CoreConfig; @@ -558,15 +559,6 @@ public class CoreConfigSingboxService singboxConfig.inbounds.Add(inbound); inbound.listen_port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks); - inbound.sniff = _config.Inbound.First().SniffingEnabled; - inbound.sniff_override_destination = _config.Inbound.First().RouteOnly ? false : _config.Inbound.First().SniffingEnabled; - inbound.domain_strategy = _config.RoutingBasicItem.DomainStrategy4Singbox.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainStrategy4Singbox; - - var routing = await ConfigHandler.GetDefaultRouting(_config); - if (routing.DomainStrategy4Singbox.IsNotEmpty()) - { - inbound.domain_strategy = routing.DomainStrategy4Singbox; - } if (_config.Inbound.First().SecondLocalPortEnabled) { @@ -611,8 +603,6 @@ public class CoreConfigSingboxService tunInbound.mtu = _config.TunModeItem.Mtu; tunInbound.strict_route = _config.TunModeItem.StrictRoute; tunInbound.stack = _config.TunModeItem.Stack; - tunInbound.sniff = _config.Inbound.First().SniffingEnabled; - //tunInbound.sniff_override_destination = _config.inbound.First().routeOnly ? false : _config.inbound.First().sniffingEnabled; if (_config.TunModeItem.EnableIPv6Address == false) { tunInbound.address = ["172.18.0.1/30"]; @@ -978,17 +968,6 @@ public class CoreConfigSingboxService { try { - var dnsOutbound = "dns_out"; - if (!_config.Inbound.First().SniffingEnabled) - { - singboxConfig.route.rules.Add(new() - { - port = [53], - network = ["udp"], - outbound = dnsOutbound - }); - } - singboxConfig.route.rules.Insert(0, new() { outbound = Global.DirectTag, @@ -1000,6 +979,44 @@ public class CoreConfigSingboxService clash_mode = ERuleMode.Global.ToString() }); + if (_config.Inbound.First().SniffingEnabled) + { + singboxConfig.route.rules.Add(new() + { + action = "sniff", + sniffer = new() { "dns", _config.Inbound.First().DestOverride } + }); + singboxConfig.route.rules.Add(new() + { + protocol = new() { "dns" }, + action = "hijack-dns" + }); + } + else + { + singboxConfig.route.rules.Add(new() + { + port = new() { 53 }, + network = new() { "udp" }, + action = "hijack-dns" + }); + } + + if (!(_config.Inbound.First().RouteOnly || _config.TunModeItem.EnableTun)) + { + var domainStrategy = _config.RoutingBasicItem.DomainStrategy4Singbox.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainStrategy4Singbox; + var defaultRouting = await ConfigHandler.GetDefaultRouting(_config); + if (defaultRouting.DomainStrategy4Singbox.IsNotEmpty()) + { + domainStrategy = defaultRouting.DomainStrategy4Singbox; + } + singboxConfig.route.rules.Add(new() + { + action = "resolve", + strategy = domainStrategy + }); + } + if (_config.TunModeItem.EnableTun) { singboxConfig.route.auto_detect_interface = true; @@ -1014,7 +1031,7 @@ public class CoreConfigSingboxService singboxConfig.route.rules.Add(new() { port = new() { 53 }, - outbound = dnsOutbound, + action = "hijack-dns", process_name = lstDnsExe }); @@ -1080,10 +1097,15 @@ public class CoreConfigSingboxService return 0; } - var rule = new Rule4Sbox() + var rule = new Rule4Sbox(); + if (item.OutboundTag == "block") { - outbound = item.OutboundTag, - }; + rule.action = "reject"; + } + else + { + rule.outbound = item.OutboundTag; + } if (item.Port.IsNotEmpty()) { From 7384fb3d3199d6d9a144422343df5d3a6dd63451 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sun, 6 Apr 2025 23:01:16 +0800 Subject: [PATCH 02/16] Removes unnecessary sniffer --- .../ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 3fc08556..cb065be0 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -983,8 +983,7 @@ public class CoreConfigSingboxService { singboxConfig.route.rules.Add(new() { - action = "sniff", - sniffer = new() { "dns", _config.Inbound.First().DestOverride } + action = "sniff" }); singboxConfig.route.rules.Add(new() { From 1d2aa70fe943a8674254364a7d53c447a6f44b3b Mon Sep 17 00:00:00 2001 From: DHR60 Date: Mon, 7 Apr 2025 19:24:30 +0800 Subject: [PATCH 03/16] Migrating to singbox 1.12 support --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 9 +- v2rayN/ServiceLib/Sample/dns_singbox_normal | 13 ++- v2rayN/ServiceLib/Sample/tun_singbox_dns | 13 ++- .../CoreConfig/CoreConfigSingboxService.cs | 90 +++++++++++++++---- 4 files changed, 86 insertions(+), 39 deletions(-) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index cbb2cb29..2c616776 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -134,6 +134,7 @@ public class Outbound4Sbox public HyObfs4Sbox? obfs { get; set; } public List? outbounds { get; set; } public bool? interrupt_exist_connections { get; set; } + public Rule4Sbox? domain_resolver { get; set; } } public class Endpoints4Sbox @@ -220,12 +221,12 @@ public class HyObfs4Sbox public class Server4Sbox { public string? tag { get; set; } - public string? address { get; set; } - public string? address_resolver { get; set; } - public string? address_strategy { get; set; } - public string? strategy { get; set; } public string? detour { get; set; } public string? client_subnet { get; set; } + public string? type { get; set; } + public string? server { get; set; } + public string? server_resolver { get; set; } + //public string? interface { get; set; } } public class Experimental4Sbox diff --git a/v2rayN/ServiceLib/Sample/dns_singbox_normal b/v2rayN/ServiceLib/Sample/dns_singbox_normal index 0921fe64..13aa7ead 100644 --- a/v2rayN/ServiceLib/Sample/dns_singbox_normal +++ b/v2rayN/ServiceLib/Sample/dns_singbox_normal @@ -2,19 +2,16 @@ "servers": [ { "tag": "remote", - "address": "tcp://8.8.8.8", + "type": "tcp", + "server": "8.8.8.8", "strategy": "prefer_ipv4", "detour": "proxy" }, { "tag": "local", - "address": "223.5.5.5", - "strategy": "prefer_ipv4", - "detour": "direct" - }, - { - "tag": "block", - "address": "rcode://success" + "type": "udp", + "server": "223.5.5.5", + "strategy": "prefer_ipv4" } ], "rules": [ diff --git a/v2rayN/ServiceLib/Sample/tun_singbox_dns b/v2rayN/ServiceLib/Sample/tun_singbox_dns index d8ca9808..e20c5cd5 100644 --- a/v2rayN/ServiceLib/Sample/tun_singbox_dns +++ b/v2rayN/ServiceLib/Sample/tun_singbox_dns @@ -2,19 +2,16 @@ "servers": [ { "tag": "remote", - "address": "tcp://8.8.8.8", + "type": "tcp", + "server": "8.8.8.8", "strategy": "prefer_ipv4", "detour": "proxy" }, { "tag": "local", - "address": "223.5.5.5", - "strategy": "prefer_ipv4", - "detour": "direct" - }, - { - "tag": "block", - "address": "rcode://success" + "type": "udp", + "server": "223.5.5.5", + "strategy": "prefer_ipv4" } ], "rules": [ diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index cb065be0..449a00fb 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -2,6 +2,7 @@ using System.Data; using System.Net; using System.Net.NetworkInformation; using DynamicData; +using ServiceLib.Models; namespace ServiceLib.Services.CoreConfig; @@ -635,6 +636,16 @@ public class CoreConfigSingboxService outbound.server_port = node.Port; outbound.type = Global.ProtocolTypes[node.ConfigType]; + if (Utils.IsDomain(node.Address)) + { + outbound.domain_resolver = new() + { + server = "local_local", + // TODO + //strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom + }; + } + switch (node.ConfigType) { case EConfigType.VMess: @@ -1292,17 +1303,71 @@ public class CoreConfigSingboxService dns4Sbox.rules ??= []; var tag = "local_local"; + var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress; + string? localDnsType = null; + //string? dhcpDnsInterface = null; + if (localDnsAddress == "local") + { + localDnsType = "local"; + localDnsAddress = null; + } + else if (localDnsAddress.StartsWith("dhcp")) + { + localDnsType = "dhcp"; + //if (localDnsAddress.Length > 7) // dhcp:// + //{ + // localDnsAddress = localDnsAddress.Substring(7); + //} + localDnsAddress = null; + } + else if (localDnsAddress.StartsWith("tcp")) + { + localDnsType = "tcp"; + if (localDnsAddress.Length > 6) // tcp:// + { + localDnsAddress = localDnsAddress.Substring(6); + } + } + else if (localDnsAddress.StartsWith("tls")) + { + localDnsType = "tls"; + if (localDnsAddress.Length > 6) // tls:// + { + localDnsAddress = localDnsAddress.Substring(6); + } + } + else if (localDnsAddress.StartsWith("https")) + { + localDnsType = "https"; + if (localDnsAddress.Length > 8) // https:// + { + localDnsAddress = localDnsAddress.Substring(8); + } + } + else if (localDnsAddress.StartsWith("quic")) + { + localDnsType = "quic"; + if (localDnsAddress.Length > 7) // quic:// + { + localDnsAddress = localDnsAddress.Substring(7); + } + } + else + { + localDnsType = "udp"; + } + dns4Sbox.servers.Add(new() { tag = tag, - address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, - detour = Global.DirectTag, - strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom, + type = localDnsType, + server = localDnsAddress }); dns4Sbox.rules.Insert(0, new() { server = tag, - clash_mode = ERuleMode.Direct.ToString() + clash_mode = ERuleMode.Direct.ToString(), + strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom }); dns4Sbox.rules.Insert(0, new() { @@ -1310,27 +1375,14 @@ public class CoreConfigSingboxService clash_mode = ERuleMode.Global.ToString() }); - var lstDomain = singboxConfig.outbounds - .Where(t => t.server.IsNotEmpty() && Utils.IsDomain(t.server)) - .Select(t => t.server) - .Distinct() - .ToList(); - if (lstDomain != null && lstDomain.Count > 0) - { - dns4Sbox.rules.Insert(0, new() - { - server = tag, - domain = lstDomain - }); - } - //Tun2SocksAddress if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni)) { dns4Sbox.rules.Insert(0, new() { server = tag, - domain = [node?.Sni] + domain = [node?.Sni], + strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom }); } From 7a9e3597be1495e11bd89a12abf16db40415b17b Mon Sep 17 00:00:00 2001 From: DHR60 Date: Tue, 8 Apr 2025 20:05:31 +0800 Subject: [PATCH 04/16] Adds Google cn dns rules --- v2rayN/ServiceLib/Sample/dns_singbox_normal | 7 +++++++ v2rayN/ServiceLib/Sample/tun_singbox_dns | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/v2rayN/ServiceLib/Sample/dns_singbox_normal b/v2rayN/ServiceLib/Sample/dns_singbox_normal index 13aa7ead..19b2ceae 100644 --- a/v2rayN/ServiceLib/Sample/dns_singbox_normal +++ b/v2rayN/ServiceLib/Sample/dns_singbox_normal @@ -15,6 +15,13 @@ } ], "rules": [ + { + "domain_suffix": [ + "googleapis.cn", + "gstatic.com" + ], + "server": "remote" + }, { "rule_set": [ "geosite-cn" diff --git a/v2rayN/ServiceLib/Sample/tun_singbox_dns b/v2rayN/ServiceLib/Sample/tun_singbox_dns index e20c5cd5..31a9af33 100644 --- a/v2rayN/ServiceLib/Sample/tun_singbox_dns +++ b/v2rayN/ServiceLib/Sample/tun_singbox_dns @@ -15,6 +15,13 @@ } ], "rules": [ + { + "domain_suffix": [ + "googleapis.cn", + "gstatic.com" + ], + "server": "remote" + }, { "rule_set": [ "geosite-cn", From cee5d0ad89a676914048595d091214a7e181759b Mon Sep 17 00:00:00 2001 From: DHR60 Date: Tue, 8 Apr 2025 20:12:03 +0800 Subject: [PATCH 05/16] Improves geoip rule handling in singbox --- .../CoreConfig/CoreConfigSingboxService.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 449a00fb..66d05cf7 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1242,24 +1242,28 @@ public class CoreConfigSingboxService { return false; } - else if (address.StartsWith("geoip:!")) - { - return false; - } else if (address.Equals("geoip:private")) { rule.ip_is_private = true; } else if (address.StartsWith("geoip:")) { - if (rule.geoip is null) - { rule.geoip = new(); } + rule.geoip ??= new(); rule.geoip?.Add(address.Substring(6)); } + else if (address.Equals("geoip:!private")) + { + rule.ip_is_private = false; + } + else if (address.StartsWith("geoip:!")) + { + rule.geoip ??= new(); + rule.geoip?.Add(address.Substring(6)); + rule.invert = true; + } else { - if (rule.ip_cidr is null) - { rule.ip_cidr = new(); } + rule.ip_cidr ??= new(); rule.ip_cidr?.Add(address); } return true; From 3e20ef1e8a6d813c518f36824613777b42f58614 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Thu, 10 Apr 2025 23:04:54 +0800 Subject: [PATCH 06/16] add anytls support --- v2rayN/ServiceLib/Enums/EConfigType.cs | 3 +- v2rayN/ServiceLib/Global.cs | 6 ++- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 31 +++++++++++ v2rayN/ServiceLib/Handler/CoreHandler.cs | 2 +- v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs | 54 +++++++++++++++++++ v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs | 5 ++ v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 9 ++++ v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 5 +- v2rayN/ServiceLib/Resx/ResUI.hu.resx | 3 ++ v2rayN/ServiceLib/Resx/ResUI.resx | 3 ++ v2rayN/ServiceLib/Resx/ResUI.ru.resx | 3 ++ v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 11 ++-- v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 11 ++-- .../CoreConfig/CoreConfigSingboxService.cs | 5 ++ .../CoreConfig/CoreConfigV2rayService.cs | 6 ++- .../ServiceLib/Services/SpeedtestService.cs | 4 +- .../ViewModels/MainWindowViewModel.cs | 5 ++ .../Views/AddServerWindow.axaml | 20 +++++++ .../Views/AddServerWindow.axaml.cs | 9 ++++ v2rayN/v2rayN.Desktop/Views/MainWindow.axaml | 1 + .../v2rayN.Desktop/Views/MainWindow.axaml.cs | 1 + v2rayN/v2rayN/Views/AddServerWindow.xaml | 29 ++++++++++ v2rayN/v2rayN/Views/AddServerWindow.xaml.cs | 8 +++ v2rayN/v2rayN/Views/MainWindow.xaml | 4 ++ v2rayN/v2rayN/Views/MainWindow.xaml.cs | 1 + 25 files changed, 222 insertions(+), 17 deletions(-) create mode 100644 v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs diff --git a/v2rayN/ServiceLib/Enums/EConfigType.cs b/v2rayN/ServiceLib/Enums/EConfigType.cs index f56d0e0f..6698f962 100644 --- a/v2rayN/ServiceLib/Enums/EConfigType.cs +++ b/v2rayN/ServiceLib/Enums/EConfigType.cs @@ -11,5 +11,6 @@ public enum EConfigType Hysteria2 = 7, TUIC = 8, WireGuard = 9, - HTTP = 10 + HTTP = 10, + Anytls = 11 } diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 78459920..fae23dc3 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -169,7 +169,8 @@ public class Global { EConfigType.Trojan, "trojan://" }, { EConfigType.Hysteria2, "hysteria2://" }, { EConfigType.TUIC, "tuic://" }, - { EConfigType.WireGuard, "wireguard://" } + { EConfigType.WireGuard, "wireguard://" }, + { EConfigType.Anytls, "anytls://" } }; public static readonly Dictionary ProtocolTypes = new() @@ -182,7 +183,8 @@ public class Global { EConfigType.Trojan, "trojan" }, { EConfigType.Hysteria2, "hysteria2" }, { EConfigType.TUIC, "tuic" }, - { EConfigType.WireGuard, "wireguard" } + { EConfigType.WireGuard, "wireguard" }, + { EConfigType.Anytls, "anytls" } }; public static readonly List VmessSecurities = diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index a23b1c67..52baab5f 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -259,6 +259,7 @@ public class ConfigHandler EConfigType.Hysteria2 => await AddHysteria2Server(config, item), EConfigType.TUIC => await AddTuicServer(config, item), EConfigType.WireGuard => await AddWireguardServer(config, item), + EConfigType.Anytls => await AddAnytlsServer(config, item), _ => -1, }; return ret; @@ -783,6 +784,35 @@ public class ConfigHandler return 0; } + /// + /// Add or edit a Anytls server + /// Validates and processes Anytls-specific settings + /// + /// Current configuration + /// Anytls profile to add + /// Whether to save to file + /// 0 if successful, -1 if failed + public static async Task AddAnytlsServer(Config config, ProfileItem profileItem, bool toFile = true) + { + profileItem.ConfigType = EConfigType.Anytls; + profileItem.CoreType = ECoreType.sing_box; + + profileItem.Address = profileItem.Address.TrimEx(); + profileItem.Id = profileItem.Id.TrimEx(); + profileItem.Security = profileItem.Security.TrimEx(); + profileItem.Network = string.Empty; + if (profileItem.StreamSecurity.IsNullOrEmpty()) + { + profileItem.StreamSecurity = Global.StreamSecurity; + } + if (profileItem.Id.IsNullOrEmpty()) + { + return -1; + } + await AddServerCommon(config, profileItem, toFile); + return 0; + } + /// /// Sort the server list by the specified column /// Updates the sort order in the profile extension data @@ -1277,6 +1307,7 @@ public class ConfigHandler EConfigType.Hysteria2 => await AddHysteria2Server(config, profileItem, false), EConfigType.TUIC => await AddTuicServer(config, profileItem, false), EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false), + EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false), _ => -1, }; diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs index 41ea866d..fb1d1dbb 100644 --- a/v2rayN/ServiceLib/Handler/CoreHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs @@ -101,7 +101,7 @@ public class CoreHandler public async Task LoadCoreConfigSpeedtest(List selecteds) { - var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC) ? ECoreType.sing_box : ECoreType.Xray; + var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls) ? ECoreType.sing_box : ECoreType.Xray; var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false)); var configPath = Utils.GetBinConfigPath(fileName); var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType); diff --git a/v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs new file mode 100644 index 00000000..bad36b19 --- /dev/null +++ b/v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs @@ -0,0 +1,54 @@ +using static QRCoder.PayloadGenerator; + +namespace ServiceLib.Handler.Fmt; +public class AnytlsFmt : BaseFmt +{ + public static ProfileItem? Resolve(string str, out string msg) + { + msg = ResUI.ConfigurationFormatIncorrect; + + var parsedUrl = Utils.TryUri(str); + if (parsedUrl == null) + { + return null; + } + + ProfileItem item = new() + { + ConfigType = EConfigType.Anytls, + Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), + Address = parsedUrl.IdnHost, + Port = parsedUrl.Port, + }; + var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); + item.Id = rawUserInfo; + + var query = Utils.ParseQueryString(parsedUrl.Query); + item.Sni = query["sni"] ?? Global.None; + item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false"; + + return item; + } + + public static string? ToUri(ProfileItem? item) + { + if (item == null) + { + return null; + } + var remark = string.Empty; + if (item.Remarks.IsNotEmpty()) + { + remark = "#" + Utils.UrlEncode(item.Remarks); + } + var pw = item.Id; + var dicQuery = new Dictionary(); + if (item.Sni.IsNotEmpty()) + { + dicQuery.Add("sni", item.Sni); + } + dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0"); + + return ToUri(EConfigType.Anytls, item.Address, item.Port, pw, dicQuery, remark); + } +} diff --git a/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs b/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs index 3e8ab2ae..814d753d 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs @@ -18,6 +18,7 @@ public class FmtHandler EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item), EConfigType.TUIC => TuicFmt.ToUri(item), EConfigType.WireGuard => WireguardFmt.ToUri(item), + EConfigType.Anytls => AnytlsFmt.ToUri(item), _ => null, }; @@ -75,6 +76,10 @@ public class FmtHandler { return WireguardFmt.Resolve(str, out msg); } + else if (str.StartsWith(Global.ProtocolShares[EConfigType.Anytls])) + { + return AnytlsFmt.Resolve(str, out msg); + } else { msg = ResUI.NonvmessOrssProtocol; diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 0b9cc936..a90f81ab 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -672,6 +672,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Add [Anytls] Configuration 的本地化字符串。 + /// + public static string menuAddAnytlsServer { + get { + return ResourceManager.GetString("menuAddAnytlsServer", resourceCulture); + } + } + /// /// 查找类似 Add a custom configuration Configuration 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index a937a262..97c6d1e7 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1416,4 +1416,7 @@ صادر کردن سرور - + + Add [Anytls] Configuration + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index 05a12c10..0d1a60e4 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1416,4 +1416,7 @@ Export server + + Add [Anytls] Configuration + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 1fb3d23b..9d63ab68 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1416,4 +1416,7 @@ Export Configuration + + Add [Anytls] Configuration + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index 824ea29a..11c1fba1 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1416,4 +1416,7 @@ Export server + + Add [Anytls] Configuration + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index a5f07957..660e9c4d 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1071,13 +1071,13 @@ 拥塞控制算法 - + 前置代理配置文件别名 - + 落地代理配置文件別名 - + 请确保配置文件别名存在并唯一 @@ -1413,4 +1413,7 @@ 导出配置文件 - + + 添加 [Anytls] 配置文件 + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index b8a5011a..250e9775 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1071,13 +1071,13 @@ 擁塞控制算法 - + 前置代理設定檔別名 - + 落地代理設定檔別名 - + 請確保設定檔別名存在並且唯一 @@ -1413,4 +1413,7 @@ 匯出設定檔 - + + 新增 [Anytls] 設定檔 + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 66d05cf7..617718b7 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -759,6 +759,11 @@ public class CoreConfigSingboxService outbound.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt(); break; } + case EConfigType.Anytls: + { + outbound.password = node.Id; + break; + } } await GenOutboundTls(node, outbound); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index 95511836..17621e4c 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -1291,7 +1291,8 @@ public class CoreConfigV2rayService if (prevNode is not null && prevNode.ConfigType != EConfigType.Custom && prevNode.ConfigType != EConfigType.Hysteria2 - && prevNode.ConfigType != EConfigType.TUIC) + && prevNode.ConfigType != EConfigType.TUIC + && prevNode.ConfigType != EConfigType.Anytls) { var prevOutbound = JsonUtils.Deserialize(txtOutbound); await GenOutbound(prevNode, prevOutbound); @@ -1309,7 +1310,8 @@ public class CoreConfigV2rayService if (nextNode is not null && nextNode.ConfigType != EConfigType.Custom && nextNode.ConfigType != EConfigType.Hysteria2 - && nextNode.ConfigType != EConfigType.TUIC) + && nextNode.ConfigType != EConfigType.TUIC + && prevNode.ConfigType != EConfigType.Anytls) { var nextOutbound = JsonUtils.Deserialize(txtOutbound); await GenOutbound(nextNode, nextOutbound); diff --git a/v2rayN/ServiceLib/Services/SpeedtestService.cs b/v2rayN/ServiceLib/Services/SpeedtestService.cs index f4cd64a2..5ae9196d 100644 --- a/v2rayN/ServiceLib/Services/SpeedtestService.cs +++ b/v2rayN/ServiceLib/Services/SpeedtestService.cs @@ -357,8 +357,8 @@ public class SpeedtestService private List> GetTestBatchItem(List lstSelected, int pageSize) { List> lstTest = new(); - var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC)).ToList(); - var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC).ToList(); + var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls)).ToList(); + var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls).ToList(); for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++) { diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index ec07b825..d27c6be5 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -20,6 +20,7 @@ public class MainWindowViewModel : MyReactiveObject public ReactiveCommand AddHysteria2ServerCmd { get; } public ReactiveCommand AddTuicServerCmd { get; } public ReactiveCommand AddWireguardServerCmd { get; } + public ReactiveCommand AddAnytlsServerCmd { get; } public ReactiveCommand AddCustomServerCmd { get; } public ReactiveCommand AddServerViaClipboardCmd { get; } public ReactiveCommand AddServerViaScanCmd { get; } @@ -111,6 +112,10 @@ public class MainWindowViewModel : MyReactiveObject { await AddServerAsync(true, EConfigType.WireGuard); }); + AddAnytlsServerCmd = ReactiveCommand.CreateFromTask(async () => + { + await AddServerAsync(true, EConfigType.Anytls); + }); AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () => { await AddServerAsync(true, EConfigType.Custom); diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml index ef1885af..02c5dc6f 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml @@ -481,6 +481,26 @@ HorizontalAlignment="Left" Watermark="1500" /> + + + + + gridTls.IsVisible = false; break; + + case EConfigType.Anytls: + gridAnytls.IsVisible = true; + cmbCoreType.IsEnabled = false; + break; } gridTlsMore.IsVisible = false; @@ -193,6 +198,10 @@ public partial class AddServerWindow : ReactiveWindow this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId9.Text).DisposeWith(disposables); break; + + case EConfigType.Anytls: + this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId10.Text).DisposeWith(disposables); + break; } this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables); diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index bbc78a72..af4ae529 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -46,6 +46,7 @@ + diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 91328046..7c2dd397 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -83,6 +83,7 @@ public partial class MainWindow : ReactiveWindow this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml index ba06cd3f..aae8d336 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml @@ -646,6 +646,35 @@ materialDesign:HintAssist.Hint="1500" Style="{StaticResource DefTextBox}" /> + + + + + + + + + + + + + + vm.SelectedSource.RequestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId9.Text).DisposeWith(disposables); break; + + case EConfigType.Anytls: + this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId10.Text).DisposeWith(disposables); + break; } this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.Text).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 6c233ef4..a439edd5 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -107,6 +107,10 @@ x:Name="menuAddTuicServer" Height="{StaticResource MenuItemHeight}" Header="{x:Static resx:ResUI.menuAddTuicServer}" /> + diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index b837f65c..48ef5e44 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -80,6 +80,7 @@ public partial class MainWindow this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables); From f82ba4bc08a920f049f2a9f51398bca7d64c4102 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Thu, 10 Apr 2025 23:19:56 +0800 Subject: [PATCH 07/16] Simplifies local DNS address handling --- .../CoreConfig/CoreConfigSingboxService.cs | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 617718b7..303c57a3 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1320,46 +1320,36 @@ public class CoreConfigSingboxService localDnsType = "local"; localDnsAddress = null; } - else if (localDnsAddress.StartsWith("dhcp")) + else if (localDnsAddress.StartsWith("dhcp") && localDnsAddress.Length > 7) { localDnsType = "dhcp"; - //if (localDnsAddress.Length > 7) // dhcp:// - //{ - // localDnsAddress = localDnsAddress.Substring(7); - //} + // // dhcp:// + // dhcpDnsInterface = localDnsAddress.Substring(7); localDnsAddress = null; } - else if (localDnsAddress.StartsWith("tcp")) + else if (localDnsAddress.StartsWith("tcp") && localDnsAddress.Length > 6) { localDnsType = "tcp"; - if (localDnsAddress.Length > 6) // tcp:// - { - localDnsAddress = localDnsAddress.Substring(6); - } + // tcp:// + localDnsAddress = localDnsAddress.Substring(6); } - else if (localDnsAddress.StartsWith("tls")) + else if (localDnsAddress.StartsWith("tls") && localDnsAddress.Length > 6) { localDnsType = "tls"; - if (localDnsAddress.Length > 6) // tls:// - { - localDnsAddress = localDnsAddress.Substring(6); - } + // tls:// + localDnsAddress = localDnsAddress.Substring(6); } - else if (localDnsAddress.StartsWith("https")) + else if (localDnsAddress.StartsWith("https") && localDnsAddress.Length > 8) { localDnsType = "https"; - if (localDnsAddress.Length > 8) // https:// - { - localDnsAddress = localDnsAddress.Substring(8); - } + // https:// + localDnsAddress = localDnsAddress.Substring(8); } - else if (localDnsAddress.StartsWith("quic")) + else if (localDnsAddress.StartsWith("quic") && localDnsAddress.Length > 7) { localDnsType = "quic"; - if (localDnsAddress.Length > 7) // quic:// - { - localDnsAddress = localDnsAddress.Substring(7); - } + // quic:// + localDnsAddress = localDnsAddress.Substring(7); } else { From ec29e87dd2e4053bb4a4a80833e80acdd758c8a6 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 11 Apr 2025 18:30:45 +0800 Subject: [PATCH 08/16] Enables dhcp interface configuration --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 4 +++- .../Services/CoreConfig/CoreConfigSingboxService.cs | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index 2c616776..f0e74e19 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -1,3 +1,5 @@ +using System.Text.Json.Serialization; + namespace ServiceLib.Models; public class SingboxConfig @@ -226,7 +228,7 @@ public class Server4Sbox public string? type { get; set; } public string? server { get; set; } public string? server_resolver { get; set; } - //public string? interface { get; set; } + [JsonPropertyName("interface")] public string? Interface { get; set; } } public class Experimental4Sbox diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 303c57a3..a99678b1 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1314,7 +1314,7 @@ public class CoreConfigSingboxService var tag = "local_local"; var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress; string? localDnsType = null; - //string? dhcpDnsInterface = null; + string? dhcpDnsInterface = null; if (localDnsAddress == "local") { localDnsType = "local"; @@ -1323,8 +1323,12 @@ public class CoreConfigSingboxService else if (localDnsAddress.StartsWith("dhcp") && localDnsAddress.Length > 7) { localDnsType = "dhcp"; - // // dhcp:// - // dhcpDnsInterface = localDnsAddress.Substring(7); + // dhcp:// + dhcpDnsInterface = localDnsAddress.Substring(7); + if (dhcpDnsInterface == "auto") + { + dhcpDnsInterface = null; + } localDnsAddress = null; } else if (localDnsAddress.StartsWith("tcp") && localDnsAddress.Length > 6) @@ -1360,7 +1364,8 @@ public class CoreConfigSingboxService { tag = tag, type = localDnsType, - server = localDnsAddress + server = localDnsAddress, + Interface = dhcpDnsInterface }); dns4Sbox.rules.Insert(0, new() { From 0edfb2b08b0db77e4c496a32a7b72c833215f236 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 11 Apr 2025 19:03:52 +0800 Subject: [PATCH 09/16] Fetches DNS strategy for domain resolution --- .../Services/CoreConfig/CoreConfigSingboxService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index a99678b1..4dafffcf 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -638,11 +638,11 @@ public class CoreConfigSingboxService if (Utils.IsDomain(node.Address)) { + var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); outbound.domain_resolver = new() { server = "local_local", - // TODO - //strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom + strategy = string.IsNullOrEmpty(item?.DomainStrategy4Freedom) ? null : item?.DomainStrategy4Freedom }; } From b938538926efb6d5181cf5e52f665956020c6a9c Mon Sep 17 00:00:00 2001 From: DHR60 Date: Tue, 8 Apr 2025 21:23:01 +0800 Subject: [PATCH 10/16] support Wireguard endpoint --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 8 +- .../CoreConfig/CoreConfigSingboxService.cs | 200 +++++++++++++++--- 2 files changed, 169 insertions(+), 39 deletions(-) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index f0e74e19..6731611b 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -8,6 +8,7 @@ public class SingboxConfig public Dns4Sbox? dns { get; set; } public List inbounds { get; set; } public List outbounds { get; set; } + public List? endpoints { get; set; } public Route4Sbox route { get; set; } public Experimental4Sbox? experimental { get; set; } } @@ -123,11 +124,6 @@ public class Outbound4Sbox public string? version { get; set; } public string? network { get; set; } public string? packet_encoding { get; set; } - public List? local_address { get; set; } - public string? private_key { get; set; } - public string? peer_public_key { get; set; } - public List? reserved { get; set; } - public int? mtu { get; set; } public string? plugin { get; set; } public string? plugin_opts { get; set; } public Tls4Sbox? tls { get; set; } @@ -152,6 +148,8 @@ public class Endpoints4Sbox public string? udp_timeout { get; set; } public int? workers { get; set; } public List peers { get; set; } + public string? detour { get; set; } + public Rule4Sbox? domain_resolver { get; set; } } public class Peer4Sbox diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 4dafffcf..5df11976 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -55,7 +55,18 @@ public class CoreConfigSingboxService await GenInbounds(singboxConfig); - await GenOutbound(node, singboxConfig.outbounds.First()); + if (node.ConfigType == EConfigType.WireGuard) + { + singboxConfig.outbounds.RemoveAt(0); + var endpoints = new Endpoints4Sbox(); + await GenEndpoint(node, endpoints); + endpoints.tag = Global.ProxyTag; + singboxConfig.endpoints = new() { endpoints }; + } + else + { + await GenOutbound(node, singboxConfig.outbounds.First()); + } await GenMoreOutbounds(node, singboxConfig); @@ -204,16 +215,32 @@ public class CoreConfigSingboxService continue; } - var outbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(item, outbound); - outbound.tag = Global.ProxyTag + inbound.listen_port.ToString(); - singboxConfig.outbounds.Add(outbound); + var tag = string.Empty; + if (item.ConfigType == EConfigType.WireGuard) + { + var endpoints = new Endpoints4Sbox(); + await GenEndpoint(item, endpoints); + endpoints.tag = Global.ProxyTag + inbound.listen_port.ToString(); + singboxConfig.endpoints ??= new(); + singboxConfig.endpoints.Add(endpoints); + + tag = endpoints.tag; + } + else + { + var outbound = JsonUtils.Deserialize(txtOutbound); + await GenOutbound(item, outbound); + outbound.tag = Global.ProxyTag + inbound.listen_port.ToString(); + singboxConfig.outbounds.Add(outbound); + + tag = outbound.tag; + } //rule Rule4Sbox rule = new() { inbound = new List { inbound.tag }, - outbound = outbound.tag + outbound = tag }; singboxConfig.route.rules.Add(rule); } @@ -277,7 +304,18 @@ public class CoreConfigSingboxService } await GenLog(singboxConfig); - await GenOutbound(node, singboxConfig.outbounds.First()); + if (node.ConfigType == EConfigType.WireGuard) + { + singboxConfig.outbounds.RemoveAt(0); + var endpoints = new Endpoints4Sbox(); + await GenEndpoint(node, endpoints); + endpoints.tag = Global.ProxyTag; + singboxConfig.endpoints = new() { endpoints }; + } + else + { + await GenOutbound(node, singboxConfig.outbounds.First()); + } await GenMoreOutbounds(node, singboxConfig); await GenDnsDomains(null, singboxConfig, null); @@ -371,12 +409,26 @@ public class CoreConfigSingboxService continue; } - //outbound - var outbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(item, outbound); - outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}"; - singboxConfig.outbounds.Insert(0, outbound); - tagProxy.Add(outbound.tag); + + if (item.ConfigType == EConfigType.WireGuard) + { + //endpoint + var endpoints = new Endpoints4Sbox(); + await GenEndpoint(item, endpoints); + endpoints.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}"; + singboxConfig.endpoints ??= new(); + singboxConfig.endpoints.Add(endpoints); + tagProxy.Add(endpoints.tag); + } + else + { + //outbound + var outbound = JsonUtils.Deserialize(txtOutbound); + await GenOutbound(item, outbound); + outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}"; + singboxConfig.outbounds.Insert(0, outbound); + tagProxy.Add(outbound.tag); + } } if (tagProxy.Count <= 0) { @@ -750,15 +802,6 @@ public class CoreConfigSingboxService outbound.congestion_control = node.HeaderType; break; } - case EConfigType.WireGuard: - { - outbound.private_key = node.Id; - outbound.peer_public_key = node.PublicKey; - outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(); - outbound.local_address = Utils.String2List(node.RequestHost); - outbound.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt(); - break; - } case EConfigType.Anytls: { outbound.password = node.Id; @@ -777,6 +820,51 @@ public class CoreConfigSingboxService return 0; } + private async Task GenEndpoint(ProfileItem node, Endpoints4Sbox endpoints) + { + try + { + endpoints.address = Utils.String2List(node.RequestHost); + // Utils.GetFreePort() 9090 ? + endpoints.listen_port = Utils.GetFreePort(); + endpoints.type = Global.ProtocolTypes[node.ConfigType]; + + if (Utils.IsDomain(node.Address)) + { + var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box); + endpoints.domain_resolver = new() + { + server = "local_local", + strategy = string.IsNullOrEmpty(item?.DomainStrategy4Freedom) ? null : item?.DomainStrategy4Freedom + }; + } + + switch (node.ConfigType) + { + case EConfigType.WireGuard: + { + var peer = new Peer4Sbox + { + public_key = node.PublicKey, + reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(), + address = node.Address, + port = node.Port, + // TODO default ["0.0.0.0/0", "::/0"] + allowed_ips = new() { "0.0.0.0/0", "::/0" }, + }; + endpoints.private_key = node.Id; + endpoints.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt(); + break; + } + } + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + } + return await Task.FromResult(0); + } + private async Task GenOutboundMux(ProfileItem node, Outbound4Sbox outbound) { try @@ -942,7 +1030,9 @@ public class CoreConfigSingboxService } //current proxy - var outbound = singboxConfig.outbounds.First(); + var endpoint = singboxConfig.endpoints?.FirstOrDefault(t => t.tag == Global.ProxyTag); + var outbound = endpoint == null ? singboxConfig.outbounds.First() : null; + var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound); //Previous proxy @@ -950,12 +1040,34 @@ public class CoreConfigSingboxService if (prevNode is not null && prevNode.ConfigType != EConfigType.Custom) { - var prevOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(prevNode, prevOutbound); - prevOutbound.tag = $"{Global.ProxyTag}2"; - singboxConfig.outbounds.Add(prevOutbound); + var tag = string.Empty; + if (prevNode.ConfigType == EConfigType.WireGuard) + { + var prevEndpoint = JsonUtils.Deserialize(txtOutbound); + await GenEndpoint(prevNode, prevEndpoint); + prevEndpoint.tag = $"{Global.ProxyTag}2"; + singboxConfig.endpoints ??= new(); + singboxConfig.endpoints.Add(prevEndpoint); - outbound.detour = prevOutbound.tag; + tag = prevEndpoint.tag; + } + else + { + var prevOutbound = JsonUtils.Deserialize(txtOutbound); + await GenOutbound(prevNode, prevOutbound); + prevOutbound.tag = $"{Global.ProxyTag}2"; + singboxConfig.outbounds.Add(prevOutbound); + + tag = prevOutbound.tag; + } + if (endpoint != null) + { + endpoint.detour = tag; + } + else + { + outbound.detour = tag; + } } //Next proxy @@ -963,13 +1075,33 @@ public class CoreConfigSingboxService if (nextNode is not null && nextNode.ConfigType != EConfigType.Custom) { - var nextOutbound = JsonUtils.Deserialize(txtOutbound); - await GenOutbound(nextNode, nextOutbound); - nextOutbound.tag = Global.ProxyTag; - singboxConfig.outbounds.Insert(0, nextOutbound); + var tag = $"{Global.ProxyTag}1"; + if (endpoint != null) + { + endpoint.tag = tag; + } + else + { + outbound.tag = tag; + } + if (nextNode.ConfigType == EConfigType.WireGuard) + { + var nextEndpoint = JsonUtils.Deserialize(txtOutbound); + await GenEndpoint(nextNode, nextEndpoint); + nextEndpoint.tag = Global.ProxyTag; + singboxConfig.endpoints.Insert(0, nextEndpoint); - outbound.tag = $"{Global.ProxyTag}1"; - nextOutbound.detour = outbound.tag; + nextEndpoint.detour = tag; + } + else + { + var nextOutbound = JsonUtils.Deserialize(txtOutbound); + await GenOutbound(nextNode, nextOutbound); + nextOutbound.tag = Global.ProxyTag; + singboxConfig.outbounds.Insert(0, nextOutbound); + + nextOutbound.detour = tag; + } } } catch (Exception ex) From f2c7cb4e43008b1e1530b9920ead9cd68c50bb18 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 11 Apr 2025 19:33:51 +0800 Subject: [PATCH 11/16] Utils.GetFreePort() default port to be zero --- v2rayN/ServiceLib/Common/Utils.cs | 4 ++-- .../Services/CoreConfig/CoreConfigSingboxService.cs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index 03a1a860..2078940d 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -427,11 +427,11 @@ public class Utils return false; } - public static int GetFreePort(int defaultPort = 9090) + public static int GetFreePort(int defaultPort = 0) { try { - if (!Utils.PortInUse(defaultPort)) + if (!(defaultPort == 0 || Utils.PortInUse(defaultPort))) { return defaultPort; } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 5df11976..fec5c524 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -825,7 +825,6 @@ public class CoreConfigSingboxService try { endpoints.address = Utils.String2List(node.RequestHost); - // Utils.GetFreePort() 9090 ? endpoints.listen_port = Utils.GetFreePort(); endpoints.type = Global.ProtocolTypes[node.ConfigType]; From 60d40747a007cfbfcda1bdb752c2e9159727b8f1 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 11 Apr 2025 19:59:20 +0800 Subject: [PATCH 12/16] Adds Sing-box legacy DNS config support --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 6 ++ v2rayN/ServiceLib/Sample/dns_singbox_normal | 4 +- v2rayN/ServiceLib/Sample/tun_singbox_dns | 4 +- .../CoreConfig/CoreConfigSingboxService.cs | 62 ++++++++++++++++++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index 6731611b..77c98db6 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -227,6 +227,12 @@ public class Server4Sbox public string? server { get; set; } public string? server_resolver { get; set; } [JsonPropertyName("interface")] public string? Interface { get; set; } + // Deprecated + public string? address { get; set; } + public string? address_resolver { get; set; } + public string? address_strategy { get; set; } + public string? strategy { get; set; } + // Deprecated End } public class Experimental4Sbox diff --git a/v2rayN/ServiceLib/Sample/dns_singbox_normal b/v2rayN/ServiceLib/Sample/dns_singbox_normal index 19b2ceae..69367e86 100644 --- a/v2rayN/ServiceLib/Sample/dns_singbox_normal +++ b/v2rayN/ServiceLib/Sample/dns_singbox_normal @@ -4,14 +4,12 @@ "tag": "remote", "type": "tcp", "server": "8.8.8.8", - "strategy": "prefer_ipv4", "detour": "proxy" }, { "tag": "local", "type": "udp", - "server": "223.5.5.5", - "strategy": "prefer_ipv4" + "server": "223.5.5.5" } ], "rules": [ diff --git a/v2rayN/ServiceLib/Sample/tun_singbox_dns b/v2rayN/ServiceLib/Sample/tun_singbox_dns index 31a9af33..530267b0 100644 --- a/v2rayN/ServiceLib/Sample/tun_singbox_dns +++ b/v2rayN/ServiceLib/Sample/tun_singbox_dns @@ -4,14 +4,12 @@ "tag": "remote", "type": "tcp", "server": "8.8.8.8", - "strategy": "prefer_ipv4", "detour": "proxy" }, { "tag": "local", "type": "udp", - "server": "223.5.5.5", - "strategy": "prefer_ipv4" + "server": "223.5.5.5" } ], "rules": [ diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index fec5c524..f417ac1d 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1427,7 +1427,14 @@ public class CoreConfigSingboxService } singboxConfig.dns = dns4Sbox; - await GenDnsDomains(node, singboxConfig, item); + if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty()) + { + await GenDnsDomains(node, singboxConfig, item); + } + else + { + await GenDnsDomainsLegacy(node, singboxConfig, item); + } } catch (Exception ex) { @@ -1525,6 +1532,59 @@ public class CoreConfigSingboxService return await Task.FromResult(0); } + private async Task GenDnsDomainsLegacy(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem) + { + var dns4Sbox = singboxConfig.dns ?? new(); + dns4Sbox.servers ??= []; + dns4Sbox.rules ??= []; + + var tag = "local_local"; + dns4Sbox.servers.Add(new() + { + tag = tag, + address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, + detour = Global.DirectTag, + strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom, + }); + dns4Sbox.rules.Insert(0, new() + { + server = tag, + clash_mode = ERuleMode.Direct.ToString() + }); + dns4Sbox.rules.Insert(0, new() + { + server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote", + clash_mode = ERuleMode.Global.ToString() + }); + + var lstDomain = singboxConfig.outbounds + .Where(t => t.server.IsNotEmpty() && Utils.IsDomain(t.server)) + .Select(t => t.server) + .Distinct() + .ToList(); + if (lstDomain != null && lstDomain.Count > 0) + { + dns4Sbox.rules.Insert(0, new() + { + server = tag, + domain = lstDomain + }); + } + + //Tun2SocksAddress + if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni)) + { + dns4Sbox.rules.Insert(0, new() + { + server = tag, + domain = [node?.Sni] + }); + } + + singboxConfig.dns = dns4Sbox; + return await Task.FromResult(0); + } + private async Task GenExperimental(SingboxConfig singboxConfig) { //if (_config.guiItem.enableStatistics) From 236501267029b0c66387f25c059bd3c7be81723c Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 11 Apr 2025 20:10:49 +0800 Subject: [PATCH 13/16] Adds IPv4 preference to DNS configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对应原dns.servers[].strategy = prefer_ipv4 --- v2rayN/ServiceLib/Sample/dns_singbox_normal | 9 ++++++--- v2rayN/ServiceLib/Sample/tun_singbox_dns | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/v2rayN/ServiceLib/Sample/dns_singbox_normal b/v2rayN/ServiceLib/Sample/dns_singbox_normal index 69367e86..b32b439c 100644 --- a/v2rayN/ServiceLib/Sample/dns_singbox_normal +++ b/v2rayN/ServiceLib/Sample/dns_singbox_normal @@ -18,14 +18,17 @@ "googleapis.cn", "gstatic.com" ], - "server": "remote" + "server": "remote", + "strategy": "prefer_ipv4" }, { "rule_set": [ "geosite-cn" ], - "server": "local" + "server": "local", + "strategy": "prefer_ipv4" } ], - "final": "remote" + "final": "remote", + "strategy": "prefer_ipv4" } diff --git a/v2rayN/ServiceLib/Sample/tun_singbox_dns b/v2rayN/ServiceLib/Sample/tun_singbox_dns index 530267b0..39bf43ac 100644 --- a/v2rayN/ServiceLib/Sample/tun_singbox_dns +++ b/v2rayN/ServiceLib/Sample/tun_singbox_dns @@ -18,15 +18,18 @@ "googleapis.cn", "gstatic.com" ], - "server": "remote" + "server": "remote", + "strategy": "prefer_ipv4" }, { "rule_set": [ "geosite-cn", "geosite-geolocation-cn" ], - "server": "local" + "server": "local", + "strategy": "prefer_ipv4" } ], - "final": "remote" + "final": "remote", + "strategy": "prefer_ipv4" } From 9d95143d85ade850f7014e5193bd896d860237d8 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Fri, 11 Apr 2025 20:55:15 +0800 Subject: [PATCH 14/16] Refactors DNS address parsing --- .../CoreConfig/CoreConfigSingboxService.cs | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index f417ac1d..815ab873 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1453,45 +1453,50 @@ public class CoreConfigSingboxService var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress; string? localDnsType = null; string? dhcpDnsInterface = null; + var dnsProtocols = new List + { + "dhcp", + "https", + "tcp", + "tls", + "quic", + "h3", + "udp" + }; if (localDnsAddress == "local") { localDnsType = "local"; localDnsAddress = null; } - else if (localDnsAddress.StartsWith("dhcp") && localDnsAddress.Length > 7) + else if (dnsProtocols.Any(protocol => localDnsAddress.StartsWith(protocol))) { - localDnsType = "dhcp"; - // dhcp:// - dhcpDnsInterface = localDnsAddress.Substring(7); - if (dhcpDnsInterface == "auto") + var protocol = dnsProtocols.First(p => localDnsAddress.StartsWith(p)); + localDnsType = protocol; + // +3 for "://" + if (localDnsAddress.Length > protocol.Length + 3) { - dhcpDnsInterface = null; + localDnsAddress = localDnsAddress.Substring(protocol.Length + 3); + if (protocol == "dhcp") + { + dhcpDnsInterface = localDnsAddress; + if (dhcpDnsInterface == "auto") + { + dhcpDnsInterface = null; + } + localDnsAddress = null; + } + else if (protocol is "https" or "h3") + { + if (localDnsAddress.Contains('/')) + { + localDnsAddress = localDnsAddress.Substring(0, localDnsAddress.IndexOf('/')); + } + } + } + else + { + localDnsAddress = null; } - localDnsAddress = null; - } - else if (localDnsAddress.StartsWith("tcp") && localDnsAddress.Length > 6) - { - localDnsType = "tcp"; - // tcp:// - localDnsAddress = localDnsAddress.Substring(6); - } - else if (localDnsAddress.StartsWith("tls") && localDnsAddress.Length > 6) - { - localDnsType = "tls"; - // tls:// - localDnsAddress = localDnsAddress.Substring(6); - } - else if (localDnsAddress.StartsWith("https") && localDnsAddress.Length > 8) - { - localDnsType = "https"; - // https:// - localDnsAddress = localDnsAddress.Substring(8); - } - else if (localDnsAddress.StartsWith("quic") && localDnsAddress.Length > 7) - { - localDnsType = "quic"; - // quic:// - localDnsAddress = localDnsAddress.Substring(7); } else { From 736ba9e52cbeb6a9e9ddd81672a4964619e034a7 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sat, 12 Apr 2025 12:05:47 +0800 Subject: [PATCH 15/16] Fixes config generation --- .../ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs | 3 +++ .../ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 815ab873..899d412f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -853,6 +853,7 @@ public class CoreConfigSingboxService }; endpoints.private_key = node.Id; endpoints.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt(); + endpoints.peers = new() { peer }; break; } } @@ -1088,6 +1089,7 @@ public class CoreConfigSingboxService var nextEndpoint = JsonUtils.Deserialize(txtOutbound); await GenEndpoint(nextNode, nextEndpoint); nextEndpoint.tag = Global.ProxyTag; + singboxConfig.endpoints ??= new(); singboxConfig.endpoints.Insert(0, nextEndpoint); nextEndpoint.detour = tag; @@ -1097,6 +1099,7 @@ public class CoreConfigSingboxService var nextOutbound = JsonUtils.Deserialize(txtOutbound); await GenOutbound(nextNode, nextOutbound); nextOutbound.tag = Global.ProxyTag; + singboxConfig.outbounds ??= new(); singboxConfig.outbounds.Insert(0, nextOutbound); nextOutbound.detour = tag; diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index 17621e4c..3dbfe219 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -1311,7 +1311,7 @@ public class CoreConfigV2rayService && nextNode.ConfigType != EConfigType.Custom && nextNode.ConfigType != EConfigType.Hysteria2 && nextNode.ConfigType != EConfigType.TUIC - && prevNode.ConfigType != EConfigType.Anytls) + && nextNode.ConfigType != EConfigType.Anytls) { var nextOutbound = JsonUtils.Deserialize(txtOutbound); await GenOutbound(nextNode, nextOutbound); From e3831d1695f5b0beccabb256a0c85988e6c7992e Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sat, 12 Apr 2025 13:37:51 +0800 Subject: [PATCH 16/16] fix singbox endpoints proxy chain not work --- v2rayN/ServiceLib/Models/SingboxConfig.cs | 1 + .../ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index 77c98db6..f698cc70 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -40,6 +40,7 @@ public class Route4Sbox public bool? auto_detect_interface { get; set; } public List rules { get; set; } public List? rule_set { get; set; } + public string? final { get; set; } } [Serializable] diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 899d412f..7b7c640d 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -1118,6 +1118,7 @@ public class CoreConfigSingboxService { try { + singboxConfig.route.final = Global.ProxyTag; singboxConfig.route.rules.Insert(0, new() { outbound = Global.DirectTag,