using ClashDotNetFramework.Utils; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.ServiceProcess; using System.Text; using System.Threading.Tasks; namespace ClashDotNetFramework.Controllers { public class NFController : Guard { private readonly string BinDriver = string.Empty; private readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys"; public NFController() { string fileName; switch ($"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor}") { case "10.0": // Win 10 case "6.3": // Win 8 case "6.2": // Win 8 case "6.1": // Win 7 case "6.0": // Win 7 if (SystemHelper.Is64BitOperatingSystem()) fileName = "netfilter2-amd64.sys"; else fileName = "netfilter2-i386.sys"; break; default: Logging.Error($"不支持的系统版本:{Environment.OSVersion.Version}"); return; } BinDriver = Path.Combine(Global.ClashDotNetFrameworkDir, $"bin\\{fileName}"); RedirectStd = true; } public override string MainFile { get; protected set; } = "Redirector.exe"; public override string Name { get; } = "Redirector"; #region NetFilter Controller public void Start() { if (!CheckDriver()) return; try { _ = Task.Run(FireWallController.AddFireWallRules); string arguments = $"-m {string.Join(",", Global.Settings.RedirectTraffic)} -l {Global.Settings.ProcessMode} -b {string.Join(",", Global.Settings.BypassType)} -p {string.Join(",", Global.Settings.Processes)} -r 127.0.0.1:{Global.ClashMixedPort}"; StartInstanceAuto(arguments); } catch { } } public override void Stop() { StopInstance(); } #endregion #region NetFilter Driver /// /// 检查 NF 驱动 /// private bool CheckDriver() { var binFileVersion = Utils.Utils.GetFileVersion(BinDriver); var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver); Logging.Info("内置驱动版本: " + binFileVersion); Logging.Info("系统驱动版本: " + systemFileVersion); if (!File.Exists(BinDriver)) { Logging.Warning("内置驱动不存在"); if (File.Exists(SystemDriver)) { Logging.Warning("使用系统驱动"); return true; } Logging.Error("未安装驱动"); return false; } if (!File.Exists(SystemDriver)) { return InstallDriver(); } var reinstallFlag = false; if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult)) { if (binResult.CompareTo(systemResult) > 0) // Bin greater than Installed reinstallFlag = true; else if (systemResult.Major != binResult.Major) // Installed greater than Bin but Major Version Difference (has breaking changes), do downgrade reinstallFlag = true; } else { if (!systemFileVersion.Equals(binFileVersion)) reinstallFlag = true; } if (!reinstallFlag) return true; return ReinstallDriver(); } /// /// 安装 NF 驱动 /// /// 驱动是否安装成功 public bool InstallDriver() { Logging.Info("安装 NF 驱动"); if (!File.Exists(BinDriver)) throw new Exception("builtin driver files missing, can't install NF driver"); Process proc = new Process { StartInfo = { FileName = Path.GetFullPath($"bin\\NetFilterHelper.exe"), WorkingDirectory = $"{Global.ClashDotNetFrameworkDir}\\bin", Arguments = "install", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = true, Verb = "runas" } }; proc.Start(); proc.WaitForExit(); return proc.ExitCode == 0; } // /// 卸载 NF 驱动 /// /// 是否成功卸载 public bool UninstallDriver() { Logging.Info("卸载 NF 驱动"); Process proc = new Process { StartInfo = { FileName = Path.GetFullPath($"bin\\NetFilterHelper.exe"), WorkingDirectory = $"{Global.ClashDotNetFrameworkDir}\\bin", Arguments = "uninstall", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = true, Verb = "runas" } }; proc.Start(); proc.WaitForExit(); return proc.ExitCode == 0; } /// /// 更新 NF 驱动 /// /// 是否更新成功 public bool ReinstallDriver() { Logging.Info("更新 NF 驱动"); Process proc = new Process { StartInfo = { FileName = Path.GetFullPath($"bin\\NetFilterHelper.exe"), WorkingDirectory = $"{Global.ClashDotNetFrameworkDir}\\bin", Arguments = "reinstall", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = true, Verb = "runas" } }; proc.Start(); proc.WaitForExit(); return proc.ExitCode == 0; } #endregion } }