From 41bc08abc2c8a9c910c7425e71b36abe1c9f4bdc Mon Sep 17 00:00:00 2001
From: be-not-afraid <165935268+be-not-afraid@users.noreply.github.com>
Date: Wed, 15 Apr 2026 14:08:17 +0400
Subject: [PATCH] Added socks auth
---
.../ServiceLib/Handler/ConnectionHandler.cs | 17 +++++++
v2rayN/ServiceLib/Models/ConfigItems.cs | 3 ++
v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 27 +++++++++++
v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 9 ++++
v2rayN/ServiceLib/Resx/ResUI.fr.resx | 9 ++++
v2rayN/ServiceLib/Resx/ResUI.hu.resx | 9 ++++
v2rayN/ServiceLib/Resx/ResUI.resx | 9 ++++
v2rayN/ServiceLib/Resx/ResUI.ru.resx | 9 ++++
v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 9 ++++
v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 9 ++++
.../Singbox/SingboxInboundService.cs | 15 ++++++
.../CoreConfig/V2ray/V2rayInboundService.cs | 17 +++++++
v2rayN/ServiceLib/Services/DownloadService.cs | 19 +++++++-
.../ServiceLib/Services/SpeedtestService.cs | 18 ++++++++
.../ViewModels/OptionSettingViewModel.cs | 9 ++++
.../Views/OptionSettingWindow.axaml | 41 +++++++++++++++++
.../Views/OptionSettingWindow.axaml.cs | 5 ++
v2rayN/v2rayN/Views/OptionSettingWindow.xaml | 46 +++++++++++++++++++
.../v2rayN/Views/OptionSettingWindow.xaml.cs | 5 ++
19 files changed, 284 insertions(+), 1 deletion(-)
diff --git a/v2rayN/ServiceLib/Handler/ConnectionHandler.cs b/v2rayN/ServiceLib/Handler/ConnectionHandler.cs
index 05825d93..896d0947 100644
--- a/v2rayN/ServiceLib/Handler/ConnectionHandler.cs
+++ b/v2rayN/ServiceLib/Handler/ConnectionHandler.cs
@@ -46,6 +46,7 @@ public static class ConnectionHandler
{
var port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{port}");
+ ApplyMixedPortAuth(webProxy);
var url = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
for (var i = 0; i < 2; i++)
@@ -95,4 +96,20 @@ public static class ConnectionHandler
}
return responseTime;
}
+
+ private static void ApplyMixedPortAuth(WebProxy webProxy)
+ {
+ var inbound = AppManager.Instance.Config?.Inbound?.FirstOrDefault();
+ if (inbound?.MixedPortAuthEnabled != true)
+ {
+ return;
+ }
+ if (inbound.MixedPortAuthUser.IsNullOrEmpty() || inbound.MixedPortAuthPass.IsNullOrEmpty())
+ {
+ return;
+ }
+
+ // Use credential object instead of URI userinfo to avoid leaking secrets.
+ webProxy.Credentials = new NetworkCredential(inbound.MixedPortAuthUser, inbound.MixedPortAuthPass);
+ }
}
diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs
index fa766f0d..98b4bae4 100644
--- a/v2rayN/ServiceLib/Models/ConfigItems.cs
+++ b/v2rayN/ServiceLib/Models/ConfigItems.cs
@@ -35,6 +35,9 @@ public class InItem
public bool NewPort4LAN { get; set; }
public string User { get; set; }
public string Pass { get; set; }
+ public bool MixedPortAuthEnabled { get; set; }
+ public string MixedPortAuthUser { get; set; }
+ public string MixedPortAuthPass { get; set; }
public bool SecondLocalPortEnabled { get; set; }
}
diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index d323889a..547888f2 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -4068,6 +4068,33 @@ namespace ServiceLib.Resx {
}
}
+ ///
+ /// 查找类似 Enable Mixed Port Auth 的本地化字符串。
+ ///
+ public static string TbSettingsMixedPortAuthEnabled {
+ get {
+ return ResourceManager.GetString("TbSettingsMixedPortAuthEnabled", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 Mixed Port Auth Pass 的本地化字符串。
+ ///
+ public static string TbSettingsMixedPortAuthPass {
+ get {
+ return ResourceManager.GetString("TbSettingsMixedPortAuthPass", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 Mixed Port Auth User 的本地化字符串。
+ ///
+ public static string TbSettingsMixedPortAuthUser {
+ get {
+ return ResourceManager.GetString("TbSettingsMixedPortAuthUser", resourceCulture);
+ }
+ }
+
///
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
///
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index eda45653..694c5bd3 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -1338,6 +1338,15 @@
نوع Sniffing
+
+ فعالسازی احراز هویت پورت ترکیبی
+
+
+ رمز عبور احراز هویت پورت ترکیبی
+
+
+ نام کاربری احراز هویت پورت ترکیبی
+
فعال کردن دومین پورت ترکیبی
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
index 8f173e6e..d64a5cae 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
@@ -1335,6 +1335,15 @@
Type de détection de trafic
+
+ Activer l'authentification du port mixte
+
+
+ Mot de passe d'authentification du port mixte
+
+
+ Utilisateur d'authentification du port mixte
+
Activer un second port d’écoute local
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index 4437eafa..69050aae 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -1338,6 +1338,15 @@
Sniffing típus
+
+ Vegyes port hitelesítés engedélyezése
+
+
+ Vegyes port hitelesítési jelszó
+
+
+ Vegyes port hitelesítési felhasználó
+
Második vegyes port engedélyezése
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index 6bbf3f72..fd0e89e1 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -1347,6 +1347,15 @@
Sniffing type
+
+ Enable Mixed Port Auth
+
+
+ Mixed Port Auth Pass
+
+
+ Mixed Port Auth User
+
Enable second mixed port
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index c777c4d9..a46609c1 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -1338,6 +1338,15 @@
Тип сниффинга
+
+ Включить авторизацию смешанного порта
+
+
+ Пароль авторизации смешанного порта
+
+
+ Пользователь авторизации смешанного порта
+
Включить второй смешанный порт
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
index b26059ad..d40fccfd 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -1344,6 +1344,15 @@
流量探测类型
+
+ 启用混合端口认证
+
+
+ 混合端口认证密码
+
+
+ 混合端口认证用户名
+
开启第二个本地监听端口
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
index bacf2f11..2b9b9458 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -1335,6 +1335,15 @@
流量探測類型
+
+ 啟用混合連接埠驗證
+
+
+ 混合連接埠驗證密碼
+
+
+ 混合連接埠驗證使用者
+
開啟第二個本機監聽埠
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs
index 3a27c7da..fe72db31 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxInboundService.cs
@@ -22,6 +22,21 @@ public partial class CoreConfigSingboxService
_coreConfig.inbounds.Add(inbound);
inbound.listen_port = listenPort;
+ if (_config.Inbound.First().MixedPortAuthEnabled)
+ {
+ inbound.users = new()
+ {
+ new()
+ {
+ username = _config.Inbound.First().MixedPortAuthUser,
+ password = _config.Inbound.First().MixedPortAuthPass
+ }
+ };
+ }
+ else
+ {
+ inbound.users = null;
+ }
if (_config.Inbound.First().SecondLocalPortEnabled)
{
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs
index 7ae12c7c..8bb7d0a6 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayInboundService.cs
@@ -65,6 +65,23 @@ public partial class CoreConfigV2rayService
inbound.sniffing.enabled = inItem.SniffingEnabled;
inbound.sniffing.destOverride = inItem.DestOverride;
inbound.sniffing.routeOnly = inItem.RouteOnly;
+ if (inItem.MixedPortAuthEnabled)
+ {
+ inbound.settings.auth = "password";
+ inbound.settings.accounts = new List
+ {
+ new()
+ {
+ user = inItem.MixedPortAuthUser,
+ pass = inItem.MixedPortAuthPass
+ }
+ };
+ }
+ else
+ {
+ inbound.settings.auth = "noauth";
+ inbound.settings.accounts = null;
+ }
return inbound;
}
diff --git a/v2rayN/ServiceLib/Services/DownloadService.cs b/v2rayN/ServiceLib/Services/DownloadService.cs
index 77d3a7c1..a6ee41d2 100644
--- a/v2rayN/ServiceLib/Services/DownloadService.cs
+++ b/v2rayN/ServiceLib/Services/DownloadService.cs
@@ -212,7 +212,24 @@ public class DownloadService
return null;
}
- return new WebProxy($"socks5://{Global.Loopback}:{port}");
+ var webProxy = new WebProxy($"socks5://{Global.Loopback}:{port}");
+ ApplyMixedPortAuth(webProxy);
+ return webProxy;
+ }
+
+ private void ApplyMixedPortAuth(WebProxy webProxy)
+ {
+ var inbound = AppManager.Instance.Config?.Inbound?.FirstOrDefault();
+ if (inbound?.MixedPortAuthEnabled != true)
+ {
+ return;
+ }
+ if (inbound.MixedPortAuthUser.IsNullOrEmpty() || inbound.MixedPortAuthPass.IsNullOrEmpty())
+ {
+ return;
+ }
+
+ webProxy.Credentials = new NetworkCredential(inbound.MixedPortAuthUser, inbound.MixedPortAuthPass);
}
private async Task SocketCheck(string ip, int port)
diff --git a/v2rayN/ServiceLib/Services/SpeedtestService.cs b/v2rayN/ServiceLib/Services/SpeedtestService.cs
index 362f64d0..b54ce0ea 100644
--- a/v2rayN/ServiceLib/Services/SpeedtestService.cs
+++ b/v2rayN/ServiceLib/Services/SpeedtestService.cs
@@ -305,6 +305,7 @@ public class SpeedtestService(Config config, Func updateF
private async Task DoRealPing(ServerTestItem it)
{
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
+ ApplyMixedPortAuth(webProxy);
var responseTime = await ConnectionHandler.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
ProfileExManager.Instance.SetTestDelay(it.IndexId, responseTime);
@@ -317,6 +318,7 @@ public class SpeedtestService(Config config, Func updateF
await UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
+ ApplyMixedPortAuth(webProxy);
var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, async (success, msg) =>
@@ -378,6 +380,22 @@ public class SpeedtestService(Config config, Func updateF
return lstTest;
}
+ private void ApplyMixedPortAuth(WebProxy webProxy)
+ {
+ var inbound = _config?.Inbound?.FirstOrDefault();
+ if (inbound?.MixedPortAuthEnabled != true)
+ {
+ return;
+ }
+ if (inbound.MixedPortAuthUser.IsNullOrEmpty() || inbound.MixedPortAuthPass.IsNullOrEmpty())
+ {
+ return;
+ }
+
+ // Keep credentials out of URLs/logs and pass them via proxy credentials only.
+ webProxy.Credentials = new NetworkCredential(inbound.MixedPortAuthUser, inbound.MixedPortAuthPass);
+ }
+
private async Task UpdateFunc(string indexId, string delay, string speed = "")
{
await _updateFunc?.Invoke(new() { IndexId = indexId, Delay = delay, Speed = speed });
diff --git a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
index 1d26f02f..c1d7588f 100644
--- a/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
+++ b/v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
@@ -14,6 +14,9 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public bool newPort4LAN { get; set; }
[Reactive] public string user { get; set; }
[Reactive] public string pass { get; set; }
+ [Reactive] public bool mixedPortAuthEnabled { get; set; }
+ [Reactive] public string mixedPortAuthUser { get; set; }
+ [Reactive] public string mixedPortAuthPass { get; set; }
[Reactive] public bool muxEnabled { get; set; }
[Reactive] public bool logEnabled { get; set; }
[Reactive] public string loglevel { get; set; }
@@ -149,6 +152,9 @@ public class OptionSettingViewModel : MyReactiveObject
newPort4LAN = inbound.NewPort4LAN;
user = inbound.User;
pass = inbound.Pass;
+ mixedPortAuthEnabled = inbound.MixedPortAuthEnabled;
+ mixedPortAuthUser = inbound.MixedPortAuthUser;
+ mixedPortAuthPass = inbound.MixedPortAuthPass;
muxEnabled = _config.CoreBasicItem.MuxEnabled;
logEnabled = _config.CoreBasicItem.LogEnabled;
loglevel = _config.CoreBasicItem.Loglevel;
@@ -334,6 +340,9 @@ public class OptionSettingViewModel : MyReactiveObject
_config.Inbound.First().NewPort4LAN = newPort4LAN;
_config.Inbound.First().User = user;
_config.Inbound.First().Pass = pass;
+ _config.Inbound.First().MixedPortAuthEnabled = mixedPortAuthEnabled;
+ _config.Inbound.First().MixedPortAuthUser = mixedPortAuthUser;
+ _config.Inbound.First().MixedPortAuthPass = mixedPortAuthPass;
if (_config.Inbound.Count > 1)
{
_config.Inbound.RemoveAt(1);
diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
index 640a4f6f..6ccce9e5 100644
--- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
@@ -59,6 +59,47 @@
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsSocksPortTip}"
TextWrapping="Wrap" />
+
+
+
+
+
+
+
+
this.Bind(ViewModel, vm => vm.newPort4LAN, v => v.txtpass.IsEnabled).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.user, v => v.txtuser.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.pass, v => v.txtpass.Text).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthEnabled, v => v.togMixedPortAuthEnabled.IsChecked).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthEnabled, v => v.txtMixedPortAuthUser.IsEnabled).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthEnabled, v => v.txtMixedPortAuthPass.IsEnabled).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthUser, v => v.txtMixedPortAuthUser.Text).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthPass, v => v.txtMixedPortAuthPass.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.muxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.logEnabled, v => v.toglogEnabled.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.loglevel, v => v.cmbloglevel.SelectedValue).DisposeWith(disposables);
diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml
index 5a545c65..6595409f 100644
--- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml
+++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml
@@ -94,6 +94,52 @@
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSocksPortTip}"
TextWrapping="Wrap" />
+
+
+
+
+
+
+
+
vm.newPort4LAN, v => v.txtpass.IsEnabled).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.user, v => v.txtuser.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.pass, v => v.txtpass.Text).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthEnabled, v => v.togMixedPortAuthEnabled.IsChecked).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthEnabled, v => v.txtMixedPortAuthUser.IsEnabled).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthEnabled, v => v.txtMixedPortAuthPass.IsEnabled).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthUser, v => v.txtMixedPortAuthUser.Text).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.mixedPortAuthPass, v => v.txtMixedPortAuthPass.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.muxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.logEnabled, v => v.toglogEnabled.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.loglevel, v => v.cmbloglevel.Text).DisposeWith(disposables);