Browse Source

winApi安装dnscrypt-proxy服务

老九 3 năm trước cách đây
mục cha
commit
c11f7af44d

+ 29 - 30
FastGithub.DomainResolve/DnscryptProxy.cs

@@ -10,6 +10,7 @@ using System.Net.NetworkInformation;
 using System.Net.Sockets;
 using System.Threading;
 using System.Threading.Tasks;
+using static PInvoke.AdvApi32;
 
 namespace FastGithub.DomainResolve
 {
@@ -18,10 +19,11 @@ namespace FastGithub.DomainResolve
     /// </summary>
     sealed class DnscryptProxy
     {
-        private const string PATH = "dnscrypt-proxy";
-        private const string NAME = "dnscrypt-proxy";
-
         private readonly ILogger<DnscryptProxy> logger;
+        private readonly string processName;
+        private readonly string serviceName;
+        private readonly string exeFilePath;
+        private readonly string tomlFilePath;
 
         /// <summary>
         /// 相关进程
@@ -39,7 +41,14 @@ namespace FastGithub.DomainResolve
         /// <param name="logger"></param>
         public DnscryptProxy(ILogger<DnscryptProxy> logger)
         {
+            const string PATH = "dnscrypt-proxy";
+            const string NAME = "dnscrypt-proxy";
+
             this.logger = logger;
+            this.processName = NAME;
+            this.serviceName = $"{nameof(FastGithub)}.{NAME}";
+            this.exeFilePath = Path.Combine(PATH, OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME);
+            this.tomlFilePath = Path.Combine(PATH, $"{NAME}.toml");
         }
 
         /// <summary>
@@ -55,7 +64,7 @@ namespace FastGithub.DomainResolve
             }
             catch (Exception ex)
             {
-                this.logger.LogWarning($"{NAME}启动失败:{ex.Message}");
+                this.logger.LogWarning($"{this.processName}启动失败:{ex.Message}");
             }
         }
 
