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 =>