增加DnsOverHttps服务

This commit is contained in:
老九 2021-08-25 20:38:44 +08:00
parent a9d3ffbfb5
commit 0f94f118ca
5 changed files with 129 additions and 0 deletions

View File

@ -0,0 +1,23 @@
using FastGithub.Dns;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace FastGithub
{
/// <summary>
/// DoH的中间件扩展
/// </summary>
public static class DnsOverHttpsApplicationBuilderExtensions
{
/// <summary>
/// 使用DoH的中间件
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseDnsOverHttps(this IApplicationBuilder app)
{
var middleware = app.ApplicationServices.GetRequiredService<DnsOverHttpsMiddleware>();
return app.Use(next => context => middleware.InvokeAsync(context, next));
}
}
}

View File

@ -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
{
/// <summary>
/// DoH中间件
/// </summary>
sealed class DnsOverHttpsMiddleware
{
private static readonly PathString dnsQueryPath = "/dns-query";
private const string MEDIA_TYPE = "application/dns-message";
private readonly RequestResolver requestResolver;
/// <summary>
/// DoH中间件
/// </summary>
/// <param name="requestResolver"></param>
public DnsOverHttpsMiddleware(RequestResolver requestResolver)
{
this.requestResolver = requestResolver;
}
/// <summary>
/// 执行请求
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
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);
}
}
/// <summary>
/// 解析dns请求
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private static async Task<Request?> 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;
}
}
}

View File

@ -5,6 +5,7 @@
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="DNS" Version="6.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
</ItemGroup>

View File

@ -18,6 +18,7 @@ namespace FastGithub
{
services.TryAddSingleton<RequestResolver>();
services.TryAddSingleton<DnsServer>();
services.TryAddSingleton<DnsOverHttpsMiddleware>();
services.AddSingleton<IDnsValidator, HostsValidator>();
services.AddSingleton<IDnsValidator, ProxyValidtor>();
return services.AddHostedService<DnsHostedService>();

View File

@ -45,6 +45,7 @@ namespace FastGithub
public void Configure(IApplicationBuilder app)
{
app.UseRequestLogging();
app.UseDnsOverHttps();
app.UseReverseProxy();
app.UseRouting();
app.UseEndpoints(endpoints =>