using FastGithub.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; namespace FastGithub.PacketIntercept.Dns { /// /// 代理冲突解决者 /// [SupportedOSPlatform("windows")] sealed class ProxyConflictSolver : IDnsConflictSolver { private const int INTERNET_OPTION_REFRESH = 37; private const int INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95; private const char PROXYOVERRIDE_SEPARATOR = ';'; private const string PROXYOVERRIDE_KEY = "ProxyOverride"; private const string INTERNET_SETTINGS = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings"; private readonly IOptions options; private readonly ILogger logger; [DllImport("wininet.dll")] private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); /// /// 代理冲突解决者 /// /// /// public ProxyConflictSolver( IOptions options, ILogger logger) { this.options = options; this.logger = logger; } /// /// 解决冲突 /// /// /// public Task SolveAsync(CancellationToken cancellationToken) { this.SetToProxyOvride(); this.CheckProxyConflict(); return Task.CompletedTask; } /// /// 恢复冲突 /// /// /// public Task RestoreAsync(CancellationToken cancellationToken) { this.RemoveFromProxyOvride(); return Task.CompletedTask; } /// /// 添加到ProxyOvride /// private void SetToProxyOvride() { using var settings = Registry.CurrentUser.OpenSubKey(INTERNET_SETTINGS, writable: true); if (settings == null) { return; } var items = this.options.Value.DomainConfigs.Keys.ToHashSet(); foreach (var item in GetProxyOvride(settings)) { items.Add(item); } SetProxyOvride(settings, items); } /// /// 从ProxyOvride移除 /// private void RemoveFromProxyOvride() { using var settings = Registry.CurrentUser.OpenSubKey(INTERNET_SETTINGS, writable: true); if (settings == null) { return; } var proxyOvride = GetProxyOvride(settings); var items = proxyOvride.Except(this.options.Value.DomainConfigs.Keys); SetProxyOvride(settings, items); } /// /// 检测代理冲突 /// private void CheckProxyConflict() { var systemProxy = HttpClient.DefaultProxy; if (systemProxy == null) { return; } foreach (var domain in this.options.Value.DomainConfigs.Keys) { var destination = new Uri($"https://{domain.Replace('*', 'a')}"); var proxyServer = systemProxy.GetProxy(destination); if (proxyServer != null) { this.logger.LogError($"由于系统设置了代理{proxyServer},{nameof(FastGithub)}无法加速{domain}"); } } } /// /// 获取ProxyOverride /// /// /// private static string[] GetProxyOvride(RegistryKey registryKey) { var value = registryKey.GetValue(PROXYOVERRIDE_KEY, null)?.ToString(); if (value == null) { return Array.Empty(); } return value .Split(PROXYOVERRIDE_SEPARATOR, StringSplitOptions.RemoveEmptyEntries) .Select(item => item.Trim()) .ToArray(); } /// /// 设置ProxyOverride /// /// /// private static void SetProxyOvride(RegistryKey registryKey, IEnumerable items) { var value = string.Join(PROXYOVERRIDE_SEPARATOR, items); registryKey.SetValue(PROXYOVERRIDE_KEY, value, RegistryValueKind.String); InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0); InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); } } }