diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index 81b46ac6..c64b7402 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -4014,24 +4014,6 @@ namespace ServiceLib.Resx {
}
}
- ///
- /// 查找类似 Local outbound address (SendThrough) 的本地化字符串。
- ///
- public static string TbSettingsSendThrough {
- get {
- return ResourceManager.GetString("TbSettingsSendThrough", resourceCulture);
- }
- }
-
- ///
- /// 查找类似 Only applies to Xray. Fill in a local IPv4 address; leave empty to disable. 的本地化字符串。
- ///
- public static string TbSettingsSendThroughTip {
- get {
- return ResourceManager.GetString("TbSettingsSendThroughTip", resourceCulture);
- }
- }
-
///
/// 查找类似 Enable Log 的本地化字符串。
///
@@ -4176,6 +4158,24 @@ namespace ServiceLib.Resx {
}
}
+ ///
+ /// 查找类似 Local outbound address (SendThrough) 的本地化字符串。
+ ///
+ public static string TbSettingsSendThrough {
+ get {
+ return ResourceManager.GetString("TbSettingsSendThrough", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 For multi-interface environments, enter the local machine's IPv4 address 的本地化字符串。
+ ///
+ public static string TbSettingsSendThroughTip {
+ get {
+ return ResourceManager.GetString("TbSettingsSendThroughTip", resourceCulture);
+ }
+ }
+
///
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
///
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index 61ccbf7b..56e7bd5c 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -1698,4 +1698,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
Legacy TUN Protect
+
+ For multi-interface environments, enter the local machine's IPv4 address
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
index d466eedd..9e81a7c9 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
@@ -1695,4 +1695,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
Legacy TUN Protect
+
+ For multi-interface environments, enter the local machine's IPv4 address
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index 89456f99..8f64e04b 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -1698,4 +1698,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
Legacy TUN Protect
+
+ For multi-interface environments, enter the local machine's IPv4 address
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index fbab6252..3b21ec73 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -1324,7 +1324,7 @@
Local outbound address (SendThrough)
- Only applies to Xray. Fill in a local IPv4 address; leave empty to disable.
+ For multi-interface environments, enter the local machine's IPv4 address
Please fill in the correct IPv4 address for SendThrough.
@@ -1707,4 +1707,4 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
Legacy TUN Protect
-
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index 9c6ff77e..86a613c3 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -1698,4 +1698,7 @@
Устаревшая защита TUN (Legacy Protect)
-
+
+ For multi-interface environments, enter the local machine's IPv4 address
+
+
\ 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 8416287e..36e5efc0 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -1321,7 +1321,7 @@
本地出站地址 (SendThrough)
- 仅对 Xray 生效,填写本机 IPv4;留空则不设置。
+ 用于多网口环境,请填写本机 IPv4 地址
请填写正确的 SendThrough IPv4 地址。
@@ -1704,4 +1704,4 @@
旧版 TUN 保护
-
+
\ 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 59a9fc9f..be707759 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -1695,4 +1695,7 @@
Legacy TUN Protect
+
+ For multi-interface environments, enter the local machine's IPv4 address
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs
index 4f0203af..f0a4f0ef 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs
@@ -57,6 +57,8 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
ConvertGeo2Ruleset();
+ ApplyOutboundSendThrough();
+
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
@@ -221,6 +223,7 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
_coreConfig.route.rules.Add(rule);
}
+ ApplyOutboundSendThrough();
ret.Success = true;
ret.Data = JsonUtils.Serialize(_coreConfig);
return ret;
@@ -279,6 +282,7 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
listen_port = port,
type = EInboundProtocol.mixed.ToString(),
});
+ ApplyOutboundSendThrough();
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs
index 25b29701..d20aec1c 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs
@@ -58,4 +58,40 @@ public partial class CoreConfigSingboxService
return JsonUtils.Serialize(fullConfigTemplateNode);
}
+
+ private void ApplyOutboundSendThrough()
+ {
+ var sendThrough = _config.CoreBasicItem.SendThrough?.TrimEx();
+ foreach (var outbound in _coreConfig.outbounds ?? [])
+ {
+ outbound.inet4_bind_address = ShouldApplySendThrough(outbound, sendThrough) ? sendThrough : null;
+ }
+ }
+
+ private static bool ShouldApplySendThrough(Outbound4Sbox outbound, string? sendThrough)
+ {
+ if (sendThrough.IsNullOrEmpty())
+ {
+ return false;
+ }
+
+ if (outbound.type is "direct" or "block" or "dns" or "selector" or "urltest")
+ {
+ return false;
+ }
+
+ if (!outbound.detour.IsNullOrEmpty())
+ {
+ return false;
+ }
+
+ var outboundAddress = outbound.server ?? string.Empty;
+
+ if (outboundAddress.Equals("localhost", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return !IPAddress.TryParse(outboundAddress, out var address) || !IPAddress.IsLoopback(address);
+ }
}
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs
index 1e72de41..fb8d92a7 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs
@@ -407,43 +407,4 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
}
#endregion public gen function
-
- private void ApplyOutboundSendThrough()
- {
- var sendThrough = _config.CoreBasicItem.SendThrough?.TrimEx();
- foreach (var outbound in _coreConfig.outbounds ?? [])
- {
- outbound.sendThrough = ShouldApplySendThrough(outbound, sendThrough) ? sendThrough : null;
- }
- }
-
- private static bool ShouldApplySendThrough(Outbounds4Ray outbound, string? sendThrough)
- {
- if (sendThrough.IsNullOrEmpty())
- {
- return false;
- }
-
- if (outbound.protocol is "freedom" or "blackhole" or "dns" or "loopback")
- {
- return false;
- }
-
- if (outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == false)
- {
- return false;
- }
-
- var outboundAddress = outbound.settings?.servers?.FirstOrDefault()?.address
- ?? outbound.settings?.vnext?.FirstOrDefault()?.address
- ?? outbound.settings?.address?.ToString()
- ?? string.Empty;
-
- if (outboundAddress.Equals("localhost", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- return !IPAddress.TryParse(outboundAddress, out var address) || !IPAddress.IsLoopback(address);
- }
}
diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs
index db7c3f32..6e563f0f 100644
--- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs
+++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayConfigTemplateService.cs
@@ -127,4 +127,43 @@ public partial class CoreConfigV2rayService
return JsonUtils.Serialize(fullConfigTemplateNode);
}
+
+ private void ApplyOutboundSendThrough()
+ {
+ var sendThrough = _config.CoreBasicItem.SendThrough?.TrimEx();
+ foreach (var outbound in _coreConfig.outbounds ?? [])
+ {
+ outbound.sendThrough = ShouldApplySendThrough(outbound, sendThrough) ? sendThrough : null;
+ }
+ }
+
+ private static bool ShouldApplySendThrough(Outbounds4Ray outbound, string? sendThrough)
+ {
+ if (sendThrough.IsNullOrEmpty())
+ {
+ return false;
+ }
+
+ if (outbound.protocol is "freedom" or "blackhole" or "dns" or "loopback")
+ {
+ return false;
+ }
+
+ if (outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == false)
+ {
+ return false;
+ }
+
+ var outboundAddress = outbound.settings?.servers?.FirstOrDefault()?.address
+ ?? outbound.settings?.vnext?.FirstOrDefault()?.address
+ ?? outbound.settings?.address?.ToString()
+ ?? string.Empty;
+
+ if (outboundAddress.Equals("localhost", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return !IPAddress.TryParse(outboundAddress, out var address) || !IPAddress.IsLoopback(address);
+ }
}
diff --git a/v2rayN/v2rayN.slnx b/v2rayN/v2rayN.slnx
index 1550478b..4042dad1 100644
--- a/v2rayN/v2rayN.slnx
+++ b/v2rayN/v2rayN.slnx
@@ -16,6 +16,7 @@
+