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

Aleks Efimov aleksej.efimov at oracle.com
Fri Dec 13 15:35:24 UTC 2019


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 
> <mailto: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 <mailto: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
>         <http://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
>         <http://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
>>         <mailto: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 <http://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 <http://test.domain.com>
>>
>>                 Ethernet adapter Ethernet:
>>
>>                    Connection-specific DNS Suffix  . :
>>                 test.domain.com <http://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
>>                 <http://isatap.test.domain.com>:
>>
>>                    Media State . . . . . . . . . . . : Media disconnected
>>                    Connection-specific DNS Suffix  . :
>>                 test.domain.com <http://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
>>>             <mailto: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/20191213/08031930/attachment-0001.htm>


More information about the net-dev mailing list