我做了一些尝试:包括:检测nixos的环境,检测系统配置下的特权文件.
然后卡在了这里:
Plugins.cs
private static bool IsNixOS()
{
if (_isNixOS.HasValue)
return _isNixOS.Value;
try
{
if (File.Exists("/etc/os-release"))
{
var osRelease = File.ReadAllText("/etc/os-release");
if (osRelease.Contains("ID=nixos", StringComparison.OrdinalIgnoreCase))
{
_isNixOS = true;
return true;
}
}
var nixStoreDir = new DirectoryInfo("/nix/store");
if (nixStoreDir.Exists && nixStoreDir.GetDirectories().Any(d => d.Name.Length > 30 && d.Name.Contains("-")))
{
_isNixOS = true;
return true;
}
}
catch { }
_isNixOS = false;
return false;
}
internal string? SubProcessPath
{
get
{
if (subProcessPath == null)
{
try
{
subProcessPath = Assembly.GetExecutingAssembly().Location;
subProcessPath = Path.GetDirectoryName(subProcessPath);
subProcessPath.ThrowIsNull();
const string fileName = $"Steam++.{moduleName}";
var subProcessFileName = OperatingSystem.IsWindows() ? $"{fileName}{FileEx.EXE}" : fileName;
// NixOS 环境下优先使用 security.wrappers
if (OperatingSystem.IsLinux() && IsNixOS())
{
var wrapperName = "steampp-accelerator";
var wrapperPath = Path.Combine("/run/wrappers/bin", wrapperName);
Log.Info(nameof(Plugin), "NixOS detected, checking wrapper: {path}", wrapperPath);
Log.Info(nameof(Plugin), "Wrapper exists: {exists}", File.Exists(wrapperPath));
if (File.Exists(wrapperPath))
{
Log.Info(nameof(Plugin), "Using NixOS wrapper: {path}", wrapperPath);
subProcessPath = wrapperPath;
return subProcessPath;
}
else
{
Log.Warn(nameof(Plugin), "NixOS detected but wrapper not found ({path}), falling back to default path", wrapperPath);
}
}
subProcessPath = Path.Combine(subProcessPath, subProcessFileName);
Log.Info(nameof(Plugin), "Using default subprocess path: {path}", subProcessPath);
Log.Info(nameof(Plugin), "Default subprocess exists: {exists}", File.Exists(subProcessPath));
return subProcessPath;
#if DEBUG
if (!File.Exists(subProcessPath))
{
subProcessPath = Path.Combine(ProjectUtils.ProjPath, "src", "BD.WTTS.Client.Plugins.Accelerator.ReverseProxy", "bin", "Debug", $"net{Environment.Version.Major}.{Environment.Version.Minor}", subProcessFileName);
}
#endif
return subProcessPath;
}
catch (Exception ex)
{
Log.Error(nameof(Plugin), ex, "Error getting SubProcessPath");
subProcessPath = string.Empty;
}
}
return subProcessPath;
}
}
public override async ValueTask OnInitializeAsync()
{
var ipc = IPCMainProcessService.Instance;
// 启动加速模块子进程
await ipc.AddDaemonWithStartSubProcessAsync(moduleName, async ipc =>
{
var subProcessPath = SubProcessPath;
// 在 NixOS 上,如果我们检测到这是一个设置了 capabilities 的 wrapper,
// 我们需要处理 .NET App Host 与 capabilities 的兼容性问题
// bool isAdminRequired = !(OperatingSystem.IsLinux() && IsNixOS());
bool isAdminRequired = false;
Log.Info(nameof(Plugin), "Starting subprocess: {path}, admin required: {isAdminRequired}",
subProcessPath, isAdminRequired);
// 尝试启动子进程
Process? process = null;
try
{
process = await ipc.StartSubProcessAsync(subProcessPath.ThrowIsNull(),
isAdministrator: isAdminRequired);
}
catch (Exception ex)
{
Log.Error(nameof(Plugin), ex, "Failed to start subprocess, trying fallback method");
// 如果直接启动失败,尝试其他方法
if (OperatingSystem.IsLinux() && IsNixOS())
{
// 尝试使用不同的启动方式
var psi = new ProcessStartInfo
{
FileName = subProcessPath,
UseShellExecute = false,
CreateNoWindow = true,
Arguments = "" // 可能需要传递一些参数
};
// 添加必要的环境变量
psi.Environment["DOTNET_ROOT"] = Environment.GetEnvironmentVariable("DOTNET_ROOT");
try
{
process = Process.Start(psi);
}
catch (Exception ex2)
{
Log.Error(nameof(Plugin), ex2, "Fallback method also failed");
throw;
}
}
else
{
throw;
}
}
return process;
});
}
当检测到文件后 就直接报错:failed to inherit capabilities: Operation not permitted.此时我已经在系统下配置了
security.wrappers.steampp-accelerator = {
owner = "root";
group = "root";
capabilities = "cap_net_bind_service,cap_net_raw,cap_net_admin=+ep";
source = "${pkgs.SteamTools-my}/bin/modules/Accelerator/Steam++.Accelerator";
};
这个文件也确实有:
/run/wrappers/bin/steampp-accelerator
然后
我在SteamTools/src/BD.WTTS.Client.Plugins.Accelerator/Services/Mvvm/ProxyService.Operate.cs
下添加了
if (startProxyResult)
{
switch (proxyMode)
{
case ProxyMode.Hosts: // 启动加速服务后修改 Hosts 文件
if (proxyDomains.Any_Nullable())
{
var localhost = IPAddress.Any.Equals(proxyIp_.Value) ?
IPAddress.Loopback.ToString() : proxyIp!;
var hosts = proxyDomains.SelectMany(s =>
{
if (s == null) return default!;
return s.ListeningDomainNamesArray.Select(host =>
{
if (host.Contains(' '))
{
var h = host.Split(' ');
return new KeyValuePair<string, string>(h[1], h[0]);
}
return new KeyValuePair<string, string>(host, localhost);
});
}).ToDictionaryIgnoreRepeat(x => x.Key, y => y.Value);
if (isEnableScript)
{
hosts.TryAdd(IReverseProxyService.Constants.LocalDomain, localhost);
}
var updateHostsResult = await hostsFileService.UpdateHosts(hosts);
if (updateHostsResult.ResultType != OperationResultType.Success)
{
if (OperatingSystem2.IsMacOS() || OperatingSystem2.IsLinux())
{
Browser2.Open(Constants.Urls.OfficialWebsite_UnixHostAccess);
//platformService.RunShell($" \\cp \"{Path.Combine(IOPath.CacheDirectory, "hosts")}\" \"{platformService.HostsFilePath}\"");
}
await reverseProxyService.StopProxyAsync();
return Strings.OperationHostsError_.Format(updateHostsResult.Message);
}
}
break;
}
_StartAccelerateTime = DateTimeOffset.Now;
StartTimer();
return default;
}
else
{
if (startProxyResult.Code == StartProxyResultCode.BindPortError)
{
// NixOS 下通过 security.wrappers 机制处理权限,不需要 setcap
if (NixOSDetector.IsNixOS())
{
// 在 NixOS 上,如果绑定失败,说明 wrapper 未正确配置
Toast.Show(ToastIcon.Error, "NixOS 环境下需要配置 security.wrappers 以启用特权端口绑定");
reverseProxyService.Exit();
return "StartProxyFail: BindPortError (NixOS wrapper not configured)";
}
if (!string.IsNullOrWhiteSpace(Plugin.Instance.SubProcessPath))
{
// 非 NixOS 的 Linux 系统使用 pkexec setcap
Process.Start("pkexec", new string[] { "setcap", "cap_net_bind_service=+eip", Plugin.Instance.SubProcessPath }).WaitForExit();
}
//新线程等待 IPC 错误返回后 Kill 自己 Linux 修改权限需要重新启动
reverseProxyService.Exit();
return "StartProxyFail: BindPortError";
}
else
{
var errorString = startProxyResult.Code switch
{
StartProxyResultCode.Exception => startProxyResult.Exception?.ToString() ?? nameof(StartProxyResultCode.Exception),
_ => $"StartProxyFail, ErrCode: {startProxyResult.Code}"
};
return errorString;
}
}
当文件不存在的时候能弹出消息。文件存在的时候直接报错:failed to inherit capabilities: Operation not permitted.
需要请教。
我做了一些尝试:包括:检测nixos的环境,检测系统配置下的特权文件.
然后卡在了这里:
Plugins.cs
当检测到文件后 就直接报错:failed to inherit capabilities: Operation not permitted.此时我已经在系统下配置了
这个文件也确实有:
/run/wrappers/bin/steampp-accelerator
然后
我在SteamTools/src/BD.WTTS.Client.Plugins.Accelerator/Services/Mvvm/ProxyService.Operate.cs
下添加了
当文件不存在的时候能弹出消息。文件存在的时候直接报错:failed to inherit capabilities: Operation not permitted.
需要请教。