增加快速扫描功能
This commit is contained in:
		
							parent
							
								
									01b91b801c
								
							
						
					
					
						commit
						4b025a60c1
					
				@ -1,6 +1,6 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<Version>1.0.0</Version>
 | 
							<Version>1.0.1</Version>
 | 
				
			||||||
		<Nullable>enable</Nullable>
 | 
							<Nullable>enable</Nullable>
 | 
				
			||||||
		<Description>github定制版的dns服务,解析github最优的ip</Description>
 | 
							<Description>github定制版的dns服务,解析github最优的ip</Description>
 | 
				
			||||||
		<Copyright>https://github.com/xljiulang/FastGithub</Copyright>
 | 
							<Copyright>https://github.com/xljiulang/FastGithub</Copyright>
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,7 @@ namespace FastGithub
 | 
				
			|||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 | 
					        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            await githubScanService.ScanFastAsync(stoppingToken);
 | 
				
			||||||
            while (stoppingToken.IsCancellationRequested == false)
 | 
					            while (stoppingToken.IsCancellationRequested == false)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                await githubScanService.ScanAllAsync(stoppingToken);
 | 
					                await githubScanService.ScanAllAsync(stoppingToken);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using Microsoft.Extensions.Options;
 | 
					using Microsoft.Extensions.Options;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
@ -15,6 +16,7 @@ namespace FastGithub.Scanner
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IEnumerable<IGithubLookupProvider> providers;
 | 
					        private readonly IEnumerable<IGithubLookupProvider> providers;
 | 
				
			||||||
        private readonly IOptionsMonitor<GithubLookupFactoryOptions> options;
 | 
					        private readonly IOptionsMonitor<GithubLookupFactoryOptions> options;
 | 
				
			||||||
 | 
					        private readonly ILogger<GithubLookupFacotry> logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 域名与ip关系工厂
 | 
					        /// 域名与ip关系工厂
 | 
				
			||||||
@ -23,10 +25,12 @@ namespace FastGithub.Scanner
 | 
				
			|||||||
        /// <param name="options"></param>
 | 
					        /// <param name="options"></param>
 | 
				
			||||||
        public GithubLookupFacotry(
 | 
					        public GithubLookupFacotry(
 | 
				
			||||||
            IEnumerable<IGithubLookupProvider> providers,
 | 
					            IEnumerable<IGithubLookupProvider> providers,
 | 
				
			||||||
            IOptionsMonitor<GithubLookupFactoryOptions> options)
 | 
					            IOptionsMonitor<GithubLookupFactoryOptions> options,
 | 
				
			||||||
 | 
					            ILogger<GithubLookupFacotry> logger)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.providers = providers.OrderBy(item => item.Order);
 | 
					            this.providers = providers.OrderBy(item => item.Order);
 | 
				
			||||||
            this.options = options;
 | 
					            this.options = options;
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@ -35,6 +39,7 @@ namespace FastGithub.Scanner
 | 
				
			|||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public async Task<IEnumerable<DomainAddress>> LookupAsync(CancellationToken cancellationToken)
 | 
					        public async Task<IEnumerable<DomainAddress>> LookupAsync(CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger.LogInformation($"开始查找各域名的ip..");
 | 
				
			||||||
            var hashSet = new HashSet<DomainAddress>();
 | 
					            var hashSet = new HashSet<DomainAddress>();
 | 
				
			||||||
            var domains = this.options.CurrentValue.Domains;
 | 
					            var domains = this.options.CurrentValue.Domains;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,6 +51,8 @@ namespace FastGithub.Scanner
 | 
				
			|||||||
                    hashSet.Add(item);
 | 
					                    hashSet.Add(item);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.logger.LogInformation($"查找到{hashSet.Count}条域名ip记录");
 | 
				
			||||||
            return hashSet;
 | 
					            return hashSet;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
@ -54,23 +55,68 @@ namespace FastGithub.Scanner
 | 
				
			|||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 快速扫描所有的ip
 | 
				
			||||||
 | 
					        /// </summary> 
 | 
				
			||||||
 | 
					        /// <param name="cancellationToken"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public async Task<bool> 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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 扫描所有的ip
 | 
					        /// 扫描所有的ip
 | 
				
			||||||
        /// </summary> 
 | 
					        /// </summary> 
 | 
				
			||||||
 | 
					        /// <param name="cancellationToken"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public async Task ScanAllAsync(CancellationToken cancellationToken)
 | 
					        public async Task ScanAllAsync(CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.logger.LogInformation("完整扫描开始..");
 | 
					            this.logger.LogInformation("完整扫描开始..");
 | 
				
			||||||
            var domainAddresses = await this.lookupFactory.LookupAsync(cancellationToken);
 | 
					            var domainAddresses = await this.lookupFactory.LookupAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var successCount = await this.ScanAsync(domainAddresses, cancellationToken);
 | 
				
			||||||
 | 
					            this.logger.LogInformation($"完整扫描结束,成功{successCount}条共{domainAddresses.Count()}条");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 扫描记录
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="domainAddresses"></param>
 | 
				
			||||||
 | 
					        /// <param name="cancellationToken"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        private async Task<int> ScanAsync(IEnumerable<DomainAddress> domainAddresses, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            var scanTasks = domainAddresses
 | 
					            var scanTasks = domainAddresses
 | 
				
			||||||
                .Select(item => new GithubContext(item.Domain, item.Address, cancellationToken))
 | 
					                .Select(item => new GithubContext(item.Domain, item.Address, cancellationToken))
 | 
				
			||||||
                .Select(ctx => ScanAsync(ctx));
 | 
					                .Select(ctx => ScanAsync(ctx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var results = await Task.WhenAll(scanTasks);
 | 
					            var results = await Task.WhenAll(scanTasks);
 | 
				
			||||||
            var successCount = results.Count(item => item);
 | 
					            return results.Count(item => item);
 | 
				
			||||||
            this.logger.LogInformation($"完整扫描结束,成功{successCount}条共{results.Length}条");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            async Task<bool> ScanAsync(GithubContext context)
 | 
					            async Task<bool> ScanAsync(GithubContext context)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										110
									
								
								FastGithub.Scanner/RawSocketPing.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								FastGithub.Scanner/RawSocketPing.cs
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// RawSocket的ping功能
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    static class RawSocketPing
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private static readonly byte[] echoRequestPacket = Convert.FromHexString("0800F6FF0100000000000000");
 | 
				
			||||||
 | 
					        private static readonly byte[] icmpReceiveBuffer = new byte[72];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 获取是否支持
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public static bool IsSupported { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// RawSocket的ping功能
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        static RawSocketPing()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp).Dispose();
 | 
				
			||||||
 | 
					                IsSupported = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                IsSupported = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// ping目标ip
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="destAddresses"></param>
 | 
				
			||||||
 | 
					        /// <param name="timeWait">等待时间</param>
 | 
				
			||||||
 | 
					        /// <param name="cancellationToken">取消令牌</param>
 | 
				
			||||||
 | 
					        /// <returns>ping通的ip</returns>
 | 
				
			||||||
 | 
					        public static async Task<HashSet<IPAddress>> PingAsync(IEnumerable<IPAddress> 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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 循环接收任务
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="socket"></param>
 | 
				
			||||||
 | 
					        /// <param name="cancellationToken"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        private static async Task<HashSet<IPAddress>> ReceiveAsync(Socket socket, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await Task.Yield();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var hashSet = new HashSet<IPAddress>();
 | 
				
			||||||
 | 
					            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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user