diff --git a/v2rayN/ServiceLib/Common/ProcUtils.cs b/v2rayN/ServiceLib/Common/ProcUtils.cs index ce487c7a..3f5c31af 100644 --- a/v2rayN/ServiceLib/Common/ProcUtils.cs +++ b/v2rayN/ServiceLib/Common/ProcUtils.cs @@ -46,7 +46,7 @@ public static class ProcUtils return null; } - public static void RebootAsAdmin(bool blAdmin = true) + public static bool RebootAsAdmin(bool blAdmin = true) { try { @@ -58,11 +58,12 @@ public static class ProcUtils FileName = Utils.GetExePath().AppendQuotes(), Verb = blAdmin ? "runas" : null, }; - _ = Process.Start(startInfo); + return Process.Start(startInfo) != null; } catch (Exception ex) { Logging.SaveLog(_tag, ex); + return false; } } } diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index 35847d71..7354c305 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -144,10 +144,16 @@ public sealed class AppManager AppEvents.ShutdownRequested.Publish(byUser); } - public async Task RebootAsAdmin() + public async Task RebootAsAdmin() { - ProcUtils.RebootAsAdmin(); + var started = ProcUtils.RebootAsAdmin(); + if (!started) + { + return false; + } + await AppManager.Instance.AppExitAsync(true); + return true; } #endregion App diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 7a86761f..f422da96 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -345,6 +345,14 @@ public partial class CoreConfigSingboxService { try { + // The synthetic TUN relay outbound talks to the local Xray shadowsocks relay. + // Xray cannot terminate sing-box h2mux, so muxing here turns local relay traffic + // into sp.mux.sing-box.arpa pseudo-destinations and breaks DNS over TUN. + if (IsTunRelayProxyOutbound()) + { + return; + } + var muxEnabled = _node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty()) { @@ -364,6 +372,21 @@ public partial class CoreConfigSingboxService } } + private bool IsTunRelayProxyOutbound() + { + if (!context.IsTunEnabled + || _node.ConfigType != EConfigType.Shadowsocks + || _node.Address != Global.Loopback + || _node.Port != context.ProxyRelaySsPort + || _node.Password != Global.None) + { + return false; + } + + var protocolExtra = _node.GetProtocolExtra(); + return protocolExtra.SsMethod == Global.None; + } + private void FillOutboundTls(Outbound4Sbox outbound) { try diff --git a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs index b8154c16..aac51c5c 100644 --- a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs @@ -469,31 +469,40 @@ public class StatusBarViewModel : MyReactiveObject return; } - _config.TunModeItem.EnableTun = EnableTun; - - if (EnableTun && AllowEnableTun() == false) + var allowEnableTun = AllowEnableTun(); + if (PrepareTunConfigForPrivilegeEscalation(_config, EnableTun, allowEnableTun, Utils.IsWindows())) { - // When running as a non-administrator, reboot to administrator mode - if (Utils.IsWindows()) + await ConfigHandler.SaveConfig(_config); + if (!await AppManager.Instance.RebootAsAdmin()) + { + _config.TunModeItem.EnableTun = false; + EnableTun = false; + await ConfigHandler.SaveConfig(_config); + NoticeManager.Instance.SendMessageEx(ResUI.OperationFailed); + } + return; + } + + if (EnableTun && !allowEnableTun) + { + bool? passwordResult = await _updateView?.Invoke(EViewAction.PasswordInput, null); + if (passwordResult == false) { _config.TunModeItem.EnableTun = false; - await AppManager.Instance.RebootAsAdmin(); return; } - else - { - bool? passwordResult = await _updateView?.Invoke(EViewAction.PasswordInput, null); - if (passwordResult == false) - { - _config.TunModeItem.EnableTun = false; - return; - } - } } + await ConfigHandler.SaveConfig(_config); AppEvents.ReloadRequested.Publish(); } + private static bool PrepareTunConfigForPrivilegeEscalation(Config config, bool enableTun, bool allowEnableTun, bool isWindows) + { + config.TunModeItem.EnableTun = enableTun; + return enableTun && !allowEnableTun && isWindows; + } + private bool AllowEnableTun() { if (Utils.IsWindows())