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