@@ -66,30 +75,22 @@ namespace FastGithub.DomainResolve
         /// <returns></returns>
         private async Task StartCoreAsync(CancellationToken cancellationToken)
         {
-            var tomlPath = Path.Combine(PATH, $"{NAME}.toml");
             var port = GetAvailablePort(IPAddress.Loopback.AddressFamily);
             var localEndPoint = new IPEndPoint(IPAddress.Loopback, port);
 
-            await TomlUtil.SetListensAsync(tomlPath, localEndPoint, cancellationToken);
-            await TomlUtil.SetlogLevelAsync(tomlPath, 6, cancellationToken);
-            await TomlUtil.SetEdnsClientSubnetAsync(tomlPath, cancellationToken);
-
-            foreach (var process in Process.GetProcessesByName(NAME))
-            {
-                process.Kill();
-                process.WaitForExit();
-            }
+            await TomlUtil.SetListensAsync(this.tomlFilePath, localEndPoint, cancellationToken);
+            await TomlUtil.SetlogLevelAsync(this.tomlFilePath, 6, cancellationToken);
+            await TomlUtil.SetEdnsClientSubnetAsync(this.tomlFilePath, cancellationToken);
 
             if (OperatingSystem.IsWindows() && Process.GetCurrentProcess().SessionId == 0)
             {
-                StartDnscryptProxy("-service uninstall")?.WaitForExit();
-                StartDnscryptProxy("-service install")?.WaitForExit();
-                StartDnscryptProxy("-service start")?.WaitForExit();
-                this.process = Process.GetProcessesByName(NAME).FirstOrDefault(item => item.SessionId == 0);
+                ServiceInstallUtil.StopAndDeleteService(this.serviceName);
+                ServiceInstallUtil.InstallAndStartService(this.serviceName, this.exeFilePath, ServiceStartType.SERVICE_DEMAND_START);
+                this.process = Process.GetProcessesByName(this.processName).FirstOrDefault(item => item.SessionId == 0);
             }
             else
             {
-                this.process = StartDnscryptProxy(string.Empty);
+                this.process = StartDnscryptProxy();
             }
 
             if (this.process != null)
@@ -109,9 +110,9 @@ namespace FastGithub.DomainResolve
             {
                 if (OperatingSystem.IsWindows() && Process.GetCurrentProcess().SessionId == 0)
                 {
-                    StartDnscryptProxy("-service stop")?.WaitForExit();
-                    StartDnscryptProxy("-service uninstall")?.WaitForExit();
+                    ServiceInstallUtil.StopAndDeleteService(this.serviceName);
                 }
+
                 if (this.process != null && this.process.HasExited == false)
                 {
                     this.process.Kill();
@@ -119,7 +120,7 @@ namespace FastGithub.DomainResolve
             }
             catch (Exception ex)
             {
-                this.logger.LogWarning($"{NAME}停止失败:{ex.Message }");
+                this.logger.LogWarning($"{this.processName}停止失败:{ex.Message }");
             }
             finally
             {
@@ -160,16 +161,14 @@ namespace FastGithub.DomainResolve
 
         /// <summary>
         /// 启动DnscryptProxy进程
-        /// </summary>
-        /// <param name="arguments"></param> 
-        private static Process? StartDnscryptProxy(string arguments)
+        /// </summary> 
+        /// <returns></returns>
+        private Process? StartDnscryptProxy()
         {
-            var fileName = OperatingSystem.IsWindows() ? $"{NAME}.exe" : NAME;
             return Process.Start(new ProcessStartInfo
             {
-                FileName = Path.Combine(PATH, fileName),
-                Arguments = arguments,
-                WorkingDirectory = PATH,
+                FileName = this.exeFilePath,
+                WorkingDirectory = Path.GetDirectoryName(this.exeFilePath),
                 UseShellExecute = false,
                 CreateNoWindow = true,
                 WindowStyle = ProcessWindowStyle.Hidden
@@ -182,7 +181,7 @@ namespace FastGithub.DomainResolve
         /// <returns></returns>
         public override string ToString()
         {
-            return NAME;
+            return this.processName;
         }
     }
 }

+ 1 - 0
FastGithub.DomainResolve/FastGithub.DomainResolve.csproj

@@ -1,6 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   
 	<ItemGroup>
+		<PackageReference Include="PInvoke.AdvApi32" Version="0.7.104" />
 		<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
 		<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
 		<PackageReference Include="DNS" Version="6.1.0" />

+ 88 - 0
FastGithub.DomainResolve/ServiceInstallUtil.cs

@@ -0,0 +1,88 @@
+using System.IO;
+using System.Runtime.Versioning;
+using static PInvoke.AdvApi32;
+
+namespace FastGithub.DomainResolve
+{
+    public static class ServiceInstallUtil
+    {
+        /// <summary>
+        /// 安装并启动服务
+        /// </summary>
+        /// <param name="serviceName"></param>
+        /// <param name="binaryPath"></param>
+        /// <param name="startType"></param>
+        /// <returns></returns>
+        [SupportedOSPlatform("windows")]
+        public static bool InstallAndStartService(string serviceName, string binaryPath, ServiceStartType startType = ServiceStartType.SERVICE_AUTO_START)
+        {
+            using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS);
+            if (hSCManager.IsInvalid == true)
+            {
+                return false;
+            }
+
+            var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS);
+            if (hService.IsInvalid == true)
+            {
+                hService = CreateService(
+                    hSCManager,
+                    serviceName,
+                    serviceName,
+                    ServiceAccess.SERVICE_ALL_ACCESS,
+                    ServiceType.SERVICE_WIN32_OWN_PROCESS,
+                    startType,
+                    ServiceErrorControl.SERVICE_ERROR_NORMAL,
+                    Path.GetFullPath(binaryPath),
+                    lpLoadOrderGroup: null,
+                    lpdwTagId: 0,
+                    lpDependencies: null,
+                    lpServiceStartName: null,
+                    lpPassword: null);
+            }
+
+            if (hService.IsInvalid == true)
+            {
+                return false;
+            }
+
+            using (hService)
+            {
+                return StartService(hService, 0, null);
+            }
+        }
+
+        /// <summary>
+        /// 停止并删除服务
+        /// </summary>
+        /// <param name="serviceName"></param>
+        /// <returns></returns>
+        [SupportedOSPlatform("windows")]
+        public static bool StopAndDeleteService(string serviceName)
+        {
+            using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS);
+            if (hSCManager.IsInvalid == true)
+            {
+                return false;
+            }
+
+            using var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS);
+            if (hService.IsInvalid == true)
+            {
+                return true;
+            }
+
+            var status = new SERVICE_STATUS();
+            if (QueryServiceStatus(hService, ref status) == true)
+            {
+                if (status.dwCurrentState != ServiceState.SERVICE_STOP_PENDING &&
+                    status.dwCurrentState != ServiceState.SERVICE_STOPPED)
+                {
+                    ControlService(hService, ServiceControl.SERVICE_CONTROL_STOP, ref status);
+                }
+            }
+
+            return DeleteService(hService);
+        }
+    }
+}

