using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace FastGithub.Scanner.ScanMiddlewares { /// /// tcp扫描中间件 /// [Service(ServiceLifetime.Singleton)] sealed class TcpScanMiddleware : IMiddleware { private const int PORT = 443; private readonly IOptionsMonitor options; private readonly IMemoryCache memoryCache; private readonly ILogger logger; /// /// tcp扫描中间件 /// /// /// public TcpScanMiddleware( IOptionsMonitor options, IMemoryCache memoryCache, ILogger logger) { this.options = options; this.memoryCache = memoryCache; this.logger = logger; } /// /// tcp扫描 /// /// /// /// public async Task InvokeAsync(GithubContext context, Func next) { var key = $"tcp://{context.Address}"; if (this.memoryCache.TryGetValue(key, out var available) == false) { available = await this.TcpScanAsync(context); this.memoryCache.Set(key, available, this.options.CurrentValue.CacheExpiration); } if (available == true) { await next(); } else { this.logger.LogTrace($"{context.Domain} {context.Address}的{PORT}端口未开放"); } } /// /// tcp扫描 /// /// /// private async Task TcpScanAsync(GithubContext context) { try { var timeout = this.options.CurrentValue.Timeout; using var timeoutTokenSource = new CancellationTokenSource(timeout); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, context.CancellationToken); using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await socket.ConnectAsync(context.Address, PORT, linkedTokenSource.Token); return true; } catch (Exception) { context.CancellationToken.ThrowIfCancellationRequested(); return false; } } } }