Browse code

wintun: interactive service support

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>
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>

Lev Stipakov authored on 2019/12/17 21:50:41
Showing 14 changed files
... ...
@@ -39,6 +39,7 @@ typedef enum {
39 39
     msg_del_block_dns,
40 40
     msg_register_dns,
41 41
     msg_enable_dhcp,
42
+    msg_register_ring_buffers
42 43
 } message_type_t;
43 44
 
44 45
 typedef struct {
... ...
@@ -117,4 +118,13 @@ typedef struct {
117 117
     interface_t iface;
118 118
 } enable_dhcp_message_t;
119 119
 
120
+typedef struct {
121
+    message_header_t header;
122
+    HANDLE device;
123
+    HANDLE send_ring_handle;
124
+    HANDLE receive_ring_handle;
125
+    HANDLE send_tail_moved;
126
+    HANDLE receive_tail_moved;
127
+} register_ring_buffers_message_t;
128
+
120 129
 #endif /* ifndef OPENVPN_MSG_H_ */
... ...
@@ -138,6 +138,6 @@ openvpn_LDADD = \
138 138
 	$(OPTIONAL_SYSTEMD_LIBS) \
139 139
 	$(OPTIONAL_DL_LIBS)
140 140
 if WIN32
141
-openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h
141
+openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h ring_buffer.c ring_buffer.h
142 142
 openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi
143 143
 endif
... ...
@@ -181,6 +181,7 @@
181 181
     <ClCompile Include="ps.c" />
182 182
     <ClCompile Include="push.c" />
183 183
     <ClCompile Include="reliable.c" />
184
+    <ClCompile Include="ring_buffer.c" />
184 185
     <ClCompile Include="route.c" />
185 186
     <ClCompile Include="run_command.c" />
186 187
     <ClCompile Include="schedule.c" />
... ...
@@ -265,6 +266,7 @@
265 265
     <ClInclude Include="push.h" />
266 266
     <ClInclude Include="pushlist.h" />
267 267
     <ClInclude Include="reliable.h" />
268
+    <ClInclude Include="ring_buffer.h" />
268 269
     <ClInclude Include="route.h" />
269 270
     <ClInclude Include="run_command.h" />
270 271
     <ClInclude Include="schedule.h" />
... ...
@@ -240,6 +240,9 @@
240 240
     <ClCompile Include="vlan.c">
241 241
       <Filter>Source Files</Filter>
242 242
     </ClCompile>
243
+    <ClCompile Include="ring_buffer.c">
244
+      <Filter>Source Files</Filter>
245
+    </ClCompile>
243 246
   </ItemGroup>
244 247
   <ItemGroup>
245 248
     <ClInclude Include="base64.h">
... ...
@@ -500,10 +503,13 @@
500 500
     <ClInclude Include="vlan.h">
501 501
       <Filter>Header Files</Filter>
502 502
     </ClInclude>
503
+    <ClInclude Include="ring_buffer.h">
504
+      <Filter>Header Files</Filter>
505
+    </ClInclude>
503 506
   </ItemGroup>
504 507
   <ItemGroup>
505 508
     <ResourceCompile Include="openvpn_win32_resources.rc">
506 509
       <Filter>Resource Files</Filter>
507 510
     </ResourceCompile>
508 511
   </ItemGroup>
509
-</Project>
510 512
\ No newline at end of file
513
+</Project>
511 514
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2019 OpenVPN Inc <sales@openvpn.net>
8
+ *                2019 Lev Stipakov <lev@openvpn.net>
9
+ *
10
+ *  This program is free software; you can redistribute it and/or modify
11
+ *  it under the terms of the GNU General Public License version 2
12
+ *  as published by the Free Software Foundation.
13
+ *
14
+ *  This program is distributed in the hope that it will be useful,
15
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ *  GNU General Public License for more details.
18
+ *
19
+ *  You should have received a copy of the GNU General Public License along
20
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
21
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
+ */
23
+
24
+#include "ring_buffer.h"
25
+
26
+#ifdef _WIN32
27
+
28
+bool
29
+register_ring_buffers(HANDLE device,
30
+                      struct tun_ring *send_ring,
31
+                      struct tun_ring *receive_ring,
32
+                      HANDLE send_tail_moved,
33
+                      HANDLE receive_tail_moved)
34
+{
35
+    struct tun_register_rings rr;
36
+    BOOL res;
37
+    DWORD bytes_returned;
38
+
39
+    ZeroMemory(&rr, sizeof(rr));
40
+
41
+    rr.send.ring = send_ring;
42
+    rr.send.ring_size = sizeof(struct tun_ring);
43
+    rr.send.tail_moved = send_tail_moved;
44
+
45
+    rr.receive.ring = receive_ring;
46
+    rr.receive.ring_size = sizeof(struct tun_ring);
47
+    rr.receive.tail_moved = receive_tail_moved;
48
+
49
+    res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr),
50
+                          NULL, 0, &bytes_returned, NULL);
51
+
52
+    return res != FALSE;
53
+}
54
+
55
+#endif /* ifdef _WIN32 */
0 56
\ No newline at end of file
1 57
new file mode 100644
... ...
@@ -0,0 +1,104 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2019 OpenVPN Inc <sales@openvpn.net>
8
+ *                2019 Lev Stipakov <lev@openvpn.net>
9
+ *
10
+ *  This program is free software; you can redistribute it and/or modify
11
+ *  it under the terms of the GNU General Public License version 2
12
+ *  as published by the Free Software Foundation.
13
+ *
14
+ *  This program is distributed in the hope that it will be useful,
15
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ *  GNU General Public License for more details.
18
+ *
19
+ *  You should have received a copy of the GNU General Public License along
20
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
21
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
+ */
23
+
24
+#ifdef _WIN32
25
+#ifndef OPENVPN_RING_BUFFER_H
26
+#define OPENVPN_RING_BUFFER_H
27
+
28
+#include <windows.h>
29
+#include <winioctl.h>
30
+
31
+#include <stdint.h>
32
+#include <stdbool.h>
33
+
34
+/*
35
+ * Values below are taken from Wireguard Windows client
36
+ * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14
37
+ */
38
+#define WINTUN_RING_CAPACITY        0x800000
39
+#define WINTUN_RING_TRAILING_BYTES  0x10000
40
+#define WINTUN_MAX_PACKET_SIZE      0xffff
41
+#define WINTUN_PACKET_ALIGN         4
42
+
43
+#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
44
+
45
+/**
46
+ * Wintun ring buffer
47
+ * See https://github.com/WireGuard/wintun#ring-layout
48
+ */
49
+struct tun_ring
50
+{
51
+    volatile ULONG head;
52
+    volatile ULONG tail;
53
+    volatile LONG alertable;
54
+    UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES];
55
+};
56
+
57
+/**
58
+ * Struct for ring buffers registration
59
+ * See https://github.com/WireGuard/wintun#registering-rings
60
+ */
61
+struct tun_register_rings
62
+{
63
+    struct
64
+    {
65
+        ULONG ring_size;
66
+        struct tun_ring *ring;
67
+        HANDLE tail_moved;
68
+    } send, receive;
69
+};
70
+
71
+struct TUN_PACKET_HEADER
72
+{
73
+    uint32_t size;
74
+};
75
+
76
+struct TUN_PACKET
77
+{
78
+    uint32_t size;
79
+    UCHAR data[WINTUN_MAX_PACKET_SIZE];
80
+};
81
+
82
+/**
83
+ * Registers ring buffers used to exchange data between
84
+ * userspace openvpn process and wintun kernel driver,
85
+ * see https://github.com/WireGuard/wintun#registering-rings
86
+ *
87
+ * @param device              handle to opened wintun device
88
+ * @param send_ring           pointer to send ring
89
+ * @param receive_ring        pointer to receive ring
90
+ * @param send_tail_moved     event set by wintun to signal openvpn
91
+ *                            that data is available for reading in send ring
92
+ * @param receive_tail_moved  event set by openvpn to signal wintun
93
+ *                            that data has been written to receive ring
94
+ * @return                    true if registration is successful, false otherwise
95
+ */
96
+bool register_ring_buffers(HANDLE device,
97
+                           struct tun_ring *send_ring,
98
+                           struct tun_ring *receive_ring,
99
+                           HANDLE send_tail_moved,
100
+                           HANDLE receive_tail_moved);
101
+
102
+#endif /* ifndef OPENVPN_RING_BUFFER_H */
103
+#endif /* ifdef _WIN32 */
... ...
@@ -779,17 +779,29 @@ init_tun_post(struct tuntap *tt,
779 779
 
780 780
     if (tt->wintun)
781 781
     {
782
-        tt->wintun_send_ring = malloc(sizeof(struct tun_ring));
783
-        tt->wintun_receive_ring = malloc(sizeof(struct tun_ring));
784
-        if ((tt->wintun_send_ring == NULL) || (tt->wintun_receive_ring == NULL))
782
+        tt->wintun_send_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
783
+                                                        PAGE_READWRITE,
784
+                                                        0,
785
+                                                        sizeof(struct tun_ring),
786
+                                                        NULL);
787
+        tt->wintun_receive_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE,
788
+                                                           NULL,
789
+                                                           PAGE_READWRITE,
790
+                                                           0,
791
+                                                           sizeof(struct tun_ring),
792
+                                                           NULL);
793
+        if ((tt->wintun_send_ring_handle == NULL) || (tt->wintun_receive_ring_handle == NULL))
785 794
         {
786 795
             msg(M_FATAL, "Cannot allocate memory for ring buffer");
787 796
         }
788
-        ZeroMemory(tt->wintun_send_ring, sizeof(struct tun_ring));
789
-        ZeroMemory(tt->wintun_receive_ring, sizeof(struct tun_ring));
790 797
 
791 798
         tt->rw_handle.read = CreateEvent(NULL, FALSE, FALSE, NULL);
792 799
         tt->rw_handle.write = CreateEvent(NULL, FALSE, FALSE, NULL);
800
+
801
+        if ((tt->rw_handle.read == NULL) || (tt->rw_handle.write == NULL))
802
+        {
803
+            msg(M_FATAL, "Cannot create events for ring buffer");
804
+        }
793 805
     }
794 806
     else
795 807
     {
... ...
@@ -5604,6 +5616,44 @@ register_dns_service(const struct tuntap *tt)
5604 5604
     gc_free(&gc);
5605 5605
 }
5606 5606
 
5607
+static void
5608
+service_register_ring_buffers(const struct tuntap *tt)
5609
+{
5610
+    HANDLE msg_channel = tt->options.msg_channel;
5611
+    ack_message_t ack;
5612
+    struct gc_arena gc = gc_new();
5613
+
5614
+    register_ring_buffers_message_t msg = {
5615
+        .header = {
5616
+            msg_register_ring_buffers,
5617
+            sizeof(register_ring_buffers_message_t),
5618
+            0
5619
+        },
5620
+        .device = tt->hand,
5621
+        .send_ring_handle = tt->wintun_send_ring_handle,
5622
+        .receive_ring_handle = tt->wintun_receive_ring_handle,
5623
+        .send_tail_moved = tt->rw_handle.read,
5624
+        .receive_tail_moved = tt->rw_handle.write
5625
+    };
5626
+
5627
+    if (!send_msg_iservice(msg_channel, &msg, sizeof(msg), &ack, "Register ring buffers"))
5628
+    {
5629
+        gc_free(&gc);
5630
+        return;
5631
+    }
5632
+    else if (ack.error_number != NO_ERROR)
5633
+    {
5634
+        msg(M_FATAL, "Register ring buffers failed using service: %s [status=0x%x]",
5635
+            strerror_win32(ack.error_number, &gc), ack.error_number);
5636
+    }
5637
+    else
5638
+    {
5639
+        msg(M_INFO, "Ring buffers registered via service");
5640
+    }
5641
+
5642
+    gc_free(&gc);
5643
+}
5644
+
5607 5645
 void
5608 5646
 fork_register_dns_action(struct tuntap *tt)
5609 5647
 {
... ...
@@ -6198,9 +6248,20 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
6198 6198
 
6199 6199
     if (tt->wintun)
6200 6200
     {
6201
+        tt->wintun_send_ring = (struct tun_ring *)MapViewOfFile(tt->wintun_send_ring_handle,
6202
+                                                                FILE_MAP_ALL_ACCESS,
6203
+                                                                0,
6204
+                                                                0,
6205
+                                                                sizeof(struct tun_ring));
6206
+        tt->wintun_receive_ring = (struct tun_ring *)MapViewOfFile(tt->wintun_receive_ring_handle,
6207
+                                                                   FILE_MAP_ALL_ACCESS,
6208
+                                                                   0,
6209
+                                                                   0,
6210
+                                                                   sizeof(struct tun_ring));
6211
+
6201 6212
         if (tt->options.msg_channel)
6202 6213
         {
6203
-            /* TODO */
6214
+            service_register_ring_buffers(tt);
6204 6215
         }
6205 6216
         else
6206 6217
         {
... ...
@@ -6365,13 +6426,12 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
6365 6365
     {
6366 6366
         CloseHandle(tt->rw_handle.read);
6367 6367
         CloseHandle(tt->rw_handle.write);
6368
+        UnmapViewOfFile(tt->wintun_send_ring);
6369
+        UnmapViewOfFile(tt->wintun_receive_ring);
6370
+        CloseHandle(tt->wintun_send_ring_handle);
6371
+        CloseHandle(tt->wintun_receive_ring_handle);
6368 6372
     }
6369 6373
 
6370
-    free(tt->wintun_receive_ring);
6371
-    free(tt->wintun_send_ring);
6372
-
6373
-    tt->wintun_receive_ring = NULL;
6374
-    tt->wintun_send_ring = NULL;
6375 6374
 
6376 6375
     clear_tuntap(tt);
6377 6376
     free(tt);
... ...
@@ -39,6 +39,7 @@
39 39
 #include "proto.h"
40 40
 #include "misc.h"
41 41
 #include "networking.h"
42
+#include "ring_buffer.h"
42 43
 
43 44
 #ifdef _WIN32
44 45
 #define WINTUN_COMPONENT_ID "wintun"
... ...
@@ -183,6 +184,8 @@ struct tuntap
183 183
     bool wintun; /* true if wintun is used instead of tap-windows6 */
184 184
     int standby_iter;
185 185
 
186
+    HANDLE wintun_send_ring_handle;
187
+    HANDLE wintun_receive_ring_handle;
186 188
     struct tun_ring *wintun_send_ring;
187 189
     struct tun_ring *wintun_receive_ring;
188 190
 #else  /* ifdef _WIN32 */
... ...
@@ -1588,31 +1588,4 @@ impersonate_as_system()
1588 1588
     return true;
1589 1589
 }
1590 1590
 
1591
-bool
1592
-register_ring_buffers(HANDLE device,
1593
-                      struct tun_ring* send_ring,
1594
-                      struct tun_ring* receive_ring,
1595
-                      HANDLE send_tail_moved,
1596
-                      HANDLE receive_tail_moved)
1597
-{
1598
-    struct tun_register_rings rr;
1599
-    BOOL res;
1600
-    DWORD bytes_returned;
1601
-
1602
-    ZeroMemory(&rr, sizeof(rr));
1603
-
1604
-    rr.send.ring = send_ring;
1605
-    rr.send.ring_size = sizeof(struct tun_ring);
1606
-    rr.send.tail_moved = send_tail_moved;
1607
-
1608
-    rr.receive.ring = receive_ring;
1609
-    rr.receive.ring_size = sizeof(struct tun_ring);
1610
-    rr.receive.tail_moved = receive_tail_moved;
1611
-
1612
-    res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr),
1613
-                          NULL, 0, &bytes_returned, NULL);
1614
-
1615
-    return res != FALSE;
1616
-}
1617
-
1618 1591
 #endif /* ifdef _WIN32 */
... ...
@@ -325,53 +325,7 @@ bool send_msg_iservice(HANDLE pipe, const void *data, size_t size,
325 325
 int
326 326
 openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags);
327 327
 
328
-/*
329
- * Values below are taken from Wireguard Windows client
330
- * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14
331
- */
332
-#define WINTUN_RING_CAPACITY 0x800000
333
-#define WINTUN_RING_TRAILING_BYTES 0x10000
334
-#define WINTUN_MAX_PACKET_SIZE 0xffff
335
-#define WINTUN_PACKET_ALIGN 4
336
-
337
-struct tun_ring
338
-{
339
-    volatile ULONG head;
340
-    volatile ULONG tail;
341
-    volatile LONG alertable;
342
-    UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES];
343
-};
344
-
345
-struct tun_register_rings
346
-{
347
-    struct
348
-    {
349
-        ULONG ring_size;
350
-        struct tun_ring *ring;
351
-        HANDLE tail_moved;
352
-    } send, receive;
353
-};
354
-
355
-struct TUN_PACKET_HEADER
356
-{
357
-    uint32_t size;
358
-};
359
-
360
-struct TUN_PACKET
361
-{
362
-    uint32_t size;
363
-    UCHAR data[WINTUN_MAX_PACKET_SIZE];
364
-};
365
-
366
-#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
367
-
368 328
 bool impersonate_as_system();
369 329
 
370
-bool register_ring_buffers(HANDLE device,
371
-                           struct tun_ring *send_ring,
372
-                           struct tun_ring *receive_ring,
373
-                           HANDLE send_tail_moved,
374
-                           HANDLE receive_tail_moved);
375
-
376 330
 #endif /* ifndef OPENVPN_WIN32_H */
377 331
 #endif /* ifdef _WIN32 */
... ...
@@ -36,4 +36,5 @@ openvpnserv_SOURCES = \
36 36
 	service.c service.h \
37 37
 	validate.c validate.h \
38 38
 	$(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \
39
-	openvpnserv_resources.rc
39
+	openvpnserv_resources.rc \
40
+	$(top_srcdir)/src/openvpn/ring_buffer.c $(top_srcdir)/src/openvpn/ring_buffer.h
... ...
@@ -43,13 +43,15 @@
43 43
 #include "openvpn-msg.h"
44 44
 #include "validate.h"
45 45
 #include "block_dns.h"
46
+#include "ring_buffer.h"
46 47
 
47 48
 #define IO_TIMEOUT  2000 /*ms*/
48 49
 
49
-#define ERROR_OPENVPN_STARTUP  0x20000000
50
-#define ERROR_STARTUP_DATA     0x20000001
51
-#define ERROR_MESSAGE_DATA     0x20000002
52
-#define ERROR_MESSAGE_TYPE     0x20000003
50
+#define ERROR_OPENVPN_STARTUP        0x20000000
51
+#define ERROR_STARTUP_DATA           0x20000001
52
+#define ERROR_MESSAGE_DATA           0x20000002
53
+#define ERROR_MESSAGE_TYPE           0x20000003
54
+#define ERROR_REGISTER_RING_BUFFERS  0x20000004
53 55
 
54 56
 static SERVICE_STATUS_HANDLE service;
55 57
 static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
... ...
@@ -58,6 +60,7 @@ static settings_t settings;
58 58
 static HANDLE rdns_semaphore = NULL;
59 59
 #define RDNS_TIMEOUT 600  /* seconds to wait for the semaphore */
60 60
 
61
+#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
61 62
 
62 63
 openvpn_service_t interactive_service = {
63 64
     interactive,
... ...
@@ -100,6 +103,14 @@ typedef struct {
100 100
     int metric_v6;
101 101
 } block_dns_data_t;
102 102
 
103
+typedef struct {
104
+    HANDLE send_ring_handle;
105
+    HANDLE receive_ring_handle;
106
+    HANDLE send_tail_moved;
107
+    HANDLE receive_tail_moved;
108
+    HANDLE device;
109
+} ring_buffer_handles_t;
110
+
103 111
 
104 112
 static DWORD
105 113
 AddListItem(list_item_t **pfirst, LPVOID data)
... ...
@@ -154,6 +165,26 @@ CloseHandleEx(LPHANDLE handle)
154 154
     return INVALID_HANDLE_VALUE;
155 155
 }
156 156
 
157
+static HANDLE
158
+OvpnUnmapViewOfFile(LPHANDLE handle)
159
+{
160
+    if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
161
+    {
162
+        UnmapViewOfFile(*handle);
163
+        *handle = INVALID_HANDLE_VALUE;
164
+    }
165
+    return INVALID_HANDLE_VALUE;
166
+}
167
+
168
+static void
169
+CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles)
170
+{
171
+    CloseHandleEx(&ring_buffer_handles->device);
172
+    CloseHandleEx(&ring_buffer_handles->receive_tail_moved);
173
+    CloseHandleEx(&ring_buffer_handles->send_tail_moved);
174
+    OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle);
175
+    OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle);
176
+}
157 177
 
