From ae662a628d844e18cf4a712a9b17fc44e0443aac Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Sun, 26 Apr 2026 17:50:10 +0800
Subject: [PATCH 1/4] Remove TbSettingsRemoteDNS and update DNS doc
---
v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 11 +----------
v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 3 ---
v2rayN/ServiceLib/Resx/ResUI.fr.resx | 3 ---
v2rayN/ServiceLib/Resx/ResUI.hu.resx | 3 ---
v2rayN/ServiceLib/Resx/ResUI.resx | 5 +----
v2rayN/ServiceLib/Resx/ResUI.ru.resx | 3 ---
v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 5 +----
v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 5 +----
v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml | 6 ------
v2rayN/v2rayN/Views/DNSSettingWindow.xaml | 5 -----
10 files changed, 4 insertions(+), 45 deletions(-)
diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index 616574e5..4ffb8efa 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -2881,7 +2881,7 @@ namespace ServiceLib.Resx {
}
///
- /// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。
+ /// 查找类似 Please fill in DNS Object; Click to view documentation 的本地化字符串。
///
public static string TbDnsObjectDoc {
get {
@@ -4158,15 +4158,6 @@ namespace ServiceLib.Resx {
}
}
- ///
- /// 查找类似 Custom DNS (multiple, separated by commas (,)) 的本地化字符串。
- ///
- public static string TbSettingsRemoteDNS {
- get {
- return ResourceManager.GetString("TbSettingsRemoteDNS", resourceCulture);
- }
- }
-
///
/// 查找类似 Route Only 的本地化字符串。
///
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index bd4c9fea..8b81572c 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -720,9 +720,6 @@
مجوز احراز هویت
-
- سفارشی DNS (multiple, separated by commas (,))
-
تنظیم کردن Win10 UWP Loopback
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
index 9533c895..b9fa9ffd 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
@@ -720,9 +720,6 @@
Mot de passe d’authentification
-
- DNS perso (plusieurs configurables, séparés par virgules)
-
Lever la restriction de proxy en boucle locale pour les applications Win10 UWP
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index 85fa0101..a3e99129 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -720,9 +720,6 @@
Hitelesítési jelszó
-
- Egyéni DNS (több, vesszővel (,) elválasztva)
-
Win10 UWP Loopback beállítása
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index db4e9222..2cc7929e 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -720,9 +720,6 @@
Auth pass
-
- Custom DNS (multiple, separated by commas (,))
-
Set Win10 UWP Loopback
@@ -862,7 +859,7 @@
Rule object Doc
- Supports DNS Object; Click to view documentation
+ Please fill in DNS Object; Click to view documentation
For group please leave blank here
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index 0b64698c..c1dc1b35 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -720,9 +720,6 @@
Пароль авторизации
-
- Пользовательский DNS (если несколько, то делите запятыми (,))
-
Разрешить loopback для приложений UWP (Win10)
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
index 42aa942b..06d07da0 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -720,9 +720,6 @@
认证密码
-
- 自定义 DNS (可多个,用逗号 (,) 分隔)
-
解除 Win10 UWP 应用回环代理限制
@@ -862,7 +859,7 @@
规则详细说明文档
- 支持填写 DnsObject,JSON 格式,点击查看文档
+ 请填写 DnsObject,JSON 格式,点击查看文档
普通分组此处请留空
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
index e5f34cf6..e12e3f39 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -720,9 +720,6 @@
認證密碼
-
- 自訂 DNS (可多個,用逗號 (,) 分隔)
-
解除 Win10 UWP 應用回環代理限制
@@ -862,7 +859,7 @@
規則詳細說明檔案
- 支援填寫 DnsObject,JSON 格式,點擊查看說明
+ 請填寫 DnsObject,JSON 格式,點擊查看說明
普通分組此處請留空
diff --git a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml
index 1b2a691c..b736de32 100644
--- a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml
@@ -342,11 +342,6 @@
-
-
@@ -494,7 +489,6 @@
Header="{x:Static resx:ResUI.TbSettingsTunMode}">
-
diff --git a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml
index d27188a4..d2bdcb9b 100644
--- a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml
+++ b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml
@@ -390,11 +390,6 @@
-
Date: Sun, 26 Apr 2026 19:24:57 +0800
Subject: [PATCH 2/4] Code clean
---
.../Context/CoreConfigContextBuilderTests.cs | 160 +++++++++---------
.../CoreConfig/CoreConfigTestFactory.cs | 26 ++-
.../ServiceLib.Tests/Fmt/FmtHandlerTests.cs | 4 +-
v2rayN/ServiceLib.UdpTest/Socks5UdpChannel.cs | 12 +-
.../ServiceLib.UdpTest/Tester/DnsService.cs | 1 +
v2rayN/ServiceLib.UdpTest/Tester/IUdpTest.cs | 3 +
.../ServiceLib.UdpTest/Tester/McBeService.cs | 7 +-
.../ServiceLib.UdpTest/Tester/StunService.cs | 1 +
v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs | 1 +
v2rayN/ServiceLib/Models/SingboxConfig.cs | 1 +
v2rayN/ServiceLib/Models/V2rayConfig.cs | 5 +
.../CoreConfig/V2ray/V2rayOutboundService.cs | 1 +
v2rayN/ServiceLib/Services/UpdateService.cs | 2 -
.../Views/AddServerWindow.axaml.cs | 6 +
.../Views/RoutingSettingWindow.axaml.cs | 5 +-
.../ViewModels/ThemeSettingViewModel.cs | 2 +-
v2rayN/v2rayN/Views/AddServerWindow.xaml.cs | 6 +
v2rayN/v2rayN/Views/MainWindow.xaml.cs | 4 +-
18 files changed, 148 insertions(+), 99 deletions(-)
diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs
index 5f185a9f..ee329845 100644
--- a/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs
+++ b/v2rayN/ServiceLib.Tests/CoreConfig/Context/CoreConfigContextBuilderTests.cs
@@ -9,105 +9,105 @@ namespace ServiceLib.Tests.CoreConfig.Context;
public class CoreConfigContextBuilderTests
{
- [Fact]
- public async Task ResolveNodeAsync_DirectCycleDependency_ShouldFailWithCycleError()
- {
- var config = CoreConfigTestFactory.CreateConfig();
- CoreConfigTestFactory.BindAppManagerConfig(config);
+ [Fact]
+ public async Task ResolveNodeAsync_DirectCycleDependency_ShouldFailWithCycleError()
+ {
+ var config = CoreConfigTestFactory.CreateConfig();
+ CoreConfigTestFactory.BindAppManagerConfig(config);
- var groupAId = NewId("group-a");
- var groupBId = NewId("group-b");
- var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId]);
- var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupAId]);
+ var groupAId = NewId("group-a");
+ var groupBId = NewId("group-b");
+ var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId]);
+ var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupAId]);
- await UpsertProfilesAsync(groupA, groupB);
+ await UpsertProfilesAsync(groupA, groupB);
- var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
- context.AllProxiesMap.Clear();
+ var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
+ context.AllProxiesMap.Clear();
- var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
+ var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
- validatorResult.Success.Should().BeFalse();
- validatorResult.Errors.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
- context.AllProxiesMap.Should().NotContainKey(groupA.IndexId);
- context.AllProxiesMap.Should().NotContainKey(groupB.IndexId);
- }
+ validatorResult.Success.Should().BeFalse();
+ validatorResult.Errors.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
+ context.AllProxiesMap.Should().NotContainKey(groupA.IndexId);
+ context.AllProxiesMap.Should().NotContainKey(groupB.IndexId);
+ }
- [Fact]
- public async Task ResolveNodeAsync_IndirectCycleDependency_ShouldFailWithCycleError()
- {
- var config = CoreConfigTestFactory.CreateConfig();
- CoreConfigTestFactory.BindAppManagerConfig(config);
+ [Fact]
+ public async Task ResolveNodeAsync_IndirectCycleDependency_ShouldFailWithCycleError()
+ {
+ var config = CoreConfigTestFactory.CreateConfig();
+ CoreConfigTestFactory.BindAppManagerConfig(config);
- var groupAId = NewId("group-a");
- var groupBId = NewId("group-b");
- var groupCId = NewId("group-c");
- var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId]);
- var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupCId]);
- var groupC = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupCId, "group-c", [groupAId]);
+ var groupAId = NewId("group-a");
+ var groupBId = NewId("group-b");
+ var groupCId = NewId("group-c");
+ var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId]);
+ var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupCId]);
+ var groupC = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupCId, "group-c", [groupAId]);
- await UpsertProfilesAsync(groupA, groupB, groupC);
+ await UpsertProfilesAsync(groupA, groupB, groupC);
- var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
- context.AllProxiesMap.Clear();
+ var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
+ context.AllProxiesMap.Clear();
- var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
+ var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
- validatorResult.Success.Should().BeFalse();
- validatorResult.Errors.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
- context.AllProxiesMap.Should().NotContainKey(groupA.IndexId);
- context.AllProxiesMap.Should().NotContainKey(groupB.IndexId);
- context.AllProxiesMap.Should().NotContainKey(groupC.IndexId);
- }
+ validatorResult.Success.Should().BeFalse();
+ validatorResult.Errors.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
+ context.AllProxiesMap.Should().NotContainKey(groupA.IndexId);
+ context.AllProxiesMap.Should().NotContainKey(groupB.IndexId);
+ context.AllProxiesMap.Should().NotContainKey(groupC.IndexId);
+ }
- [Fact]
- public async Task ResolveNodeAsync_CycleWithValidBranch_ShouldSkipCycleAndKeepValidChild()
- {
- var config = CoreConfigTestFactory.CreateConfig();
- CoreConfigTestFactory.BindAppManagerConfig(config);
+ [Fact]
+ public async Task ResolveNodeAsync_CycleWithValidBranch_ShouldSkipCycleAndKeepValidChild()
+ {
+ var config = CoreConfigTestFactory.CreateConfig();
+ CoreConfigTestFactory.BindAppManagerConfig(config);
- var groupAId = NewId("group-a");
- var groupBId = NewId("group-b");
- var leafId = NewId("leaf");
- var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId, leafId]);
- var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupAId]);
- var leaf = CoreConfigTestFactory.CreateSocksNode(ECoreType.Xray, leafId, "leaf");
+ var groupAId = NewId("group-a");
+ var groupBId = NewId("group-b");
+ var leafId = NewId("leaf");
+ var groupA = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupAId, "group-a", [groupBId, leafId]);
+ var groupB = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, groupBId, "group-b", [groupAId]);
+ var leaf = CoreConfigTestFactory.CreateSocksNode(ECoreType.Xray, leafId, "leaf");
- await UpsertProfilesAsync(groupA, groupB, leaf);
+ await UpsertProfilesAsync(groupA, groupB, leaf);
- var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
- context.AllProxiesMap.Clear();
+ var context = CoreConfigTestFactory.CreateContext(config, groupA, ECoreType.Xray);
+ context.AllProxiesMap.Clear();
- var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
+ var (_, validatorResult) = await CoreConfigContextBuilder.ResolveNodeAsync(context, groupA, false);
- validatorResult.Success.Should().BeTrue();
- validatorResult.Errors.Should().BeEmpty();
- validatorResult.Warnings.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
+ validatorResult.Success.Should().BeTrue();
+ validatorResult.Errors.Should().BeEmpty();
+ validatorResult.Warnings.Should().Contain(msg => ContainsCycleDependencyMessage(msg));
- context.AllProxiesMap.Should().ContainKey(leaf.IndexId);
- context.AllProxiesMap.Should().ContainKey(groupA.IndexId);
- context.AllProxiesMap.Should().NotContainKey(groupB.IndexId);
- groupA.GetProtocolExtra().ChildItems.Should().Be(leaf.IndexId);
- }
+ context.AllProxiesMap.Should().ContainKey(leaf.IndexId);
+ context.AllProxiesMap.Should().ContainKey(groupA.IndexId);
+ context.AllProxiesMap.Should().NotContainKey(groupB.IndexId);
+ groupA.GetProtocolExtra().ChildItems.Should().Be(leaf.IndexId);
+ }
- private static string NewId(string prefix)
- {
- return $"{prefix}-{Guid.NewGuid():N}";
- }
+ private static string NewId(string prefix)
+ {
+ return $"{prefix}-{Guid.NewGuid():N}";
+ }
- private static bool ContainsCycleDependencyMessage(string message)
- {
- return message.Contains("cycle dependency", StringComparison.OrdinalIgnoreCase)
- || message.Contains("循环依赖", StringComparison.Ordinal)
- || message.Contains("循環依賴", StringComparison.Ordinal);
- }
+ private static bool ContainsCycleDependencyMessage(string message)
+ {
+ return message.Contains("cycle dependency", StringComparison.OrdinalIgnoreCase)
+ || message.Contains("循环依赖", StringComparison.Ordinal)
+ || message.Contains("循環依賴", StringComparison.Ordinal);
+ }
- private static async Task UpsertProfilesAsync(params ProfileItem[] profiles)
- {
- SQLiteHelper.Instance.CreateTable();
- foreach (var profile in profiles)
- {
- await SQLiteHelper.Instance.ReplaceAsync(profile);
- }
- }
+ private static async Task UpsertProfilesAsync(params ProfileItem[] profiles)
+ {
+ SQLiteHelper.Instance.CreateTable();
+ foreach (var profile in profiles)
+ {
+ await SQLiteHelper.Instance.ReplaceAsync(profile);
+ }
+ }
}
diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs b/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs
index c5acd854..812a5a32 100644
--- a/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs
+++ b/v2rayN/ServiceLib.Tests/CoreConfig/CoreConfigTestFactory.cs
@@ -1,7 +1,7 @@
+using System.Reflection;
using ServiceLib.Enums;
using ServiceLib.Manager;
using ServiceLib.Models;
-using System.Reflection;
namespace ServiceLib.Tests.CoreConfig;
@@ -33,7 +33,10 @@ internal static class CoreConfigTestFactory
UiItem =
new UIItem
{
- CurrentLanguage = "en", CurrentFontFamily = "sans", MainColumnItem = [], WindowSizeItem = []
+ CurrentLanguage = "en",
+ CurrentFontFamily = "sans",
+ MainColumnItem = [],
+ WindowSizeItem = []
},
ConstItem = new ConstItem(),
SpeedTestItem = new SpeedTestItem
@@ -51,7 +54,8 @@ internal static class CoreConfigTestFactory
SystemProxyItem =
new SystemProxyItem
{
- SystemProxyExceptions = string.Empty, SystemProxyAdvancedProtocol = string.Empty
+ SystemProxyExceptions = string.Empty,
+ SystemProxyAdvancedProtocol = string.Empty
},
WebDavItem = new WebDavItem(),
CheckUpdateItem = new CheckUpdateItem(),
@@ -131,11 +135,15 @@ internal static class CoreConfigTestFactory
{
var node = new ProfileItem
{
- IndexId = indexId, ConfigType = EConfigType.PolicyGroup, CoreType = coreType, Remarks = remarks,
+ IndexId = indexId,
+ ConfigType = EConfigType.PolicyGroup,
+ CoreType = coreType,
+ Remarks = remarks,
};
node.SetProtocolExtra(node.GetProtocolExtra() with
{
- GroupType = nameof(EConfigType.PolicyGroup), ChildItems = string.Join(",", childIndexIds),
+ GroupType = nameof(EConfigType.PolicyGroup),
+ ChildItems = string.Join(",", childIndexIds),
});
return node;
@@ -146,11 +154,15 @@ internal static class CoreConfigTestFactory
{
var node = new ProfileItem
{
- IndexId = indexId, ConfigType = EConfigType.ProxyChain, CoreType = coreType, Remarks = remarks,
+ IndexId = indexId,
+ ConfigType = EConfigType.ProxyChain,
+ CoreType = coreType,
+ Remarks = remarks,
};
node.SetProtocolExtra(node.GetProtocolExtra() with
{
- GroupType = nameof(EConfigType.ProxyChain), ChildItems = string.Join(",", childIndexIds),
+ GroupType = nameof(EConfigType.ProxyChain),
+ ChildItems = string.Join(",", childIndexIds),
});
return node;
diff --git a/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs b/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs
index 56fb0f97..143fa3e5 100644
--- a/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs
+++ b/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs
@@ -1,7 +1,7 @@
using AwesomeAssertions;
+using ServiceLib.Enums;
using ServiceLib.Handler.Fmt;
using ServiceLib.Models;
-using ServiceLib.Enums;
using Xunit;
namespace ServiceLib.Tests.Fmt;
@@ -92,7 +92,7 @@ public class FmtHandlerTests
var uri = FmtHandler.GetShareUri(source);
uri.Should().NotBeNullOrWhiteSpace();
- (uri!.StartsWith(Global.ProtocolShares[source.ConfigType], StringComparison.OrdinalIgnoreCase)).Should()
+ uri!.StartsWith(Global.ProtocolShares[source.ConfigType], StringComparison.OrdinalIgnoreCase).Should()
.BeTrue();
var resolved = FmtHandler.ResolveConfig(uri, out var msg);
diff --git a/v2rayN/ServiceLib.UdpTest/Socks5UdpChannel.cs b/v2rayN/ServiceLib.UdpTest/Socks5UdpChannel.cs
index 51a5b3ed..f9a2951f 100644
--- a/v2rayN/ServiceLib.UdpTest/Socks5UdpChannel.cs
+++ b/v2rayN/ServiceLib.UdpTest/Socks5UdpChannel.cs
@@ -239,7 +239,9 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
var clientAddrForSocks = new Socks5AddressData
{
- AddressType = Socks5AddressData.AddrTypeIPv4, Host = "0.0.0.0", Port = 0
+ AddressType = Socks5AddressData.AddrTypeIPv4,
+ Host = "0.0.0.0",
+ Port = 0
};
using var udpAssociateReqMs = new MemoryStream();
udpAssociateReqMs.WriteByte(Socks5Version);
@@ -267,7 +269,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
return true;
}
- #endregion
+ #endregion SOCKS5 Connection Handling
#region SOCKS5 Address Handling
@@ -298,6 +300,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
}
break;
+
case AddrTypeDomain:
if (string.IsNullOrEmpty(Host))
{
@@ -311,6 +314,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
}
break;
+
case AddrTypeIPv6:
if (IPAddress.TryParse(Host, out var ip6) && ip6.AddressFamily == AddressFamily.InterNetworkV6)
{
@@ -322,6 +326,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
}
break;
+
default:
throw new NotSupportedException($"SOCKS5 address type {AddressType} not supported.");
}
@@ -355,6 +360,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
addr.Host = new IPAddress(ipv4Bytes).ToString();
break;
+
case AddrTypeDomain:
var lenByte = new byte[1];
if (await stream.ReadAsync(lenByte.AsMemory(0, 1), ct).ConfigureAwait(false) < 1)
@@ -379,6 +385,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
}
break;
+
case AddrTypeIPv6:
var ipv6Bytes = new byte[16];
if (await stream.ReadAsync(ipv6Bytes.AsMemory(0, 16), ct).ConfigureAwait(false) < 16)
@@ -388,6 +395,7 @@ public class Socks5UdpChannel(string socks5Host, int socks5TcpPort) : IDisposabl
addr.Host = new IPAddress(ipv6Bytes).ToString();
break;
+
default:
return null;
}
diff --git a/v2rayN/ServiceLib.UdpTest/Tester/DnsService.cs b/v2rayN/ServiceLib.UdpTest/Tester/DnsService.cs
index a6f5d910..81bea2b8 100644
--- a/v2rayN/ServiceLib.UdpTest/Tester/DnsService.cs
+++ b/v2rayN/ServiceLib.UdpTest/Tester/DnsService.cs
@@ -4,6 +4,7 @@ public class DnsService : IUdpTest
{
private const int DnsDefaultPort = 53;
private const string DnsDefaultServer = "8.8.8.8"; // Google Public DNS
+
private static readonly byte[] DnsQueryPacket =
[
// Header: ID=0x1234, Standard query with RD set, QDCOUNT=1
diff --git a/v2rayN/ServiceLib.UdpTest/Tester/IUdpTest.cs b/v2rayN/ServiceLib.UdpTest/Tester/IUdpTest.cs
index 550f712e..af3fa6c5 100644
--- a/v2rayN/ServiceLib.UdpTest/Tester/IUdpTest.cs
+++ b/v2rayN/ServiceLib.UdpTest/Tester/IUdpTest.cs
@@ -3,7 +3,10 @@ namespace ServiceLib.UdpTest.Tester;
public interface IUdpTest
{
public byte[] BuildUdpRequestPacket();
+
public bool VerifyAndExtractUdpResponse(byte[] udpResponseBytes);
+
public ushort GetDefaultTargetPort();
+
public string GetDefaultTargetHost();
}
diff --git a/v2rayN/ServiceLib.UdpTest/Tester/McBeService.cs b/v2rayN/ServiceLib.UdpTest/Tester/McBeService.cs
index 777928b1..b4ec0221 100644
--- a/v2rayN/ServiceLib.UdpTest/Tester/McBeService.cs
+++ b/v2rayN/ServiceLib.UdpTest/Tester/McBeService.cs
@@ -4,6 +4,7 @@ public class McBeService : IUdpTest
{
private const int McBeDefaultPort = 19132;
private const string McBeDefaultServer = "pms.mc-complex.com";
+
// 0x01 | client alive time in ms (unsigned long long) | magic | client GUID
private static readonly byte[] McBeQueryPacket =
[
@@ -18,11 +19,13 @@ public class McBeService : IUdpTest
0x66, 0x0E, 0xAB, 0xBC, 0x61, 0x0D, 0x1F, 0x4E,
0xA4, 0x40, 0x8C, 0x65, 0xC1, 0xBE, 0xF5, 0x4B
];
+
private static readonly byte[] McBeMagicBytes =
[
0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78
];
+
private static readonly List ValidGameModes =
[
"Survival",
@@ -40,9 +43,9 @@ public class McBeService : IUdpTest
{
// 0x1c | client alive time in ms (recorded from previous ping) |
// server GUID | Magic | string length | Edition
- //
+ //
// Edition Example:
- //
+ //
// MCPE;Dedicated Server;527;1.19.1;0;10;13253860892328930865;Bedrock level;Survival;1;19132;19133;
if (mcbeResponseBytes.Length < 48)
{
diff --git a/v2rayN/ServiceLib.UdpTest/Tester/StunService.cs b/v2rayN/ServiceLib.UdpTest/Tester/StunService.cs
index 1dc4d3e7..c6b925a3 100644
--- a/v2rayN/ServiceLib.UdpTest/Tester/StunService.cs
+++ b/v2rayN/ServiceLib.UdpTest/Tester/StunService.cs
@@ -4,6 +4,7 @@ public class StunService : IUdpTest
{
private const int StunDefaultPort = 3478;
private const string StunDefaultServer = "stun.voztovoice.org";
+
private static readonly byte[] StunBindingRequestPacket =
[
// STUN Binding Request
diff --git a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs
index 722d97f5..ff7d6d20 100644
--- a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs
+++ b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs
@@ -5,6 +5,7 @@ namespace ServiceLib.Handler.Fmt;
public class BaseFmt
{
private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure" };
+
private static string UrlEncodeSafe(string? value) => Utils.UrlEncode(value ?? string.Empty);
protected static string GetIpv6(string address)
diff --git a/v2rayN/ServiceLib/Models/SingboxConfig.cs b/v2rayN/ServiceLib/Models/SingboxConfig.cs
index 06449224..2282e830 100644
--- a/v2rayN/ServiceLib/Models/SingboxConfig.cs
+++ b/v2rayN/ServiceLib/Models/SingboxConfig.cs
@@ -237,6 +237,7 @@ public class Transport4Sbox
public class Headers4Sbox
{
public string? Host { get; set; }
+
[JsonPropertyName("User-Agent")]
public string UserAgent { get; set; }
}
diff --git a/v2rayN/ServiceLib/Models/V2rayConfig.cs b/v2rayN/ServiceLib/Models/V2rayConfig.cs
index b6aaa2df..26739b69 100644
--- a/v2rayN/ServiceLib/Models/V2rayConfig.cs
+++ b/v2rayN/ServiceLib/Models/V2rayConfig.cs
@@ -500,12 +500,16 @@ public class MaskSettings4Ray
{
public string? password { get; set; }
public string? domain { get; set; }
+
// fragment
public string? packets { get; set; }
+
public string? length { get; set; }
public string? delay { get; set; }
+
// noise
public int? reset { get; set; }
+
public List? noise { get; set; }
}
@@ -533,6 +537,7 @@ public class AccountsItem4Ray
public class Sockopt4Ray
{
public string? dialerProxy { get; set; }
+
[JsonPropertyName("interface")]
public string? Interface { get; set; }
}
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
index ef22d545..4d88b1b5 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
@@ -548,6 +548,7 @@ public partial class CoreConfigV2rayService
FillOutboundMux(outbound);
break;
+
case nameof(ETransport.grpc):
GrpcSettings4Ray grpcSettings = new()
{
diff --git a/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayN/ServiceLib/Services/UpdateService.cs
index 86b5d889..87281149 100644
--- a/v2rayN/ServiceLib/Services/UpdateService.cs
+++ b/v2rayN/ServiceLib/Services/UpdateService.cs
@@ -299,7 +299,6 @@ public class UpdateService(Config config, Func updateFunc)
return url;
}
-
else if (Utils.IsLinux())
{
var arch = RuntimeInformation.ProcessArchitecture;
@@ -314,7 +313,6 @@ public class UpdateService(Config config, Func updateFunc)
_ => null,
};
}
-
else if (Utils.IsMacOS())
{
return RuntimeInformation.ProcessArchitecture switch
diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs
index cc20fff2..71d9a1a9 100644
--- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs
+++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs
@@ -338,21 +338,27 @@ public partial class AddServerWindow : WindowBase
case nameof(ETransport.raw):
gridTransportRaw.IsVisible = true;
break;
+
case nameof(ETransport.kcp):
gridTransportKcp.IsVisible = true;
break;
+
case nameof(ETransport.ws):
gridTransportWs.IsVisible = true;
break;
+
case nameof(ETransport.httpupgrade):
gridTransportHttpupgrade.IsVisible = true;
break;
+
case nameof(ETransport.xhttp):
gridTransportXhttp.IsVisible = true;
break;
+
case nameof(ETransport.grpc):
gridTransportGrpc.IsVisible = true;
break;
+
default:
gridTransportRaw.IsVisible = true;
break;
diff --git a/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs
index 11af7506..544a7242 100644
--- a/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs
+++ b/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs
@@ -64,7 +64,10 @@ public partial class RoutingSettingWindow : WindowBase
private void RoutingSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
{
- if (_closed) return;
+ if (_closed)
+ {
+ return;
+ }
// DomainStrategy is auto-saved reactively; just ensure the caller knows changes were made
if (ViewModel?.IsModified == true)
diff --git a/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs
index 2d663eb1..1d2061cd 100644
--- a/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs
+++ b/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs
@@ -137,7 +137,7 @@ public class ThemeSettingViewModel : MyReactiveObject
private void ModifyFontSize()
{
- double size = (long)CurrentFontSize;
+ double size = CurrentFontSize;
if (size < Global.MinFontSize)
{
return;
diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs b/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs
index aeb6ceaa..74413c80 100644
--- a/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs
+++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs
@@ -340,21 +340,27 @@ public partial class AddServerWindow
case nameof(ETransport.raw):
gridTransportRaw.Visibility = Visibility.Visible;
break;
+
case nameof(ETransport.kcp):
gridTransportKcp.Visibility = Visibility.Visible;
break;
+
case nameof(ETransport.ws):
gridTransportWs.Visibility = Visibility.Visible;
break;
+
case nameof(ETransport.httpupgrade):
gridTransportHttpupgrade.Visibility = Visibility.Visible;
break;
+
case nameof(ETransport.xhttp):
gridTransportXhttp.Visibility = Visibility.Visible;
break;
+
case nameof(ETransport.grpc):
gridTransportGrpc.Visibility = Visibility.Visible;
break;
+
default:
gridTransportRaw.Visibility = Visibility.Visible;
break;
diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs
index 81f2f720..bb74813d 100644
--- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs
+++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs
@@ -170,10 +170,10 @@ public partial class MainWindow
private void OnProgramStarted(object state, bool timeout)
{
- Application.Current?.Dispatcher.Invoke((Action)(() =>
+ Application.Current?.Dispatcher.Invoke(() =>
{
ShowHideWindow(true);
- }));
+ });
}
private async Task DelegateSnackMsg(string content)
From b6f2912f296ef9ef02393e3a676ff3a0e522c19b Mon Sep 17 00:00:00 2001
From: DHR60
Date: Wed, 29 Apr 2026 06:43:13 +0000
Subject: [PATCH 3/4] Remove EchForceQuery (#9214)
---
v2rayN/ServiceLib/Global.cs | 8 --------
v2rayN/ServiceLib/Handler/ConfigHandler.cs | 1 -
v2rayN/ServiceLib/Models/ProfileItem.cs | 1 -
v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 9 ---------
v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 3 ---
v2rayN/ServiceLib/Resx/ResUI.fr.resx | 3 ---
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 | 3 ---
v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 3 ---
.../CoreConfig/V2ray/V2rayOutboundService.cs | 6 +++++-
.../v2rayN.Desktop/Views/AddServerWindow.axaml | 15 +--------------
.../Views/AddServerWindow.axaml.cs | 6 +-----
v2rayN/v2rayN/Views/AddServerWindow.xaml | 17 +----------------
v2rayN/v2rayN/Views/AddServerWindow.xaml.cs | 6 +-----
16 files changed, 9 insertions(+), 81 deletions(-)
diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs
index 312140d6..8de3d925 100644
--- a/v2rayN/ServiceLib/Global.cs
+++ b/v2rayN/ServiceLib/Global.cs
@@ -691,14 +691,6 @@ public class Global
""
];
- public static readonly List EchForceQuerys =
- [
- "none",
- "half",
- "full",
- ""
- ];
-
public static readonly List TunIcmpRoutingPolicies =
[
"rule",
diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs
index d319118f..12523ddf 100644
--- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs
+++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs
@@ -256,7 +256,6 @@ public static class ConfigHandler
item.Cert = profileItem.Cert;
item.CertSha = profileItem.CertSha;
item.EchConfigList = profileItem.EchConfigList;
- item.EchForceQuery = profileItem.EchForceQuery;
item.Finalmask = profileItem.Finalmask;
item.ProtoExtra = profileItem.ProtoExtra;
item.TransportExtra = profileItem.TransportExtra;
diff --git a/v2rayN/ServiceLib/Models/ProfileItem.cs b/v2rayN/ServiceLib/Models/ProfileItem.cs
index 6fe44a3b..ae5f77ad 100644
--- a/v2rayN/ServiceLib/Models/ProfileItem.cs
+++ b/v2rayN/ServiceLib/Models/ProfileItem.cs
@@ -191,7 +191,6 @@ public class ProfileItem
public string Cert { get; set; }
public string CertSha { get; set; }
public string EchConfigList { get; set; }
- public string EchForceQuery { get; set; }
public string Finalmask { get; set; }
public string ProtoExtra { get; set; }
diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index 4ffb8efa..56f95191 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -2943,15 +2943,6 @@ namespace ServiceLib.Resx {
}
}
- ///
- /// 查找类似 EchForceQuery 的本地化字符串。
- ///
- public static string TbEchForceQuery {
- get {
- return ResourceManager.GetString("TbEchForceQuery", resourceCulture);
- }
- }
-
///
/// 查找类似 Edit 的本地化字符串。
///
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index 8b81572c..f2818543 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -1581,9 +1581,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
EchConfigList
-
- EchForceQuery
-
Full certificate (chain), PEM format
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
index b9fa9ffd..1a782f98 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
@@ -1587,9 +1587,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
EchConfigList
-
- EchForceQuery
-
Certificat complet (chaîne), format PEM
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index a3e99129..dbd24707 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -1581,9 +1581,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
EchConfigList
-
- EchForceQuery
-
Full certificate (chain), PEM format
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index 2cc7929e..b3cbc87e 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -1590,9 +1590,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
EchConfigList
-
- EchForceQuery
-
Full certificate (chain), PEM format
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index c1dc1b35..f394c23b 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -1581,9 +1581,6 @@
EchConfigList
-
- EchForceQuery
-
Полный сертификат (цепочка) в формате PEM
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
index 06d07da0..4e2bd39d 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -1587,9 +1587,6 @@
EchConfigList
-
- EchForceQuery
-
完整证书(链),PEM 格式
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
index e12e3f39..14cbec63 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -1578,9 +1578,6 @@
EchConfigList
-
- EchForceQuery
-
完整憑證(鏈),PEM 格式
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
index 4d88b1b5..d8985ccc 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs
@@ -383,7 +383,6 @@ public partial class CoreConfigV2rayService
alpn = _node.GetAlpn(),
fingerprint = _node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : _node.Fingerprint,
echConfigList = _node.EchConfigList.NullIfEmpty(),
- echForceQuery = _node.EchForceQuery.NullIfEmpty()
};
if (sni.IsNotEmpty())
{
@@ -393,6 +392,11 @@ public partial class CoreConfigV2rayService
{
tlsSettings.serverName = Utils.String2List(host)?.First();
}
+ if (!tlsSettings.echConfigList.IsNullOrEmpty())
+ {
+ // For legacy xray compatibility, remove this in the future
+ tlsSettings.echForceQuery = "full";
+ }
var certs = CertPemManager.ParsePemChain(_node.Cert);
if (certs.Count > 0)
{
diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
index 00bcff1b..3ab748b1 100644
--- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
@@ -306,7 +306,7 @@
x:Name="txtSecurity5"
Grid.Row="3"
Grid.Column="1"
- Width="200"
+ Width="400"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
@@ -1115,19 +1115,6 @@
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
-
-
-
cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
cmbAlpn.ItemsSource = Global.Alpns;
- cmbEchForceQuery.ItemsSource = Global.EchForceQuerys;
- var lstStreamSecurity = new List();
- lstStreamSecurity.Add(string.Empty);
- lstStreamSecurity.Add(Global.StreamSecurity);
+ var lstStreamSecurity = new List { string.Empty, Global.StreamSecurity };
switch (profileItem.ConfigType)
{
@@ -246,7 +243,6 @@ public partial class AddServerWindow : WindowBase
this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.togAllowInsecureCertFetch.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.txtAllowInsecureCertFetchTips.IsVisible).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
- this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.SelectedValue).DisposeWith(disposables);
//reality
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml
index 4efb6b94..047d32e4 100644
--- a/v2rayN/v2rayN/Views/AddServerWindow.xaml
+++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml
@@ -415,7 +415,7 @@
x:Name="txtSecurity5"
Grid.Row="3"
Grid.Column="1"
- Width="200"
+ Width="400"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
@@ -1444,21 +1444,6 @@
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
-
-
-
();
- lstStreamSecurity.Add(string.Empty);
- lstStreamSecurity.Add(Global.StreamSecurity);
+ var lstStreamSecurity = new List { string.Empty, Global.StreamSecurity };
switch (profileItem.ConfigType)
{
@@ -247,7 +244,6 @@ public partial class AddServerWindow
.BindTo(this, v => v.txtAllowInsecureCertFetchTips.Visibility);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
- this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.Text).DisposeWith(disposables);
//reality
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
From 49d197e37fd823f99d3df4d4bad197f38618115a Mon Sep 17 00:00:00 2001
From: Miheichev Aleksandr Sergeevich
Date: Wed, 29 Apr 2026 09:43:35 +0300
Subject: [PATCH 4/4] i18n(ru): translate new strings and fix terminology
casing (#9207)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Translate 11 new strings introduced in upstream and fix casing of
several technical terms in ResUI.ru.resx.
New translations (9 existing + 2 added):
- TbAllowInsecureCertFetch, TbAllowInsecureCertFetchTips — insecure
certificate fetch checkbox and MITM warning tooltip
- TbHost — host field label
- TbSettingsDefUserAgentTips — updated transport list
(raw/http, ws, gRPC, xhttp)
- TbSettingsSendThrough, TbSettingsSendThroughTip,
FillCorrectSendThroughIPv4 — local outbound IPv4 setting
- TbSettingsUdpTestUrl, menuUdpTestServer — UDP test URL and menu item
- TransportExtra, TransportExtraTip — XHTTP Extra raw JSON
Terminology fixes:
- "V2ray" → "v2ray" (core name is lowercase by convention)
- "[Anytls]" → "[AnyTLS]" (canonical protocol spelling)
- "LAN порт" → "LAN-порт" (hyphen per Russian grammar)
All translations use canonical casing for protocols (VMess, VLESS,
Shadowsocks, Trojan, WireGuard, Hysteria, TUIC, AnyTLS), cores
(Xray, sing-box, mihomo, v2ray) and abbreviations (TLS, DNS, UUID,
HTTP, IPv4, MTU, TUN, PAC, SOCKS, gRPC, XHTTP).
---
v2rayN/ServiceLib/Resx/ResUI.ru.resx | 32 +++++++++++++++++-----------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index f394c23b..8f234843 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -673,7 +673,7 @@
Ядро: базовые настройки
- Пользовательский DNS для V2ray
+ Пользовательский DNS для v2ray
Ядро: настройки KCP
@@ -931,7 +931,7 @@
User-Agent
- This parameter is valid only for raw/http, ws, gRPC and xhttp
+ Параметр действует только для raw/http, ws, gRPC и xhttp
Шрифт (требуется перезапуск)
@@ -1318,7 +1318,7 @@
XHTTP-режим
- Raw JSON, format: { XHTTP Object }
+ Сырой JSON, формат: { XHTTP Object }
Сворачивать в трей при закрытии окна
@@ -1336,7 +1336,7 @@
Включить второй смешанный порт
- socks: локальный порт, socks2: второй локальный порт, socks3: LAN порт
+ socks: локальный порт, socks2: второй локальный порт, socks3: LAN-порт
Тема
@@ -1378,7 +1378,7 @@
Mldsa65Verify
- Добавить сервер [Anytls]
+ Добавить сервер [AnyTLS]
Удалённый DNS
@@ -1690,27 +1690,33 @@
Устаревшая защита TUN (Legacy Protect)
- For multi-interface environments, enter the local machine's IPv4 address
+ Для среды с несколькими сетевыми интерфейсами укажите IPv4-адрес локального компьютера
Камуфляжный домен
- Host
+ Хост
- XHTTP Extra
+ Дополнительные параметры XHTTP (Extra)
- Allow insecure cert fetch (self-signed)
+ Разрешить небезопасную загрузку сертификата (самоподписанного)
- Only for fetching self-signed certificates. This may expose you to MITM risks.
+ Только для загрузки самоподписанных сертификатов. Это может подвергнуть вас риску атаки «человек посередине» (MITM).
- Test Configurations UDP Delay
+ Тест UDP-задержки конфигураций
- UDP Test Url
+ URL для UDP-теста
-
\ No newline at end of file
+
+ Укажите корректный IPv4-адрес для SendThrough.
+
+
+ Локальный исходящий адрес (SendThrough)
+
+