]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Handle --dhcp-option DNS6 on Windows using netsh
authorSelva Nair <selva.nair@gmail.com>
Tue, 22 Nov 2016 03:12:12 +0000 (22:12 -0500)
committerGert Doering <gert@greenie.muc.de>
Tue, 22 Nov 2016 16:26:08 +0000 (17:26 +0100)
v2: On closing tun delete the ipv6 dns addresses (if any were set).
Also use "validate=no" only in Windows 7 and higher where it is
supported. Its used to skip the time consuming automatic address
validation which is on by default on those platforms.

Tested on Windows Server 2008 (i686), Win 7 (x64) and Win 10 (x64)

TODO: set dns servers using the interactive service

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1479784332-21680-1-git-send-email-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13193.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
doc/openvpn.8
src/openvpn/options.c
src/openvpn/tun.c
src/openvpn/tun.h

index d454a3659d72002739523cb676844da413743634..171bd724354db4b556b7113719e846250c9e2d28 100644 (file)
@@ -5634,13 +5634,12 @@ this option to set secondary DNS server addresses.
 Set primary domain name server IPv6 address.  Repeat
 this option to set secondary DNS server IPv6 addresses.
 
-Note: currently this is somewhat of a placeholder option - it is
-understood, but OpenVPN has no code to tell Windows about it (the
+Note: currently this is handled using netsh and requires admin rights (the
 existing DHCP code can only do IPv4 DHCP, and that protocol only
 permits IPv4 addresses anywhere).  The option will be put into the
 environment, so an
 .B \-\-up
-script could act upon it.
+script could act upon it if needed.
 
 .B WINS addr \-\-
 Set primary WINS server address (NetBIOS over TCP/IP Name Server).
index f30e62dd7bd6ebcc98eea2a3484ddd1de3586720..8e09e4a00b622edc7f16d5f4c9a0739027f039dc 100644 (file)
@@ -6407,13 +6407,19 @@ add_option (struct options *options,
        {
          dhcp_option_address_parse ("DNS", p[2], o->dns, &o->dns_len, msglevel);
        }
-      else if (streq (p[1], "DNS6") && p[2])
+      else if (streq (p[1], "DNS6") && p[2] && ipv6_addr_safe(p[2]))
        {
-         /* this is somewhat of a placeholder - we understand the option,
-          * but cannot act upon it - so we'll just accept it and put it
-          * into the environment, as we would do on all non-win32 platforms
-          */
+         struct in6_addr addr;
          foreign_option (options, p, 3, es);
+         if (o->dns6_len >= N_DHCP_ADDR)
+           {
+             msg (msglevel, "--dhcp-option DNS6: maximum of %d dns servers can be specified",
+                  N_DHCP_ADDR);
+           }
+         else if (get_ipv6_addr (p[2], &addr, NULL, msglevel))
+           {
+             o->dns6[o->dns6_len++] = addr;
+           }
        }
       else if (streq (p[1], "WINS") && p[2])
        {
index 36e0b15be10abb041f6583121a7150c8b17bfa97..a079f4718d217621d1a92bbd89ed60a446c8da7c 100644 (file)
@@ -68,6 +68,9 @@ static void netsh_ifconfig (const struct tuntap_options *to,
                            const in_addr_t ip,
                            const in_addr_t netmask,
                            const unsigned int flags);
+static void netsh_set_dns6_servers (const struct in6_addr *addr_list,
+                                   const int addr_len,
+                                   const char *flex_name);
 static void netsh_command (const struct argv *a, int n, int msglevel);
 
 static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
@@ -1381,6 +1384,7 @@ do_ifconfig (struct tuntap *tt,
        else if (tt->options.msg_channel)
          {
            do_address_service (true, AF_INET6, tt);
+           /* TODO: do_dns6_service() */
          }
        else
          {
@@ -1394,6 +1398,8 @@ do_ifconfig (struct tuntap *tt,
                         iface,
                         ifconfig_ipv6_local );
            netsh_command (&argv, 4, M_FATAL);
+           /* set ipv6 dns servers if any are specified */
+           netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, actual);
          }
 
        /* explicit route needed */
@@ -4626,6 +4632,41 @@ ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias)
   return false;
 }
 
+/**
+ * Set the ipv6 dns servers on the specified interface.
+ * The list of dns servers currently set on the interface
+ * are cleared first.
+ * No action is taken if number of addresses (addr_len) < 1.
+ */
+static void
+netsh_set_dns6_servers (const struct in6_addr *addr_list,
+                       const int addr_len,
+                       const char *flex_name)
+{
+    struct gc_arena gc = gc_new ();
+    struct argv argv = argv_new ();
+
+    for (int i = 0; i < addr_len; ++i)
+    {
+       const char *fmt = (i == 0) ?
+           "%s%sc interface ipv6 set dns %s static %s"
+           : "%s%sc interface ipv6 add dns %s %s";
+       argv_printf (&argv, fmt, get_win_sys_path(),
+                    NETSH_PATH_SUFFIX, flex_name,
+                    print_in6_addr (addr_list[i], 0, &gc));
+
+       /* disable slow address validation on Windows 7 and higher */
+       if (win32_version_info() >= WIN_7)
+           argv_printf_cat (&argv, "%s", "validate=no");
+
+       /* Treat errors while adding as non-fatal as we do not check for duplicates */
+       netsh_command (&argv, 1, (i==0)? M_FATAL : M_NONFATAL);
+    }
+
+    argv_reset (&argv);
+    gc_free (&gc);
+}
+
 static void
 netsh_ifconfig_options (const char *type,
                        const in_addr_t *addr_list,
@@ -5572,6 +5613,17 @@ close_tun (struct tuntap *tt)
                            ifconfig_ipv6_local);
 
               netsh_command (&argv, 1, M_WARN);
+
+             /* delete ipv6 dns servers if any were set */
+             if (tt->options.dns6_len > 0)
+               {
+                 argv_printf (&argv,
+                              "%s%sc interface ipv6 delete dns %s all",
+                              get_win_sys_path(),
+                              NETSH_PATH_SUFFIX,
+                              tt->actual_name);
+                 netsh_command (&argv, 1, M_WARN);
+               }
               argv_reset (&argv);
             }
        }
index dedd915c350ad260717fa487c619efc172226992..9b5a1b7cca6330248a8ea45b95b2c247d46d649b 100644 (file)
@@ -107,6 +107,9 @@ struct tuntap_options {
   bool dhcp_release;
 
   bool register_dns;
+
+  struct in6_addr dns6[N_DHCP_ADDR];
+  int dns6_len;
 };
 
 #elif TARGET_LINUX