ProxyConflictSolver.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using FastGithub.Configuration;
  2. using Microsoft.Extensions.Logging;
  3. using Microsoft.Extensions.Options;
  4. using Microsoft.Win32;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Net.Http;
  9. using System.Runtime.InteropServices;
  10. using System.Runtime.Versioning;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. namespace FastGithub.PacketIntercept.Dns
  14. {
  15. /// <summary>
  16. /// 代理冲突解决者
  17. /// </summary>
  18. [SupportedOSPlatform("windows")]
  19. sealed class ProxyConflictSolver : IDnsConflictSolver
  20. {
  21. private const int INTERNET_OPTION_REFRESH = 37;
  22. private const int INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95;
  23. private const char PROXYOVERRIDE_SEPARATOR = ';';
  24. private const string PROXYOVERRIDE_KEY = "ProxyOverride";
  25. private const string INTERNET_SETTINGS = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
  26. private readonly IOptions<FastGithubOptions> options;
  27. private readonly ILogger<ProxyConflictSolver> logger;
  28. [DllImport("wininet.dll")]
  29. private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
  30. /// <summary>
  31. /// 代理冲突解决者
  32. /// </summary>
  33. /// <param name="options"></param>
  34. /// <param name="logger"></param>
  35. public ProxyConflictSolver(
  36. IOptions<FastGithubOptions> options,
  37. ILogger<ProxyConflictSolver> logger)
  38. {
  39. this.options = options;
  40. this.logger = logger;
  41. }
  42. /// <summary>
  43. /// 解决冲突
  44. /// </summary>
  45. /// <param name="cancellationToken"></param>
  46. /// <returns></returns>
  47. public Task SolveAsync(CancellationToken cancellationToken)
  48. {
  49. this.SetToProxyOvride();
  50. this.CheckProxyConflict();
  51. return Task.CompletedTask;
  52. }
  53. /// <summary>
  54. /// 恢复冲突
  55. /// </summary>
  56. /// <param name="cancellationToken"></param>
  57. /// <returns></returns>
  58. public Task RestoreAsync(CancellationToken cancellationToken)
  59. {
  60. this.RemoveFromProxyOvride();
  61. return Task.CompletedTask;
  62. }
  63. /// <summary>
  64. /// 添加到ProxyOvride
  65. /// </summary>
  66. private void SetToProxyOvride()
  67. {
  68. using var settings = Registry.CurrentUser.OpenSubKey(INTERNET_SETTINGS, writable: true);
  69. if (settings == null)
  70. {
  71. return;
  72. }
  73. var items = this.options.Value.DomainConfigs.Keys.ToHashSet();
  74. foreach (var item in GetProxyOvride(settings))
  75. {
  76. items.Add(item);
  77. }
  78. SetProxyOvride(settings, items);
  79. }
  80. /// <summary>
  81. /// 从ProxyOvride移除
  82. /// </summary>
  83. private void RemoveFromProxyOvride()
  84. {
  85. using var settings = Registry.CurrentUser.OpenSubKey(INTERNET_SETTINGS, writable: true);
  86. if (settings == null)
  87. {
  88. return;
  89. }
  90. var proxyOvride = GetProxyOvride(settings);
  91. var items = proxyOvride.Except(this.options.Value.DomainConfigs.Keys);
  92. SetProxyOvride(settings, items);
  93. }
  94. /// <summary>
  95. /// 检测代理冲突
  96. /// </summary>
  97. private void CheckProxyConflict()
  98. {
  99. var systemProxy = HttpClient.DefaultProxy;
  100. if (systemProxy == null)
  101. {
  102. return;
  103. }
  104. foreach (var domain in this.options.Value.DomainConfigs.Keys)
  105. {
  106. var destination = new Uri($"https://{domain.Replace('*', 'a')}");
  107. var proxyServer = systemProxy.GetProxy(destination);
  108. if (proxyServer != null)
  109. {
  110. this.logger.LogError($"由于系统设置了代理{proxyServer},{nameof(FastGithub)}无法加速{domain}");
  111. }
  112. }
  113. }
  114. /// <summary>
  115. /// 获取ProxyOverride
  116. /// </summary>
  117. /// <param name="registryKey"></param>
  118. /// <returns></returns>
  119. private static string[] GetProxyOvride(RegistryKey registryKey)
  120. {
  121. var value = registryKey.GetValue(PROXYOVERRIDE_KEY, null)?.ToString();
  122. if (value == null)
  123. {
  124. return Array.Empty<string>();
  125. }
  126. return value
  127. .Split(PROXYOVERRIDE_SEPARATOR, StringSplitOptions.RemoveEmptyEntries)
  128. .Select(item => item.Trim())
  129. .ToArray();
  130. }
  131. /// <summary>
  132. /// 设置ProxyOverride
  133. /// </summary>
  134. /// <param name="registryKey"></param>
  135. /// <param name="items"></param>
  136. private static void SetProxyOvride(RegistryKey registryKey, IEnumerable<string> items)
  137. {
  138. var value = string.Join(PROXYOVERRIDE_SEPARATOR, items);
  139. registryKey.SetValue(PROXYOVERRIDE_KEY, value, RegistryValueKind.String);
  140. InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0);
  141. InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
  142. }
  143. }
  144. }