OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tunutil.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// tun interface utilities for Windows
13
14#pragma once
15
16#include <openvpn/common/socktypes.hpp> // prevent winsock multiple def errors
17
18#include <windows.h>
19#include <winsock2.h> // for IPv6
20#include <winioctl.h>
21#include <iphlpapi.h>
22#include <ntddndis.h>
23#include <wininet.h>
24#include <ws2tcpip.h> // for IPv6
25#include <tlhelp32.h> // for impersonating as LocalSystem
26
27
28#include <setupapi.h>
29#include <devguid.h>
30#include <cfgmgr32.h>
31
32#ifdef __MINGW32__
33#include <ddk/ndisguid.h>
34#else
35#include <ndisguid.h>
36#endif
37
38#include <string>
39#include <vector>
40#include <sstream>
41#include <cstdint> // for std::uint32_t
42#include <memory>
43#include <new>
44
45#include <tap-windows.h>
46
57#include <openvpn/addr/ip.hpp>
58#include <openvpn/addr/ipv6.hpp>
60#include <openvpn/win/reg.hpp>
63#include <openvpn/win/cmd.hpp>
65
66namespace openvpn::TunWin {
73
74namespace Util {
75OPENVPN_EXCEPTION(tun_win_util);
76
77namespace {
78// from tap-windows.h
79const char ADAPTER[] = ADAPTER_KEY; // CONST GLOBAL
80const char NETWORK_CONNECTIONS[] = NETWORK_CONNECTIONS_KEY; // CONST GLOBAL
81
82// generally defined on cl command line
83const char COMPONENT_ID[] = OPENVPN_STRINGIZE(TAP_WIN_COMPONENT_ID); // CONST GLOBAL
84const char WINTUN_COMPONENT_ID[] = "wintun"; // CONST GLOBAL
85const char OVPNDCO_COMPONENT_ID[] = "ovpn-dco"; // CONST GLOBAL
86
87const char ROOT_COMPONENT_ID[] = "root\\" OPENVPN_STRINGIZE(TAP_WIN_COMPONENT_ID);
88const char ROOT_WINTUN_COMPONENT_ID[] = "root\\wintun";
89const char ROOT_OVPNDCO_COMPONENT_ID[] = "root\\ovpn-dco";
90
91const char OVPNDCO_DEV_INTERFACE_REF_STRING[] = "\\ovpn-dco";
92} // namespace
93
94using TapGuidLuid = std::pair<std::string, DWORD>;
95
96// Return a list of TAP device GUIDs installed on the system,
97// filtered by TAP_WIN_COMPONENT_ID.
98inline std::vector<TapGuidLuid> tap_guids(const Type tun_type)
99{
100 LONG status;
101 DWORD len;
102 DWORD data_type;
103
104 std::vector<TapGuidLuid> ret;
105
106 const char *component_id;
107 const char *root_component_id;
108
109 switch (tun_type)
110 {
111 case TapWindows6:
112 component_id = COMPONENT_ID;
113 root_component_id = ROOT_COMPONENT_ID;
114 break;
115 case Wintun:
116 component_id = WINTUN_COMPONENT_ID;
117 root_component_id = ROOT_WINTUN_COMPONENT_ID;
118 break;
119 case OvpnDco:
120 component_id = OVPNDCO_COMPONENT_ID;
121 root_component_id = ROOT_OVPNDCO_COMPONENT_ID;
122 break;
123 default:
124 OPENVPN_THROW(tun_win_util, "tap_guids: unsupported TAP type");
125 break;
126 }
127
128 Win::Reg::Key adapter_key;
129 status = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
130 ADAPTER,
131 0,
132 KEY_READ,
133 adapter_key.ref());
134 if (status != ERROR_SUCCESS)
135 {
136 const Win::Error err(status);
137 OPENVPN_THROW(tun_win_util, "tap_guids: error opening adapter registry key: " << ADAPTER << " : " << err.message());
138 }
139
140 for (int i = 0;; ++i)
141 {
142 char strbuf[256];
143 Win::Reg::Key unit_key;
144
145 len = sizeof(strbuf);
146 status = ::RegEnumKeyExA(adapter_key(),
147 i,
148 strbuf,
149 &len,
150 nullptr,
151 nullptr,
152 nullptr,
153 nullptr);
154 if (status == ERROR_NO_MORE_ITEMS)
155 break;
156 else if (status != ERROR_SUCCESS)
157 OPENVPN_THROW(tun_win_util, "tap_guids: error enumerating registry subkeys of key: " << ADAPTER);
158 strbuf[len] = '\0';
159
160 const std::string unit_string = std::string(ADAPTER)
161 + std::string("\\")
162 + std::string(strbuf);
163
164 status = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
165 unit_string.c_str(),
166 0,
167 KEY_READ,
168 unit_key.ref());
169
170 if (status != ERROR_SUCCESS)
171 continue;
172
173 len = sizeof(strbuf);
174 status = ::RegQueryValueExA(unit_key(),
175 "ComponentId",
176 nullptr,
177 &data_type,
178 (LPBYTE)strbuf,
179 &len);
180
181 if (status != ERROR_SUCCESS || data_type != REG_SZ)
182 continue;
183 strbuf[len] = '\0';
184 if (string::strcasecmp(strbuf, component_id)
185 && string::strcasecmp(strbuf, root_component_id))
186 continue;
187
188 TapGuidLuid tgl;
189
190 len = sizeof(strbuf);
191 status = ::RegQueryValueExA(unit_key(),
192 "NetCfgInstanceId",
193 nullptr,
194 &data_type,
195 (LPBYTE)strbuf,
196 &len);
197
198 if (status == ERROR_SUCCESS && data_type == REG_SZ)
199 {
200 strbuf[len] = '\0';
201 tgl.first = std::string(strbuf);
202 }
203
204 DWORD luid;
205 len = sizeof(luid);
206 status = ::RegQueryValueExA(unit_key(),
207 "NetLuidIndex",
208 nullptr,
209 &data_type,
210 (LPBYTE)&luid,
211 &len);
212
213 if (status == ERROR_SUCCESS && data_type == REG_DWORD)
214 {
215 tgl.second = luid;
216 }
217
218 ret.push_back(tgl);
219 }
220 return ret;
221}
222
224{
226 : index(DWORD(-1))
227 {
228 }
229
230 bool index_defined() const
231 {
232 return index != DWORD(-1);
233 }
234
235 std::string index_or_name() const
236 {
237 if (index_defined())
238 return to_string(index);
239 else if (!name.empty())
240 return '"' + name + '"';
241 else
242 OPENVPN_THROW(tun_win_util, "TapNameGuidPair: TAP interface " << guid << " has no name or interface index");
243 }
244
245 void reset()
246 {
247 name.clear();
248 guid.clear();
249 net_luid_index = DWORD(-1);
250 index = DWORD(-1);
251 }
252
253 std::string name;
254 std::string guid;
255 DWORD net_luid_index = DWORD(-1);
256 DWORD index = DWORD(-1);
257};
258
259struct TapNameGuidPairList : public std::vector<TapNameGuidPair>
260{
261 TapNameGuidPairList(const Type tun_type)
262 {
263 // first get the TAP guids
264 {
265 std::vector<TapGuidLuid> guids = tap_guids(tun_type);
266 for (auto i = guids.begin(); i != guids.end(); i++)
267 {
268 TapNameGuidPair pair;
269 pair.guid = i->first;
270 pair.net_luid_index = i->second;
271
272 // lookup adapter index
273 {
274 ULONG aindex;
275 const size_t len = 128;
276 wchar_t wbuf[len];
277 _snwprintf(wbuf, len, L"\\DEVICE\\TCPIP_%S", pair.guid.c_str());
278 wbuf[len - 1] = 0;
279 if (::GetAdapterIndex(wbuf, &aindex) == NO_ERROR)
280 pair.index = aindex;
281 }
282
283 push_back(pair);
284 }
285 }
286
287 // next, match up control panel interface names with GUIDs
288 {
289 LONG status;
290 DWORD len;
291 DWORD data_type;
292
293 Win::Reg::Key network_connections_key;
294 status = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
295 NETWORK_CONNECTIONS,
296 0,
297 KEY_READ,
298 network_connections_key.ref());
299 if (status != ERROR_SUCCESS)
300 {
301 const Win::Error err(status);
302 OPENVPN_THROW(tun_win_util, "TapNameGuidPairList: error opening network connections registry key: " << NETWORK_CONNECTIONS << " : " << err.message());
303 }
304
305 for (int i = 0;; ++i)
306 {
307 char strbuf[256];
308 Win::Reg::Key connection_key;
309
310 len = sizeof(strbuf);
311 status = ::RegEnumKeyExA(network_connections_key(),
312 i,
313 strbuf,
314 &len,
315 nullptr,
316 nullptr,
317 nullptr,
318 nullptr);
319 if (status == ERROR_NO_MORE_ITEMS)
320 break;
321 else if (status != ERROR_SUCCESS)
322 OPENVPN_THROW(tun_win_util, "TapNameGuidPairList: error enumerating registry subkeys of key: " << NETWORK_CONNECTIONS);
323 strbuf[len] = '\0';
324
325 const std::string guid = std::string(strbuf);
326 const std::string connection_string = std::string(NETWORK_CONNECTIONS) + std::string("\\") + guid + std::string("\\Connection");
327
328 status = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
329 connection_string.c_str(),
330 0,
331 KEY_READ,
332 connection_key.ref());
333 if (status != ERROR_SUCCESS)
334 continue;
335
336 wchar_t wbuf[256] = L"";
337 DWORD cbwbuf = sizeof(wbuf);
338 status = ::RegQueryValueExW(connection_key(),
339 L"Name",
340 nullptr,
341 &data_type,
342 (LPBYTE)wbuf,
343 &cbwbuf);
344 if (status != ERROR_SUCCESS || data_type != REG_SZ)
345 continue;
346 wbuf[(cbwbuf / sizeof(wchar_t)) - 1] = L'\0';
347
348 // iterate through self and try to patch the name
349 {
350 for (iterator j = begin(); j != end(); j++)
351 {
352 TapNameGuidPair &pair = *j;
353 if (pair.guid == guid)
354 pair.name = wstring::to_utf8(wbuf);
355 }
356 }
357 }
358 }
359 }
360
361 std::string to_string() const
362 {
363 std::ostringstream os;
364 for (const_iterator i = begin(); i != end(); i++)
365 {
366 const TapNameGuidPair &pair = *i;
367 os << "guid='" << pair.guid << '\'';
368 if (pair.index_defined())
369 os << " index=" << pair.index;
370 if (!pair.name.empty())
371 os << " name='" << pair.name << '\'';
372 os << "\n";
373 }
374 return os.str();
375 }
376
377 std::string name_from_guid(const std::string &guid) const
378 {
379 for (const_iterator i = begin(); i != end(); i++)
380 {
381 const TapNameGuidPair &pair = *i;
382 if (pair.guid == guid)
383 return pair.name;
384 }
385 throw std::range_error{"guid not found"};
386 }
387
388 std::string guid_from_name(const std::string &name) const
389 {
390 for (const_iterator i = begin(); i != end(); i++)
391 {
392 const TapNameGuidPair &pair = *i;
393 if (pair.name == name)
394 return pair.guid;
395 }
396 throw std::range_error{"name not found"};
397 }
398};
399
405
407{
408 public:
410 {
411 handle = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
412 }
413
414 bool is_valid()
415 {
416 return handle != INVALID_HANDLE_VALUE;
417 }
418
419 operator HDEVINFO()
420 {
421 return handle;
422 }
423
425 {
426 if (is_valid())
427 {
428 SetupDiDestroyDeviceInfoList(handle);
429 }
430 }
431
432 private:
433 HDEVINFO handle;
434};
435
436struct DeviceInstanceIdInterfaceList : public std::vector<DeviceInstanceIdInterfacePair>
437{
439 {
440 DevInfoSetHelper device_info_set;
441 if (!device_info_set.is_valid())
442 return;
443
444 for (DWORD i = 0;; ++i)
445 {
446 SP_DEVINFO_DATA dev_info_data;
447 ZeroMemory(&dev_info_data, sizeof(SP_DEVINFO_DATA));
448 dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
449 BOOL res = SetupDiEnumDeviceInfo(device_info_set, i, &dev_info_data);
450 if (!res)
451 {
452 if (GetLastError() == ERROR_NO_MORE_ITEMS)
453 break;
454 else
455 continue;
456 }
457
458 Win::Reg::Key regkey;
459 *regkey.ref() = SetupDiOpenDevRegKey(device_info_set, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
460 if (!regkey.defined())
461 continue;
462
463 std::string str_net_cfg_instance_id;
464
465 DWORD size;
466 LONG status = RegQueryValueExA(regkey(), "NetCfgInstanceId", NULL, NULL, NULL, &size);
467 if (status != ERROR_SUCCESS)
468 continue;
470
471 status = RegQueryValueExA(regkey(), "NetCfgInstanceId", NULL, NULL, (LPBYTE)buf_net_cfg_inst_id.data(), &size);
472 if (status == ERROR_SUCCESS)
473 {
474 buf_net_cfg_inst_id.data()[size - 1] = '\0';
475 str_net_cfg_instance_id = std::string(buf_net_cfg_inst_id.data());
476 }
477 else
478 continue;
479
480 res = SetupDiGetDeviceInstanceId(device_info_set, &dev_info_data, NULL, 0, &size);
481 if (res != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
482 continue;
483
485 if (!SetupDiGetDeviceInstanceId(device_info_set, &dev_info_data, buf_dev_inst_id.data(), size, &size))
486 continue;
487 buf_dev_inst_id.set_size(size);
488
489 ULONG dev_interface_list_size = 0;
490 CONFIGRET cr = CM_Get_Device_Interface_List_Size(&dev_interface_list_size,
491 (LPGUID)&GUID_DEVINTERFACE_NET,
492 buf_dev_inst_id.data(),
493 CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
494
495 if (cr != CR_SUCCESS)
496 continue;
497
498 BufferAllocatedType<char> buf_dev_iface_list(dev_interface_list_size, BufAllocFlags::CONSTRUCT_ZERO);
499 cr = CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_NET,
500 buf_dev_inst_id.data(),
501 buf_dev_iface_list.data(),
502 dev_interface_list_size,
503 CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
504 if (cr != CR_SUCCESS)
505 continue;
506
507 char *dev_if = buf_dev_iface_list.data();
508 while (strlen(dev_if) > 0)
509 {
511 pair.net_cfg_instance_id = str_net_cfg_instance_id;
512 pair.device_interface = std::string(dev_if);
513 push_back(pair);
514
515 dev_if += strlen(dev_if) + 1;
516 }
517 }
518 }
519};
520
521// given a TAP GUID, form the pathname of the TAP device node
522inline std::string tap_path(const TapNameGuidPair &tap)
523{
524 return std::string(USERMODEDEVICEDIR) + tap.guid + std::string(TAP_WIN_SUFFIX);
525}
526
527// open an available TAP adapter
528inline HANDLE tap_open(const Type tun_type,
529 const TapNameGuidPairList &guids,
530 std::string &path_opened,
531 TapNameGuidPair &used)
532{
534
535 std::unique_ptr<DeviceInstanceIdInterfaceList> inst_id_interface_list;
536 if (tun_type != TapWindows6)
537 inst_id_interface_list.reset(new DeviceInstanceIdInterfaceList());
538
539 // iterate over list of TAP adapters on system
540 for (TapNameGuidPairList::const_iterator i = guids.begin(); i != guids.end(); i++)
541 {
542 const TapNameGuidPair &tap = *i;
543
544 std::string path;
545
546 if (tun_type != TapWindows6)
547 {
548 for (const auto &inst_id_interface : *inst_id_interface_list)
549 {
550 if (inst_id_interface.net_cfg_instance_id != tap.guid)
551 continue;
552
553 if (tun_type == OvpnDco)
554 {
555 if (!inst_id_interface.device_interface.ends_with(OVPNDCO_DEV_INTERFACE_REF_STRING))
556 continue;
557 }
558 path = inst_id_interface.device_interface;
559 break;
560 }
561 }
562 else
563 {
564 path = tap_path(tap);
565 }
566
567 if (path.length() > 0)
568 {
569 hand.reset(::CreateFileA(path.c_str(),
570 GENERIC_READ | GENERIC_WRITE,
571 0, /* was: FILE_SHARE_READ */
572 0,
573 OPEN_EXISTING,
574 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
575 0));
576
577 if (hand.defined())
578 {
579 used = tap;
580 path_opened = path;
581 break;
582 }
583 }
584 }
585 return hand.release();
586}
587
588// set TAP adapter to topology subnet
589inline void tap_configure_topology_subnet(HANDLE th, const IP::Addr &local, const unsigned int prefix_len)
590{
592 const IPv4::Addr network = local.to_ipv4() & netmask;
593
594 std::uint32_t ep[3];
595 ep[0] = htonl(local.to_ipv4().to_uint32());
596 ep[1] = htonl(network.to_uint32());
597 ep[2] = htonl(netmask.to_uint32());
598
599 DWORD len;
600 if (!::DeviceIoControl(th,
601 TAP_WIN_IOCTL_CONFIG_TUN,
602 ep,
603 sizeof(ep),
604 ep,
605 sizeof(ep),
606 &len,
607 nullptr))
608 {
609 throw tun_win_util("DeviceIoControl TAP_WIN_IOCTL_CONFIG_TUN failed");
610 }
611}
612
613// set TAP adapter to topology net30
614inline void tap_configure_topology_net30(HANDLE th, const IP::Addr &local_addr, const IP::Addr &remote_addr)
615{
616 const IPv4::Addr local = local_addr.to_ipv4();
617 const IPv4::Addr remote = remote_addr.to_ipv4();
618
619 std::uint32_t ep[2];
620 ep[0] = htonl(local.to_uint32());
621 ep[1] = htonl(remote.to_uint32());
622
623 DWORD len;
624 if (!::DeviceIoControl(th,
625 TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT,
626 ep,
627 sizeof(ep),
628 ep,
629 sizeof(ep),
630 &len,
631 nullptr))
632 {
633 throw tun_win_util("DeviceIoControl TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT failed");
634 }
635}
636
637// set driver media status to 'connected'
638inline void tap_set_media_status(HANDLE th, bool media_status)
639{
640 DWORD len;
641 ULONG status = media_status ? TRUE : FALSE;
642 if (!::DeviceIoControl(th,
643 TAP_WIN_IOCTL_SET_MEDIA_STATUS,
644 &status,
645 sizeof(status),
646 &status,
647 sizeof(status),
648 &len,
649 nullptr))
650 {
651 throw tun_win_util("DeviceIoControl TAP_WIN_IOCTL_SET_MEDIA_STATUS failed");
652 }
653}
654
655// get debug logging from TAP driver (requires that
656// TAP driver was built with logging enabled)
657inline void tap_process_logging(HANDLE th)
658{
659 const size_t size = 1024;
660 std::unique_ptr<char[]> line(new char[size]);
661 DWORD len;
662
663 while (::DeviceIoControl(th,
664 TAP_WIN_IOCTL_GET_LOG_LINE,
665 line.get(),
666 size,
667 line.get(),
668 size,
669 &len,
670 nullptr))
671 {
672 OPENVPN_LOG("TAP-Windows: " << line.get());
673 }
674}
675
677{
678 public:
680 {
681 DWORD size = 0;
682 if (::GetInterfaceInfo(nullptr, &size) != ERROR_INSUFFICIENT_BUFFER)
683 OPENVPN_THROW(tun_win_util, "InterfaceInfoList: GetInterfaceInfo #1");
684 list.reset((IP_INTERFACE_INFO *)::operator new(size));
685 if (::GetInterfaceInfo(list.get(), &size) != NO_ERROR)
686 OPENVPN_THROW(tun_win_util, "InterfaceInfoList: GetInterfaceInfo #2");
687 }
688
689 IP_ADAPTER_INDEX_MAP *iface(const DWORD index) const
690 {
691 if (list)
692 {
693 for (LONG i = 0; i < list->NumAdapters; ++i)
694 {
695 IP_ADAPTER_INDEX_MAP *inter = &list->Adapter[i];
696 if (index == inter->Index)
697 return inter;
698 }
699 }
700 return nullptr;
701 }
702
704};
705
706inline void dhcp_release(const InterfaceInfoList &ii,
707 const DWORD adapter_index,
708 std::ostream &os)
709{
710 IP_ADAPTER_INDEX_MAP *iface = ii.iface(adapter_index);
711 if (iface)
712 {
713 const DWORD status = ::IpReleaseAddress(iface);
714 if (status == NO_ERROR)
715 os << "TAP: DHCP release succeeded\n";
716 else
717 os << "TAP: DHCP release failed\n";
718 }
719}
720
721inline void dhcp_renew(const InterfaceInfoList &ii,
722 const DWORD adapter_index,
723 std::ostream &os)
724{
725 IP_ADAPTER_INDEX_MAP *iface = ii.iface(adapter_index);
726 if (iface)
727 {
728 const DWORD status = ::IpRenewAddress(iface);
729 if (status == NO_ERROR)
730 os << "TAP: DHCP renew succeeded\n";
731 else
732 os << "TAP: DHCP renew failed\n";
733 }
734}
735
736inline void flush_arp(const DWORD adapter_index,
737 std::ostream &os)
738{
739 const DWORD status = ::FlushIpNetTable2(AF_INET, adapter_index);
740 if (status == NO_ERROR)
741 os << "TAP: ARP flush succeeded\n";
742 else
743 os << "TAP: ARP flush failed\n";
744}
745
747{
748 IPNetmask4() = default;
749
750 IPNetmask4(const TunBuilderCapture &pull, const char *title)
751 {
752 const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
753 if (local4)
754 {
755 ip = IPv4::Addr::from_string(local4->address, title);
757 }
758 }
759
760 IPNetmask4(const IP_ADDR_STRING *ias)
761 {
762 if (ias)
763 {
764 try
765 {
766 ip = IPv4::Addr::from_string(ias->IpAddress.String);
767 }
768 catch (const std::exception &)
769 {
770 }
771 try
772 {
773 netmask = IPv4::Addr::from_string(ias->IpMask.String);
774 }
775 catch (const std::exception &)
776 {
777 }
778 }
779 }
780
781 bool operator==(const IPNetmask4 &rhs) const
782 {
783 return ip == rhs.ip && netmask == rhs.netmask;
784 }
785
786 bool operator!=(const IPNetmask4 &rhs) const
787 {
788 return !operator==(rhs);
789 }
790
793};
794
796{
798 {
799 ULONG size = 0;
800 if (::GetAdaptersInfo(nullptr, &size) != ERROR_BUFFER_OVERFLOW)
801 OPENVPN_THROW(tun_win_util, "IPAdaptersInfo: GetAdaptersInfo #1");
802 list.reset((IP_ADAPTER_INFO *)::operator new(size));
803 if (::GetAdaptersInfo(list.get(), &size) != NO_ERROR)
804 OPENVPN_THROW(tun_win_util, "IPAdaptersInfo: GetAdaptersInfo #2");
805 }
806
807 const IP_ADAPTER_INFO *adapter(const DWORD index) const
808 {
809 if (list)
810 {
811 for (const IP_ADAPTER_INFO *a = list.get(); a != nullptr; a = a->Next)
812 {
813 if (index == a->Index)
814 return a;
815 }
816 }
817 return nullptr;
818 }
819
820 bool is_up(const DWORD index, const IPNetmask4 &vpn_addr) const
821 {
822 const IP_ADAPTER_INFO *ai = adapter(index);
823 if (ai)
824 {
825 for (const IP_ADDR_STRING *iplist = &ai->IpAddressList; iplist != nullptr; iplist = iplist->Next)
826 {
827 if (vpn_addr == IPNetmask4(iplist))
828 return true;
829 }
830 }
831 return false;
832 }
833
834 bool is_dhcp_enabled(const DWORD index) const
835 {
836 const IP_ADAPTER_INFO *ai = adapter(index);
837 return ai && ai->DhcpEnabled;
838 }
839
841};
842
844{
845 IPPerAdapterInfo(const DWORD index)
846 {
847 ULONG size = 0;
848 if (::GetPerAdapterInfo(index, nullptr, &size) != ERROR_BUFFER_OVERFLOW)
849 return;
850 adapt.reset((IP_PER_ADAPTER_INFO *)::operator new(size));
851 if (::GetPerAdapterInfo(index, adapt.get(), &size) != ERROR_SUCCESS)
852 adapt.reset();
853 }
854
856};
857
859{
860 public:
862 : defined(false)
863 {
864 DWORD len;
865 info[0] = info[1] = info[2] = 0;
866 if (::DeviceIoControl(th,
867 TAP_WIN_IOCTL_GET_VERSION,
868 &info,
869 sizeof(info),
870 &info,
871 sizeof(info),
872 &len,
873 nullptr))
874 {
875 defined = true;
876 }
877 }
878
879 std::string to_string()
880 {
881 std::ostringstream os;
882 os << "TAP-Windows Driver Version ";
883 if (defined)
884 {
885 os << info[0] << '.' << info[1];
886 if (info[2])
887 os << " (DEBUG)";
888 }
889 else
890 os << "UNDEFINED";
891 return os.str();
892 }
893
894 private:
896 ULONG info[3];
897};
898
899// An action to set the DNS "Connection-specific DNS Suffix"
901{
902 public:
903 ActionSetAdapterDomainSuffix(const std::string &search_domain_arg,
904 const std::string &tap_guid_arg)
905 : search_domain(search_domain_arg),
906 tap_guid(tap_guid_arg)
907 {
908 }
909
910 void execute(std::ostream &os) override
911 {
912 os << to_string() << "\n";
913
914 LONG status;
915 Win::Reg::Key key;
916 const std::string reg_key_name = "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\" + tap_guid;
917 status = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
918 reg_key_name.c_str(),
919 0,
920 KEY_READ | KEY_WRITE,
921 key.ref());
922 if (status != ERROR_SUCCESS)
923 {
924 const Win::Error err(status);
925 OPENVPN_THROW(tun_win_util, "ActionSetAdapterDomainSuffix: error opening registry key: " << reg_key_name << " : " << err.message());
926 }
927
929 status = ::RegSetValueExW(key(),
930 L"Domain",
931 0,
932 REG_SZ,
933 reinterpret_cast<const BYTE *>(dom.get()),
934 static_cast<DWORD>((Win::utf16_strlen(dom.get()) + 1) * sizeof(wchar_t)));
935 if (status != ERROR_SUCCESS)
936 OPENVPN_THROW(tun_win_util, "ActionSetAdapterDomainSuffix: error writing Domain registry key: " << reg_key_name);
937 }
938
939 std::string to_string() const override
940 {
941 return "Set adapter domain suffix: '" + search_domain + "' " + tap_guid;
942 }
943
944 private:
945 const std::string search_domain;
946 const std::string tap_guid;
947};
948
949// get the Windows IPv4 routing table
950inline const MIB_IPFORWARDTABLE *windows_routing_table()
951{
952 ULONG size = 0;
953 DWORD status;
955
956 status = ::GetIpForwardTable(nullptr, &size, TRUE);
957 if (status == ERROR_INSUFFICIENT_BUFFER)
958 {
959 rt.reset((MIB_IPFORWARDTABLE *)::operator new(size));
960 status = ::GetIpForwardTable(rt.get(), &size, TRUE);
961 if (status != NO_ERROR)
962 {
963 OPENVPN_LOG("windows_routing_table: GetIpForwardTable failed");
964 return nullptr;
965 }
966 }
967 return rt.release();
968}
969
970// Get the Windows IPv4/IPv6 routing table.
971// Note that returned pointer must be freed with FreeMibTable.
972inline const MIB_IPFORWARD_TABLE2 *windows_routing_table2(ADDRESS_FAMILY af)
973{
974 MIB_IPFORWARD_TABLE2 *routes = nullptr;
975 int res = ::GetIpForwardTable2(af, &routes);
976 if (res == NO_ERROR)
977 return routes;
978 else
979 return nullptr;
980}
981
983{
984 public:
988 BestGateway(ADDRESS_FAMILY af)
989 {
991 [](const MIB_IPFORWARD_TABLE2 *p)
992 { FreeMibTable((PVOID)p); });
993
994 if (!rt2)
995 {
996 OPENVPN_THROW(tun_win_util, "Failed to get routing table");
997 }
998
999 std::map<NET_IFINDEX, ULONG> metric_per_iface;
1000 ULONG gw_metric = 0;
1001
1002 const MIB_IPFORWARD_ROW2 *gw = nullptr;
1003 for (size_t i = 0; i < rt2->NumEntries; ++i)
1004 {
1005 const MIB_IPFORWARD_ROW2 *row = &rt2->Table[i];
1006
1007 IP::Addr dst = IP::Addr::from_sockaddr((const sockaddr *)&row->DestinationPrefix.Prefix);
1008 bool default_gw = dst.all_zeros() && row->DestinationPrefix.PrefixLength == 0;
1009
1010 ULONG metric = row->Metric + get_iface_metric(metric_per_iface, row->InterfaceIndex, af);
1011
1012 if (default_gw && (!gw || metric < gw_metric))
1013 {
1014 gw = row;
1015 gw_metric = metric;
1016 }
1017 }
1018 if (gw)
1019 {
1020 index = gw->InterfaceIndex;
1021 if (af == AF_INET6)
1022 {
1023 addr = IPv6::Addr::from_in6_addr(&gw->NextHop.Ipv6.sin6_addr).to_string();
1024 }
1025 else
1026 {
1027 addr = IPv4::Addr::from_in_addr(&gw->NextHop.Ipv4.sin_addr).to_string();
1028 }
1029 }
1030 }
1031
1042 BestGateway(ADDRESS_FAMILY af, const std::string &dest_str, DWORD vpn_interface_index)
1043 {
1045 [](const MIB_IPFORWARD_TABLE2 *p)
1046 { FreeMibTable((PVOID)p); });
1047
1048 if (!rt2)
1049 {
1050 OPENVPN_THROW(tun_win_util, "Failed to get routing table");
1051 }
1052
1053 IP::Addr dest = IP::Addr::from_string(dest_str);
1054
1055 void *dst_addr = NULL;
1056 struct sockaddr_in sa4;
1057 struct sockaddr_in6 sa6;
1058 if (af == AF_INET6)
1059 {
1060 sa6 = dest.to_ipv6().to_sockaddr();
1061 dst_addr = &sa6;
1062 }
1063 else
1064 {
1065 sa4 = dest.to_ipv4().to_sockaddr();
1066 dst_addr = &sa4;
1067 }
1068
1069 NET_IFINDEX best_interface = 0;
1070 DWORD res = ::GetBestInterfaceEx((sockaddr *)dst_addr, &best_interface);
1071 if (res != NO_ERROR)
1072 {
1073 OPENVPN_THROW(tun_win_util,
1074 "GetBestInterfaceEx: error retrieving the best interface for " << dest
1075 << ": " << res);
1076 }
1077
1078 // check if route is local
1079 MIB_IPFORWARD_ROW2 row{};
1080 SOCKADDR_INET best_source{};
1081 res = ::GetBestRoute2(NULL, best_interface, NULL, (const SOCKADDR_INET *)dst_addr, 0, &row, &best_source);
1082 if (res != NO_ERROR)
1083 {
1084 OPENVPN_THROW(tun_win_util,
1085 "GetBestGateway: error retrieving the best route for " << dest
1086 << ": " << res);
1087 }
1088
1089 // no gw needed, route is local
1090 if (row.Protocol == RouteProtocolLocal)
1091 {
1092 local_route_ = true;
1093 return;
1094 }
1095
1096 // if there is no VPN interface - we're done
1097 if (vpn_interface_index == DWORD(-1))
1098 {
1099 fill_gw_details(&row, dest_str);
1100 return;
1101 }
1102
1103 // find the best route excluding VPN interface
1104 const MIB_IPFORWARD_ROW2 *gw = nullptr;
1105 std::map<NET_IFINDEX, ULONG> metric_per_iface;
1106 ULONG gw_metric = 0;
1107 for (size_t i = 0; i < rt2->NumEntries; ++i)
1108 {
1109 const MIB_IPFORWARD_ROW2 *row = &rt2->Table[i];
1110 IP::Addr mask = IP::Addr::netmask_from_prefix_len(af == AF_INET6 ? IP::Addr::Version::V6 : IP::Addr::Version::V4, row->DestinationPrefix.PrefixLength);
1111
1112 IP::Addr dest_prefix = IP::Addr::from_sockaddr((const sockaddr *)&row->DestinationPrefix.Prefix);
1113
1114 if ((dest & mask) == dest_prefix)
1115 {
1116 // skip gateway on VPN interface
1117 if ((vpn_interface_index != DWORD(-1)) && (row->InterfaceIndex == vpn_interface_index))
1118 {
1119 OPENVPN_LOG("GetBestGateway: skip gateway "
1120 << IP::Addr::from_sockaddr((const sockaddr *)&row->NextHop).to_string()
1121 << " on VPN interface " << vpn_interface_index);
1122 continue;
1123 }
1124
1125 if (!gw)
1126 {
1127 gw = row;
1128 continue;
1129 }
1130
1131 ULONG metric = row->Metric + get_iface_metric(metric_per_iface, row->InterfaceIndex, af);
1132
1133 // use new gateway if it has longer prefix OR the same prefix but lower metric
1134 if ((row->DestinationPrefix.PrefixLength > gw->DestinationPrefix.PrefixLength) || ((row->DestinationPrefix.PrefixLength == gw->DestinationPrefix.PrefixLength) && (metric < gw_metric)))
1135 {
1136 gw = row;
1137 gw_metric = metric;
1138 }
1139 }
1140 }
1141
1142 if (gw)
1143 {
1144 fill_gw_details(gw, dest_str);
1145 }
1146 }
1147
1148 bool defined() const
1149 {
1150 return index != DWORD(-1) && !addr.empty();
1151 }
1152
1153 DWORD interface_index() const
1154 {
1155 return index;
1156 }
1157
1158 const std::string &gateway_address() const
1159 {
1160 return addr;
1161 }
1162
1167 bool local_route() const
1168 {
1169 return local_route_;
1170 }
1171
1172 private:
1173 void fill_gw_details(const MIB_IPFORWARD_ROW2 *row, const std::string &dest)
1174 {
1175 index = row->InterfaceIndex;
1176 addr = IP::Addr::from_sockaddr((const sockaddr *)&row->NextHop).to_string();
1177 OPENVPN_LOG("GetBestGateway: "
1178 << "selected gateway " << addr
1179 << " on adapter " << index
1180 << " for destination " << dest);
1181 }
1182
1183 static ULONG get_iface_metric(std::map<NET_IFINDEX, ULONG> &metric_per_iface, NET_IFINDEX iface, ADDRESS_FAMILY af)
1184 {
1185 if (!metric_per_iface.contains(iface))
1186 {
1187 MIB_IPINTERFACE_ROW ir{};
1188 ir.InterfaceIndex = iface;
1189 ir.Family = af;
1190 ::GetIpInterfaceEntry(&ir);
1191 metric_per_iface[iface] = ir.Metric;
1192 }
1193 return metric_per_iface[iface];
1194 }
1195
1196 DWORD index = -1;
1197 std::string addr;
1198 bool local_route_ = false;
1199};
1200
1201// An action to delete all routes on an interface
1203{
1204 public:
1205 ActionDeleteAllRoutesOnInterface(const DWORD iface_index_arg)
1206 : iface_index(iface_index_arg)
1207 {
1208 }
1209
1210 void execute(std::ostream &os) override
1211 {
1212 os << to_string() << "\n";
1213
1214 ActionList::Ptr actions = new ActionList();
1217 actions->execute(os);
1218 }
1219
1220 std::string to_string() const override
1221 {
1222 return "ActionDeleteAllRoutesOnInterface iface_index=" + std::to_string(iface_index);
1223 }
1224
1225 private:
1226 static void remove_all_ipv4_routes_on_iface(DWORD index, ActionList &actions)
1227 {
1228 std::unique_ptr<const MIB_IPFORWARDTABLE> rt(windows_routing_table());
1229 if (rt)
1230 {
1231 for (size_t i = 0; i < rt->dwNumEntries; ++i)
1232 {
1233 const MIB_IPFORWARDROW *row = &rt->table[i];
1234 if (row->dwForwardIfIndex == index)
1235 {
1236 const IPv4::Addr net = IPv4::Addr::from_uint32(ntohl(row->dwForwardDest));
1237 const IPv4::Addr mask = IPv4::Addr::from_uint32(ntohl(row->dwForwardMask));
1238 const std::string net_str = net.to_string();
1239 const unsigned int pl = mask.prefix_len();
1240
1241 // don't remove multicast route or other Windows-assigned routes
1242 if (net_str == "224.0.0.0" && pl == 4)
1243 continue;
1244 if (net_str == "255.255.255.255" && pl == 32)
1245 continue;
1246
1247 actions.add(new WinCmd("netsh interface ip delete route " + net_str + '/' + openvpn::to_string(pl) + ' ' + openvpn::to_string(index) + " store=active"));
1248 }
1249 }
1250 }
1251 }
1252
1253 static void remove_all_ipv6_routes_on_iface(DWORD index, ActionList &actions)
1254 {
1256 [](const MIB_IPFORWARD_TABLE2 *p)
1257 { FreeMibTable((PVOID)p); });
1258 if (rt2)
1259 {
1260 const IPv6::Addr ll_net = IPv6::Addr::from_string("fe80::");
1262 for (size_t i = 0; i < rt2->NumEntries; ++i)
1263 {
1264 const MIB_IPFORWARD_ROW2 *row = &rt2->Table[i];
1265 if (row->InterfaceIndex == index)
1266 {
1267 const unsigned int pl = row->DestinationPrefix.PrefixLength;
1268 if (row->DestinationPrefix.Prefix.si_family == AF_INET6)
1269 {
1270 const IPv6::Addr net = IPv6::Addr::from_byte_string(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte);
1271 const std::string net_str = net.to_string();
1272
1273 // don't remove multicast route or other Windows-assigned routes
1274 if (net_str == "ff00::" && pl == 8)
1275 continue;
1276 if ((net & ll_mask) == ll_net && pl >= 64)
1277 continue;
1278 actions.add(new WinCmd("netsh interface ipv6 delete route " + net_str + '/' + openvpn::to_string(pl) + ' ' + openvpn::to_string(index) + " store=active"));
1279 }
1280 }
1281 }
1282 }
1283 }
1284
1285 const DWORD iface_index;
1286};
1287
1289{
1290 public:
1292 : WinCmd(cmd(tap))
1293 {
1294 }
1295
1296 private:
1297 static std::string cmd(const TapNameGuidPair &tap)
1298 {
1299 return "netsh interface ip set address " + tap.index_or_name() + " dhcp";
1300 }
1301};
1302
1303namespace TunNETSH {
1304class AddRoute4Cmd : public Action
1305{
1306 public:
1308
1309 AddRoute4Cmd(const std::string &route_address,
1310 int prefix_length,
1311 DWORD iface_index,
1312 const std::string &iface_name,
1313 const std::string &gw_address,
1314 int metric,
1315 bool add)
1316 {
1317 std::ostringstream os;
1318 os << "netsh interface ip ";
1319 if (add)
1320 os << "add ";
1321 else
1322 os << "delete ";
1323 os << "route " << route_address << "/" << std::to_string(prefix_length) << " ";
1324 if (iface_index != DWORD(-1))
1325 os << iface_index;
1326 else
1327 os << iface_name;
1328 os << " " << gw_address << " ";
1329 if (add && metric >= 0)
1330 os << "metric=" << std::to_string(metric) << " ";
1331 os << "store=active";
1332 cmd.reset(new WinCmd(os.str()));
1333 };
1334
1335 void execute(std::ostream &os) override
1336 {
1337 cmd->execute(os);
1338 }
1339
1340 std::string to_string() const override
1341 {
1342 return cmd->to_string();
1343 }
1344
1345 private:
1347};
1348} // namespace TunNETSH
1349
1350namespace TunIPHELPER {
1351static SOCKADDR_INET sockaddr_inet(short family, const std::string &addr)
1352{
1353 SOCKADDR_INET sa;
1354 ZeroMemory(&sa, sizeof(sa));
1355 sa.si_family = family;
1356 inet_pton(family, addr.c_str(), family == AF_INET ? &(sa.Ipv4.sin_addr) : (PVOID) & (sa.Ipv6.sin6_addr));
1357 return sa;
1358}
1359
1360static DWORD InterfaceLuid(const std::string &iface_name, PNET_LUID luid)
1361{
1362 auto wide_name = wstring::from_utf8(iface_name);
1363 return ConvertInterfaceAliasToLuid(wide_name.c_str(), luid);
1364}
1365
1366class AddRoute4Cmd : public Action
1367{
1368 public:
1370
1371 AddRoute4Cmd(const std::string &route_address,
1372 int prefix_length,
1373 DWORD iface_index,
1374 const std::string &iface_name,
1375 const std::string &gw_address,
1376 int metric,
1377 bool add)
1378 : add(add)
1379 {
1380 os_ << "IPHelper: ";
1381 if (add)
1382 os_ << "add ";
1383 else
1384 os_ << "delete ";
1385 os_ << "route " << route_address << "/" << std::to_string(prefix_length) << " ";
1386 if (iface_index != DWORD(-1))
1387 os_ << iface_index;
1388 else
1389 os_ << iface_name;
1390 os_ << " " << gw_address << " metric=" << std::to_string(metric);
1391
1392 ZeroMemory(&fwd_row, sizeof(fwd_row));
1393 fwd_row.ValidLifetime = 0xffffffff;
1394 fwd_row.PreferredLifetime = 0xffffffff;
1395 fwd_row.Protocol = (NL_ROUTE_PROTOCOL)MIB_IPPROTO_NETMGMT;
1396 fwd_row.Metric = metric;
1397 fwd_row.DestinationPrefix.Prefix = sockaddr_inet(AF_INET, route_address);
1398 fwd_row.DestinationPrefix.PrefixLength = prefix_length;
1399 fwd_row.NextHop = sockaddr_inet(AF_INET, gw_address);
1400
1401 if (iface_index != DWORD(-1))
1402 fwd_row.InterfaceIndex = iface_index;
1403 else if (!iface_name.empty())
1404 {
1405 NET_LUID luid;
1406 auto err = InterfaceLuid(iface_name, &luid);
1407 if (err)
1408 OPENVPN_THROW(tun_win_util, "Cannot convert interface name " << iface_name << " to LUID");
1409 fwd_row.InterfaceLuid = luid;
1410 }
1411 };
1412
1413 void execute(std::ostream &os) override
1414 {
1415 os << os_.str() << "\n";
1416 DWORD res;
1417 if (add)
1418 res = CreateIpForwardEntry2(&fwd_row);
1419 else
1420 res = DeleteIpForwardEntry2(&fwd_row);
1421 if (res)
1422 os << "cannot modify route: error " << res << "\n";
1423 }
1424
1425 std::string to_string() const override
1426 {
1427 return os_.str();
1428 }
1429
1430 private:
1431 MIB_IPFORWARD_ROW2 fwd_row;
1432 bool add;
1433 std::ostringstream os_;
1434};
1435} // namespace TunIPHELPER
1436} // namespace Util
1437} // namespace openvpn::TunWin
void add(Action *action)
Definition action.hpp:57
virtual std::unordered_set< std::string > execute(std::ostream &os)
Executes a sequence of actions and returns marks of failed actions.
Definition action.hpp:98
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1447
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1381
static Addr from_string(const std::string &ipstr, const TITLE &title, const Version required_version)
Definition ip.hpp:105
static Addr from_sockaddr(const struct sockaddr *sa)
Definition ip.hpp:326
std::string to_string() const
Definition ip.hpp:528
bool all_zeros() const
Definition ip.hpp:816
const IPv4::Addr & to_ipv4() const
Definition ip.hpp:276
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
Definition ip.hpp:502
const IPv6::Addr & to_ipv6() const
Definition ip.hpp:296
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv4.hpp:186
unsigned int prefix_len() const
Definition ipv4.hpp:453
static Addr from_in_addr(const in_addr *in4)
Definition ipv4.hpp:63
static Addr from_zero()
Definition ipv4.hpp:165
static Addr from_uint32(const base_type addr)
Definition ipv4.hpp:97
std::string to_string() const
Definition ipv4.hpp:229
std::uint32_t to_uint32() const
Definition ipv4.hpp:104
sockaddr_in to_sockaddr(const unsigned short port=0) const
Definition ipv4.hpp:84
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv4.hpp:202
static Addr from_byte_string(const unsigned char *bytestr)
Definition ipv6.hpp:251
static Addr from_in6_addr(const in6_addr *in6)
Definition ipv6.hpp:60
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv6.hpp:325
std::string to_string() const
Definition ipv6.hpp:128
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv6.hpp:101
sockaddr_in6 to_sockaddr(const unsigned short port=0) const
Definition ipv6.hpp:84
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
Route address class that may use non-canonical form.
Definition capture.hpp:295
const RouteAddress * vpn_ipv4() const
Gets the IPv4 tunnel address.
Definition capture.hpp:902
ActionDeleteAllRoutesOnInterface(const DWORD iface_index_arg)
Definition tunutil.hpp:1205
static void remove_all_ipv4_routes_on_iface(DWORD index, ActionList &actions)
Definition tunutil.hpp:1226
static void remove_all_ipv6_routes_on_iface(DWORD index, ActionList &actions)
Definition tunutil.hpp:1253
static std::string cmd(const TapNameGuidPair &tap)
Definition tunutil.hpp:1297
ActionEnableDHCP(const TapNameGuidPair &tap)
Definition tunutil.hpp:1291
ActionSetAdapterDomainSuffix(const std::string &search_domain_arg, const std::string &tap_guid_arg)
Definition tunutil.hpp:903
void execute(std::ostream &os) override
Definition tunutil.hpp:910
const std::string & gateway_address() const
Definition tunutil.hpp:1158
BestGateway(ADDRESS_FAMILY af, const std::string &dest_str, DWORD vpn_interface_index)
Definition tunutil.hpp:1042
void fill_gw_details(const MIB_IPFORWARD_ROW2 *row, const std::string &dest)
Definition tunutil.hpp:1173
static ULONG get_iface_metric(std::map< NET_IFINDEX, ULONG > &metric_per_iface, NET_IFINDEX iface, ADDRESS_FAMILY af)
Definition tunutil.hpp:1183
void execute(std::ostream &os) override
Definition tunutil.hpp:1413
AddRoute4Cmd(const std::string &route_address, int prefix_length, DWORD iface_index, const std::string &iface_name, const std::string &gw_address, int metric, bool add)
Definition tunutil.hpp:1371
AddRoute4Cmd(const std::string &route_address, int prefix_length, DWORD iface_index, const std::string &iface_name, const std::string &gw_address, int metric, bool add)
Definition tunutil.hpp:1309
std::string to_string() const override
Definition tunutil.hpp:1340
void execute(std::ostream &os) override
Definition tunutil.hpp:1335
std::string cmd
Definition cmd.hpp:51
std::string to_string() const override
Definition cmd.hpp:45
void execute(std::ostream &os) override
Definition cmd.hpp:38
Wrapper class for a Registry key handle.
Definition reg.hpp:45
bool defined() const
Check for a valid key handle.
Definition reg.hpp:136
PHKEY ref()
Retrun a pointer to the Registry key handle.
Definition reg.hpp:146
#define OPENVPN_EXCEPTION(C)
Definition exception.hpp:99
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_LOG(args)
constexpr BufferFlags CONSTRUCT_ZERO(1U<< 0)
if enabled, constructors/init will zero allocated space
static SOCKADDR_INET sockaddr_inet(short family, const std::string &addr)
Definition tunutil.hpp:1351
static DWORD InterfaceLuid(const std::string &iface_name, PNET_LUID luid)
Definition tunutil.hpp:1360
const MIB_IPFORWARD_TABLE2 * windows_routing_table2(ADDRESS_FAMILY af)
Definition tunutil.hpp:972
void flush_arp(const DWORD adapter_index, std::ostream &os)
Definition tunutil.hpp:736
void dhcp_release(const InterfaceInfoList &ii, const DWORD adapter_index, std::ostream &os)
Definition tunutil.hpp:706
std::string tap_path(const TapNameGuidPair &tap)
Definition tunutil.hpp:522
HANDLE tap_open(const Type tun_type, const TapNameGuidPairList &guids, std::string &path_opened, TapNameGuidPair &used)
Definition tunutil.hpp:528
const MIB_IPFORWARDTABLE * windows_routing_table()
Definition tunutil.hpp:950
void tap_configure_topology_subnet(HANDLE th, const IP::Addr &local, const unsigned int prefix_len)
Definition tunutil.hpp:589
void dhcp_renew(const InterfaceInfoList &ii, const DWORD adapter_index, std::ostream &os)
Definition tunutil.hpp:721
void tap_set_media_status(HANDLE th, bool media_status)
Definition tunutil.hpp:638
void tap_process_logging(HANDLE th)
Definition tunutil.hpp:657
std::vector< TapGuidLuid > tap_guids(const Type tun_type)
Definition tunutil.hpp:98
std::pair< std::string, DWORD > TapGuidLuid
Definition tunutil.hpp:94
void tap_configure_topology_net30(HANDLE th, const IP::Addr &local_addr, const IP::Addr &remote_addr)
Definition tunutil.hpp:614
DNS utilities for Windows.
std::unique_ptr< wchar_t[]> UTF16
Definition unicode.hpp:24
size_t utf16_strlen(const wchar_t *str)
Definition unicode.hpp:52
wchar_t * utf16(const std::string &str, int cp=CP_UTF8)
Definition unicode.hpp:29
int strcasecmp(const char *s1, const char *s2)
Definition string.hpp:33
std::string to_string(const T &t)
Convert a value to a string.
Definition to_string.hpp:45
std::unique_ptr< T, std::function< void(T *)> > unique_ptr_del
Definition uniqueptr.hpp:21
std::unique_ptr< T, slab_deleter< T > > unique_ptr_slab
Definition uniqueptr.hpp:55
#define OPENVPN_STRINGIZE(x)
Definition stringize.hpp:17
unique_ptr_slab< IP_ADAPTER_INFO > list
Definition tunutil.hpp:840
const IP_ADAPTER_INFO * adapter(const DWORD index) const
Definition tunutil.hpp:807
bool is_up(const DWORD index, const IPNetmask4 &vpn_addr) const
Definition tunutil.hpp:820
bool is_dhcp_enabled(const DWORD index) const
Definition tunutil.hpp:834
IPNetmask4(const IP_ADDR_STRING *ias)
Definition tunutil.hpp:760
bool operator==(const IPNetmask4 &rhs) const
Definition tunutil.hpp:781
bool operator!=(const IPNetmask4 &rhs) const
Definition tunutil.hpp:786
IPNetmask4(const TunBuilderCapture &pull, const char *title)
Definition tunutil.hpp:750
unique_ptr_slab< IP_PER_ADAPTER_INFO > adapt
Definition tunutil.hpp:855
unique_ptr_slab< IP_INTERFACE_INFO > list
Definition tunutil.hpp:703
IP_ADAPTER_INDEX_MAP * iface(const DWORD index) const
Definition tunutil.hpp:689
std::string guid_from_name(const std::string &name) const
Definition tunutil.hpp:388
std::string name_from_guid(const std::string &guid) const
Definition tunutil.hpp:377
const auto metric
server addresses push_back(address)
std::string ret
std::ostringstream os
int prefix_len(const IPv4::Addr::base_type mask)
static void add(const Time &t1, const Time::Duration &d1)