diff --git a/FastGithub.Dns/DnsOverHttpsApplicationBuilderExtensions.cs b/FastGithub.Dns/DnsOverHttpsApplicationBuilderExtensions.cs
new file mode 100644
index 0000000..9255fd8
--- /dev/null
+++ b/FastGithub.Dns/DnsOverHttpsApplicationBuilderExtensions.cs
@@ -0,0 +1,23 @@
+using FastGithub.Dns;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace FastGithub
+{
+ ///
+ /// DoH的中间件扩展
+ ///
+ public static class DnsOverHttpsApplicationBuilderExtensions
+ {
+ ///
+ /// 使用DoH的中间件
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseDnsOverHttps(this IApplicationBuilder app)
+ {
+ var middleware = app.ApplicationServices.GetRequiredService();
+ return app.Use(next => context => middleware.InvokeAsync(context, next));
+ }
+ }
+}
diff --git a/FastGithub.Dns/DnsOverHttpsMiddleware.cs b/FastGithub.Dns/DnsOverHttpsMiddleware.cs
new file mode 100644
index 0000000..e7d9b35
--- /dev/null
+++ b/FastGithub.Dns/DnsOverHttpsMiddleware.cs
@@ -0,0 +1,103 @@
+using DNS.Protocol;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace FastGithub.Dns
+{
+ ///
+ /// DoH中间件
+ ///
+ sealed class DnsOverHttpsMiddleware
+ {
+ private static readonly PathString dnsQueryPath = "/dns-query";
+ private const string MEDIA_TYPE = "application/dns-message";
+ private readonly RequestResolver requestResolver;
+
+ ///
+ /// DoH中间件
+ ///
+ ///
+ public DnsOverHttpsMiddleware(RequestResolver requestResolver)
+ {
+ this.requestResolver = requestResolver;
+ }
+
+ ///
+ /// 执行请求
+ ///
+ ///
+ ///
+ ///
+ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
+ {
+ try
+ {
+ var request = await ParseDnsRequestAsync(context.Request);
+ if (request == null)
+ {
+ await next(context);
+ }
+ else
+ {
+ var remoteIPAddress = context.Connection.RemoteIpAddress ?? IPAddress.Loopback;
+ var remoteEndPoint = new IPEndPoint(remoteIPAddress, context.Connection.RemotePort);
+ var remoteEndPointRequest = new RemoteEndPointRequest(request, remoteEndPoint);
+ var response = await this.requestResolver.Resolve(remoteEndPointRequest);
+
+ context.Response.ContentType = MEDIA_TYPE;
+ await context.Response.BodyWriter.WriteAsync(response.ToArray());
+ }
+ }
+ catch (Exception)
+ {
+ await next(context);
+ }
+ }
+
+ ///
+ /// 解析dns请求
+ ///
+ ///
+ ///
+ private static async Task ParseDnsRequestAsync(HttpRequest request)
+ {
+ if (request.Path != dnsQueryPath ||
+ request.Headers.TryGetValue("accept", out var accept) == false ||
+ accept.Contains(MEDIA_TYPE) == false)
+ {
+ return default;
+ }
+
+ if (request.Method == HttpMethods.Get)
+ {
+ if (request.Query.TryGetValue("dns", out var dns) == false)
+ {
+ return default;
+ }
+
+ var dnsRequest = dns.ToString().Replace('-', '+').Replace('_', '/');
+ int mod = dnsRequest.Length % 4;
+ if (mod > 0)
+ {
+ dnsRequest = dnsRequest.PadRight(dnsRequest.Length - mod + 4, '=');
+ }
+
+ var message = Convert.FromBase64String(dnsRequest);
+ return Request.FromArray(message);
+ }
+
+ if (request.Method == HttpMethods.Post && request.ContentType == MEDIA_TYPE)
+ {
+ using var message = new MemoryStream();
+ await request.Body.CopyToAsync(message);
+ return Request.FromArray(message.ToArray());
+ }
+
+ return default;
+ }
+ }
+}
diff --git a/FastGithub.Dns/FastGithub.Dns.csproj b/FastGithub.Dns/FastGithub.Dns.csproj
index ea1d4dc..4bc4ac2 100644
--- a/FastGithub.Dns/FastGithub.Dns.csproj
+++ b/FastGithub.Dns/FastGithub.Dns.csproj
@@ -5,6 +5,7 @@
+
diff --git a/FastGithub.Dns/ServiceCollectionExtensions.cs b/FastGithub.Dns/ServiceCollectionExtensions.cs
index 3f74afc..0d7b51a 100644
--- a/FastGithub.Dns/ServiceCollectionExtensions.cs
+++ b/FastGithub.Dns/ServiceCollectionExtensions.cs
@@ -18,6 +18,7 @@ namespace FastGithub
{
services.TryAddSingleton();
services.TryAddSingleton();
+ services.TryAddSingleton();
services.AddSingleton();
services.AddSingleton();
return services.AddHostedService();
diff --git a/FastGithub/Startup.cs b/FastGithub/Startup.cs
index 2d14eb6..bd0d3e6 100644
--- a/FastGithub/Startup.cs
+++ b/FastGithub/Startup.cs
@@ -45,6 +45,7 @@ namespace FastGithub
public void Configure(IApplicationBuilder app)
{
app.UseRequestLogging();
+ app.UseDnsOverHttps();
app.UseReverseProxy();
app.UseRouting();
app.UseEndpoints(endpoints =>