Skip to content

Commit

Permalink
Support of DNS domain for DHCP-less drivers
Browse files Browse the repository at this point in the history
We set DNS domain either via interactve service or DHCP.
When interactive service is not used, for example,
when profiles are started by OpenVPNService, this option
is not working for DCO and wintun.

This implements setting DNS domain via WMIC command,
similar to implementation in interactive service.
This is done when:

 - interactive service is not used
 - ip_win32_type is either METSH or IPAPI, which is
the case for DCO and wintun.

Fixes OpenVPN#306

Change-Id: I9ab51bf1c0774564204c75ecce9ebfb818db2f5b
  • Loading branch information
lstipakov committed Apr 3, 2023
1 parent 253a87d commit 7b50c66
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 20 deletions.
8 changes: 3 additions & 5 deletions src/openvpn/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -3396,20 +3396,18 @@ options_postprocess_mutate_invariant(struct options *options)
#ifdef _WIN32
const int dev = dev_type_enum(options->dev, options->dev_type);

const bool dhcp = tuntap_maybe_dhcp(&options->tuntap_options);

/* when using wintun/ovpn-dco, kernel doesn't send DHCP requests, so don't use it */
if ((options->windows_driver == WINDOWS_DRIVER_WINTUN
|| options->windows_driver == WINDOWS_DRIVER_DCO)
&& (options->tuntap_options.ip_win32_type == IPW32_SET_DHCP_MASQ
|| options->tuntap_options.ip_win32_type == IPW32_SET_ADAPTIVE))
|| options->windows_driver == WINDOWS_DRIVER_DCO) && dhcp)
{
options->tuntap_options.ip_win32_type = IPW32_SET_NETSH;
}

if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined)
{
/* delay may only be necessary when we perform DHCP handshake */
const bool dhcp = (options->tuntap_options.ip_win32_type == IPW32_SET_DHCP_MASQ)
|| (options->tuntap_options.ip_win32_type == IPW32_SET_ADAPTIVE);
if ((options->mode == MODE_POINT_TO_POINT) && dhcp)
{
options->route_delay_defined = true;
Expand Down
72 changes: 57 additions & 15 deletions src/openvpn/tun.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ static void netsh_set_dns6_servers(const struct in6_addr *addr_list,

static void netsh_command(const struct argv *a, int n, int msglevel);

static void exec_command(const char *prefix, const struct argv *a, int n, int msglevel);

static const char *netsh_get_id(const char *dev_node, struct gc_arena *gc);

static bool
Expand Down Expand Up @@ -324,6 +326,22 @@ do_set_mtu_service(const struct tuntap *tt, const short family, const int mtu)
return ret;
}

static void
wmic_do_dns_domain(bool add, const struct tuntap *tt)
{
if (!tt->options.domain)
{
return;
}

struct argv argv = argv_new();
argv_printf(&argv, "%s%s nicconfig where (InterfaceIndex=%ld) call SetDNSDomain %s",
get_win_sys_path(), WMIC_PATH_SUFFIX, tt->adapter_index, add ? tt->options.domain : "");
exec_command("WMIC", &argv, 1, M_WARN);

argv_free(&argv);
}

#endif /* ifdef _WIN32 */

#ifdef TARGET_SOLARIS
Expand Down Expand Up @@ -1190,6 +1208,11 @@ do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu,
/* set ipv6 dns servers if any are specified */
netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, tt->adapter_index);
windows_set_mtu(tt->adapter_index, AF_INET6, tun_mtu);

if (!tt->did_ifconfig_setup && !tuntap_maybe_dhcp(&tt->options))
{
wmic_do_dns_domain(true, tt);
}
}
#else /* platforms we have no IPv6 code for */
msg(M_FATAL, "Sorry, but I don't know how to do IPv6 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script.");
Expand Down Expand Up @@ -1525,7 +1548,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
ifname, ifconfig_local,
ifconfig_remote_netmask);
}
else if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ || tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
else if (tuntap_maybe_dhcp(&tt->options))
{
/* Let the DHCP configure the interface. */
}
Expand All @@ -1535,11 +1558,18 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
do_dns_service(true, AF_INET, tt);
do_dns_domain_service(true, tt);
}
else if (tt->options.ip_win32_type == IPW32_SET_NETSH)
else
{
netsh_ifconfig(&tt->options, tt->adapter_index, tt->local,
tt->adapter_netmask, NI_IP_NETMASK|NI_OPTIONS);
if (tt->options.ip_win32_type == IPW32_SET_NETSH)
{
netsh_ifconfig(&tt->options, tt->adapter_index, tt->local,
tt->adapter_netmask, NI_IP_NETMASK | NI_OPTIONS);
}

wmic_do_dns_domain(true, tt);
}


if (tt->options.msg_channel)
{
do_set_mtu_service(tt, AF_INET, tun_mtu);
Expand Down Expand Up @@ -5238,29 +5268,31 @@ dhcp_renew(const struct tuntap *tt)
}
}

/*
* netsh functions
*/

static void
netsh_command(const struct argv *a, int n, int msglevel)
exec_command(const char *prefix, const struct argv *a, int n, int msglevel)
{
int i;
for (i = 0; i < n; ++i)
{
bool status;
management_sleep(0);
netcmd_semaphore_lock();
argv_msg_prefix(M_INFO, a, "NETSH");
status = openvpn_execve_check(a, NULL, 0, "ERROR: netsh command failed");
argv_msg_prefix(M_INFO, a, prefix);
status = openvpn_execve_check(a, NULL, 0, "ERROR: command failed");
netcmd_semaphore_release();
if (status)
{
return;
}
management_sleep(4);
}
msg(msglevel, "NETSH: command failed");
msg(msglevel, "%s: command failed", prefix);
}

static void
netsh_command(const struct argv *a, int n, int msglevel)
{
exec_command("NETSH", a, n, msglevel);
}

void
Expand Down Expand Up @@ -6927,6 +6959,11 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
}
else
{
if (!tt->did_ifconfig_setup && !tuntap_maybe_dhcp(&tt->options))
{
wmic_do_dns_domain(false, tt);
}

netsh_delete_address_dns(tt, true, &gc);
}
}
Expand All @@ -6937,7 +6974,7 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
/* We didn't do ifconfig. */
}
else if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ || tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
else if (tuntap_maybe_dhcp(&tt->options))
{
/* We don't have to clean the configuration with DHCP. */
}
Expand All @@ -6947,9 +6984,14 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
do_dns_service(false, AF_INET, tt);
do_address_service(false, AF_INET, tt);
}
else if (tt->options.ip_win32_type == IPW32_SET_NETSH)
else
{
netsh_delete_address_dns(tt, false, &gc);
wmic_do_dns_domain(false, tt);

if (tt->options.ip_win32_type == IPW32_SET_NETSH)
{
netsh_delete_address_dns(tt, false, &gc);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/openvpn/tun.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,12 @@ tuntap_is_dco_win_timeout(struct tuntap *tt, int status)
const char *
print_windows_driver(enum windows_driver_type windows_driver);

static inline bool
tuntap_maybe_dhcp(struct tuntap_options *o)
{
return o->ip_win32_type == IPW32_SET_DHCP_MASQ || o->ip_win32_type == IPW32_SET_ADAPTIVE;
}

#else /* ifdef _WIN32 */

static inline bool
Expand Down
1 change: 1 addition & 0 deletions src/openvpn/win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#define WIN_ROUTE_PATH_SUFFIX "\\system32\\route.exe"
#define WIN_IPCONFIG_PATH_SUFFIX "\\system32\\ipconfig.exe"
#define WIN_NET_PATH_SUFFIX "\\system32\\net.exe"
#define WMIC_PATH_SUFFIX "\\system32\\wbem\\wmic.exe"

/*
* Win32-specific OpenVPN code, targeted at the mingw
Expand Down

0 comments on commit 7b50c66

Please sign in to comment.