158 178
 static HANDLE
159 179
 InitOverlapped(LPOVERLAPPED overlapped)
... ...
@@ -1198,8 +1229,95 @@ HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
1198 1198
     return err;
1199 1199
 }
1200 1200
 
1201
+static DWORD
1202
+OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle)
1203
+{
1204
+    DWORD err = ERROR_SUCCESS;
1205
+
1206
+    if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
1207
+    {
1208
+        err = GetLastError();
1209
+        MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle"));
1210
+        return err;
1211
+    }
1212
+
1213
+    return err;
1214
+}
1215
+
1216
+static DWORD
1217
+DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring)
1218
+{
1219
+    DWORD err = ERROR_SUCCESS;
1220
+
1221
+    err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle);
1222
+    if (err != ERROR_SUCCESS)
1223
+    {
1224
+        return err;
1225
+    }
1226
+    *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring));
1227
+    if (*ring == NULL)
1228
+    {
1229
+        err = GetLastError();
1230
+        MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory"));
1231
+        return err;
1232
+    }
1233
+
1234
+    return err;
1235
+}
1236
+
1237
+static DWORD
1238
+HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc,
1239
+                          ring_buffer_handles_t *ring_buffer_handles)
1240
+{
1241
+    DWORD err = 0;
1242
+    struct tun_ring *send_ring;
1243
+    struct tun_ring *receive_ring;
1244
+
1245
+    CloseRingBufferHandles(ring_buffer_handles);
1246
+
1247
+    err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device);
1248
+    if (err != ERROR_SUCCESS)
1249
+    {
1250
+        return err;
1251
+    }
1252
+
1253
+    err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring);
1254
+    if (err != ERROR_SUCCESS)
1255
+    {
1256
+        return err;
1257
+    }
1258
+
1259
+    err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring);
1260
+    if (err != ERROR_SUCCESS)
1261
+    {
1262
+        return err;
1263
+    }
1264
+
1265
+    err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved);
1266
+    if (err != ERROR_SUCCESS)
1267
+    {
1268
+        return err;
1269
+    }
1270
+
1271
+    err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved);
1272
+    if (err != ERROR_SUCCESS)
1273
+    {
1274
+        return err;
1275
+    }
1276
+
1277
+    if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring,
1278
+                               ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved))
1279
+    {
1280
+        MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers"));
1281
+        err = ERROR_REGISTER_RING_BUFFERS;
1282
+    }
1283
+
1284
+    return err;
1285
+}
1286
+
1201 1287
 static VOID
1202
-HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
1288
+HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles,
1289
+              DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
1203 1290
 {
1204 1291
     DWORD read;
1205 1292
     union {
... ...
@@ -1210,6 +1328,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists
1210 1210
         block_dns_message_t block_dns;
1211 1211
         dns_cfg_message_t dns;
1212 1212
         enable_dhcp_message_t dhcp;
1213
+        register_ring_buffers_message_t rrb;
1213 1214
     } msg;
1214 1215
     ack_message_t ack = {
1215 1216
         .header = {
... ...
@@ -1277,6 +1396,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists
1277 1277
             }
1278 1278
             break;
1279 1279
 
1280
+        case msg_register_ring_buffers:
1281
+            if (msg.header.size == sizeof(msg.rrb))
1282
+            {
1283
+                ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles);
1284
+            }
1285
+            break;
1286
+
1280 1287
         default:
1281 1288
             ack.error_number = ERROR_MESSAGE_TYPE;
1282 1289
             MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type);
