[Openvpn-devel,v2] Support of DNS domain for DHCP-less drivers

Message ID 20230406071546.1056-1-lstipakov@gmail.com
State Accepted
Headers show
Series [Openvpn-devel,v2] Support of DNS domain for DHCP-less drivers | expand

Commit Message

Lev Stipakov April 6, 2023, 7:15 a.m. UTC
From: Lev Stipakov <lev@openvpn.net>

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

 - DHCP is not used (ip-win32 is either NETSH or IPAPI,
 or IPv4 address is not pushed)

Fixes https://github.com/OpenVPN/openvpn/issues/306

Change-Id: Ic72a4ecd0414c0d7bf013415f52640fd122cb739
Signed-off-by: Lev Stipakov <lev@openvpn.net>
---
 v2:
  - remove tuntap_maybe_dhcp() check in ipv6 setup/teardown,
  because we still need wmic call in this case

  - remove the whole tuntap_maybe_dhcp() function, because
  let's do refactoring separately

  - rename wmic_do_dns_domain() to do_dns_domain_wmic() to be
  consistent with do_dns_domain_service()

 src/openvpn/tun.c   | 68 ++++++++++++++++++++++++++++++++++++---------
 src/openvpn/win32.h |  1 +
 2 files changed, 56 insertions(+), 13 deletions(-)

Comments

Selva Nair April 7, 2023, 1:16 a.m. UTC | #1
Hi

On Thu, Apr 6, 2023 at 3:17 AM Lev Stipakov <lstipakov@gmail.com> wrote:

> From: Lev Stipakov <lev@openvpn.net>
>
> 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
>
>  - DHCP is not used (ip-win32 is either NETSH or IPAPI,
>  or IPv4 address is not pushed)
>
> Fixes https://github.com/OpenVPN/openvpn/issues/306
>
> Change-Id: Ic72a4ecd0414c0d7bf013415f52640fd122cb739
> Signed-off-by: Lev Stipakov <lev@openvpn.net>
> ---
>  v2:
>   - remove tuntap_maybe_dhcp() check in ipv6 setup/teardown,
>   because we still need wmic call in this case
>
>   - remove the whole tuntap_maybe_dhcp() function, because
>   let's do refactoring separately
>
>   - rename wmic_do_dns_domain() to do_dns_domain_wmic() to be
>   consistent with do_dns_domain_service()
>
>  src/openvpn/tun.c   | 68 ++++++++++++++++++++++++++++++++++++---------
>  src/openvpn/win32.h |  1 +
>  2 files changed, 56 insertions(+), 13 deletions(-)
>
> diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
> index 2ebe4809..2320e8b1 100644
> --- a/src/openvpn/tun.c
> +++ b/src/openvpn/tun.c
> @@ -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
> @@ -324,6 +326,22 @@ out:
>      return ret;
>  }
>
> +static void
> +do_dns_domain_wmic(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
> @@ -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)
> +        {
> +            do_dns_domain_wmic(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.");
> @@ -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);
> +        }
> +
> +        do_dns_domain_wmic(true, tt);
>      }
> +
> +
>      if (tt->options.msg_channel)
>      {
>          do_set_mtu_service(tt, AF_INET, tun_mtu);
> @@ -5238,12 +5268,8 @@ 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)
> @@ -5251,8 +5277,8 @@ netsh_command(const struct argv *a, int n, int
> msglevel)
>          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)
>          {
> @@ -5260,7 +5286,13 @@ netsh_command(const struct argv *a, int n, int
> msglevel)
>          }
>          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
> @@ -6927,6 +6959,11 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
>          }
>          else
>          {
> +            if (!tt->did_ifconfig_setup)
> +            {
> +                do_dns_domain_wmic(false, tt);
> +            }
> +
>              netsh_delete_address_dns(tt, true, &gc);
>          }
>      }
> @@ -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);
> +            do_dns_domain_wmic(false, tt);
> +
> +            if (tt->options.ip_win32_type == IPW32_SET_NETSH)
> +            {
> +                netsh_delete_address_dns(tt, false, &gc);
> +            }
>          }
>      }
>
> diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h
> index 72ffb012..36059662 100644
> --- a/src/openvpn/win32.h
> +++ b/src/openvpn/win32.h
> @@ -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
>

Acked-by: Selva Nair <selva.nair@gmail.com>

Useful to have in 2.6 as well, as dco is the default now. The changes are
minimal and should not have any side effects.

Did some quick test runs on Win 10 using tap-windows6 and dco drivers with
and without "dhcp-option DOMAIN".

Selva
Gert Doering April 11, 2023, 2:33 p.m. UTC | #2
I haven't tested this beyond "compiles with MinGW" and "Github actions",
but stared a bit at the code and it looks okay.

This can be considered a bugfix, so 2.6 as well.

Your patch has been applied to the master and release/2.6 branch.

commit 6cf7ce4eb33626b861031f965b35c3107d75e843 (master)
commit 77a74357e3f9a5a18665d387e7c268f0c8cb975c (release/2.6)
Author: Lev Stipakov
Date:   Thu Apr 6 10:15:46 2023 +0300

     Support of DNS domain for DHCP-less drivers

     Signed-off-by: Lev Stipakov <lev@openvpn.net>
     Acked-by: Selva Nair <selva.nair@gmail.com>
     Message-Id: <20230406071546.1056-1-lstipakov@gmail.com>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg26582.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 2ebe4809..2320e8b1 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -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
@@ -324,6 +326,22 @@  out:
     return ret;
 }
 
+static void
+do_dns_domain_wmic(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
@@ -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)
+        {
+            do_dns_domain_wmic(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.");
@@ -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);
+        }
+
+        do_dns_domain_wmic(true, tt);
     }
+
+
     if (tt->options.msg_channel)
     {
         do_set_mtu_service(tt, AF_INET, tun_mtu);
@@ -5238,12 +5268,8 @@  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)
@@ -5251,8 +5277,8 @@  netsh_command(const struct argv *a, int n, int msglevel)
         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)
         {
@@ -5260,7 +5286,13 @@  netsh_command(const struct argv *a, int n, int msglevel)
         }
         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
@@ -6927,6 +6959,11 @@  close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
         }
         else
         {
+            if (!tt->did_ifconfig_setup)
+            {
+                do_dns_domain_wmic(false, tt);
+            }
+
             netsh_delete_address_dns(tt, true, &gc);
         }
     }
@@ -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);
+            do_dns_domain_wmic(false, tt);
+
+            if (tt->options.ip_win32_type == IPW32_SET_NETSH)
+            {
+                netsh_delete_address_dns(tt, false, &gc);
+            }
         }
     }
 
diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h
index 72ffb012..36059662 100644
--- a/src/openvpn/win32.h
+++ b/src/openvpn/win32.h
@@ -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