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-2026 Arne Schwabe <arne@rfc2549.org>
5 * Copyright (C) 2020-2026 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#if defined(_WIN32)
26
27#include "syshead.h"
28
29#include "dco.h"
30#include "forward.h"
31#include "tun.h"
32#include "crypto.h"
33#include "multi.h"
34#include "ssl_common.h"
35#include "openvpn.h"
36
37#include <bcrypt.h>
38#include <winsock2.h>
39#include <ws2tcpip.h>
40
41#if defined(__MINGW32__)
42const IN_ADDR in4addr_any = { 0 };
43#endif
44
45/* Sometimes IP Helper API, which we use for setting IP address etc,
46 * complains that interface is not found. Give it some time to settle
47 */
48static void
50{
51 for (int i = 0; i < 20; ++i)
52 {
53 MIB_IPINTERFACE_ROW row = { .InterfaceIndex = idx, .Family = AF_INET };
54 if (GetIpInterfaceEntry(&row) != ERROR_NOT_FOUND)
55 {
56 break;
57 }
58 msg(D_DCO_DEBUG, "interface %ld not yet ready, retrying", idx);
59 Sleep(50);
60 }
61}
62
72static bool
74{
75 CLEAR(*version);
76
77 bool res = false;
78
79 HANDLE h = CreateFile("\\\\.\\ovpn-dco-ver", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
80
81 if (h == INVALID_HANDLE_VALUE)
82 {
83 /* fallback to a "normal" device, this will fail if device is already in use */
84 h = CreateFile("\\\\.\\ovpn-dco", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
85 }
86
87 if (h == INVALID_HANDLE_VALUE)
88 {
89 goto done;
90 }
91
92 DWORD bytes_returned = 0;
93 if (!DeviceIoControl(h, OVPN_IOCTL_GET_VERSION, NULL, 0, version, sizeof(*version),
94 &bytes_returned, NULL))
95 {
96 goto done;
97 }
98
99 res = true;
100
101done:
102 if (h != INVALID_HANDLE_VALUE)
103 {
104 CloseHandle(h);
105 }
106
107 msg(D_DCO_DEBUG, "dco version: %ld.%ld.%ld", version->Major, version->Minor, version->Patch);
108
109 return res;
110}
111
121void
122ovpn_dco_init_mp(dco_context_t *dco, const char *dev_node)
123{
124 ASSERT(dco->ifmode == DCO_MODE_UNINIT);
125 dco->ifmode = DCO_MODE_MP;
126
127 /* Use manual reset event so it remains signalled until
128 * explicitly reset. This way we won't lose notifications
129 */
130 dco->ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
131 if (dco->ov.hEvent == NULL)
132 {
133 msg(M_ERR, "Error: ovpn_dco_init: CreateEvent failed");
134 }
135
136 dco->rwhandle.read = dco->ov.hEvent;
137
138 /* open DCO device */
139 struct gc_arena gc = gc_new();
140 const char *device_guid;
141 tun_open_device(dco->tt, dev_node, &device_guid, &gc);
142 gc_free(&gc);
143
144 /* set mp mode */
146 DWORD bytes_returned = 0;
147 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_SET_MODE, &m, sizeof(m), NULL, 0,
148 &bytes_returned, NULL))
149 {
150 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SET_MODE) failed");
151 }
152
153 dco_wait_ready(dco->tt->adapter_index);
154}
155
164void
166{
167 DWORD bytes_returned = 0;
168 if (!DeviceIoControl(tt->hand, OVPN_IOCTL_START_VPN, NULL, 0, NULL, 0, &bytes_returned, NULL))
169 {
170 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_START_VPN) failed");
171 }
172
173 /* Sometimes IP Helper API, which we use for setting IP address etc,
174 * complains that interface is not found. Give it some time to settle
175 */
177}
178
179
189bool
191{
192 dco_context_t *dco = &c->c1.tuntap->dco;
193
194 dco->c = c;
195
196 switch (c->mode)
197 {
199 dco->ifmode = DCO_MODE_P2P;
200 dco_p2p_start_vpn(dco->tt);
201 break;
202
203 case MODE_SERVER:
205 break;
206
207 default:
208 ASSERT(false);
209 }
210
211 return true;
212}
213
214int
215open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
216{
217 ASSERT(0);
218 return 0;
219}
220
221static void
222dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, struct signal_info *sig_info)
223{
224 volatile int *signal_received = &sig_info->signal_received;
225 /* GetOverlappedResultEx is available starting from Windows 8 */
226 typedef BOOL(WINAPI * get_overlapped_result_ex_t)(HANDLE, LPOVERLAPPED, LPDWORD, DWORD, BOOL);
227 get_overlapped_result_ex_t get_overlapped_result_ex =
228 (get_overlapped_result_ex_t)GetProcAddress(GetModuleHandle("Kernel32.dll"),
229 "GetOverlappedResultEx");
230
231 if (get_overlapped_result_ex == NULL)
232 {
233 msg(M_ERR, "Failed to load GetOverlappedResult()");
234 }
235
236 DWORD timeout_msec = timeout * 1000;
237 const int poll_interval_ms = 50;
238
239 while (timeout_msec > 0)
240 {
241 timeout_msec -= poll_interval_ms;
242
243 DWORD transferred;
244 if (get_overlapped_result_ex(handle, ov, &transferred, poll_interval_ms, FALSE) != 0)
245 {
246 /* TCP connection established by dco */
247 return;
248 }
249
250 DWORD err = GetLastError();
251 if ((err != WAIT_TIMEOUT) && (err != ERROR_IO_INCOMPLETE))
252 {
253 /* dco reported connection error */
254 msg(M_NONFATAL | M_ERRNO, "dco connect error");
255 register_signal(sig_info, SIGUSR1, "dco-connect-error");
256 return;
257 }
258
259 get_signal(signal_received);
260 if (*signal_received)
261 {
262 return;
263 }
264
266 }
267
268 /* we end up here when timeout occurs in userspace */
269 msg(M_NONFATAL, "dco connect timeout");
270 register_signal(sig_info, SIGUSR1, "dco-connect-timeout");
271}
272
282void
283dco_mp_start_vpn(HANDLE handle, struct link_socket *sock)
284{
285 msg(D_DCO_DEBUG, "%s", __func__);
286
287 int ai_family = sock->info.lsa->bind_local->ai_family;
288 const struct addrinfo *local = sock->info.lsa->bind_local;
289 const struct addrinfo *cur = NULL;
290
291 for (cur = local; cur; cur = cur->ai_next)
292 {
293 if (cur->ai_family == ai_family)
294 {
295 break;
296 }
297 }
298 if (!cur)
299 {
300 msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", __func__,
301 addr_family_name(ai_family));
302 }
303
304 OVPN_MP_START_VPN in, out;
305 in.IPv6Only = sock->info.bind_ipv6_only ? 1 : 0;
306 if (ai_family == AF_INET)
307 {
308 memcpy(&in.ListenAddress.Addr4, cur->ai_addr, sizeof(struct sockaddr_in));
309 }
310 else
311 {
312 memcpy(&in.ListenAddress.Addr6, cur->ai_addr, sizeof(struct sockaddr_in6));
313 }
314
315 /* in multipeer mode control channel packets are prepended with remote peer's sockaddr */
316 sock->sockflags |= SF_PREPEND_SA;
317
318 DWORD bytes_returned = 0;
319 if (!DeviceIoControl(handle, OVPN_IOCTL_MP_START_VPN, &in, sizeof(in), &out, sizeof(out),
320 &bytes_returned, NULL))
321 {
322 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_MP_START_VPN) failed");
323 }
324}
325
326void
327dco_p2p_new_peer(HANDLE handle, OVERLAPPED *ov, struct link_socket *sock,
328 struct signal_info *sig_info)
329{
330 msg(D_DCO_DEBUG, "%s", __func__);
331
332 OVPN_NEW_PEER peer = { 0 };
333
334 struct addrinfo *remoteaddr = sock->info.lsa->current_remote;
335
336 struct sockaddr *local = NULL;
337 const struct sockaddr *remote = remoteaddr->ai_addr;
338
339 if (remoteaddr->ai_protocol == IPPROTO_TCP || remoteaddr->ai_socktype == SOCK_STREAM)
340 {
341 peer.Proto = OVPN_PROTO_TCP;
342 }
343 else
344 {
345 peer.Proto = OVPN_PROTO_UDP;
346 }
347
348 if (sock->bind_local)
349 {
350 /* Use first local address with correct address family */
351 const struct addrinfo *bind = sock->info.lsa->bind_local;
352 while (bind && !local)
353 {
354 if (bind->ai_family == remote->sa_family)
355 {
356 local = bind->ai_addr;
357 }
358 bind = bind->ai_next;
359 }
360 }
361
362 if (sock->bind_local && !local)
363 {
364 msg(M_FATAL, "DCO: Socket bind failed: Address to bind lacks %s record",
365 addr_family_name(remote->sa_family));
366 }
367
368 if (remote->sa_family == AF_INET6)
369 {
370 peer.Remote.Addr6 = *((SOCKADDR_IN6 *)(remoteaddr->ai_addr));
371 if (local)
372 {
373 peer.Local.Addr6 = *((SOCKADDR_IN6 *)local);
374 }
375 else
376 {
377 peer.Local.Addr6.sin6_addr = in6addr_any;
378 peer.Local.Addr6.sin6_port = 0;
379 peer.Local.Addr6.sin6_family = AF_INET6;
380 }
381 }
382 else if (remote->sa_family == AF_INET)
383 {
384 peer.Remote.Addr4 = *((SOCKADDR_IN *)(remoteaddr->ai_addr));
385 if (local)
386 {
387 peer.Local.Addr4 = *((SOCKADDR_IN *)local);
388 }
389 else
390 {
391 peer.Local.Addr4.sin_addr = in4addr_any;
392 peer.Local.Addr4.sin_port = 0;
393 peer.Local.Addr4.sin_family = AF_INET;
394 }
395 }
396 else
397 {
398 ASSERT(0);
399 }
400
401 CLEAR(*ov);
402 if (!DeviceIoControl(handle, OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, NULL, ov))
403 {
404 DWORD err = GetLastError();
405 if (err != ERROR_IO_PENDING)
406 {
407 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_PEER) failed");
408 }
409 else
410 {
412 sig_info);
413 }
414 }
415}
416
417int
418dco_new_peer(dco_context_t *dco, unsigned int peerid, socket_descriptor_t sd,
419 struct sockaddr *localaddr, struct sockaddr *remoteaddr,
420 const struct in_addr *vpn_ipv4, const struct in6_addr *vpn_ipv6)
421{
422 msg(D_DCO_DEBUG, "%s: peer-id %d, fd " SOCKET_PRINTF, __func__, peerid, sd);
423
424 if (dco->ifmode == DCO_MODE_P2P)
425 {
426 /* no-op for p2p */
427 return 0;
428 }
429
430 OVPN_MP_NEW_PEER newPeer = { 0 };
431
432 if (remoteaddr)
433 {
434 /* while the driver doesn't use the local address yet it requires its AF to be valid */
435 newPeer.Local.Addr4.sin_family = remoteaddr->sa_family;
436
437 if (remoteaddr->sa_family == AF_INET)
438 {
439 memcpy(&newPeer.Remote.Addr4, remoteaddr, sizeof(struct sockaddr_in));
440 }
441 else
442 {
443 memcpy(&newPeer.Remote.Addr6, remoteaddr, sizeof(struct sockaddr_in6));
444 }
445 }
446
447 if (vpn_ipv4)
448 {
449 newPeer.VpnAddr4 = *vpn_ipv4;
450 }
451
452 if (vpn_ipv6)
453 {
454 newPeer.VpnAddr6 = *vpn_ipv6;
455 }
456
457 newPeer.PeerId = peerid;
458
459 DWORD bytesReturned;
460 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_NEW_PEER, &newPeer, sizeof(newPeer), NULL, 0,
461 &bytesReturned, NULL))
462 {
463 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_MP_NEW_PEER) failed");
464 }
465
466 return 0;
467}
468
469int
470dco_del_peer(dco_context_t *dco, unsigned int peerid)
471{
472 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
473
474 OVPN_MP_DEL_PEER del_peer = { peerid };
475 VOID *buf = NULL;
476 DWORD len = 0;
477 DWORD ioctl = OVPN_IOCTL_DEL_PEER;
478
479 if (dco->ifmode == DCO_MODE_MP)
480 {
482 buf = &del_peer;
483 len = sizeof(del_peer);
484 }
485
486 DWORD bytes_returned = 0;
487 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL))
488 {
489 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_DEL_PEER) failed");
490 return -1;
491 }
492 return 0;
493}
494
495int
496dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout,
497 int mss)
498{
499 msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__, peerid,
500 keepalive_interval, keepalive_timeout, mss);
501
502 OVPN_MP_SET_PEER mp_peer = { peerid, keepalive_interval, keepalive_timeout, mss };
503 OVPN_SET_PEER peer = { keepalive_interval, keepalive_timeout, mss };
504 VOID *buf = NULL;
505 DWORD len = 0;
506 DWORD ioctl = (dco->ifmode == DCO_MODE_MP) ? OVPN_IOCTL_MP_SET_PEER : OVPN_IOCTL_SET_PEER;
507
508 if (dco->ifmode == DCO_MODE_MP)
509 {
510 buf = &mp_peer;
511 len = sizeof(OVPN_MP_SET_PEER);
512 }
513 else
514 {
515 buf = &peer;
516 len = sizeof(OVPN_SET_PEER);
517 }
518
519 DWORD bytes_returned = 0;
520 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL))
521 {
522 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_SET_PEER) failed");
523 return -1;
524 }
525
526 return 0;
527}
528
529int
530dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, dco_key_slot_t slot,
531 const uint8_t *encrypt_key, const uint8_t *encrypt_iv, const uint8_t *decrypt_key,
532 const uint8_t *decrypt_iv, const char *ciphername, bool epoch)
533{
534 msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s", __func__, slot, keyid, peerid,
535 ciphername);
536
537 const int nonce_len = 8;
538 size_t key_len = cipher_kt_key_size(ciphername);
539 ASSERT(key_len <= 32);
540
541 OVPN_CRYPTO_DATA_V2 crypto_data;
542 ZeroMemory(&crypto_data, sizeof(crypto_data));
543
544 OVPN_CRYPTO_DATA *v1 = &crypto_data.V1;
545
546 v1->CipherAlg = dco_get_cipher(ciphername);
547 ASSERT(keyid >= 0 && keyid <= UCHAR_MAX);
548 v1->KeyId = (unsigned char)keyid;
549 v1->PeerId = peerid;
550 v1->KeySlot = slot;
551
552 /* for epoch we use key material as a seed, no as actual key */
553 CopyMemory(v1->Encrypt.Key, encrypt_key, epoch ? 32 : key_len);
554 v1->Encrypt.KeyLen = (unsigned char)key_len;
555 CopyMemory(v1->Encrypt.NonceTail, encrypt_iv, nonce_len);
556
557 CopyMemory(v1->Decrypt.Key, decrypt_key, epoch ? 32 : key_len);
558 v1->Decrypt.KeyLen = (unsigned char)key_len;
559 CopyMemory(v1->Decrypt.NonceTail, decrypt_iv, nonce_len);
560
561 ASSERT(v1->CipherAlg > 0);
562
563 DWORD ioctl = OVPN_IOCTL_NEW_KEY;
564 VOID *buf = &crypto_data.V1;
565 DWORD bufSize = sizeof(crypto_data.V1);
566 if (epoch)
567 {
568 ioctl = OVPN_IOCTL_NEW_KEY_V2;
569 crypto_data.CryptoOptions |= CRYPTO_OPTIONS_EPOCH;
570 buf = &crypto_data;
571 bufSize = sizeof(crypto_data);
572 }
573
574 DWORD bytes_returned = 0;
575
576 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, bufSize, NULL, 0, &bytes_returned, NULL))
577 {
578 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY) failed");
579 return -1;
580 }
581 return 0;
582}
583
584int
585dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
586{
587 msg(D_DCO, "%s: peer-id %d, slot %d called but ignored", __func__, peerid, slot);
588 /* FIXME: Implement in driver first */
589 return 0;
590}
591
592int
593dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
594{
595 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
596
597 OVPN_MP_SWAP_KEYS swap = { peer_id };
598 DWORD ioctl = OVPN_IOCTL_SWAP_KEYS;
599 VOID *buf = NULL;
600 DWORD len = 0;
601
602 if (dco->ifmode == DCO_MODE_MP)
603 {
605 buf = &swap;
606 len = sizeof(swap);
607 }
608
609 DWORD bytes_returned = 0;
610 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL))
611 {
612 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SWAP_KEYS) failed");
613 return -1;
614 }
615 return 0;
616}
617
618bool
620{
621 /* try to open device by symbolic name */
622 HANDLE h = CreateFile("\\\\.\\ovpn-dco", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
623 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
624
625 if (h != INVALID_HANDLE_VALUE)
626 {
627 CloseHandle(h);
628 return true;
629 }
630
631 DWORD err = GetLastError();
632 if (err == ERROR_ACCESS_DENIED)
633 {
634 /* this likely means that device exists but is already in use,
635 * don't bail out since later we try to open all existing dco
636 * devices and then bail out if all devices are in use
637 */
638 return true;
639 }
640
641 msg(msglevel, "Note: ovpn-dco-win driver is missing, disabling data channel offload.");
642 return false;
643}
644
645const char *
647{
648 OVPN_VERSION version = { 0 };
649 if (dco_get_version(&version))
650 {
651 struct buffer out = alloc_buf_gc(256, gc);
652 buf_printf(&out, "%ld.%ld.%ld", version.Major, version.Minor, version.Patch);
653 return BSTR(&out);
654 }
655 else
656 {
657 return "N/A";
658 }
659}
660
672static void
674{
675 DWORD bytes_read = 0;
676 BOOL res = GetOverlappedResult(dco->tt->hand, &dco->ov, &bytes_read, FALSE);
677 if (res)
678 {
679 msg(D_DCO_DEBUG, "%s: completion%s success [%ld]", __func__, queued ? "" : " non-queued",
680 bytes_read);
681
682 dco->dco_message_peer_id = dco->notif_buf.PeerId;
683 dco->dco_message_type = dco->notif_buf.Cmd;
684 dco->dco_del_peer_reason = dco->notif_buf.DelPeerReason;
685 dco->dco_float_peer_ss = dco->notif_buf.FloatAddress;
686 }
687 else
688 {
689 msg(D_DCO_DEBUG | M_ERRNO, "%s: completion%s error", __func__, queued ? "" : " non-queued");
690 }
691}
692
693int
695{
696 if (dco->ifmode != DCO_MODE_MP)
697 {
698 ASSERT(false);
699 }
700
701 dco->dco_message_peer_id = -1;
702 dco->dco_message_type = 0;
703
704 switch (dco->iostate)
705 {
706 case IOSTATE_QUEUED:
708
709 ASSERT(ResetEvent(dco->ov.hEvent));
710 dco->iostate = IOSTATE_INITIAL;
711
712 break;
713
715 dco->iostate = IOSTATE_INITIAL;
716 ASSERT(ResetEvent(dco->ov.hEvent));
717
718 if (dco->ov_ret == ERROR_SUCCESS)
719 {
721 }
722 else
723 {
724 SetLastError(dco->ov_ret);
725 msg(D_DCO_DEBUG | M_ERRNO, "%s: completion non-queued error", __func__);
726 }
727
728 break;
729 }
730
731 if (dco->c->mode == CM_TOP)
732 {
734 }
735 else
736 {
738 }
739
740 return 0;
741}
742
743int
745{
746 struct gc_arena gc = gc_new();
747
748 int ret = 0;
749 const struct tuntap *tt = dco->tt;
750
751 if (!tuntap_defined(tt))
752 {
753 ret = -1;
754 goto done;
755 }
756
758 .PeerId = -1
759 };
760
761 DWORD required_size = 0, bytes_returned = 0;
762 /* first, figure out buffer size */
763 if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_PEER_STATS, &ps, sizeof(ps), &required_size, sizeof(DWORD), &bytes_returned, NULL))
764 {
765 if (GetLastError() == ERROR_MORE_DATA)
766 {
767 if (bytes_returned != sizeof(DWORD))
768 {
769 msg(M_WARN, "%s: invalid bytes returned for size query (%lu, expected %zu)", __func__, bytes_returned, sizeof(DWORD));
770 ret = -1;
771 goto done;
772 }
773 /* required_size now contains the size written by the driver */
774 if (required_size == 0)
775 {
776 ret = 0; /* no peers to process */
777 goto done;
778 }
779 if (required_size < sizeof(OVPN_PEER_STATS))
780 {
781 msg(M_WARN, "%s: invalid required size %lu (minimum %zu)", __func__, required_size, sizeof(OVPN_PEER_STATS));
782 ret = -1;
783 goto done;
784 }
785 }
786 else
787 {
788 msg(M_WARN | M_ERRNO, "%s: failed to fetch required buffer size", __func__);
789 ret = -1;
790 goto done;
791 }
792 }
793 else
794 {
795 /* unexpected success? */
796 if (bytes_returned == 0)
797 {
798 ret = 0; /* no peers to process */
799 goto done;
800 }
801
802 msg(M_WARN, "%s: first DeviceIoControl call succeeded unexpectedly (%lu bytes returned)", __func__, bytes_returned);
803 ret = -1;
804 goto done;
805 }
806
807
808 /* allocate the buffer and fetch stats */
809 OVPN_PEER_STATS *peer_stats = gc_malloc(required_size, true, &gc);
810 if (!peer_stats)
811 {
812 msg(M_WARN, "%s: failed to allocate buffer of size %lu", __func__, required_size);
813 ret = -1;
814 goto done;
815 }
816
817 if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_PEER_STATS, &ps, sizeof(ps), peer_stats, required_size, &bytes_returned, NULL))
818 {
819 /* unlikely case when a peer has been added since fetching buffer size, not an error! */
820 if (GetLastError() == ERROR_MORE_DATA)
821 {
822 msg(M_WARN, "%s: peer has been added, skip fetching stats", __func__);
823 ret = 0;
824 goto done;
825 }
826
827 msg(M_WARN | M_ERRNO, "%s: failed to fetch multipeer stats", __func__);
828 ret = -1;
829 goto done;
830 }
831
832 /* iterate over stats and update peers */
833 for (size_t i = 0; i < bytes_returned / sizeof(OVPN_PEER_STATS); ++i)
834 {
835 OVPN_PEER_STATS *stat = &peer_stats[i];
836
837 if (stat->PeerId >= (int)dco->c->multi->max_clients)
838 {
839 msg(M_WARN, "%s: received out of bound peer_id %d (max=%u)", __func__, stat->PeerId,
840 dco->c->multi->max_clients);
841 continue;
842 }
843
844 struct multi_instance *mi = dco->c->multi->instances[stat->PeerId];
845 if (!mi)
846 {
847 msg(M_WARN, "%s: received data for a non-existing peer %u", __func__, stat->PeerId);
848 continue;
849 }
850
851 /* update peer stats */
852 struct context_2 *c2 = &mi->context.c2;
853 c2->dco_read_bytes = stat->LinkRxBytes;
854 c2->dco_write_bytes = stat->LinkTxBytes;
855 c2->tun_read_bytes = stat->VpnRxBytes;
856 c2->tun_write_bytes = stat->VpnTxBytes;
857 }
858
859done:
860 gc_free(&gc);
861
862 if (raise_sigusr1_on_err && ret < 0)
863 {
864 register_signal(dco->c->sig, SIGUSR1, "dco peer stats error");
865 }
866
867 return ret;
868}
869
870int
871dco_get_peer_stats_fallback(struct context *c, const bool raise_sigusr1_on_err)
872{
873 const struct tuntap *tt = c->c1.tuntap;
874
875 if (!tuntap_defined(tt))
876 {
877 return -1;
878 }
879
880 OVPN_STATS stats;
881 ZeroMemory(&stats, sizeof(OVPN_STATS));
882
883 DWORD bytes_returned = 0;
884 if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_STATS, NULL, 0, &stats, sizeof(stats),
885 &bytes_returned, NULL))
886 {
887 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_GET_STATS) failed");
888 return -1;
889 }
890
895
896 return 0;
897}
898
899int
900dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
901{
902 const struct tuntap *tt = c->c1.tuntap;
903
904 if (!tuntap_defined(tt))
905 {
906 return -1;
907 }
908
909 /* first, try a new ioctl */
911
912 OVPN_PEER_STATS peer_stats = { 0 };
913 DWORD bytes_returned = 0;
914 if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_PEER_STATS, &ps, sizeof(ps), &peer_stats, sizeof(peer_stats),
915 &bytes_returned, NULL))
916 {
917 if (GetLastError() == ERROR_INVALID_FUNCTION)
918 {
919 /* are we using the old driver? */
920 return dco_get_peer_stats_fallback(c, raise_sigusr1_on_err);
921 }
922
923 msg(M_WARN | M_ERRNO, "%s: DeviceIoControl(OVPN_IOCTL_GET_PEER_STATS) failed", __func__);
924 return -1;
925 }
926
927 if (bytes_returned != sizeof(OVPN_PEER_STATS))
928 {
929 msg(M_WARN | M_ERRNO, "%s: DeviceIoControl(OVPN_IOCTL_GET_PEER_STATS) returned invalid size", __func__);
930 return -1;
931 }
932
933 c->c2.dco_read_bytes = peer_stats.LinkRxBytes;
934 c->c2.dco_write_bytes = peer_stats.LinkTxBytes;
935 c->c2.tun_read_bytes = peer_stats.VpnRxBytes;
936 c->c2.tun_write_bytes = peer_stats.VpnTxBytes;
937
938 return 0;
939}
940
941void
943{
944 if (dco->ifmode != DCO_MODE_MP)
945 {
946 /* mp only */
947 return;
948 }
949
950 event_ctl(es, &dco->rwhandle, EVENT_READ, arg);
951
952 if (dco->iostate == IOSTATE_INITIAL)
953 {
954 /* the overlapped IOCTL will signal this event on I/O completion */
955 ASSERT(ResetEvent(dco->ov.hEvent));
956
957 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_NOTIFY_EVENT, NULL, 0, &dco->notif_buf,
958 sizeof(dco->notif_buf), NULL, &dco->ov))
959 {
960 DWORD err = GetLastError();
961 if (err == ERROR_IO_PENDING) /* operation queued? */
962 {
963 dco->iostate = IOSTATE_QUEUED;
964 dco->ov_ret = ERROR_SUCCESS;
965
966 msg(D_DCO_DEBUG, "%s: notify ioctl queued", __func__);
967 }
968 else
969 {
970 /* error occured */
971 ASSERT(SetEvent(dco->ov.hEvent));
972 dco->iostate = IOSTATE_IMMEDIATE_RETURN;
973 dco->ov_ret = err;
974
975 msg(D_DCO_DEBUG | M_ERRNO, "%s: notify ioctl error", __func__);
976 }
977 }
978 else
979 {
980 ASSERT(SetEvent(dco->ov.hEvent));
981 dco->iostate = IOSTATE_IMMEDIATE_RETURN;
982 dco->ov_ret = ERROR_SUCCESS;
983
984 msg(D_DCO_DEBUG, "%s: notify ioctl immediate return", __func__);
985 }
986 }
987}
988
989const char *
991{
992 /*
993 * this API can be called either from user mode or kernel mode,
994 * which enables us to probe driver's chachapoly support
995 * (available starting from Windows 11)
996 */
997
998 BCRYPT_ALG_HANDLE h;
999 NTSTATUS status = BCryptOpenAlgorithmProvider(&h, L"CHACHA20_POLY1305", NULL, 0);
1000 if (BCRYPT_SUCCESS(status))
1001 {
1002 BCryptCloseAlgorithmProvider(h, 0);
1003 return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
1004 }
1005 else
1006 {
1007 return "AES-128-GCM:AES-256-GCM:AES-192-GCM";
1008 }
1009}
1010
1011bool
1013{
1014 OVPN_VERSION ver = { 0 };
1015 return dco_get_version(&ver) && ver.Major >= 2;
1016}
1017
1018void
1020 unsigned int peer_id)
1021{
1022 struct gc_arena gc = gc_new();
1023
1025 .Addr.Addr4.S_un.S_addr = dst, .Netbits = netbits, .PeerId = peer_id, .IPv6 = 0
1026 };
1027
1028 msg(D_DCO_DEBUG, "%s: %s/%d -> peer %d", __func__, print_in_addr_t(dst, IA_NET_ORDER, &gc),
1029 netbits, peer_id);
1030
1031 DWORD bytes_returned = 0;
1032 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_ADD_IROUTE, &route, sizeof(route), NULL, 0,
1033 &bytes_returned, NULL))
1034 {
1035 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_ADD_IROUTE) failed");
1036 }
1037
1038 gc_free(&gc);
1039}
1040
1041void
1042dco_win_add_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits,
1043 unsigned int peer_id)
1044{
1045 struct gc_arena gc = gc_new();
1046
1047 OVPN_MP_IROUTE route = { .Addr.Addr6 = dst, .Netbits = netbits, .PeerId = peer_id, .IPv6 = 1 };
1048
1049 msg(D_DCO_DEBUG, "%s: %s/%d -> peer %d", __func__, print_in6_addr(dst, IA_NET_ORDER, &gc),
1050 netbits, peer_id);
1051
1052 DWORD bytes_returned = 0;
1053 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_ADD_IROUTE, &route, sizeof(route), NULL, 0,
1054 &bytes_returned, NULL))
1055 {
1056 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_ADD_IROUTE) failed");
1057 }
1058
1059 gc_free(&gc);
1060}
1061
1062void
1063dco_win_del_iroute_ipv4(dco_context_t *dco, in_addr_t dst, unsigned int netbits)
1064{
1065 struct gc_arena gc = gc_new();
1066
1068 .Addr.Addr4.S_un.S_addr = dst, .Netbits = netbits, .PeerId = -1, .IPv6 = 0
1069 };
1070
1071 msg(D_DCO_DEBUG, "%s: %s/%d", __func__, print_in_addr_t(dst, IA_NET_ORDER, &gc), netbits);
1072
1073 DWORD bytes_returned = 0;
1074 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_DEL_IROUTE, &route, sizeof(route), NULL, 0,
1075 &bytes_returned, NULL))
1076 {
1077 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_DEL_IROUTE) failed");
1078 }
1079
1080 gc_free(&gc);
1081}
1082
1083void
1084dco_win_del_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits)
1085{
1086 struct gc_arena gc = gc_new();
1087
1088 OVPN_MP_IROUTE route = { .Addr.Addr6 = dst, .Netbits = netbits, .PeerId = -1, .IPv6 = 1 };
1089
1090 msg(D_DCO_DEBUG, "%s: %s/%d", __func__, print_in6_addr(dst, IA_NET_ORDER, &gc), netbits);
1091
1092 DWORD bytes_returned = 0;
1093 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_DEL_IROUTE, &route, sizeof(route), NULL, 0,
1094 &bytes_returned, NULL))
1095 {
1096 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_DEL_IROUTE) failed");
1097 }
1098
1099 gc_free(&gc);
1100}
1101
1102bool
1104{
1105 OVPN_VERSION ver = { 0 };
1106 return dco_get_version(&ver) && ((ver.Major == 2 && ver.Minor >= 8) || (ver.Major > 2));
1107}
1108
1109#endif /* defined(_WIN32) */
bool buf_printf(struct buffer *buf, const char *format,...)
printf-style append to a buffer with overflow check.
Definition buffer.c:226
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:318
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
#define BSTR(buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:151
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1912
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1896
Data Channel Cryptography Module.
unsigned int cipher_kt_key_size(const char *ciphername)
Returns the size of keys used by the cipher, in bytes.
void * dco_context_t
Definition dco.h:259
int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
Definition dco_win.c:215
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
Definition dco_win.c:585
bool dco_supports_epoch_data(struct context *c)
Definition dco_win.c:1103
bool dco_available(msglvl_t msglevel)
Definition dco_win.c:619
void dco_mp_start_vpn(HANDLE handle, struct link_socket *sock)
Initializes and binds the kernel UDP transport socket for multipeer mode.
Definition dco_win.c:283
int dco_del_peer(dco_context_t *dco, unsigned int peerid)
Definition dco_win.c:470
void dco_win_add_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits, unsigned int peer_id)
Definition dco_win.c:1042
const char * dco_version_string(struct gc_arena *gc)
Definition dco_win.c:646
void dco_p2p_start_vpn(struct tuntap *tt)
Transitions the DCO adapter to the connected state in P2P mode.
Definition dco_win.c:165
int dco_read_and_process(dco_context_t *dco)
Definition dco_win.c:694
const char * dco_get_supported_ciphers(void)
Definition dco_win.c:990
bool ovpn_dco_init(struct context *c)
Initializes DCO depends on mode
Definition dco_win.c:190
static void dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, struct signal_info *sig_info)
Definition dco_win.c:222
void dco_win_del_iroute_ipv4(dco_context_t *dco, in_addr_t dst, unsigned int netbits)
Definition dco_win.c:1063
bool dco_win_supports_multipeer(void)
Definition dco_win.c:1012
int dco_get_peer_stats_multi(dco_context_t *dco, const bool raise_sigusr1_on_err)
Definition dco_win.c:744
void dco_win_del_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits)
Definition dco_win.c:1084
int dco_get_peer_stats_fallback(struct context *c, const bool raise_sigusr1_on_err)
Definition dco_win.c:871
static void dco_wait_ready(DWORD idx)
Definition dco_win.c:49
int dco_set_peer(dco_context_t *dco, unsigned int peerid, int keepalive_interval, int keepalive_timeout, int mss)
Definition dco_win.c:496
int dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
Definition dco_win.c:593
void ovpn_dco_init_mp(dco_context_t *dco, const char *dev_node)
Initializes the DCO adapter in multipeer mode and sets it to "connected" state.
Definition dco_win.c:122
int dco_new_peer(dco_context_t *dco, unsigned int peerid, socket_descriptor_t sd, struct sockaddr *localaddr, struct sockaddr *remoteaddr, const struct in_addr *vpn_ipv4, const struct in6_addr *vpn_ipv6)
Definition dco_win.c:418
int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
Definition dco_win.c:900
static void dco_handle_overlapped_success(dco_context_t *dco, bool queued)
Handles successful completion of overlapped operation.
Definition dco_win.c:673
static bool dco_get_version(OVPN_VERSION *version)
Gets version of dco-win driver.
Definition dco_win.c:73
void dco_p2p_new_peer(HANDLE handle, OVERLAPPED *ov, struct link_socket *sock, struct signal_info *sig_info)
Definition dco_win.c:327
void dco_win_add_iroute_ipv4(dco_context_t *dco, in_addr_t dst, unsigned int netbits, unsigned int peer_id)
Definition dco_win.c:1019
void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
Definition dco_win.c:942
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, bool epoch)
Definition dco_win.c:530
#define D_DCO
Definition errlevel.h:93
#define D_DCO_DEBUG
Definition errlevel.h:117
#define EVENT_READ
Definition event.h:37
static void event_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg)
Definition event.h:180
void process_incoming_dco(dco_context_t *dco)
Process an incoming DCO message (from kernel space).
Definition forward.c:1245
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
Definition forward.c:504
Interface functions to the internal and external multiplexers.
static SERVICE_STATUS status
Definition interactive.c:52
@ route
Definition interactive.c:86
void management_sleep(const int n)
A sleep function that services the management layer for n seconds rather than doing nothing.
Definition manage.c:4238
Header file for server-mode related structures and functions.
void multi_process_incoming_dco(dco_context_t *dco)
Process an incoming DCO message (from kernel space).
void * openvpn_net_ctx_t
Definition networking.h:38
#define CLEAR(x)
Definition basic.h:32
#define M_FATAL
Definition error.h:90
#define M_NONFATAL
Definition error.h:91
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
unsigned int msglvl_t
Definition error.h:77
#define ASSERT(x)
Definition error.h:219
#define M_WARN
Definition error.h:92
#define M_ERRNO
Definition error.h:95
#define CM_TOP
Definition openvpn.h:480
#define MODE_POINT_TO_POINT
Definition options.h:264
#define MODE_SERVER
Definition options.h:265
#define OVPN_SET_PEER
#define OVPN_IOCTL_GET_STATS
#define OVPN_IOCTL_NEW_KEY_V2
#define OVPN_IOCTL_GET_VERSION
@ OVPN_PROTO_UDP
@ OVPN_PROTO_TCP
#define OVPN_IOCTL_SWAP_KEYS
#define OVPN_IOCTL_NEW_KEY
#define OVPN_IOCTL_NOTIFY_EVENT
#define OVPN_IOCTL_MP_DEL_IROUTE
OVPN_MODE
@ OVPN_MODE_MP
#define OVPN_IOCTL_MP_SET_PEER
#define OVPN_IOCTL_MP_SWAP_KEYS
#define OVPN_IOCTL_GET_PEER_STATS
#define OVPN_IOCTL_SET_PEER
#define OVPN_IOCTL_NEW_PEER
#define OVPN_IOCTL_MP_ADD_IROUTE
#define CRYPTO_OPTIONS_EPOCH
#define OVPN_IOCTL_START_VPN
#define OVPN_IOCTL_MP_NEW_PEER
#define OVPN_IOCTL_SET_MODE
#define OVPN_IOCTL_DEL_PEER
#define OVPN_IOCTL_MP_START_VPN
struct _OVPN_MP_SET_PEER OVPN_MP_SET_PEER
#define OVPN_IOCTL_MP_DEL_PEER
struct _OVPN_PEER_STATS OVPN_PEER_STATS
void register_signal(struct signal_info *si, int signum, const char *signal_text)
Register a soft signal in the signal_info struct si respecting priority.
Definition sig.c:228
static void get_signal(volatile int *sig)
Copy the global signal_received (if non-zero) to the passed-in argument sig.
Definition sig.h:109
#define SF_PREPEND_SA
Definition socket.h:216
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
const char * addr_family_name(int af)
#define IA_NET_ORDER
Definition socket_util.h:90
Control Channel Common Data Structures.
OVPN_CRYPTO_DATA V1
OVPN_KEY_SLOT KeySlot
unsigned char KeyId
OVPN_KEY_DIRECTION Decrypt
OVPN_KEY_DIRECTION Encrypt
OVPN_CIPHER_ALG CipherAlg
unsigned char Key[32]
unsigned char NonceTail[8]
unsigned char KeyLen
union _OVPN_MP_IROUTE::@20 Addr
union _OVPN_MP_NEW_PEER::@17 Local
SOCKADDR_IN6 Addr6
SOCKADDR_IN Addr4
union _OVPN_MP_NEW_PEER::@18 Remote
SOCKADDR_IN6 Addr6
union _OVPN_MP_START_VPN::@19 ListenAddress
SOCKADDR_IN6 Addr6
union _OVPN_NEW_PEER::@15 Local
SOCKADDR_IN Addr4
union _OVPN_NEW_PEER::@16 Remote
OVPN_PROTO Proto
LONG64 TunBytesSent
LONG64 TransportBytesSent
LONG64 TunBytesReceived
LONG64 TransportBytesReceived
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:76
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition openvpn.h:173
Level 2 context containing state that is reset on both SIGHUP and SIGUSR1 restarts.
Definition openvpn.h:225
counter_type dco_read_bytes
Definition openvpn.h:268
counter_type tun_read_bytes
Definition openvpn.h:265
counter_type dco_write_bytes
Definition openvpn.h:271
struct tls_multi * tls_multi
TLS state structure for this VPN tunnel.
Definition openvpn.h:324
counter_type tun_write_bytes
Definition openvpn.h:266
Contains all state information for one tunnel.
Definition openvpn.h:471
int mode
Role of this context within the OpenVPN process.
Definition openvpn.h:484
struct context_2 c2
Level 2 context.
Definition openvpn.h:514
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:472
struct context_1 c1
Level 1 context.
Definition openvpn.h:513
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
Server-mode state structure for one single VPN tunnel.
Definition multi.h:102
struct context context
The context structure storing state for this VPN tunnel.
Definition multi.h:142
const char * dev_node
Definition options.h:324
volatile int signal_received
Definition sig.h:42
int dco_peer_id
This is the handle that DCO uses to identify this session with the kernel.
Definition ssl_common.h:725
Definition tun.h:181
DWORD adapter_index
Definition tun.h:232
HANDLE hand
Definition tun.h:216
dco_context_t dco
Definition tun.h:247
#define SOCKET_PRINTF
Definition syshead.h:444
SOCKET socket_descriptor_t
Definition syshead.h:445
#define SIGUSR1
Definition syshead.h:57
uint32_t in_addr_t
Definition syshead.h:52
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:122
void tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid, struct gc_arena *gc)
Definition tun.c:5803
static bool tuntap_defined(const struct tuntap *tt)
Definition tun.h:252
#define IOSTATE_IMMEDIATE_RETURN
Definition win32.h:208
#define IOSTATE_INITIAL
Definition win32.h:206
#define IOSTATE_QUEUED
Definition win32.h:207