golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/embeddable-dll-service/csharp/TunnelDll/Service.cs (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  using System;
     7  using System.IO;
     8  using System.IO.Pipes;
     9  using System.Runtime.InteropServices;
    10  using System.ComponentModel;
    11  using System.Diagnostics;
    12  using System.Threading;
    13  
    14  namespace Tunnel
    15  {
    16      public class Service
    17      {
    18          private const string LongName = "WireGuard Demo Box";
    19          private const string Description = "Demonstration tunnel for testing WireGuard";
    20  
    21          [DllImport("tunnel.dll", EntryPoint = "WireGuardTunnelService", CallingConvention = CallingConvention.Cdecl)]
    22          public static extern bool Run([MarshalAs(UnmanagedType.LPWStr)] string configFile);
    23  
    24          public static Driver.Adapter GetAdapter(string configFile)
    25          {
    26              return new Driver.Adapter(Path.GetFileNameWithoutExtension(configFile));
    27          }
    28  
    29          public static void Add(string configFile, bool ephemeral)
    30          {
    31              var tunnelName = Path.GetFileNameWithoutExtension(configFile);
    32              var shortName = String.Format("WireGuardTunnel${0}", tunnelName);
    33              var longName = String.Format("{0}: {1}", LongName, tunnelName);
    34              var exeName = Process.GetCurrentProcess().MainModule.FileName;
    35              var pathAndArgs = String.Format("\"{0}\" /service \"{1}\" {2}", exeName, configFile, Process.GetCurrentProcess().Id); //TODO: This is not the proper way to escape file args.
    36  
    37              var scm = Win32.OpenSCManager(null, null, Win32.ScmAccessRights.AllAccess);
    38              if (scm == IntPtr.Zero)
    39                  throw new Win32Exception(Marshal.GetLastWin32Error());
    40              try
    41              {
    42                  var service = Win32.OpenService(scm, shortName, Win32.ServiceAccessRights.AllAccess);
    43                  if (service != IntPtr.Zero)
    44                  {
    45                      Win32.CloseServiceHandle(service);
    46                      Remove(configFile, true);
    47                  }
    48                  service = Win32.CreateService(scm, shortName, longName, Win32.ServiceAccessRights.AllAccess, Win32.ServiceType.Win32OwnProcess, Win32.ServiceStartType.Demand, Win32.ServiceError.Normal, pathAndArgs, null, IntPtr.Zero, "Nsi\0TcpIp\0", null, null);
    49                  if (service == IntPtr.Zero)
    50                      throw new Win32Exception(Marshal.GetLastWin32Error());
    51                  try
    52                  {
    53                      var sidType = Win32.ServiceSidType.Unrestricted;
    54                      if (!Win32.ChangeServiceConfig2(service, Win32.ServiceConfigType.SidInfo, ref sidType))
    55                          throw new Win32Exception(Marshal.GetLastWin32Error());
    56  
    57                      var description = new Win32.ServiceDescription { lpDescription = Description };
    58                      if (!Win32.ChangeServiceConfig2(service, Win32.ServiceConfigType.Description, ref description))
    59                          throw new Win32Exception(Marshal.GetLastWin32Error());
    60  
    61                      if (!Win32.StartService(service, 0, null))
    62                          throw new Win32Exception(Marshal.GetLastWin32Error());
    63  
    64                      if (ephemeral && !Win32.DeleteService(service))
    65                          throw new Win32Exception(Marshal.GetLastWin32Error());
    66                  }
    67                  finally
    68                  {
    69                      Win32.CloseServiceHandle(service);
    70                  }
    71              }
    72              finally
    73              {
    74                  Win32.CloseServiceHandle(scm);
    75              }
    76          }
    77  
    78          public static void Remove(string configFile, bool waitForStop)
    79          {
    80              var tunnelName = Path.GetFileNameWithoutExtension(configFile);
    81              var shortName = String.Format("WireGuardTunnel${0}", tunnelName);
    82  
    83              var scm = Win32.OpenSCManager(null, null, Win32.ScmAccessRights.AllAccess);
    84              if (scm == IntPtr.Zero)
    85                  throw new Win32Exception(Marshal.GetLastWin32Error());
    86              try
    87              {
    88                  var service = Win32.OpenService(scm, shortName, Win32.ServiceAccessRights.AllAccess);
    89                  if (service == IntPtr.Zero)
    90                      return;
    91                  try
    92                  {
    93                      var serviceStatus = new Win32.ServiceStatus();
    94                      Win32.ControlService(service, Win32.ServiceControl.Stop, serviceStatus);
    95  
    96                      for (int i = 0; waitForStop && i < 180 && Win32.QueryServiceStatus(service, serviceStatus) && serviceStatus.dwCurrentState != Win32.ServiceState.Stopped; ++i)
    97                          Thread.Sleep(1000);
    98  
    99                      if (!Win32.DeleteService(service) && Marshal.GetLastWin32Error() != 0x00000430)
   100                          throw new Win32Exception(Marshal.GetLastWin32Error());
   101                  }
   102                  finally
   103                  {
   104                      Win32.CloseServiceHandle(service);
   105                  }
   106              }
   107              finally
   108              {
   109                  Win32.CloseServiceHandle(scm);
   110              }
   111          }
   112      }
   113  }