+ 3 - 3
FastGithub.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31808.319
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31320.298
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub", "FastGithub\FastGithub.csproj", "{C1099390-6103-4917-A740-A3002B542FE0}"
 EndProject
@@ -15,7 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.HttpServer", "Fa
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.PacketIntercept", "FastGithub.PacketIntercept\FastGithub.PacketIntercept.csproj", "{701FF90C-E651-4E0B-AE7F-84D1F17DD178}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastGithub.UI", "FastGithub.UI\FastGithub.UI.csproj", "{5082061F-38D5-4F50-945E-791C85B9BDB5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.UI", "FastGithub.UI\FastGithub.UI.csproj", "{5082061F-38D5-4F50-945E-791C85B9BDB5}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastGithub.FlowAnalyze", "FastGithub.FlowAnalyze\FastGithub.FlowAnalyze.csproj", "{93478EAF-739C-47DA-B8FE-AEBA78A75E11}"
 EndProject

+ 1 - 2
FastGithub/FastGithub.csproj

@@ -9,7 +9,6 @@
 	</PropertyGroup>
 
 	<ItemGroup>
-		<PackageReference Include="PInvoke.AdvApi32" Version="0.7.104" />
 		<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" />
 		<PackageReference Include="Serilog.Sinks.Network" Version="2.0.2.68" />
 		<ProjectReference Include="..\FastGithub.DomainResolve\FastGithub.DomainResolve.csproj" />
@@ -18,7 +17,7 @@
 	</ItemGroup>
 
 	<ItemGroup>
-    <PackageReference Include="Serilog.Extensions.Hosting" Version="4.1.2" />
+		<PackageReference Include="Serilog.Extensions.Hosting" Version="4.1.2" />
 		<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
 		<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
 		<PackageReference Include="Serilog.Settings.Configuration" Version="3.2.0" />

+ 0 - 185
FastGithub/WindowServiceExtensions.cs

@@ -1,185 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using PInvoke;
-using System;
-using System.IO;
-using System.Linq;
-using System.Runtime.Versioning;
-using System.Threading;
-using static PInvoke.AdvApi32;
-
-namespace FastGithub
-{
-    /// <summary>
-    /// IHostBuilder扩展
-    /// </summary>
-    static class WindowServiceExtensions
-    {
-        /// <summary>
-        /// 控制命令
-        /// </summary>
-        private enum Command
-        {
-            Start,
-            Stop,
-        }
-
-        /// <summary>
-        /// 使用windows服务
-        /// </summary>
-        /// <param name="hostBuilder"></param> 
-        /// <returns></returns>
-        public static IHostBuilder UseWindowsService(this IHostBuilder hostBuilder)
-        {
-            var contentRoot = Path.GetDirectoryName(Environment.GetCommandLineArgs().First());
-            if (contentRoot != null)
-            {
-                Environment.CurrentDirectory = contentRoot;
-                hostBuilder.UseContentRoot(contentRoot);
-            }
-            return WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(hostBuilder);
-        }
-
-        /// <summary>
-        /// 运行主机
-        /// </summary>
-        /// <param name="host"></param>
-        /// <param name="singleton"></param>
-        public static void Run(this IHost host, bool singleton = true)
-        {
-            if (OperatingSystem.IsWindows() && TryGetCommand(out var cmd))
-            {
-                try
-                {
-                    UseCommand(cmd);
-                }
-                catch (Exception ex)
-                {
-                    var loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
-                    loggerFactory.CreateLogger(nameof(FastGithub)).LogError(ex.Message);
-                }
-            }
-            else
-            {
-                using var mutex = new Mutex(true, "Global\\FastGithub", out var firstInstance);
-                if (singleton == false || firstInstance)
-                {
-                    HostingAbstractionsHostExtensions.Run(host);
-                }
-            }
-        }
-
-        /// <summary>
-        /// 获取控制指令
-        /// </summary>
-        /// <param name="cmd"></param>
-        /// <returns></returns>
-        private static bool TryGetCommand(out Command cmd)
-        {
-            var args = Environment.GetCommandLineArgs();
-            return Enum.TryParse(args.Skip(1).FirstOrDefault(), true, out cmd);
-        }
-
-        /// <summary>
-        /// 应用控制指令
-        /// </summary> 
-        /// <param name="cmd"></param>
-        [SupportedOSPlatform("windows")]
-        private static void UseCommand(Command cmd)
-        {
-            var binaryPath = Environment.GetCommandLineArgs().First();
-            var serviceName = Path.GetFileNameWithoutExtension(binaryPath);
-            if (cmd == Command.Start)
-            {
-                InstallAndStartService(serviceName, binaryPath);
-            }
-            else if (cmd == Command.Stop)
-            {
-                StopAndDeleteService(serviceName);
-            }
-        }
-
-        /// <summary>
-        /// 安装并启动服务
-        /// </summary>
-        /// <param name="serviceName"></param>
-        /// <param name="binaryPath"></param>
-        /// <exception cref = "Win32Exception" ></ exception >
-        [SupportedOSPlatform("windows")]
-        private static void InstallAndStartService(string serviceName, string binaryPath)
-        {
-            using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS);
-            if (hSCManager.IsInvalid == true)
-            {
-                throw new Win32Exception();
-            }
-
-            var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS);
-            if (hService.IsInvalid == true)
-            {
-                hService = CreateService(
-                    hSCManager,
-                    serviceName,
-                    serviceName,
-                    ServiceAccess.SERVICE_ALL_ACCESS,
-                    ServiceType.SERVICE_WIN32_OWN_PROCESS,
-                    ServiceStartType.SERVICE_AUTO_START,
-                    ServiceErrorControl.SERVICE_ERROR_NORMAL,
-                    binaryPath,
-                    lpLoadOrderGroup: null,
-                    lpdwTagId: 0,
-                    lpDependencies: null,
-                    lpServiceStartName: null,
-                    lpPassword: null);
-            }
-
-            if (hService.IsInvalid == true)
-            {
-                throw new Win32Exception();
-            }
-
-            using (hService)
-            {
-                StartService(hService, 0, null);
-            }
-        }
-
-        /// <summary>
-        /// 停止并删除服务
-        /// </summary>
-        /// <param name="serviceName"></param>
-        /// <exception cref = "Win32Exception" ></ exception >
-        [SupportedOSPlatform("windows")]
-        private static void StopAndDeleteService(string serviceName)
-        {
-            using var hSCManager = OpenSCManager(null, null, ServiceManagerAccess.SC_MANAGER_ALL_ACCESS);
-            if (hSCManager.IsInvalid == true)
-            {
-                throw new Win32Exception();
-            }
-
-            using var hService = OpenService(hSCManager, serviceName, ServiceAccess.SERVICE_ALL_ACCESS);
-            if (hService.IsInvalid == true)
-            {
-                return;
-            }
-
-            var status = new SERVICE_STATUS();
-            if (QueryServiceStatus(hService, ref status) == true)
-            {
-                if (status.dwCurrentState != ServiceState.SERVICE_STOP_PENDING &&
-                    status.dwCurrentState != ServiceState.SERVICE_STOPPED)
-                {
-                    ControlService(hService, ServiceControl.SERVICE_CONTROL_STOP, ref status);
-                }
-            }
-
-            if (DeleteService(hService) == false)
-            {
-                throw new Win32Exception();
-            }
-        }
-
-    }
-}

