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-2024 Arne Schwabe <arne@rfc2549.org>
5 * Copyright (C) 2020-2024 OpenVPN Inc <sales@openvpn.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING included with this
18 * distribution); if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#if defined(_WIN32)
27
28#include "syshead.h"
29
30#include "dco.h"
31#include "forward.h"
32#include "tun.h"
33#include "crypto.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,
80 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,
86 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,
96 version, sizeof(*version), &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, &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
191ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node)
192{
193 switch (mode)
194 {
196 dco->ifmode = DCO_MODE_P2P;
197 dco_p2p_start_vpn(dco->tt);
198 break;
199
200 case MODE_SERVER:
201 ovpn_dco_init_mp(dco, dev_node);
202 break;
203
204 default:
205 ASSERT(false);
206 }
207
208 return true;
209}
210
211int
212open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
213{
214 ASSERT(0);
215 return 0;
216}
217
218static void
219dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, struct signal_info *sig_info)
220{
221 volatile int *signal_received = &sig_info->signal_received;
222 /* GetOverlappedResultEx is available starting from Windows 8 */
223 typedef BOOL (WINAPI *get_overlapped_result_ex_t)(HANDLE, LPOVERLAPPED, LPDWORD, DWORD, BOOL);
224 get_overlapped_result_ex_t get_overlapped_result_ex =
225 (get_overlapped_result_ex_t)GetProcAddress(GetModuleHandle("Kernel32.dll"),
226 "GetOverlappedResultEx");
227
228 if (get_overlapped_result_ex == NULL)
229 {
230 msg(M_ERR, "Failed to load GetOverlappedResult()");
231 }
232
233 DWORD timeout_msec = timeout * 1000;
234 const int poll_interval_ms = 50;
235
236 while (timeout_msec > 0)
237 {
238 timeout_msec -= poll_interval_ms;
239
240 DWORD transferred;
241 if (get_overlapped_result_ex(handle, ov, &transferred, poll_interval_ms, FALSE) != 0)
242 {
243 /* TCP connection established by dco */
244 return;
245 }
246
247 DWORD err = GetLastError();
248 if ((err != WAIT_TIMEOUT) && (err != ERROR_IO_INCOMPLETE))
249 {
250 /* dco reported connection error */
251 msg(M_NONFATAL | M_ERRNO, "dco connect error");
252 register_signal(sig_info, SIGUSR1, "dco-connect-error");
253 return;
254 }
255
256 get_signal(signal_received);
257 if (*signal_received)
258 {
259 return;
260 }
261
263 }
264
265 /* we end up here when timeout occurs in userspace */
266 msg(M_NONFATAL, "dco connect timeout");
267 register_signal(sig_info, SIGUSR1, "dco-connect-timeout");
268}
269
279void
280dco_mp_start_vpn(HANDLE handle, struct link_socket *sock)
281{
282 msg(D_DCO_DEBUG, "%s", __func__);
283
284 int ai_family = sock->info.lsa->bind_local->ai_family;
285 struct addrinfo *local = sock->info.lsa->bind_local;
286 struct addrinfo *cur = NULL;
287
288 for (cur = local; cur; cur = cur->ai_next)
289 {
290 if (cur->ai_family == ai_family)
291 {
292 break;
293 }
294 }
295 if (!cur)
296 {
297 msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
298 __func__, addr_family_name(ai_family));
299 }
300
301 OVPN_MP_START_VPN in, out;
302 in.IPv6Only = sock->info.bind_ipv6_only ? 1 : 0;
303 if (ai_family == AF_INET)
304 {
305 memcpy(&in.ListenAddress.Addr4, cur->ai_addr, sizeof(struct sockaddr_in));
306 }
307 else
308 {
309 memcpy(&in.ListenAddress.Addr6, cur->ai_addr, sizeof(struct sockaddr_in6));
310 }
311
312 /* in multipeer mode control channel packets are prepended with remote peer's sockaddr */
313 sock->sockflags |= SF_PREPEND_SA;
314
315 DWORD bytes_returned = 0;
316 if (!DeviceIoControl(handle, OVPN_IOCTL_MP_START_VPN, &in, sizeof(in), &out, sizeof(out),
317 &bytes_returned, NULL))
318 {
319 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_MP_START_VPN) failed");
320 }
321}
322
323void
324dco_p2p_new_peer(HANDLE handle, struct link_socket *sock, struct signal_info *sig_info)
325{
326 msg(D_DCO_DEBUG, "%s", __func__);
327
328 OVPN_NEW_PEER peer = { 0 };
329
330 struct addrinfo *remoteaddr = sock->info.lsa->current_remote;
331
332 struct sockaddr *local = NULL;
333 struct sockaddr *remote = remoteaddr->ai_addr;
334
335 if (remoteaddr->ai_protocol == IPPROTO_TCP
336 || remoteaddr->ai_socktype == SOCK_STREAM)
337 {
338 peer.Proto = OVPN_PROTO_TCP;
339 }
340 else
341 {
342 peer.Proto = OVPN_PROTO_UDP;
343 }
344
345 if (sock->bind_local)
346 {
347 /* Use first local address with correct address family */
348 struct addrinfo *bind = sock->info.lsa->bind_local;
349 while (bind && !local)
350 {
351 if (bind->ai_family == remote->sa_family)
352 {
353 local = bind->ai_addr;
354 }
355 bind = bind->ai_next;
356 }
357 }
358
359 if (sock->bind_local && !local)
360 {
361 msg(M_FATAL, "DCO: Socket bind failed: Address to bind lacks %s record",
362 addr_family_name(remote->sa_family));
363 }
364
365 if (remote->sa_family == AF_INET6)
366 {
367 peer.Remote.Addr6 = *((SOCKADDR_IN6 *)(remoteaddr->ai_addr));
368 if (local)
369 {
370 peer.Local.Addr6 = *((SOCKADDR_IN6 *)local);
371 }
372 else
373 {
374 peer.Local.Addr6.sin6_addr = in6addr_any;
375 peer.Local.Addr6.sin6_port = 0;
376 peer.Local.Addr6.sin6_family = AF_INET6;
377 }
378 }
379 else if (remote->sa_family == AF_INET)
380 {
381 peer.Remote.Addr4 = *((SOCKADDR_IN *)(remoteaddr->ai_addr));
382 if (local)
383 {
384 peer.Local.Addr4 = *((SOCKADDR_IN *)local);
385 }
386 else
387 {
388 peer.Local.Addr4.sin_addr = in4addr_any;
389 peer.Local.Addr4.sin_port = 0;
390 peer.Local.Addr4.sin_family = AF_INET;
391 }
392 }
393 else
394 {
395 ASSERT(0);
396 }
397
398 OVERLAPPED ov = { 0 };
399 if (!DeviceIoControl(handle, OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, NULL, &ov))
400 {
401 DWORD err = GetLastError();
402 if (err != ERROR_IO_PENDING)
403 {
404 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_PEER) failed");
405 }
406 else
407 {
409 }
410 }
411}
412
413int
414dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd,
415 struct sockaddr *localaddr, struct sockaddr *remoteaddr,
416 struct in_addr *vpn_ipv4, struct in6_addr *vpn_ipv6)
417{
418 msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd);
419
420 if (dco->ifmode == DCO_MODE_P2P)
421 {
422 /* no-op for p2p */
423 return 0;
424 }
425
426 OVPN_MP_NEW_PEER newPeer = {0};
427
428 if (remoteaddr)
429 {
430 /* while the driver doesn't use the local address yet it requires its AF to be valid */
431 newPeer.Local.Addr4.sin_family = remoteaddr->sa_family;
432
433 if (remoteaddr->sa_family == AF_INET)
434 {
435 memcpy(&newPeer.Remote.Addr4, remoteaddr, sizeof(struct sockaddr_in));
436 }
437 else
438 {
439 memcpy(&newPeer.Remote.Addr6, remoteaddr, sizeof(struct sockaddr_in6));
440 }
441 }
442
443 if (vpn_ipv4)
444 {
445 newPeer.VpnAddr4 = *vpn_ipv4;
446 }
447
448 if (vpn_ipv6)
449 {
450 newPeer.VpnAddr6 = *vpn_ipv6;
451 }
452
453 newPeer.PeerId = peerid;
454
455 DWORD bytesReturned;
456 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_NEW_PEER, &newPeer, sizeof(newPeer), NULL, 0, &bytesReturned, NULL))
457 {
458 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_MP_NEW_PEER) failed");
459 }
460
461 return 0;
462}
463
464int
465dco_del_peer(dco_context_t *dco, unsigned int peerid)
466{
467 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid);
468
469 OVPN_MP_DEL_PEER del_peer = { peerid };
470 VOID *buf = NULL;
471 DWORD len = 0;
472 DWORD ioctl = OVPN_IOCTL_DEL_PEER;
473
474 if (dco->ifmode == DCO_MODE_MP)
475 {
477 buf = &del_peer;
478 len = sizeof(del_peer);
479 }
480
481 DWORD bytes_returned = 0;
482 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL))
483 {
484 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_DEL_PEER) failed");
485 return -1;
486 }
487 return 0;
488}
489
490int
491dco_set_peer(dco_context_t *dco, unsigned int peerid,
492 int keepalive_interval, int keepalive_timeout, int mss)
493{
494 msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__,
495 peerid, keepalive_interval, keepalive_timeout, mss);
496
497 OVPN_MP_SET_PEER mp_peer = { peerid, keepalive_interval, keepalive_timeout, mss };
498 OVPN_SET_PEER peer = { keepalive_interval, keepalive_timeout, mss };
499 VOID *buf = NULL;
500 DWORD len = 0;
501 DWORD ioctl = (dco->ifmode == DCO_MODE_MP) ? OVPN_IOCTL_MP_SET_PEER : OVPN_IOCTL_SET_PEER;
502
503 if (dco->ifmode == DCO_MODE_MP)
504 {
505 buf = &mp_peer;
506 len = sizeof(OVPN_MP_SET_PEER);
507 }
508 else
509 {
510 buf = &peer;
511 len = sizeof(OVPN_SET_PEER);
512 }
513
514 DWORD bytes_returned = 0;
515 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL))
516 {
517 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_SET_PEER) failed");
518 return -1;
519 }
520
521 return 0;
522}
523
524int
525dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid,
526 dco_key_slot_t slot,
527 const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
528 const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
529 const char *ciphername)
530{
531 msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
532 __func__, slot, keyid, peerid, ciphername);
533
534 const int nonce_len = 8;
535 size_t key_len = cipher_kt_key_size(ciphername);
536
537 OVPN_CRYPTO_DATA crypto_data;
538 ZeroMemory(&crypto_data, sizeof(crypto_data));
539
540 crypto_data.CipherAlg = dco_get_cipher(ciphername);
541 crypto_data.KeyId = keyid;
542 crypto_data.PeerId = peerid;
543 crypto_data.KeySlot = slot;
544
545 CopyMemory(crypto_data.Encrypt.Key, encrypt_key, key_len);
546 crypto_data.Encrypt.KeyLen = (char)key_len;
547 CopyMemory(crypto_data.Encrypt.NonceTail, encrypt_iv, nonce_len);
548
549 CopyMemory(crypto_data.Decrypt.Key, decrypt_key, key_len);
550 crypto_data.Decrypt.KeyLen = (char)key_len;
551 CopyMemory(crypto_data.Decrypt.NonceTail, decrypt_iv, nonce_len);
552
553 ASSERT(crypto_data.CipherAlg > 0);
554
555 DWORD bytes_returned = 0;
556
557 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_NEW_KEY, &crypto_data,
558 sizeof(crypto_data), NULL, 0, &bytes_returned, NULL))
559 {
560 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY) failed");
561 return -1;
562 }
563 return 0;
564}
565int
566dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
567{
568 msg(D_DCO, "%s: peer-id %d, slot %d called but ignored", __func__, peerid,
569 slot);
570 /* FIXME: Implement in driver first */
571 return 0;
572}
573
574int
575dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
576{
577 msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
578
579 OVPN_MP_SWAP_KEYS swap = {peer_id};
580 DWORD ioctl = OVPN_IOCTL_SWAP_KEYS;
581 VOID *buf = NULL;
582 DWORD len = 0;
583
584 if (dco->ifmode == DCO_MODE_MP)
585 {
587 buf = &swap;
588 len = sizeof(swap);
589 }
590
591 DWORD bytes_returned = 0;
592 if (!DeviceIoControl(dco->tt->hand, ioctl, buf, len, NULL, 0, &bytes_returned, NULL))
593 {
594 msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SWAP_KEYS) failed");
595 return -1;
596 }
597 return 0;
598}
599
600bool
601dco_available(int msglevel)
602{
603 /* try to open device by symbolic name */
604 HANDLE h = CreateFile("\\\\.\\ovpn-dco", GENERIC_READ | GENERIC_WRITE,
605 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
606
607 if (h != INVALID_HANDLE_VALUE)
608 {
609 CloseHandle(h);
610 return true;
611 }
612
613 DWORD err = GetLastError();
614 if (err == ERROR_ACCESS_DENIED)
615 {
616 /* this likely means that device exists but is already in use,
617 * don't bail out since later we try to open all existing dco
618 * devices and then bail out if all devices are in use
619 */
620 return true;
621 }
622
623 msg(msglevel, "Note: ovpn-dco-win driver is missing, disabling data channel offload.");
624 return false;
625}
626
627const char *
629{
630 OVPN_VERSION version = {0};
631 if (dco_get_version(&version))
632 {
633 struct buffer out = alloc_buf_gc(256, gc);
634 buf_printf(&out, "%ld.%ld.%ld", version.Major, version.Minor, version.Patch);
635 return BSTR(&out);
636 }
637 else
638 {
639 return "N/A";
640 }
641}
642
654static void
656{
657 DWORD bytes_read = 0;
658 BOOL res = GetOverlappedResult(dco->tt->hand, &dco->ov, &bytes_read, FALSE);
659 if (res)
660 {
661 msg(D_DCO_DEBUG, "%s: completion%s success [%ld]", __func__, queued ? "" : " non-queued", bytes_read);
662
663 dco->dco_message_peer_id = dco->notif_buf.PeerId;
664 dco->dco_message_type = dco->notif_buf.Cmd;
665 dco->dco_del_peer_reason = dco->notif_buf.DelPeerReason;
666 }
667 else
668 {
669 msg(D_DCO_DEBUG | M_ERRNO, "%s: completion%s error", __func__, queued ? "" : " non-queued");
670 }
671}
672
673int
675{
676 if (dco->ifmode != DCO_MODE_MP)
677 {
678 ASSERT(false);
679 }
680
681 dco->dco_message_peer_id = -1;
682 dco->dco_message_type = 0;
683
684 switch (dco->iostate)
685 {
686 case IOSTATE_QUEUED:
688
689 ASSERT(ResetEvent(dco->ov.hEvent));
690 dco->iostate = IOSTATE_INITIAL;
691
692 break;
693
695 dco->iostate = IOSTATE_INITIAL;
696 ASSERT(ResetEvent(dco->ov.hEvent));
697
698 if (dco->ov_ret == ERROR_SUCCESS)
699 {
701 }
702 else
703 {
704 SetLastError(dco->ov_ret);
705 msg(D_DCO_DEBUG | M_ERRNO, "%s: completion non-queued error", __func__);
706 }
707
708 break;
709 }
710
711 return 0;
712}
713
714int
716 const bool raise_sigusr1_on_err)
717{
718 /* Not implemented. */
719 return 0;
720}
721
722int
724{
725 struct tuntap *tt = c->c1.tuntap;
726
727 if (!tuntap_defined(tt))
728 {
729 return -1;
730 }
731
732 OVPN_STATS stats;
733 ZeroMemory(&stats, sizeof(OVPN_STATS));
734
735 DWORD bytes_returned = 0;
736 if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_STATS, NULL, 0,
737 &stats, sizeof(stats), &bytes_returned, NULL))
738 {
739 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_GET_STATS) failed");
740 return -1;
741 }
742
747
748 return 0;
749}
750
751void
753{
754 if (dco->ifmode != DCO_MODE_MP)
755 {
756 /* mp only */
757 return;
758 }
759
760 event_ctl(es, &dco->rwhandle, EVENT_READ, arg);
761
762 if (dco->iostate == IOSTATE_INITIAL)
763 {
764 /* the overlapped IOCTL will signal this event on I/O completion */
765 ASSERT(ResetEvent(dco->ov.hEvent));
766
767 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_NOTIFY_EVENT, NULL, 0, &dco->notif_buf, sizeof(dco->notif_buf), NULL, &dco->ov))
768 {
769 DWORD err = GetLastError();
770 if (err == ERROR_IO_PENDING) /* operation queued? */
771 {
772 dco->iostate = IOSTATE_QUEUED;
773 dco->ov_ret = ERROR_SUCCESS;
774
775 msg(D_DCO_DEBUG, "%s: notify ioctl queued", __func__);
776 }
777 else
778 {
779 /* error occured */
780 ASSERT(SetEvent(dco->ov.hEvent));
781 dco->iostate = IOSTATE_IMMEDIATE_RETURN;
782 dco->ov_ret = err;
783
784 msg(D_DCO_DEBUG | M_ERRNO, "%s: notify ioctl error", __func__);
785 }
786 }
787 else
788 {
789 ASSERT(SetEvent(dco->ov.hEvent));
790 dco->iostate = IOSTATE_IMMEDIATE_RETURN;
791 dco->ov_ret = ERROR_SUCCESS;
792
793 msg(D_DCO_DEBUG, "%s: notify ioctl immediate return", __func__);
794 }
795 }
796}
797
798const char *
800{
801 /*
802 * this API can be called either from user mode or kernel mode,
803 * which enables us to probe driver's chachapoly support
804 * (available starting from Windows 11)
805 */
806
807 BCRYPT_ALG_HANDLE h;
808 NTSTATUS status = BCryptOpenAlgorithmProvider(&h, L"CHACHA20_POLY1305", NULL, 0);
809 if (BCRYPT_SUCCESS(status))
810 {
811 BCryptCloseAlgorithmProvider(h, 0);
812 return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
813 }
814 else
815 {
816 return "AES-128-GCM:AES-256-GCM:AES-192-GCM";
817 }
818}
819
820bool
822{
823 OVPN_VERSION ver = { 0 };
824 return dco_get_version(&ver) && ver.Major >= 2;
825}
826
827void
828dco_win_add_iroute_ipv4(dco_context_t *dco, in_addr_t dst, unsigned int netbits, unsigned int peer_id)
829{
830 struct gc_arena gc = gc_new();
831
832 OVPN_MP_IROUTE route = {.Addr.Addr4.S_un.S_addr = dst, .Netbits = netbits, .PeerId = peer_id, .IPv6 = 0};
833
834 msg(D_DCO_DEBUG, "%s: %s/%d -> peer %d", __func__, print_in_addr_t(dst, IA_NET_ORDER, &gc), netbits, peer_id);
835
836 DWORD bytes_returned = 0;
837 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_ADD_IROUTE, &route,
838 sizeof(route), NULL, 0, &bytes_returned, NULL))
839 {
840 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_ADD_IROUTE) failed");
841 }
842
843 gc_free(&gc);
844}
845
846void
847dco_win_add_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits, unsigned int peer_id)
848{
849 struct gc_arena gc = gc_new();
850
851 OVPN_MP_IROUTE route = { .Addr.Addr6 = dst, .Netbits = netbits, .PeerId = peer_id, .IPv6 = 1 };
852
853 msg(D_DCO_DEBUG, "%s: %s/%d -> peer %d", __func__, print_in6_addr(dst, IA_NET_ORDER, &gc), netbits, peer_id);
854
855 DWORD bytes_returned = 0;
856 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_ADD_IROUTE, &route,
857 sizeof(route), NULL, 0, &bytes_returned, NULL))
858 {
859 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_ADD_IROUTE) failed");
860 }
861
862 gc_free(&gc);
863}
864
865void
866dco_win_del_iroute_ipv4(dco_context_t *dco, in_addr_t dst, unsigned int netbits)
867{
868 struct gc_arena gc = gc_new();
869
870 OVPN_MP_IROUTE route = { .Addr.Addr4.S_un.S_addr = dst, .Netbits = netbits, .PeerId = -1, .IPv6 = 0 };
871
872 msg(D_DCO_DEBUG, "%s: %s/%d", __func__, print_in_addr_t(dst, IA_NET_ORDER, &gc), netbits);
873
874 DWORD bytes_returned = 0;
875 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_DEL_IROUTE, &route,
876 sizeof(route), NULL, 0, &bytes_returned, NULL))
877 {
878 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_DEL_IROUTE) failed");
879 }
880
881 gc_free(&gc);
882}
883
884void
885dco_win_del_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits)
886{
887 struct gc_arena gc = gc_new();
888
889 OVPN_MP_IROUTE route = { .Addr.Addr6 = dst, .Netbits = netbits, .PeerId = -1, .IPv6 = 1 };
890
891 msg(D_DCO_DEBUG, "%s: %s/%d", __func__, print_in6_addr(dst, IA_NET_ORDER, &gc), netbits);
892
893 DWORD bytes_returned = 0;
894 if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_MP_DEL_IROUTE, &route,
895 sizeof(route), NULL, 0, &bytes_returned, NULL))
896 {
897 msg(M_WARN | M_ERRNO, "DeviceIoControl(OVPN_IOCTL_MP_DEL_IROUTE) failed");
898 }
899
900 gc_free(&gc);
901}
902
903#endif /* defined(_WIN32) */
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define BSTR(buf)
Definition buffer.h:129
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
Data Channel Cryptography Module.
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:267
int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev)
Definition dco_win.c:212
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
Definition dco_win.c:566
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:280
int dco_del_peer(dco_context_t *dco, unsigned int peerid)
Definition dco_win.c:465
bool ovpn_dco_init(int mode, dco_context_t *dco, const char *dev_node)
Initializes DCO depends on mode
Definition dco_win.c:191
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:847
const char * dco_version_string(struct gc_arena *gc)
Definition dco_win.c:628
void dco_p2p_start_vpn(struct tuntap *tt)
Transitions the DCO adapter to the connected state in P2P mode.
Definition dco_win.c:166
const char * dco_get_supported_ciphers(void)
Definition dco_win.c:799
bool dco_available(int msglevel)
Definition dco_win.c:601
static void dco_connect_wait(HANDLE handle, OVERLAPPED *ov, int timeout, struct signal_info *sig_info)
Definition dco_win.c:219
void dco_win_del_iroute_ipv4(dco_context_t *dco, in_addr_t dst, unsigned int netbits)
Definition dco_win.c:866
bool dco_win_supports_multipeer(void)
Definition dco_win.c:821
void dco_win_del_iroute_ipv6(dco_context_t *dco, struct in6_addr dst, unsigned int netbits)
Definition dco_win.c:885
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:491
int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, const bool raise_sigusr1_on_err)
Definition dco_win.c:715
int dco_swap_keys(dco_context_t *dco, unsigned int peer_id)
Definition dco_win.c:575
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_do_read(dco_context_t *dco)
Definition dco_win.c:674
int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
Definition dco_win.c:723
int dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, struct sockaddr *localaddr, struct sockaddr *remoteaddr, struct in_addr *vpn_ipv4, struct in6_addr *vpn_ipv6)
Definition dco_win.c:414
void dco_p2p_new_peer(HANDLE handle, struct link_socket *sock, struct signal_info *sig_info)
Definition dco_win.c:324
static void dco_handle_overlapped_success(dco_context_t *dco, bool queued)
Handles successful completion of overlapped operation.
Definition dco_win.c:655
static bool dco_get_version(OVPN_VERSION *version)
Gets version of dco-win driver.
Definition dco_win.c:73
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:828
void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
Definition dco_win.c:752
int dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, dco_key_slot_t slot, const uint8_t *encrypt_key, const uint8_t *encrypt_iv, const uint8_t *decrypt_key, const uint8_t *decrypt_iv, const char *ciphername)
Definition dco_win.c:525
#define D_DCO
Definition errlevel.h:94
#define D_DCO_DEBUG
Definition errlevel.h:118
#define EVENT_READ
Definition event.h:39
static void event_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg)
Definition event.h:181
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
Definition forward.c:509
Interface functions to the internal and external multiplexers.
static SERVICE_STATUS status
Definition interactive.c:53
@ route
Definition interactive.c:87
void management_sleep(const int n)
A sleep function that services the management layer for n seconds rather than doing nothing.
Definition manage.c:4117
void * openvpn_net_ctx_t
Definition networking.h:39
#define CLEAR(x)
Definition basic.h:33
#define M_FATAL
Definition error.h:89
#define M_NONFATAL
Definition error.h:90
#define M_ERR
Definition error.h:105
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define M_ERRNO
Definition error.h:94
#define MODE_POINT_TO_POINT
Definition options.h:258
#define MODE_SERVER
Definition options.h:259
#define OVPN_SET_PEER
@ OVPN_MODE_MP
#define OVPN_IOCTL_GET_STATS
#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
#define OVPN_IOCTL_MP_SET_PEER
#define OVPN_IOCTL_MP_SWAP_KEYS
#define OVPN_IOCTL_SET_PEER
#define OVPN_IOCTL_NEW_PEER
#define OVPN_IOCTL_MP_ADD_IROUTE
#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
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:231
static void get_signal(volatile int *sig)
Copy the global signal_received (if non-zero) to the passed-in argument sig.
Definition sig.h:110
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2994
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2974
const char * addr_family_name(int af)
Definition socket.c:3233
#define SF_PREPEND_SA
Definition socket.h:227
#define IA_NET_ORDER
Definition socket.h:402
Control Channel Common Data Structures.
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::@15 Addr
SOCKADDR_IN6 Addr6
SOCKADDR_IN Addr4
union _OVPN_MP_NEW_PEER::@12 Local
union _OVPN_MP_NEW_PEER::@13 Remote
union _OVPN_MP_START_VPN::@14 ListenAddress
SOCKADDR_IN6 Addr6
union _OVPN_NEW_PEER::@10 Local
SOCKADDR_IN6 Addr6
union _OVPN_NEW_PEER::@11 Remote
SOCKADDR_IN Addr4
OVPN_PROTO Proto
LONG64 TunBytesSent
LONG64 TransportBytesSent
LONG64 TunBytesReceived
LONG64 TransportBytesReceived
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition openvpn.h:171
counter_type dco_read_bytes
Definition openvpn.h:267
counter_type tun_read_bytes
Definition openvpn.h:264
counter_type dco_write_bytes
Definition openvpn.h:270
counter_type tun_write_bytes
Definition openvpn.h:265
Contains all state information for one tunnel.
Definition openvpn.h:474
struct context_2 c2
Level 2 context.
Definition openvpn.h:514
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:117
Main OpenVPN server state structure.
Definition multi.h:163
volatile int signal_received
Definition sig.h:43
Definition tun.h:181
DWORD adapter_index
Definition tun.h:230
HANDLE hand
Definition tun.h:216
dco_context_t dco
Definition tun.h:249
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:155
void tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid, struct gc_arena *gc)
Definition tun.c:6565
static bool tuntap_defined(const struct tuntap *tt)
Definition tun.h:254
#define IOSTATE_IMMEDIATE_RETURN
Definition win32.h:205
#define IOSTATE_INITIAL
Definition win32.h:203
#define IOSTATE_QUEUED
Definition win32.h:204