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 << std::endl;
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 (!string::ends_with(inst_id_interface.device_interface, 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" << std::endl;
716 else
717 os << "TAP: DHCP release failed" << std::endl;
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" << std::endl;
731 else
732 os << "TAP: DHCP renew failed" << std::endl;
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" << std::endl;
742 else
743 os << "TAP: ARP flush failed" << std::endl;
744}
745
747{
749 {
750 }
751
752 IPNetmask4(const TunBuilderCapture &pull, const char *title)
753 {
754 const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
755 if (local4)
756 {
757 ip = IPv4::Addr::from_string(local4->address, title);
759 }
760 }
761
762 IPNetmask4(const IP_ADDR_STRING *ias)
763 {
764 if (ias)
765 {
766 try
767 {
768 ip = IPv4::Addr::from_string(ias->IpAddress.String);
769 }
770 catch (const std::exception &)
771 {
772 }
773 try
774 {
775 netmask = IPv4::Addr::from_string(ias->IpMask.String);
776 }
777 catch (const std::exception &)
778 {
779 }
780 }
781 }
782
783 bool operator==(const IPNetmask4 &rhs) const
784 {
785 return ip == rhs.ip && netmask == rhs.netmask;
786 }
787
788 bool operator!=(const IPNetmask4 &rhs) const
789 {
790 return !operator==(rhs);
791 }
792
795};
796
798{
800 {
801 ULONG size = 0;
802 if (::GetAdaptersInfo(nullptr, &size) != ERROR_BUFFER_OVERFLOW)
803 OPENVPN_THROW(tun_win_util, "IPAdaptersInfo: GetAdaptersInfo #1");
804 list.reset((IP_ADAPTER_INFO *)::operator new(size));
805 if (::GetAdaptersInfo(list.get(), &size) != NO_ERROR)
806 OPENVPN_THROW(tun_win_util, "IPAdaptersInfo: GetAdaptersInfo #2");
807 }
808
809 const IP_ADAPTER_INFO *adapter(const DWORD index) const
810 {
811 if (list)
812 {
813 for (const IP_ADAPTER_INFO *a = list.get(); a != nullptr; a = a->Next)
814 {
815 if (index == a->Index)
816 return a;
817 }
818 }
819 return nullptr;
820 }
821
822 bool is_up(const DWORD index, const IPNetmask4 &vpn_addr) const
823 {
824 const IP_ADAPTER_INFO *ai = adapter(index);
825 if (ai)
826 {
827 for (const IP_ADDR_STRING *iplist = &ai->IpAddressList; iplist != nullptr; iplist = iplist->Next)
828 {
829 if (vpn_addr == IPNetmask4(iplist))
830 return true;
831 }
832 }
833 return false;
834 }
835
836 bool is_dhcp_enabled(const DWORD index) const
837 {
838 const IP_ADAPTER_INFO *ai = adapter(index);
839 return ai && ai->DhcpEnabled;
840 }
841
843};
844
846{
847 IPPerAdapterInfo(const DWORD index)
848 {
849 ULONG size = 0;
850 if (::GetPerAdapterInfo(index, nullptr, &size) != ERROR_BUFFER_OVERFLOW)
851 return;
852 adapt.reset((IP_PER_ADAPTER_INFO *)::operator new(size));
853 if (::GetPerAdapterInfo(index, adapt.get(), &size) != ERROR_SUCCESS)
854 adapt.reset();
855 }
856
858};
859
861{
862 public:
864 : defined(false)
865 {
866 DWORD len;
867 info[0] = info[1] = info[2] = 0;
868 if (::DeviceIoControl(th,
869 TAP_WIN_IOCTL_GET_VERSION,
870 &info,
871 sizeof(info),
872 &info,
873 sizeof(info),
874 &len,
875 nullptr))
876 {
877 defined = true;
878 }
879 }
880
881 std::string to_string()
882 {
883 std::ostringstream os;
884 os << "TAP-Windows Driver Version ";
885 if (defined)
886 {
887 os << info[0] << '.' << info[1];
888 if (info[2])
889 os << " (DEBUG)";
890 }
891 else
892 os << "UNDEFINED";
893 return os.str();
894 }
895
896 private:
898 ULONG info[3];
899};
900
901// An action to set the DNS "Connection-specific DNS Suffix"
903{
904 public:
905 ActionSetAdapterDomainSuffix(const std::string &search_domain_arg,
906 const std::string &tap_guid_arg)
907 : search_domain(search_domain_arg),
908 tap_guid(tap_guid_arg)
909 {
910 }
911
912 virtual void execute(std::ostream &os) override
913 {
914 os << to_string() << std::endl;
915
916 LONG status;
917 Win::Reg::Key key;
918 const std::string reg_key_name = "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\" + tap_guid;
919 status = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE,
920 reg_key_name.c_str(),
921 0,
922 KEY_READ | KEY_WRITE,
923 key.ref());
924 if (status != ERROR_SUCCESS)
925 {
926 const Win::Error err(status);
927 OPENVPN_THROW(tun_win_util, "ActionSetAdapterDomainSuffix: error opening registry key: " << reg_key_name << " : " << err.message());
928 }
929
931 status = ::RegSetValueExW(key(),
932 L"Domain",
933 0,
934 REG_SZ,
935 reinterpret_cast<const BYTE *>(dom.get()),
936 static_cast<DWORD>((Win::utf16_strlen(dom.get()) + 1) * sizeof(wchar_t)));
937 if (status != ERROR_SUCCESS)
938 OPENVPN_THROW(tun_win_util, "ActionSetAdapterDomainSuffix: error writing Domain registry key: " << reg_key_name);
939 }
940
941 virtual std::string to_string() const override
942 {
943 return "Set adapter domain suffix: '" + search_domain + "' " + tap_guid;
944 }
945
946 private:
947 const std::string search_domain;
948 const std::string tap_guid;
949};
950
951// get the Windows IPv4 routing table
952inline const MIB_IPFORWARDTABLE *windows_routing_table()
953{
954 ULONG size = 0;
955 DWORD status;
957
958 status = ::GetIpForwardTable(nullptr, &size, TRUE);
959 if (status == ERROR_INSUFFICIENT_BUFFER)
960 {
961 rt.reset((MIB_IPFORWARDTABLE *)::operator new(size));
962 status = ::GetIpForwardTable(rt.get(), &size, TRUE);
963 if (status != NO_ERROR)
964 {
965 OPENVPN_LOG("windows_routing_table: GetIpForwardTable failed");
966 return nullptr;
967 }
968 }
969 return rt.release();
970}
971
972// Get the Windows IPv4/IPv6 routing table.
973// Note that returned pointer must be freed with FreeMibTable.
974inline const MIB_IPFORWARD_TABLE2 *windows_routing_table2(ADDRESS_FAMILY af)
975{
976 MIB_IPFORWARD_TABLE2 *routes = nullptr;
977 int res = ::GetIpForwardTable2(af, &routes);
978 if (res == NO_ERROR)
979 return routes;
980 else
981 return nullptr;
982}
983
985{
986 public:
990 BestGateway(ADDRESS_FAMILY af)
991 {
993 [](const MIB_IPFORWARD_TABLE2 *p)
994 { FreeMibTable((PVOID)p); });
995
996 if (!rt2)
997 {
998 OPENVPN_THROW(tun_win_util, "Failed to get routing table");
999 }
1000
1001 std::map<NET_IFINDEX, ULONG> metric_per_iface;
1002 ULONG gw_metric = 0;
1003
1004 const MIB_IPFORWARD_ROW2 *gw = nullptr;
1005 for (size_t i = 0; i < rt2->NumEntries; ++i)
1006 {
1007 const MIB_IPFORWARD_ROW2 *row = &rt2->Table[i];
1008
1009 IP::Addr dst = IP::Addr::from_sockaddr((const sockaddr *)&row->DestinationPrefix.Prefix);
1010 bool default_gw = dst.all_zeros() && row->DestinationPrefix.PrefixLength == 0;
1011
1012 ULONG metric = row->Metric + get_iface_metric(metric_per_iface, row->InterfaceIndex, af);
1013
1014 if (default_gw && (!gw || metric < gw_metric))
1015 {
1016 gw = row;
1017 gw_metric = metric;
1018 }
1019 }
1020 if (gw)
1021 {
1022 index = gw->InterfaceIndex;
1023 if (af == AF_INET6)
1024 {
1025 addr = IPv6::Addr::from_in6_addr(&gw->NextHop.Ipv6.sin6_addr).to_string();
1026 }
1027 else
1028 {
1029 addr = IPv4::Addr::from_in_addr(&gw->NextHop.Ipv4.sin_addr).to_string();
1030 }
1031 }
1032 }
1033
1044 BestGateway(ADDRESS_FAMILY af, const std::string &dest_str, DWORD vpn_interface_index)
1045 {
1047 [](const MIB_IPFORWARD_TABLE2 *p)
1048 { FreeMibTable((PVOID)p); });
1049
1050 if (!rt2)
1051 {
1052 OPENVPN_THROW(tun_win_util, "Failed to get routing table");
1053 }
1054
1055 IP::Addr dest = IP::Addr::from_string(dest_str);
1056
1057 void *dst_addr = NULL;
1058 struct sockaddr_in sa4;
1059 struct sockaddr_in6 sa6;
1060 if (af == AF_INET6)
1061 {
1062 sa6 = dest.to_ipv6().to_sockaddr();
1063 dst_addr = &sa6;
1064 }
1065 else
1066 {
1067 sa4 = dest.to_ipv4().to_sockaddr();
1068 dst_addr = &sa4;
1069 }
1070
1071 NET_IFINDEX best_interface = 0;
1072 DWORD res = ::GetBestInterfaceEx((sockaddr *)dst_addr, &best_interface);
1073 if (res != NO_ERROR)
1074 {
1075 OPENVPN_THROW(tun_win_util,
1076 "GetBestInterfaceEx: error retrieving the best interface for " << dest
1077 << ": " << res);
1078 }
1079
1080 // check if route is local
1081 MIB_IPFORWARD_ROW2 row{};
1082 SOCKADDR_INET best_source{};
1083 res = ::GetBestRoute2(NULL, best_interface, NULL, (const SOCKADDR_INET *)dst_addr, 0, &row, &best_source);
1084 if (res != NO_ERROR)
1085 {
1086 OPENVPN_THROW(tun_win_util,
1087 "GetBestGateway: error retrieving the best route for " << dest
1088 << ": " << res);
1089 }
1090
1091 // no gw needed, route is local
1092 if (row.Protocol == RouteProtocolLocal)
1093 {
1094 local_route_ = true;
1095 return;
1096 }
1097
1098 // if there is no VPN interface - we're done
1099 if (vpn_interface_index == DWORD(-1))
1100 {
1101 fill_gw_details(&row, dest_str);
1102 return;
1103 }
1104
1105 // find the best route excluding VPN interface
1106 const MIB_IPFORWARD_ROW2 *gw = nullptr;
1107 std::map<NET_IFINDEX, ULONG> metric_per_iface;
1108 ULONG gw_metric = 0;
1109 for (size_t i = 0; i < rt2->NumEntries; ++i)
1110 {
1111 const MIB_IPFORWARD_ROW2 *row = &rt2->Table[i];
1112 IP::Addr mask = IP::Addr::netmask_from_prefix_len(af == AF_INET6 ? IP::Addr::Version::V6 : IP::Addr::Version::V4, row->DestinationPrefix.PrefixLength);
1113
1114 IP::Addr dest_prefix = IP::Addr::from_sockaddr((const sockaddr *)&row->DestinationPrefix.Prefix);
1115
1116 if ((dest & mask) == dest_prefix)
1117 {
1118 // skip gateway on VPN interface
1119 if ((vpn_interface_index != DWORD(-1)) && (row->InterfaceIndex == vpn_interface_index))
1120 {
1121 OPENVPN_LOG("GetBestGateway: skip gateway "
1122 << IP::Addr::from_sockaddr((const sockaddr *)&row->NextHop).to_string()
1123 << " on VPN interface " << vpn_interface_index);
1124 continue;
1125 }
1126
1127 if (!gw)
1128 {
1129 gw = row;
1130 continue;
1131 }
1132
1133 ULONG metric = row->Metric + get_iface_metric(metric_per_iface, row->InterfaceIndex, af);
1134
1135 // use new gateway if it has longer prefix OR the same prefix but lower metric
1136 if ((row->DestinationPrefix.PrefixLength > gw->DestinationPrefix.PrefixLength) || ((row->DestinationPrefix.PrefixLength == gw->DestinationPrefix.PrefixLength) && (metric < gw_metric)))
1137 {
1138 gw = row;
1139 gw_metric = metric;
1140 }
1141 }
1142 }
1143
1144 if (gw)
1145 {
1146 fill_gw_details(gw, dest_str);
1147 }
1148 }
1149
1150 bool defined() const
1151 {
1152 return index != DWORD(-1) && !addr.empty();
1153 }
1154
1155 DWORD interface_index() const
1156 {
1157 return index;
1158 }
1159
1160 const std::string &gateway_address() const
1161 {
1162 return addr;
1163 }
1164
1169 bool local_route() const
1170 {
1171 return local_route_;
1172 }
1173
1174 private:
1175 void fill_gw_details(const MIB_IPFORWARD_ROW2 *row, const std::string &dest)
1176 {
1177 index = row->InterfaceIndex;
1178 addr = IP::Addr::from_sockaddr((const sockaddr *)&row->NextHop).to_string();
1179 OPENVPN_LOG("GetBestGateway: "
1180 << "selected gateway " << addr
1181 << " on adapter " << index
1182 << " for destination " << dest);
1183 }
1184
1185 static ULONG get_iface_metric(std::map<NET_IFINDEX, ULONG> &metric_per_iface, NET_IFINDEX iface, ADDRESS_FAMILY af)
1186 {
1187 if (!metric_per_iface.contains(iface))
1188 {
1189 MIB_IPINTERFACE_ROW ir{};
1190 ir.InterfaceIndex = iface;
1191 ir.Family = af;
1192 ::GetIpInterfaceEntry(&ir);
1193 metric_per_iface[iface] = ir.Metric;
1194 }
1195 return metric_per_iface[iface];
1196 }
1197
1198 DWORD index = -1;
1199 std::string addr;
1200 bool local_route_ = false;
1201};
1202
1203// An action to delete all routes on an interface
1205{
1206 public:
1207 ActionDeleteAllRoutesOnInterface(const DWORD iface_index_arg)
1208 : iface_index(iface_index_arg)
1209 {
1210 }
1211
1212 virtual void execute(std::ostream &os) override
1213 {
1214 os << to_string() << std::endl;
1215
1216 ActionList::Ptr actions = new ActionList();
1219 actions->execute(os);
1220 }
1221
1222 virtual std::string to_string() const override
1223 {
1224 return "ActionDeleteAllRoutesOnInterface iface_index=" + std::to_string(iface_index);
1225 }
1226
1227 private:
1228 static void remove_all_ipv4_routes_on_iface(DWORD index, ActionList &actions)
1229 {
1230 std::unique_ptr<const MIB_IPFORWARDTABLE> rt(windows_routing_table());
1231 if (rt)
1232 {
1233 for (size_t i = 0; i < rt->dwNumEntries; ++i)
1234 {
1235 const MIB_IPFORWARDROW *row = &rt->table[i];
1236 if (row->dwForwardIfIndex == index)
1237 {
1238 const IPv4::Addr net = IPv4::Addr::from_uint32(ntohl(row->dwForwardDest));
1239 const IPv4::Addr mask = IPv4::Addr::from_uint32(ntohl(row->dwForwardMask));
1240 const std::string net_str = net.to_string();
1241 const unsigned int pl = mask.prefix_len();
1242
1243 // don't remove multicast route or other Windows-assigned routes
1244 if (net_str == "224.0.0.0" && pl == 4)
1245 continue;
1246 if (net_str == "255.255.255.255" && pl == 32)
1247 continue;
1248
1249 actions.add(new WinCmd("netsh interface ip delete route " + net_str + '/' + openvpn::to_string(pl) + ' ' + openvpn::to_string(index) + " store=active"));
1250 }
1251 }
1252 }
1253 }
1254
1255 static void remove_all_ipv6_routes_on_iface(DWORD index, ActionList &actions)
1256 {
1258 [](const MIB_IPFORWARD_TABLE2 *p)
1259 { FreeMibTable((PVOID)p); });
1260 if (rt2)
1261 {
1262 const IPv6::Addr ll_net = IPv6::Addr::from_string("fe80::");
1264 for (size_t i = 0; i < rt2->NumEntries; ++i)
1265 {
1266 const MIB_IPFORWARD_ROW2 *row = &rt2->Table[i];
1267 if (row->InterfaceIndex == index)
1268 {
1269 const unsigned int pl = row->DestinationPrefix.PrefixLength;
1270 if (row->DestinationPrefix.Prefix.si_family == AF_INET6)
1271 {
1272 const IPv6::Addr net = IPv6::Addr::from_byte_string(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte);
1273 const std::string net_str = net.to_string();
1274
1275 // don't remove multicast route or other Windows-assigned routes
1276 if (net_str == "ff00::" && pl == 8)
1277 continue;
1278 if ((net & ll_mask) == ll_net && pl >= 64)
1279 continue;
1280 actions.add(new WinCmd("netsh interface ipv6 delete route " + net_str + '/' + openvpn::to_string(pl) + ' ' + openvpn::to_string(index) + " store=active"));
1281 }
1282 }
1283 }
1284 }
1285 }
1286
1287 const DWORD iface_index;
1288};
1289
1291{
1292 public:
1294 : WinCmd(cmd(tap))
1295 {
1296 }
1297
1298 private:
1299 static std::string cmd(const TapNameGuidPair &tap)
1300 {
1301 return "netsh interface ip set address " + tap.index_or_name() + " dhcp";
1302 }
1303};
1304
1305namespace TunNETSH {
1306class AddRoute4Cmd : public Action
1307{
1308 public:
1310
1311 AddRoute4Cmd(const std::string &route_address,
1312 int prefix_length,
1313 DWORD iface_index,
1314 const std::string &iface_name,
1315 const std::string &gw_address,
1316 int metric,
1317 bool add)
1318 {
1319 std::ostringstream os;
1320 os << "netsh interface ip ";
1321 if (add)
1322 os << "add ";
1323 else
1324 os << "delete ";
1325 os << "route " << route_address << "/" << std::to_string(prefix_length) << " ";
1326 if (iface_index != DWORD(-1))
1327 os << iface_index;
1328 else
1329 os << iface_name;
1330 os << " " << gw_address << " ";
1331 if (add && metric >= 0)
1332 os << "metric=" << std::to_string(metric) << " ";
1333 os << "store=active";
1334 cmd.reset(new WinCmd(os.str()));
1335 };
1336
1337 void execute(std::ostream &os) override
1338 {
1339 cmd->execute(os);
1340 }
1341
1342 std::string to_string() const override
1343 {
1344 return cmd->to_string();
1345 }
1346
1347 private:
1349};
1350} // namespace TunNETSH
1351
1352namespace TunIPHELPER {
1353static SOCKADDR_INET sockaddr_inet(short family, const std::string &addr)
1354{
1355 SOCKADDR_INET sa;
1356 ZeroMemory(&sa, sizeof(sa));
1357 sa.si_family = family;
1358 inet_pton(family, addr.c_str(), family == AF_INET ? &(sa.Ipv4.sin_addr) : (PVOID) & (sa.Ipv6.sin6_addr));
1359 return sa;
1360}
1361
1362static DWORD InterfaceLuid(const std::string &iface_name, PNET_LUID luid)
1363{
1364 auto wide_name = wstring::from_utf8(iface_name);
1365 return ConvertInterfaceAliasToLuid(wide_name.c_str(), luid);
1366}
1367
1368class AddRoute4Cmd : public Action
1369{
1370 public:
1372
1373 AddRoute4Cmd(const std::string &route_address,
1374 int prefix_length,
1375 DWORD iface_index,
1376 const std::string &iface_name,
1377 const std::string &gw_address,
1378 int metric,
1379 bool add)
1380 : add(add)
1381 {
1382 os_ << "IPHelper: ";
1383 if (add)
1384 os_ << "add ";
1385 else
1386 os_ << "delete ";
1387 os_ << "route " << route_address << "/" << std::to_string(prefix_length) << " ";
1388 if (iface_index != DWORD(-1))
1389 os_ << iface_index;
1390 else
1391 os_ << iface_name;
1392 os_ << " " << gw_address << " metric=" << std::to_string(metric);
1393
1394 ZeroMemory(&fwd_row, sizeof(fwd_row));
1395 fwd_row.ValidLifetime = 0xffffffff;
1396 fwd_row.PreferredLifetime = 0xffffffff;
1397 fwd_row.Protocol = (NL_ROUTE_PROTOCOL)MIB_IPPROTO_NETMGMT;
1398 fwd_row.Metric = metric;
1399 fwd_row.DestinationPrefix.Prefix = sockaddr_inet(AF_INET, route_address);
1400 fwd_row.DestinationPrefix.PrefixLength = prefix_length;
1401 fwd_row.NextHop = sockaddr_inet(AF_INET, gw_address);
1402
1403 if (iface_index != DWORD(-1))
1404 fwd_row.InterfaceIndex = iface_index;
1405 else if (!iface_name.empty())
1406 {
1407 NET_LUID luid;
1408 auto err = InterfaceLuid(iface_name, &luid);
1409 if (err)
1410 OPENVPN_THROW(tun_win_util, "Cannot convert interface name " << iface_name << " to LUID");
1411 fwd_row.InterfaceLuid = luid;
1412 }
1413 };
1414
1415 void execute(std::ostream &os) override
1416 {
1417 os << os_.str() << std::endl;
1418 DWORD res;
1419 if (add)
1420 res = CreateIpForwardEntry2(&fwd_row);
1421 else
1422 res = DeleteIpForwardEntry2(&fwd_row);
1423 if (res)
1424 os << "cannot modify route: error " << res << std::endl;
1425 }
1426
1427 std::string to_string() const override
1428 {
1429 return os_.str();
1430 }
1431
1432 private:
1433 MIB_IPFORWARD_ROW2 fwd_row;
1434 bool add;
1435 std::ostringstream os_;
1436};
1437} // namespace TunIPHELPER
1438} // namespace Util
1439} // 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:1450
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1384
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:189
unsigned int prefix_len() const
Definition ipv4.hpp:456
static Addr from_in_addr(const in_addr *in4)
Definition ipv4.hpp:66
static Addr from_zero()
Definition ipv4.hpp:168
static Addr from_uint32(const base_type addr)
Definition ipv4.hpp:100
std::string to_string() const
Definition ipv4.hpp:232
std::uint32_t to_uint32() const
Definition ipv4.hpp:107
sockaddr_in to_sockaddr(const unsigned short port=0) const
Definition ipv4.hpp:87
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv4.hpp:205
static Addr from_byte_string(const unsigned char *bytestr)
Definition ipv6.hpp:254
static Addr from_in6_addr(const in6_addr *in6)
Definition ipv6.hpp:63
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv6.hpp:328
std::string to_string() const
Definition ipv6.hpp:131
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv6.hpp:104
sockaddr_in6 to_sockaddr(const unsigned short port=0) const
Definition ipv6.hpp:87
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:1207
virtual std::string to_string() const override
Definition tunutil.hpp:1222
virtual void execute(std::ostream &os) override
Definition tunutil.hpp:1212
static void remove_all_ipv4_routes_on_iface(DWORD index, ActionList &actions)
Definition tunutil.hpp:1228
static void remove_all_ipv6_routes_on_iface(DWORD index, ActionList &actions)
Definition tunutil.hpp:1255
static std::string cmd(const TapNameGuidPair &tap)
Definition tunutil.hpp:1299
ActionEnableDHCP(const TapNameGuidPair &tap)
Definition tunutil.hpp:1293
virtual std::string to_string() const override
Definition tunutil.hpp:941
ActionSetAdapterDomainSuffix(const std::string &search_domain_arg, const std::string &tap_guid_arg)
Definition tunutil.hpp:905
virtual void execute(std::ostream &os) override
Definition tunutil.hpp:912
const std::string & gateway_address() const
Definition tunutil.hpp:1160
BestGateway(ADDRESS_FAMILY af, const std::string &dest_str, DWORD vpn_interface_index)
Definition tunutil.hpp:1044
void fill_gw_details(const MIB_IPFORWARD_ROW2 *row, const std::string &dest)
Definition tunutil.hpp:1175
static ULONG get_iface_metric(std::map< NET_IFINDEX, ULONG > &metric_per_iface, NET_IFINDEX iface, ADDRESS_FAMILY af)
Definition tunutil.hpp:1185
void execute(std::ostream &os) override
Definition tunutil.hpp:1415
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:1373
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:1311
std::string to_string() const override
Definition tunutil.hpp:1342
void execute(std::ostream &os) override
Definition tunutil.hpp:1337
virtual void execute(std::ostream &os) override
Definition cmd.hpp:38
virtual std::string to_string() const override
Definition cmd.hpp:45
std::string cmd
Definition cmd.hpp:51
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)
#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:1353
static DWORD InterfaceLuid(const std::string &iface_name, PNET_LUID luid)
Definition tunutil.hpp:1362
const MIB_IPFORWARD_TABLE2 * windows_routing_table2(ADDRESS_FAMILY af)
Definition tunutil.hpp:974
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:952
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:29
bool ends_with(const STRING &str, const std::string &suffix)
Definition string.hpp:111
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:842
const IP_ADAPTER_INFO * adapter(const DWORD index) const
Definition tunutil.hpp:809
bool is_up(const DWORD index, const IPNetmask4 &vpn_addr) const
Definition tunutil.hpp:822
bool is_dhcp_enabled(const DWORD index) const
Definition tunutil.hpp:836
IPNetmask4(const IP_ADDR_STRING *ias)
Definition tunutil.hpp:762
bool operator==(const IPNetmask4 &rhs) const
Definition tunutil.hpp:783
bool operator!=(const IPNetmask4 &rhs) const
Definition tunutil.hpp:788
IPNetmask4(const TunBuilderCapture &pull, const char *title)
Definition tunutil.hpp:752
unique_ptr_slab< IP_PER_ADAPTER_INFO > adapt
Definition tunutil.hpp:857
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, port})
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)