GithubScanService.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using FastGithub.Scanner.ScanMiddlewares;
  2. using Microsoft.Extensions.DependencyInjection;
  3. using Microsoft.Extensions.Logging;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace FastGithub.Scanner
  10. {
  11. /// <summary>
  12. /// github扫描服务
  13. /// </summary>
  14. [Service(ServiceLifetime.Singleton)]
  15. sealed class GithubScanService
  16. {
  17. private readonly GithubLookupFacotry lookupFactory;
  18. private readonly GithubScanResults scanResults;
  19. private readonly GithubDnsFlushService dnsFlushService;
  20. private readonly ILoggerFactory loggerFactory;
  21. private readonly ILogger<GithubScanService> logger;
  22. private readonly InvokeDelegate<GithubContext> fullScanDelegate;
  23. private readonly InvokeDelegate<GithubContext> resultScanDelegate;
  24. /// <summary>
  25. /// github扫描服务
  26. /// </summary>
  27. /// <param name="lookupFactory"></param>
  28. /// <param name="scanResults"></param>
  29. /// <param name="appService"></param>
  30. /// <param name="logger"></param>
  31. public GithubScanService(
  32. GithubLookupFacotry lookupFactory,
  33. GithubScanResults scanResults,
  34. GithubDnsFlushService dnsFlushService,
  35. IServiceProvider appService,
  36. ILoggerFactory loggerFactory,
  37. ILogger<GithubScanService> logger)
  38. {
  39. this.lookupFactory = lookupFactory;
  40. this.scanResults = scanResults;
  41. this.dnsFlushService = dnsFlushService;
  42. this.loggerFactory = loggerFactory;
  43. this.logger = logger;
  44. this.fullScanDelegate = new PipelineBuilder<GithubContext>(appService, ctx => Task.CompletedTask)
  45. .Use<ConcurrentMiddleware>()
  46. .Use<StatisticsMiddleware>()
  47. .Use<TcpScanMiddleware>()
  48. .Use<HttpsScanMiddleware>()
  49. .Build();
  50. this.resultScanDelegate = new PipelineBuilder<GithubContext>(appService, ctx => Task.CompletedTask)
  51. .Use<StatisticsMiddleware>()
  52. .Use<HttpsScanMiddleware>()
  53. .Build();
  54. }
  55. /// <summary>
  56. /// 快速扫描所有的ip
  57. /// </summary>
  58. /// <param name="cancellationToken"></param>
  59. /// <returns></returns>
  60. public async Task<bool> ScanFastAsync(CancellationToken cancellationToken)
  61. {
  62. if (RawSocketPing.IsSupported == false)
  63. {
  64. this.logger.LogWarning($"{Environment.OSVersion.Platform}不支持快速扫描功能");
  65. return false;
  66. }
  67. try
  68. {
  69. this.logger.LogInformation("快速扫描开始..");
  70. var domainAddresses = await this.lookupFactory.LookupAsync(cancellationToken);
  71. // ping快速过滤可用的ip
  72. var destAddresses = domainAddresses.Select(item => item.Address);
  73. var hashSet = await RawSocketPing.PingAsync(destAddresses, TimeSpan.FromSeconds(3d), cancellationToken);
  74. var results = domainAddresses.Where(item => hashSet.Contains(item.Address)).ToArray();
  75. this.logger.LogInformation($"快速扫描到{hashSet.Count}条ip,{results.Length}条域名ip记录");
  76. var successCount = await this.ScanAsync(results, cancellationToken);
  77. this.logger.LogInformation($"快速扫描结束,成功{successCount}条共{domainAddresses.Count()}条");
  78. return true;
  79. }
  80. catch (Exception ex)
  81. {
  82. this.logger.LogWarning($"快速扫描失败:{ex.Message}");
  83. return false;
  84. }
  85. }
  86. /// <summary>
  87. /// 扫描所有的ip
  88. /// </summary>
  89. /// <param name="cancellationToken"></param>
  90. /// <returns></returns>
  91. public async Task ScanAllAsync(CancellationToken cancellationToken)
  92. {
  93. this.logger.LogInformation("完整扫描开始..");
  94. var domainAddresses = await this.lookupFactory.LookupAsync(cancellationToken);
  95. var successCount = await this.ScanAsync(domainAddresses, cancellationToken);
  96. this.logger.LogInformation($"完整扫描结束,成功{successCount}条共{domainAddresses.Count()}条");
  97. }
  98. /// <summary>
  99. /// 扫描记录
  100. /// </summary>
  101. /// <param name="domainAddresses"></param>
  102. /// <param name="cancellationToken"></param>
  103. /// <returns></returns>
  104. private async Task<int> ScanAsync(IEnumerable<DomainAddress> domainAddresses, CancellationToken cancellationToken)
  105. {
  106. var scanTasks = domainAddresses
  107. .Select(item => new GithubContext(item.Domain, item.Address, cancellationToken))
  108. .Select(ctx => ScanAsync(ctx));
  109. var results = await Task.WhenAll(scanTasks);
  110. return results.Count(item => item);
  111. async Task<bool> ScanAsync(GithubContext context)
  112. {
  113. await this.fullScanDelegate(context);
  114. if (context.Available && this.scanResults.Add(context))
  115. {
  116. this.logger.LogInformation($"扫描到{context}");
  117. }
  118. return context.Available;
  119. }
  120. }
  121. /// <summary>
  122. /// 扫描历史结果
  123. /// </summary>
  124. /// <param name="cancellationToken"></param>
  125. /// <returns></returns>
  126. public async Task ScanResultAsync(CancellationToken cancellationToken)
  127. {
  128. this.logger.LogInformation("结果扫描开始..");
  129. var results = this.scanResults.ToArray();
  130. var contexts = results
  131. .OrderBy(item => item.Domain)
  132. .ThenByDescending(item => item.AvailableRate)
  133. .ThenBy(item => item.AvgElapsed);
  134. foreach (var context in contexts)
  135. {
  136. await this.resultScanDelegate(context);
  137. var domainLogger = this.loggerFactory.CreateLogger(context.Domain);
  138. if (context.Available == true)
  139. {
  140. domainLogger.LogInformation(context.ToStatisticsString());
  141. }
  142. else
  143. {
  144. domainLogger.LogWarning(context.ToStatisticsString());
  145. }
  146. }
  147. this.dnsFlushService.FlushGithubResolverCache();
  148. this.logger.LogInformation($"结果扫描结束,共扫描{results.Length}条记录");
  149. await this.scanResults.SaveDatasAsync(cancellationToken);
  150. }
  151. }
  152. }