增加SocketTimedOut的ip黑名单处理

This commit is contained in:
老九 2021-08-28 00:11:18 +08:00
parent 2324634a86
commit d9034477da
4 changed files with 91 additions and 18 deletions

View File

@ -3,6 +3,7 @@ using DNS.Protocol;
using FastGithub.Configuration;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@ -19,7 +20,9 @@ namespace FastGithub.DomainResolve
/// </summary>
sealed class DomainResolver : IDomainResolver
{
private readonly IMemoryCache memoryCache;
private readonly IMemoryCache blackIPAddressCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
private readonly IMemoryCache domainResolveCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
private readonly FastGithubConfig fastGithubConfig;
private readonly DnscryptProxy dnscryptProxy;
private readonly ILogger<DomainResolver> logger;
@ -33,23 +36,40 @@ namespace FastGithub.DomainResolve
/// <summary>
/// 域名解析器
/// </summary>
/// <param name="memoryCache"></param>
/// </summary>
/// <param name="fastGithubConfig"></param>
/// <param name="dnscryptProxy"></param>
/// <param name="logger"></param>
public DomainResolver(
IMemoryCache memoryCache,
FastGithubConfig fastGithubConfig,
DnscryptProxy dnscryptProxy,
ILogger<DomainResolver> logger)
{
this.memoryCache = memoryCache;
this.fastGithubConfig = fastGithubConfig;
this.dnscryptProxy = dnscryptProxy;
this.logger = logger;
}
/// <summary>
/// 设置ip黑名单
/// </summary>
/// <param name="address">ip</param>
/// <param name="expiration">过期时间</param>
public void SetBlack(IPAddress address, TimeSpan expiration)
{
this.blackIPAddressCache.Set(address, address, expiration);
this.logger.LogWarning($"已自动将{address}关到黑屋{expiration}");
}
/// <summary>
/// 刷新域名解析结果
/// </summary>
/// <param name="domain">域名</param>
public void FlushDomain(DnsEndPoint domain)
{
this.domainResolveCache.Remove(domain);
}
/// <summary>
/// 解析域名
/// </summary>
@ -78,7 +98,7 @@ namespace FastGithub.DomainResolve
/// <returns></returns>
private async Task<IPAddress> LookupAsync(DnsEndPoint domain, CancellationToken cancellationToken)
{
if (this.memoryCache.TryGetValue<IPAddress>(domain, out var address))
if (this.domainResolveCache.TryGetValue<IPAddress>(domain, out var address))
{
return address;
}
@ -107,7 +127,7 @@ namespace FastGithub.DomainResolve
}
this.logger.LogInformation($"[{domain.Host}->{address}]");
this.memoryCache.Set(domain, address, expiration);
this.domainResolveCache.Set(domain, address, expiration);
return address;
}
@ -170,11 +190,6 @@ namespace FastGithub.DomainResolve
return default;
}
if (port <= 0)
{
return addresses.FirstOrDefault();
}
var tasks = addresses.Select(address => this.IsAvailableAsync(address, port, cancellationToken));
var fastTask = await Task.WhenAny(tasks);
return await fastTask;
@ -190,6 +205,16 @@ namespace FastGithub.DomainResolve
/// <returns></returns>
private async Task<IPAddress?> IsAvailableAsync(IPAddress address, int port, CancellationToken cancellationToken)
{
if (port <= 0)
{
return address;
}
if (this.blackIPAddressCache.TryGetValue(address, out _))
{
return default;
}
try
{
using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

View File

@ -1,4 +1,5 @@
using System.Net;
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
@ -9,10 +10,23 @@ namespace FastGithub.DomainResolve
/// </summary>
public interface IDomainResolver
{
/// <summary>
/// 设置ip黑名单
/// </summary>
/// <param name="address">ip</param>
/// <param name="expiration">过期时间</param>
void SetBlack(IPAddress address, TimeSpan expiration);
/// <summary>
/// 刷新域名解析结果
/// </summary>
/// <param name="domain">域名</param>
void FlushDomain(DnsEndPoint domain);
/// <summary>
/// 解析域名
/// </summary>
/// <param name="domain"></param>
/// <param name="domain">域名</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IPAddress> ResolveAsync(DnsEndPoint domain, CancellationToken cancellationToken = default);

View File

@ -15,8 +15,7 @@ namespace FastGithub
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddDomainResolve(this IServiceCollection services)
{
services.AddMemoryCache();
{
services.TryAddSingleton<DnscryptProxy>();
services.TryAddSingleton<IDomainResolver, DomainResolver>();
return services.AddHostedService<DnscryptProxyHostedService>();

View File

@ -21,6 +21,7 @@ namespace FastGithub.Http
{
private readonly DomainConfig domainConfig;
private readonly IDomainResolver domainResolver;
private readonly TimeSpan blackIPAddressExpiration = TimeSpan.FromMinutes(10d);
/// <summary>
/// HttpClientHandler
@ -42,8 +43,16 @@ namespace FastGithub.Http
/// <returns></returns>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
await this.ProcessRequestAsync(request, cancellationToken);
return await this.SendRequestAsync(request, cancellationToken);
try
{
await this.ProcessRequestAsync(request, cancellationToken);
return await this.SendRequestAsync(request, cancellationToken);
}
catch (HttpRequestException ex)
{
this.InterceptRequestException(request, ex);
throw;
}
}
/// <summary>
@ -109,6 +118,32 @@ namespace FastGithub.Http
}
}
/// <summary>
/// 拦截请求异常
/// 查找TimedOut的ip地址添加到黑名单
/// </summary>
/// <param name="request"></param>
/// <param name="exception"></param>
private void InterceptRequestException(HttpRequestMessage request, HttpRequestException exception)
{
if (request.RequestUri == null ||
exception.InnerException is not SocketException socketException ||
socketException.SocketErrorCode != SocketError.TimedOut)
{
return;
}
if (IPAddress.TryParse(request.RequestUri.Host, out var address))
{
this.domainResolver.SetBlack(address, this.blackIPAddressExpiration);
}
if (request.Headers.Host != null)
{
this.domainResolver.FlushDomain(new DnsEndPoint(request.Headers.Host, request.RequestUri.Port));
}
}
/// <summary>
/// 创建转发代理的httpHandler
/// </summary>