增加快速扫描功能
This commit is contained in:
parent
01b91b801c
commit
4b025a60c1
@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>1.0.0</Version>
|
||||
<Version>1.0.1</Version>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>github定制版的dns服务,解析github最优的ip</Description>
|
||||
<Copyright>https://github.com/xljiulang/FastGithub</Copyright>
|
||||
|
||||
@ -34,6 +34,7 @@ namespace FastGithub
|
||||
/// <returns></returns>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await githubScanService.ScanFastAsync(stoppingToken);
|
||||
while (stoppingToken.IsCancellationRequested == false)
|
||||
{
|
||||
await githubScanService.ScanAllAsync(stoppingToken);
|
||||
|
||||
@ -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<IGithubLookupProvider> providers;
|
||||
private readonly IOptionsMonitor<GithubLookupFactoryOptions> options;
|
||||
private readonly ILogger<GithubLookupFacotry> logger;
|
||||
|
||||
/// <summary>
|
||||
/// 域名与ip关系工厂
|
||||
@ -23,10 +25,12 @@ namespace FastGithub.Scanner
|
||||
/// <param name="options"></param>
|
||||
public GithubLookupFacotry(
|
||||
IEnumerable<IGithubLookupProvider> providers,
|
||||
IOptionsMonitor<GithubLookupFactoryOptions> options)
|
||||
IOptionsMonitor<GithubLookupFactoryOptions> options,
|
||||
ILogger<GithubLookupFacotry> logger)
|
||||
{
|
||||
this.providers = providers.OrderBy(item => item.Order);
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -35,6 +39,7 @@ namespace FastGithub.Scanner
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<DomainAddress>> LookupAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
this.logger.LogInformation($"开始查找各域名的ip..");
|
||||
var hashSet = new HashSet<DomainAddress>();
|
||||
var domains = this.options.CurrentValue.Domains;
|
||||
|
||||
@ -46,6 +51,8 @@ namespace FastGithub.Scanner
|
||||
hashSet.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.LogInformation($"查找到{hashSet.Count}条域名ip记录");
|
||||
return hashSet;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 扫描所有的ip
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
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()}条");
|
||||
}
|
||||
|
||||
/// <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
|
||||
.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<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