Message ID | 20191217125041.207-1-lstipakov@gmail.com |
---|---|
State | Accepted |
Headers | show |
Series | None | expand |
Definitely an ack. We need this for Wintun and to drop that SYSTEM token hack. Acked-by: Simon Rozman <simon@rozman.si> Best regards, Simon > -----Original Message----- > From: Lev Stipakov <lstipakov@gmail.com> > Sent: Tuesday, December 17, 2019 1:51 PM > To: openvpn-devel@lists.sourceforge.net > Cc: Lev Stipakov <lev@openvpn.net> > Subject: [Openvpn-devel] [PATCH v5 5/7] wintun: interactive service > support > > From: Lev Stipakov <lev@openvpn.net> > > Wintun requires ring buffers registration to be performed by privileged > process. In order to use openvpn with wintun by non-Administrator, we > need to use interactive service and shared memory to register buffers. > > Openvpn process creates memory mapping object and event for send and > receive ring and passes handles to interactive service. There handles > are duplicated and memory mapped object is mapped into the address space > of service process. > Then address of mapped view and event handle is passed to wintun kernel > driver. > > After interactive service preformed registration, openvpn process maps > memory mapped object into own address space. Thus mapped views in > openvpn and service process represent the same memory region. > > Signed-off-by: Lev Stipakov <lev@openvpn.net> > --- > > While v2 has been ACKed, it had to be rebased on top of previous patch > in series, which required some manual work. > > v5: > - rebased on top of [PATCH v8 4/7] wintun: ring buffers based I/O > (fixed struct tun_ring layout and made DeviceIoControl result check > more robust) > > v4: > - rebased on top of [PATCH v5 4/7] "wintun: ring buffers based I/O" > > v3: > - rebased on top of [PATCH v4 4/7] "wintun: ring buffers based I/O" > - added doxygen comments to ring_buffer.h > > v2: > - rebased on top of master > > include/openvpn-msg.h | 10 ++ > src/openvpn/Makefile.am | 2 +- > src/openvpn/openvpn.vcxproj | 2 + > src/openvpn/openvpn.vcxproj.filters | 8 +- > src/openvpn/ring_buffer.c | 56 ++++++++ > src/openvpn/ring_buffer.h | 104 +++++++++++++++ > src/openvpn/tun.c | 82 ++++++++++-- > src/openvpn/tun.h | 3 + > src/openvpn/win32.c | 27 ---- > src/openvpn/win32.h | 46 ------- > src/openvpnserv/Makefile.am | 3 +- > src/openvpnserv/interactive.c | 141 +++++++++++++++++++- > src/openvpnserv/openvpnserv.vcxproj | 2 + > src/openvpnserv/openvpnserv.vcxproj.filters | 6 + > 14 files changed, 399 insertions(+), 93 deletions(-) create mode > 100644 src/openvpn/ring_buffer.c create mode 100644 > src/openvpn/ring_buffer.h > > diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index > 66177a21..3ed62069 100644 > --- a/include/openvpn-msg.h > +++ b/include/openvpn-msg.h > @@ -39,6 +39,7 @@ typedef enum { > msg_del_block_dns, > msg_register_dns, > msg_enable_dhcp, > + msg_register_ring_buffers > } message_type_t; > > typedef struct { > @@ -117,4 +118,13 @@ typedef struct { > interface_t iface; > } enable_dhcp_message_t; > > +typedef struct { > + message_header_t header; > + HANDLE device; > + HANDLE send_ring_handle; > + HANDLE receive_ring_handle; > + HANDLE send_tail_moved; > + HANDLE receive_tail_moved; > +} register_ring_buffers_message_t; > + > #endif /* ifndef OPENVPN_MSG_H_ */ > diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index > a091ffc2..d1bb99c2 100644 > --- a/src/openvpn/Makefile.am > +++ b/src/openvpn/Makefile.am > @@ -138,6 +138,6 @@ openvpn_LDADD = \ > $(OPTIONAL_SYSTEMD_LIBS) \ > $(OPTIONAL_DL_LIBS) > if WIN32 > -openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h > +openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h > +ring_buffer.c ring_buffer.h > openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi - > lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi endif diff --git > a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index > 7446d97d..614d720a 100644 > --- a/src/openvpn/openvpn.vcxproj > +++ b/src/openvpn/openvpn.vcxproj > @@ -181,6 +181,7 @@ > <ClCompile Include="ps.c" /> > <ClCompile Include="push.c" /> > <ClCompile Include="reliable.c" /> > + <ClCompile Include="ring_buffer.c" /> > <ClCompile Include="route.c" /> > <ClCompile Include="run_command.c" /> > <ClCompile Include="schedule.c" /> > @@ -265,6 +266,7 @@ > <ClInclude Include="push.h" /> > <ClInclude Include="pushlist.h" /> > <ClInclude Include="reliable.h" /> > + <ClInclude Include="ring_buffer.h" /> > <ClInclude Include="route.h" /> > <ClInclude Include="run_command.h" /> > <ClInclude Include="schedule.h" /> > diff --git a/src/openvpn/openvpn.vcxproj.filters > b/src/openvpn/openvpn.vcxproj.filters > index 653e892c..41e62d14 100644 > --- a/src/openvpn/openvpn.vcxproj.filters > +++ b/src/openvpn/openvpn.vcxproj.filters > @@ -240,6 +240,9 @@ > <ClCompile Include="vlan.c"> > <Filter>Source Files</Filter> > </ClCompile> > + <ClCompile Include="ring_buffer.c"> > + <Filter>Source Files</Filter> > + </ClCompile> > </ItemGroup> > <ItemGroup> > <ClInclude Include="base64.h"> > @@ -500,10 +503,13 @@ > <ClInclude Include="vlan.h"> > <Filter>Header Files</Filter> > </ClInclude> > + <ClInclude Include="ring_buffer.h"> > + <Filter>Header Files</Filter> > + </ClInclude> > </ItemGroup> > <ItemGroup> > <ResourceCompile Include="openvpn_win32_resources.rc"> > <Filter>Resource Files</Filter> > </ResourceCompile> > </ItemGroup> > -</Project> > \ No newline at end of file > +</Project> > diff --git a/src/openvpn/ring_buffer.c b/src/openvpn/ring_buffer.c new > file mode 100644 index 00000000..8c81dc46 > --- /dev/null > +++ b/src/openvpn/ring_buffer.c > @@ -0,0 +1,56 @@ > +/* > + * OpenVPN -- An application to securely tunnel IP networks > + * over a single UDP port, with support for SSL/TLS-based > + * session authentication and key exchange, > + * packet encryption, packet authentication, and > + * packet compression. > + * > + * Copyright (C) 2002-2019 OpenVPN Inc <sales@openvpn.net> > + * 2019 Lev Stipakov <lev@openvpn.net> > + * > + * This program is free software; you can redistribute it and/or > +modify > + * it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > +along > + * with this program; if not, write to the Free Software Foundation, > +Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > + */ > + > +#include "ring_buffer.h" > + > +#ifdef _WIN32 > + > +bool > +register_ring_buffers(HANDLE device, > + struct tun_ring *send_ring, > + struct tun_ring *receive_ring, > + HANDLE send_tail_moved, > + HANDLE receive_tail_moved) { > + struct tun_register_rings rr; > + BOOL res; > + DWORD bytes_returned; > + > + ZeroMemory(&rr, sizeof(rr)); > + > + rr.send.ring = send_ring; > + rr.send.ring_size = sizeof(struct tun_ring); > + rr.send.tail_moved = send_tail_moved; > + > + rr.receive.ring = receive_ring; > + rr.receive.ring_size = sizeof(struct tun_ring); > + rr.receive.tail_moved = receive_tail_moved; > + > + res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, > sizeof(rr), > + NULL, 0, &bytes_returned, NULL); > + > + return res != FALSE; > +} > + > +#endif /* ifdef _WIN32 */ > \ No newline at end of file > diff --git a/src/openvpn/ring_buffer.h b/src/openvpn/ring_buffer.h new > file mode 100644 index 00000000..3522c984 > --- /dev/null > +++ b/src/openvpn/ring_buffer.h > @@ -0,0 +1,104 @@ > +/* > + * OpenVPN -- An application to securely tunnel IP networks > + * over a single UDP port, with support for SSL/TLS-based > + * session authentication and key exchange, > + * packet encryption, packet authentication, and > + * packet compression. > + * > + * Copyright (C) 2002-2019 OpenVPN Inc <sales@openvpn.net> > + * 2019 Lev Stipakov <lev@openvpn.net> > + * > + * This program is free software; you can redistribute it and/or > +modify > + * it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > +along > + * with this program; if not, write to the Free Software Foundation, > +Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > + */ > + > +#ifdef _WIN32 > +#ifndef OPENVPN_RING_BUFFER_H > +#define OPENVPN_RING_BUFFER_H > + > +#include <windows.h> > +#include <winioctl.h> > + > +#include <stdint.h> > +#include <stdbool.h> > + > +/* > + * Values below are taken from Wireguard Windows client > + * > +https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_w > +indows.go#L14 > + */ > +#define WINTUN_RING_CAPACITY 0x800000 > +#define WINTUN_RING_TRAILING_BYTES 0x10000 > +#define WINTUN_MAX_PACKET_SIZE 0xffff > +#define WINTUN_PACKET_ALIGN 4 > + > +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, > +METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) > + > +/** > + * Wintun ring buffer > + * See https://github.com/WireGuard/wintun#ring-layout > + */ > +struct tun_ring > +{ > + volatile ULONG head; > + volatile ULONG tail; > + volatile LONG alertable; > + UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; }; > + > +/** > + * Struct for ring buffers registration > + * See https://github.com/WireGuard/wintun#registering-rings > + */ > +struct tun_register_rings > +{ > + struct > + { > + ULONG ring_size; > + struct tun_ring *ring; > + HANDLE tail_moved; > + } send, receive; > +}; > + > +struct TUN_PACKET_HEADER > +{ > + uint32_t size; > +}; > + > +struct TUN_PACKET > +{ > + uint32_t size; > + UCHAR data[WINTUN_MAX_PACKET_SIZE]; }; > + > +/** > + * Registers ring buffers used to exchange data between > + * userspace openvpn process and wintun kernel driver, > + * see https://github.com/WireGuard/wintun#registering-rings > + * > + * @param device handle to opened wintun device > + * @param send_ring pointer to send ring > + * @param receive_ring pointer to receive ring > + * @param send_tail_moved event set by wintun to signal openvpn > + * that data is available for reading in > send ring > + * @param receive_tail_moved event set by openvpn to signal wintun > + * that data has been written to receive > ring > + * @return true if registration is successful, false > otherwise > + */ > +bool register_ring_buffers(HANDLE device, > + struct tun_ring *send_ring, > + struct tun_ring *receive_ring, > + HANDLE send_tail_moved, > + HANDLE receive_tail_moved); > + > +#endif /* ifndef OPENVPN_RING_BUFFER_H */ #endif /* ifdef _WIN32 */ > diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index > 3f66b216..77d84fb2 100644 > --- a/src/openvpn/tun.c > +++ b/src/openvpn/tun.c > @@ -779,17 +779,29 @@ init_tun_post(struct tuntap *tt, > > if (tt->wintun) > { > - tt->wintun_send_ring = malloc(sizeof(struct tun_ring)); > - tt->wintun_receive_ring = malloc(sizeof(struct tun_ring)); > - if ((tt->wintun_send_ring == NULL) || (tt->wintun_receive_ring > == NULL)) > + tt->wintun_send_ring_handle = > CreateFileMapping(INVALID_HANDLE_VALUE, NULL, > + PAGE_READWRITE, > + 0, > + sizeof(struct > tun_ring), > + NULL); > + tt->wintun_receive_ring_handle = > CreateFileMapping(INVALID_HANDLE_VALUE, > + NULL, > + > PAGE_READWRITE, > + 0, > + > sizeof(struct tun_ring), > + NULL); > + if ((tt->wintun_send_ring_handle == NULL) || > + (tt->wintun_receive_ring_handle == NULL)) > { > msg(M_FATAL, "Cannot allocate memory for ring buffer"); > } > - ZeroMemory(tt->wintun_send_ring, sizeof(struct tun_ring)); > - ZeroMemory(tt->wintun_receive_ring, sizeof(struct tun_ring)); > > tt->rw_handle.read = CreateEvent(NULL, FALSE, FALSE, NULL); > tt->rw_handle.write = CreateEvent(NULL, FALSE, FALSE, NULL); > + > + if ((tt->rw_handle.read == NULL) || (tt->rw_handle.write == > NULL)) > + { > + msg(M_FATAL, "Cannot create events for ring buffer"); > + } > } > else > { > @@ -5604,6 +5616,44 @@ register_dns_service(const struct tuntap *tt) > gc_free(&gc); > } > > +static void > +service_register_ring_buffers(const struct tuntap *tt) { > + HANDLE msg_channel = tt->options.msg_channel; > + ack_message_t ack; > + struct gc_arena gc = gc_new(); > + > + register_ring_buffers_message_t msg = { > + .header = { > + msg_register_ring_buffers, > + sizeof(register_ring_buffers_message_t), > + 0 > + }, > + .device = tt->hand, > + .send_ring_handle = tt->wintun_send_ring_handle, > + .receive_ring_handle = tt->wintun_receive_ring_handle, > + .send_tail_moved = tt->rw_handle.read, > + .receive_tail_moved = tt->rw_handle.write > + }; > + > + if (!send_msg_iservice(msg_channel, &msg, sizeof(msg), &ack, > "Register ring buffers")) > + { > + gc_free(&gc); > + return; > + } > + else if (ack.error_number != NO_ERROR) > + { > + msg(M_FATAL, "Register ring buffers failed using service: %s > [status=0x%x]", > + strerror_win32(ack.error_number, &gc), ack.error_number); > + } > + else > + { > + msg(M_INFO, "Ring buffers registered via service"); > + } > + > + gc_free(&gc); > +} > + > void > fork_register_dns_action(struct tuntap *tt) { @@ -6198,9 +6248,20 @@ > open_tun(const char *dev, const char *dev_type, const char *dev_node, > struct tun > > if (tt->wintun) > { > + tt->wintun_send_ring = (struct tun_ring *)MapViewOfFile(tt- > >wintun_send_ring_handle, > + > FILE_MAP_ALL_ACCESS, > + 0, > + 0, > + > sizeof(struct tun_ring)); > + tt->wintun_receive_ring = (struct tun_ring *)MapViewOfFile(tt- > >wintun_receive_ring_handle, > + > FILE_MAP_ALL_ACCESS, > + 0, > + 0, > + > + sizeof(struct tun_ring)); > + > if (tt->options.msg_channel) > { > - /* TODO */ > + service_register_ring_buffers(tt); > } > else > { > @@ -6365,13 +6426,12 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t > *ctx) > { > CloseHandle(tt->rw_handle.read); > CloseHandle(tt->rw_handle.write); > + UnmapViewOfFile(tt->wintun_send_ring); > + UnmapViewOfFile(tt->wintun_receive_ring); > + CloseHandle(tt->wintun_send_ring_handle); > + CloseHandle(tt->wintun_receive_ring_handle); > } > > - free(tt->wintun_receive_ring); > - free(tt->wintun_send_ring); > - > - tt->wintun_receive_ring = NULL; > - tt->wintun_send_ring = NULL; > > clear_tuntap(tt); > free(tt); > diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index > 10f687c5..b0b80d1a 100644 > --- a/src/openvpn/tun.h > +++ b/src/openvpn/tun.h > @@ -39,6 +39,7 @@ > #include "proto.h" > #include "misc.h" > #include "networking.h" > +#include "ring_buffer.h" > > #ifdef _WIN32 > #define WINTUN_COMPONENT_ID "wintun" > @@ -183,6 +184,8 @@ struct tuntap > bool wintun; /* true if wintun is used instead of tap-windows6 */ > int standby_iter; > > + HANDLE wintun_send_ring_handle; > + HANDLE wintun_receive_ring_handle; > struct tun_ring *wintun_send_ring; > struct tun_ring *wintun_receive_ring; #else /* ifdef _WIN32 */ > diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index > 24dae7d6..b2f2a19f 100644 > --- a/src/openvpn/win32.c > +++ b/src/openvpn/win32.c > @@ -1588,31 +1588,4 @@ impersonate_as_system() > return true; > } > > -bool > -register_ring_buffers(HANDLE device, > - struct tun_ring* send_ring, > - struct tun_ring* receive_ring, > - HANDLE send_tail_moved, > - HANDLE receive_tail_moved) > -{ > - struct tun_register_rings rr; > - BOOL res; > - DWORD bytes_returned; > - > - ZeroMemory(&rr, sizeof(rr)); > - > - rr.send.ring = send_ring; > - rr.send.ring_size = sizeof(struct tun_ring); > - rr.send.tail_moved = send_tail_moved; > - > - rr.receive.ring = receive_ring; > - rr.receive.ring_size = sizeof(struct tun_ring); > - rr.receive.tail_moved = receive_tail_moved; > - > - res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, > sizeof(rr), > - NULL, 0, &bytes_returned, NULL); > - > - return res != FALSE; > -} > - > #endif /* ifdef _WIN32 */ > diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index > 5fe95f47..4b508c56 100644 > --- a/src/openvpn/win32.h > +++ b/src/openvpn/win32.h > @@ -325,53 +325,7 @@ bool send_msg_iservice(HANDLE pipe, const void > *data, size_t size, int openvpn_execve(const struct argv *a, const > struct env_set *es, const unsigned int flags); > > -/* > - * Values below are taken from Wireguard Windows client > - * https://github.com/WireGuard/wireguard- > go/blob/master/tun/wintun/ring_windows.go#L14 > - */ > -#define WINTUN_RING_CAPACITY 0x800000 > -#define WINTUN_RING_TRAILING_BYTES 0x10000 -#define > WINTUN_MAX_PACKET_SIZE 0xffff -#define WINTUN_PACKET_ALIGN 4 > - > -struct tun_ring > -{ > - volatile ULONG head; > - volatile ULONG tail; > - volatile LONG alertable; > - UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; > -}; > - > -struct tun_register_rings > -{ > - struct > - { > - ULONG ring_size; > - struct tun_ring *ring; > - HANDLE tail_moved; > - } send, receive; > -}; > - > -struct TUN_PACKET_HEADER > -{ > - uint32_t size; > -}; > - > -struct TUN_PACKET > -{ > - uint32_t size; > - UCHAR data[WINTUN_MAX_PACKET_SIZE]; > -}; > - > -#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, > METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) > - > bool impersonate_as_system(); > > -bool register_ring_buffers(HANDLE device, > - struct tun_ring *send_ring, > - struct tun_ring *receive_ring, > - HANDLE send_tail_moved, > - HANDLE receive_tail_moved); > - > #endif /* ifndef OPENVPN_WIN32_H */ > #endif /* ifdef _WIN32 */ > diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am > index bc65070b..f8d3319c 100644 > --- a/src/openvpnserv/Makefile.am > +++ b/src/openvpnserv/Makefile.am > @@ -36,4 +36,5 @@ openvpnserv_SOURCES = \ > service.c service.h \ > validate.c validate.h \ > $(top_srcdir)/src/openvpn/block_dns.c > $(top_srcdir)/src/openvpn/block_dns.h \ > - openvpnserv_resources.rc > + openvpnserv_resources.rc \ > + $(top_srcdir)/src/openvpn/ring_buffer.c > +$(top_srcdir)/src/openvpn/ring_buffer.h > diff --git a/src/openvpnserv/interactive.c > b/src/openvpnserv/interactive.c index 623c3ff7..6e72a141 100644 > --- a/src/openvpnserv/interactive.c > +++ b/src/openvpnserv/interactive.c > @@ -43,13 +43,15 @@ > #include "openvpn-msg.h" > #include "validate.h" > #include "block_dns.h" > +#include "ring_buffer.h" > > #define IO_TIMEOUT 2000 /*ms*/ > > -#define ERROR_OPENVPN_STARTUP 0x20000000 > -#define ERROR_STARTUP_DATA 0x20000001 > -#define ERROR_MESSAGE_DATA 0x20000002 > -#define ERROR_MESSAGE_TYPE 0x20000003 > +#define ERROR_OPENVPN_STARTUP 0x20000000 > +#define ERROR_STARTUP_DATA 0x20000001 > +#define ERROR_MESSAGE_DATA 0x20000002 > +#define ERROR_MESSAGE_TYPE 0x20000003 > +#define ERROR_REGISTER_RING_BUFFERS 0x20000004 > > static SERVICE_STATUS_HANDLE service; > static SERVICE_STATUS status = { .dwServiceType = > SERVICE_WIN32_SHARE_PROCESS }; @@ -58,6 +60,7 @@ static settings_t > settings; static HANDLE rdns_semaphore = NULL; #define RDNS_TIMEOUT > 600 /* seconds to wait for the semaphore */ > > +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, > +METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) > > openvpn_service_t interactive_service = { > interactive, > @@ -100,6 +103,14 @@ typedef struct { > int metric_v6; > } block_dns_data_t; > > +typedef struct { > + HANDLE send_ring_handle; > + HANDLE receive_ring_handle; > + HANDLE send_tail_moved; > + HANDLE receive_tail_moved; > + HANDLE device; > +} ring_buffer_handles_t; > + > > static DWORD > AddListItem(list_item_t **pfirst, LPVOID data) @@ -154,6 +165,26 @@ > CloseHandleEx(LPHANDLE handle) > return INVALID_HANDLE_VALUE; > } > > +static HANDLE > +OvpnUnmapViewOfFile(LPHANDLE handle) > +{ > + if (handle && *handle && *handle != INVALID_HANDLE_VALUE) > + { > + UnmapViewOfFile(*handle); > + *handle = INVALID_HANDLE_VALUE; > + } > + return INVALID_HANDLE_VALUE; > +} > + > +static void > +CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles) { > + CloseHandleEx(&ring_buffer_handles->device); > + CloseHandleEx(&ring_buffer_handles->receive_tail_moved); > + CloseHandleEx(&ring_buffer_handles->send_tail_moved); > + OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle); > + OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle); > +} > > static HANDLE > InitOverlapped(LPOVERLAPPED overlapped) @@ -1198,8 +1229,95 @@ > HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp) > return err; > } > > +static DWORD > +OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* > +new_handle) { > + DWORD err = ERROR_SUCCESS; > + > + if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), > new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) > + { > + err = GetLastError(); > + MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle")); > + return err; > + } > + > + return err; > +} > + > +static DWORD > +DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE > +*new_handle, struct tun_ring **ring) { > + DWORD err = ERROR_SUCCESS; > + > + err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle); > + if (err != ERROR_SUCCESS) > + { > + return err; > + } > + *ring = (struct tun_ring *)MapViewOfFile(*new_handle, > FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); > + if (*ring == NULL) > + { > + err = GetLastError(); > + MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory")); > + return err; > + } > + > + return err; > +} > + > +static DWORD > +HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, > HANDLE ovpn_proc, > + ring_buffer_handles_t *ring_buffer_handles) { > + DWORD err = 0; > + struct tun_ring *send_ring; > + struct tun_ring *receive_ring; > + > + CloseRingBufferHandles(ring_buffer_handles); > + > + err = OvpnDuplicateHandle(ovpn_proc, rrb->device, > &ring_buffer_handles->device); > + if (err != ERROR_SUCCESS) > + { > + return err; > + } > + > + err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, > &ring_buffer_handles->send_ring_handle, &send_ring); > + if (err != ERROR_SUCCESS) > + { > + return err; > + } > + > + err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, > &ring_buffer_handles->receive_ring_handle, &receive_ring); > + if (err != ERROR_SUCCESS) > + { > + return err; > + } > + > + err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, > &ring_buffer_handles->send_tail_moved); > + if (err != ERROR_SUCCESS) > + { > + return err; > + } > + > + err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, > &ring_buffer_handles->receive_tail_moved); > + if (err != ERROR_SUCCESS) > + { > + return err; > + } > + > + if (!register_ring_buffers(ring_buffer_handles->device, send_ring, > receive_ring, > + ring_buffer_handles->send_tail_moved, > ring_buffer_handles->receive_tail_moved)) > + { > + MsgToEventLog(M_SYSERR, TEXT("Could not register ring > buffers")); > + err = ERROR_REGISTER_RING_BUFFERS; > + } > + > + return err; > +} > + > static VOID > -HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, > undo_lists_t *lists) > +HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t > *ring_buffer_handles, > + DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t > +*lists) > { > DWORD read; > union { > @@ -1210,6 +1328,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD > count, LPHANDLE events, undo_lists > block_dns_message_t block_dns; > dns_cfg_message_t dns; > enable_dhcp_message_t dhcp; > + register_ring_buffers_message_t rrb; > } msg; > ack_message_t ack = { > .header = { > @@ -1277,6 +1396,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD > count, LPHANDLE events, undo_lists > } > break; > > + case msg_register_ring_buffers: > + if (msg.header.size == sizeof(msg.rrb)) > + { > + ack.error_number = HandleRegisterRingBuffers(&msg.rrb, > ovpn_proc, ring_buffer_handles); > + } > + break; > + > default: > ack.error_number = ERROR_MESSAGE_TYPE; > MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type > %d"), msg.header.type); @@ -1360,6 +1486,7 @@ RunOpenvpn(LPVOID p) > WCHAR *cmdline = NULL; > size_t cmdline_size; > undo_lists_t undo_lists; > + ring_buffer_handles_t ring_buffer_handles; > > SECURITY_ATTRIBUTES inheritable = { > .nLength = sizeof(inheritable), @@ -1380,6 +1507,7 @@ > RunOpenvpn(LPVOID p) > ZeroMemory(&startup_info, sizeof(startup_info)); > ZeroMemory(&undo_lists, sizeof(undo_lists)); > ZeroMemory(&proc_info, sizeof(proc_info)); > + ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles)); > > if (!GetStartupData(pipe, &sud)) > { > @@ -1611,7 +1739,7 @@ RunOpenvpn(LPVOID p) > break; > } > > - HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists); > + HandleMessage(ovpn_pipe, proc_info.hProcess, > + &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists); > } > > WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT); @@ -1638,6 > +1766,7 @@ out: > free(cmdline); > DestroyEnvironmentBlock(user_env); > FreeStartupData(&sud); > + CloseRingBufferHandles(&ring_buffer_handles); > CloseHandleEx(&proc_info.hProcess); > CloseHandleEx(&proc_info.hThread); > CloseHandleEx(&stdin_read); > diff --git a/src/openvpnserv/openvpnserv.vcxproj > b/src/openvpnserv/openvpnserv.vcxproj > index 7061b7b1..c5a34b87 100644 > --- a/src/openvpnserv/openvpnserv.vcxproj > +++ b/src/openvpnserv/openvpnserv.vcxproj > @@ -115,6 +115,7 @@ > </Link> > </ItemDefinitionGroup> > <ItemGroup> > + <ClCompile Include="..\openvpn\ring_buffer.c" /> > <ClCompile Include="automatic.c" /> > <ClCompile Include="common.c" /> > <ClCompile Include="interactive.c" /> @@ -123,6 +124,7 @@ > <ClCompile Include="..\openvpn\block_dns.c" /> > </ItemGroup> > <ItemGroup> > + <ClInclude Include="..\openvpn\ring_buffer.h" /> > <ClInclude Include="service.h" /> > <ClInclude Include="validate.h" /> > <ClInclude Include="..\openvpn\block_dns.h" /> diff --git > a/src/openvpnserv/openvpnserv.vcxproj.filters > b/src/openvpnserv/openvpnserv.vcxproj.filters > index 3ce9bb24..3cb14ef6 100644 > --- a/src/openvpnserv/openvpnserv.vcxproj.filters > +++ b/src/openvpnserv/openvpnserv.vcxproj.filters > @@ -33,6 +33,9 @@ > <ClCompile Include="..\openvpn\block_dns.c"> > <Filter>Source Files</Filter> > </ClCompile> > + <ClCompile Include="..\openvpn\ring_buffer.c"> > + <Filter>Source Files</Filter> > + </ClCompile> > </ItemGroup> > <ItemGroup> > <ClInclude Include="service.h"> > @@ -44,6 +47,9 @@ > <ClInclude Include="..\openvpn\block_dns.h"> > <Filter>Header Files</Filter> > </ClInclude> > + <ClInclude Include="..\openvpn\ring_buffer.h"> > + <Filter>Header Files</Filter> > + </ClInclude> > </ItemGroup> > <ItemGroup> > <ResourceCompile Include="openvpnserv_resources.rc"> > -- > 2.17.1 > > > > _______________________________________________ > Openvpn-devel mailing list > Openvpn-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/openvpn-devel
Your patch has been applied to the master branch. (An ACK on v2, an ACK on v5, this is v5 :-) ). Test built on Ubuntu 1604 (works), not actually tested anything. Did a little bit of stare-at-code, which did not turn up anything I need to complain about... introducing a new ring_buffer.c file for less lines of code than the ring_buffer.h header file has seems a bit excessive, but since this is shared code between openvpn and iservice, it makes sense. commit da2e66ca74688094a3dcbf8e2ce0a3bc54478a53 Author: Lev Stipakov Date: Tue Dec 17 14:50:41 2019 +0200 wintun: interactive service support Signed-off-by: Lev Stipakov <lev@openvpn.net> Acked-by: Simon Rozman <simon@rozman.si> Message-Id: <20191217125041.207-1-lstipakov@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg19244.html Signed-off-by: Gert Doering <gert@greenie.muc.de> -- kind regards, Gert Doering
diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 66177a21..3ed62069 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -39,6 +39,7 @@ typedef enum { msg_del_block_dns, msg_register_dns, msg_enable_dhcp, + msg_register_ring_buffers } message_type_t; typedef struct { @@ -117,4 +118,13 @@ typedef struct { interface_t iface; } enable_dhcp_message_t; +typedef struct { + message_header_t header; + HANDLE device; + HANDLE send_ring_handle; + HANDLE receive_ring_handle; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; +} register_ring_buffers_message_t; + #endif /* ifndef OPENVPN_MSG_H_ */ diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a091ffc2..d1bb99c2 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -138,6 +138,6 @@ openvpn_LDADD = \ $(OPTIONAL_SYSTEMD_LIBS) \ $(OPTIONAL_DL_LIBS) if WIN32 -openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h +openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h ring_buffer.c ring_buffer.h openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi endif diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 7446d97d..614d720a 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -181,6 +181,7 @@ <ClCompile Include="ps.c" /> <ClCompile Include="push.c" /> <ClCompile Include="reliable.c" /> + <ClCompile Include="ring_buffer.c" /> <ClCompile Include="route.c" /> <ClCompile Include="run_command.c" /> <ClCompile Include="schedule.c" /> @@ -265,6 +266,7 @@ <ClInclude Include="push.h" /> <ClInclude Include="pushlist.h" /> <ClInclude Include="reliable.h" /> + <ClInclude Include="ring_buffer.h" /> <ClInclude Include="route.h" /> <ClInclude Include="run_command.h" /> <ClInclude Include="schedule.h" /> diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index 653e892c..41e62d14 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -240,6 +240,9 @@ <ClCompile Include="vlan.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="ring_buffer.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="base64.h"> @@ -500,10 +503,13 @@ <ClInclude Include="vlan.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="ring_buffer.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="openvpn_win32_resources.rc"> <Filter>Resource Files</Filter> </ResourceCompile> </ItemGroup> -</Project> \ No newline at end of file +</Project> diff --git a/src/openvpn/ring_buffer.c b/src/openvpn/ring_buffer.c new file mode 100644 index 00000000..8c81dc46 --- /dev/null +++ b/src/openvpn/ring_buffer.c @@ -0,0 +1,56 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2019 OpenVPN Inc <sales@openvpn.net> + * 2019 Lev Stipakov <lev@openvpn.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "ring_buffer.h" + +#ifdef _WIN32 + +bool +register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved) +{ + struct tun_register_rings rr; + BOOL res; + DWORD bytes_returned; + + ZeroMemory(&rr, sizeof(rr)); + + rr.send.ring = send_ring; + rr.send.ring_size = sizeof(struct tun_ring); + rr.send.tail_moved = send_tail_moved; + + rr.receive.ring = receive_ring; + rr.receive.ring_size = sizeof(struct tun_ring); + rr.receive.tail_moved = receive_tail_moved; + + res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), + NULL, 0, &bytes_returned, NULL); + + return res != FALSE; +} + +#endif /* ifdef _WIN32 */ \ No newline at end of file diff --git a/src/openvpn/ring_buffer.h b/src/openvpn/ring_buffer.h new file mode 100644 index 00000000..3522c984 --- /dev/null +++ b/src/openvpn/ring_buffer.h @@ -0,0 +1,104 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2019 OpenVPN Inc <sales@openvpn.net> + * 2019 Lev Stipakov <lev@openvpn.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef _WIN32 +#ifndef OPENVPN_RING_BUFFER_H +#define OPENVPN_RING_BUFFER_H + +#include <windows.h> +#include <winioctl.h> + +#include <stdint.h> +#include <stdbool.h> + +/* + * Values below are taken from Wireguard Windows client + * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14 + */ +#define WINTUN_RING_CAPACITY 0x800000 +#define WINTUN_RING_TRAILING_BYTES 0x10000 +#define WINTUN_MAX_PACKET_SIZE 0xffff +#define WINTUN_PACKET_ALIGN 4 + +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +/** + * Wintun ring buffer + * See https://github.com/WireGuard/wintun#ring-layout + */ +struct tun_ring +{ + volatile ULONG head; + volatile ULONG tail; + volatile LONG alertable; + UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; +}; + +/** + * Struct for ring buffers registration + * See https://github.com/WireGuard/wintun#registering-rings + */ +struct tun_register_rings +{ + struct + { + ULONG ring_size; + struct tun_ring *ring; + HANDLE tail_moved; + } send, receive; +}; + +struct TUN_PACKET_HEADER +{ + uint32_t size; +}; + +struct TUN_PACKET +{ + uint32_t size; + UCHAR data[WINTUN_MAX_PACKET_SIZE]; +}; + +/** + * Registers ring buffers used to exchange data between + * userspace openvpn process and wintun kernel driver, + * see https://github.com/WireGuard/wintun#registering-rings + * + * @param device handle to opened wintun device + * @param send_ring pointer to send ring + * @param receive_ring pointer to receive ring + * @param send_tail_moved event set by wintun to signal openvpn + * that data is available for reading in send ring + * @param receive_tail_moved event set by openvpn to signal wintun + * that data has been written to receive ring + * @return true if registration is successful, false otherwise + */ +bool register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved); + +#endif /* ifndef OPENVPN_RING_BUFFER_H */ +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 3f66b216..77d84fb2 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -779,17 +779,29 @@ init_tun_post(struct tuntap *tt, if (tt->wintun) { - tt->wintun_send_ring = malloc(sizeof(struct tun_ring)); - tt->wintun_receive_ring = malloc(sizeof(struct tun_ring)); - if ((tt->wintun_send_ring == NULL) || (tt->wintun_receive_ring == NULL)) + tt->wintun_send_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, + 0, + sizeof(struct tun_ring), + NULL); + tt->wintun_receive_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + sizeof(struct tun_ring), + NULL); + if ((tt->wintun_send_ring_handle == NULL) || (tt->wintun_receive_ring_handle == NULL)) { msg(M_FATAL, "Cannot allocate memory for ring buffer"); } - ZeroMemory(tt->wintun_send_ring, sizeof(struct tun_ring)); - ZeroMemory(tt->wintun_receive_ring, sizeof(struct tun_ring)); tt->rw_handle.read = CreateEvent(NULL, FALSE, FALSE, NULL); tt->rw_handle.write = CreateEvent(NULL, FALSE, FALSE, NULL); + + if ((tt->rw_handle.read == NULL) || (tt->rw_handle.write == NULL)) + { + msg(M_FATAL, "Cannot create events for ring buffer"); + } } else { @@ -5604,6 +5616,44 @@ register_dns_service(const struct tuntap *tt) gc_free(&gc); } +static void +service_register_ring_buffers(const struct tuntap *tt) +{ + HANDLE msg_channel = tt->options.msg_channel; + ack_message_t ack; + struct gc_arena gc = gc_new(); + + register_ring_buffers_message_t msg = { + .header = { + msg_register_ring_buffers, + sizeof(register_ring_buffers_message_t), + 0 + }, + .device = tt->hand, + .send_ring_handle = tt->wintun_send_ring_handle, + .receive_ring_handle = tt->wintun_receive_ring_handle, + .send_tail_moved = tt->rw_handle.read, + .receive_tail_moved = tt->rw_handle.write + }; + + if (!send_msg_iservice(msg_channel, &msg, sizeof(msg), &ack, "Register ring buffers")) + { + gc_free(&gc); + return; + } + else if (ack.error_number != NO_ERROR) + { + msg(M_FATAL, "Register ring buffers failed using service: %s [status=0x%x]", + strerror_win32(ack.error_number, &gc), ack.error_number); + } + else + { + msg(M_INFO, "Ring buffers registered via service"); + } + + gc_free(&gc); +} + void fork_register_dns_action(struct tuntap *tt) { @@ -6198,9 +6248,20 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (tt->wintun) { + tt->wintun_send_ring = (struct tun_ring *)MapViewOfFile(tt->wintun_send_ring_handle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + sizeof(struct tun_ring)); + tt->wintun_receive_ring = (struct tun_ring *)MapViewOfFile(tt->wintun_receive_ring_handle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + sizeof(struct tun_ring)); + if (tt->options.msg_channel) { - /* TODO */ + service_register_ring_buffers(tt); } else { @@ -6365,13 +6426,12 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) { CloseHandle(tt->rw_handle.read); CloseHandle(tt->rw_handle.write); + UnmapViewOfFile(tt->wintun_send_ring); + UnmapViewOfFile(tt->wintun_receive_ring); + CloseHandle(tt->wintun_send_ring_handle); + CloseHandle(tt->wintun_receive_ring_handle); } - free(tt->wintun_receive_ring); - free(tt->wintun_send_ring); - - tt->wintun_receive_ring = NULL; - tt->wintun_send_ring = NULL; clear_tuntap(tt); free(tt); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 10f687c5..b0b80d1a 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -39,6 +39,7 @@ #include "proto.h" #include "misc.h" #include "networking.h" +#include "ring_buffer.h" #ifdef _WIN32 #define WINTUN_COMPONENT_ID "wintun" @@ -183,6 +184,8 @@ struct tuntap bool wintun; /* true if wintun is used instead of tap-windows6 */ int standby_iter; + HANDLE wintun_send_ring_handle; + HANDLE wintun_receive_ring_handle; struct tun_ring *wintun_send_ring; struct tun_ring *wintun_receive_ring; #else /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 24dae7d6..b2f2a19f 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1588,31 +1588,4 @@ impersonate_as_system() return true; } -bool -register_ring_buffers(HANDLE device, - struct tun_ring* send_ring, - struct tun_ring* receive_ring, - HANDLE send_tail_moved, - HANDLE receive_tail_moved) -{ - struct tun_register_rings rr; - BOOL res; - DWORD bytes_returned; - - ZeroMemory(&rr, sizeof(rr)); - - rr.send.ring = send_ring; - rr.send.ring_size = sizeof(struct tun_ring); - rr.send.tail_moved = send_tail_moved; - - rr.receive.ring = receive_ring; - rr.receive.ring_size = sizeof(struct tun_ring); - rr.receive.tail_moved = receive_tail_moved; - - res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), - NULL, 0, &bytes_returned, NULL); - - return res != FALSE; -} - #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 5fe95f47..4b508c56 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -325,53 +325,7 @@ bool send_msg_iservice(HANDLE pipe, const void *data, size_t size, int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags); -/* - * Values below are taken from Wireguard Windows client - * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14 - */ -#define WINTUN_RING_CAPACITY 0x800000 -#define WINTUN_RING_TRAILING_BYTES 0x10000 -#define WINTUN_MAX_PACKET_SIZE 0xffff -#define WINTUN_PACKET_ALIGN 4 - -struct tun_ring -{ - volatile ULONG head; - volatile ULONG tail; - volatile LONG alertable; - UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; -}; - -struct tun_register_rings -{ - struct - { - ULONG ring_size; - struct tun_ring *ring; - HANDLE tail_moved; - } send, receive; -}; - -struct TUN_PACKET_HEADER -{ - uint32_t size; -}; - -struct TUN_PACKET -{ - uint32_t size; - UCHAR data[WINTUN_MAX_PACKET_SIZE]; -}; - -#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) - bool impersonate_as_system(); -bool register_ring_buffers(HANDLE device, - struct tun_ring *send_ring, - struct tun_ring *receive_ring, - HANDLE send_tail_moved, - HANDLE receive_tail_moved); - #endif /* ifndef OPENVPN_WIN32_H */ #endif /* ifdef _WIN32 */ diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index bc65070b..f8d3319c 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -36,4 +36,5 @@ openvpnserv_SOURCES = \ service.c service.h \ validate.c validate.h \ $(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \ - openvpnserv_resources.rc + openvpnserv_resources.rc \ + $(top_srcdir)/src/openvpn/ring_buffer.c $(top_srcdir)/src/openvpn/ring_buffer.h diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 623c3ff7..6e72a141 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -43,13 +43,15 @@ #include "openvpn-msg.h" #include "validate.h" #include "block_dns.h" +#include "ring_buffer.h" #define IO_TIMEOUT 2000 /*ms*/ -#define ERROR_OPENVPN_STARTUP 0x20000000 -#define ERROR_STARTUP_DATA 0x20000001 -#define ERROR_MESSAGE_DATA 0x20000002 -#define ERROR_MESSAGE_TYPE 0x20000003 +#define ERROR_OPENVPN_STARTUP 0x20000000 +#define ERROR_STARTUP_DATA 0x20000001 +#define ERROR_MESSAGE_DATA 0x20000002 +#define ERROR_MESSAGE_TYPE 0x20000003 +#define ERROR_REGISTER_RING_BUFFERS 0x20000004 static SERVICE_STATUS_HANDLE service; static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS }; @@ -58,6 +60,7 @@ static settings_t settings; static HANDLE rdns_semaphore = NULL; #define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */ +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) openvpn_service_t interactive_service = { interactive, @@ -100,6 +103,14 @@ typedef struct { int metric_v6; } block_dns_data_t; +typedef struct { + HANDLE send_ring_handle; + HANDLE receive_ring_handle; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; + HANDLE device; +} ring_buffer_handles_t; + static DWORD AddListItem(list_item_t **pfirst, LPVOID data) @@ -154,6 +165,26 @@ CloseHandleEx(LPHANDLE handle) return INVALID_HANDLE_VALUE; } +static HANDLE +OvpnUnmapViewOfFile(LPHANDLE handle) +{ + if (handle && *handle && *handle != INVALID_HANDLE_VALUE) + { + UnmapViewOfFile(*handle); + *handle = INVALID_HANDLE_VALUE; + } + return INVALID_HANDLE_VALUE; +} + +static void +CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles) +{ + CloseHandleEx(&ring_buffer_handles->device); + CloseHandleEx(&ring_buffer_handles->receive_tail_moved); + CloseHandleEx(&ring_buffer_handles->send_tail_moved); + OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle); + OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle); +} static HANDLE InitOverlapped(LPOVERLAPPED overlapped) @@ -1198,8 +1229,95 @@ HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp) return err; } +static DWORD +OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle) +{ + DWORD err = ERROR_SUCCESS; + + if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + err = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle")); + return err; + } + + return err; +} + +static DWORD +DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring) +{ + DWORD err = ERROR_SUCCESS; + + err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle); + if (err != ERROR_SUCCESS) + { + return err; + } + *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); + if (*ring == NULL) + { + err = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory")); + return err; + } + + return err; +} + +static DWORD +HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc, + ring_buffer_handles_t *ring_buffer_handles) +{ + DWORD err = 0; + struct tun_ring *send_ring; + struct tun_ring *receive_ring; + + CloseRingBufferHandles(ring_buffer_handles); + + err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved); + if (err != ERROR_SUCCESS) + { + return err; + } + + if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring, + ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved)) + { + MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers")); + err = ERROR_REGISTER_RING_BUFFERS; + } + + return err; +} + static VOID -HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) +HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles, + DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { DWORD read; union { @@ -1210,6 +1328,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists block_dns_message_t block_dns; dns_cfg_message_t dns; enable_dhcp_message_t dhcp; + register_ring_buffers_message_t rrb; } msg; ack_message_t ack = { .header = { @@ -1277,6 +1396,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists } break; + case msg_register_ring_buffers: + if (msg.header.size == sizeof(msg.rrb)) + { + ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles); + } + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1360,6 +1486,7 @@ RunOpenvpn(LPVOID p) WCHAR *cmdline = NULL; size_t cmdline_size; undo_lists_t undo_lists; + ring_buffer_handles_t ring_buffer_handles; SECURITY_ATTRIBUTES inheritable = { .nLength = sizeof(inheritable), @@ -1380,6 +1507,7 @@ RunOpenvpn(LPVOID p) ZeroMemory(&startup_info, sizeof(startup_info)); ZeroMemory(&undo_lists, sizeof(undo_lists)); ZeroMemory(&proc_info, sizeof(proc_info)); + ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles)); if (!GetStartupData(pipe, &sud)) { @@ -1611,7 +1739,7 @@ RunOpenvpn(LPVOID p) break; } - HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists); + HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists); } WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT); @@ -1638,6 +1766,7 @@ out: free(cmdline); DestroyEnvironmentBlock(user_env); FreeStartupData(&sud); + CloseRingBufferHandles(&ring_buffer_handles); CloseHandleEx(&proc_info.hProcess); CloseHandleEx(&proc_info.hThread); CloseHandleEx(&stdin_read); diff --git a/src/openvpnserv/openvpnserv.vcxproj b/src/openvpnserv/openvpnserv.vcxproj index 7061b7b1..c5a34b87 100644 --- a/src/openvpnserv/openvpnserv.vcxproj +++ b/src/openvpnserv/openvpnserv.vcxproj @@ -115,6 +115,7 @@ </Link> </ItemDefinitionGroup> <ItemGroup> + <ClCompile Include="..\openvpn\ring_buffer.c" /> <ClCompile Include="automatic.c" /> <ClCompile Include="common.c" /> <ClCompile Include="interactive.c" /> @@ -123,6 +124,7 @@ <ClCompile Include="..\openvpn\block_dns.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\openvpn\ring_buffer.h" /> <ClInclude Include="service.h" /> <ClInclude Include="validate.h" /> <ClInclude Include="..\openvpn\block_dns.h" /> diff --git a/src/openvpnserv/openvpnserv.vcxproj.filters b/src/openvpnserv/openvpnserv.vcxproj.filters index 3ce9bb24..3cb14ef6 100644 --- a/src/openvpnserv/openvpnserv.vcxproj.filters +++ b/src/openvpnserv/openvpnserv.vcxproj.filters @@ -33,6 +33,9 @@ <ClCompile Include="..\openvpn\block_dns.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\openvpn\ring_buffer.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="service.h"> @@ -44,6 +47,9 @@ <ClInclude Include="..\openvpn\block_dns.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\openvpn\ring_buffer.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="openvpnserv_resources.rc">