From 0369fe2750779a17cf381ec9d83d0e3115f6323f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com>
Date: Fri, 16 Jul 2021 11:45:42 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=BF=A1=E4=BB=BBdns?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FastGithub.Configuration/Class1.cs | 8 ++
.../FastGithub.Configuration.csproj | 7 ++
FastGithub.Core/DnsIPEndPoint.cs | 24 ++++
FastGithub.Core/FastGithub.Core.csproj | 8 +-
FastGithub.Core/FastGithubOptions.cs | 49 ++++++++
FastGithub.Core/IMiddleware.cs | 20 ---
FastGithub.Core/IPipelineBuilder.cs | 54 --------
FastGithub.Core/InvokeDelegate.cs | 12 --
FastGithub.Core/OptionsAttribute.cs | 32 -----
FastGithub.Core/PipelineBuilder.cs | 103 ---------------
FastGithub.Core/PipelineBuilderExtensions.cs | 71 -----------
FastGithub.Core/ServiceAttribute.cs | 32 -----
.../ServiceCollectionExtensions.cs | 118 ------------------
FastGithub.Dns.Configuration/Class1.cs | 8 ++
.../FastGithub.Dns.Configuration.csproj | 7 ++
FastGithub.Dns/DnsOptions.cs | 31 -----
FastGithub.Dns/DnsServerHostedService.cs | 52 ++------
.../DnsServiceCollectionExtensions.cs | 9 +-
FastGithub.Dns/FastGihubResolver.cs | 70 +++++++++++
FastGithub.Dns/FastGithub.Dns.csproj | 1 -
FastGithub.Dns/GithubRequestResolver.cs | 102 ---------------
.../FastGithub.ReverseProxy.csproj | 9 +-
.../GithubHttpClientHanlder.cs | 84 +++++++++++++
FastGithub.ReverseProxy/GithubResolver.cs | 64 ++++++++++
...everseProxyApplicationBuilderExtensions.cs | 7 +-
...ReverseProxyServiceCollectionExtensions.cs | 14 +--
FastGithub.sln | 8 +-
FastGithub/Program.cs | 14 +--
FastGithub/appsettings.github.json | 39 ------
FastGithub/appsettings.json | 51 +++-----
30 files changed, 376 insertions(+), 732 deletions(-)
create mode 100644 FastGithub.Configuration/Class1.cs
create mode 100644 FastGithub.Configuration/FastGithub.Configuration.csproj
create mode 100644 FastGithub.Core/DnsIPEndPoint.cs
create mode 100644 FastGithub.Core/FastGithubOptions.cs
delete mode 100644 FastGithub.Core/IMiddleware.cs
delete mode 100644 FastGithub.Core/IPipelineBuilder.cs
delete mode 100644 FastGithub.Core/InvokeDelegate.cs
delete mode 100644 FastGithub.Core/OptionsAttribute.cs
delete mode 100644 FastGithub.Core/PipelineBuilder.cs
delete mode 100644 FastGithub.Core/PipelineBuilderExtensions.cs
delete mode 100644 FastGithub.Core/ServiceAttribute.cs
delete mode 100644 FastGithub.Core/ServiceCollectionExtensions.cs
create mode 100644 FastGithub.Dns.Configuration/Class1.cs
create mode 100644 FastGithub.Dns.Configuration/FastGithub.Dns.Configuration.csproj
delete mode 100644 FastGithub.Dns/DnsOptions.cs
create mode 100644 FastGithub.Dns/FastGihubResolver.cs
delete mode 100644 FastGithub.Dns/GithubRequestResolver.cs
create mode 100644 FastGithub.ReverseProxy/GithubHttpClientHanlder.cs
create mode 100644 FastGithub.ReverseProxy/GithubResolver.cs
delete mode 100644 FastGithub/appsettings.github.json
diff --git a/FastGithub.Configuration/Class1.cs b/FastGithub.Configuration/Class1.cs
new file mode 100644
index 0000000..f26a0e2
--- /dev/null
+++ b/FastGithub.Configuration/Class1.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace FastGithub.Configuration
+{
+ public class Class1
+ {
+ }
+}
diff --git a/FastGithub.Configuration/FastGithub.Configuration.csproj b/FastGithub.Configuration/FastGithub.Configuration.csproj
new file mode 100644
index 0000000..f208d30
--- /dev/null
+++ b/FastGithub.Configuration/FastGithub.Configuration.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net5.0
+
+
+
diff --git a/FastGithub.Core/DnsIPEndPoint.cs b/FastGithub.Core/DnsIPEndPoint.cs
new file mode 100644
index 0000000..640d2e8
--- /dev/null
+++ b/FastGithub.Core/DnsIPEndPoint.cs
@@ -0,0 +1,24 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Net;
+
+namespace FastGithub
+{
+ public class DnsIPEndPoint
+ {
+ [AllowNull]
+ public string Address { get; set; } = IPAddress.Loopback.ToString();
+
+ public int Port { get; set; } = 53;
+
+ public IPEndPoint ToIPEndPoint()
+ {
+ return new IPEndPoint(IPAddress.Parse(this.Address), this.Port);
+ }
+
+ public bool Validate()
+ {
+ return IPAddress.TryParse(this.Address, out var address) &&
+ !(address.Equals(IPAddress.Loopback) && this.Port == 53);
+ }
+ }
+}
diff --git a/FastGithub.Core/FastGithub.Core.csproj b/FastGithub.Core/FastGithub.Core.csproj
index e89fd2b..8c0b46e 100644
--- a/FastGithub.Core/FastGithub.Core.csproj
+++ b/FastGithub.Core/FastGithub.Core.csproj
@@ -3,10 +3,6 @@
net5.0
FastGithub
-
-
-
-
-
-
+
+
diff --git a/FastGithub.Core/FastGithubOptions.cs b/FastGithub.Core/FastGithubOptions.cs
new file mode 100644
index 0000000..148f04d
--- /dev/null
+++ b/FastGithub.Core/FastGithubOptions.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace FastGithub
+{
+ public class FastGithubOptions
+ {
+ private DomainMatch[]? domainMatches;
+
+ public DnsIPEndPoint TrustedDns { get; set; } = new DnsIPEndPoint { Address = "127.0.0.1", Port = 5533 };
+
+ public DnsIPEndPoint UntrustedDns { get; set; } = new DnsIPEndPoint { Address = "114.1114.114.114", Port = 53 };
+
+ public HashSet DomainMatches { get; set; } = new();
+
+ public bool IsMatch(string domain)
+ {
+ if (this.domainMatches == null)
+ {
+ this.domainMatches = this.DomainMatches.Select(item => new DomainMatch(item)).ToArray();
+ }
+ return this.domainMatches.Any(item => item.IsMatch(domain));
+ }
+
+ private class DomainMatch
+ {
+ private readonly Regex regex;
+ private readonly string value;
+
+ public DomainMatch(string value)
+ {
+ this.value = value;
+ var pattern = Regex.Escape(value).Replace(@"\*", ".*");
+ this.regex = new Regex($"^{pattern}$");
+ }
+
+ public bool IsMatch(string domain)
+ {
+ return this.regex.IsMatch(domain);
+ }
+
+ public override string ToString()
+ {
+ return this.value;
+ }
+ }
+ }
+}
diff --git a/FastGithub.Core/IMiddleware.cs b/FastGithub.Core/IMiddleware.cs
deleted file mode 100644
index 5eeb445..0000000
--- a/FastGithub.Core/IMiddleware.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using System.Threading.Tasks;
-
-namespace FastGithub
-{
- ///
- /// 定义中间件的接口
- ///
- ///
- public interface IMiddleware
- {
- ///
- /// 执行中间件
- ///
- /// 上下文
- /// 下一个中间件
- ///
- Task InvokeAsync(TContext context, Func next);
- }
-}
diff --git a/FastGithub.Core/IPipelineBuilder.cs b/FastGithub.Core/IPipelineBuilder.cs
deleted file mode 100644
index 2c68118..0000000
--- a/FastGithub.Core/IPipelineBuilder.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.Threading.Tasks;
-
-namespace FastGithub
-{
- ///
- /// 定义中间件管道创建者的接口
- ///
- /// 中间件上下文
- public interface IPipelineBuilder
- {
- ///
- /// 获取服务提供者
- ///
- IServiceProvider AppServices { get; }
-
- ///
- /// 使用中间件
- ///
- ///
- ///
- ///
- ///
- IPipelineBuilder Use() where TMiddleware : class, IMiddleware;
-
- ///
- /// 使用中间件
- ///
- ///
- ///
- ///
- ///
- IPipelineBuilder Use(Func, Task> middleware);
-
- ///
- /// 使用中间件
- ///
- /// 中间件
- ///
- IPipelineBuilder Use(Func, InvokeDelegate> middleware);
-
- ///
- /// 创建所有中间件执行处理者
- ///
- ///
- InvokeDelegate Build();
-
- ///
- /// 使用默认配制创建新的PipelineBuilder
- ///
- ///
- IPipelineBuilder New();
- }
-}
diff --git a/FastGithub.Core/InvokeDelegate.cs b/FastGithub.Core/InvokeDelegate.cs
deleted file mode 100644
index 985d433..0000000
--- a/FastGithub.Core/InvokeDelegate.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Threading.Tasks;
-
-namespace FastGithub
-{
- ///
- /// 表示所有中间件执行委托
- ///
- /// 中间件上下文类型
- /// 中间件上下文
- ///
- public delegate Task InvokeDelegate(TContext context);
-}
diff --git a/FastGithub.Core/OptionsAttribute.cs b/FastGithub.Core/OptionsAttribute.cs
deleted file mode 100644
index a123be5..0000000
--- a/FastGithub.Core/OptionsAttribute.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-
-namespace FastGithub
-{
- ///
- /// 表示选项特性
- ///
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class OptionsAttribute : Attribute
- {
- ///
- /// 获取配置节点名称
- ///
- public string? SessionKey { get; }
-
- ///
- /// 选项特性
- ///
- public OptionsAttribute()
- {
- }
-
- ///
- /// 选项特性
- ///
- /// 配置节点名称
- public OptionsAttribute(string sessionKey)
- {
- this.SessionKey = sessionKey;
- }
- }
-}
diff --git a/FastGithub.Core/PipelineBuilder.cs b/FastGithub.Core/PipelineBuilder.cs
deleted file mode 100644
index 8e0f017..0000000
--- a/FastGithub.Core/PipelineBuilder.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-
-namespace FastGithub
-{
- ///
- /// 表示中间件创建者
- ///
- public class PipelineBuilder : IPipelineBuilder
- {
- private readonly InvokeDelegate completedHandler;
- private readonly List, InvokeDelegate>> middlewares = new();
-
- ///
- /// 获取服务提供者
- ///
- public IServiceProvider AppServices { get; }
-
- ///
- /// 中间件创建者
- ///
- ///
- public PipelineBuilder(IServiceProvider appServices)
- : this(appServices, context => Task.CompletedTask)
- {
- }
-
- ///
- /// 中间件创建者
- ///
- ///
- /// 完成执行内容处理者
- public PipelineBuilder(IServiceProvider appServices, InvokeDelegate completedHandler)
- {
- this.AppServices = appServices;
- this.completedHandler = completedHandler;
- }
-
-
- ///
- /// 使用中间件
- ///
- ///
- ///
- ///
- ///
- public IPipelineBuilder Use() where TMiddleware : class, IMiddleware
- {
- var middleware = this.AppServices.GetRequiredService();
- return this.Use(middleware.InvokeAsync);
- }
-
- ///
- /// 使用中间件
- ///
- ///
- ///
- ///
- ///
- public IPipelineBuilder Use(Func, Task> middleware)
- {
- return this.Use(next => context => middleware(context, () => next(context)));
- }
-
- ///
- /// 使用中间件
- ///
- ///
- ///
- public IPipelineBuilder Use(Func, InvokeDelegate> middleware)
- {
- this.middlewares.Add(middleware);
- return this;
- }
-
-
- ///
- /// 创建所有中间件执行处理者
- ///
- ///
- public InvokeDelegate Build()
- {
- var handler = this.completedHandler;
- for (var i = this.middlewares.Count - 1; i >= 0; i--)
- {
- handler = this.middlewares[i](handler);
- }
- return handler;
- }
-
-
- ///
- /// 使用默认配制创建新的PipelineBuilder
- ///
- ///
- public IPipelineBuilder New()
- {
- return new PipelineBuilder(this.AppServices, this.completedHandler);
- }
- }
-}
\ No newline at end of file
diff --git a/FastGithub.Core/PipelineBuilderExtensions.cs b/FastGithub.Core/PipelineBuilderExtensions.cs
deleted file mode 100644
index 67a585b..0000000
--- a/FastGithub.Core/PipelineBuilderExtensions.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-
-namespace FastGithub
-{
- ///
- /// 中间件创建者扩展
- ///
- public static class PipelineBuilderExtensions
- {
- ///
- /// 中断执行中间件
- ///
- ///
- ///
- /// 处理者
- ///
- public static IPipelineBuilder Run(this IPipelineBuilder builder, InvokeDelegate handler)
- {
- return builder.Use(_ => handler);
- }
-
- ///
- /// 条件中间件
- ///
- ///
- ///
- ///
- ///
- ///
- public static IPipelineBuilder When(this IPipelineBuilder builder, Func predicate, InvokeDelegate handler)
- {
- return builder.Use(next => async context =>
- {
- if (predicate.Invoke(context) == true)
- {
- await handler.Invoke(context);
- }
- else
- {
- await next(context);
- }
- });
- }
-
-
- ///
- /// 条件中间件
- ///
- ///
- ///
- ///
- ///
- ///
- public static IPipelineBuilder When(this IPipelineBuilder builder, Func predicate, Action> configureAction)
- {
- return builder.Use(next => async context =>
- {
- if (predicate.Invoke(context) == true)
- {
- var branchBuilder = builder.New();
- configureAction(branchBuilder);
- await branchBuilder.Build().Invoke(context);
- }
- else
- {
- await next(context);
- }
- });
- }
- }
-}
diff --git a/FastGithub.Core/ServiceAttribute.cs b/FastGithub.Core/ServiceAttribute.cs
deleted file mode 100644
index be8f59d..0000000
--- a/FastGithub.Core/ServiceAttribute.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using System;
-
-namespace FastGithub
-{
- ///
- /// 表示服务特性
- ///
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
- public sealed class ServiceAttribute : Attribute
- {
- ///
- /// 获取服务的生命周期
- ///
- public ServiceLifetime Lifetime { get; }
-
- ///
- /// 获取或设置注册的服务类型
- /// 为null直接使得当前类型
- ///
- public Type? ServiceType { get; set; }
-
- ///
- /// 将当前实现类型注册为服务的特性
- ///
- /// 生命周期
- public ServiceAttribute(ServiceLifetime lifetime)
- {
- Lifetime = lifetime;
- }
- }
-}
diff --git a/FastGithub.Core/ServiceCollectionExtensions.cs b/FastGithub.Core/ServiceCollectionExtensions.cs
deleted file mode 100644
index 7b0e744..0000000
--- a/FastGithub.Core/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using System;
-using System.Linq;
-using System.Reflection;
-
-namespace FastGithub
-{
- ///
- /// 服务注册扩展
- ///
- public static class ServiceCollectionExtensions
- {
- ///
- /// 注册程序集下所有服务下选项
- ///
- ///
- /// 配置
- ///
- public static IServiceCollection AddServiceAndOptions(this IServiceCollection services, Assembly assembly, IConfiguration configuration)
- {
- services.AddAttributeServices(assembly);
- services.AddAttributeOptions(assembly, configuration);
-
- return services;
- }
-
- ///
- /// 添加程序集下ServiceAttribute标记的服务
- ///
- ///
- ///
- ///
- private static IServiceCollection AddAttributeServices(this IServiceCollection services, Assembly assembly)
- {
- var implTypes = assembly
- .GetTypes()
- .Where(item => item.IsClass && item.IsAbstract == false)
- .ToArray();
-
- foreach (var implType in implTypes)
- {
- var attributes = implType.GetCustomAttributes(false);
- foreach (var attr in attributes)
- {
- var serviceType = attr.ServiceType ?? implType;
- if (services.Any(item => item.ServiceType == serviceType && item.ImplementationType == implType) == false)
- {
- var descriptor = ServiceDescriptor.Describe(serviceType, implType, attr.Lifetime);
- services.Add(descriptor);
- }
- }
- }
- return services;
- }
-
-
- ///
- /// 添加程序集下OptionsAttribute标记的服务
- ///
- ///
- ///
- ///
- private static IServiceCollection AddAttributeOptions(this IServiceCollection services, Assembly assembly, IConfiguration configuration)
- {
- foreach (var optionsType in assembly.GetTypes())
- {
- var optionsAttribute = optionsType.GetCustomAttribute();
- if (optionsAttribute != null)
- {
- var key = optionsAttribute.SessionKey ?? optionsType.Name;
- var section = configuration.GetSection(key);
- OptionsBinder.Create(services, optionsType).Bind(section);
- }
- }
- return services;
- }
-
- ///
- /// options绑定器
- ///
- private abstract class OptionsBinder
- {
- public abstract void Bind(IConfiguration configuration);
-
- ///
- /// 创建OptionsBinder实例
- ///
- ///
- ///
- ///
- public static OptionsBinder Create(IServiceCollection services, Type optionsType)
- {
- var binderType = typeof(OptionsBinderImpl<>).MakeGenericType(optionsType);
- var binder = Activator.CreateInstance(binderType, new object[] { services });
-
- return binder is OptionsBinder optionsBinder
- ? optionsBinder
- : throw new TypeInitializationException(binderType.FullName, null);
- }
-
- private class OptionsBinderImpl : OptionsBinder where TOptions : class
- {
- private readonly IServiceCollection services;
-
- public OptionsBinderImpl(IServiceCollection services)
- {
- this.services = services;
- }
-
- public override void Bind(IConfiguration configuration)
- {
- this.services.AddOptions().Bind(configuration);
- }
- }
- }
- }
-}
diff --git a/FastGithub.Dns.Configuration/Class1.cs b/FastGithub.Dns.Configuration/Class1.cs
new file mode 100644
index 0000000..a32a9ef
--- /dev/null
+++ b/FastGithub.Dns.Configuration/Class1.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace FastGithub.Dns.Configuration
+{
+ public class Class1
+ {
+ }
+}
diff --git a/FastGithub.Dns.Configuration/FastGithub.Dns.Configuration.csproj b/FastGithub.Dns.Configuration/FastGithub.Dns.Configuration.csproj
new file mode 100644
index 0000000..f208d30
--- /dev/null
+++ b/FastGithub.Dns.Configuration/FastGithub.Dns.Configuration.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net5.0
+
+
+
diff --git a/FastGithub.Dns/DnsOptions.cs b/FastGithub.Dns/DnsOptions.cs
deleted file mode 100644
index f34f524..0000000
--- a/FastGithub.Dns/DnsOptions.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-
-namespace FastGithub.Dns
-{
- ///
- /// dns服务选项
- ///
- [Options("Dns")]
- sealed class DnsOptions
- {
- ///
- /// 获取或设置上游ip地址
- ///
- public string UpStream { get; set; } = "114.114.114.114";
-
- ///
- /// 获取或设置github相关域名的ip存活时长
- ///
- public TimeSpan GithubTTL { get; set; } = TimeSpan.FromMinutes(10d);
-
- ///
- /// 是否设置本机使用此dns
- ///
- public bool SetToLocalMachine { get; set; } = true;
-
- ///
- /// 是否使用反向代理访问github
- ///
- public bool UseGithubReverseProxy { get; set; } = true;
- }
-}
diff --git a/FastGithub.Dns/DnsServerHostedService.cs b/FastGithub.Dns/DnsServerHostedService.cs
index 499eebc..aa2ce82 100644
--- a/FastGithub.Dns/DnsServerHostedService.cs
+++ b/FastGithub.Dns/DnsServerHostedService.cs
@@ -1,5 +1,4 @@
-using DNS.Client.RequestResolver;
-using DNS.Protocol;
+using DNS.Protocol;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -18,15 +17,14 @@ namespace FastGithub.Dns
{
private const int SIO_UDP_CONNRESET = unchecked((int)0x9800000C);
- private readonly IRequestResolver requestResolver;
- private readonly IOptions options;
+ private readonly FastGihubResolver fastGihubResolver;
+ private readonly IOptions options;
private readonly ILogger logger;
private readonly Socket socket = new(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
private readonly byte[] buffer = new byte[ushort.MaxValue];
private IPAddress[]? dnsAddresses;
-
///
/// dns后台服务
///
@@ -34,15 +32,13 @@ namespace FastGithub.Dns
///
///
public DnsServerHostedService(
- GithubRequestResolver githubRequestResolver,
- IOptions options,
+ FastGihubResolver fastGihubResolver,
+ IOptions options,
ILogger logger)
{
+ this.fastGihubResolver = fastGihubResolver;
this.options = options;
this.logger = logger;
-
- var upStream = IPAddress.Parse(options.Value.UpStream);
- this.requestResolver = new CompositeRequestResolver(upStream, githubRequestResolver);
}
///
@@ -59,7 +55,7 @@ namespace FastGithub.Dns
}
this.logger.LogInformation("dns服务启动成功");
- var upStream = IPAddress.Parse(options.Value.UpStream);
+ var upStream = IPAddress.Parse(options.Value.UntrustedDns.Address);
this.dnsAddresses = this.SetNameServers(IPAddress.Loopback, upStream);
return base.StartAsync(cancellationToken);
}
@@ -93,7 +89,7 @@ namespace FastGithub.Dns
{
var request = Request.FromArray(datas);
var remoteRequest = new RemoteRequest(request, remoteEndPoint);
- var response = await this.requestResolver.Resolve(remoteRequest, cancellationToken);
+ var response = await this.fastGihubResolver.Resolve(remoteRequest, cancellationToken);
await this.socket.SendToAsync(response.ToArray(), SocketFlags.None, remoteEndPoint);
}
catch (Exception ex)
@@ -126,7 +122,7 @@ namespace FastGithub.Dns
///
private IPAddress[]? SetNameServers(params IPAddress[] nameServers)
{
- if (this.options.Value.SetToLocalMachine && OperatingSystem.IsWindows())
+ if (OperatingSystem.IsWindows())
{
try
{
@@ -140,34 +136,12 @@ namespace FastGithub.Dns
this.logger.LogWarning($"设置本机dns失败:{ex.Message}");
}
}
+ else
+ {
+ this.logger.LogError("不支持自动为本机设备设置dns值");
+ }
return default;
}
-
- private class CompositeRequestResolver : IRequestResolver
- {
- private readonly IRequestResolver upStreamResolver;
- private readonly IRequestResolver[] customResolvers;
-
- public CompositeRequestResolver(IPAddress upStream, params IRequestResolver[] customResolvers)
- {
- this.upStreamResolver = new UdpRequestResolver(new IPEndPoint(upStream, 53));
- this.customResolvers = customResolvers;
- }
-
- public async Task Resolve(IRequest request, CancellationToken cancellationToken = default)
- {
- foreach (IRequestResolver resolver in customResolvers)
- {
- var response = await resolver.Resolve(request, cancellationToken);
- if (response.AnswerRecords.Count > 0)
- {
- return response;
- }
- }
-
- return await this.upStreamResolver.Resolve(request, cancellationToken);
- }
- }
}
}
diff --git a/FastGithub.Dns/DnsServiceCollectionExtensions.cs b/FastGithub.Dns/DnsServiceCollectionExtensions.cs
index 715480f..2ad2699 100644
--- a/FastGithub.Dns/DnsServiceCollectionExtensions.cs
+++ b/FastGithub.Dns/DnsServiceCollectionExtensions.cs
@@ -1,5 +1,4 @@
using FastGithub.Dns;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace FastGithub
@@ -12,14 +11,12 @@ namespace FastGithub
///
/// 注册github的dns服务
///
- ///
- /// 配置
+ ///
///
- public static IServiceCollection AddGithubDns(this IServiceCollection services, IConfiguration configuration)
+ public static IServiceCollection AddGithubDns(this IServiceCollection services)
{
- var assembly = typeof(DnsServiceCollectionExtensions).Assembly;
return services
- .AddServiceAndOptions(assembly, configuration)
+ .AddSingleton()
.AddHostedService();
}
}
diff --git a/FastGithub.Dns/FastGihubResolver.cs b/FastGithub.Dns/FastGihubResolver.cs
new file mode 100644
index 0000000..0520069
--- /dev/null
+++ b/FastGithub.Dns/FastGihubResolver.cs
@@ -0,0 +1,70 @@
+using DNS.Client.RequestResolver;
+using DNS.Protocol;
+using DNS.Protocol.ResourceRecords;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Linq;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FastGithub.Dns
+{
+ ///
+ /// 反向代理解析器
+ ///
+ sealed class FastGihubResolver : IRequestResolver
+ {
+ private readonly IRequestResolver untrustedDnsResolver;
+ private readonly IOptionsMonitor options;
+ private readonly ILogger logger;
+
+ ///
+ /// github相关域名解析器
+ ///
+ ///
+ ///
+ public FastGihubResolver(
+ IOptionsMonitor options,
+ ILogger logger)
+ {
+ this.options = options;
+ this.logger = logger;
+ this.untrustedDnsResolver = new UdpRequestResolver(options.CurrentValue.UntrustedDns.ToIPEndPoint());
+ }
+
+ ///
+ /// 解析域名
+ ///
+ ///
+ ///
+ ///
+ public async Task Resolve(IRequest request, CancellationToken cancellationToken = default)
+ {
+ var response = Response.FromRequest(request);
+ if (request is not RemoteRequest remoteRequest)
+ {
+ return response;
+ }
+
+ var question = request.Questions.FirstOrDefault();
+ if (question == null || question.Type != RecordType.A)
+ {
+ return response;
+ }
+
+ var domain = question.Name;
+ if (this.options.CurrentValue.IsMatch(domain.ToString()) == true)
+ {
+ var localAddress = remoteRequest.GetLocalAddress() ?? IPAddress.Loopback;
+ var record = new IPAddressResourceRecord(domain, localAddress, TimeSpan.FromMinutes(1d));
+ this.logger.LogInformation($"[{domain}->{localAddress}]");
+ response.AnswerRecords.Add(record);
+ return response;
+ }
+
+ return await this.untrustedDnsResolver.Resolve(request, cancellationToken);
+ }
+ }
+}
diff --git a/FastGithub.Dns/FastGithub.Dns.csproj b/FastGithub.Dns/FastGithub.Dns.csproj
index e2d2214..efd748e 100644
--- a/FastGithub.Dns/FastGithub.Dns.csproj
+++ b/FastGithub.Dns/FastGithub.Dns.csproj
@@ -6,6 +6,5 @@
-
diff --git a/FastGithub.Dns/GithubRequestResolver.cs b/FastGithub.Dns/GithubRequestResolver.cs
deleted file mode 100644
index 221f336..0000000
--- a/FastGithub.Dns/GithubRequestResolver.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using DNS.Client.RequestResolver;
-using DNS.Protocol;
-using DNS.Protocol.ResourceRecords;
-using FastGithub.Scanner;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using System;
-using System.Linq;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace FastGithub.Dns
-{
- ///
- /// github相关域名解析器
- ///
- [Service(ServiceLifetime.Singleton)]
- sealed class GithubRequestResolver : IRequestResolver
- {
- private readonly IGithubResolver githubResolver;
- private readonly IOptionsMonitor options;
- private readonly ILogger logger;
-
- ///
- /// github相关域名解析器
- ///
- ///
- ///
- ///
- public GithubRequestResolver(
- IGithubResolver githubResolver,
- IOptionsMonitor options,
- ILogger logger)
- {
- this.githubResolver = githubResolver;
- this.options = options;
- this.logger = logger;
- }
-
- ///
- /// 解析域名
- ///
- ///
- ///
- ///
- public Task Resolve(IRequest request, CancellationToken cancellationToken = default)
- {
- IResponse response = Response.FromRequest(request);
- if (request is not RemoteRequest remoteRequest)
- {
- return Task.FromResult(response);
- }
-
- var question = request.Questions.FirstOrDefault();
- if (question == null || question.Type != RecordType.A)
- {
- return Task.FromResult(response);
- }
-
- var domain = question.Name;
- if (this.githubResolver.IsSupported(domain.ToString()) == false)
- {
- return Task.FromResult(response);
- }
-
- var record = this.GetAnswerRecord(remoteRequest, domain);
- if (record != null)
- {
- this.logger.LogInformation($"[{domain}->{record.IPAddress}]");
- response.AnswerRecords.Add(record);
- }
-
- return Task.FromResult(response);
- }
-
- ///
- /// 获取答案
- ///
- ///
- ///
- ///
- private IPAddressResourceRecord? GetAnswerRecord(RemoteRequest request, Domain domain)
- {
- if (this.options.CurrentValue.UseGithubReverseProxy == true)
- {
- var localAddress = request.GetLocalAddress() ?? IPAddress.Loopback;
- return new IPAddressResourceRecord(domain, localAddress, TimeSpan.FromMinutes(1d));
- }
-
- var githubAddress = this.githubResolver.Resolve(domain.ToString());
- if (githubAddress == null)
- {
- return default;
- }
-
- var ttl = this.options.CurrentValue.GithubTTL;
- return new IPAddressResourceRecord(domain, githubAddress, ttl);
- }
- }
-}
diff --git a/FastGithub.ReverseProxy/FastGithub.ReverseProxy.csproj b/FastGithub.ReverseProxy/FastGithub.ReverseProxy.csproj
index 818a7d8..15b19a6 100644
--- a/FastGithub.ReverseProxy/FastGithub.ReverseProxy.csproj
+++ b/FastGithub.ReverseProxy/FastGithub.ReverseProxy.csproj
@@ -3,15 +3,16 @@
net5.0
-
+
-
+
+
-
+
-
+
diff --git a/FastGithub.ReverseProxy/GithubHttpClientHanlder.cs b/FastGithub.ReverseProxy/GithubHttpClientHanlder.cs
new file mode 100644
index 0000000..2894191
--- /dev/null
+++ b/FastGithub.ReverseProxy/GithubHttpClientHanlder.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Net.Http;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FastGithub.ReverseProxy
+{
+ ///
+ /// 适用于请求github的HttpClientHandler
+ ///
+ class GithubHttpClientHanlder : DelegatingHandler
+ {
+ private readonly GithubResolver githubResolver;
+
+ ///
+ /// 请求github的HttpClientHandler
+ ///
+ ///
+ public GithubHttpClientHanlder(GithubResolver githubResolver)
+ {
+ this.githubResolver = githubResolver;
+ this.InnerHandler = CreateNoneSniHttpHandler();
+ }
+
+ ///
+ /// 创建无Sni发送的httpHandler
+ ///
+ ///
+ private static HttpMessageHandler CreateNoneSniHttpHandler()
+ {
+ return new SocketsHttpHandler
+ {
+ Proxy = null,
+ UseProxy = false,
+ AllowAutoRedirect = false,
+ ConnectCallback = async (ctx, ct) =>
+ {
+ var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
+ await socket.ConnectAsync(ctx.DnsEndPoint, ct);
+ var stream = new NetworkStream(socket, ownsSocket: true);
+ if (ctx.InitialRequestMessage.Headers.Host == null)
+ {
+ return stream;
+ }
+
+ var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
+ await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
+ {
+ TargetHost = string.Empty,
+ RemoteCertificateValidationCallback = delegate { return true; }
+ }, ct);
+ return sslStream;
+ }
+ };
+ }
+
+
+ ///
+ /// 替换github域名为ip
+ ///
+ ///
+ ///
+ ///
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ var uri = request.RequestUri;
+ if (uri != null && uri.HostNameType == UriHostNameType.Dns)
+ {
+ var address = await this.githubResolver.ResolveAsync(uri.Host, cancellationToken);
+ var builder = new UriBuilder(uri)
+ {
+ Scheme = Uri.UriSchemeHttp,
+ Host = address.ToString(),
+ Port = 443
+ };
+ request.RequestUri = builder.Uri;
+ request.Headers.Host = uri.Host;
+ }
+ return await base.SendAsync(request, cancellationToken);
+ }
+ }
+}
diff --git a/FastGithub.ReverseProxy/GithubResolver.cs b/FastGithub.ReverseProxy/GithubResolver.cs
new file mode 100644
index 0000000..e08474b
--- /dev/null
+++ b/FastGithub.ReverseProxy/GithubResolver.cs
@@ -0,0 +1,64 @@
+using DNS.Client;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FastGithub.ReverseProxy
+{
+ ///
+ /// github解析器
+ ///
+ sealed class GithubResolver
+ {
+ private readonly IMemoryCache memoryCache;
+ private readonly IOptionsMonitor options;
+ private readonly ILogger logger;
+
+ ///
+ /// github解析器
+ ///
+ ///
+ public GithubResolver(
+ IMemoryCache memoryCache,
+ IOptionsMonitor options,
+ ILogger logger)
+ {
+ this.memoryCache = memoryCache;
+ this.options = options;
+ this.logger = logger;
+ }
+
+ ///
+ /// 解析指定的域名
+ ///
+ ///
+ ///
+ public async Task ResolveAsync(string domain, CancellationToken cancellationToken)
+ {
+ // 缓存,避免做不必要的并发查询
+ var key = $"domain:{domain}";
+ var address = await this.memoryCache.GetOrCreateAsync(key, async e =>
+ {
+ e.SetAbsoluteExpiration(TimeSpan.FromMinutes(2d));
+ var dnsClient = new DnsClient(this.options.CurrentValue.TrustedDns.ToIPEndPoint());
+ var addresses = await dnsClient.Lookup(domain, DNS.Protocol.RecordType.A, cancellationToken);
+ return addresses?.FirstOrDefault();
+ });
+
+ if (address == null)
+ {
+ var message = $"无法解析{domain}的ip";
+ this.logger.LogWarning(message);
+ throw new HttpRequestException(message);
+ }
+ this.logger.LogInformation($"[{domain}->{address}]");
+ return address;
+ }
+ }
+}
diff --git a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs
index 28eb2f9..5b565e8 100644
--- a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs
+++ b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs
@@ -1,7 +1,8 @@
-using FastGithub.Scanner;
+using FastGithub.ReverseProxy;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
using System.Net.Http;
using Yarp.ReverseProxy.Forwarder;
@@ -21,12 +22,12 @@ namespace FastGithub
{
var httpForwarder = app.ApplicationServices.GetRequiredService();
var httpClientHanlder = app.ApplicationServices.GetRequiredService();
- var githubResolver = app.ApplicationServices.GetRequiredService();
+ var options = app.ApplicationServices.GetRequiredService>();
app.Use(next => async context =>
{
var host = context.Request.Host.Host;
- if (githubResolver.IsSupported(host) == false)
+ if (options.CurrentValue.IsMatch(host) == false)
{
await context.Response.WriteAsJsonAsync(new { message = $"不支持以{host}访问" });
}
diff --git a/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs
index df95e9e..e1e5a05 100644
--- a/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs
+++ b/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Configuration;
+using FastGithub.ReverseProxy;
using Microsoft.Extensions.DependencyInjection;
namespace FastGithub
@@ -11,15 +11,15 @@ namespace FastGithub
///
/// gitub反向代理
///
- ///
- ///
+ ///
///
- public static IServiceCollection AddGithubReverseProxy(this IServiceCollection services, IConfiguration configuration)
+ public static IServiceCollection AddGithubReverseProxy(this IServiceCollection services)
{
- var assembly = typeof(ReverseProxyServiceCollectionExtensions).Assembly;
return services
- .AddServiceAndOptions(assembly, configuration)
- .AddHttpForwarder();
+ .AddMemoryCache()
+ .AddHttpForwarder()
+ .AddSingleton()
+ .AddTransient();
}
}
}
diff --git a/FastGithub.sln b/FastGithub.sln
index 6923f45..0c59484 100644
--- a/FastGithub.sln
+++ b/FastGithub.sln
@@ -9,11 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Core", "FastGith
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Dns", "FastGithub.Dns\FastGithub.Dns.csproj", "{43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Scanner", "FastGithub.Scanner\FastGithub.Scanner.csproj", "{7F24CD2F-07C0-4002-A534-80688DE95ECF}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.Upgrade", "FastGithub.Upgrade\FastGithub.Upgrade.csproj", "{8239A077-A84C-4FDF-A204-02A2DE4243F3}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastGithub.ReverseProxy", "FastGithub.ReverseProxy\FastGithub.ReverseProxy.csproj", "{28326D0F-B0FB-4B6B-A65A-C69ACB72CAD8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.ReverseProxy", "FastGithub.ReverseProxy\FastGithub.ReverseProxy.csproj", "{28326D0F-B0FB-4B6B-A65A-C69ACB72CAD8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -33,10 +31,6 @@ Global
{43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{43FF9C79-51D5-4037-AA0B-CA3006E2A7E6}.Release|Any CPU.Build.0 = Release|Any CPU
- {7F24CD2F-07C0-4002-A534-80688DE95ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7F24CD2F-07C0-4002-A534-80688DE95ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7F24CD2F-07C0-4002-A534-80688DE95ECF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7F24CD2F-07C0-4002-A534-80688DE95ECF}.Release|Any CPU.Build.0 = Release|Any CPU
{8239A077-A84C-4FDF-A204-02A2DE4243F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8239A077-A84C-4FDF-A204-02A2DE4243F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8239A077-A84C-4FDF-A204-02A2DE4243F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/FastGithub/Program.cs b/FastGithub/Program.cs
index fa4ece1..e827f73 100644
--- a/FastGithub/Program.cs
+++ b/FastGithub/Program.cs
@@ -1,5 +1,5 @@
using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace FastGithub
@@ -30,16 +30,14 @@ namespace FastGithub
{
c.ValidateOnBuild = false;
})
- .ConfigureAppConfiguration(c =>
- {
- c.AddJsonFile("appsettings.github.json", optional: true);
- })
.ConfigureServices((ctx, services) =>
{
services.AddAppUpgrade();
- services.AddGithubDns(ctx.Configuration);
- services.AddGithubReverseProxy(ctx.Configuration);
- services.AddGithubScanner(ctx.Configuration);
+ services.AddGithubDns();
+ services.AddGithubReverseProxy();
+ services.AddOptions()
+ .Bind(ctx.Configuration.GetSection(nameof(FastGithub)))
+ .Validate(opt => opt.TrustedDns.Validate() && opt.UntrustedDns.Validate(), "无效的Dns配置");
})
.ConfigureWebHostDefaults(web =>
{
diff --git a/FastGithub/appsettings.github.json b/FastGithub/appsettings.github.json
deleted file mode 100644
index b3c21c9..0000000
--- a/FastGithub/appsettings.github.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "Lookup": { // ip
- "Domains": [ // ҵgithubҪ
- "github.com",
- "api.github.com",
- "collector.githubapp.com",
- "github.githubassets.com",
- "raw.githubusercontent.com",
- "avatars.githubusercontent.com",
- "favicons.githubusercontent.com"
- ]
- },
- "Scan": {
- "HttpsScan": {
- "Rules": { // ɨȱʧĬHEADĸ·
- "github.com": {
- "Method": "HEAD",
- "Path": "/xljiulang/FastGithub"
- },
- "github.githubassets.com": {
- "Method": "HEAD",
- "Path": "/favicons/favicon.png"
- },
- "raw.githubusercontent.com": {
- "Method": "HEAD",
- "Path": "/xljiulang/FastGithub/master/README.md"
- },
- "avatars.githubusercontent.com": {
- "Method": "HEAD",
- "Path": "/u/8308014?s=40&v=4"
- },
- "favicons.githubusercontent.com": {
- "Method": "HEAD",
- "Path": "/github.com"
- }
- }
- }
- }
-}
diff --git a/FastGithub/appsettings.json b/FastGithub/appsettings.json
index 2d20684..8adf40c 100644
--- a/FastGithub/appsettings.json
+++ b/FastGithub/appsettings.json
@@ -1,43 +1,20 @@
{
- "Dns": {
- "UpStream": "114.114.114.114", // dns
- "GithubTTL": "00:05:00", // githubĴʱ
- "SetToLocalMachine": true, // Ƿñʹôdns(֧windows)
- "UseGithubReverseProxy": true // Ƿʹ÷githubԽӱõ⣬ͻҪװFastGithub.cer֤
- },
- "Lookup": { // ip
- "IPAddressComProvider": {
- "Enable": true // Ǵôaddress.comip
+ "FastGithub": {
+ "TrustedDns": {
+ "Address": "127.0.0.1",
+ "Port": 5533
},
- "GithubMetaProvider": {
- "Enable": true, // Ƿgithubȡipб
- "MetaUri": "https://gitee.com/jiulang/fast-github/raw/master/FastGithub/meta.json"
+ "UnTrustedDns": {
+ "Address": "114.114.114.114",
+ "Port": 53
},
- "PublicDnsProvider": {
- "Enable": true, // ǷҪdnsip
- "Timeout": "00:00:00.200", // dnsѯʱʱ
- "Dnss": [ // dnsб
- "1.2.4.8",
- "8.8.8.8",
- "223.5.5.5",
- "123.125.81.6",
- "119.29.29.29",
- "208.67.220.220",
- "114.114.114.114"
- ]
- }
- },
- "Scan": {
- "FullScanInterval": "02:00:00", // ɨʱ
- "ResultScanInterval": "00:01:00", // ɨʱ
- "TcpScan": {
- "Timeout": "00:00:01", // tcpɨ賬ʱʱ
- "CacheExpiration": "00:30:00" // ɨʱ
- },
- "HttpsScan": {
- "Timeout": "00:00:05", // httpsɨ賬ʱʱ
- "ConnectionClose": false // Ƿʹhttps
- }
+ "DomainMatches": [
+ "github.com",
+ "*.github.com",
+ "*.githubapp.com",
+ "*.githubassets.com",
+ "*.githubusercontent.com"
+ ]
},
"Logging": {
"LogLevel": {