FastGithub/FastGithub.PacketIntercept/Dns/ProxyConflictSolver.cs
xingyuan55 4d9d97f871 start
2022-11-16 08:01:03 +08:00

162 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}