+ 110 - 0
FastGithub/WindowsServiceExtensions.cs

@@ -0,0 +1,110 @@
+using FastGithub.DomainResolve;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using PInvoke;
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.Versioning;
+using System.Threading;
+
+namespace FastGithub
+{
+    /// <summary>
+    /// IHostBuilder扩展
+    /// </summary>
+    static class WindowsServiceExtensions
+    {
+        /// <summary>
+        /// 控制命令
+        /// </summary>
+        private enum Command
+        {
+            Start,
+            Stop,
+        }
+
+        /// <summary>
+        /// 使用windows服务
+        /// </summary>
+        /// <param name="hostBuilder"></param> 
+        /// <returns></returns>
+        public static IHostBuilder UseWindowsService(this IHostBuilder hostBuilder)
+        {
+            var contentRoot = Path.GetDirectoryName(Environment.GetCommandLineArgs().First());
+            if (contentRoot != null)
+            {
+                Environment.CurrentDirectory = contentRoot;
+                hostBuilder.UseContentRoot(contentRoot);
+            }
+            return WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(hostBuilder);
+        }
+
+        /// <summary>
+        /// 运行主机
+        /// </summary>
+        /// <param name="host"></param>
+        /// <param name="singleton"></param>
+        public static void Run(this IHost host, bool singleton = true)
+        {
+            if (OperatingSystem.IsWindows() && TryGetCommand(out var cmd))
+            {
+                try
+                {
+                    UseCommand(cmd);
+                }
+                catch (Exception ex)
+                {
+                    var loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
+                    loggerFactory.CreateLogger(nameof(FastGithub)).LogError(ex.Message);
+                }
+            }
+            else
+            {
+                using var mutex = new Mutex(true, "Global\\FastGithub", out var firstInstance);
+                if (singleton == false || firstInstance)
+                {
+                    HostingAbstractionsHostExtensions.Run(host);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 获取控制指令
+        /// </summary>
+        /// <param name="cmd"></param>
+        /// <returns></returns>
+        private static bool TryGetCommand(out Command cmd)
+        {
+            var args = Environment.GetCommandLineArgs();
+            return Enum.TryParse(args.Skip(1).FirstOrDefault(), true, out cmd);
+        }
+
+        /// <summary>
+        /// 应用控制指令
+        /// </summary> 
+        /// <param name="cmd"></param>
+        [SupportedOSPlatform("windows")]
+        private static void UseCommand(Command cmd)
+        {
+            var binaryPath = Environment.GetCommandLineArgs().First();
+            var serviceName = Path.GetFileNameWithoutExtension(binaryPath);
+            var state = true;
+            if (cmd == Command.Start)
+            {
+                state = ServiceInstallUtil.InstallAndStartService(serviceName, binaryPath);
+            }
+            else if (cmd == Command.Stop)
+            {
+                state = ServiceInstallUtil.StopAndDeleteService(serviceName);
+            }
+
+            if (state == false)
+            {
+                throw new Win32Exception();
+            }
+        }
+
+    }
+}