using DNS.Client; using DNS.Protocol; using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace FastGithub.DnscryptProxy { /// /// DnscryptProxy服务 /// sealed class DnscryptProxyService { private const string name = "dnscrypt-proxy"; private const string testDomain = "api.github.com"; private readonly FastGithubConfig fastGithubConfig; /// /// 获取相关进程 /// public Process? Process { get; private set; } /// /// 获取服务控制状态 /// public ControllState ControllState { get; private set; } = ControllState.None; /// /// DnscryptProxy服务 /// /// public DnscryptProxyService(FastGithubConfig fastGithubConfig) { this.fastGithubConfig = fastGithubConfig; } /// /// 启动dnscrypt-proxy /// /// /// public async Task StartAsync(CancellationToken cancellationToken) { this.ControllState = ControllState.Started; var tomlPath = $"{name}.toml"; await TomlUtil.SetListensAsync(tomlPath, this.fastGithubConfig.PureDns, cancellationToken); foreach (var process in Process.GetProcessesByName(name)) { process.Kill(); } if (OperatingSystem.IsWindows()) { StartDnscryptProxy("-service install")?.WaitForExit(); StartDnscryptProxy("-service start")?.WaitForExit(); this.Process = Process.GetProcessesByName(name).FirstOrDefault(item => item.SessionId == 0); } else { this.Process = StartDnscryptProxy(string.Empty); } } /// /// 等待dns服务OK /// /// /// public async Task WaitForDnsOKAsync(CancellationToken cancellationToken) { var process = this.Process; if (process == null || process.HasExited || this.ControllState != ControllState.Started) { return; } using var processExitTokenSource = new CancellationTokenSource(); process.EnableRaisingEvents = true; process.Exited += (s, e) => processExitTokenSource.Cancel(); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, processExitTokenSource.Token); await this.WaitForDnsOKCoreAsync(linkedTokenSource.Token); } /// /// 等待dns服务OK /// /// /// private async Task WaitForDnsOKCoreAsync(CancellationToken cancellationToken) { while (true) { try { using var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1d)); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); var dnsClient = new DnsClient(this.fastGithubConfig.PureDns); await dnsClient.Lookup(testDomain, RecordType.A, linkedTokenSource.Token); break; } catch (Exception) { cancellationToken.ThrowIfCancellationRequested(); } } } /// /// 停止dnscrypt-proxy /// public void Stop() { this.ControllState = ControllState.Stopped; if (OperatingSystem.IsWindows()) { StartDnscryptProxy("-service stop")?.WaitForExit(); StartDnscryptProxy("-service uninstall")?.WaitForExit(); } if (this.Process != null && this.Process.HasExited == false) { this.Process.Kill(); } } /// /// 启动DnscryptProxy进程 /// /// private static Process? StartDnscryptProxy(string arguments) { return Process.Start(new ProcessStartInfo { FileName = OperatingSystem.IsWindows() ? $"{name}.exe" : name, Arguments = arguments, UseShellExecute = true, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden }); } /// /// 转换为字符串 /// /// public override string ToString() { return name; } } }