]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added support for DHCP option 119 (dns search suffix list) for Windows.
authorJan Just Keijser <jan.just.keijser@gmail.com>
Tue, 14 Jul 2020 09:39:10 +0000 (11:39 +0200)
committerGert Doering <gert@greenie.muc.de>
Tue, 14 Jul 2020 12:46:41 +0000 (14:46 +0200)
As of Windows 10 1809 Windows finally supports this so it makes sense
to add support to OpenVPN as well.

Multiple options can be specified at the same time, with one search
domain per line (in the config, or pushed from server):

  dhcp-option DOMAIN-SEARCH my.company.domain
  dhcp-option DOMAIN-SEARCH some.example.domain

OpenVPN will (on windows) concatenate them all together into a single
"option 119" for the tapv9 DHCP server.  Max length is 254 in total.

DNS label compression is not used - it's complicated, and Windows does
not need it.  See RFC 3397 for more details.

This only works with the tun/tap driver, not with wintun.

On non-windows platforms, these settings are exported in the environment
towards --up scripts (or to the management interface), and need to be
picked up there.

Signed-off-by: Jan Just Keijser <jan.just.keijser@gmail.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <c404dd17-e0db-ce61-0d79-864a5736f2d0@nikhef.nl>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg20349.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/options.c
src/openvpn/tun.c
src/openvpn/tun.h

index bf2760e1e58b0f275b07eb74647f35079a22b448..b6b8d769facaa053f414867374be610d5b85bbda 100644 (file)
@@ -729,6 +729,7 @@ static const char usage_message[] =
     "                    which allow multiple addresses,\n"
     "                    --dhcp-option must be repeated.\n"
     "                    DOMAIN name : Set DNS suffix\n"
+    "                    DOMAIN-SEARCH entry : Add entry to DNS domain search list\n"
     "                    DNS addr    : Set domain name server address(es) (IPv4 and IPv6)\n"
     "                    NTP         : Set NTP server address(es)\n"
     "                    NBDD        : Set NBDD server address(es)\n"
@@ -1144,6 +1145,16 @@ parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_aren
 
 #ifndef ENABLE_SMALL
 
+static void
+show_dhcp_option_list(const char *name, const char * const*array, int len)
+{
+    int i;
+    for (i = 0; i < len; ++i)
+    {
+        msg(D_SHOW_PARMS, "  %s[%d] = %s", name, i, array[i] );
+    }
+}
+
 static void
 show_dhcp_option_addrs(const char *name, const in_addr_t *array, int len)
 {
@@ -1179,6 +1190,7 @@ show_tuntap_options(const struct tuntap_options *o)
     show_dhcp_option_addrs("WINS", o->wins, o->wins_len);
     show_dhcp_option_addrs("NTP", o->ntp, o->ntp_len);
     show_dhcp_option_addrs("NBDD", o->nbdd, o->nbdd_len);
+    show_dhcp_option_list("DOMAIN-SEARCH", o->domain_search_list, o->domain_search_list_len);
 }
 
 #endif /* ifndef ENABLE_SMALL */
@@ -7460,6 +7472,18 @@ add_option(struct options *options,
         {
             dhcp_option_address_parse("NBDD", p[2], o->nbdd, &o->nbdd_len, msglevel);
         }
+        else if (streq(p[1], "DOMAIN-SEARCH") && p[2])
+        {
+            if (o->domain_search_list_len < N_SEARCH_LIST_LEN)
+            {
+                o->domain_search_list[o->domain_search_list_len++] = p[2];
+            }
+            else
+            {
+                msg(msglevel, "--dhcp-option %s: maximum of %d search entries can be specified",
+                    p[1], N_SEARCH_LIST_LEN);
+            }
+        }
         else if (streq(p[1], "DISABLE-NBT") && !p[2])
         {
             o->disable_nbt = 1;
index 2a2df27fdad500f2e4af98a547d5c379b5e0a8e3..e96368ca7078d7d270747d7d9378dcbd3eef6755 100644 (file)
@@ -5673,6 +5673,75 @@ write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error)
     buf_write(buf, str, len);
 }
 
+/*
+ * RFC3397 states that multiple searchdomains are encoded as follows:
+ *  - at start the length of the entire option is given
+ *  - each subdomain is preceded by its length
+ *  - each searchdomain is separated by a NUL character
+ * e.g. if you want "openvpn.net" and "duckduckgo.com" then you end up with
+ *  0x1D  0x7 openvpn 0x3 net 0x00 0x0A duckduckgo 0x3 com 0x00
+ */
+static void
+write_dhcp_search_str(struct buffer *buf, const int type, const char * const *str_array,
+                      int array_len, bool *error)
+{
+    char         tmp_buf[256];
+    int          i;
+    int          len = 0;
+    int          label_length_pos;
+
+    for (i=0; i < array_len; i++)
+    {
+        const char  *ptr = str_array[i];
+
+        if (strlen(ptr) + len + 1 > sizeof(tmp_buf))
+        {
+            *error = true;
+            msg(M_WARN, "write_dhcp_search_str: temp buffer overflow building DHCP options");
+            return;
+        }
+        /* Loop over all subdomains separated by a dot and replace the dot
+           with the length of the subdomain */
+
+        /* label_length_pos points to the byte to be replaced by the length
+         * of the following domain label */
+        label_length_pos = len++;
+
+        while (true)
+        {
+            if (*ptr == '.' || *ptr == '\0' )
+            {
+                tmp_buf[label_length_pos] = (len-label_length_pos)-1;
+                label_length_pos = len;
+                if (*ptr == '\0')
+                {
+                    break;
+                }
+            }
+            tmp_buf[len++] = *ptr++;
+        }
+        /* And close off with an extra NUL char */
+        tmp_buf[len++] = 0;
+    }
+
+    if (!buf_safe(buf, 2 + len))
+    {
+        *error = true;
+        msg(M_WARN, "write_search_dhcp_str: buffer overflow building DHCP options");
+        return;
+    }
+    if (len > 255)
+    {
+        *error = true;
+        msg(M_WARN, "write_dhcp_search_str: search domain string must be <= 255 bytes");
+        return;
+    }
+
+    buf_write_u8(buf, type);
+    buf_write_u8(buf, len);
+    buf_write(buf, tmp_buf, len);
+}
+
 static bool
 build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o)
 {
@@ -5697,6 +5766,13 @@ build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o)
     write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error);
     write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error);
 
+    if (o->domain_search_list_len > 0)
+    {
+        write_dhcp_search_str(buf, 119, o->domain_search_list,
+                                        o->domain_search_list_len,
+                                       &error);
+    }
+
     /* 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 */
index b38e7e90bffacfec34d4a71aae26e77fb1a2d83e..99826cf78133798cdf82a201799bda56e2859fdc 100644 (file)
@@ -112,6 +112,12 @@ struct tuntap_options {
     in_addr_t nbdd[N_DHCP_ADDR];
     int nbdd_len;
 
+#define N_SEARCH_LIST_LEN 10 /* Max # of entries in domin-search list */
+
+    /* SEARCH (119), MacOS, Linux, Win10 1809+ */
+    const char *domain_search_list[N_SEARCH_LIST_LEN];
+    int domain_search_list_len;
+
     /* DISABLE_NBT (43, Vendor option 001) */
     bool disable_nbt;