From 4b025a60c15559df022ad5342cb3d8e24967c077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com> Date: Wed, 23 Jun 2021 11:49:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BF=AB=E9=80=9F=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Directory.Build.props | 2 +- .../GithubFullScanHostedService.cs | 1 + FastGithub.Scanner/GithubLookupFacotry.cs | 9 +- FastGithub.Scanner/GithubScanService.cs | 54 ++++++++- FastGithub.Scanner/RawSocketPing.cs | 110 ++++++++++++++++++ 5 files changed, 170 insertions(+), 6 deletions(-) create mode 100644 FastGithub.Scanner/RawSocketPing.cs diff --git a/Directory.Build.props b/Directory.Build.props index 1c190b7..90b27e3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 1.0.0 + 1.0.1 enable github定制版的dns服务,解析github最优的ip https://github.com/xljiulang/FastGithub diff --git a/FastGithub.Scanner/GithubFullScanHostedService.cs b/FastGithub.Scanner/GithubFullScanHostedService.cs index 88bd628..647cb79 100644 --- a/FastGithub.Scanner/GithubFullScanHostedService.cs +++ b/FastGithub.Scanner/GithubFullScanHostedService.cs @@ -34,6 +34,7 @@ namespace FastGithub /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + await githubScanService.ScanFastAsync(stoppingToken); while (stoppingToken.IsCancellationRequested == false) { await githubScanService.ScanAllAsync(stoppingToken); diff --git a/FastGithub.Scanner/GithubLookupFacotry.cs b/FastGithub.Scanner/GithubLookupFacotry.cs index b48692f..bdcc363 100644 --- a/FastGithub.Scanner/GithubLookupFacotry.cs +++ b/FastGithub.Scanner/GithubLookupFacotry.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Collections.Generic; using System.Linq; @@ -15,6 +16,7 @@ namespace FastGithub.Scanner { private readonly IEnumerable providers; private readonly IOptionsMonitor options; + private readonly ILogger logger; /// /// 域名与ip关系工厂 @@ -23,10 +25,12 @@ namespace FastGithub.Scanner /// public GithubLookupFacotry( IEnumerable providers, - IOptionsMonitor options) + IOptionsMonitor options, + ILogger logger) { this.providers = providers.OrderBy(item => item.Order); this.options = options; + this.logger = logger; } /// @@ -35,6 +39,7 @@ namespace FastGithub.Scanner /// public async Task> LookupAsync(CancellationToken cancellationToken) { + this.logger.LogInformation($"开始查找各域名的ip.."); var hashSet = new HashSet(); var domains = this.options.CurrentValue.Domains; @@ -46,6 +51,8 @@ namespace FastGithub.Scanner hashSet.Add(item); } } + + this.logger.LogInformation($"查找到{hashSet.Count}条域名ip记录"); return hashSet; } } diff --git a/FastGithub.Scanner/GithubScanService.cs b/FastGithub.Scanner/GithubScanService.cs index bac71c3..ec276f1 100644 --- a/FastGithub.Scanner/GithubScanService.cs +++ b/FastGithub.Scanner/GithubScanService.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -54,23 +55,68 @@ namespace FastGithub.Scanner .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); - var successCount = results.Count(item => item); - this.logger.LogInformation($"完整扫描结束,成功{successCount}条共{results.Length}条"); - + return results.Count(item => item); async Task ScanAsync(GithubContext context) { diff --git a/FastGithub.Scanner/RawSocketPing.cs b/FastGithub.Scanner/RawSocketPing.cs new file mode 100644 index 0000000..938b3fb --- /dev/null +++ b/FastGithub.Scanner/RawSocketPing.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub.Scanner +{ + /// + /// RawSocket的ping功能 + /// + static class RawSocketPing + { + private static readonly byte[] echoRequestPacket = Convert.FromHexString("0800F6FF0100000000000000"); + private static readonly byte[] icmpReceiveBuffer = new byte[72]; + + /// + /// 获取是否支持 + /// + public static bool IsSupported { get; private set; } + + /// + /// RawSocket的ping功能 + /// + static RawSocketPing() + { + try + { + new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp).Dispose(); + IsSupported = true; + } + catch (Exception) + { + IsSupported = false; + } + } + + /// + /// ping目标ip + /// + /// + /// 等待时间 + /// 取消令牌 + /// ping通的ip + public static async Task> PingAsync(IEnumerable destAddresses, TimeSpan timeWait, CancellationToken cancellationToken = default) + { + using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp) + { + Ttl = 128, + DontFragment = false + }; + socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + + using var cancellationTokenSource = new CancellationTokenSource(); + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancellationTokenSource.Token); + var receiveTask = ReceiveAsync(socket, linkedTokenSource.Token); + + var distinctDestAddresses = destAddresses.Distinct(); + foreach (var address in distinctDestAddresses) + { + var remoteEndPoint = new IPEndPoint(address, 0); + await socket.SendToAsync(echoRequestPacket, SocketFlags.None, remoteEndPoint); + } + + await Task.Delay(timeWait, cancellationToken); + cancellationTokenSource.Cancel(); + socket.Close(); + + var hashSet = await receiveTask; + hashSet.IntersectWith(distinctDestAddresses); + return hashSet; + } + + /// + /// 循环接收任务 + /// + /// + /// + /// + private static async Task> ReceiveAsync(Socket socket, CancellationToken cancellationToken) + { + await Task.Yield(); + + var hashSet = new HashSet(); + var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + while (cancellationToken.IsCancellationRequested == false) + { + try + { + var result = await socket.ReceiveFromAsync(icmpReceiveBuffer, SocketFlags.None, remoteEndPoint); + if (result.RemoteEndPoint is IPEndPoint ipEndPoint) + { + hashSet.Add(ipEndPoint.Address); + } + } + catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted) + { + break; + } + catch (Exception) + { + } + } + return hashSet; + } + } +}