Browse Source

Use tun mode without running with sudo in linux

pull/6079/head
2dust 1 week ago
parent
commit
9d638968a9
  1. 47
      v2rayN/ServiceLib/Handler/CoreHandler.cs
  2. 1
      v2rayN/ServiceLib/Models/ConfigItems.cs
  3. 36
      v2rayN/ServiceLib/Resx/ResUI.Designer.cs
  4. 12
      v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
  5. 12
      v2rayN/ServiceLib/Resx/ResUI.resx
  6. 12
      v2rayN/ServiceLib/Resx/ResUI.ru.resx
  7. 12
      v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
  8. 12
      v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
  9. 2
      v2rayN/ServiceLib/ServiceLib.csproj
  10. 3
      v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs
  11. 26
      v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs
  12. 6
      v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs
  13. 23
      v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
  14. 1
      v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs
  15. 2
      v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs

47
v2rayN/ServiceLib/Handler/CoreHandler.cs

@ -68,6 +68,7 @@ namespace ServiceLib.Handler
{
ShowMsg(true, $"{node.GetSummary()}");
await CoreStop();
await Task.Delay(100);
await CoreStart(node);
//In tun mode, do a delay check and restart the core
@ -169,21 +170,12 @@ namespace ServiceLib.Handler
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
//ECoreType coreType;
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
//{
// coreType = ECoreType.sing_box;
//}
//else
//{
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
//}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog);
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null)
{
return;
@ -225,7 +217,7 @@ namespace ServiceLib.Handler
if (result.Success)
{
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = await RunProcess(coreInfo2, Global.CorePreConfigFileName, true);
var proc2 = await RunProcess(coreInfo2, Global.CorePreConfigFileName, true, true);
if (proc2 is not null)
{
_processPre = proc2;
@ -243,7 +235,7 @@ namespace ServiceLib.Handler
try
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true);
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
if (proc is null)
{
return -1;
@ -264,17 +256,28 @@ namespace ServiceLib.Handler
_updateFunc?.Invoke(notify, msg);
}
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& Utils.IsLinux()
&& _config.TunModeItem.LinuxSudoPassword.IsNotEmpty()
;
}
#endregion Private
#region Process
private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog)
private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{
var fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
try
{
Process proc = new()
@ -292,6 +295,15 @@ namespace ServiceLib.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
if (isNeedSudo)
{
proc.StartInfo.FileName = $"/bin/sudo";
proc.StartInfo.Arguments = $"-S {fileName} {string.Format(coreInfo.Arguments, configPath)}";
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
}
var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false;
if (displayLog)
@ -313,6 +325,15 @@ namespace ServiceLib.Handler
};
}
proc.Start();
if (isNeedSudo)
{
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(_config.TunModeItem.LinuxSudoPassword);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(_config.TunModeItem.LinuxSudoPassword);
}
if (displayLog)
{
proc.BeginOutputReadLine();

1
v2rayN/ServiceLib/Models/ConfigItems.cs

@ -161,6 +161,7 @@
public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPassword { get; set; }
}
[Serializable]

36
v2rayN/ServiceLib/Resx/ResUI.Designer.cs generated

@ -3148,6 +3148,42 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Linux system sudo password 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPassword {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPassword", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordIsEmpty {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
}
}
/// <summary>
/// 查找类似 The password will only be stored in the local file. 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordTip {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable Log 的本地化字符串。
/// </summary>

12
v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx

@ -1369,4 +1369,16 @@
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will only be stored in the local file.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
</root>

12
v2rayN/ServiceLib/Resx/ResUI.resx

@ -1369,4 +1369,16 @@
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will only be stored in the local file.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
</root>

12
v2rayN/ServiceLib/Resx/ResUI.ru.resx

@ -1369,4 +1369,16 @@
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will only be stored in the local file.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
</root>

12
v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx

@ -1366,4 +1366,16 @@
<data name="LvMemo" xml:space="preserve">
<value>备注备忘</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux系统的sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码只会存储在本地文件中,没有密码无法开启Tun</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>请不要用sudo运行本app</value>
</data>
</root>

12
v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx

@ -1366,4 +1366,16 @@
<data name="TbPath7" xml:space="preserve">
<value>混淆密碼(obfs password)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux系統的sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼只會儲存在本機檔案中,沒有密碼無法開啟Tun</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>請不要用sudo來運行本app</value>
</data>
</root>

2
v2rayN/ServiceLib/ServiceLib.csproj

@ -14,7 +14,7 @@
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="Splat.NLog" Version="15.2.22" />
<PackageReference Include="WebDav.Client" Version="2.8.0" />
<PackageReference Include="YamlDotNet" Version="16.1.3" />
<PackageReference Include="YamlDotNet" Version="16.2.0" />
<PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="CliWrap" Version="3.6.7" />
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />

3
v2rayN/ServiceLib/ViewModels/OptionSettingViewModel.cs

@ -85,6 +85,7 @@ namespace ServiceLib.ViewModels
[Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; }
[Reactive] public string TunLinuxSudoPassword { get; set; }
#endregion Tun mode
@ -197,6 +198,7 @@ namespace ServiceLib.ViewModels
TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPassword;
#endregion Tun mode
@ -340,6 +342,7 @@ namespace ServiceLib.ViewModels
_config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
_config.TunModeItem.LinuxSudoPassword = TunLinuxSudoPassword;
//coreType
await SaveCoreType();

26
v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs

@ -108,7 +108,7 @@ namespace ServiceLib.ViewModels
SelectedServer = new();
RunningServerToolTipText = "-";
if (_config.TunModeItem.EnableTun && AppHandler.Instance.IsAdministrator)
if (_config.TunModeItem.EnableTun && AllowEnableTun())
{
EnableTun = true;
}
@ -414,10 +414,17 @@ namespace ServiceLib.ViewModels
{
_config.TunModeItem.EnableTun = EnableTun;
// When running as a non-administrator, reboot to administrator mode
if (EnableTun && !AppHandler.Instance.IsAdministrator)
if (EnableTun && AllowEnableTun() == false)
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
if (Utils.IsWindows())
{
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
}
else if (Utils.IsLinux())
{
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
}
return;
}
await ConfigHandler.SaveConfig(_config);
@ -425,6 +432,19 @@ namespace ServiceLib.ViewModels
}
}
private bool AllowEnableTun()
{
if (Utils.IsWindows())
{
return AppHandler.Instance.IsAdministrator;
}
else if (Utils.IsLinux())
{
return _config.TunModeItem.LinuxSudoPassword.IsNotEmpty();
}
return false;
}
#endregion System proxy and Routings
#region UI

6
v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs

@ -117,6 +117,11 @@ namespace v2rayN.Desktop.Views
}
else
{
if (AppHandler.Instance.IsAdministrator)
{
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
}
menuRebootAsAdmin.IsVisible = false;
menuSettingsSetUWP.IsVisible = false;
menuGlobalHotkeySetting.IsVisible = false;
@ -282,6 +287,7 @@ namespace v2rayN.Desktop.Views
e.Cancel = true;
ShowHideWindow(false);
break;
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
await ViewModel?.MyAppExitAsync(true);
break;

23
v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml

@ -721,6 +721,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@ -794,6 +795,28 @@
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
<TextBox
x:Name="txtLinuxSudoPassword"
Grid.Row="7"
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8"
PasswordChar="*" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
TextWrapping="Wrap" />
</Grid>
</DockPanel>
</TabItem>

1
v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs

@ -152,6 +152,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);

2
v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs

@ -41,7 +41,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables);
});
spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
//spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
}
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

Loading…
Cancel
Save