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