[PATCH] 7006496: Use modern Windows API to retrieve OS DNS servers

Anuraag Agrawal anuraaga at gmail.com
Wed Dec 18 06:08:23 UTC 2019


Hi Aleksei,

Thanks for all the reviews, it's really helped a lot. Just wondering, is
there anything we need to go to finish getting approvals?

Thanks,
- Anuraag

On Sat, Dec 14, 2019 at 12:35 AM Aleks Efimov <aleksej.efimov at oracle.com>
wrote:

> Hi Anuraag,
>
> Thank you for moving the site-local/link-local check to the native code.
> The latest version of your changes looks good to me. Webrev of it can be
> viewed here:
> http://cr.openjdk.java.net/~aefimov/anuraaga/7006496/03/
>
> Our CI system is also happy with it.
>
> With Best Regards,
> Aleksei
>
>
> On 12/12/2019 13:26, Anuraag Agrawal wrote:
>
> Hi Aleksei,
>
> I've gone ahead and moved the site-local check to native code - it does
> reduce the chance of filling up our buffer, though the code is a bit more
> complicated. To get sockaddr_in6, I went ahead and switched the imports to
> net_util.h, which I noticed was used in other files. Let me know if it
> looks ok.
>
> Inline patch follows
>
> diff --git
> a/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
> b/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
> index 2250b3158e..c3ebe09776 100644
> ---
> a/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
> +++
> b/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
> @@ -25,9 +25,9 @@
>
>  package sun.net.dns;
>
> +import java.util.ArrayList;
>  import java.util.List;
> -import java.util.LinkedList;
> -import java.util.StringTokenizer;
> +import java.util.concurrent.TimeUnit;
>
>  /*
>   * An implementation of sun.net.ResolverConfiguration for Windows.
> @@ -50,30 +50,55 @@ public class ResolverConfigurationImpl
>
>      // Cache timeout (120 seconds) - should be converted into property
>      // or configured as preference in the future.
> -    private static final int TIMEOUT = 120000;
> +    private static final long TIMEOUT_NANOS =
> TimeUnit.SECONDS.toNanos(120);
>
>      // DNS suffix list and name servers populated by native method
>      private static String os_searchlist;
>      private static String os_nameservers;
>
>      // Cached lists
> -    private static LinkedList<String> searchlist;
> -    private static LinkedList<String> nameservers;
> -
> -    // Parse string that consists of token delimited by space or commas
> -    // and return LinkedHashMap
> -    private LinkedList<String> stringToList(String str) {
> -        LinkedList<String> ll = new LinkedList<>();
> -
> -        // comma and space are valid delimiters
> -        StringTokenizer st = new StringTokenizer(str, ", ");
> -        while (st.hasMoreTokens()) {
> -            String s = st.nextToken();
> -            if (!ll.contains(s)) {
> -                ll.add(s);
> +    private static ArrayList<String> searchlist;
> +    private static ArrayList<String> nameservers;
> +
> +    // Parse string that consists of token delimited by comma
> +    // and return ArrayList. Refer to ResolverConfigurationImpl.c and
> +    // strappend to see how the string is created.
> +    private ArrayList<String> stringToList(String str) {
> +        // String is delimited by comma.
> +        String[] tokens = str.split(",");
> +        ArrayList<String> l = new ArrayList<>(tokens.length);
> +        for (String s : tokens) {
> +            if (!l.contains(s)) {
> +                l.add(s);
>              }
>          }
> -        return ll;
> +        l.trimToSize();
> +        return l;
> +    }
> +
> +    // Parse string that consists of token delimited by comma
> +    // and return ArrayList.  Refer to ResolverConfigurationImpl.c and
> +    // strappend to see how the string is created.
> +    // In addition to splitting the string, converts IPv6 addresses to
> +    // BSD-style.
> +    private ArrayList<String> addressesToList(String str) {
> +        // String is delimited by comma
> +        String[] tokens = str.split(",");
> +        ArrayList<String> l = new ArrayList<>(tokens.length);
> +
> +        for (String s : tokens) {
> +            if (!s.isEmpty()) {
> +                if (s.indexOf(':') >= 0 && s.charAt(0) != '[') {
> +                    // Not BSD style
> +                    s = '[' + s + ']';
> +                }
> +                if (!l.contains(s)) {
> +                    l.add(s);
> +                }
> +            }
> +        }
> +        l.trimToSize();
> +        return l;
>      }
>
>      // Load DNS configuration from OS
> @@ -81,28 +106,34 @@ public class ResolverConfigurationImpl
>      private void loadConfig() {
>          assert Thread.holdsLock(lock);
>
> -        // if address have changed then DNS probably changed as well;
> -        // otherwise check if cached settings have expired.
> -        //
> +        // A change in the network address of the machine usually
> indicates
> +        // a change in DNS configuration too so we always refresh the
> config
> +        // after such a change.
>          if (changed) {
>              changed = false;
>          } else {
> +            // Otherwise we refresh if TIMEOUT_NANOS has passed since last
> +            // load.
>              if (lastRefresh >= 0) {
> -                long currTime = System.currentTimeMillis();
> -                if ((currTime - lastRefresh) < TIMEOUT) {
> +                long currTime = System.nanoTime();
> +                if ((currTime - lastRefresh) < TIMEOUT_NANOS) {
>                      return;
>                  }
>              }
>          }
>
> -        // load DNS configuration, update timestamp, create
> -        // new HashMaps from the loaded configuration
> -        //
> +        // Native code that uses Windows API to find out the DNS server
> +        // addresses and search suffixes. It builds a comma-delimited
> string
> +        // of nameservers and domain suffixes and sets them to the static
> +        // os_nameservers and os_searchlist. We then split these into Java
> +        // Lists here.
>          loadDNSconfig0();
>
> -        lastRefresh = System.currentTimeMillis();
> +        // Record the time of update and refresh the lists of addresses /
> +        // domain suffixes.
> +        lastRefresh = System.nanoTime();
>          searchlist = stringToList(os_searchlist);
> -        nameservers = stringToList(os_nameservers);
> +        nameservers = addressesToList(os_nameservers);
>          os_searchlist = null;                       // can be GC'ed
>          os_nameservers = null;
>      }
> diff --git a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
> b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
> index f2368bafcb..297a1561ef 100644
> --- a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
> +++ b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
> @@ -73,8 +73,8 @@ const int MAX_TRIES = 3;
>   * for each adapter on the system. Returned in *adapters.
>   * Buffer is malloc'd and must be freed (unless error returned)
>   */
> -static int getAdapters (JNIEnv *env, IP_ADAPTER_ADDRESSES **adapters) {
> -    DWORD ret, flags;
> +int getAdapters (JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES **adapters)
> {
> +    DWORD ret;
>      IP_ADAPTER_ADDRESSES *adapterInfo;
>      ULONG len;
>      int try;
> @@ -87,9 +87,6 @@ static int getAdapters (JNIEnv *env,
> IP_ADAPTER_ADDRESSES **adapters) {
>      }
>
>      len = BUFF_SIZE;
> -    flags = GAA_FLAG_SKIP_DNS_SERVER;
> -    flags |= GAA_FLAG_SKIP_MULTICAST;
> -    flags |= GAA_FLAG_INCLUDE_PREFIX;
>      ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len);
>
>      for (try = 0; ret == ERROR_BUFFER_OVERFLOW && try < MAX_TRIES; ++try)
> {
> @@ -240,7 +237,7 @@ static int ipinflen = 2048;
>   */
>  int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP)
>  {
> -    DWORD ret;
> +    DWORD ret, flags;
>      MIB_IPADDRTABLE *tableP;
>      IP_ADAPTER_ADDRESSES *ptr, *adapters=NULL;
>      ULONG len=ipinflen, count=0;
> @@ -296,7 +293,11 @@ int getAllInterfacesAndAddresses (JNIEnv *env, netif
> **netifPP)
>          }
>      }
>      free(tableP);
> -    ret = getAdapters (env, &adapters);
> +
> +    flags = GAA_FLAG_SKIP_DNS_SERVER;
> +    flags |= GAA_FLAG_SKIP_MULTICAST;
> +    flags |= GAA_FLAG_INCLUDE_PREFIX;
> +    ret = getAdapters (env, flags, &adapters);
>      if (ret != ERROR_SUCCESS) {
>          goto err;
>      }
> diff --git
> a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
> b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
> index 13b28044a5..580347540d 100644
> --- a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
> +++ b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights
> reserved.
> + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights
> reserved.
>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>   *
>   * This code is free software; you can redistribute it and/or modify it
> @@ -24,14 +24,12 @@
>   */
>
>  #include <stdlib.h>
> -#include <windows.h>
>  #include <stdio.h>
>  #include <stddef.h>
> -#include <iprtrmib.h>
>  #include <time.h>
>  #include <assert.h>
> -#include <iphlpapi.h>
>
> +#include "net_util.h"
>  #include "jni_util.h"
>
>  #define MAX_STR_LEN         256
> @@ -48,8 +46,10 @@
>  static jfieldID searchlistID;
>  static jfieldID nameserversID;
>
> +extern int getAdapters(JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES
> **adapters);
> +
>  /*
> - * Utility routine to append s2 to s1 with a space delimiter.
> + * Utility routine to append s2 to s1 with a comma delimiter.
>   *  strappend(s1="abc", "def")  => "abc def"
>   *  strappend(s1="", "def")     => "def
>   */
> @@ -60,41 +60,32 @@ void strappend(char *s1, char *s2) {
>          return;
>
>      len = strlen(s1)+1;
> -    if (s1[0] != 0)                         /* needs space character */
> +    if (s1[0] != 0)                         /* needs comma character */
>          len++;
>      if (len + strlen(s2) > MAX_STR_LEN)     /* insufficient space */
>          return;
>
>      if (s1[0] != 0) {
> -        strcat(s1, " ");
> +        strcat(s1, ",");
>      }
>      strcat(s1, s2);
>  }
>
>  /*
> - * Windows 2000/XP
> - *
> - * Use registry approach based on settings described in Appendix C
> - * of "Microsoft Windows 2000 TCP/IP Implementation Details".
> - *
> - * DNS suffix list is obtained from SearchList registry setting. If
> - * this is not specified we compile suffix list based on the
> - * per-connection domain suffix.
> - *
> - * DNS name servers and domain settings are on a per-connection
> - * basic. We therefore enumerate the network adapters to get the
> - * names of each adapter and then query the corresponding registry
> - * settings to obtain NameServer/DhcpNameServer and Domain/DhcpDomain.
> + * Use DNS server addresses returned by GetAdaptersAddresses for currently
> + * active interfaces.
>   */
> -static int loadConfig(char *sl, char *ns) {
> -    IP_ADAPTER_INFO *adapterP;
> -    ULONG size;
> -    DWORD ret;
> +static int loadConfig(JNIEnv *env, char *sl, char *ns) {
> +    IP_ADAPTER_ADDRESSES *adapters, *adapter;
> +    IP_ADAPTER_DNS_SERVER_ADDRESS *dnsServer;
> +    WCHAR *suffix;
> +    DWORD ret, flags;
>      DWORD dwLen;
>      ULONG ulType;
>      char result[MAX_STR_LEN];
>      HANDLE hKey;
> -    int gotSearchList = 0;
> +    SOCKADDR *sockAddr;
> +    struct sockaddr_in6 *sockAddrIpv6;
>
>      /*
>       * First see if there is a global suffix list specified.
> @@ -112,122 +103,67 @@ static int loadConfig(char *sl, char *ns) {
>              assert(ulType == REG_SZ);
>              if (strlen(result) > 0) {
>                  strappend(sl, result);
> -                gotSearchList = 1;
>              }
>          }
>          RegCloseKey(hKey);
>      }
>
> -    /*
> -     * Ask the IP Helper library to enumerate the adapters
> -     */
> -    size = sizeof(IP_ADAPTER_INFO);
> -    adapterP = (IP_ADAPTER_INFO *)malloc(size);
> -    if (adapterP == NULL) {
> -        return STS_ERROR;
> -    }
> -    ret = GetAdaptersInfo(adapterP, &size);
> -    if (ret == ERROR_BUFFER_OVERFLOW) {
> -        IP_ADAPTER_INFO *newAdapterP = (IP_ADAPTER_INFO
> *)realloc(adapterP, size);
> -        if (newAdapterP == NULL) {
> -            free(adapterP);
> -            return STS_ERROR;
> -        }
> -        adapterP = newAdapterP;
>
> -        ret = GetAdaptersInfo(adapterP, &size);
> +    // We only need DNS server addresses so skip everything else.
> +    flags = GAA_FLAG_SKIP_UNICAST;
> +    flags |= GAA_FLAG_SKIP_ANYCAST;
> +    flags |= GAA_FLAG_SKIP_MULTICAST;
> +    flags |= GAA_FLAG_SKIP_FRIENDLY_NAME;
> +    ret = getAdapters(env, flags, &adapters);
> +    if (ret != ERROR_SUCCESS) {
> +        return STS_ERROR;
>      }
>
> -    /*
> -     * Iterate through the list of adapters as registry settings are
> -     * keyed on the adapter name (GUID).
> -     */
> -    if (ret == ERROR_SUCCESS) {
> -        IP_ADAPTER_INFO *curr = adapterP;
> -        while (curr != NULL) {
> -            char key[MAX_STR_LEN];
> -
> -            sprintf(key,
> -
>  "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
> -                curr->AdapterName);
> -
> -            ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
> -                               key,
> -                               0,
> -                               KEY_READ,
> -                               (PHKEY)&hKey);
> -            if (ret == ERROR_SUCCESS) {
> -                DWORD enableDhcp = 0;
> -
> -                /*
> -                 * Is DHCP enabled on this interface
> -                 */
> -                dwLen = sizeof(enableDhcp);
> -                ret = RegQueryValueEx(hKey, "EnableDhcp", NULL, &ulType,
> -                                     (LPBYTE)&enableDhcp, &dwLen);
> -
> -                /*
> -                 * If we don't have the suffix list when get the Domain
> -                 * or DhcpDomain. If DHCP is enabled then Domain overides
> -                 * DhcpDomain
> -                 */
> -                if (!gotSearchList) {
> -                    result[0] = '\0';
> -                    dwLen = sizeof(result);
> -                    ret = RegQueryValueEx(hKey, "Domain", NULL, &ulType,
> -                                         (LPBYTE)&result, &dwLen);
> -                    if (((ret != ERROR_SUCCESS) || (strlen(result) == 0))
> &&
> -                        enableDhcp) {
> -                        dwLen = sizeof(result);
> -                        ret = RegQueryValueEx(hKey, "DhcpDomain", NULL,
> &ulType,
> -                                              (LPBYTE)&result, &dwLen);
> -                    }
> -                    if (ret == ERROR_SUCCESS) {
> -                        assert(ulType == REG_SZ);
> -                        strappend(sl, result);
> +    adapter = adapters;
> +    while (adapter != NULL) {
> +        // Only load config from enabled adapters.
> +        if (adapter->OperStatus == IfOperStatusUp) {
> +            dnsServer = adapter->FirstDnsServerAddress;
> +            while (dnsServer != NULL) {
> +                sockAddr = dnsServer->Address.lpSockaddr;
> +                if (sockAddr->sa_family == AF_INET6) {
> +                    sockAddrIpv6 = (struct sockaddr_in6 *)sockAddr;
> +                    if (sockAddrIpv6->sin6_scope_id != 0) {
> +                        // An address with a scope is either link-local or
> +                        // site-local, which aren't valid for DNS queries
> so
> +                        // we can skip them.
> +                        dnsServer = dnsServer->Next;
> +                        continue;
>                      }
>                  }
>
> -                /*
> -                 * Get DNS servers based on NameServer or DhcpNameServer
> -                 * registry setting. If NameServer is set then it
> overrides
> -                 * DhcpNameServer (even if DHCP is enabled).
> -                 */
> -                result[0] = '\0';
>                  dwLen = sizeof(result);
> -                ret = RegQueryValueEx(hKey, "NameServer", NULL, &ulType,
> -                                     (LPBYTE)&result, &dwLen);
> -                if (((ret != ERROR_SUCCESS) || (strlen(result) == 0)) &&
> -                    enableDhcp) {
> -                    dwLen = sizeof(result);
> -                    ret = RegQueryValueEx(hKey, "DhcpNameServer", NULL,
> &ulType,
> -                                          (LPBYTE)&result, &dwLen);
> -                }
> -                if (ret == ERROR_SUCCESS) {
> -                    assert(ulType == REG_SZ);
> +                ret = WSAAddressToStringA(sockAddr,
> +                          dnsServer->Address.iSockaddrLength, NULL,
> +                          result, &dwLen);
> +                if (ret == 0) {
>                      strappend(ns, result);
>                  }
>
> -                /*
> -                 * Finished with this registry key
> -                 */
> -                RegCloseKey(hKey);
> +                dnsServer = dnsServer->Next;
>              }
>
> -            /*
> -             * Onto the next adapeter
> -             */
> -            curr = curr->Next;
> +            // Add connection-specific search domains in addition to
> global one.
> +            suffix = adapter->DnsSuffix;
> +            if (suffix != NULL) {
> +                ret = WideCharToMultiByte(CP_UTF8, 0, suffix, -1,
> +                    result, sizeof(result), NULL, NULL);
> +                if (ret != 0) {
> +                    strappend(sl, result);
> +                }
> +            }
>          }
> -    }
>
> -    /*
> -     * Free the adpater structure
> -     */
> -    if (adapterP) {
> -        free(adapterP);
> +        adapter = adapter->Next;
>      }
>
> +    free(adapters);
> +
>      return STS_SL_FOUND & STS_NS_FOUND;
>  }
>
> @@ -260,7 +196,7 @@
> Java_sun_net_dns_ResolverConfigurationImpl_loadDNSconfig0(JNIEnv *env,
> jclass cl
>      searchlist[0] = '\0';
>      nameservers[0] = '\0';
>
> -    if (loadConfig(searchlist, nameservers) != STS_ERROR) {
> +    if (loadConfig(env, searchlist, nameservers) != STS_ERROR) {
>
>          /*
>           * Populate static fields in sun.net.DefaultResolverConfiguration
>
> On Thu, Dec 12, 2019 at 1:49 AM Anuraag Agrawal <anuraaga at gmail.com>
> wrote:
>
>> Hi Aleksei,
>>
>> Thanks for the feedback. I had thought about it but felt that it might be
>> better to leave as much business logic to Java vs native as possible as a
>> general principle. But if it makes more sense to do it native here happy to
>> make the change :)
>>
>> Thanks,
>> - Anuraag
>>
>> On Thu, Dec 12, 2019, 01:18 Aleks Efimov <aleksej.efimov at oracle.com>
>> wrote:
>>
>>> Hi Anuraag,
>>>
>>> The webrev with the latest patch can be viewed here:
>>> http://cr.openjdk.java.net/~aefimov/anuraaga/7006496/02
>>>
>>> Thanks for replacing FirstDnsSuffix usages with DnsSuffix. I've double
>>> checked it with native application and can confirm that on my test host
>>> (Microsoft Windows Server 2016 Standard) the DnsSuffix contains correct
>>> information while the FirstDnsSuffix list is empty:
>>>         DNS Suffix (From DnsSuffix field):  test.domain.com
>>>         Number of IP Adapter DNS suffix entries: 0
>>>
>>>         DNS Suffix (From DnsSuffix field):
>>>         Number of IP Adapter DNS suffix entries: 0
>>>
>>>         DNS Suffix (From DnsSuffix field):
>>>         Number of IP Adapter DNS suffix entries: 0
>>>
>>>         DNS Suffix (From DnsSuffix field):
>>>         Number of IP Adapter DNS suffix entries: 0
>>>
>>>         DNS Suffix (From DnsSuffix field):  test.domain.com
>>>         Number of IP Adapter DNS suffix entries: 0
>>>
>>> About site-local addresses: Maybe we can move the site-local address
>>> check to native code? i.e. analyze dnsServer->Address.lpSockaddr and filter
>>> out site-local addresses.
>>>
>>> Testing:
>>> Run your latest patch though our CI system -  no issues detected.
>>>
>>> -Aleksei
>>>
>>> On 10/12/2019 06:59, Anuraag Agrawal wrote:
>>>
>>> Hi Aleksei,
>>>
>>> Thanks for running the test. I had checked the global search list, but
>>> realize I didn't check connection-specific suffixes which were causing the
>>> issue you see. While the documentation states that FirstDnsSuffix is
>>> populated on Vista+, amazingly it doesn't seem to be
>>>
>>>
>>> https://docs.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_addresses_lh
>>>
>>>
>>> Chromium has run into the same issue and just doesn't use the field
>>>
>>>
>>> https://cs.chromium.org/chromium/src/net/dns/dns_config_service_win.cc?q=firstdnssuffix&sq=package:chromium&dr=C&l=532
>>>
>>> So I have gone ahead and switched to using the normal DnsSuffix field.
>>> DnsSuffix and looking up the search list in the registry should generally
>>> give a full list.
>>>
>>> During this testing, other issues I found are that the search list
>>> returns a comma-separated list. So to keep the string list parsing simple,
>>> I changed the delimiter from space to comma. Also, on my machine I would
>>> always have DNS servers like fec0:0:0:ffff:1 on some adapters. At first, I
>>> assumed it is ok to return these, since they are configured by the OS and
>>> should be valid, but I learnt that these are deprecated IPv6 site-local
>>> addresses and should not be used.
>>>
>>> https://en.wikipedia.org/wiki/Unique_local_address
>>>
>>> I used the same check for site-local as Inet6Address, which just sees if
>>> the first bytes are fec0.
>>>
>>> Thanks again - inline patch follows.
>>>
>>> diff --git
>>> a/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>> b/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>> index 2250b3158e..b9a06461ab 100644
>>> ---
>>> a/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>> +++
>>> b/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>> @@ -25,9 +25,9 @@
>>>
>>>  package sun.net.dns;
>>>
>>> +import java.util.ArrayList;
>>>  import java.util.List;
>>> -import java.util.LinkedList;
>>> -import java.util.StringTokenizer;
>>> +import java.util.concurrent.TimeUnit;
>>>
>>>  /*
>>>   * An implementation of sun.net.ResolverConfiguration for Windows.
>>> @@ -50,30 +50,65 @@ public class ResolverConfigurationImpl
>>>
>>>      // Cache timeout (120 seconds) - should be converted into property
>>>      // or configured as preference in the future.
>>> -    private static final int TIMEOUT = 120000;
>>> +    private static final long TIMEOUT_NANOS =
>>> TimeUnit.SECONDS.toNanos(120);
>>>
>>>      // DNS suffix list and name servers populated by native method
>>>      private static String os_searchlist;
>>>      private static String os_nameservers;
>>>
>>>      // Cached lists
>>> -    private static LinkedList<String> searchlist;
>>> -    private static LinkedList<String> nameservers;
>>> -
>>> -    // Parse string that consists of token delimited by space or commas
>>> -    // and return LinkedHashMap
>>> -    private LinkedList<String> stringToList(String str) {
>>> -        LinkedList<String> ll = new LinkedList<>();
>>> -
>>> -        // comma and space are valid delimiters
>>> -        StringTokenizer st = new StringTokenizer(str, ", ");
>>> -        while (st.hasMoreTokens()) {
>>> -            String s = st.nextToken();
>>> -            if (!ll.contains(s)) {
>>> -                ll.add(s);
>>> +    private static ArrayList<String> searchlist;
>>> +    private static ArrayList<String> nameservers;
>>> +
>>> +    // Parse string that consists of token delimited by comma
>>> +    // and return ArrayList. Refer to ResolverConfigurationImpl.c and
>>> +    // strappend to see how the string is created.
>>> +    private ArrayList<String> stringToList(String str) {
>>> +        // String is delimited by comma.
>>> +        String[] tokens = str.split(",");
>>> +        ArrayList<String> l = new ArrayList<>(tokens.length);
>>> +        for (String s : tokens) {
>>> +            if (!l.contains(s)) {
>>> +                l.add(s);
>>>              }
>>>          }
>>> -        return ll;
>>> +        l.trimToSize();
>>> +        return l;
>>> +    }
>>> +
>>> +    // Parse string that consists of token delimited by comma
>>> +    // and return ArrayList.  Refer to ResolverConfigurationImpl.c and
>>> +    // strappend to see how the string is created.
>>> +    // In addition to splitting the string, converts IPv6 addresses to
>>> +    // BSD-style.
>>> +    private ArrayList<String> addressesToList(String str) {
>>> +        // String is delimited by comma
>>> +        String[] tokens = str.split(",");
>>> +        ArrayList<String> l = new ArrayList<>(tokens.length);
>>> +
>>> +        for (String s : tokens) {
>>> +            if (!s.isEmpty()) {
>>> +                if (s.indexOf(':') >= 0) {
>>> +                    // IPv6
>>> +                    if (s.charAt(0) != '[') {
>>> +                        // Not BSD style
>>> +                        s = '[' + s + ']';
>>> +                    }
>>> +                    if (s.startsWith("[fec0:")) {
>>> +                        // Deprecated site-local address. Windows adds
>>> +                        // such addresses to IPv6 adapters without DNS
>>> +                        // configured, but these should not actually be
>>> +                        // used for queries.
>>> +                        continue;
>>> +                    }
>>> +                }
>>> +                if (!l.contains(s)) {
>>> +                    l.add(s);
>>> +                }
>>> +            }
>>> +        }
>>> +        l.trimToSize();
>>> +        return l;
>>>      }
>>>
>>>      // Load DNS configuration from OS
>>> @@ -81,28 +116,34 @@ public class ResolverConfigurationImpl
>>>      private void loadConfig() {
>>>          assert Thread.holdsLock(lock);
>>>
>>> -        // if address have changed then DNS probably changed as well;
>>> -        // otherwise check if cached settings have expired.
>>> -        //
>>> +        // A change in the network address of the machine usually
>>> indicates
>>> +        // a change in DNS configuration too so we always refresh the
>>> config
>>> +        // after such a change.
>>>          if (changed) {
>>>              changed = false;
>>>          } else {
>>> +            // Otherwise we refresh if TIMEOUT_NANOS has passed since
>>> last
>>> +            // load.
>>>              if (lastRefresh >= 0) {
>>> -                long currTime = System.currentTimeMillis();
>>> -                if ((currTime - lastRefresh) < TIMEOUT) {
>>> +                long currTime = System.nanoTime();
>>> +                if ((currTime - lastRefresh) < TIMEOUT_NANOS) {
>>>                      return;
>>>                  }
>>>              }
>>>          }
>>>
>>> -        // load DNS configuration, update timestamp, create
>>> -        // new HashMaps from the loaded configuration
>>> -        //
>>> +        // Native code that uses Windows API to find out the DNS server
>>> +        // addresses and search suffixes. It builds a comma-delimited
>>> string
>>> +        // of nameservers and domain suffixes and sets them to the
>>> static
>>> +        // os_nameservers and os_searchlist. We then split these into
>>> Java
>>> +        // Lists here.
>>>          loadDNSconfig0();
>>>
>>> -        lastRefresh = System.currentTimeMillis();
>>> +        // Record the time of update and refresh the lists of addresses
>>> /
>>> +        // domain suffixes.
>>> +        lastRefresh = System.nanoTime();
>>>          searchlist = stringToList(os_searchlist);
>>> -        nameservers = stringToList(os_nameservers);
>>> +        nameservers = addressesToList(os_nameservers);
>>>          os_searchlist = null;                       // can be GC'ed
>>>          os_nameservers = null;
>>>      }
>>> diff --git
>>> a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>> b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>> index f2368bafcb..297a1561ef 100644
>>> --- a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>> +++ b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>> @@ -73,8 +73,8 @@ const int MAX_TRIES = 3;
>>>   * for each adapter on the system. Returned in *adapters.
>>>   * Buffer is malloc'd and must be freed (unless error returned)
>>>   */
>>> -static int getAdapters (JNIEnv *env, IP_ADAPTER_ADDRESSES **adapters) {
>>> -    DWORD ret, flags;
>>> +int getAdapters (JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES
>>> **adapters) {
>>> +    DWORD ret;
>>>      IP_ADAPTER_ADDRESSES *adapterInfo;
>>>      ULONG len;
>>>      int try;
>>> @@ -87,9 +87,6 @@ static int getAdapters (JNIEnv *env,
>>> IP_ADAPTER_ADDRESSES **adapters) {
>>>      }
>>>
>>>      len = BUFF_SIZE;
>>> -    flags = GAA_FLAG_SKIP_DNS_SERVER;
>>> -    flags |= GAA_FLAG_SKIP_MULTICAST;
>>> -    flags |= GAA_FLAG_INCLUDE_PREFIX;
>>>      ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo,
>>> &len);
>>>
>>>      for (try = 0; ret == ERROR_BUFFER_OVERFLOW && try < MAX_TRIES;
>>> ++try) {
>>> @@ -240,7 +237,7 @@ static int ipinflen = 2048;
>>>   */
>>>  int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP)
>>>  {
>>> -    DWORD ret;
>>> +    DWORD ret, flags;
>>>      MIB_IPADDRTABLE *tableP;
>>>      IP_ADAPTER_ADDRESSES *ptr, *adapters=NULL;
>>>      ULONG len=ipinflen, count=0;
>>> @@ -296,7 +293,11 @@ int getAllInterfacesAndAddresses (JNIEnv *env,
>>> netif **netifPP)
>>>          }
>>>      }
>>>      free(tableP);
>>> -    ret = getAdapters (env, &adapters);
>>> +
>>> +    flags = GAA_FLAG_SKIP_DNS_SERVER;
>>> +    flags |= GAA_FLAG_SKIP_MULTICAST;
>>> +    flags |= GAA_FLAG_INCLUDE_PREFIX;
>>> +    ret = getAdapters (env, flags, &adapters);
>>>      if (ret != ERROR_SUCCESS) {
>>>          goto err;
>>>      }
>>> diff --git
>>> a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>> b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>> index 13b28044a5..427d7c85eb 100644
>>> --- a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>> +++ b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>> @@ -1,5 +1,5 @@
>>>  /*
>>> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights
>>> reserved.
>>> + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights
>>> reserved.
>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>   *
>>>   * This code is free software; you can redistribute it and/or modify it
>>> @@ -30,6 +30,7 @@
>>>  #include <iprtrmib.h>
>>>  #include <time.h>
>>>  #include <assert.h>
>>> +#include <winsock2.h>
>>>  #include <iphlpapi.h>
>>>
>>>  #include "jni_util.h"
>>> @@ -48,8 +49,10 @@
>>>  static jfieldID searchlistID;
>>>  static jfieldID nameserversID;
>>>
>>> +extern int getAdapters(JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES
>>> **adapters);
>>> +
>>>  /*
>>> - * Utility routine to append s2 to s1 with a space delimiter.
>>> + * Utility routine to append s2 to s1 with a comma delimiter.
>>>   *  strappend(s1="abc", "def")  => "abc def"
>>>   *  strappend(s1="", "def")     => "def
>>>   */
>>> @@ -60,41 +63,30 @@ void strappend(char *s1, char *s2) {
>>>          return;
>>>
>>>      len = strlen(s1)+1;
>>> -    if (s1[0] != 0)                         /* needs space character */
>>> +    if (s1[0] != 0)                         /* needs comma character */
>>>          len++;
>>>      if (len + strlen(s2) > MAX_STR_LEN)     /* insufficient space */
>>>          return;
>>>
>>>      if (s1[0] != 0) {
>>> -        strcat(s1, " ");
>>> +        strcat(s1, ",");
>>>      }
>>>      strcat(s1, s2);
>>>  }
>>>
>>>  /*
>>> - * Windows 2000/XP
>>> - *
>>> - * Use registry approach based on settings described in Appendix C
>>> - * of "Microsoft Windows 2000 TCP/IP Implementation Details".
>>> - *
>>> - * DNS suffix list is obtained from SearchList registry setting. If
>>> - * this is not specified we compile suffix list based on the
>>> - * per-connection domain suffix.
>>> - *
>>> - * DNS name servers and domain settings are on a per-connection
>>> - * basic. We therefore enumerate the network adapters to get the
>>> - * names of each adapter and then query the corresponding registry
>>> - * settings to obtain NameServer/DhcpNameServer and Domain/DhcpDomain.
>>> + * Use DNS server addresses returned by GetAdaptersAddresses for
>>> currently
>>> + * active interfaces.
>>>   */
>>> -static int loadConfig(char *sl, char *ns) {
>>> -    IP_ADAPTER_INFO *adapterP;
>>> -    ULONG size;
>>> -    DWORD ret;
>>> +static int loadConfig(JNIEnv *env, char *sl, char *ns) {
>>> +    IP_ADAPTER_ADDRESSES *adapters, *adapter;
>>> +    IP_ADAPTER_DNS_SERVER_ADDRESS *dnsServer;
>>> +    WCHAR *suffix;
>>> +    DWORD ret, flags;
>>>      DWORD dwLen;
>>>      ULONG ulType;
>>>      char result[MAX_STR_LEN];
>>>      HANDLE hKey;
>>> -    int gotSearchList = 0;
>>>
>>>      /*
>>>       * First see if there is a global suffix list specified.
>>> @@ -112,122 +104,55 @@ static int loadConfig(char *sl, char *ns) {
>>>              assert(ulType == REG_SZ);
>>>              if (strlen(result) > 0) {
>>>                  strappend(sl, result);
>>> -                gotSearchList = 1;
>>>              }
>>>          }
>>>          RegCloseKey(hKey);
>>>      }
>>>
>>> -    /*
>>> -     * Ask the IP Helper library to enumerate the adapters
>>> -     */
>>> -    size = sizeof(IP_ADAPTER_INFO);
>>> -    adapterP = (IP_ADAPTER_INFO *)malloc(size);
>>> -    if (adapterP == NULL) {
>>> -        return STS_ERROR;
>>> -    }
>>> -    ret = GetAdaptersInfo(adapterP, &size);
>>> -    if (ret == ERROR_BUFFER_OVERFLOW) {
>>> -        IP_ADAPTER_INFO *newAdapterP = (IP_ADAPTER_INFO
>>> *)realloc(adapterP, size);
>>> -        if (newAdapterP == NULL) {
>>> -            free(adapterP);
>>> -            return STS_ERROR;
>>> -        }
>>> -        adapterP = newAdapterP;
>>>
>>> -        ret = GetAdaptersInfo(adapterP, &size);
>>> +    // We only need DNS server addresses so skip everything else.
>>> +    flags = GAA_FLAG_SKIP_UNICAST;
>>> +    flags |= GAA_FLAG_SKIP_ANYCAST;
>>> +    flags |= GAA_FLAG_SKIP_MULTICAST;
>>> +    flags |= GAA_FLAG_SKIP_FRIENDLY_NAME;
>>> +    ret = getAdapters(env, flags, &adapters);
>>> +    if (ret != ERROR_SUCCESS) {
>>> +        return STS_ERROR;
>>>      }
>>>
>>> -    /*
>>> -     * Iterate through the list of adapters as registry settings are
>>> -     * keyed on the adapter name (GUID).
>>> -     */
>>> -    if (ret == ERROR_SUCCESS) {
>>> -        IP_ADAPTER_INFO *curr = adapterP;
>>> -        while (curr != NULL) {
>>> -            char key[MAX_STR_LEN];
>>> -
>>> -            sprintf(key,
>>> -
>>>  "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
>>> -                curr->AdapterName);
>>> -
>>> -            ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
>>> -                               key,
>>> -                               0,
>>> -                               KEY_READ,
>>> -                               (PHKEY)&hKey);
>>> -            if (ret == ERROR_SUCCESS) {
>>> -                DWORD enableDhcp = 0;
>>> -
>>> -                /*
>>> -                 * Is DHCP enabled on this interface
>>> -                 */
>>> -                dwLen = sizeof(enableDhcp);
>>> -                ret = RegQueryValueEx(hKey, "EnableDhcp", NULL, &ulType,
>>> -                                     (LPBYTE)&enableDhcp, &dwLen);
>>> -
>>> -                /*
>>> -                 * If we don't have the suffix list when get the Domain
>>> -                 * or DhcpDomain. If DHCP is enabled then Domain
>>> overides
>>> -                 * DhcpDomain
>>> -                 */
>>> -                if (!gotSearchList) {
>>> -                    result[0] = '\0';
>>> -                    dwLen = sizeof(result);
>>> -                    ret = RegQueryValueEx(hKey, "Domain", NULL, &ulType,
>>> -                                         (LPBYTE)&result, &dwLen);
>>> -                    if (((ret != ERROR_SUCCESS) || (strlen(result) ==
>>> 0)) &&
>>> -                        enableDhcp) {
>>> -                        dwLen = sizeof(result);
>>> -                        ret = RegQueryValueEx(hKey, "DhcpDomain", NULL,
>>> &ulType,
>>> -                                              (LPBYTE)&result, &dwLen);
>>> -                    }
>>> -                    if (ret == ERROR_SUCCESS) {
>>> -                        assert(ulType == REG_SZ);
>>> -                        strappend(sl, result);
>>> -                    }
>>> -                }
>>> -
>>> -                /*
>>> -                 * Get DNS servers based on NameServer or DhcpNameServer
>>> -                 * registry setting. If NameServer is set then it
>>> overrides
>>> -                 * DhcpNameServer (even if DHCP is enabled).
>>> -                 */
>>> -                result[0] = '\0';
>>> +    adapter = adapters;
>>> +    while (adapter != NULL) {
>>> +        // Only load config from enabled adapters.
>>> +        if (adapter->OperStatus == IfOperStatusUp) {
>>> +            dnsServer = adapter->FirstDnsServerAddress;
>>> +            while (dnsServer != NULL) {
>>>                  dwLen = sizeof(result);
>>> -                ret = RegQueryValueEx(hKey, "NameServer", NULL, &ulType,
>>> -                                     (LPBYTE)&result, &dwLen);
>>> -                if (((ret != ERROR_SUCCESS) || (strlen(result) == 0)) &&
>>> -                    enableDhcp) {
>>> -                    dwLen = sizeof(result);
>>> -                    ret = RegQueryValueEx(hKey, "DhcpNameServer", NULL,
>>> &ulType,
>>> -                                          (LPBYTE)&result, &dwLen);
>>> -                }
>>> -                if (ret == ERROR_SUCCESS) {
>>> -                    assert(ulType == REG_SZ);
>>> +                ret = WSAAddressToStringA(dnsServer->Address.lpSockaddr,
>>> +                          dnsServer->Address.iSockaddrLength, NULL,
>>> +                          result, &dwLen);
>>> +                if (ret == 0) {
>>>                      strappend(ns, result);
>>>                  }
>>>
>>> -                /*
>>> -                 * Finished with this registry key
>>> -                 */
>>> -                RegCloseKey(hKey);
>>> +                dnsServer = dnsServer->Next;
>>>              }
>>>
>>> -            /*
>>> -             * Onto the next adapeter
>>> -             */
>>> -            curr = curr->Next;
>>> +            // Add connection-specific search domains in addition to
>>> global one.
>>> +            suffix = adapter->DnsSuffix;
>>> +            if (suffix != NULL) {
>>> +                ret = WideCharToMultiByte(CP_UTF8, 0, suffix, -1,
>>> +                    result, sizeof(result), NULL, NULL);
>>> +                if (ret != 0) {
>>> +                    strappend(sl, result);
>>> +                }
>>> +            }
>>>          }
>>> -    }
>>>
>>> -    /*
>>> -     * Free the adpater structure
>>> -     */
>>> -    if (adapterP) {
>>> -        free(adapterP);
>>> +        adapter = adapter->Next;
>>>      }
>>>
>>> +    free(adapters);
>>> +
>>>      return STS_SL_FOUND & STS_NS_FOUND;
>>>  }
>>>
>>> @@ -260,7 +185,7 @@
>>> Java_sun_net_dns_ResolverConfigurationImpl_loadDNSconfig0(JNIEnv *env,
>>> jclass cl
>>>      searchlist[0] = '\0';
>>>      nameservers[0] = '\0';
>>>
>>> -    if (loadConfig(searchlist, nameservers) != STS_ERROR) {
>>> +    if (loadConfig(env, searchlist, nameservers) != STS_ERROR) {
>>>
>>>          /*
>>>           * Populate static fields in
>>> sun.net.DefaultResolverConfiguration
>>>
>>> On Tue, Dec 10, 2019 at 1:29 AM Aleks Efimov <aleksej.efimov at oracle.com>
>>> wrote:
>>>
>>>> Hi Anuraag,
>>>>
>>>> The webrev with your latest changes can be found here:
>>>>     http://cr.openjdk.java.net/~aefimov/anuraaga/7006496/01
>>>>
>>>> The copyright changes looks good.
>>>>
>>>> The split by space also looks good with assumption that we will never
>>>> get string with two spaces between IP addresses/DNS suffixes.
>>>>
>>>> I've also performed one test on Windows machine and it shows an issue
>>>> with the retrieval of DNS suffixes:
>>>> Method to call:
>>>>      sun.net.dns.ResolverConfiguration.open().searchlist()
>>>>
>>>> Old implementation returns:
>>>>     [test.domain.com]
>>>>
>>>> With the latest patch the suffixes list (searchlist) is empty:
>>>>     []
>>>>
>>>> I've collected the following information on the test host that might
>>>> help you to fix the issue:
>>>>
>>>> The host OS: Microsoft Windows Server 2016 Standard
>>>>
>>>> Networking configuration (<---> is for masked addresses/info):
>>>> $ ipconfig /all
>>>>
>>>> Windows IP Configuration
>>>>
>>>>    Host Name . . . . . . . . . . . . : host-name-1
>>>>    Primary Dns Suffix  . . . . . . . :
>>>>    Node Type . . . . . . . . . . . . : Hybrid
>>>>    IP Routing Enabled. . . . . . . . : No
>>>>    WINS Proxy Enabled. . . . . . . . : No
>>>>    DNS Suffix Search List. . . . . . : test.domain.com
>>>>
>>>> Ethernet adapter Ethernet:
>>>>
>>>>    Connection-specific DNS Suffix  . : test.domain.com
>>>>    Description . . . . . . . . . . . : Broadcom NetXtreme-E Virtual
>>>> Function
>>>>    Physical Address. . . . . . . . . : <------------>
>>>>    DHCP Enabled. . . . . . . . . . . : Yes
>>>>    Autoconfiguration Enabled . . . . : Yes
>>>>    Link-local IPv6 Address . . . . . : <------------>
>>>>    IPv4 Address. . . . . . . . . . . : <------------>
>>>>    Subnet Mask . . . . . . . . . . . : <------------>
>>>>    Lease Obtained. . . . . . . . . . : <------------>
>>>>    Lease Expires . . . . . . . . . . : <------------>
>>>>    Default Gateway . . . . . . . . . : <------------>
>>>>    DHCP Server . . . . . . . . . . . : <------------>
>>>>    DHCPv6 Client DUID. . . . . . . . : <------------>
>>>>    DNS Servers . . . . . . . . . . . : <------------>
>>>>                                        <------------>
>>>>    NetBIOS over Tcpip. . . . . . . . : Disabled
>>>>
>>>> Tunnel adapter isatap.test.domain.com:
>>>>
>>>>    Media State . . . . . . . . . . . : Media disconnected
>>>>    Connection-specific DNS Suffix  . : test.domain.com
>>>>    Description . . . . . . . . . . . : Microsoft ISATAP Adapter #3
>>>>    Physical Address. . . . . . . . . : <------------>
>>>>    DHCP Enabled. . . . . . . . . . . : No
>>>>    Autoconfiguration Enabled . . . . : Yes
>>>>
>>>>
>>>> - Aleksei
>>>>
>>>>
>>>> On 07/12/2019 09:44, Anuraag Agrawal wrote:
>>>>
>>>> Hi all,
>>>>
>>>> Thanks for the reviews. I've fixed the formatting errors, and I hope I
>>>> fixed the copyright issue. I couldn't find documentation on the format of
>>>> the copyright header, but assume the second number is the year of
>>>> modification to update. I found ResolverConfigurationImpl.c to have an old
>>>> one and updated it to 2019.
>>>>
>>>> I also found the note in the docs that StringTokenizer is deprecated
>>>> and shouldn't be used - I agree it's a good time to replace it. As we have
>>>> a simple split by space, I have gone ahead and used the simpler
>>>> String.split instead of regex, hope that makes sense. While in many code
>>>> I'd be a little concerned with the array allocation, this is only run very
>>>> infrequently so I think it should be ok.
>>>>
>>>> Inline diff follows
>>>>
>>>> diff --git
>>>> a/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>>> b/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>>> index 2250b3158e..47065e805e 100644
>>>> ---
>>>> a/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>>> +++
>>>> b/src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java
>>>> @@ -25,9 +25,9 @@
>>>>
>>>>  package sun.net.dns;
>>>>
>>>> +import java.util.ArrayList;
>>>>  import java.util.List;
>>>> -import java.util.LinkedList;
>>>> -import java.util.StringTokenizer;
>>>> +import java.util.concurrent.TimeUnit;
>>>>
>>>>  /*
>>>>   * An implementation of sun.net.ResolverConfiguration for Windows.
>>>> @@ -50,30 +50,55 @@ public class ResolverConfigurationImpl
>>>>
>>>>      // Cache timeout (120 seconds) - should be converted into property
>>>>      // or configured as preference in the future.
>>>> -    private static final int TIMEOUT = 120000;
>>>> +    private static final long TIMEOUT_NANOS =
>>>> TimeUnit.SECONDS.toNanos(120);
>>>>
>>>>      // DNS suffix list and name servers populated by native method
>>>>      private static String os_searchlist;
>>>>      private static String os_nameservers;
>>>>
>>>>      // Cached lists
>>>> -    private static LinkedList<String> searchlist;
>>>> -    private static LinkedList<String> nameservers;
>>>> -
>>>> -    // Parse string that consists of token delimited by space or commas
>>>> -    // and return LinkedHashMap
>>>> -    private LinkedList<String> stringToList(String str) {
>>>> -        LinkedList<String> ll = new LinkedList<>();
>>>> -
>>>> -        // comma and space are valid delimiters
>>>> -        StringTokenizer st = new StringTokenizer(str, ", ");
>>>> -        while (st.hasMoreTokens()) {
>>>> -            String s = st.nextToken();
>>>> -            if (!ll.contains(s)) {
>>>> -                ll.add(s);
>>>> +    private static ArrayList<String> searchlist;
>>>> +    private static ArrayList<String> nameservers;
>>>> +
>>>> +    // Parse string that consists of token delimited by space
>>>> +    // and return ArrayList. Refer to ResolverConfigurationImpl.c and
>>>> +    // strappend to see how the string is created.
>>>> +    private ArrayList<String> stringToList(String str) {
>>>> +        // String is delimited by space.
>>>> +        String[] tokens = str.split(" ");
>>>> +        ArrayList<String> l = new ArrayList<>(tokens.length);
>>>> +        for (String s : tokens) {
>>>> +            if (!l.contains(s)) {
>>>> +                l.add(s);
>>>>              }
>>>>          }
>>>> -        return ll;
>>>> +        l.trimToSize();
>>>> +        return l;
>>>> +    }
>>>> +
>>>> +    // Parse string that consists of token delimited by space
>>>> +    // and return ArrayList.  Refer to ResolverConfigurationImpl.c and
>>>> +    // strappend to see how the string is created.
>>>> +    // In addition to splitting the string, converts IPv6 addresses to
>>>> +    // BSD-style.
>>>> +    private ArrayList<String> addressesToList(String str) {
>>>> +        // String is delimited by space
>>>> +        String[] tokens = str.split(" ");
>>>> +        ArrayList<String> l = new ArrayList<>(tokens.length);
>>>> +
>>>> +        for (String s : tokens) {
>>>> +            if (!s.isEmpty()) {
>>>> +                if (s.indexOf(':') >= 0 && s.charAt(0) != '[') {
>>>> +                    // Not BSD style
>>>> +                    s = '[' + s + ']';
>>>> +                }
>>>> +                if (!l.contains(s)) {
>>>> +                    l.add(s);
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +        l.trimToSize();
>>>> +        return l;
>>>>      }
>>>>
>>>>      // Load DNS configuration from OS
>>>> @@ -81,28 +106,34 @@ public class ResolverConfigurationImpl
>>>>      private void loadConfig() {
>>>>          assert Thread.holdsLock(lock);
>>>>
>>>> -        // if address have changed then DNS probably changed as well;
>>>> -        // otherwise check if cached settings have expired.
>>>> -        //
>>>> +        // A change in the network address of the machine usually
>>>> indicates
>>>> +        // a change in DNS configuration too so we always refresh the
>>>> config
>>>> +        // after such a change.
>>>>          if (changed) {
>>>>              changed = false;
>>>>          } else {
>>>> +            // Otherwise we refresh if TIMEOUT_NANOS has passed since
>>>> last
>>>> +            // load.
>>>>              if (lastRefresh >= 0) {
>>>> -                long currTime = System.currentTimeMillis();
>>>> -                if ((currTime - lastRefresh) < TIMEOUT) {
>>>> +                long currTime = System.nanoTime();
>>>> +                if ((currTime - lastRefresh) < TIMEOUT_NANOS) {
>>>>                      return;
>>>>                  }
>>>>              }
>>>>          }
>>>>
>>>> -        // load DNS configuration, update timestamp, create
>>>> -        // new HashMaps from the loaded configuration
>>>> -        //
>>>> +        // Native code that uses Windows API to find out the DNS server
>>>> +        // addresses and search suffixes. It builds a space-delimited
>>>> string
>>>> +        // of nameservers and domain suffixes and sets them to the
>>>> static
>>>> +        // os_nameservers and os_searchlist. We then split these into
>>>> Java
>>>> +        // Lists here.
>>>>          loadDNSconfig0();
>>>>
>>>> -        lastRefresh = System.currentTimeMillis();
>>>> +        // Record the time of update and refresh the lists of
>>>> addresses /
>>>> +        // domain suffixes.
>>>> +        lastRefresh = System.nanoTime();
>>>>          searchlist = stringToList(os_searchlist);
>>>> -        nameservers = stringToList(os_nameservers);
>>>> +        nameservers = addressesToList(os_nameservers);
>>>>          os_searchlist = null;                       // can be GC'ed
>>>>          os_nameservers = null;
>>>>      }
>>>> diff --git
>>>> a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>>> b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>>> index f2368bafcb..297a1561ef 100644
>>>> --- a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>>> +++ b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c
>>>> @@ -73,8 +73,8 @@ const int MAX_TRIES = 3;
>>>>   * for each adapter on the system. Returned in *adapters.
>>>>   * Buffer is malloc'd and must be freed (unless error returned)
>>>>   */
>>>> -static int getAdapters (JNIEnv *env, IP_ADAPTER_ADDRESSES **adapters) {
>>>> -    DWORD ret, flags;
>>>> +int getAdapters (JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES
>>>> **adapters) {
>>>> +    DWORD ret;
>>>>      IP_ADAPTER_ADDRESSES *adapterInfo;
>>>>      ULONG len;
>>>>      int try;
>>>> @@ -87,9 +87,6 @@ static int getAdapters (JNIEnv *env,
>>>> IP_ADAPTER_ADDRESSES **adapters) {
>>>>      }
>>>>
>>>>      len = BUFF_SIZE;
>>>> -    flags = GAA_FLAG_SKIP_DNS_SERVER;
>>>> -    flags |= GAA_FLAG_SKIP_MULTICAST;
>>>> -    flags |= GAA_FLAG_INCLUDE_PREFIX;
>>>>      ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo,
>>>> &len);
>>>>
>>>>      for (try = 0; ret == ERROR_BUFFER_OVERFLOW && try < MAX_TRIES;
>>>> ++try) {
>>>> @@ -240,7 +237,7 @@ static int ipinflen = 2048;
>>>>   */
>>>>  int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP)
>>>>  {
>>>> -    DWORD ret;
>>>> +    DWORD ret, flags;
>>>>      MIB_IPADDRTABLE *tableP;
>>>>      IP_ADAPTER_ADDRESSES *ptr, *adapters=NULL;
>>>>      ULONG len=ipinflen, count=0;
>>>> @@ -296,7 +293,11 @@ int getAllInterfacesAndAddresses (JNIEnv *env,
>>>> netif **netifPP)
>>>>          }
>>>>      }
>>>>      free(tableP);
>>>> -    ret = getAdapters (env, &adapters);
>>>> +
>>>> +    flags = GAA_FLAG_SKIP_DNS_SERVER;
>>>> +    flags |= GAA_FLAG_SKIP_MULTICAST;
>>>> +    flags |= GAA_FLAG_INCLUDE_PREFIX;
>>>> +    ret = getAdapters (env, flags, &adapters);
>>>>      if (ret != ERROR_SUCCESS) {
>>>>          goto err;
>>>>      }
>>>> diff --git
>>>> a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> index 13b28044a5..85a7935314 100644
>>>> --- a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> +++ b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> @@ -1,5 +1,5 @@
>>>>  /*
>>>> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights
>>>> reserved.
>>>> + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights
>>>> reserved.
>>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>   *
>>>>   * This code is free software; you can redistribute it and/or modify it
>>>> @@ -30,6 +30,7 @@
>>>>  #include <iprtrmib.h>
>>>>  #include <time.h>
>>>>  #include <assert.h>
>>>> +#include <winsock2.h>
>>>>  #include <iphlpapi.h>
>>>>
>>>>  #include "jni_util.h"
>>>> @@ -48,6 +49,8 @@
>>>>  static jfieldID searchlistID;
>>>>  static jfieldID nameserversID;
>>>>
>>>> +extern int getAdapters(JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES
>>>> **adapters);
>>>> +
>>>>  /*
>>>>   * Utility routine to append s2 to s1 with a space delimiter.
>>>>   *  strappend(s1="abc", "def")  => "abc def"
>>>> @@ -72,29 +75,19 @@ void strappend(char *s1, char *s2) {
>>>>  }
>>>>
>>>>  /*
>>>> - * Windows 2000/XP
>>>> - *
>>>> - * Use registry approach based on settings described in Appendix C
>>>> - * of "Microsoft Windows 2000 TCP/IP Implementation Details".
>>>> - *
>>>> - * DNS suffix list is obtained from SearchList registry setting. If
>>>> - * this is not specified we compile suffix list based on the
>>>> - * per-connection domain suffix.
>>>> - *
>>>> - * DNS name servers and domain settings are on a per-connection
>>>> - * basic. We therefore enumerate the network adapters to get the
>>>> - * names of each adapter and then query the corresponding registry
>>>> - * settings to obtain NameServer/DhcpNameServer and Domain/DhcpDomain.
>>>> + * Use DNS server addresses returned by GetAdaptersAddresses for
>>>> currently
>>>> + * active interfaces.
>>>>   */
>>>> -static int loadConfig(char *sl, char *ns) {
>>>> -    IP_ADAPTER_INFO *adapterP;
>>>> -    ULONG size;
>>>> -    DWORD ret;
>>>> +static int loadConfig(JNIEnv *env, char *sl, char *ns) {
>>>> +    IP_ADAPTER_ADDRESSES *adapters, *adapter;
>>>> +    IP_ADAPTER_DNS_SERVER_ADDRESS *dnsServer;
>>>> +    SOCKADDR *address;
>>>> +    IP_ADAPTER_DNS_SUFFIX *suffix;
>>>> +    DWORD ret, flags;
>>>>      DWORD dwLen;
>>>>      ULONG ulType;
>>>>      char result[MAX_STR_LEN];
>>>>      HANDLE hKey;
>>>> -    int gotSearchList = 0;
>>>>
>>>>      /*
>>>>       * First see if there is a global suffix list specified.
>>>> @@ -112,122 +105,58 @@ static int loadConfig(char *sl, char *ns) {
>>>>              assert(ulType == REG_SZ);
>>>>              if (strlen(result) > 0) {
>>>>                  strappend(sl, result);
>>>> -                gotSearchList = 1;
>>>>              }
>>>>          }
>>>>          RegCloseKey(hKey);
>>>>      }
>>>>
>>>> -    /*
>>>> -     * Ask the IP Helper library to enumerate the adapters
>>>> -     */
>>>> -    size = sizeof(IP_ADAPTER_INFO);
>>>> -    adapterP = (IP_ADAPTER_INFO *)malloc(size);
>>>> -    if (adapterP == NULL) {
>>>> -        return STS_ERROR;
>>>> -    }
>>>> -    ret = GetAdaptersInfo(adapterP, &size);
>>>> -    if (ret == ERROR_BUFFER_OVERFLOW) {
>>>> -        IP_ADAPTER_INFO *newAdapterP = (IP_ADAPTER_INFO
>>>> *)realloc(adapterP, size);
>>>> -        if (newAdapterP == NULL) {
>>>> -            free(adapterP);
>>>> -            return STS_ERROR;
>>>> -        }
>>>> -        adapterP = newAdapterP;
>>>>
>>>> -        ret = GetAdaptersInfo(adapterP, &size);
>>>> +    // We only need DNS server addresses so skip everything else.
>>>> +    flags = GAA_FLAG_SKIP_UNICAST;
>>>> +    flags |= GAA_FLAG_SKIP_ANYCAST;
>>>> +    flags |= GAA_FLAG_SKIP_MULTICAST;
>>>> +    flags |= GAA_FLAG_SKIP_FRIENDLY_NAME;
>>>> +    ret = getAdapters(env, flags, &adapters);
>>>> +    if (ret != ERROR_SUCCESS) {
>>>> +        return STS_ERROR;
>>>>      }
>>>>
>>>> -    /*
>>>> -     * Iterate through the list of adapters as registry settings are
>>>> -     * keyed on the adapter name (GUID).
>>>> -     */
>>>> -    if (ret == ERROR_SUCCESS) {
>>>> -        IP_ADAPTER_INFO *curr = adapterP;
>>>> -        while (curr != NULL) {
>>>> -            char key[MAX_STR_LEN];
>>>> -
>>>> -            sprintf(key,
>>>> -
>>>>  "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
>>>> -                curr->AdapterName);
>>>> -
>>>> -            ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
>>>> -                               key,
>>>> -                               0,
>>>> -                               KEY_READ,
>>>> -                               (PHKEY)&hKey);
>>>> -            if (ret == ERROR_SUCCESS) {
>>>> -                DWORD enableDhcp = 0;
>>>> -
>>>> -                /*
>>>> -                 * Is DHCP enabled on this interface
>>>> -                 */
>>>> -                dwLen = sizeof(enableDhcp);
>>>> -                ret = RegQueryValueEx(hKey, "EnableDhcp", NULL,
>>>> &ulType,
>>>> -                                     (LPBYTE)&enableDhcp, &dwLen);
>>>> -
>>>> -                /*
>>>> -                 * If we don't have the suffix list when get the Domain
>>>> -                 * or DhcpDomain. If DHCP is enabled then Domain
>>>> overides
>>>> -                 * DhcpDomain
>>>> -                 */
>>>> -                if (!gotSearchList) {
>>>> -                    result[0] = '\0';
>>>> -                    dwLen = sizeof(result);
>>>> -                    ret = RegQueryValueEx(hKey, "Domain", NULL,
>>>> &ulType,
>>>> -                                         (LPBYTE)&result, &dwLen);
>>>> -                    if (((ret != ERROR_SUCCESS) || (strlen(result) ==
>>>> 0)) &&
>>>> -                        enableDhcp) {
>>>> -                        dwLen = sizeof(result);
>>>> -                        ret = RegQueryValueEx(hKey, "DhcpDomain",
>>>> NULL, &ulType,
>>>> -                                              (LPBYTE)&result, &dwLen);
>>>> -                    }
>>>> -                    if (ret == ERROR_SUCCESS) {
>>>> -                        assert(ulType == REG_SZ);
>>>> -                        strappend(sl, result);
>>>> -                    }
>>>> -                }
>>>> -
>>>> -                /*
>>>> -                 * Get DNS servers based on NameServer or
>>>> DhcpNameServer
>>>> -                 * registry setting. If NameServer is set then it
>>>> overrides
>>>> -                 * DhcpNameServer (even if DHCP is enabled).
>>>> -                 */
>>>> -                result[0] = '\0';
>>>> +    adapter = adapters;
>>>> +    while (adapter != NULL) {
>>>> +        // Only load config from enabled adapters.
>>>> +        if (adapter->OperStatus == IfOperStatusUp) {
>>>> +            dnsServer = adapter->FirstDnsServerAddress;
>>>> +            while (dnsServer != NULL) {
>>>> +                address = dnsServer->Address.lpSockaddr;
>>>>                  dwLen = sizeof(result);
>>>> -                ret = RegQueryValueEx(hKey, "NameServer", NULL,
>>>> &ulType,
>>>> -                                     (LPBYTE)&result, &dwLen);
>>>> -                if (((ret != ERROR_SUCCESS) || (strlen(result) == 0))
>>>> &&
>>>> -                    enableDhcp) {
>>>> -                    dwLen = sizeof(result);
>>>> -                    ret = RegQueryValueEx(hKey, "DhcpNameServer",
>>>> NULL, &ulType,
>>>> -                                          (LPBYTE)&result, &dwLen);
>>>> -                }
>>>> -                if (ret == ERROR_SUCCESS) {
>>>> -                    assert(ulType == REG_SZ);
>>>> +                ret =
>>>> WSAAddressToStringA(dnsServer->Address.lpSockaddr,
>>>> +                          dnsServer->Address.iSockaddrLength, NULL,
>>>> +                          result, &dwLen);
>>>> +                if (ret == 0) {
>>>>                      strappend(ns, result);
>>>>                  }
>>>>
>>>> -                /*
>>>> -                 * Finished with this registry key
>>>> -                 */
>>>> -                RegCloseKey(hKey);
>>>> +                dnsServer = dnsServer->Next;
>>>>              }
>>>>
>>>> -            /*
>>>> -             * Onto the next adapeter
>>>> -             */
>>>> -            curr = curr->Next;
>>>> +            // Add connection-specific search domains in addition to
>>>> global one.
>>>> +            suffix = adapter->FirstDnsSuffix;
>>>> +            while (suffix != NULL) {
>>>> +                ret = WideCharToMultiByte(CP_UTF8, 0, suffix->String,
>>>> -1,
>>>> +                    result, sizeof(result), NULL, NULL);
>>>> +                if (ret != 0) {
>>>> +                    strappend(sl, result);
>>>> +                }
>>>> +
>>>> +                suffix = suffix->Next;
>>>> +            }
>>>>          }
>>>> -    }
>>>>
>>>> -    /*
>>>> -     * Free the adpater structure
>>>> -     */
>>>> -    if (adapterP) {
>>>> -        free(adapterP);
>>>> +        adapter = adapter->Next;
>>>>      }
>>>>
>>>> +    free(adapters);
>>>> +
>>>>      return STS_SL_FOUND & STS_NS_FOUND;
>>>>  }
>>>>
>>>> @@ -260,7 +189,7 @@
>>>> Java_sun_net_dns_ResolverConfigurationImpl_loadDNSconfig0(JNIEnv *env,
>>>> jclass cl
>>>>      searchlist[0] = '\0';
>>>>      nameservers[0] = '\0';
>>>>
>>>> -    if (loadConfig(searchlist, nameservers) != STS_ERROR) {
>>>> +    if (loadConfig(env, searchlist, nameservers) != STS_ERROR) {
>>>>
>>>>          /*
>>>>           * Populate static fields in
>>>> sun.net.DefaultResolverConfiguration
>>>>
>>>> On Sat, Dec 7, 2019 at 12:41 AM Alan Bateman <Alan.Bateman at oracle.com>
>>>> wrote:
>>>>
>>>>> On 06/12/2019 15:34, Aleks Efimov wrote:
>>>>> > :
>>>>> >
>>>>> > I've created webrev with your latest changes - it could be
>>>>> convenient
>>>>> > for other reviewers:
>>>>> > http://cr.openjdk.java.net/~aefimov/anuraaga/7006496/00
>>>>> >
>>>>> > I will happily sponsor this change once it gets necessary approvals
>>>>> This could be split into two issues but since the code using
>>>>> StringTokenizer is changing significantly then we should replace it
>>>>> with
>>>>> regex while we there.
>>>>>
>>>>> -Alan
>>>>>
>>>>
>>>>
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/net-dev/attachments/20191218/1fd84cfe/attachment-0001.htm>


More information about the net-dev mailing list