From 0032a3d27af7d91010233bed494105120f0cff5b Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:36:28 +0800 Subject: [PATCH 1/6] Fix kill process for linux --- v2rayN/ServiceLib/Handler/CoreHandler.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs index 499d8999..a2f24df8 100644 --- a/v2rayN/ServiceLib/Handler/CoreHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs @@ -155,6 +155,12 @@ public class CoreHandler { try { + if (_linuxSudoPid > 0) + { + await KillProcessAsLinuxSudo(); + _linuxSudoPid = -1; + } + if (_process != null) { await ProcUtils.ProcessKill(_process, true); @@ -166,12 +172,6 @@ public class CoreHandler await ProcUtils.ProcessKill(_processPre, true); _processPre = null; } - - if (_linuxSudoPid > 0) - { - await KillProcessAsLinuxSudo(); - } - _linuxSudoPid = -1; } catch (Exception ex) { @@ -390,7 +390,7 @@ public class CoreHandler await File.WriteAllTextAsync(shFilePath, sb.ToString()); await Utils.SetLinuxChmod(shFilePath); - Logging.SaveLog(shFilePath); + //Logging.SaveLog(shFilePath); return shFilePath; } From adf3b955d6a4546425fabbc99e1fce2955bd4840 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 26 Apr 2025 09:50:31 +0800 Subject: [PATCH 2/6] Refactor Linux to run Tun as sudo --- v2rayN/ServiceLib/Handler/AppHandler.cs | 9 -- v2rayN/ServiceLib/Handler/CoreAdminHandler.cs | 144 ++++++++++++++++++ v2rayN/ServiceLib/Handler/CoreHandler.cs | 136 +++-------------- .../ViewModels/StatusBarViewModel.cs | 2 +- .../v2rayN.Desktop/Views/MainWindow.axaml.cs | 2 +- v2rayN/v2rayN/Views/MainWindow.xaml.cs | 2 +- 6 files changed, 171 insertions(+), 124 deletions(-) create mode 100644 v2rayN/ServiceLib/Handler/CoreAdminHandler.cs diff --git a/v2rayN/ServiceLib/Handler/AppHandler.cs b/v2rayN/ServiceLib/Handler/AppHandler.cs index 3f9fdf74..906e2ba3 100644 --- a/v2rayN/ServiceLib/Handler/AppHandler.cs +++ b/v2rayN/ServiceLib/Handler/AppHandler.cs @@ -31,15 +31,6 @@ public sealed class AppHandler } } - public bool IsAdministrator - { - get - { - _isAdministrator ??= Utils.IsAdministrator(); - return _isAdministrator.Value; - } - } - public string LinuxSudoPwd { get; set; } #endregion Property diff --git a/v2rayN/ServiceLib/Handler/CoreAdminHandler.cs b/v2rayN/ServiceLib/Handler/CoreAdminHandler.cs new file mode 100644 index 00000000..85d90fc3 --- /dev/null +++ b/v2rayN/ServiceLib/Handler/CoreAdminHandler.cs @@ -0,0 +1,144 @@ +using System.Diagnostics; +using System.Text; +using CliWrap; + +namespace ServiceLib.Handler; + +public class CoreAdminHandler +{ + private static readonly Lazy _instance = new(() => new()); + public static CoreAdminHandler Instance => _instance.Value; + private Config _config; + private Action? _updateFunc; + private const string _tag = "CoreAdminHandler"; + private int _linuxSudoPid = -1; + + public async Task Init(Config config, Action updateFunc) + { + if (_config != null) + { + return; + } + _config = config; + _updateFunc = updateFunc; + } + + private void UpdateFunc(bool notify, string msg) + { + _updateFunc?.Invoke(notify, msg); + } + + public async Task RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath) + { + try + { + var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}"; + var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh"); + + Process proc = new() + { + StartInfo = new() + { + FileName = shFilePath, + Arguments = "", + WorkingDirectory = Utils.GetBinConfigPath(), + UseShellExecute = false, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardInputEncoding = Encoding.UTF8, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + } + }; + + proc.OutputDataReceived += (sender, e) => + { + if (e.Data.IsNotEmpty()) + { + UpdateFunc(false, e.Data + Environment.NewLine); + } + }; + proc.ErrorDataReceived += (sender, e) => + { + if (e.Data.IsNotEmpty()) + { + UpdateFunc(false, e.Data + Environment.NewLine); + } + }; + + proc.Start(); + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); + + await Task.Delay(10); + await proc.StandardInput.WriteLineAsync(); + await Task.Delay(10); + await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd); + + await Task.Delay(100); + if (proc is null or { HasExited: true }) + { + throw new Exception(ResUI.FailedToRunCore); + } + + _linuxSudoPid = proc.Id; + + return proc; + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + UpdateFunc(false, ex.Message); + return null; + } + } + + public async Task KillProcessAsLinuxSudo() + { + if (_linuxSudoPid < 0) + { + return; + } + + try + { + var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}"; + var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh"); + + var result = await Cli.Wrap(shFilePath) + .WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd)) + .ExecuteAsync(); + + _linuxSudoPid = -1; + } + catch (Exception ex) + { + Logging.SaveLog(_tag, ex); + UpdateFunc(false, ex.Message); + } + } + + private async Task CreateLinuxShellFile(string cmdLine, string fileName) + { + var shFilePath = Utils.GetBinConfigPath(fileName); + File.Delete(shFilePath); + + var sb = new StringBuilder(); + sb.AppendLine("#!/bin/sh"); + if (Utils.IsAdministrator()) + { + sb.AppendLine($"{cmdLine}"); + } + else + { + sb.AppendLine($"sudo -S {cmdLine}"); + } + + await File.WriteAllTextAsync(shFilePath, sb.ToString()); + await Utils.SetLinuxChmod(shFilePath); + + return shFilePath; + } +} diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs index a2f24df8..97918693 100644 --- a/v2rayN/ServiceLib/Handler/CoreHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs @@ -13,7 +13,7 @@ public class CoreHandler private Config _config; private Process? _process; private Process? _processPre; - private int _linuxSudoPid = -1; + private bool _linuxSudo = false; private Action? _updateFunc; private const string _tag = "CoreHandler"; @@ -155,21 +155,21 @@ public class CoreHandler { try { - if (_linuxSudoPid > 0) + if (_linuxSudo) { - await KillProcessAsLinuxSudo(); - _linuxSudoPid = -1; + await CoreAdminHandler.Instance.KillProcessAsLinuxSudo(); + _linuxSudo = false; } if (_process != null) { - await ProcUtils.ProcessKill(_process, true); + await ProcUtils.ProcessKill(_process, Utils.IsWindows()); _process = null; } if (_processPre != null) { - await ProcUtils.ProcessKill(_processPre, true); + await ProcUtils.ProcessKill(_processPre, Utils.IsWindows()); _processPre = null; } } @@ -225,13 +225,6 @@ public class CoreHandler _updateFunc?.Invoke(notify, msg); } - private bool IsNeedSudo(ECoreType eCoreType) - { - return _config.TunModeItem.EnableTun - && eCoreType == ECoreType.sing_box - && Utils.IsNonWindows(); - } - #endregion Private #region Process @@ -245,6 +238,16 @@ public class CoreHandler return null; } + if (mayNeedSudo + && _config.TunModeItem.EnableTun + && coreInfo.CoreType == ECoreType.sing_box + && Utils.IsNonWindows()) + { + _linuxSudo = true; + await CoreAdminHandler.Instance.Init(_config, _updateFunc); + return await CoreAdminHandler.Instance.RunProcessAsLinuxSudo(fileName, coreInfo, configPath); + } + try { Process proc = new() @@ -263,38 +266,25 @@ public class CoreHandler } }; - var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType); - if (isNeedSudo) - { - await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath); - } - if (displayLog) { proc.OutputDataReceived += (sender, e) => { - if (e.Data.IsNullOrEmpty()) - return; - UpdateFunc(false, e.Data + Environment.NewLine); + if (e.Data.IsNotEmpty()) + { + UpdateFunc(false, e.Data + Environment.NewLine); + } }; proc.ErrorDataReceived += (sender, e) => { - if (e.Data.IsNullOrEmpty()) - return; - UpdateFunc(false, e.Data + Environment.NewLine); + if (e.Data.IsNotEmpty()) + { + UpdateFunc(false, e.Data + Environment.NewLine); + } }; } proc.Start(); - if (isNeedSudo && AppHandler.Instance.LinuxSudoPwd.IsNotEmpty()) - { - await proc.StandardInput.WriteLineAsync(); - await Task.Delay(10); - await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd); - } - if (isNeedSudo) - _linuxSudoPid = proc.Id; - if (displayLog) { proc.BeginOutputReadLine(); @@ -318,82 +308,4 @@ public class CoreHandler } #endregion Process - - #region Linux - - private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath) - { - var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}"; - - var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh"); - proc.StartInfo.FileName = shFilePath; - proc.StartInfo.Arguments = ""; - proc.StartInfo.WorkingDirectory = ""; - if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty()) - { - proc.StartInfo.StandardInputEncoding = Encoding.UTF8; - proc.StartInfo.RedirectStandardInput = true; - } - } - - private async Task KillProcessAsLinuxSudo() - { - var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}"; - var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh"); - Process proc = new() - { - StartInfo = new() - { - FileName = shFilePath, - UseShellExecute = false, - CreateNoWindow = true, - StandardInputEncoding = Encoding.UTF8, - RedirectStandardInput = true - } - }; - proc.Start(); - - if (AppHandler.Instance.LinuxSudoPwd.IsNotEmpty()) - { - try - { - await proc.StandardInput.WriteLineAsync(); - await Task.Delay(10); - await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd); - } - catch (Exception) - { - // ignored - } - } - - var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - await proc.WaitForExitAsync(timeout.Token); - await Task.Delay(1000); - } - - private async Task CreateLinuxShellFile(string cmdLine, string fileName) - { - //Shell scripts - var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName); - File.Delete(shFilePath); - var sb = new StringBuilder(); - sb.AppendLine("#!/bin/sh"); - if (AppHandler.Instance.IsAdministrator) - { - sb.AppendLine($"{cmdLine}"); - } - else - { - sb.AppendLine($"sudo -S {cmdLine}"); - } - - await File.WriteAllTextAsync(shFilePath, sb.ToString()); - await Utils.SetLinuxChmod(shFilePath); - //Logging.SaveLog(shFilePath); - - return shFilePath; - } - - #endregion Linux } diff --git a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs index ec6ec39e..2c48d0bf 100644 --- a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs @@ -454,7 +454,7 @@ public class StatusBarViewModel : MyReactiveObject { if (Utils.IsWindows()) { - return AppHandler.Instance.IsAdministrator; + return Utils.IsAdministrator(); } else if (Utils.IsLinux()) { diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 91328046..34852a50 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -143,7 +143,7 @@ public partial class MainWindow : ReactiveWindow } else { - if (AppHandler.Instance.IsAdministrator) + if (Utils.IsAdministrator()) { this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}"; NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp); diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index b837f65c..b3869cae 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -132,7 +132,7 @@ public partial class MainWindow } }); - this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; + this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; if (!_config.GuiItem.EnableHWA) { From 1c04144573cd2e57df137cbf42f9b33d6626bc24 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 26 Apr 2025 09:53:19 +0800 Subject: [PATCH 3/6] Code clean --- .../Views/StatusBarView.axaml.cs | 1 - v2rayN/v2rayN/App.xaml | 2 +- v2rayN/v2rayN/Views/MainWindow.xaml | 47 ++++++++++-------- v2rayN/v2rayN/Views/ProfilesView.xaml | 16 +++--- .../Views/RoutingRuleDetailsWindow.xaml | 6 +-- .../Views/RoutingRuleSettingWindow.xaml | 6 +-- v2rayN/v2rayN/Views/StatusBarView.xaml | 49 ++++++++++++------- v2rayN/v2rayN/Views/SubEditWindow.xaml | 6 +-- v2rayN/v2rayN/Views/SubSettingWindow.xaml | 6 +-- v2rayN/v2rayN/Views/ThemeSettingView.xaml | 4 +- 10 files changed, 80 insertions(+), 63 deletions(-) diff --git a/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs index 3c44e2d4..b646b5d6 100644 --- a/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs @@ -8,7 +8,6 @@ using DialogHostAvalonia; using ReactiveUI; using Splat; using v2rayN.Desktop.Common; -using static QRCoder.PayloadGenerator; namespace v2rayN.Desktop.Views; diff --git a/v2rayN/v2rayN/App.xaml b/v2rayN/v2rayN/App.xaml index 2be80ccb..49a31268 100644 --- a/v2rayN/v2rayN/App.xaml +++ b/v2rayN/v2rayN/App.xaml @@ -1,9 +1,9 @@ diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 6c233ef4..ea2cbe2d 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -1,14 +1,14 @@ - + - + - + - + - + - + - + - + + ToolTip="{x:Static resx:ResUI.menuSubEdit}"> @@ -61,9 +61,9 @@ Width="30" Height="30" Margin="{StaticResource MarginLeftRight8}" + AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}" - ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}" - AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"> + ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"> + AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}" + Style="{StaticResource DefTextBox}" /> + VerticalAlignment="Center" + AutomationProperties.Name="{x:Static resx:ResUI.TbEnableTunAs}" /> + Style="{StaticResource MaterialDesignFloatingHintComboBox}"> @@ -88,10 +89,10 @@ Width="160" Margin="{StaticResource MarginLeftRight8}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}" + AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}" DisplayMemberPath="Remarks" FontSize="{DynamicResource StdFontSize}" - Style="{StaticResource MaterialDesignFloatingHintComboBox}" - AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}"/> + Style="{StaticResource MaterialDesignFloatingHintComboBox}" /> @@ -109,8 +110,10 @@ ToolTipText="v2rayN"> - + - + - + - + - + + Style="{StaticResource MaterialDesignFilledComboBox}" /> @@ -184,10 +195,10 @@ x:Name="cmbServers" MaxWidth="300" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}" + AutomationProperties.Name="{x:Static resx:ResUI.menuServers}" DisplayMemberPath="Text" FontSize="{DynamicResource StdFontSize}" - Style="{StaticResource MaterialDesignFilledComboBox}" - AutomationProperties.Name="{x:Static resx:ResUI.menuServers}"/> + Style="{StaticResource MaterialDesignFilledComboBox}" /> diff --git a/v2rayN/v2rayN/Views/SubEditWindow.xaml b/v2rayN/v2rayN/Views/SubEditWindow.xaml index c7cd0ea1..4d33cb11 100644 --- a/v2rayN/v2rayN/Views/SubEditWindow.xaml +++ b/v2rayN/v2rayN/Views/SubEditWindow.xaml @@ -1,11 +1,11 @@ Date: Sat, 26 Apr 2025 06:00:05 +0330 Subject: [PATCH 4/6] Update Persian translation (#7191) https://github.com/2dust/v2rayN/commit/0032a3d27af7d91010233bed494105120f0cff5b --- v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index adf4eb0e..adb95f2c 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1339,7 +1339,7 @@ رمز عبور sudo سیستم - The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart. + رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید. لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید @@ -1416,4 +1416,4 @@ صادر کردن سرور - \ No newline at end of file + From be3dbfb8e3c2635c981b8f66a58aa6c12d9a9d7e Mon Sep 17 00:00:00 2001 From: Reza Bakhshi Laktasaraei <74649066+rezabakhshilaktasaraei@users.noreply.github.com> Date: Sat, 26 Apr 2025 06:01:00 +0330 Subject: [PATCH 5/6] Fix Tab navigation in ToolBar by setting KeyboardNavigation to Continue (#7185) --- v2rayN/v2rayN/Views/MainWindow.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index ea2cbe2d..925d1f84 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -40,7 +40,8 @@ HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="True" - Style="{StaticResource MaterialDesignToolBar}"> + Style="{StaticResource MaterialDesignToolBar}" + KeyboardNavigation.TabNavigation="Continue"> From 30f7f2c56382f9e5e118bf6c8b4cfb91455e9e8c Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:32:20 +0800 Subject: [PATCH 6/6] Update Directory.Packages.props --- v2rayN/Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2rayN/Directory.Packages.props b/v2rayN/Directory.Packages.props index b269cbe7..5777d1bb 100644 --- a/v2rayN/Directory.Packages.props +++ b/v2rayN/Directory.Packages.props @@ -18,8 +18,8 @@ - - + +