diff --git a/v2rayN/ServiceLib/Enums/EConfigType.cs b/v2rayN/ServiceLib/Enums/EConfigType.cs index 287d7b94..ae4e30ca 100644 --- a/v2rayN/ServiceLib/Enums/EConfigType.cs +++ b/v2rayN/ServiceLib/Enums/EConfigType.cs @@ -13,6 +13,7 @@ public enum EConfigType WireGuard = 9, HTTP = 10, Anytls = 11, + Naive = 12, PolicyGroup = 101, ProxyChain = 102, } diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index e502435f..03ec9cdc 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -178,6 +178,10 @@ public class Global public const string Hysteria2ProtocolShare = "hy2://"; + public const string NaiveHttpsProtocolShare = "naive+https://"; + + public const string NaiveQuicProtocolShare = "naive+quic://"; + public static readonly Dictionary ProtocolShares = new() { { EConfigType.VMess, "vmess://" }, @@ -188,7 +192,8 @@ public class Global { EConfigType.Hysteria2, "hysteria2://" }, { EConfigType.TUIC, "tuic://" }, { EConfigType.WireGuard, "wireguard://" }, - { EConfigType.Anytls, "anytls://" } + { EConfigType.Anytls, "anytls://" }, + { EConfigType.Naive, "naive://" } }; public static readonly Dictionary ProtocolTypes = new() @@ -202,7 +207,8 @@ public class Global { EConfigType.Hysteria2, "hysteria2" }, { EConfigType.TUIC, "tuic" }, { EConfigType.WireGuard, "wireguard" }, - { EConfigType.Anytls, "anytls" } + { EConfigType.Anytls, "anytls" }, + { EConfigType.Naive, "naive" } }; public static readonly List VmessSecurities = @@ -327,6 +333,7 @@ public class Global EConfigType.Hysteria2, EConfigType.TUIC, EConfigType.Anytls, + EConfigType.Naive, EConfigType.WireGuard, EConfigType.SOCKS, EConfigType.HTTP, @@ -543,6 +550,14 @@ public class Global "bbr" ]; + public static readonly List NaiveCongestionControls = + [ + "bbr", + "bbr2", + "cubic", + "reno" + ]; + public static readonly List allowSelectType = [ "selector", diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 37176608..bb94c0f9 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -231,6 +231,7 @@ public static class ConfigHandler item.Address = profileItem.Address; item.Port = profileItem.Port; + item.Username = profileItem.Username; item.Password = profileItem.Password; item.Network = profileItem.Network; @@ -269,6 +270,7 @@ public static class ConfigHandler EConfigType.TUIC => await AddTuicServer(config, item), EConfigType.WireGuard => await AddWireguardServer(config, item), EConfigType.Anytls => await AddAnytlsServer(config, item), + EConfigType.Naive => await AddNaiveServer(config, item), _ => -1, }; return ret; @@ -806,7 +808,7 @@ public static class ConfigHandler } /// - /// Add or edit a Anytls server + /// Add or edit an Anytls server /// Validates and processes Anytls-specific settings /// /// Current configuration @@ -833,6 +835,35 @@ public static class ConfigHandler return 0; } + /// + /// Add or edit a Naive server + /// Validates and processes Naive-specific settings + /// + /// Current configuration + /// Naive profile to add + /// Whether to save to file + /// 0 if successful, -1 if failed + public static async Task AddNaiveServer(Config config, ProfileItem profileItem, bool toFile = true) + { + profileItem.ConfigType = EConfigType.Naive; + profileItem.CoreType = ECoreType.sing_box; + + profileItem.Address = profileItem.Address.TrimEx(); + profileItem.Username = profileItem.Username.TrimEx(); + profileItem.Password = profileItem.Password.TrimEx(); + profileItem.Network = profileItem.Network == "quic" ? "quic" : string.Empty; + if (profileItem.StreamSecurity.IsNullOrEmpty()) + { + profileItem.StreamSecurity = Global.StreamSecurity; + } + if (profileItem.Password.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 @@ -1079,7 +1110,8 @@ public static class ConfigHandler if (toFile) { - profileItem.SetProtocolExtra(); + //profileItem.SetProtocolExtra(); + profileItem.SetProtocolExtra(profileItem.GetProtocolExtra()); await SQLiteHelper.Instance.ReplaceAsync(profileItem); } return 0; @@ -1107,6 +1139,7 @@ public static class ConfigHandler && AreEqual(o.Address, n.Address) && o.Port == n.Port && AreEqual(o.Password, n.Password) + && AreEqual(o.Username, n.Username) && AreEqual(oProtocolExtra.VlessEncryption, nProtocolExtra.VlessEncryption) && AreEqual(oProtocolExtra.SsMethod, nProtocolExtra.SsMethod) && AreEqual(oProtocolExtra.VmessSecurity, nProtocolExtra.VmessSecurity) @@ -1368,6 +1401,7 @@ public static class ConfigHandler EConfigType.TUIC => await AddTuicServer(config, profileItem, false), EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false), EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false), + EConfigType.Naive => await AddNaiveServer(config, profileItem, false), _ => -1, }; diff --git a/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs b/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs index 4fc251b7..611e5159 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs @@ -19,6 +19,7 @@ public class FmtHandler EConfigType.TUIC => TuicFmt.ToUri(item), EConfigType.WireGuard => WireguardFmt.ToUri(item), EConfigType.Anytls => AnytlsFmt.ToUri(item), + EConfigType.Naive => NaiveFmt.ToUri(item), _ => null, }; @@ -80,6 +81,12 @@ public class FmtHandler { return AnytlsFmt.Resolve(str, out msg); } + else if (str.StartsWith(Global.ProtocolShares[EConfigType.Naive]) + || str.StartsWith(Global.NaiveHttpsProtocolShare) + || str.StartsWith(Global.NaiveQuicProtocolShare)) + { + return NaiveFmt.Resolve(str, out msg); + } else { msg = ResUI.NonvmessOrssProtocol; diff --git a/v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs new file mode 100644 index 00000000..aec27d57 --- /dev/null +++ b/v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs @@ -0,0 +1,85 @@ +namespace ServiceLib.Handler.Fmt; + +public class NaiveFmt : 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.Naive, + Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), + Address = parsedUrl.IdnHost, + Port = parsedUrl.Port, + }; + if (parsedUrl.Scheme.Contains("quic")) + { + item.Network = "quic"; + } + var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); + if (rawUserInfo.Contains(':')) + { + var split = rawUserInfo.Split(':', 2); + item.Username = split[0]; + item.Password = split[1]; + } + else + { + item.Password = rawUserInfo; + } + + var query = Utils.ParseQueryString(parsedUrl.Query); + ResolveUriQuery(query, ref item); + var insecureConcurrency = int.TryParse(GetQueryValue(query, "insecure-concurrency"), out var ic) ? ic : 0; + if (insecureConcurrency > 0) + { + item.SetProtocolExtra(item.GetProtocolExtra() with + { + InsecureConcurrency = insecureConcurrency, + }); + } + + 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 userInfo = item.Username.IsNotEmpty() ? $"{Utils.UrlEncode(item.Username)}:{Utils.UrlEncode(item.Password)}" : Utils.UrlEncode(item.Password); + var dicQuery = new Dictionary(); + ToUriQuery(item, Global.None, ref dicQuery); + if (item.GetProtocolExtra().InsecureConcurrency > 0) + { + dicQuery.Add("insecure-concurrency", item.GetProtocolExtra()?.InsecureConcurrency.ToString()); + } + + var query = dicQuery.Count > 0 + ? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray())) + : string.Empty; + var url = $"{userInfo}@{GetIpv6(item.Address)}:{item.Port}"; + + if (item.Network == "quic") + { + return $"{Global.NaiveQuicProtocolShare}{url}{query}{remark}"; + } + else + { + return $"{Global.NaiveHttpsProtocolShare}{url}{query}{remark}"; + } + } +} diff --git a/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs index 56f78ea9..d1f802b0 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs @@ -30,7 +30,10 @@ public class TuicFmt : BaseFmt var query = Utils.ParseQueryString(url.Query); ResolveUriQuery(query, ref item); - item.HeaderType = GetQueryValue(query, "congestion_control"); + item.SetProtocolExtra(item.GetProtocolExtra() with + { + CongestionControl = GetQueryValue(query, "congestion_control") + }); return item; } @@ -51,7 +54,10 @@ public class TuicFmt : BaseFmt var dicQuery = new Dictionary(); ToUriQueryLite(item, ref dicQuery); - dicQuery.Add("congestion_control", item.HeaderType); + if (!item.GetProtocolExtra().CongestionControl.IsNullOrEmpty()) + { + dicQuery.Add("congestion_control", item.GetProtocolExtra().CongestionControl); + } return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Username ?? ""}:{item.Password}", dicQuery, remark); } diff --git a/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs b/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs index ee3cd5a0..8101ced6 100644 --- a/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs +++ b/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs @@ -243,6 +243,11 @@ public class ActionPrecheckManager return string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net); } + if (configType == EConfigType.Naive && net == "quic") + { + return null; + } + // sing-box does not support non-tcp transports for protocols other than vmess/trojan/vless/shadowsocks if (!SingboxTransportSupportedProtocols.Contains(configType) && net != nameof(ETransport.tcp)) { diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index 0e471568..3137f998 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -269,12 +269,11 @@ public sealed class AppManager return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); } +#pragma warning disable CS0618 public async Task MigrateProfileExtra() { await MigrateProfileExtraGroup(); -#pragma warning disable CS0618 - const int pageSize = 100; var offset = 0; @@ -298,7 +297,6 @@ public sealed class AppManager } //await ProfileGroupItemManager.Instance.ClearAll(); -#pragma warning restore CS0618 } private async Task MigrateProfileExtraSub(List batch) @@ -344,6 +342,7 @@ public sealed class AppManager break; case EConfigType.TUIC: + extra = extra with { CongestionControl = item.HeaderType.NullIfEmpty(), }; item.Username = item.Id; item.Id = item.Security; item.Password = item.Security; @@ -400,7 +399,6 @@ public sealed class AppManager private async Task MigrateProfileExtraGroup() { -#pragma warning disable CS0618 var list = await SQLiteHelper.Instance.TableAsync().ToListAsync(); var groupItems = new ConcurrentDictionary(list.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!)); @@ -465,8 +463,8 @@ public sealed class AppManager return true; //await ProfileGroupItemManager.Instance.ClearAll(); -#pragma warning restore CS0618 } +#pragma warning restore CS0618 #endregion SqliteHelper diff --git a/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs b/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs index a768ba80..89f171ea 100644 --- a/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs +++ b/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs @@ -2,6 +2,9 @@ namespace ServiceLib.Models; public record ProtocolExtraItem { + public bool? Uot { get; init; } + public string? CongestionControl { get; init; } + // vmess public string? AlterId { get; init; } public string? VmessSecurity { get; init; } @@ -29,6 +32,9 @@ public record ProtocolExtraItem public string? Ports { get; init; } public string? HopInterval { get; init; } + // naiveproxy + public int? InsecureConcurrency { get; init; } + // group profile public string? GroupType { get; init; } public string? ChildItems { get; init; } diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index c0cd2e08..9b0c304f 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -133,10 +133,14 @@ public class Outbound4Sbox : BaseServer4Sbox public int? recv_window_conn { get; set; } public int? recv_window { get; set; } public bool? disable_mtu_discovery { get; set; } + public int? insecure_concurrency { get; set; } + public bool? udp_over_tcp { get; set; } public string? method { get; set; } public string? username { get; set; } public string? password { get; set; } public string? congestion_control { get; set; } + public bool? quic { get; set; } + public string? quic_congestion_control { get; set; } public string? version { get; set; } public string? network { get; set; } public string? packet_encoding { get; set; } diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index 34456a8e..4714357f 100644 --- a/v2rayN/ServiceLib/Models/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs @@ -179,6 +179,8 @@ public class ServersItem4Ray public string flow { get; set; } + public bool? uot { get; set; } + public List users { get; set; } } diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 6f223693..cf9ac1b9 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -745,7 +745,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add Child 的本地化字符串。 + /// 查找类似 Add Child 的本地化字符串。 /// public static string menuAddChildServer { get { @@ -772,7 +772,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Hysteria2] 的本地化字符串。 + /// 查找类似 Add [Hysteria2] 的本地化字符串。 /// public static string menuAddHysteria2Server { get { @@ -781,7 +781,16 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add Policy Group 的本地化字符串。 + /// 查找类似 Add [NaïveProxy] 的本地化字符串。 + /// + public static string menuAddNaiveServer { + get { + return ResourceManager.GetString("menuAddNaiveServer", resourceCulture); + } + } + + /// + /// 查找类似 Add Policy Group 的本地化字符串。 /// public static string menuAddPolicyGroupServer { get { @@ -826,7 +835,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Shadowsocks] 的本地化字符串。 + /// 查找类似 Add [Shadowsocks] 的本地化字符串。 /// public static string menuAddShadowsocksServer { get { @@ -835,7 +844,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [SOCKS] 的本地化字符串。 + /// 查找类似 Add [SOCKS] 的本地化字符串。 /// public static string menuAddSocksServer { get { @@ -844,7 +853,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [Trojan] 的本地化字符串。 + /// 查找类似 Add [Trojan] 的本地化字符串。 /// public static string menuAddTrojanServer { get { @@ -853,7 +862,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [TUIC] 的本地化字符串。 + /// 查找类似 Add [TUIC] 的本地化字符串。 /// public static string menuAddTuicServer { get { @@ -862,7 +871,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [VLESS] 的本地化字符串。 + /// 查找类似 Add [VLESS] 的本地化字符串。 /// public static string menuAddVlessServer { get { @@ -871,7 +880,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [VMess] 的本地化字符串。 + /// 查找类似 Add [VMess] 的本地化字符串。 /// public static string menuAddVmessServer { get { @@ -880,7 +889,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Add [WireGuard] 的本地化字符串。 + /// 查找类似 Add [WireGuard] 的本地化字符串。 /// public static string menuAddWireguardServer { get { @@ -3051,6 +3060,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Insecure Concurrency 的本地化字符串。 + /// + public static string TbInsecureConcurrency { + get { + return ResourceManager.GetString("TbInsecureConcurrency", resourceCulture); + } + } + /// /// 查找类似 Most Stable 的本地化字符串。 /// @@ -4464,6 +4482,24 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 UDP over TCP 的本地化字符串。 + /// + public static string TbUot { + get { + return ResourceManager.GetString("TbUot", resourceCulture); + } + } + + /// + /// 查找类似 Username 的本地化字符串。 + /// + public static string TbUsername { + get { + return ResourceManager.GetString("TbUsername", resourceCulture); + } + } + /// /// 查找类似 Validate Regional Domain IPs 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index dbce6ac4..c7c8975f 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1671,4 +1671,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Configuration item preview + + UDP over TCP + + + Add NaïveProxy + + + Insecure Concurrency + + + Username + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx index 005a51d5..20f8ce04 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -1668,4 +1668,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Configuration item preview + + UDP over TCP + + + Ajouter [NaïveProxy] + + + Insecure Concurrency + + + Username + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index 3d169590..aed27048 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1671,4 +1671,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Configuration item preview + + UDP over TCP + + + [NaïveProxy] konfiguráció hozzáadása + + + Insecure Concurrency + + + Username + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 041a103b..1fd1f595 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -514,19 +514,19 @@ Add a custom configuration - Add [Shadowsocks] + Add [Shadowsocks] - Add [SOCKS] + Add [SOCKS] - Add [Trojan] + Add [Trojan] - Add [VLESS] + Add [VLESS] - Add [VMess] + Add [VMess] Select all @@ -1036,7 +1036,7 @@ Domain - Add [Hysteria2] + Add [Hysteria2] Hysteria Max bandwidth (Up/Down) @@ -1045,7 +1045,7 @@ Use System Hosts - Add [TUIC] + Add [TUIC] Congestion control @@ -1078,7 +1078,7 @@ Enable IPv6 Address - Add [WireGuard] + Add [WireGuard] Private Key @@ -1522,13 +1522,13 @@ Policy Group Type - Add Policy Group + Add Policy Group Add Proxy Chain - Add Child + Add Child Remove Child @@ -1671,4 +1671,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Configuration item preview + + UDP over TCP + + + Add [NaïveProxy] + + + Insecure Concurrency + + + Username + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index 66ebef79..ae741f36 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1671,4 +1671,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Configuration item preview + + UDP over TCP + + + Добавить сервер [NaïveProxy] + + + Insecure Concurrency + + + Username + \ 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 c8936668..0111cc3c 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -517,16 +517,16 @@ 添加 [Shadowsocks] - 添加 [SOCKS] + 添加 [SOCKS] - 添加 [Trojan] + 添加 [Trojan] - 添加 [VLESS] + 添加 [VLESS] - 添加 [VMess] + 添加 [VMess] 全选 @@ -1033,7 +1033,7 @@ Domain - 添加 [Hysteria2] + 添加 [Hysteria2] Hysteria 最大带宽 (Up/Dw) @@ -1042,7 +1042,7 @@ 使用系统 hosts - 添加 [TUIC] + 添加 [TUIC] 拥塞控制算法 @@ -1075,7 +1075,7 @@ 启用 IPv6 - 添加 [WireGuard] + 添加 [WireGuard] PrivateKey @@ -1108,7 +1108,7 @@ *grpc Authority - 添加 [HTTP] + 添加 [HTTP] 和分组前置代理冲突 @@ -1408,7 +1408,7 @@ Mldsa65Verify - 添加 [Anytls] + 添加 [Anytls] 远程 DNS @@ -1668,4 +1668,16 @@ 子配置项预览 + + UDP over TCP + + + 添加 [NaïveProxy] + + + 不安全并发 + + + 用户名 + \ 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 2ee4dc4f..b05a66ca 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1668,4 +1668,16 @@ Configuration item preview + + UDP over TCP + + + 新增 [NaïveProxy] 節點 + + + Insecure Concurrency + + + Username + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 178350b3..a22fdb72 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -35,6 +35,7 @@ public partial class CoreConfigSingboxService outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(protocolExtra.SsMethod) ? protocolExtra.SsMethod : Global.None; outbound.password = node.Password; + outbound.udp_over_tcp = protocolExtra.Uot == true ? true : null; if (node.Network == nameof(ETransport.tcp) && node.HeaderType == Global.TcpHeaderHttp) { @@ -192,7 +193,7 @@ public partial class CoreConfigSingboxService { outbound.uuid = node.Username; outbound.password = node.Password; - outbound.congestion_control = node.HeaderType; + outbound.congestion_control = protocolExtra.CongestionControl; break; } case EConfigType.Anytls: @@ -200,6 +201,22 @@ public partial class CoreConfigSingboxService outbound.password = node.Password; break; } + case EConfigType.Naive: + { + outbound.username = node.Username; + outbound.password = node.Password; + if (outbound.network == "quic") + { + outbound.quic = true; + outbound.quic_congestion_control = protocolExtra.CongestionControl.NullIfEmpty(); + } + if (protocolExtra.InsecureConcurrency > 0) + { + outbound.insecure_concurrency = protocolExtra.InsecureConcurrency; + } + outbound.udp_over_tcp = protocolExtra.Uot == true ? true : null; + break; + } } await GenOutboundTls(node, outbound); diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 7f9c26ca..01ee7ae8 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -70,6 +70,7 @@ public partial class CoreConfigV2rayService serversItem.password = node.Password; serversItem.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(protocolExtra.SsMethod) ? protocolExtra.SsMethod : "none"; + serversItem.uot = protocolExtra.Uot == true ? true : null; serversItem.ota = false; serversItem.level = 1; diff --git a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs index ba698c20..f6b0587b 100644 --- a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs @@ -61,6 +61,15 @@ public class AddServerViewModel : MyReactiveObject [Reactive] public int WgMtu { get; set; } + [Reactive] + public bool Uot { get; set; } + + [Reactive] + public string CongestionControl { get; set; } + + [Reactive] + public int InsecureConcurrency { get; set; } + public ReactiveCommand FetchCertCmd { get; } public ReactiveCommand FetchCertChainCmd { get; } public ReactiveCommand SaveCmd { get; } @@ -123,6 +132,9 @@ public class AddServerViewModel : MyReactiveObject WgInterfaceAddress = protocolExtra?.WgInterfaceAddress ?? string.Empty; WgReserved = protocolExtra?.WgReserved ?? string.Empty; WgMtu = protocolExtra?.WgMtu ?? 1280; + Uot = protocolExtra?.Uot ?? false; + CongestionControl = protocolExtra?.CongestionControl ?? string.Empty; + InsecureConcurrency = protocolExtra?.InsecureConcurrency ?? 0; } private async Task SaveServerAsync() @@ -185,6 +197,9 @@ public class AddServerViewModel : MyReactiveObject WgInterfaceAddress = WgInterfaceAddress.NullIfEmpty(), WgReserved = WgReserved.NullIfEmpty(), WgMtu = WgMtu >= 576 ? WgMtu : null, + Uot = Uot ? true : null, + CongestionControl = CongestionControl.NullIfEmpty(), + InsecureConcurrency = InsecureConcurrency > 0 ? InsecureConcurrency : null }); if (await ConfigHandler.AddServer(_config, SelectedSource) == 0) diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index 8f5e9029..16b36c7b 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -18,6 +18,7 @@ public class MainWindowViewModel : MyReactiveObject public ReactiveCommand AddTuicServerCmd { get; } public ReactiveCommand AddWireguardServerCmd { get; } public ReactiveCommand AddAnytlsServerCmd { get; } + public ReactiveCommand AddNaiveServerCmd { get; } public ReactiveCommand AddCustomServerCmd { get; } public ReactiveCommand AddPolicyGroupServerCmd { get; } public ReactiveCommand AddProxyChainServerCmd { get; } @@ -117,6 +118,10 @@ public class MainWindowViewModel : MyReactiveObject { await AddServerAsync(EConfigType.Anytls); }); + AddNaiveServerCmd = ReactiveCommand.CreateFromTask(async () => + { + await AddServerAsync(EConfigType.Naive); + }); AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () => { await AddServerAsync(EConfigType.Custom); diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml index 356698fb..67d2868f 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml @@ -197,6 +197,19 @@ Width="300" Margin="{StaticResource Margin4}" /> + + + - + - + + + + + + + + + + + + + + + + + case EConfigType.Anytls: gridAnytls.IsVisible = true; + sepa2.IsVisible = false; + gridTransport.IsVisible = false; lstStreamSecurity.Add(Global.StreamSecurityReality); cmbCoreType.IsEnabled = false; break; + + case EConfigType.Naive: + gridNaive.IsVisible = true; + cmbCoreType.IsEnabled = false; + cmbFingerprint.IsEnabled = false; + cmbFingerprint.SelectedValue = string.Empty; + cmbAllowInsecure.IsEnabled = false; + cmbAllowInsecure.SelectedValue = string.Empty; + + cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls; + break; } cmbStreamSecurity.ItemsSource = lstStreamSecurity; @@ -120,6 +133,7 @@ public partial class AddServerWindow : WindowBase case EConfigType.Shadowsocks: this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId3.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SsMethod, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled3.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables); break; @@ -154,7 +168,7 @@ public partial class AddServerWindow : WindowBase case EConfigType.TUIC: this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables); break; case EConfigType.WireGuard: @@ -166,7 +180,15 @@ public partial class AddServerWindow : WindowBase break; case EConfigType.Anytls: - this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId10.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId11.Text).DisposeWith(disposables); + break; + + case EConfigType.Naive: + this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType12.SelectedValue).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables); break; } this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables); diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index ca59c472..8d9a5f85 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -50,6 +50,7 @@ + diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 5c5ba9cb..4adc8d7e 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -72,6 +72,7 @@ public partial class MainWindow : WindowBase 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.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml index 8c6b4a35..f67fe36a 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml @@ -275,6 +275,20 @@ Margin="{StaticResource Margin4}" Style="{StaticResource DefComboBox}" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vm.SelectedSource.Password, v => v.txtId3.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SsMethod, v => v.cmbSecurity3.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled3.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables); break; @@ -149,7 +163,7 @@ public partial class AddServerWindow case EConfigType.TUIC: this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType8.Text).DisposeWith(disposables); break; case EConfigType.WireGuard: @@ -161,7 +175,15 @@ public partial class AddServerWindow break; case EConfigType.Anytls: - this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId10.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId11.Text).DisposeWith(disposables); + break; + + case EConfigType.Naive: + this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType12.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables); break; } this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.Text).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 1c49ca24..f6dfe42b 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -124,6 +124,10 @@ x:Name="menuAddAnytlsServer" Height="{StaticResource MenuItemHeight}" Header="{x:Static resx:ResUI.menuAddAnytlsServer}" /> + diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index 93e62aad..d8e9011b 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -71,6 +71,7 @@ public partial class MainWindow 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.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables);