完善DnscryptProxy服务

This commit is contained in:
陈国伟 2021-07-22 15:00:54 +08:00
parent 2e357e58d4
commit 09ee688ba0
6 changed files with 253 additions and 98 deletions

View File

@ -1,8 +1,6 @@
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.Diagnostics;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -14,15 +12,19 @@ namespace FastGithub.Dns.DnscryptProxy
sealed class DnscryptProxyHostedService : BackgroundService sealed class DnscryptProxyHostedService : BackgroundService
{ {
private bool isStopped = false; private bool isStopped = false;
private const string dnscryptProxyFile = "dnscrypt-proxy"; private readonly DnscryptProxyService dnscryptProxyService;
private readonly ILogger<DnscryptProxyHostedService> logger; private readonly ILogger<DnscryptProxyHostedService> logger;
/// <summary> /// <summary>
/// DnscryptProxy后台服务 /// DnscryptProxy后台服务
/// </summary> /// </summary>
/// <param name="dnscryptProxyService"></param>
/// <param name="logger"></param> /// <param name="logger"></param>
public DnscryptProxyHostedService(ILogger<DnscryptProxyHostedService> logger) public DnscryptProxyHostedService(
DnscryptProxyService dnscryptProxyService,
ILogger<DnscryptProxyHostedService> logger)
{ {
this.dnscryptProxyService = dnscryptProxyService;
this.logger = logger; this.logger = logger;
} }
@ -31,27 +33,19 @@ namespace FastGithub.Dns.DnscryptProxy
/// </summary> /// </summary>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public override Task StartAsync(CancellationToken cancellationToken) public override async Task StartAsync(CancellationToken cancellationToken)
{ {
try try
{ {
if (OperatingSystem.IsWindows()) await this.dnscryptProxyService.StartAsync(cancellationToken);
{ this.logger.LogInformation($"{this.dnscryptProxyService}启动成功");
StartDnscryptProxy("-service install", waitForExit: true);
StartDnscryptProxy("-service start", waitForExit: true);
}
else
{
StartDnscryptProxy(string.Empty, waitForExit: false);
}
this.logger.LogInformation($"{dnscryptProxyFile}启动成功");
} }
catch (Exception ex) catch (Exception ex)
{ {
this.logger.LogWarning($"{dnscryptProxyFile}启动失败:{ex.Message}"); this.logger.LogWarning($"{this.dnscryptProxyService}启动失败:{ex.Message}");
} }
return base.StartAsync(cancellationToken); await base.StartAsync(cancellationToken);
} }
/// <summary> /// <summary>
@ -63,14 +57,10 @@ namespace FastGithub.Dns.DnscryptProxy
{ {
await Task.Yield(); await Task.Yield();
var process = Process.GetProcessesByName(dnscryptProxyFile).FirstOrDefault(); this.dnscryptProxyService.WaitForExit();
if (process != null)
{
process.WaitForExit();
}
if (this.isStopped == false) if (this.isStopped == false)
{ {
this.logger.LogCritical($"{dnscryptProxyFile}已停止运行,{nameof(FastGithub)}将无法解析域名。你可以把配置文件的{nameof(FastGithubOptions.PureDns)}修改为其它可用的DNS以临时使用。"); this.logger.LogCritical($"{this.dnscryptProxyService}已停止运行,{nameof(FastGithub)}将无法解析域名。你可以把配置文件的{nameof(FastGithubOptions.PureDns)}修改为其它可用的DNS以临时使用。");
} }
} }
@ -84,45 +74,14 @@ namespace FastGithub.Dns.DnscryptProxy
try try
{ {
this.isStopped = true; this.isStopped = true;
if (OperatingSystem.IsWindows()) this.dnscryptProxyService.Stop();
{ this.logger.LogInformation($"{this.dnscryptProxyService}已停止");
StartDnscryptProxy("-service stop", waitForExit: true);
StartDnscryptProxy("-service uninstall", waitForExit: true);
}
foreach (var process in Process.GetProcessesByName(dnscryptProxyFile))
{
process.Kill();
}
this.logger.LogInformation($"{dnscryptProxyFile}已停止");
} }
catch (Exception ex) catch (Exception ex)
{ {
this.logger.LogWarning($"{dnscryptProxyFile}停止失败:{ex.Message}"); this.logger.LogWarning($"{this.dnscryptProxyService}停止失败:{ex.Message}");
} }
return base.StopAsync(cancellationToken); return base.StopAsync(cancellationToken);
} }
/// <summary>
/// 启动DnscryptProxy进程
/// </summary>
/// <param name="arguments"></param>
/// <param name="waitForExit"></param>
private static void StartDnscryptProxy(string arguments, bool waitForExit)
{
var process = Process.Start(new ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? $"{dnscryptProxyFile}.exe" : dnscryptProxyFile,
Arguments = arguments,
UseShellExecute = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
});
if (waitForExit && process != null)
{
process.WaitForExit();
}
}
} }
} }

View File

@ -0,0 +1,116 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Dns.DnscryptProxy
{
/// <summary>
/// DnscryptProxy服务
/// </summary>
sealed class DnscryptProxyService
{
private readonly FastGithubConfig fastGithubConfig;
/// <summary>
/// 获取文件名
/// </summary>
public string Name => "dnscrypt-proxy";
/// <summary>
/// DnscryptProxy服务
/// </summary>
/// <param name="fastGithubConfig"></param>
public DnscryptProxyService(FastGithubConfig fastGithubConfig)
{
this.fastGithubConfig = fastGithubConfig;
}
/// <summary>
/// 启动dnscrypt-proxy
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task StartAsync(CancellationToken cancellationToken)
{
var tomlPath = $"{this.Name}.toml";
await TomlUtil.SetListensAsync(tomlPath, this.fastGithubConfig.PureDns, cancellationToken);
foreach (var process in Process.GetProcessesByName(this.Name))
{
process.Kill();
}
if (OperatingSystem.IsWindows())
{
this.StartDnscryptProxy("-service install", waitForExit: true);
this.StartDnscryptProxy("-service start", waitForExit: true);
}
else
{
this.StartDnscryptProxy(string.Empty, waitForExit: false);
}
}
/// <summary>
/// 停止dnscrypt-proxy
/// </summary>
public void Stop()
{
if (OperatingSystem.IsWindows())
{
this.StartDnscryptProxy("-service stop", waitForExit: true);
this.StartDnscryptProxy("-service uninstall", waitForExit: true);
}
foreach (var process in Process.GetProcessesByName(this.Name))
{
process.Kill();
}
}
/// <summary>
/// 等待退出
/// </summary>
public void WaitForExit()
{
var process = Process.GetProcessesByName(this.Name).FirstOrDefault();
if (process != null)
{
process.WaitForExit();
}
}
/// <summary>
/// 启动DnscryptProxy进程
/// </summary>
/// <param name="arguments"></param>
/// <param name="waitForExit"></param>
private void StartDnscryptProxy(string arguments, bool waitForExit)
{
var process = Process.Start(new ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? $"{this.Name}.exe" : this.Name,
Arguments = arguments,
UseShellExecute = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
});
if (waitForExit && process != null)
{
process.WaitForExit();
}
}
/// <summary>
/// 转换为字符串
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this.Name;
}
}
}

View File

@ -15,7 +15,9 @@ namespace FastGithub
/// <returns></returns> /// <returns></returns>
public static IServiceCollection AddDnscryptProxy(this IServiceCollection services) public static IServiceCollection AddDnscryptProxy(this IServiceCollection services)
{ {
return services.AddHostedService<DnscryptProxyHostedService>(); return services
.AddSingleton<DnscryptProxyService>()
.AddHostedService<DnscryptProxyHostedService>();
} }
} }
} }

View File

