using FastGithub.Scanner.ScanMiddlewares; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace FastGithub.Scanner { /// /// github扫描服务 /// [Service(ServiceLifetime.Singleton)] sealed class GithubScanService { private readonly GithubLookupFacotry lookupFactory; private readonly GithubScanResults scanResults; private readonly GithubDnsFlushService dnsFlushService; private readonly ILoggerFactory loggerFactory; private readonly ILogger logger; private readonly InvokeDelegate fullScanDelegate; private readonly InvokeDelegate resultScanDelegate; /// /// github扫描服务 /// /// /// /// /// public GithubScanService( GithubLookupFacotry lookupFactory, GithubScanResults scanResults, GithubDnsFlushService dnsFlushService, IServiceProvider appService, ILoggerFactory loggerFactory, ILogger logger) { this.lookupFactory = lookupFactory; this.scanResults = scanResults; this.dnsFlushService = dnsFlushService; this.loggerFactory = loggerFactory; this.logger = logger; this.fullScanDelegate = new PipelineBuilder(appService, ctx => Task.CompletedTask) .Use() .Use() .Use() .Use() .Build(); this.resultScanDelegate = new PipelineBuilder(appService, ctx => Task.CompletedTask) .Use() .Use() .Build(); } /// /// 快速扫描所有的ip /// /// /// public async Task ScanFastAsync(CancellationToken cancellationToken) { if (RawSocketPing.IsSupported == false) { this.logger.LogWarning($"{Environment.OSVersion.Platform}不支持快速扫描功能"); return false; } try { this.logger.LogInformation("快速扫描开始.."); var domainAddresses = await this.lookupFactory.LookupAsync(cancellationToken); // ping快速过滤可用的ip var destAddresses = domainAddresses.Select(item => item.Address); var hashSet = await RawSocketPing.PingAsync(destAddresses, TimeSpan.FromSeconds(3d), cancellationToken); var results = domainAddresses.Where(item => hashSet.Contains(item.Address)).ToArray(); this.logger.LogInformation($"快速扫描到{hashSet.Count}条ip,{results.Length}条域名ip记录"); var successCount = await this.ScanAsync(results, cancellationToken); this.logger.LogInformation($"快速扫描结束,成功{successCount}条共{domainAddresses.Count()}条"); return true; } catch (Exception ex) { this.logger.LogWarning($"快速扫描失败:{ex.Message}"); return false; } } /// /// 扫描所有的ip /// /// /// public async Task ScanAllAsync(CancellationToken cancellationToken) { this.logger.LogInformation("完整扫描开始.."); var domainAddresses = await this.lookupFactory.LookupAsync(cancellationToken); var successCount = await this.ScanAsync(domainAddresses, cancellationToken); this.logger.LogInformation($"完整扫描结束,成功{successCount}条共{domainAddresses.Count()}条"); } /// /// 扫描记录 /// /// /// /// private async Task ScanAsync(IEnumerable domainAddresses, CancellationToken cancellationToken) { var scanTasks = domainAddresses .Select(item => new GithubContext(item.Domain, item.Address, cancellationToken)) .Select(ctx => ScanAsync(ctx)); var results = await Task.WhenAll(scanTasks); return results.Count(item => item); async Task ScanAsync(GithubContext context) { await this.fullScanDelegate(context); if (context.Available && this.scanResults.Add(context)) { this.logger.LogInformation($"扫描到{context}"); } return context.Available; } } /// /// 扫描历史结果 /// /// /// public async Task ScanResultAsync(CancellationToken cancellationToken) { this.logger.LogInformation("结果扫描开始.."); var results = this.scanResults.ToArray(); var contexts = results .OrderBy(item => item.Domain) .ThenByDescending(item => item.AvailableRate) .ThenBy(item => item.AvgElapsed); foreach (var context in contexts) { await this.resultScanDelegate(context); var domainLogger = this.loggerFactory.CreateLogger(context.Domain); if (context.Available == true) { domainLogger.LogInformation(context.ToStatisticsString()); } else { domainLogger.LogWarning(context.ToStatisticsString()); } } this.dnsFlushService.FlushGithubResolverCache(); this.logger.LogInformation($"结果扫描结束,共扫描{results.Length}条记录"); await this.scanResults.SaveDatasAsync(cancellationToken); } } }