diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-08-09 22:38:35 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-08-10 02:30:33 +0200 |
commit | 747f5d07fbf14c76c9b43e91a7f81f1cab5edc51 (patch) | |
tree | a7b1e8748dc3ed2122ee4e812e4c9de91b071c3f | |
parent | embeddable-dll-service: use wgnt always (diff) | |
download | wireguard-windows-747f5d07fbf14c76c9b43e91a7f81f1cab5edc51.tar.xz wireguard-windows-747f5d07fbf14c76c9b43e91a7f81f1cab5edc51.zip |
embeddable-dll-service: csharp: update for wgnt
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | embeddable-dll-service/csharp/DemoUI/MainWindow.cs | 58 | ||||
-rw-r--r-- | embeddable-dll-service/csharp/TunnelDll/Driver.cs | 236 | ||||
-rw-r--r-- | embeddable-dll-service/csharp/TunnelDll/Service.cs | 5 | ||||
-rw-r--r-- | embeddable-dll-service/csharp/TunnelDll/Win32.cs | 52 |
4 files changed, 316 insertions, 35 deletions
diff --git a/embeddable-dll-service/csharp/DemoUI/MainWindow.cs b/embeddable-dll-service/csharp/DemoUI/MainWindow.cs index 7d1e3f6f..6e3eb21f 100644 --- a/embeddable-dll-service/csharp/DemoUI/MainWindow.cs +++ b/embeddable-dll-service/csharp/DemoUI/MainWindow.cs @@ -66,49 +66,43 @@ namespace DemoUI private void tailTransfer() { - StreamReader reader = null; - NamedPipeClientStream stream = null; + Tunnel.Driver.Adapter adapter = null; while (threadsRunning) { - try + if (adapter == null) { - stream = Tunnel.Service.GetPipe(configFile); - stream.Connect(); - reader = new StreamReader(stream); - break; + while (threadsRunning) + { + try + { + adapter = Tunnel.Service.GetAdapter(configFile); + break; + } + catch + { + try + { + Thread.Sleep(1000); + } + catch { } + } + } } - catch { } - Thread.Sleep(1000); - } - - try - { - while (threadsRunning) + if (adapter == null) + continue; + try { - stream.Write(Encoding.UTF8.GetBytes("get=1\n\n")); ulong rx = 0, tx = 0; - while (threadsRunning) + var config = adapter.GetConfiguration(); + foreach (var peer in config.Peers) { - var line = reader.ReadLine(); - if (line == null) - break; - line = line.Trim(); - if (line.Length == 0) - break; - if (line.StartsWith("rx_bytes=")) - rx += ulong.Parse(line.Substring(9)); - else if (line.StartsWith("tx_bytes=")) - tx += ulong.Parse(line.Substring(9)); + rx += peer.RxBytes; + tx += peer.TxBytes; } Invoke(new Action<ulong, ulong>(updateTransferTitle), new object[] { rx, tx }); Thread.Sleep(1000); } - } - catch { } - finally - { - if (stream.IsConnected) - stream.Close(); + catch { adapter = null; } } } diff --git a/embeddable-dll-service/csharp/TunnelDll/Driver.cs b/embeddable-dll-service/csharp/TunnelDll/Driver.cs new file mode 100644 index 00000000..2e7b69a5 --- /dev/null +++ b/embeddable-dll-service/csharp/TunnelDll/Driver.cs @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved. + */ + +using System; +using System.ComponentModel; +using System.Net; +using System.Runtime.InteropServices; + +namespace Tunnel +{ + public class Driver + { + [DllImport("wireguard.dll", EntryPoint = "WireGuardOpenAdapter", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] + private static extern IntPtr openAdapter([MarshalAs(UnmanagedType.LPWStr)] string pool, [MarshalAs(UnmanagedType.LPWStr)] string name); + [DllImport("wireguard.dll", EntryPoint = "WireGuardFreeAdapter", CallingConvention = CallingConvention.Cdecl)] + private static extern void freeAdapter(IntPtr adapter); + [DllImport("wireguard.dll", EntryPoint = "WireGuardGetConfiguration", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] + private static extern bool getConfiguration(IntPtr adapter, byte[] iface, ref UInt32 bytes); + + private const string defaultPool = "WireGuard"; + + public class Adapter + { + private IntPtr _handle; + private UInt32 _lastGetGuess; + public Adapter(string name) + { + _lastGetGuess = 1024; + _handle = openAdapter(defaultPool, name); + if (_handle == IntPtr.Zero) + throw new Win32Exception(); + } + ~Adapter() + { + freeAdapter(_handle); + } + public unsafe Interface GetConfiguration() + { + var iface = new Interface(); + byte[] bytes; + for (; ; ) + { + bytes = new byte[_lastGetGuess]; + if (getConfiguration(_handle, bytes, ref _lastGetGuess)) + break; + if (Marshal.GetLastWin32Error() != 234 /* ERROR_MORE_DATA */) + throw new Win32Exception(); + } + fixed (void* start = bytes) + { + var ioctlIface = (IoctlInterface*)start; + if ((ioctlIface->Flags & IoctlInterfaceFlags.HasPublicKey) != 0) + iface.PublicKey = new Key(ioctlIface->PublicKey); + if ((ioctlIface->Flags & IoctlInterfaceFlags.HasPrivateKey) != 0) + iface.PrivateKey = new Key(ioctlIface->PrivateKey); + if ((ioctlIface->Flags & IoctlInterfaceFlags.HasListenPort) != 0) + iface.ListenPort = ioctlIface->ListenPort; + var peers = new Peer[ioctlIface->PeersCount]; + var ioctlPeer = (IoctlPeer*)((byte*)ioctlIface + sizeof(IoctlInterface)); + for (UInt32 i = 0; i < peers.Length; ++i) + { + var peer = new Peer(); + if ((ioctlPeer->Flags & IoctlPeerFlags.HasPublicKey) != 0) + peer.PublicKey = new Key(ioctlPeer->PublicKey); + if ((ioctlPeer->Flags & IoctlPeerFlags.HasPresharedKey) != 0) + peer.PresharedKey = new Key(ioctlPeer->PresharedKey); + if ((ioctlPeer->Flags & IoctlPeerFlags.HasPersistentKeepalive) != 0) + peer.PersistentKeepalive = ioctlPeer->PersistentKeepalive; + if ((ioctlPeer->Flags & IoctlPeerFlags.HasEndpoint) != 0) + { + if (ioctlPeer->Endpoint.si_family == Win32.ADDRESS_FAMILY.AF_INET) + { + var ip = new byte[4]; + Marshal.Copy((IntPtr)ioctlPeer->Endpoint.Ipv4.sin_addr.bytes, ip, 0, 4); + peer.Endpoint = new IPEndPoint(new IPAddress(ip), IPAddress.NetworkToHostOrder(ioctlPeer->Endpoint.Ipv4.sin_port)); + } + else if (ioctlPeer->Endpoint.si_family == Win32.ADDRESS_FAMILY.AF_INET6) + { + var ip = new byte[16]; + Marshal.Copy((IntPtr)ioctlPeer->Endpoint.Ipv6.sin6_addr.bytes, ip, 0, 16); + peer.Endpoint = new IPEndPoint(new IPAddress(ip), IPAddress.NetworkToHostOrder(ioctlPeer->Endpoint.Ipv6.sin6_port)); + } + } + peer.TxBytes = ioctlPeer->TxBytes; + peer.RxBytes = ioctlPeer->RxBytes; + if (ioctlPeer->LastHandshake != 0) + peer.LastHandshake = DateTime.FromFileTimeUtc((long)ioctlPeer->LastHandshake); + var allowedIPs = new AllowedIP[ioctlPeer->AllowedIPsCount]; + var ioctlAllowedIP = (IoctlAllowedIP*)((byte*)ioctlPeer + sizeof(IoctlPeer)); + for (UInt32 j = 0; j < allowedIPs.Length; ++j) + { + var allowedIP = new AllowedIP(); + if (ioctlAllowedIP->AddressFamily == Win32.ADDRESS_FAMILY.AF_INET) + { + var ip = new byte[4]; + Marshal.Copy((IntPtr)ioctlAllowedIP->V4.bytes, ip, 0, 4); + allowedIP.Address = new IPAddress(ip); + } + else if (ioctlAllowedIP->AddressFamily == Win32.ADDRESS_FAMILY.AF_INET6) + { + var ip = new byte[16]; + Marshal.Copy((IntPtr)ioctlAllowedIP->V6.bytes, ip, 0, 16); + allowedIP.Address = new IPAddress(ip); + } + allowedIP.Cidr = ioctlAllowedIP->Cidr; + allowedIPs[j] = allowedIP; + ioctlAllowedIP = (IoctlAllowedIP*)((byte*)ioctlAllowedIP + sizeof(IoctlAllowedIP)); + } + peer.AllowedIPs = allowedIPs; + peers[i] = peer; + ioctlPeer = (IoctlPeer*)ioctlAllowedIP; + } + iface.Peers = peers; + } + return iface; + } + + public class Key + { + private byte[] _bytes; + public byte[] Bytes + { + get + { + return _bytes; + } + set + { + if (value == null || value.Length != 32) + throw new ArgumentException("Keys must be 32 bytes"); + _bytes = value; + } + } + public Key(byte[] bytes) + { + Bytes = bytes; + } + public unsafe Key(byte* bytes) + { + _bytes = new byte[32]; + Marshal.Copy((IntPtr)bytes, _bytes, 0, 32); + } + public override String ToString() + { + return Convert.ToBase64String(_bytes); + } + } + + public class Interface + { + public UInt16 ListenPort { get; set; } + public Key PrivateKey { get; set; } + public Key PublicKey { get; set; } + public Peer[] Peers { get; set; } + } + + public class Peer + { + public Key PublicKey { get; set; } + public Key PresharedKey { get; set; } + public UInt16 PersistentKeepalive { get; set; } + public IPEndPoint Endpoint { get; set; } + public UInt64 TxBytes { get; set; } + public UInt64 RxBytes { get; set; } + public DateTime LastHandshake { get; set; } + public AllowedIP[] AllowedIPs { get; set; } + } + + public class AllowedIP + { + public IPAddress Address { get; set; } + public byte Cidr { get; set; } + } + + private enum IoctlInterfaceFlags : UInt32 + { + HasPublicKey = 1 << 0, + HasPrivateKey = 1 << 1, + HasListenPort = 1 << 2, + ReplacePeers = 1 << 3 + }; + + [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 80)] + private unsafe struct IoctlInterface + { + public IoctlInterfaceFlags Flags; + public UInt16 ListenPort; + public fixed byte PrivateKey[32]; + public fixed byte PublicKey[32]; + public UInt32 PeersCount; + }; + + private enum IoctlPeerFlags : UInt32 + { + HasPublicKey = 1 << 0, + HasPresharedKey = 1 << 1, + HasPersistentKeepalive = 1 << 2, + HasEndpoint = 1 << 3, + ReplaceAllowedIPs = 1 << 5, + Remove = 1 << 6, + Update = 1 << 7 + }; + + [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 136)] + private unsafe struct IoctlPeer + { + public IoctlPeerFlags Flags; + public UInt32 Reserved; + public fixed byte PublicKey[32]; + public fixed byte PresharedKey[32]; + public UInt16 PersistentKeepalive; + public Win32.SOCKADDR_INET Endpoint; + public UInt64 TxBytes, RxBytes; + public UInt64 LastHandshake; + public UInt32 AllowedIPsCount; + }; + + [StructLayout(LayoutKind.Explicit, Pack = 8, Size = 24)] + private unsafe struct IoctlAllowedIP + { + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Struct)] + public Win32.IN_ADDR V4; + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Struct)] + public Win32.IN6_ADDR V6; + [FieldOffset(16)] + public Win32.ADDRESS_FAMILY AddressFamily; + [FieldOffset(20)] + public byte Cidr; + } + } + } +} diff --git a/embeddable-dll-service/csharp/TunnelDll/Service.cs b/embeddable-dll-service/csharp/TunnelDll/Service.cs index 7f2c622e..8e25b6c4 100644 --- a/embeddable-dll-service/csharp/TunnelDll/Service.cs +++ b/embeddable-dll-service/csharp/TunnelDll/Service.cs @@ -21,10 +21,9 @@ namespace Tunnel [DllImport("tunnel.dll", EntryPoint = "WireGuardTunnelService", CallingConvention = CallingConvention.Cdecl)] public static extern bool Run([MarshalAs(UnmanagedType.LPWStr)] string configFile); - public static NamedPipeClientStream GetPipe(string configFile) + public static Driver.Adapter GetAdapter(string configFile) { - var pipepath = "ProtectedPrefix\\Administrators\\WireGuard\\" + Path.GetFileNameWithoutExtension(configFile); - return new NamedPipeClientStream(pipepath); + return new Driver.Adapter(Path.GetFileNameWithoutExtension(configFile)); } public static void Add(string configFile, bool ephemeral) diff --git a/embeddable-dll-service/csharp/TunnelDll/Win32.cs b/embeddable-dll-service/csharp/TunnelDll/Win32.cs index d8447f7f..4987fe8f 100644 --- a/embeddable-dll-service/csharp/TunnelDll/Win32.cs +++ b/embeddable-dll-service/csharp/TunnelDll/Win32.cs @@ -135,6 +135,58 @@ namespace Tunnel SidInfo = 5 } + [StructLayout(LayoutKind.Sequential)] + public unsafe struct IN_ADDR + { + public fixed byte bytes[4]; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct IN6_ADDR + { + public fixed byte bytes[16]; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SOCKADDR_IN + { + public ushort sin_family; + public ushort sin_port; + public IN_ADDR sin_addr; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SOCKADDR_IN6 + { + public ushort sin6_family; + public ushort sin6_port; + public uint sin6_flowinfo; + public IN6_ADDR sin6_addr; + public uint sin6_scope_id; + } + + [StructLayout(LayoutKind.Explicit)] + public struct SOCKADDR_INET + { + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Struct)] + public SOCKADDR_IN Ipv4; + + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Struct)] + public SOCKADDR_IN6 Ipv6; + + [FieldOffset(0)] + public ADDRESS_FAMILY si_family; + } + + public enum ADDRESS_FAMILY : UInt32 + { + AF_UNSPEC = 0, + AF_INET = 2, + AF_INET6 = 23 + } + [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr OpenSCManager(string machineName, string databaseName, ScmAccessRights dwDesiredAccess); |