OpenVPN
dco_win.c
Go to the documentation of this file.
1 /*
2  * Interface to ovpn-win-dco networking code
3  *
4  * Copyright (C) 2020-2023 Arne Schwabe <arne@rfc2549.org>
5  * Copyright (C) 2020-2023 OpenVPN Inc <sales@openvpn.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2
9  * as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program (see the file COPYING included with this
18  * distribution); if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #elif defined(_MSC_VER)
25 #include "config-msvc.h"
26 #endif
27 
28 #if defined(_WIN32)
29 
30 #include "syshead.h"
31 
32 #include "dco.h"
33 #include "tun.h"
34 #include "crypto.h"
35 #include "ssl_common.h"
36 #include "openvpn.h"
37 
38 #include <bcrypt.h>
39 #include <winsock2.h>
40 #include <ws2tcpip.h>
41 
42 #if defined(__MINGW32__)
43 const IN_ADDR in4addr_any = { 0 };
44 #endif
45 
46 struct tuntap
47 create_dco_handle(const char *devname, struct gc_arena *gc)
48 {
49  struct tuntap tt = { .windows_driver = WINDOWS_DRIVER_DCO };
50  const char *device_guid;
51 
52  tun_open_device(&tt, devname, &device_guid, gc);
53 
54  return tt;
55 }
56 
57 bool
59 {
60  return true;
61 }
62 
63 int
64 open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
65 {
66  ASSERT(0);
67  return 0;
68 }
69 
70 static void
71 dco_wait_ready(DWORD idx)
72 {
73  for (int i = 0; i < 20; ++i)
74  {
75  MIB_IPINTERFACE_ROW row = {.InterfaceIndex = idx, .Family = AF_INET};
76  if (GetIpInterfaceEntry(&row) != ERROR_NOT_FOUND)
77  {
78  break;
79  }
80  msg(D_DCO_DEBUG, "interface %ld not yet ready, retrying", idx);
81  Sleep(50);
82  }
83 }
84 
85 void
86 dco_start_tun(struct tuntap *tt)
87 {
88  msg(D_DCO_DEBUG, "%s", __func__);
89 
90  /* reference the tt object inside the DCO context, because the latter will
91  * be passed around
92  */
93  tt->dco.tt = tt;
94 
95  DWORD bytes_returned = 0;
96  if (!DeviceIoControl(tt->hand, OVPN_IOCTL_START_VPN, NULL, 0, NULL, 0,
97  &bytes_returned, NULL))
98  {
99  msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_START_VPN) failed");
100  }
101 
102  /* Sometimes IP Helper API, which we use for setting IP address etc,
103  * complains that interface is not found. Give it some time to settle
104  */
106 }
107 
108 static void
109 dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, struct signal_info *sig_info)
110 {
111  volatile int *signal_received = &sig_info->signal_received;
112  /* GetOverlappedResultEx is available starting from Windows 8 */
113  typedef BOOL (WINAPI *get_overlapped_result_ex_t)(HANDLE, LPOVERLAPPED, LPDWORD, DWORD, BOOL);
114  get_overlapped_result_ex_t get_overlapped_result_ex =
115  (get_overlapped_result_ex_t)GetProcAddress(GetModuleHandle("Kernel32.dll"),
116  "GetOverlappedResultEx");
117 
118  if (get_overlapped_result_ex == NULL)
119  {
120  msg(M_ERR, "Failed to load GetOverlappedResult()");
121  }
122 
123  DWORD timeout_msec = timeout * 1000;
124  const int poll_interval_ms = 50;
125 
126  while (timeout_msec > 0)
127  {
128  timeout_msec -= poll_interval_ms;
129 
130  DWORD transferred;
131  if (get_overlapped_result_ex(handle, ov, &transferred, poll_interval_ms, FALSE) != 0)
132  {
133  /* TCP connection established by dco */
134  return;
135  }
136 
137  DWORD err = GetLastError();
138  if ((err != WAIT_TIMEOUT) && (err != ERROR_IO_INCOMPLETE))
139  {
140  /* dco reported connection error */
141  msg(M_NONFATAL | M_ERRNO, "dco connect error");
142  register_signal(sig_info, SIGUSR1, "dco-connect-error");
143  return;
144  }
145 
146  get_signal(signal_received);
147  if (*signal_received)
148  {
149  return;
150  }
151 
152  management_sleep(0);
153  }
154 
155  /* we end up here when timeout occurs in userspace */
156  msg(M_NONFATAL, "dco connect timeout");
157  register_signal(sig_info, SIGUSR1, "dco-connect-timeout");
158 }
159 
160 void
161 dco_create_socket(HANDLE handle, struct addrinfo *remoteaddr, bool bind_local,
162  struct addrinfo *bind, int timeout,
163  struct signal_info *sig_info)
164 {
165  msg(D_DCO_DEBUG, "%s", __func__);
166 
167  OVPN_NEW_PEER peer = { 0 };
168 
169  struct sockaddr *local = NULL;
170  struct sockaddr *remote = remoteaddr->ai_addr;
171 
172  if (remoteaddr->ai_protocol == IPPROTO_TCP
173  || remoteaddr->ai_socktype == SOCK_STREAM)
174  {
175  peer.Proto = OVPN_PROTO_TCP;
176  }
177  else
178  {
179  peer.Proto = OVPN_PROTO_UDP;
180  }
181 
182  if (bind_local)
183  {
184  /* Use first local address with correct address family */
185  while (bind && !local)
186  {
187  if (bind->ai_family == remote->sa_family)
188  {
189  local = bind->ai_addr;
190  }
191  bind = bind->ai_next;
192  }
193  }
194 
195  if (bind_local && !local)
196  {
197  msg(M_FATAL, "DCO: Socket bind failed: Address to bind lacks %s record",
198  addr_family_name(remote->sa_family));
199  }
200 
201  if (remote->sa_family == AF_INET6)
202  {
203  peer.Remote.Addr6 = *((SOCKADDR_IN6 *)(remoteaddr->ai_addr));
204  if (local)
205  {
206  peer.Local.Addr6 = *((SOCKADDR_IN6 *)local);
207  }
208  else
209  {
210  peer.Local.Addr6.sin6_addr = in6addr_any;
211  peer.Local.Addr6.sin6_port = 0;
212  peer.Local.Addr6.sin6_family = AF_INET6;
213  }
214  }
215  else if (remote->sa_family == AF_INET)
216  {
217  peer.Remote.Addr4 = *((SOCKADDR_IN *)(remoteaddr->ai_addr));
218  if (local)
219  {
220  peer.Local.Addr4 = *((SOCKADDR_IN *)local);
221  }
222  else
223  {
224  peer.Local.Addr4.sin_addr = in4addr_any;
225  peer.Local.Addr4.sin_port = 0;
226  peer.Local.Addr4.sin_family = AF_INET;
227  }
228  }
229  else
230  {
231  ASSERT(0);
232  }
233 
234  OVERLAPPED ov = { 0 };
235  if (!DeviceIoControl(handle, OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, NULL, &ov))
236  {
237  DWORD err = GetLastError();
238  if (err != ERROR_IO_PENDING)
239  {
240  msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_PEER) failed");
241  }
242  else
243  {
244  dco_connect_wait(handle, &ov, timeout, sig_info);
245  }
246  }
247 }
248 
249 int
250 dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd,
251  struct sockaddr *localaddr, struct sockaddr *remoteaddr,
252  struct in_addr *remote_in4, struct in6_addr *remote_in6)
253 {
254  msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd);
255  return 0;
256 }
257 
258 int
259 dco_del_peer(dco_context_t *dco, unsigned int peerid)
260 {
261  msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
262 
263  DWORD bytes_returned = 0;
264  if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_DEL_PEER, NULL,
265  0, NULL, 0, &bytes_returned, NULL))
266  {
267  msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_DEL_PEER) failed");
268  return -1;
269  }
270  return 0;
271 }
272 
273 int
274 dco_set_peer(dco_context_t *dco, unsigned int peerid,
275  int keepalive_interval, int keepalive_timeout, int mss)
276 {
277  msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__,
278  peerid, keepalive_interval, keepalive_timeout, mss);
279 
280  OVPN_SET_PEER peer;
281 
282  peer.KeepaliveInterval = keepalive_interval;
283  peer.KeepaliveTimeout = keepalive_timeout;
284  peer.MSS = mss;
285 
286  DWORD bytes_returned = 0;
287  if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_SET_PEER, &peer,
288  sizeof(peer), NULL, 0, &bytes_returned, NULL))
289  {
290  msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_SET_PEER) failed");
291  return -1;
292  }
293  return 0;
294 }
295 
296 int
297 dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid,
298  dco_key_slot_t slot,
299  const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
300  const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
301  const char *ciphername)
302 {
303  msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
304  __func__, slot, keyid, peerid, ciphername);
305 
306  const int nonce_len = 8;
307  size_t key_len = cipher_kt_key_size(ciphername);
308 
309  OVPN_CRYPTO_DATA crypto_data;
310  ZeroMemory(&crypto_data, sizeof(crypto_data));
311 
312  crypto_data.CipherAlg = dco_get_cipher(ciphername);
313  crypto_data.KeyId = keyid;
314  crypto_data.PeerId = peerid;
315  crypto_data.KeySlot = slot;
316 
317  CopyMemory(crypto_data.Encrypt.Key, encrypt_key, key_len);
318  crypto_data.Encrypt.KeyLen = (char)key_len;
319  CopyMemory(crypto_data.Encrypt.NonceTail, encrypt_iv, nonce_len);
320 
321  CopyMemory(crypto_data.Decrypt.Key, decrypt_key, key_len);
322  crypto_data.Decrypt.KeyLen = (char)key_len;
323  CopyMemory(crypto_data.Decrypt.NonceTail, decrypt_iv, nonce_len);
324 
325  ASSERT(crypto_data.CipherAlg > 0);
326 
327  DWORD bytes_returned = 0;
328 
329  if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_NEW_KEY, &crypto_data,
330  sizeof(crypto_data), NULL, 0, &bytes_returned, NULL))
331  {
332  msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY) failed");
333  return -1;
334  }
335  return 0;
336 }
337 int
338 dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
339 {
340  msg(D_DCO, "%s: peer-id %d, slot %d called but ignored", __func__, peerid,
341  slot);
342  /* FIXME: Implement in driver first */
343  return 0;
344 }
345 
346 int
347 dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
348 {
349  msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
350 
351  DWORD bytes_returned = 0;
352  if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_SWAP_KEYS, NULL, 0, NULL, 0,
353  &bytes_returned, NULL))
354  {
355  msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SWAP_KEYS) failed");
356  return -1;
357  }
358  return 0;
359 }
360 
361 bool
362 dco_available(int msglevel)
363 {
364  /* try to open device by symbolic name */
365  HANDLE h = CreateFile("\\\\.\\ovpn-dco", GENERIC_READ | GENERIC_WRITE,
366  0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
367 
368  if (h != INVALID_HANDLE_VALUE)
369  {
370  CloseHandle(h);
371  return true;
372  }
373 
374  DWORD err = GetLastError();
375  if (err == ERROR_ACCESS_DENIED)
376  {
377  /* this likely means that device exists but is already in use,
378  * don't bail out since later we try to open all existing dco
379  * devices and then bail out if all devices are in use
380  */
381  return true;
382  }
383 
384  msg(msglevel, "Note: ovpn-dco-win driver is missing, disabling data channel offload.");
385  return false;
386 }
387 
388 const char *
390 {
391  return "v0";
392 }
393 
394 int
396 {
397  /* no-op on windows */
398  ASSERT(0);
399  return 0;
400 }
401 
402 int
404 {
405  /* Not implemented. */
406  return 0;
407 }
408 
409 int
411 {
412  struct tuntap *tt = c->c1.tuntap;
413 
414  if (!tuntap_defined(tt))
415  {
416  return -1;
417  }
418 
419  OVPN_STATS stats;
420  ZeroMemory(&stats, sizeof(OVPN_STATS));
421 
422  DWORD bytes_returned = 0;
423  if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_STATS, NULL, 0,
424  &stats, sizeof(stats), &bytes_returned, NULL))
425  {
426  msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_GET_STATS) failed");
427  return -1;
428  }
429 
433  c->c2.tun_write_bytes = stats.TunBytesSent;
434 
435  return 0;
436 }
437 
438 void
440 {
441  /* no-op on windows */
442  ASSERT(0);
443 }
444 
445 const char *
447 {
448  /*
449  * this API can be called either from user mode or kernel mode,
450  * which enables us to probe driver's chachapoly support
451  * (available starting from Windows 11)
452  */
453 
454  BCRYPT_ALG_HANDLE h;
455  NTSTATUS status = BCryptOpenAlgorithmProvider(&h, L"CHACHA20_POLY1305", NULL, 0);
456  if (BCRYPT_SUCCESS(status))
457  {
458  BCryptCloseAlgorithmProvider(h, 0);
459  return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
460  }
461  else
462  {
463  return "AES-128-GCM:AES-256-GCM:AES-192-GCM";
464  }
465 }
466 
467 #endif /* defined(_WIN32) */
_OVPN_NEW_PEER::Proto
OVPN_PROTO Proto
Definition: ovpn_dco_win.h:47
signal_info::signal_received
volatile int signal_received
Definition: sig.h:43
D_DCO_DEBUG
#define D_DCO_DEBUG
Definition: errlevel.h:118
dco_new_key
int dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, dco_key_slot_t slot, const uint8_t *encrypt_key, const uint8_t *encrypt_iv, const uint8_t *decrypt_key, const uint8_t *decrypt_iv, const char *ciphername)
Definition: dco_win.c:297
dco_connect_wait
static void dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, struct signal_info *sig_info)
Definition: dco_win.c:109
M_ERRNO
#define M_ERRNO
Definition: error.h:100
dco_get_supported_ciphers
const char * dco_get_supported_ciphers()
Definition: dco_win.c:446
_OVPN_STATS
Definition: ovpn_dco_win.h:50
M_FATAL
#define M_FATAL
Definition: error.h:95
tuntap::windows_driver
enum windows_driver_type windows_driver
Definition: tun.h:213
context_1::tuntap
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition: openvpn.h:170
dco_version_string
const char * dco_version_string(struct gc_arena *gc)
Definition: dco_win.c:389
M_NONFATAL
#define M_NONFATAL
Definition: error.h:96
management_sleep
void management_sleep(const int n)
A sleep function that services the management layer for n seconds rather than doing nothing.
Definition: manage.c:4117
context
Contains all state information for one tunnel.
Definition: openvpn.h:479
es
struct env_set * es
Definition: test_pkcs11.c:122
context_2::tun_read_bytes
counter_type tun_read_bytes
Definition: openvpn.h:270
_OVPN_SET_PEER::MSS
LONG MSS
Definition: ovpn_dco_win.h:100
config-msvc.h
create_dco_handle
struct tuntap create_dco_handle(const char *devname, struct gc_arena *gc)
Definition: dco_win.c:47
open_tun_dco
int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
Definition: dco_win.c:64
openvpn.h
bind_local
static void bind_local(struct link_socket *sock, const sa_family_t ai_family)
Definition: socket.c:1089
_OVPN_STATS::TunBytesReceived
LONG64 TunBytesReceived
Definition: ovpn_dco_win.h:67
dco_start_tun
void dco_start_tun(struct tuntap *tt)
Definition: dco_win.c:86
addr_family_name
const char * addr_family_name(int af)
Definition: socket.c:3170
_OVPN_STATS::TransportBytesReceived
LONG64 TransportBytesReceived
Definition: ovpn_dco_win.h:64
openvpn_net_ctx_t
void * openvpn_net_ctx_t
Definition: networking.h:28
dco_get_peer_stats
int dco_get_peer_stats(struct context *c)
Definition: dco_win.c:410
dco_new_peer
int dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, struct sockaddr *localaddr, struct sockaddr *remoteaddr, struct in_addr *remote_in4, struct in6_addr *remote_in6)
Definition: dco_win.c:250
dco_do_read
int dco_do_read(dco_context_t *dco)
Definition: dco_win.c:395
_OVPN_SET_PEER
Definition: ovpn_dco_win.h:97
OVPN_PROTO_UDP
@ OVPN_PROTO_UDP
Definition: ovpn_dco_win.h:32
OVPN_IOCTL_DEL_PEER
#define OVPN_IOCTL_DEL_PEER
Definition: ovpn_dco_win.h:109
OVPN_IOCTL_START_VPN
#define OVPN_IOCTL_START_VPN
Definition: ovpn_dco_win.h:108
context::c2
struct context_2 c2
Level 2 context.
Definition: openvpn.h:520
tuntap_defined
static bool tuntap_defined(const struct tuntap *tt)
Definition: tun.h:238
tuntap::hand
HANDLE hand
Definition: tun.h:197
register_signal
void register_signal(struct signal_info *si, int sig, const char *text)
Definition: sig.c:483
OVPN_IOCTL_NEW_PEER
#define OVPN_IOCTL_NEW_PEER
Definition: ovpn_dco_win.h:103
ASSERT
#define ASSERT(x)
Definition: error.h:201
_OVPN_STATS::TransportBytesSent
LONG64 TransportBytesSent
Definition: ovpn_dco_win.h:63
D_DCO
#define D_DCO
Definition: errlevel.h:94
tun.h
WINDOWS_DRIVER_DCO
@ WINDOWS_DRIVER_DCO
Definition: tun.h:53
_OVPN_CRYPTO_DATA::PeerId
int PeerId
Definition: ovpn_dco_win.h:94
_OVPN_SET_PEER::KeepaliveTimeout
LONG KeepaliveTimeout
Definition: ovpn_dco_win.h:99
_OVPN_CRYPTO_DATA::KeyId
unsigned char KeyId
Definition: ovpn_dco_win.h:93
ovpn_dco_init
bool ovpn_dco_init(int mode, dco_context_t *dco)
Definition: dco_win.c:58
context_2::dco_write_bytes
counter_type dco_write_bytes
Definition: openvpn.h:276
M_WARN
#define M_WARN
Definition: error.h:97
tuntap::adapter_index
DWORD adapter_index
Definition: tun.h:211
OVPN_IOCTL_NEW_KEY
#define OVPN_IOCTL_NEW_KEY
Definition: ovpn_dco_win.h:105
dco_event_set
void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
Definition: dco_win.c:439
crypto.h
M_ERR
#define M_ERR
Definition: error.h:111
_OVPN_STATS::TunBytesSent
LONG64 TunBytesSent
Definition: ovpn_dco_win.h:66
_OVPN_NEW_PEER
Definition: ovpn_dco_win.h:36
dco_context_t
void * dco_context_t
Definition: dco.h:254
OVPN_IOCTL_GET_STATS
#define OVPN_IOCTL_GET_STATS
Definition: ovpn_dco_win.h:104
dco_available
bool dco_available(int msglevel)
Definition: dco_win.c:362
context_2::tun_write_bytes
counter_type tun_write_bytes
Definition: openvpn.h:271
dco_create_socket
void dco_create_socket(HANDLE handle, struct addrinfo *remoteaddr, bool bind_local, struct addrinfo *bind, int timeout, struct signal_info *sig_info)
Definition: dco_win.c:161
_OVPN_NEW_PEER::Local
union _OVPN_NEW_PEER::@8 Local
dco_set_peer
int dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout, int mss)
Definition: dco_win.c:274
_OVPN_NEW_PEER::Addr4
SOCKADDR_IN Addr4
Definition: ovpn_dco_win.h:38
_OVPN_CRYPTO_DATA::KeySlot
OVPN_KEY_SLOT KeySlot
Definition: ovpn_dco_win.h:91
syshead.h
_OVPN_CRYPTO_DATA
Definition: ovpn_dco_win.h:88
_OVPN_SET_PEER::KeepaliveInterval
LONG KeepaliveInterval
Definition: ovpn_dco_win.h:98
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
SIGUSR1
#define SIGUSR1
Definition: config-msvc.h:80
dco_del_peer
int dco_del_peer(dco_context_t *dco, unsigned int peerid)
Definition: dco_win.c:259
_OVPN_CRYPTO_DATA::Decrypt
OVPN_KEY_DIRECTION Decrypt
Definition: ovpn_dco_win.h:90
_OVPN_CRYPTO_DATA::Encrypt
OVPN_KEY_DIRECTION Encrypt
Definition: ovpn_dco_win.h:89
_OVPN_KEY_DIRECTION::NonceTail
unsigned char NonceTail[8]
Definition: ovpn_dco_win.h:85
multi_context
Main OpenVPN server state structure.
Definition: multi.h:155
cipher_kt_key_size
int cipher_kt_key_size(const char *ciphername)
Returns the size of keys used by the cipher, in bytes.
Definition: crypto_openssl.c:643
dco.h
event_set
Definition: event.h:124
dco_del_key
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
Definition: dco_win.c:338
dco_swap_keys
int dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
Definition: dco_win.c:347
OVPN_PROTO_TCP
@ OVPN_PROTO_TCP
Definition: ovpn_dco_win.h:33
tuntap::dco
dco_context_t dco
Definition: tun.h:234
signal_info
Definition: sig.h:41
context_2::dco_read_bytes
counter_type dco_read_bytes
Definition: openvpn.h:273
status
static SERVICE_STATUS status
Definition: interactive.c:56
tuntap
Definition: tun.h:171
_OVPN_KEY_DIRECTION::KeyLen
unsigned char KeyLen
Definition: ovpn_dco_win.h:84
_OVPN_KEY_DIRECTION::Key
unsigned char Key[32]
Definition: ovpn_dco_win.h:83
dco_wait_ready
static void dco_wait_ready(DWORD idx)
Definition: dco_win.c:71
config.h
ssl_common.h
_OVPN_NEW_PEER::Remote
union _OVPN_NEW_PEER::@9 Remote
get_signal
static void get_signal(volatile int *sig)
Copy the global signal_received (if non-zero) to the passed-in argument sig.
Definition: sig.h:105
dco_get_peer_stats_multi
int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
Definition: dco_win.c:403
_OVPN_NEW_PEER::Addr6
SOCKADDR_IN6 Addr6
Definition: ovpn_dco_win.h:39
OVPN_IOCTL_SWAP_KEYS
#define OVPN_IOCTL_SWAP_KEYS
Definition: ovpn_dco_win.h:106
_OVPN_CRYPTO_DATA::CipherAlg
OVPN_CIPHER_ALG CipherAlg
Definition: ovpn_dco_win.h:92
tun_open_device
void tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid, struct gc_arena *gc)
Definition: tun.c:6594
msg
#define msg(flags,...)
Definition: error.h:150
OVPN_IOCTL_SET_PEER
#define OVPN_IOCTL_SET_PEER
Definition: ovpn_dco_win.h:107
context::c1
struct context_1 c1
Level 1 context.
Definition: openvpn.h:519