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/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index e773c2ef..0caf89b9 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -281,12 +281,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; @@ -310,7 +309,6 @@ public sealed class AppManager } //await ProfileGroupItemManager.Instance.ClearAll(); -#pragma warning restore CS0618 } private async Task MigrateProfileExtraSub(List batch) @@ -356,6 +354,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; @@ -412,7 +411,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!)); @@ -477,8 +475,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..a76bad45 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; } diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs index 02deaabf..75eef8d7 100644 --- a/v2rayN/ServiceLib/Models/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs @@ -133,6 +133,7 @@ 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 bool? udp_over_tcp { get; set; } public string? method { get; set; } public string? username { get; set; } public string? password { get; set; } diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs index 80baf43b..37ad555e 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 8f798007..d56e6446 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -4455,6 +4455,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 UDP over TCP 的本地化字符串。 + /// + public static string TbUot { + get { + return ResourceManager.GetString("TbUot", resourceCulture); + } + } + /// /// 查找类似 Validate Regional Domain IPs 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index 9aba2fed..6a2e591a 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1668,4 +1668,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Finalmask + + UDP over TCP + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx index 3dfbcc09..df2959a0 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -1665,4 +1665,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Finalmask + + UDP over TCP + diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index e69a0a54..004f4eea 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1668,4 +1668,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Finalmask + + UDP over TCP + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index cc304154..f1b2fa99 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1668,4 +1668,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Finalmask + + UDP over TCP + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index 6f093f72..768af4d0 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1668,4 +1668,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Finalmask + + UDP over TCP + \ 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 c0f8665d..e28d2b47 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1665,4 +1665,7 @@ Finalmask + + UDP over TCP + \ 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 9002c3af..35034a9a 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1665,4 +1665,7 @@ Finalmask + + UDP over TCP + \ 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 b30c9c48..29754b02 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -112,6 +112,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) { @@ -269,7 +270,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: diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index c8862648..853ada7f 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -153,6 +153,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 f56bb1c0..a786580c 100644 --- a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs @@ -61,6 +61,12 @@ public class AddServerViewModel : MyReactiveObject [Reactive] public int WgMtu { get; set; } + [Reactive] + public bool Uot { get; set; } + + [Reactive] + public string CongestionControl { get; set; } + public ReactiveCommand FetchCertCmd { get; } public ReactiveCommand FetchCertChainCmd { get; } public ReactiveCommand SaveCmd { get; } @@ -123,6 +129,8 @@ 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; } private async Task SaveServerAsync() @@ -185,6 +193,8 @@ public class AddServerViewModel : MyReactiveObject WgInterfaceAddress = WgInterfaceAddress.NullIfEmpty(), WgReserved = WgReserved.NullIfEmpty(), WgMtu = WgMtu >= 576 ? WgMtu : null, + Uot = Uot ? true : null, + CongestionControl = CongestionControl.NullIfEmpty(), }); if (await ConfigHandler.AddServer(_config, SelectedSource) == 0) diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml index 477eca5d..2a1cd63f 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.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; @@ -156,7 +157,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: diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml index e78e7f9b..50641332 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml @@ -277,6 +277,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; @@ -151,7 +152,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: