0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-19 19:52:15 +02:00

Remove support for pre-Vista Windows versions

We do not care about them anymore. So remove all
the support which is untested anyway.

Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com>
This commit is contained in:
Frank Lichtenheld 2023-04-20 13:37:26 +02:00
parent 037fda0521
commit cb589b70f0
9 changed files with 7 additions and 438 deletions

View File

@ -52,10 +52,7 @@ class NamedPipe : public Base
const HANDLE h = ::CreateNamedPipeA(
name.c_str(),
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
#if _WIN32_WINNT >= 0x0600 // Vista and higher
PIPE_REJECT_REMOTE_CLIENTS |
#endif
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
PIPE_REJECT_REMOTE_CLIENTS | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
PIPE_UNLIMITED_INSTANCES,
2048, // output buffer size
2048, // input buffer size

View File

@ -61,9 +61,6 @@ class WinCommandAgent : public TunWin::SetupFactory
// Build JSON request
Json::Value jreq(Json::objectValue);
#if _WIN32_WINNT < 0x0600 // pre-Vista needs us to explicitly communicate our PID
jreq["pid"] = Json::Value((Json::UInt)::GetProcessId(::GetCurrentProcess()));
#endif
jreq["host"] = endpoint.to_string();
jreq["ipv6"] = endpoint.is_ipv6();
@ -122,7 +119,6 @@ class WinCommandAgent : public TunWin::SetupFactory
ts->http_config = hc;
ts->debug_level = debug_level;
#if _WIN32_WINNT >= 0x0600 // Vista and higher
ts->post_connect = [host, client_exe, cb = std::move(cb)](WS::ClientSet::TransactionSet &ts, AsioPolySock::Base &sock)
{
AsioPolySock::NamedPipe *np = dynamic_cast<AsioPolySock::NamedPipe *>(&sock);
@ -135,7 +131,6 @@ class WinCommandAgent : public TunWin::SetupFactory
cb(npinfo.proc.release());
}
};
#endif
return ts;
}
@ -154,9 +149,6 @@ class WinCommandAgent : public TunWin::SetupFactory
{
// Build JSON request
Json::Value jreq(Json::objectValue);
#if _WIN32_WINNT < 0x0600 // pre-Vista needs us to explicitly communicate our PID
jreq["pid"] = Json::Value((Json::UInt)::GetProcessId(::GetCurrentProcess()));
#endif
jreq["confirm_event"] = confirm_event.duplicate_local();
jreq["destroy_event"] = destroy_event.duplicate_local();
const std::string jtxt = jreq.toStyledString();
@ -217,9 +209,6 @@ class WinCommandAgent : public TunWin::SetupFactory
// Build JSON request
Json::Value jreq(Json::objectValue);
#if _WIN32_WINNT < 0x0600 // pre-Vista needs us to explicitly communicate our PID
jreq["pid"] = Json::Value((Json::UInt)::GetProcessId(::GetCurrentProcess()));
#endif
if (ring_buffer)
ring_buffer->serialize(jreq);

View File

@ -1051,9 +1051,7 @@ int run(OptionList opt)
try
{
#if _WIN32_WINNT >= 0x0600 // Vista+
TunWin::NRPT::delete_rule(); // delete stale NRPT rules
#endif
omi.reset(new OMI(io_context, std::move(opt)));
omi->start();
io_context_run_called = true;

View File

@ -514,16 +514,12 @@ class MyListener : public WS::Server::Listener
AsioPolySock::NamedPipe *np = dynamic_cast<AsioPolySock::NamedPipe *>(&sock);
if (np)
{
#if _WIN32_WINNT >= 0x0600 // Vista and higher
Win::NamedPipePeerInfoClient npinfo(np->handle.native_handle());
const std::string client_exe = wstring::to_utf8(npinfo.exe_path);
OPENVPN_LOG("connection from " << client_exe);
if (Agent::valid_pipe(client_exe, config.server_exe))
return true;
OPENVPN_LOG(client_exe << " not recognized as a valid client");
#else
return true;
#endif
}
else
OPENVPN_LOG("only named pipe clients are allowed");
@ -852,19 +848,13 @@ class MyClientInstance : public WS::Server::Listener::Client
std::wstring get_client_exe(const HANDLE client_pipe)
{
#if _WIN32_WINNT >= 0x0600 // Vista and higher
Win::NamedPipePeerInfoClient npinfo(client_pipe);
return npinfo.exe_path;
#else
return std::wstring();
#endif
}
Win::ScopedHANDLE get_client_process(const HANDLE pipe, ULONG pid_hint) const
{
#if _WIN32_WINNT >= 0x0600 // Vista and higher
pid_hint = Win::NamedPipePeerInfo::get_pid(pipe, true);
#endif
if (!pid_hint)
throw Exception("cannot determine client PID");
return Win::NamedPipePeerInfo::get_process(pid_hint, false);
@ -920,10 +910,8 @@ class MyService : public Win::Service
MyConfig conf;
#if _WIN32_WINNT >= 0x0600 // Vista and higher
Win::NamedPipePeerInfo::allow_client_query();
TunWin::NRPT::delete_rule(); // remove stale NRPT rules
#endif
WS::Server::Config::Ptr hconf = new WS::Server::Config();
hconf->http_server_id = OVPNAGENT_NAME_STRING "/" HTTP_SERVER_VERSION;
@ -981,9 +969,6 @@ class MyService : public Win::Service
Config c;
c.name = OVPNAGENT_NAME_STRING;
c.display_name = "OpenVPN Agent " OVPNAGENT_NAME_STRING;
#if _WIN32_WINNT < 0x0600 // pre-Vista
c.dependencies.push_back("Dhcp"); // DHCP client
#endif
c.autostart = true;
c.restart_on_fail = true;
return c;

View File

@ -418,11 +418,7 @@ class TimeType
#else
base_ = ::time(0);
#ifdef OPENVPN_PLATFORM_WIN
#if (_WIN32_WINNT >= 0x0600)
win_recalibrate((DWORD)::GetTickCount64());
#else
win_recalibrate(::GetTickCount());
#endif
#endif
#endif
}
@ -450,11 +446,7 @@ class TimeType
static T now_()
{
#if (_WIN32_WINNT >= 0x0600)
const DWORD gtc = (DWORD)::GetTickCount64();
#else
const DWORD gtc = ::GetTickCount();
#endif
if (gtc < gtc_last)
win_recalibrate(gtc);
const time_t sec = gtc_base + gtc / 1000;

View File

@ -22,8 +22,7 @@
// Client tun setup for Windows
#ifndef OPENVPN_TUN_WIN_CLIENT_TUNSETUP_H
#define OPENVPN_TUN_WIN_CLIENT_TUNSETUP_H
#pragma once
#include <string>
#include <sstream>
@ -47,10 +46,8 @@
#include <openvpn/win/scoped_handle.hpp>
#include <openvpn/win/cmd.hpp>
#if _WIN32_WINNT >= 0x0600 // Vista+
#include <openvpn/tun/win/nrpt.hpp>
#include <openvpn/tun/win/wfp.hpp>
#endif
#include <versionhelpers.h>
@ -353,8 +350,7 @@ class Setup : public SetupBase
}
}
#if _WIN32_WINNT >= 0x0600
// Configure TAP adapter on Vista and higher
// Configure TAP adapter
void adapter_config(HANDLE th,
const std::wstring &openvpn_app_path,
const Util::TapNameGuidPair &tap,
@ -732,167 +728,6 @@ class Setup : public SetupBase
create.add(new WinCmd("ipconfig /flushdns"));
destroy.add(new WinCmd("ipconfig /flushdns"));
}
#else
// Configure TAP adapter for pre-Vista
// Currently we don't support IPv6 on pre-Vista
void adapter_config(HANDLE th,
const std::wstring &openvpn_app_path,
const Util::TapNameGuidPair &tap,
const TunBuilderCapture &pull,
const bool l2_post,
ActionList &create,
ActionList &destroy,
std::ostream &os)
{
// Windows interface index
const std::string tap_index_name = tap.index_or_name();
// get default gateway
const Util::DefaultGateway gw;
// set local4 to point to IPv4 route configurations
const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
// This section skipped on layer 2 post-config
if (!l2_post)
{
// Make sure the TAP adapter is set for DHCP
{
const Util::IPAdaptersInfo ai;
if (!ai.is_dhcp_enabled(tap.index))
{
os << "TAP: DHCP is disabled, attempting to enable" << std::endl;
ActionList::Ptr cmds(new ActionList());
cmds->add(new Util::ActionEnableDHCP(tap));
cmds->execute(os);
}
}
// Set IPv4 Interface
if (local4)
{
// Process ifconfig and topology
const std::string netmask = IPv4::Addr::netmask_from_prefix_len(local4->prefix_length).to_string();
const IP::Addr localaddr = IP::Addr::from_string(local4->address);
if (local4->net30)
Util::tap_configure_topology_net30(th, localaddr, local4->prefix_length);
else
Util::tap_configure_topology_subnet(th, localaddr, local4->prefix_length);
}
// On pre-Vista, set up TAP adapter DHCP masquerade for
// configuring adapter properties.
{
os << "TAP: configure DHCP masquerade" << std::endl;
Util::TAPDHCPMasquerade dhmasq;
dhmasq.init_from_capture(pull);
dhmasq.ioctl(th);
}
// set TAP media status to CONNECTED
if (tun_type_ == TapWindows6)
Util::tap_set_media_status(th, true);
// ARP
Util::flush_arp(tap.index, os);
// DHCP release/renew
{
const Util::InterfaceInfoList ii;
Util::dhcp_release(ii, tap.index, os);
Util::dhcp_renew(ii, tap.index, os);
}
// Wait for TAP adapter to come up
{
bool succeed = false;
const Util::IPNetmask4 vpn_addr(pull, "VPN IP");
for (int i = 1; i <= 30; ++i)
{
os << '[' << i << "] waiting for TAP adapter to receive DHCP settings..." << std::endl;
const Util::IPAdaptersInfo ai;
if (ai.is_up(tap.index, vpn_addr))
{
succeed = true;
break;
}
::Sleep(1000);
}
if (!succeed)
throw tun_win_setup("TAP adapter DHCP handshake failed");
}
// Pre route-add sleep
os << "Sleeping 5 seconds prior to adding routes..." << std::endl;
::Sleep(5000);
}
// Process routes
for (auto &route : pull.add_routes)
{
const std::string metric = route_metric_opt(pull, route, MT_ROUTE);
if (!route.ipv6)
{
if (local4)
{
const std::string netmask = IPv4::Addr::netmask_from_prefix_len(route.prefix_length).to_string();
create.add(new WinCmd("route ADD " + route.address + " MASK " + netmask + ' ' + local4->gateway + metric));
destroy.add(new WinCmd("route DELETE " + route.address + " MASK " + netmask + ' ' + local4->gateway));
}
else
throw tun_win_setup("IPv4 routes pushed without IPv4 ifconfig");
}
}
// Process exclude routes
if (!pull.exclude_routes.empty())
{
if (gw.defined())
{
for (auto &route : pull.exclude_routes)
{
const std::string metric = route_metric_opt(pull, route, MT_ROUTE);
if (!route.ipv6)
{
const std::string netmask = IPv4::Addr::netmask_from_prefix_len(route.prefix_length).to_string();
create.add(new WinCmd("route ADD " + route.address + " MASK " + netmask + ' ' + gw.gateway_address() + metric));
destroy.add(new WinCmd("route DELETE " + route.address + " MASK " + netmask + ' ' + gw.gateway_address()));
}
}
}
else
os << "NOTE: exclude routes error: cannot detect default gateway" << std::endl;
}
// Process IPv4 redirect-gateway
if (pull.reroute_gw.ipv4)
{
// add server bypass route
if (gw.defined())
{
if (!pull.remote_address.ipv6)
{
create.add(new WinCmd("route ADD " + pull.remote_address.address + " MASK 255.255.255.255 " + gw.gateway_address()));
destroy.add(new WinCmd("route DELETE " + pull.remote_address.address + " MASK 255.255.255.255 " + gw.gateway_address()));
}
}
else
throw tun_win_setup("redirect-gateway error: cannot detect default gateway");
create.add(new WinCmd("route ADD 0.0.0.0 MASK 128.0.0.0 " + local4->gateway));
create.add(new WinCmd("route ADD 128.0.0.0 MASK 128.0.0.0 " + local4->gateway));
destroy.add(new WinCmd("route DELETE 0.0.0.0 MASK 128.0.0.0 " + local4->gateway));
destroy.add(new WinCmd("route DELETE 128.0.0.0 MASK 128.0.0.0 " + local4->gateway));
}
// flush DNS cache
// create.add(new WinCmd("net stop dnscache"));
// create.add(new WinCmd("net start dnscache"));
create.add(new WinCmd("ipconfig /flushdns"));
// create.add(new WinCmd("ipconfig /registerdns"));
destroy.add(new WinCmd("ipconfig /flushdns"));
}
#endif
void adapter_config_l2(HANDLE th,
const std::wstring &openvpn_app_path,
@ -970,9 +805,7 @@ class Setup : public SetupBase
return "";
}
#if _WIN32_WINNT >= 0x0600 // Vista+
TunWin::WFPContext::Ptr wfp{new TunWin::WFPContext};
#endif
std::unique_ptr<std::thread> l2_thread;
std::unique_ptr<L2State> l2_state;
@ -988,5 +821,3 @@ class Setup : public SetupBase
};
} // namespace TunWin
} // namespace openvpn
#endif

