增加快速扫描功能
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