diff --git a/FastGithub/DnsHostedService.cs b/FastGithub/DnsHostedService.cs new file mode 100644 index 0000000..2b1b81f --- /dev/null +++ b/FastGithub/DnsHostedService.cs @@ -0,0 +1,79 @@ +using DNS.Client.RequestResolver; +using DNS.Protocol; +using DNS.Protocol.ResourceRecords; +using DNS.Server; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub +{ + sealed class DnsHostedService : IHostedService, IRequestResolver + { + private readonly DnsServer dnsServer; + private readonly GithubScanService githubScanService; + private readonly ILogger logger; + + public DnsHostedService( + GithubScanService githubScanService, + IOptions options, + ILogger logger) + { + this.dnsServer = new DnsServer(this, options.Value.UpStream); + this.githubScanService = githubScanService; + this.logger = logger; + } + + /// + /// 解析dns + /// + /// + /// + /// + Task IRequestResolver.Resolve(IRequest request, CancellationToken cancellationToken) + { + var response = Response.FromRequest(request); + var question = request.Questions.FirstOrDefault(); + + if (question != null && question.Type == RecordType.A) + { + var domain = question.Name.ToString(); + if (domain.Contains("github", StringComparison.OrdinalIgnoreCase)) + { + var contexts = this.githubScanService.Result + .Where(item => item.Domain == domain) + .OrderBy(item => item.HttpElapsed); + + foreach (var context in contexts) + { + var record = new IPAddressResourceRecord(question.Name, context.Address, TimeSpan.FromMinutes(2d)); + response.AnswerRecords.Add(record); + this.logger.LogWarning(record.ToString()); + } + + return Task.FromResult(response); + } + } + + return Task.FromResult(response); + } + + public Task StartAsync(CancellationToken cancellationToken) + { + this.dnsServer.Listen(); + this.logger.LogInformation("dns服务启用成功"); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + this.dnsServer.Dispose(); + this.logger.LogInformation("dns服务已终止"); + return Task.CompletedTask; + } + } +} diff --git a/FastGithub/DnsOptions.cs b/FastGithub/DnsOptions.cs new file mode 100644 index 0000000..a77c824 --- /dev/null +++ b/FastGithub/DnsOptions.cs @@ -0,0 +1,9 @@ +using System.Net; + +namespace FastGithub +{ + class DnsOptions + { + public IPAddress UpStream { get; set; } = IPAddress.Parse("114.114.114.114"); + } +} diff --git a/FastGithub/FastGithub.csproj b/FastGithub/FastGithub.csproj index c102b25..0d95d9a 100644 --- a/FastGithub/FastGithub.csproj +++ b/FastGithub/FastGithub.csproj @@ -3,15 +3,16 @@ Exe enable - net6.0 + net5.0 true - 1.0.1 + 1.0.2 + - - + + diff --git a/FastGithub/GithubContext.cs b/FastGithub/GithubContext.cs index 885f157..5764c9e 100644 --- a/FastGithub/GithubContext.cs +++ b/FastGithub/GithubContext.cs @@ -1,19 +1,22 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Net; namespace FastGithub { class GithubContext { - [AllowNull] - public string Domain { get; set; } + public string Domain { get; } - [AllowNull] - public IPAddress Address { get; set; } + public IPAddress Address { get; } public TimeSpan? HttpElapsed { get; set; } + public GithubContext(string domain,IPAddress address) + { + this.Domain = domain; + this.Address = address; + } + public override string ToString() { return $"{Address}\t{Domain}\t# {HttpElapsed}"; diff --git a/FastGithub/GithubHostedService.cs b/FastGithub/GithubHostedService.cs deleted file mode 100644 index ba7a269..0000000 --- a/FastGithub/GithubHostedService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System.Threading; -using System.Threading.Tasks; - -namespace FastGithub -{ - sealed class GithubHostedService : IHostedService - { - private readonly IServiceScopeFactory serviceScopeFactory; - private readonly IHostApplicationLifetime hostApplicationLifetime; - - public GithubHostedService( - IServiceScopeFactory serviceScopeFactory, - IHostApplicationLifetime hostApplicationLifetime) - { - this.serviceScopeFactory = serviceScopeFactory; - this.hostApplicationLifetime = hostApplicationLifetime; - } - - - public async Task StartAsync(CancellationToken cancellationToken) - { - var scope = this.serviceScopeFactory.CreateScope(); - var service = scope.ServiceProvider.GetRequiredService(); - await service.ScanAddressAsync(cancellationToken); - this.hostApplicationLifetime.StopApplication(); - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/FastGithub/GithubOptions.cs b/FastGithub/GithubOptions.cs index ef46658..cfcae52 100644 --- a/FastGithub/GithubOptions.cs +++ b/FastGithub/GithubOptions.cs @@ -4,8 +4,12 @@ namespace FastGithub { class GithubOptions { + public TimeSpan ScanAllInterval { get; set; } = TimeSpan.FromHours(12d); + + public TimeSpan ScanResultInterval { get; set; } = TimeSpan.FromMinutes(5d); + public Uri MetaUri { get; set; } = new Uri("https://gitee.com/jiulang/fast-github/raw/master/FastGithub/meta.json"); - + public TimeSpan PortScanTimeout { get; set; } = TimeSpan.FromSeconds(1d); public TimeSpan HttpsScanTimeout { get; set; } = TimeSpan.FromSeconds(5d); diff --git a/FastGithub/GithubScanAllHostedService.cs b/FastGithub/GithubScanAllHostedService.cs new file mode 100644 index 0000000..7d8c30d --- /dev/null +++ b/FastGithub/GithubScanAllHostedService.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub +{ + sealed class GithubScanAllHostedService : BackgroundService + { + private readonly GithubScanService githubScanService; + private readonly IOptionsMonitor options; + + public GithubScanAllHostedService( + GithubScanService githubScanService, + IOptionsMonitor options) + { + this.githubScanService = githubScanService; + this.options = options; + } + + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (stoppingToken.IsCancellationRequested == false) + { + await githubScanService.ScanAllAsync(stoppingToken); + await Task.Delay(this.options.CurrentValue.ScanResultInterval, stoppingToken); + } + } + } +} diff --git a/FastGithub/GithubBuilder.cs b/FastGithub/GithubScanBuilder.cs similarity index 74% rename from FastGithub/GithubBuilder.cs rename to FastGithub/GithubScanBuilder.cs index 173ea50..d346926 100644 --- a/FastGithub/GithubBuilder.cs +++ b/FastGithub/GithubScanBuilder.cs @@ -7,10 +7,10 @@ namespace FastGithub /// /// 表示中间件创建者 /// - sealed class GithubBuilder : IGithubBuilder + sealed class GithubScanBuilder : IGithubScanBuilder { - private readonly GithubDelegate completedHandler; - private readonly List> middlewares = new(); + private readonly GithubScanDelegate completedHandler; + private readonly List> middlewares = new(); /// /// 获取服务提供者 @@ -21,7 +21,7 @@ namespace FastGithub /// 中间件创建者 /// /// - public GithubBuilder(IServiceProvider appServices) + public GithubScanBuilder(IServiceProvider appServices) : this(appServices, context => Task.CompletedTask) { } @@ -31,7 +31,7 @@ namespace FastGithub /// /// /// 完成执行内容处理者 - public GithubBuilder(IServiceProvider appServices, GithubDelegate completedHandler) + public GithubScanBuilder(IServiceProvider appServices, GithubScanDelegate completedHandler) { this.AppServices = appServices; this.completedHandler = completedHandler; @@ -42,7 +42,7 @@ namespace FastGithub /// /// /// - public IGithubBuilder Use(Func middleware) + public IGithubScanBuilder Use(Func middleware) { this.middlewares.Add(middleware); return this; @@ -53,7 +53,7 @@ namespace FastGithub /// 创建所有中间件执行处理者 /// /// - public GithubDelegate Build() + public GithubScanDelegate Build() { var handler = this.completedHandler; for (var i = this.middlewares.Count - 1; i >= 0; i--) diff --git a/FastGithub/GithubBuilderExtensions.cs b/FastGithub/GithubScanBuilderExtensions.cs similarity index 75% rename from FastGithub/GithubBuilderExtensions.cs rename to FastGithub/GithubScanBuilderExtensions.cs index 646c5fb..6c99ce3 100644 --- a/FastGithub/GithubBuilderExtensions.cs +++ b/FastGithub/GithubScanBuilderExtensions.cs @@ -6,7 +6,7 @@ namespace FastGithub /// /// 中间件创建者扩展 /// - static class GithubBuilderExtensions + static class GithubScanBuilderExtensions { /// /// 使用中间件 @@ -14,7 +14,7 @@ namespace FastGithub /// /// /// - public static IGithubBuilder Use(this IGithubBuilder builder) where TMiddleware : class, IGithubMiddleware + public static IGithubScanBuilder Use(this IGithubScanBuilder builder) where TMiddleware : class, IGithubScanMiddleware { return builder.AppServices.GetService(typeof(TMiddleware)) is TMiddleware middleware ? builder.Use(middleware.InvokeAsync) @@ -28,7 +28,7 @@ namespace FastGithub /// /// /// - public static IGithubBuilder Use(this IGithubBuilder builder, Func, Task> middleware) + public static IGithubScanBuilder Use(this IGithubScanBuilder builder, Func, Task> middleware) { return builder.Use(next => context => middleware(context, () => next(context))); } diff --git a/FastGithub/GithubDelegate.cs b/FastGithub/GithubScanDelegate.cs similarity index 78% rename from FastGithub/GithubDelegate.cs rename to FastGithub/GithubScanDelegate.cs index b79031e..d2908d3 100644 --- a/FastGithub/GithubDelegate.cs +++ b/FastGithub/GithubScanDelegate.cs @@ -7,5 +7,5 @@ namespace FastGithub /// /// 中间件上下文 /// - delegate Task GithubDelegate(GithubContext context); + delegate Task GithubScanDelegate(GithubContext context); } diff --git a/FastGithub/GithubScanResultHostedService.cs b/FastGithub/GithubScanResultHostedService.cs new file mode 100644 index 0000000..6442a81 --- /dev/null +++ b/FastGithub/GithubScanResultHostedService.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub +{ + sealed class GithubScanResultHostedService : BackgroundService + { + private readonly GithubScanService githubScanService; + private readonly IOptionsMonitor options; + + public GithubScanResultHostedService( + GithubScanService githubScanService, + IOptionsMonitor options) + { + this.githubScanService = githubScanService; + this.options = options; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (stoppingToken.IsCancellationRequested == false) + { + await Task.Delay(this.options.CurrentValue.ScanResultInterval, stoppingToken); + await githubScanService.ScanResultAsync(); + } + } + } +} diff --git a/FastGithub/GithubScanService.cs b/FastGithub/GithubScanService.cs new file mode 100644 index 0000000..ba6df02 --- /dev/null +++ b/FastGithub/GithubScanService.cs @@ -0,0 +1,51 @@ +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace FastGithub +{ + sealed class GithubScanService + { + private readonly GithubMetaService metaService; + private readonly GithubScanDelegate scanDelegate; + + public ConcurrentQueue Result { get; } = new(); + + public GithubScanService( + GithubMetaService metaService, + GithubScanDelegate scanDelegate) + { + this.metaService = metaService; + this.scanDelegate = scanDelegate; + } + + public async Task ScanAllAsync(CancellationToken cancellationToken = default) + { + var meta = await this.metaService.GetMetaAsync(cancellationToken); + if (meta != null) + { + this.Result.Clear(); + var scanTasks = meta.ToGithubContexts().Select(ctx => ScanAsync(ctx)); + await Task.WhenAll(scanTasks); + } + } + + public async Task ScanResultAsync() + { + while (this.Result.TryDequeue(out var context)) + { + await this.ScanAsync(context); + } + } + + private async Task ScanAsync(GithubContext context) + { + await this.scanDelegate(context); + if (context.HttpElapsed != null) + { + this.Result.Enqueue(context); + } + } + } +} diff --git a/FastGithub/GithubService.cs b/FastGithub/GithubService.cs deleted file mode 100644 index 5adb1ee..0000000 --- a/FastGithub/GithubService.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Microsoft.Extensions.Logging; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace FastGithub -{ - sealed class GithubService - { - private readonly GithubMetaService githubMetaService; - private readonly GithubDelegate githubDelegate; - private readonly ILogger logger; - - public GithubService( - GithubMetaService githubMetaService, - GithubDelegate githubDelegate, - ILogger logger) - { - this.githubMetaService = githubMetaService; - this.githubDelegate = githubDelegate; - this.logger = logger; - } - - public async Task ScanAddressAsync(CancellationToken cancellationToken = default) - { - var meta = await this.githubMetaService.GetMetaAsync(cancellationToken); - if (meta != null) - { - var scanTasks = this.GetMetaScanTasks(meta); - var contexts = await Task.WhenAll(scanTasks); - - var sortedContexts = contexts - .Where(item => item.HttpElapsed != null) - .OrderBy(item => item.Domain) - .ThenBy(item => item.HttpElapsed); - - using var fileStream = File.OpenWrite("github.txt"); - using var fileWriter = new StreamWriter(fileStream); - - foreach (var context in sortedContexts) - { - var message = context.ToString(); - await fileWriter.WriteLineAsync(message); - } - } - - this.logger.LogInformation("扫描结束"); - } - - - private IEnumerable> GetMetaScanTasks(Meta meta) - { - foreach (var item in meta.ToDomainAddress()) - { - var context = new GithubContext - { - Domain = item.Domain, - Address = item.Address, - }; - yield return InvokeAsync(context); - } - - - async Task InvokeAsync(GithubContext context) - { - await this.githubDelegate(context); - return context; - } - } - } -} diff --git a/FastGithub/IGithubBuilder.cs b/FastGithub/IGithubScanBuilder.cs similarity index 77% rename from FastGithub/IGithubBuilder.cs rename to FastGithub/IGithubScanBuilder.cs index 0911703..94495c9 100644 --- a/FastGithub/IGithubBuilder.cs +++ b/FastGithub/IGithubScanBuilder.cs @@ -5,7 +5,7 @@ namespace FastGithub /// /// 定义中间件管道创建者的接口 /// - interface IGithubBuilder + interface IGithubScanBuilder { /// /// 获取服务提供者 @@ -17,12 +17,12 @@ namespace FastGithub /// /// 中间件 /// - IGithubBuilder Use(Func middleware); + IGithubScanBuilder Use(Func middleware); /// /// 创建所有中间件执行处理者 /// /// - GithubDelegate Build(); + GithubScanDelegate Build(); } } diff --git a/FastGithub/IGithubMiddleware.cs b/FastGithub/IGithubScanMiddleware.cs similarity index 92% rename from FastGithub/IGithubMiddleware.cs rename to FastGithub/IGithubScanMiddleware.cs index c4a4fac..6dc1bec 100644 --- a/FastGithub/IGithubMiddleware.cs +++ b/FastGithub/IGithubScanMiddleware.cs @@ -6,7 +6,7 @@ namespace FastGithub /// /// 定义中间件的接口 /// - interface IGithubMiddleware + interface IGithubScanMiddleware { /// /// 执行中间件 diff --git a/FastGithub/Meta.cs b/FastGithub/Meta.cs index 3a558ec..310e01a 100644 --- a/FastGithub/Meta.cs +++ b/FastGithub/Meta.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; using System.Net.Sockets; using System.Text.Json.Serialization; @@ -37,7 +36,7 @@ namespace FastGithub public string[] Dependabot { get; set; } = Array.Empty(); - public IEnumerable ToDomainAddress() + public IEnumerable ToGithubContexts() { foreach (var range in IPRange.From(this.Web).OrderBy(item => item.Size)) { @@ -45,7 +44,7 @@ namespace FastGithub { foreach (var address in range) { - yield return new DomainAddress("github.com", address); + yield return new GithubContext("github.com", address); } } } @@ -56,12 +55,10 @@ namespace FastGithub { foreach (var address in range) { - yield return new DomainAddress("api.github.com", address); + yield return new GithubContext("api.github.com", address); } } } - } - - public record DomainAddress(string Domain, IPAddress Address); + } } } diff --git a/FastGithub/Middlewares/ConcurrentMiddleware.cs b/FastGithub/Middlewares/ConcurrentMiddleware.cs index dbf1012..5a0f38b 100644 --- a/FastGithub/Middlewares/ConcurrentMiddleware.cs +++ b/FastGithub/Middlewares/ConcurrentMiddleware.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace FastGithub.Middlewares { - sealed class ConcurrentMiddleware : IGithubMiddleware + sealed class ConcurrentMiddleware : IGithubScanMiddleware { private readonly SemaphoreSlim semaphoreSlim = new(Environment.ProcessorCount * 4); diff --git a/FastGithub/Middlewares/HttpsScanMiddleware.cs b/FastGithub/Middlewares/HttpsScanMiddleware.cs index bf14162..2eee908 100644 --- a/FastGithub/Middlewares/HttpsScanMiddleware.cs +++ b/FastGithub/Middlewares/HttpsScanMiddleware.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace FastGithub.Middlewares { - sealed class HttpsScanMiddleware : IGithubMiddleware + sealed class HttpsScanMiddleware : IGithubScanMiddleware { private readonly IOptionsMonitor options; private readonly ILogger logger; @@ -50,11 +50,11 @@ namespace FastGithub.Middlewares } catch (TaskCanceledException) { - this.logger.LogInformation($"{context.Domain} {context.Address}连接超时"); + this.logger.LogTrace($"{context.Domain} {context.Address}连接超时"); } catch (Exception ex) { - this.logger.LogInformation($"{context.Domain} {context.Address} {ex.Message}"); + this.logger.LogTrace($"{context.Domain} {context.Address} {ex.Message}"); } } } diff --git a/FastGithub/Middlewares/PortScanMiddleware.cs b/FastGithub/Middlewares/PortScanMiddleware.cs index fdc128f..fff41a9 100644 --- a/FastGithub/Middlewares/PortScanMiddleware.cs +++ b/FastGithub/Middlewares/PortScanMiddleware.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace FastGithub.Middlewares { - sealed class PortScanMiddleware : IGithubMiddleware + sealed class PortScanMiddleware : IGithubScanMiddleware { private const int PORT = 443; private readonly IOptionsMonitor options; @@ -33,7 +33,7 @@ namespace FastGithub.Middlewares } catch (Exception) { - this.logger.LogInformation($"{context.Domain} {context.Address}的{PORT}端口未开放"); + this.logger.LogTrace($"{context.Domain} {context.Address}的{PORT}端口未开放"); } } } diff --git a/FastGithub/Middlewares/ScanOkLogMiddleware.cs b/FastGithub/Middlewares/ScanOkLogMiddleware.cs index bd175bb..0e3984d 100644 --- a/FastGithub/Middlewares/ScanOkLogMiddleware.cs +++ b/FastGithub/Middlewares/ScanOkLogMiddleware.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace FastGithub.Middlewares { - sealed class ScanOkLogMiddleware : IGithubMiddleware + sealed class ScanOkLogMiddleware : IGithubScanMiddleware { private readonly ILogger logger; @@ -17,7 +17,7 @@ namespace FastGithub.Middlewares { if (context.HttpElapsed != null) { - this.logger.LogWarning(context.ToString()); + this.logger.LogInformation(context.ToString()); } return next(); diff --git a/FastGithub/Program.cs b/FastGithub/Program.cs index 2f84cad..c026562 100644 --- a/FastGithub/Program.cs +++ b/FastGithub/Program.cs @@ -28,10 +28,11 @@ namespace FastGithub .ConfigureServices((ctx, services) => { services + .Configure(ctx.Configuration.GetSection("Dns")) .Configure(ctx.Configuration.GetSection("Github")) .AddHttpClient() - .AddTransient() - .AddTransient() + .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() @@ -39,14 +40,16 @@ namespace FastGithub .AddSingleton() .AddSingleton(serviceProvider => { - return new GithubBuilder(serviceProvider, ctx => Task.CompletedTask) + return new GithubScanBuilder(serviceProvider, ctx => Task.CompletedTask) .Use() .Use() .Use() .Use() .Build(); }) - .AddHostedService() + .AddHostedService() + .AddHostedService() + .AddHostedService() ; }); diff --git a/FastGithub/appsettings.json b/FastGithub/appsettings.json index 8e41b4b..8715260 100644 --- a/FastGithub/appsettings.json +++ b/FastGithub/appsettings.json @@ -1,12 +1,17 @@ { + "Dns": { + "UpStream": "114.114.114.114" + }, "Github": { + "ScanAllInterval": "12:00:00", // ɨʱ + "ScanResultInterval": "00:05:00", // ɨʱ "MetaUri": "https://gitee.com/jiulang/fast-github/raw/master/FastGithub/meta.json", // ipԴļuri "PortScanTimeout": "00:00:01", // ˿ɨ賬ʱʱ "HttpsScanTimeout": "00:00:05" // httpsɨ賬ʱʱ }, "Logging": { "LogLevel": { - "Default": "Warning", + "Default": "Information", "System": "Warning", "Microsoft": "Warning" }