View File

@ -21,8 +21,7 @@
// tun interface utilities for Windows
#ifndef OPENVPN_TUN_WIN_TUNUTIL_H
#define OPENVPN_TUN_WIN_TUNUTIL_H
#pragma once
#include <openvpn/common/socktypes.hpp> // prevent winsock multiple def errors
@ -867,194 +866,6 @@ struct IPPerAdapterInfo
std::unique_ptr<IP_PER_ADAPTER_INFO> adapt;
};
// Use the TAP DHCP masquerade capability to set TAP adapter properties.
// Generally only used on pre-Vista.
class TAPDHCPMasquerade
{
public:
OPENVPN_EXCEPTION(dhcp_masq);
// VPN IP/netmask
IPNetmask4 vpn;
// IP address of fake DHCP server in TAP adapter
IPv4::Addr dhcp_serv_addr = IPv4::Addr::from_zero();
// DHCP lease for one year
unsigned int lease_time = 31536000;
// DHCP options
std::string domain; // DOMAIN (15)
std::string netbios_scope; // NBS (47)
int netbios_node_type = 0; // NBT 1,2,4,8 (46)
bool disable_nbt = false; // DISABLE_NBT (43, Vendor option 001)
std::vector<IPv4::Addr> dns; // DNS (6)
std::vector<IPv4::Addr> wins; // WINS (44)
std::vector<IPv4::Addr> ntp; // NTP (42)
std::vector<IPv4::Addr> nbdd; // NBDD (45)
void init_from_capture(const TunBuilderCapture &pull)
{
// VPN IP/netmask
vpn = IPNetmask4(pull, "VPN IP");
// DHCP server address
{
const IPv4::Addr network_addr = vpn.ip & vpn.netmask;
const std::uint32_t extent = vpn.netmask.extent_from_netmask_uint32();
if (extent >= 16)
dhcp_serv_addr = network_addr + (extent - 2);
else
dhcp_serv_addr = network_addr;
}
// DNS
for (auto &ds : pull.dns_servers)
{
if (!ds.ipv6)
dns.push_back(IPv4::Addr::from_string(ds.address, "DNS Server"));
}
// WINS
for (auto &ws : pull.wins_servers)
wins.push_back(IPv4::Addr::from_string(ws.address, "WINS Server"));
// DOMAIN
if (!pull.search_domains.empty())
domain = pull.search_domains[0].domain;
}
void ioctl(HANDLE th) const
{
// TAP_WIN_IOCTL_CONFIG_DHCP_MASQ
{
std::uint32_t ep[4];
ep[0] = vpn.ip.to_uint32_net();
ep[1] = vpn.netmask.to_uint32_net();
ep[2] = dhcp_serv_addr.to_uint32_net();
ep[3] = lease_time;
DWORD len;
if (!::DeviceIoControl(th,
TAP_WIN_IOCTL_CONFIG_DHCP_MASQ,
ep,
sizeof(ep),
ep,
sizeof(ep),
&len,
nullptr))
{
throw dhcp_masq("DeviceIoControl TAP_WIN_IOCTL_CONFIG_DHCP_MASQ failed");
}
}
// TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT
{
BufferAllocated buf(256, BufferAllocated::GROW);
write_options(buf);
DWORD len;
if (!::DeviceIoControl(th,
TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT,
buf.data(),
buf.size(),
buf.data(),
buf.size(),
&len,
nullptr))
{
throw dhcp_masq("DeviceIoControl TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT failed");
}
}
}
private:
void write_options(Buffer &buf) const
{
// DOMAIN
write_dhcp_str(buf, 15, domain);
// NBS
write_dhcp_str(buf, 47, netbios_scope);
// NBT
if (netbios_node_type)
write_dhcp_u8(buf, 46, netbios_node_type);
// DNS
write_dhcp_addr_list(buf, 6, dns);
// WINS
write_dhcp_addr_list(buf, 44, wins);
// NTP
write_dhcp_addr_list(buf, 42, ntp);
// NBDD
write_dhcp_addr_list(buf, 45, nbdd);
// DISABLE_NBT
//
// The MS DHCP server option 'Disable Netbios-over-TCP/IP
// is implemented as vendor option 001, value 002.
// A value of 001 means 'leave NBT alone' which is the default.
if (disable_nbt)
{
buf.push_back(43);
buf.push_back(6); // total length field
buf.push_back(0x001);
buf.push_back(4); // length of the vendor-specified field
{
const std::uint32_t raw = 0x002;
buf.write((const unsigned char *)&raw, sizeof(raw));
}
}
}
static void write_dhcp_u8(Buffer &buf,
const unsigned char type,
const unsigned char data)
{
buf.push_back(type);
buf.push_back(1);
buf.push_back(data);
}
static void write_dhcp_str(Buffer &buf,
const unsigned char type,
const std::string &str)
{
const size_t len = str.length();
if (len)
{
if (len > 255)
OPENVPN_THROW(dhcp_masq, "string '" << str << "' must be > 0 bytes and <= 255 bytes");
buf.push_back(type);
buf.push_back((unsigned char)len);
buf.write((const unsigned char *)str.c_str(), len);
}
}
static void write_dhcp_addr_list(Buffer &buf,
const unsigned char type,
const std::vector<IPv4::Addr> &addr_list)
{
if (!addr_list.empty())
{
const size_t size = addr_list.size() * sizeof(std::uint32_t);
if (size < 1 || size > 255)
OPENVPN_THROW(dhcp_masq, "array size=" << size << " must be > 0 bytes and <= 255 bytes");
buf.push_back(type);
buf.push_back((unsigned char)size);
for (auto &a : addr_list)
{
const std::uint32_t rawaddr = a.to_uint32_net();
buf.write((const unsigned char *)&rawaddr, sizeof(std::uint32_t));
}
}
}
};
class TAPDriverVersion
{
public:
@ -1167,7 +978,6 @@ inline const MIB_IPFORWARDTABLE *windows_routing_table()
return rt.release();
}
#if _WIN32_WINNT >= 0x0600 // Vista and higher
// Get the Windows IPv4/IPv6 routing table.
// Note that returned pointer must be freed with FreeMibTable.
inline const MIB_IPFORWARD_TABLE2 *windows_routing_table2(ADDRESS_FAMILY af)
@ -1179,7 +989,6 @@ inline const MIB_IPFORWARD_TABLE2 *windows_routing_table2(ADDRESS_FAMILY af)
else
return nullptr;
}
#endif
class BestGateway
{
@ -1342,9 +1151,7 @@ class ActionDeleteAllRoutesOnInterface : public Action
ActionList::Ptr actions = new ActionList();
remove_all_ipv4_routes_on_iface(iface_index, *actions);
#if _WIN32_WINNT >= 0x0600 // Vista and higher
remove_all_ipv6_routes_on_iface(iface_index, *actions);
#endif
actions->execute(os);
}
@ -1381,7 +1188,6 @@ class ActionDeleteAllRoutesOnInterface : public Action
}
}
#if _WIN32_WINNT >= 0x0600 // Vista and higher
static void remove_all_ipv6_routes_on_iface(DWORD index, ActionList &actions)
{
unique_ptr_del<const MIB_IPFORWARD_TABLE2> rt2(windows_routing_table2(AF_INET6),
@ -1413,7 +1219,6 @@ class ActionDeleteAllRoutesOnInterface : public Action
}
}
}
#endif
const DWORD iface_index;
};
@ -1569,5 +1374,3 @@ class AddRoute4Cmd : public Action
} // namespace Util
} // namespace TunWin
} // namespace openvpn
#endif

View File

@ -54,36 +54,22 @@ inline std::string call(const std::string &cmd)
else
name = cmd;
#if _WIN32_WINNT >= 0x0600
// get system path (Vista and higher)
// get system path
wchar_t *syspath_ptr = nullptr;
if (::SHGetKnownFolderPath(FOLDERID_System, 0, nullptr, &syspath_ptr) != S_OK)
throw win_call("cannot get system path using SHGetKnownFolderPath");
unique_ptr_del<wchar_t> syspath(syspath_ptr,
[](wchar_t *p)
{ ::CoTaskMemFree(p); });
#define SYSPATH_FMT_CHAR L"s"
#define SYSPATH_LEN_METH(x) ::wcslen(x)
#else
// get system path (XP and higher)
std::unique_ptr<wchar_t[]> syspath(new wchar_t[MAX_PATH]);
if (::SHGetFolderPathW(nullptr, CSIDL_SYSTEM, nullptr, 0, syspath.get()) != S_OK)
throw win_call("cannot get system path using SHGetFolderPathW");
#define SYSPATH_FMT_CHAR L"s"
#define SYSPATH_LEN_METH(x) ::wcslen(x)
#endif
// build command line
const size_t wcmdlen = SYSPATH_LEN_METH(syspath.get()) + name.length() + args.length() + 64;
const size_t wcmdlen = ::wcslen(syspath.get()) + name.length() + args.length() + 64;
std::unique_ptr<wchar_t[]> wcmd(new wchar_t[wcmdlen]);
const char *spc = "";
if (!args.empty())
spc = " ";
::_snwprintf(wcmd.get(), wcmdlen, L"\"%" SYSPATH_FMT_CHAR L"\\%S.exe\"%S%S", syspath.get(), name.c_str(), spc, args.c_str());
::_snwprintf(wcmd.get(), wcmdlen, L"\"%s\\%S.exe\"%S%S", syspath.get(), name.c_str(), spc, args.c_str());
wcmd.get()[wcmdlen - 1] = 0;
//::wprintf(L"CMD[%d]: %s\n", (int)::wcslen(wcmd.get()), wcmd.get());
#undef SYSPATH_FMT_CHAR
#undef SYSPATH_LEN_METH
// Set the bInheritHandle flag so pipe handles are inherited.
SECURITY_ATTRIBUTES saAttr;

View File

@ -69,11 +69,7 @@ struct NamedPipePeerInfo
{
// open process
Win::ScopedHANDLE proc(::OpenProcess(
#if _WIN32_WINNT >= 0x0600 // Vista and higher
limited ? (PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE) : PROCESS_ALL_ACCESS,
#else
PROCESS_ALL_ACCESS,
#endif
FALSE,
pid));
if (!proc.defined())
@ -84,8 +80,6 @@ struct NamedPipePeerInfo
return proc;
}
#if _WIN32_WINNT >= 0x0600 // Vista and higher
// Servers must call this method to modify their process
// access rights to grant clients the
// PROCESS_QUERY_LIMITED_INFORMATION right, so that clients
@ -163,12 +157,8 @@ struct NamedPipePeerInfo
}
return std::wstring(exe, exe_size);
}
#endif
};
#if _WIN32_WINNT >= 0x0600 // Vista and higher
struct NamedPipePeerInfoCS : public NamedPipePeerInfo
{
NamedPipePeerInfoCS(const HANDLE handle, const bool client)
@ -200,7 +190,5 @@ struct NamedPipePeerInfoServer : public NamedPipePeerInfoCS
}
};
#endif
} // namespace Win
} // namespace openvpn