using FastGithub.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace FastGithub.DomainResolve { /// /// DnscryptProxy服务 /// sealed class DnscryptProxy { private const string PATH = "dnscrypt-proxy"; private const string NAME = "dnscrypt-proxy"; private readonly ILogger logger; /// /// 相关进程 /// private Process? process; /// /// 获取监听的节点 /// public IPEndPoint? LocalEndPoint { get; private set; } /// /// DnscryptProxy服务 /// /// public DnscryptProxy(ILogger logger) { this.logger = logger; } /// /// 启动dnscrypt-proxy /// /// /// public async Task StartAsync(CancellationToken cancellationToken) { try { await this.StartCoreAsync(cancellationToken); } catch (Exception ex) { this.logger.LogWarning($"{NAME}启动失败:{ex.Message}"); } } /// /// 启动dnscrypt-proxy /// /// /// private async Task StartCoreAsync(CancellationToken cancellationToken) { var tomlPath = Path.Combine(PATH, $"{NAME}.toml"); var port = GetAvailablePort(IPAddress.Loopback.AddressFamily); var localEndPoint = new IPEndPoint(IPAddress.Loopback, port); await TomlUtil.SetListensAsync(tomlPath, localEndPoint, cancellationToken); await TomlUtil.SetlogLevelAsync(tomlPath, 6, cancellationToken); await TomlUtil.SetEdnsClientSubnetAsync(tomlPath, cancellationToken); foreach (var process in Process.GetProcessesByName(NAME)) { process.Kill(); process.WaitForExit(); } if (OperatingSystem.IsWindows() && Process.GetCurrentProcess().SessionId == 0) { StartDnscryptProxy("-service uninstall")?.WaitForExit(); StartDnscryptProxy("-service install")?.WaitForExit(); StartDnscryptProxy("-service start")?.WaitForExit(); this.process = Process.GetProcessesByName(NAME).FirstOrDefault(item => item.SessionId == 0); } else { this.process = StartDnscryptProxy(string.Empty); } 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() && Process.GetCurrentProcess().SessionId == 0) { StartDnscryptProxy("-service stop")?.WaitForExit(); StartDnscryptProxy("-service uninstall")?.WaitForExit(); } if (this.process != null && this.process.HasExited == false) { this.process.Kill(); } } catch (Exception ex) { this.logger.LogWarning($"{NAME}停止失败:{ex.Message }"); } finally { this.LocalEndPoint = null; } } /// /// 获取可用的随机端口 /// /// /// 最小值 /// private static int GetAvailablePort(AddressFamily addressFamily, int min = 5533) { var hashSet = new HashSet(); var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners(); var udpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners(); foreach (var endPoint in tcpListeners.Concat(udpListeners)) { if (endPoint.AddressFamily == addressFamily) { hashSet.Add(endPoint.Port); } } for (var port = min; port < IPEndPoint.MaxPort; port++) { if (hashSet.Contains(port) == false) { return port; } } throw new FastGithubException("当前无可用的端口"); } /// /// 启动DnscryptProxy进程 /// /// private static Process? StartDnscryptProxy(string arguments) { var fileName = OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME; return Process.Start(new ProcessStartInfo { FileName = Path.Combine(PATH, fileName), Arguments = arguments, WorkingDirectory = PATH, UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden }); } /// /// 转换为字符串 /// /// public override string ToString() { return NAME; } } }