... ...
@@ -1360,6 +1486,7 @@ RunOpenvpn(LPVOID p)
1360 1360
     WCHAR *cmdline = NULL;
1361 1361
     size_t cmdline_size;
1362 1362
     undo_lists_t undo_lists;
1363
+    ring_buffer_handles_t ring_buffer_handles;
1363 1364
 
1364 1365
     SECURITY_ATTRIBUTES inheritable = {
1365 1366
         .nLength = sizeof(inheritable),
... ...
@@ -1380,6 +1507,7 @@ RunOpenvpn(LPVOID p)
1380 1380
     ZeroMemory(&startup_info, sizeof(startup_info));
1381 1381
     ZeroMemory(&undo_lists, sizeof(undo_lists));
1382 1382
     ZeroMemory(&proc_info, sizeof(proc_info));
1383
+    ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles));
1383 1384
 
1384 1385
     if (!GetStartupData(pipe, &sud))
1385 1386
     {
... ...
@@ -1611,7 +1739,7 @@ RunOpenvpn(LPVOID p)
1611 1611
             break;
1612 1612
         }
1613 1613
 
1614
-        HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists);
1614
+        HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists);
1615 1615
     }
1616 1616
 
1617 1617
     WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT);
... ...
@@ -1638,6 +1766,7 @@ out:
1638 1638
     free(cmdline);
1639 1639
     DestroyEnvironmentBlock(user_env);
1640 1640
     FreeStartupData(&sud);
1641
+    CloseRingBufferHandles(&ring_buffer_handles);
1641 1642
     CloseHandleEx(&proc_info.hProcess);
1642 1643
     CloseHandleEx(&proc_info.hThread);
1643 1644
     CloseHandleEx(&stdin_read);
... ...
@@ -115,6 +115,7 @@
115 115
     </Link>
116 116
   </ItemDefinitionGroup>
117 117
   <ItemGroup>
118
+    <ClCompile Include="..\openvpn\ring_buffer.c" />
118 119
     <ClCompile Include="automatic.c" />
119 120
     <ClCompile Include="common.c" />
120 121
     <ClCompile Include="interactive.c" />
... ...
@@ -123,6 +124,7 @@
123 123
     <ClCompile Include="..\openvpn\block_dns.c" />
124 124
   </ItemGroup>
125 125
   <ItemGroup>
126
+    <ClInclude Include="..\openvpn\ring_buffer.h" />
126 127
     <ClInclude Include="service.h" />
127 128
     <ClInclude Include="validate.h" />
128 129
     <ClInclude Include="..\openvpn\block_dns.h" />
... ...
@@ -33,6 +33,9 @@
33 33
     <ClCompile Include="..\openvpn\block_dns.c">
34 34
       <Filter>Source Files</Filter>
35 35
     </ClCompile>
36
+    <ClCompile Include="..\openvpn\ring_buffer.c">
37
+      <Filter>Source Files</Filter>
38
+    </ClCompile>
36 39
   </ItemGroup>
37 40
   <ItemGroup>
38 41
     <ClInclude Include="service.h">
... ...
@@ -44,6 +47,9 @@
44 44
     <ClInclude Include="..\openvpn\block_dns.h">
45 45
       <Filter>Header Files</Filter>
46 46
     </ClInclude>
47
+    <ClInclude Include="..\openvpn\ring_buffer.h">
48
+      <Filter>Header Files</Filter>
49
+    </ClInclude>
47 50
   </ItemGroup>
48 51
   <ItemGroup>
49 52
     <ResourceCompile Include="openvpnserv_resources.rc">