@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Dns.DnscryptProxy
{
/// <summary>
/// doml配置工具
/// </summary>
static class TomlUtil
{
/// <summary>
/// 设置监听地址
/// </summary>
/// <param name="tomlPath"></param>
/// <param name="endpoint"></param>
/// <returns></returns>
public static Task SetListensAsync(string tomlPath, IPEndPoint endpoint, CancellationToken cancellationToken = default)
{
return SetAsync(tomlPath, "listen_addresses", $"['{endpoint}']");
}
/// <summary>
/// 设置指定键的值
/// </summary>
/// <param name="tomlPath"></param>
/// <param name="key"></param>
/// <param name="value"></param>
public static async Task SetAsync(string tomlPath, string key, object? value, CancellationToken cancellationToken = default)
{
var lines = await File.ReadAllLinesAsync(tomlPath, cancellationToken);
var toml = Set(lines, key, value);
await File.WriteAllTextAsync(tomlPath, toml, cancellationToken);
}
/// <summary>
/// 设置值
/// </summary>
/// <param name="lines"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
private static string Set(string[] lines, string key, object? value)
{
var updated = false;
var builder = new StringBuilder();
foreach (var line in lines)
{
var span = line.AsSpan();
if (span.IsEmpty || span[0] == '#')
{
builder.AppendLine(line);
continue;
}
var index = span.IndexOf('=');
if (index <= 0 || span.Slice(0, index).Trim().SequenceEqual(key) == false)
{
builder.AppendLine(line);
continue;
}
builder.Append(key).Append(" = ").AppendLine(value?.ToString());
updated = true;
}
if (updated == false)
{
builder.Append(key).Append(" = ").AppendLine(value?.ToString());
}
return builder.ToString();
}
}
}

View File

@ -16,7 +16,10 @@ namespace FastGithub.Upgrade
/// </summary> /// </summary>
public ReverseProxyHttpHandler() public ReverseProxyHttpHandler()
{ {
this.InnerHandler = new HttpClientHandler(); this.InnerHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = delegate { return true; }
};
} }
/// <summary> /// <summary>

View File

@ -1,46 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>net5.0;net6.0</TargetFrameworks> <TargetFrameworks>net5.0;net6.0</TargetFrameworks>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<ApplicationIcon>app.ico</ApplicationIcon> <IsWebConfigTransformDisabled>true</IsWebConfigTransformDisabled>
<IsWebConfigTransformDisabled>true</IsWebConfigTransformDisabled> <ApplicationIcon>app.ico</ApplicationIcon>
</PropertyGroup> <ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'net6.0'">
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile> <EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <ItemGroup>
<ApplicationManifest>app.manifest</ApplicationManifest> <PackageReference Include="PInvoke.AdvApi32" Version="0.7.104" />
</PropertyGroup> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" />
<ProjectReference Include="..\FastGithub.Dns.DnscryptProxy\FastGithub.Dns.DnscryptProxy.csproj" />
<ProjectReference Include="..\FastGithub.Dns\FastGithub.Dns.csproj" />
<ProjectReference Include="..\FastGithub.ReverseProxy\FastGithub.ReverseProxy.csproj" />
<ProjectReference Include="..\FastGithub.Upgrade\FastGithub.Upgrade.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="PInvoke.AdvApi32" Version="0.7.104" /> <None Update="appsettings.github.json">
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" /> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ProjectReference Include="..\FastGithub.Dns.DnscryptProxy\FastGithub.Dns.DnscryptProxy.csproj" /> </None>
<ProjectReference Include="..\FastGithub.Dns\FastGithub.Dns.csproj" /> <None Update="appsettings.json">
<ProjectReference Include="..\FastGithub.ReverseProxy\FastGithub.ReverseProxy.csproj" /> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ProjectReference Include="..\FastGithub.Upgrade\FastGithub.Upgrade.csproj" /> </None>
</ItemGroup> <None Update="FastGithub.cer">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ItemGroup> </None>
<None Update="appsettings.github.json"> <None Update="README.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="appsettings.json"> <None Update="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="FastGithub.cer"> </ItemGroup>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="README.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>