using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Json; using System.Net.Sockets; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace FastGithub.Scanner.DomainAddressProviders { /// /// Github公开的域名与ip关系提供者 /// [Service(ServiceLifetime.Singleton, ServiceType = typeof(IDomainAddressProvider))] sealed class GithubMetaProvider : IDomainAddressProvider { private readonly IOptionsMonitor options; private readonly IHttpClientFactory httpClientFactory; private readonly ILogger logger; private const string META_URI = "https://api.github.com/meta"; /// /// 获取排序 /// public int Order => int.MaxValue; /// /// Github公开的域名与ip关系提供者 /// /// /// public GithubMetaProvider( IOptionsMonitor options, IHttpClientFactory httpClientFactory, ILogger logger) { this.options = options; this.httpClientFactory = httpClientFactory; this.logger = logger; } /// /// 创建域名与ip的关系 /// /// public async Task> CreateDomainAddressesAsync() { var setting = this.options.CurrentValue.DominAddressProviders.GithubMetaProvider; if (setting.Enable == false) { return Enumerable.Empty(); } try { var httpClient = this.httpClientFactory.CreateClient(nameof(FastGithub)); var meta = await this.GetMetaAsync(httpClient, setting.MetaUri); if (meta != null) { return meta.ToDomainAddresses(); } } catch (Exception ex) { this.logger.LogWarning($"加载远程的ip列表异常:{ex.Message}"); } return Enumerable.Empty(); } /// /// 尝试获取meta /// /// /// /// private async Task GetMetaAsync(HttpClient httpClient, Uri metaUri) { try { return await httpClient.GetFromJsonAsync(META_URI); } catch (Exception) { return await httpClient.GetFromJsonAsync(metaUri); } } /// /// github的meta结构 /// private class Meta { [JsonPropertyName("web")] public string[] Web { get; set; } = Array.Empty(); [JsonPropertyName("api")] public string[] Api { get; set; } = Array.Empty(); /// /// 转换为域名与ip关系 /// /// public IEnumerable ToDomainAddresses() { foreach (var range in IPAddressRange.From(this.Web).OrderBy(item => item.Size)) { if (range.AddressFamily == AddressFamily.InterNetwork) { foreach (var address in range) { yield return new DomainAddress("github.com", address); } } } foreach (var range in IPAddressRange.From(this.Api).OrderBy(item => item.Size)) { if (range.AddressFamily == AddressFamily.InterNetwork) { foreach (var address in range) { yield return new DomainAddress("api.github.com", address); } } } } } } }