162 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
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
 | 
						||
{
 | 
						||
    /// <summary>
 | 
						||
    /// 代理冲突解决者
 | 
						||
    /// </summary>
 | 
						||
    [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<FastGithubOptions> options;
 | 
						||
        private readonly ILogger<ProxyConflictSolver> logger;
 | 
						||
 | 
						||
        [DllImport("wininet.dll")]
 | 
						||
        private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 代理冲突解决者
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="options"></param>
 | 
						||
        /// <param name="logger"></param>
 | 
						||
        public ProxyConflictSolver(
 | 
						||
            IOptions<FastGithubOptions> options,
 | 
						||
            ILogger<ProxyConflictSolver> logger)
 | 
						||
        {
 | 
						||
            this.options = options;
 | 
						||
            this.logger = logger;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 解决冲突
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="cancellationToken"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public Task SolveAsync(CancellationToken cancellationToken)
 | 
						||
        {
 | 
						||
            this.SetToProxyOvride();
 | 
						||
            this.CheckProxyConflict();
 | 
						||
            return Task.CompletedTask;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 恢复冲突
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="cancellationToken"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public Task RestoreAsync(CancellationToken cancellationToken)
 | 
						||
        {
 | 
						||
            this.RemoveFromProxyOvride();
 | 
						||
            return Task.CompletedTask;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 添加到ProxyOvride
 | 
						||
        /// </summary>
 | 
						||
        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);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 从ProxyOvride移除
 | 
						||
        /// </summary>
 | 
						||
        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);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 检测代理冲突
 | 
						||
        /// </summary>
 | 
						||
        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}");
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 获取ProxyOverride
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="registryKey"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private static string[] GetProxyOvride(RegistryKey registryKey)
 | 
						||
        {
 | 
						||
            var value = registryKey.GetValue(PROXYOVERRIDE_KEY, null)?.ToString();
 | 
						||
            if (value == null)
 | 
						||
            {
 | 
						||
                return Array.Empty<string>();
 | 
						||
            }
 | 
						||
 | 
						||
            return value
 | 
						||
                .Split(PROXYOVERRIDE_SEPARATOR, StringSplitOptions.RemoveEmptyEntries)
 | 
						||
                .Select(item => item.Trim())
 | 
						||
                .ToArray();
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 设置ProxyOverride
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="registryKey"></param>
 | 
						||
        /// <param name="items"></param>
 | 
						||
        private static void SetProxyOvride(RegistryKey registryKey, IEnumerable<string> 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);
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 |