using FastGithub.Configuration; using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; using static PInvoke.AdvApi32; namespace FastGithub.DomainResolve { /// /// DnscryptProxy服务 /// sealed class DnscryptProxy { private readonly ILogger logger; private readonly string processName; private readonly string serviceName; private readonly string exeFilePath; private readonly string tomlFilePath; /// /// 相关进程 /// private Process? process; /// /// 获取监听的节点 /// public IPEndPoint? LocalEndPoint { get; private set; } /// /// DnscryptProxy服务 /// /// public DnscryptProxy(ILogger logger) { const string PATH = "dnscrypt-proxy"; const string NAME = "dnscrypt-proxy"; this.logger = logger; this.processName = NAME; this.serviceName = $"{nameof(FastGithub)}.{NAME}"; this.exeFilePath = Path.Combine(PATH, OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME); this.tomlFilePath = Path.Combine(PATH, $"{NAME}.toml"); } /// /// 启动dnscrypt-proxy /// /// /// public async Task StartAsync(CancellationToken cancellationToken) { try { await this.StartCoreAsync(cancellationToken); } catch (Exception ex) { this.logger.LogWarning($"{this.processName}启动失败:{ex.Message}"); } } /// /// 启动dnscrypt-proxy /// /// /// private async Task StartCoreAsync(CancellationToken cancellationToken) { var port = GlobalListener.GetAvailablePort(5533); var localEndPoint = new IPEndPoint(IPAddress.Loopback, port); await TomlUtil.SetListensAsync(this.tomlFilePath, localEndPoint, cancellationToken); await TomlUtil.SetLogLevelAsync(this.tomlFilePath, 6, cancellationToken); await TomlUtil.SetLBStrategyAsync(this.tomlFilePath, "ph", cancellationToken); await TomlUtil.SetMinMaxTTLAsync(this.tomlFilePath, TimeSpan.FromMinutes(1d), TimeSpan.FromMinutes(2d), cancellationToken); if (OperatingSystem.IsWindows() && Environment.UserInteractive == false) { ServiceInstallUtil.StopAndDeleteService(this.serviceName); ServiceInstallUtil.InstallAndStartService(this.serviceName, this.exeFilePath, ServiceStartType.SERVICE_DEMAND_START); this.process = Process.GetProcessesByName(this.processName).FirstOrDefault(item => item.SessionId == 0); } else { this.process = StartDnscryptProxy(); } if (this.process != null) { this.LocalEndPoint = localEndPoint; this.process.EnableRaisingEvents = true; this.process.Exited += (s, e) => this.LocalEndPoint = null; } } /// /// 停止服务 /// public void Stop() { try { if (OperatingSystem.IsWindows() && Environment.UserInteractive == false) { ServiceInstallUtil.StopAndDeleteService(this.serviceName); } if (this.process != null && this.process.HasExited == false) { this.process.Kill(); } } catch (Exception ex) { this.logger.LogWarning($"{this.processName}停止失败:{ex.Message }"); } finally { this.LocalEndPoint = null; } } /// /// 启动DnscryptProxy进程 /// /// private Process? StartDnscryptProxy() { return Process.Start(new ProcessStartInfo { FileName = this.exeFilePath, WorkingDirectory = Path.GetDirectoryName(this.exeFilePath), UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden }); } /// /// 转换为字符串 /// /// public override string ToString() { return this.processName; } } }