41#if _WIN32_WINNT >= 0x0600
47#include <versionhelpers.h>
50#ifdef OPENVPN_USE_NETSH
51#define TUNWINDOWS Util::TunNETSH
53#define TUNWINDOWS Util::TunIPHELPER
62 Setup(openvpn_io::io_context &io_context_arg,
const Type tun_type,
bool allow_local_dns_resolvers_arg)
98 return INVALID_HANDLE_VALUE;
102 os <<
"TAP ADAPTERS:" << std::endl
106 std::string path_opened;
108 os <<
"Open TAP device \"" +
tap_.
name +
"\" PATH=\"" + path_opened +
'\"';
111 os <<
" FAILED" << std::endl;
115 os <<
" SUCCEEDED" << std::endl;
119 os << version.to_string() << std::endl;
127 const std::wstring &openvpn_app_path,
145 switch (pull.layer())
154 throw tun_win_setup(
"layer undefined");
173 return adapter_handle.
release();
182 const unsigned int route_delay = 5;
185 if (
l2_state->props_ready.defined())
205 std::ostream &os)
override
207 std::unique_ptr<L2State> l2s(std::move(
l2_state));
249 std::ostringstream os;
259 const std::string &route,
273 OPENVPN_LOG(
"Skip bypass route to " << route <<
", route is local");
282 const std::wstring &openvpn_app_path_arg)
338 ZeroMemory(&rings,
sizeof(rings));
344 rings.
send.
ring = ring_buffer->send_ring();
362 const std::wstring &openvpn_app_path,
374 const std::string ipv6_next_hop =
"fe80::8";
409 create.
add(
new WinCmd(
"netsh interface ip set interface " + tap_index_name +
" metric=9000"));
422 create.
add(
new WinCmd(
"netsh interface ip set address " + tap_index_name +
" static " + local4->
address +
' ' + netmask +
" gateway=" + local4->
gateway + metric +
" store=active"));
423 destroy.add(
new WinCmd(
"netsh interface ip delete address " + tap_index_name +
' ' + local4->
address +
" gateway=all store=active"));
428 WinCmd::Ptr cmd_delroute =
new WinCmd(
"netsh interface ip delete route 0.0.0.0/0 " + tap_index_name +
' ' + local4->
gateway +
" store=active");
431 WinCmd::Ptr cmd_setmetric =
new WinCmd(
"netsh interface ip set interface " + tap_index_name +
" metric=1");
435 cmd_delroute = std::move(cmd_delroute),
436 cmd_setmetric = std::move(cmd_setmetric)](
const openvpn_io::error_code &error)
440 std::ostringstream os;
450 static const char *
const block_ipv6_net[] = {
455 for (
size_t i = 0; i <
array_size(block_ipv6_net); ++i)
457 create.
add(
new WinCmd(
"netsh interface ipv6 add route " + std::string(block_ipv6_net[i]) +
" interface=1 store=active"));
458 destroy.add(
new WinCmd(
"netsh interface ipv6 delete route " + std::string(block_ipv6_net[i]) +
" interface=1 store=active"));
473 create.
add(
new WinCmd(
"netsh interface ipv6 set address " + tap_index_name +
' ' + local6->
address +
" store=active"));
474 destroy.add(
new WinCmd(
"netsh interface ipv6 delete address " + tap_index_name +
' ' + local6->
address +
" store=active"));
509 create.
add(
new WinCmd(
"netsh interface ipv6 add route " + route.address +
'/' +
to_string(route.prefix_length) +
' ' + tap_index_name +
' ' + ipv6_next_hop + metric +
" store=active"));
510 destroy.add(
new WinCmd(
"netsh interface ipv6 delete route " + route.address +
'/' +
to_string(route.prefix_length) +
' ' + tap_index_name +
' ' + ipv6_next_hop +
" store=active"));
518 if (route.metric >= 0)
519 metric = route.metric;
520 create.
add(
new TUNWINDOWS::AddRoute4Cmd(route.address, route.prefix_length, tap.
index, tap.
name, local4->
gateway, metric,
true));
521 destroy.add(
new TUNWINDOWS::AddRoute4Cmd(route.address, route.prefix_length, tap.
index, tap.
name, local4->
gateway, metric,
false));
524 throw tun_win_setup(
"IPv4 routes pushed without IPv4 ifconfig");
535 bool ipv6_error =
false;
539 if (route.metric >= 0)
540 metric = route.metric;
548 create.
add(
new TUNWINDOWS::AddRoute4Cmd(route.address, route.prefix_length, gw.interface_index(),
"", gw.gateway_address(), metric,
true));
549 destroy.add(
new TUNWINDOWS::AddRoute4Cmd(route.address, route.prefix_length, gw.interface_index(),
"", gw.gateway_address(), metric,
false));
553 os <<
"NOTE: exclude IPv6 routes not currently supported" << std::endl;
556 os <<
"NOTE: exclude routes error: cannot detect default gateway" << std::endl;
566 if (!gw.local_route())
575 throw tun_win_setup(
"redirect-gateway error: cannot find gateway for bypass route");
578 create.
add(
new WinCmd(
"netsh interface ip add route 0.0.0.0/1 " + tap_index_name +
' ' + local4->
gateway +
" store=active"));
579 create.
add(
new WinCmd(
"netsh interface ip add route 128.0.0.0/1 " + tap_index_name +
' ' + local4->
gateway +
" store=active"));
580 destroy.add(
new WinCmd(
"netsh interface ip delete route 0.0.0.0/1 " + tap_index_name +
' ' + local4->
gateway +
" store=active"));
581 destroy.add(
new WinCmd(
"netsh interface ip delete route 128.0.0.0/1 " + tap_index_name +
' ' + local4->
gateway +
" store=active"));
587 create.
add(
new WinCmd(
"netsh interface ipv6 add route 0::/1 " + tap_index_name +
' ' + ipv6_next_hop +
" store=active"));
588 create.
add(
new WinCmd(
"netsh interface ipv6 add route 8000::/1 " + tap_index_name +
' ' + ipv6_next_hop +
" store=active"));
589 destroy.add(
new WinCmd(
"netsh interface ipv6 delete route 0::/1 " + tap_index_name +
' ' + ipv6_next_hop +
" store=active"));
590 destroy.add(
new WinCmd(
"netsh interface ipv6 delete route 8000::/1 " + tap_index_name +
' ' + ipv6_next_hop +
" store=active"));
595 const bool use_wfp = IsWindows8OrGreater();
597 if (use_wfp && block_local_traffic && !openvpn_app_path.empty())
612 std::vector<std::string> addresses;
613 std::vector<std::string> split_domains;
614 std::vector<std::wstring> wide_search_domains;
615 std::string search_domains;
622 bool custom_port = std::any_of(server.addresses.begin(),
623 server.addresses.end(),
625 { return a.port != 0 && a.port != 53; });
626 if (secure_transport || custom_port)
632 for (
const auto &addr : server.addresses)
634 addresses.push_back(addr.address);
638 for (
const auto &dom : server.domains)
640 split_domains.push_back(
"." + dom.domain);
643 std::string delimiter;
646 wide_search_domains.emplace_back(wstring::from_utf8(domain.to_string()));
647 search_domains.append(delimiter + domain.to_string());
658 throw tun_win_setup(
"no applicable DNS server config found");
687 const bool use_nrpt = IsWindows8OrGreater();
694 const bool split_dns = (!server.
domains.empty()
699 if (!(use_nrpt && split_dns) && !l2_post)
718 std::string dns_servers_cmd =
"dnsservers";
719 std::string validate_cmd =
" validate=no";
720 if (IsWindowsVistaOrGreater() && !IsWindows7OrGreater())
722 dns_servers_cmd =
"dnsserver";
730 const int count = dc.
add(ip, pull);
733 const std::string proto =
IP::Addr(ip.address).
is_ipv6() ?
"ipv6" :
"ip";
735 create.
add(
new WinCmd(
"netsh interface " + proto +
" add " + dns_servers_cmd +
" " + tap_index_name +
' ' + ip.address +
" " +
to_string(count + 1) + validate_cmd));
738 create.
add(
new WinCmd(
"netsh interface " + proto +
" set " + dns_servers_cmd +
" " + tap_index_name +
" static " + ip.address +
" register=primary" + validate_cmd));
739 destroy.add(
new WinCmd(
"netsh interface " + proto +
" delete " + dns_servers_cmd +
" " + tap_index_name +
" all" + validate_cmd));
751 if (use_nrpt && (dns.
ipv4() || dns.
ipv6()))
754 std::vector<std::string> split_domains;
760 for (
const auto &sd : server.
domains)
762 std::string dom = sd.domain;
768 split_domains.push_back(std::move(dom));
774 std::vector<std::string> dserv;
781 std::vector<std::wstring> wide_search_domains;
784 wide_search_domains.emplace_back(wstring::from_utf8(domain.to_string()));
809 && !openvpn_app_path.empty() && (dns.
ipv4() || dns.
ipv6()))
816 create.
add(
new WinCmd(
"ipconfig /flushdns"));
832 create.
add(
new WinCmd(
"netsh interface ip add winsservers " + tap_index_name +
' ' + ws.
address +
' ' +
to_string(i + 1)));
835 create.
add(
new WinCmd(
"netsh interface ip set winsservers " + tap_index_name +
" static " + ws.
address));
836 destroy.add(
new WinCmd(
"netsh interface ip delete winsservers " + tap_index_name +
" all"));
843 ProxySettings::add_actions<WinProxySettings>(pull, create,
destroy);
847 const std::wstring &openvpn_app_path,
859 os <<
"TAP: DHCP is disabled, attempting to enable" << std::endl;
881 std::ostringstream os;
887 std::ostringstream os;
912 return " METRIC " + std::to_string(metric);
914 return " metric=" + std::to_string(metric);
916 return " gwmetric=" + std::to_string(metric);
922#if _WIN32_WINNT >= 0x0600
void destroy(std::ostream &os) override
virtual std::unordered_set< std::string > execute(std::ostream &os)
Executes a sequence of actions and returns marks of failed actions.
void enable_destroy(const bool state)
std::size_t expires_after(const Time::Duration &d)
static Addr from_string(const std::string &ipstr, const TITLE &title, const Version required_version)
std::string to_string() const
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
std::string to_string() const
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
unsigned char prefix_length
RemoteAddress remote_address
std::vector< Route > add_routes
ProxyAutoConfigURL proxy_auto_config_url
const RouteAddress * vpn_ipv6() const
const RouteAddress * vpn_ipv4() const
std::vector< Route > exclude_routes
std::vector< WINSServer > wins_servers
UseDNS(const TunBuilderCapture &pull)
static bool enabled(const DnsAddress &addr, const TunBuilderCapture &pull)
int add(const DnsAddress &addr, const TunBuilderCapture &pull)
void set_process_id(DWORD process_id)
Set the process id to be used with the NPRT rules.
Util::TapNameGuidPair tap_
static void add_bypass_route(const Util::BestGateway &gw, const std::string &route, bool ipv6, ActionList &add_cmds, ActionList &remove_cmds_bypass_gw)
void l2_finish(const TunBuilderCapture &pull, Stop *stop, std::ostream &os) override
void destroy(std::ostream &os) override
void register_rings(HANDLE handle, RingBuffer::Ptr ring_buffer)
std::unique_ptr< L2State > l2_state
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)
DWORD vpn_interface_index() const
ActionList::Ptr remove_cmds
bool allow_local_dns_resolvers
void adapter_config_l2(HANDLE th, const std::wstring &openvpn_app_path, const Util::TapNameGuidPair &tap, const TunBuilderCapture &pull, ActionList &create, ActionList &destroy, std::ostream &os)
static std::string route_metric_opt(const TunBuilderCapture &pull, const TunBuilderCapture::RouteBase &route, const MetricType mt)
Setup(openvpn_io::io_context &io_context_arg, const Type tun_type, bool allow_local_dns_resolvers_arg)
DWORD vpn_interface_index_
bool l2_ready(const TunBuilderCapture &pull) override
std::unique_ptr< std::thread > l2_thread
AsioTimer delete_route_timer
Util::TapNameGuidPair get_adapter_state() override
HANDLE establish(const TunBuilderCapture &pull, const std::wstring &openvpn_app_path, Stop *stop, std::ostream &os, RingBuffer::Ptr ring_buffer) override
HANDLE get_handle(std::ostream &os) override
void set_adapter_state(const Util::TapNameGuidPair &tap) override
const std::string & gateway_address() const
DWORD interface_index() const
Wrapper class for a WFP session.
Block
Enum for type of local traffic to block.
virtual void execute(std::ostream &os) override
#define OPENVPN_LOG(args)
#define OPENVPN_LOG_STRING(str)
@ TUN_REGISTER_RINGS_ERROR
void flush_arp(const DWORD adapter_index, std::ostream &os)
void dhcp_release(const InterfaceInfoList &ii, const DWORD adapter_index, std::ostream &os)
HANDLE tap_open(const Type tun_type, const TapNameGuidPairList &guids, std::string &path_opened, TapNameGuidPair &used)
void tap_configure_topology_subnet(HANDLE th, const IP::Addr &local, const unsigned int prefix_len)
void dhcp_renew(const InterfaceInfoList &ii, const DWORD adapter_index, std::ostream &os)
void tap_set_media_status(HANDLE th, bool media_status)
void tap_configure_topology_net30(HANDLE th, const IP::Addr &local_addr, const IP::Addr &remote_addr)
DNS utilities for Windows.
std::string to_string(T value)
constexpr std::size_t array_size(T(&)[N])
#define TUN_IOCTL_REGISTER_RINGS
A name server address and optional port.
std::map< int, DnsServer > servers
std::vector< DnsDomain > search_domains
DNS settings for a name server.
std::vector< DnsAddress > addresses
std::vector< DnsDomain > domains
Argument to construct a Context in a different thread.
Scoped RAII for the global_log pointer.
Util::TapNameGuidPair tap
L2State(const Util::TapNameGuidPair &tap_arg, const std::wstring &openvpn_app_path_arg)
std::wstring openvpn_app_path
struct openvpn::TunWin::TUN_REGISTER_RINGS::@118 receive
struct openvpn::TunWin::TUN_REGISTER_RINGS::@118 send
UCHAR data[WINTUN_RING_CAPACITY+WINTUN_RING_TRAILING_BYTES+WINTUN_RING_FRAMING_SIZE]
bool is_up(const DWORD index, const IPNetmask4 &vpn_addr) const
bool is_dhcp_enabled(const DWORD index) const
std::string to_string() const
bool index_defined() const
std::string index_or_name() const