[PATCH] 7006496: Use modern Windows API to retrieve OS DNS servers
Aleks Efimov
aleksej.efimov at oracle.com
Fri Dec 6 15:34:26 UTC 2019
Hi Anuraag,
I've run your latest patch through our CI system - no issues detected
with it.
The code changes look good to me except for few formatting issues:
src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java:64:
Trailing whitespace
src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java:84:
Trailing whitespace
src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java:77:
Tab characters
src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java:103:
Tab characters
src/java.base/windows/native/libnet/ResolverConfigurationImpl.c:78:
Trailing whitespace
src/java.base/windows/native/libnet/ResolverConfigurationImpl.c:132:
Trailing whitespace
src/java.base/windows/native/libnet/ResolverConfigurationImpl.c:145:
Trailing whitespace
Also, since your changes are not trivial I would suggest changing the
copyright years in the modified files.
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
With Best Regards,
Aleksei
On 06/12/2019 06:33, Anuraag Agrawal wrote:
> Hi Aleksei,
>
> Thanks for the suggestion! Indeed I didn't consider the implication of
> duplicates on the pre-allocation, this is a simpler approach. I've
> incorporated it into the patch.
>
> 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..9e7c47bd44 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,10 @@
>
> 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 +51,57 @@ 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;
> + 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.
> + StringTokenizer st = new StringTokenizer(str, " ");
> + ArrayList<String> l = new ArrayList<>(st.countTokens());
> + while (st.hasMoreTokens()) {
> + String s = st.nextToken();
> + if (!l.contains(s)) {
> + l.add(s);
> + }
> + }
> + l.trimToSize();
> + return l;
> + }
>
> - // 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<>();
> + // 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
> + StringTokenizer st = new StringTokenizer(str, " ");
> + ArrayList<String> l = new ArrayList<>(st.countTokens());
>
> - // 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);
> + if (!s.isEmpty()) {
> + if (s.indexOf(':') >= 0 && s.charAt(0) != '[') {
> + // Not BSD style
> + s = '[' + s + ']';
> + }
> + if (!l.contains(s)) {
> + l.add(s);
> + }
> }
> }
> - return ll;
> + l.trimToSize();
> + return l;
> }
>
> // Load DNS configuration from OS
> @@ -81,28 +109,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..83100aa9ad 100644
> --- a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
> +++ b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
> @@ -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 Thu, Dec 5, 2019 at 12:56 AM Aleks Efimov
> <aleksej.efimov at oracle.com <mailto:aleksej.efimov at oracle.com>> wrote:
>
> Hi Anuraag,
>
> I've run your latest patch via our CI system and the results are good
>
> One comment about the code changes:
> I'm not sure that we need to pre-calculate the array list size
> since we can get the same name server address multiple times and
> we will ignore the duplicates later ('l.contains(s)' check). The
> default ArrayList constructor (10 elements size) and the
> 'ArrayList::trimToSize' could be used.
>
> Or maybe combine both approaches (pre-calculate + resize):
> Use 'StringTokenizer::countTokens' (replacement for
> 'allocateListForDelimitedString' method that can be deleted) for
> initial size calculation and after processing tokens call
> 'ArrayList::trimToSize'. For cases with no duplicates (more
> frequent case) it should be cheap.
>
> Best Regards,
> Aleksei
>
>
> On 03/12/2019 06:09, Anuraag Agrawal wrote:
>> Hi Aleksei,
>>
>> Thanks a lot for running the CI and even looking into the
>> failures! I had only intended to update comments in the second
>> patch and admittedly didn't actually run the code, obviously that
>> wasn't a good idea... Here's an updated patch with the call to
>> loadDNSConfig0() restored.
>>
>> 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..03c57da415 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,10 @@
>>
>> 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 +51,69 @@ 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;
>> + private static ArrayList<String> searchlist;
>> + private static ArrayList<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<>();
>> + // 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) {
>> + ArrayList<String> l = allocateListForDelimitedString(str);
>>
>> - // comma and space are valid delimiters
>> - StringTokenizer st = new StringTokenizer(str, ", ");
>> + // String is delimited by space.
>> + StringTokenizer st = new StringTokenizer(str, " ");
>> while (st.hasMoreTokens()) {
>> String s = st.nextToken();
>> - if (!ll.contains(s)) {
>> - ll.add(s);
>> + if (!l.contains(s)) {
>> + l.add(s);
>> }
>> }
>> - return ll;
>> + 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) {
>> + ArrayList<String> l = allocateListForDelimitedString(str);
>> +
>> + // String is delimited by space
>> + StringTokenizer st = new StringTokenizer(str, " ");
>> + while (st.hasMoreTokens()) {
>> + String s = st.nextToken();
>> + if (!s.isEmpty()) {
>> + if (s.indexOf(':') >= 0 && s.charAt(0) != '[') {
>> + // Not BSD style
>> + s = '[' + s + ']';
>> + }
>> + if (!l.contains(s)) {
>> + l.add(s);
>> + }
>> + }
>> + }
>> + return l;
>> + }
>> +
>> + private ArrayList<String>
>> allocateListForDelimitedString(String str) {
>> + int num = 0;
>> + for (int i = 0; i < str.length(); i++) {
>> + char c = str.charAt(i);
>> + // String is space separated list of items
>> + if (c == ' ') {
>> + num++;
>> + }
>> + }
>> + // Actual num is number of delimiters + 1
>> + return new ArrayList<String>(num + 1);
>> }
>>
>> // Load DNS configuration from OS
>> @@ -81,28 +121,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..83100aa9ad 100644
>> --- a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>> +++ b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>> @@ -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 Tue, Dec 3, 2019 at 1:24 AM Aleks Efimov
>> <aleksej.efimov at oracle.com <mailto:aleksej.efimov at oracle.com>> wrote:
>>
>> Hey Anuraag,
>>
>> I've looked at the failures and I believe that your second
>> patch accidentally removed 'loadDNSconfig0()' native call.
>> Putting it back to
>> src/java.base/windows/classes/sun/net/dns/ResolverConfigurationImpl.java:145
>> resolves all these failures.
>>
>> -Aleksei
>>
>>
>> On 02/12/2019 13:04, Aleks Efimov wrote:
>>> Hi Anuraag,
>>>
>>> I've submited your patch to our CI system and I'm observing
>>> a bunch of NPE failures with such stack trace:
>>> java.lang.NullPointerException
>>> at
>>> java.base/sun.net.dns.ResolverConfigurationImpl.allocateListForDelimitedString(ResolverConfigurationImpl.java:108)
>>> at
>>> java.base/sun.net.dns.ResolverConfigurationImpl.stringToList(ResolverConfigurationImpl.java:68)
>>> at
>>> java.base/sun.net.dns.ResolverConfigurationImpl.loadConfig(ResolverConfigurationImpl.java:149)
>>> at
>>> java.base/sun.net.dns.ResolverConfigurationImpl.nameservers(ResolverConfigurationImpl.java:172)
>>> at
>>> jdk.naming.dns/com.sun.jndi.dns.DnsContextFactory.platformServersAvailable(DnsContextFactory.java:94)
>>> at
>>> jdk.naming.dns/com.sun.jndi.dns.DnsContextFactory.platformServersUsed(DnsContextFactory.java:171)
>>> at
>>> jdk.naming.dns/com.sun.jndi.dns.DnsContextFactory.getContext(DnsContextFactory.java:83)
>>> at
>>> jdk.naming.dns/com.sun.jndi.dns.DnsContextFactory.urlToContext(DnsContextFactory.java:120)
>>> at
>>> jdk.naming.dns/com.sun.jndi.dns.DnsContextFactory.getInitialContext(DnsContextFactory.java:64)
>>> at
>>> java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:730)
>>> at
>>> java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
>>> at
>>> java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
>>> at
>>> java.naming/javax.naming.InitialContext.<init>(InitialContext.java:208)
>>> at
>>> java.naming/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:130)
>>> at
>>> LookupWithAnyAttrProp.runTest(LookupWithAnyAttrProp.java:57)
>>> at TestBase.launch(TestBase.java:82)
>>> at TestBase.run(TestBase.java:50)
>>> at LookupWithAnyAttrProp.main(LookupWithAnyAttrProp.java:43)
>>> at
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
>>> Method)
>>> at
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>> at
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>> at
>>> java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>> at
>>> com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127)
>>> at java.base/java.lang.Thread.run(Thread.java:832)
>>>
>>> Few examples of failing tests:
>>> test/jdk/com/sun/jndi/dns/FedTests/ListSubInterior.java (and
>>> others in the same folder)
>>> test/jdk/com/sun/jndi/dns/FactoryTests/LookupWithAnyAttrProp.java
>>> (and others in the same folder)
>>>
>>> Test platform is: Windows Server 2012 R2 6.3
>>>
>>> With Best Regards,
>>> Aleksei
>>>
>>> On 25/11/2019 05:09, Anuraag Agrawal wrote:
>>>> Hi Bernd,
>>>>
>>>> Thanks for the look and suggestion. I have updated those
>>>> comments, as well as added several more to explain the
>>>> native code aspects better which I hope helps future
>>>> readers of the code. Hope it looks better now.
>>>>
>>>> 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..18996f0ee0 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,10 @@
>>>>
>>>> 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 +51,69 @@ 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;
>>>> + private static ArrayList<String> searchlist;
>>>> + private static ArrayList<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<>();
>>>> + // 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) {
>>>> + ArrayList<String> l =
>>>> allocateListForDelimitedString(str);
>>>>
>>>> - // comma and space are valid delimiters
>>>> - StringTokenizer st = new StringTokenizer(str, ", ");
>>>> + // String is delimited by space.
>>>> + StringTokenizer st = new StringTokenizer(str, " ");
>>>> while (st.hasMoreTokens()) {
>>>> String s = st.nextToken();
>>>> - if (!ll.contains(s)) {
>>>> - ll.add(s);
>>>> + if (!l.contains(s)) {
>>>> + l.add(s);
>>>> }
>>>> }
>>>> - return ll;
>>>> + 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) {
>>>> + ArrayList<String> l =
>>>> allocateListForDelimitedString(str);
>>>> +
>>>> + // String is delimited by space
>>>> + StringTokenizer st = new StringTokenizer(str, " ");
>>>> + while (st.hasMoreTokens()) {
>>>> + String s = st.nextToken();
>>>> + if (!s.isEmpty()) {
>>>> + if (s.indexOf(':') >= 0 && s.charAt(0) !=
>>>> '[') {
>>>> + // Not BSD style
>>>> + s = '[' + s + ']';
>>>> + }
>>>> + if (!l.contains(s)) {
>>>> + l.add(s);
>>>> + }
>>>> + }
>>>> + }
>>>> + return l;
>>>> + }
>>>> +
>>>> + private ArrayList<String>
>>>> allocateListForDelimitedString(String str) {
>>>> + int num = 0;
>>>> + for (int i = 0; i < str.length(); i++) {
>>>> + char c = str.charAt(i);
>>>> + // String is space separated list of items
>>>> + if (c == ' ') {
>>>> + num++;
>>>> + }
>>>> + }
>>>> + // Actual num is number of delimiters + 1
>>>> + return new ArrayList<String>(num + 1);
>>>> }
>>>>
>>>> // Load DNS configuration from OS
>>>> @@ -81,28 +121,33 @@ 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
>>>> - //
>>>> - loadDNSconfig0();
>>>> + // 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.
>>>>
>>>> - 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..83100aa9ad 100644
>>>> ---
>>>> a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> +++
>>>> b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> @@ -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 Sun, Nov 24, 2019 at 11:21 PM Bernd Eckenfels
>>>> <ecki at zusammenkunft.net <mailto:ecki at zusammenkunft.net>> wrote:
>>>>
>>>> Hello Anuraag,
>>>>
>>>> The patch looks like a good idea (especially the
>>>> additional cleanup for nanos and arraylist) Just a
>>>> minor thing I noticed there are two comments talking
>>>> about „comma and space“ but the code below will only
>>>> tokenize by space. Imguess the comment needs to be
>>>> fixed, for the next review round.
>>>>
>>>> Gruss
>>>> Bernd
>>>> --
>>>> http://bernd.eckenfels.net
>>>> ------------------------------------------------------------------------
>>>> *Von:* net-dev <net-dev-bounces at openjdk.java.net
>>>> <mailto:net-dev-bounces at openjdk.java.net>> im Auftrag
>>>> von Anuraag Agrawal <anuraaga at gmail.com
>>>> <mailto:anuraaga at gmail.com>>
>>>> *Gesendet:* Sonntag, November 24, 2019 10:47 AM
>>>> *An:* net-dev at openjdk.java.net
>>>> <mailto:net-dev at openjdk.java.net>
>>>> *Betreff:* [PATCH] 7006496: Use modern Windows API to
>>>> retrieve OS DNS servers
>>>> Hello,
>>>>
>>>> While investigating DNS resolution failure using Netty
>>>> (https://github.com/netty/netty/issues/9796), I came
>>>> across an old JDK bug where on Windows, the list of OS
>>>> name servers includes those for disabled interfaces
>>>> (https://bugs.openjdk.java.net/browse/JDK-7006496).
>>>> This is problematic since it will often include values
>>>> from a previously registered network that is not
>>>> available anymore, hence resolution requests would be
>>>> guaranteed to fail.
>>>>
>>>> The current approach reads DNS name servers from the
>>>> registry, where it isn't possible to read whether an
>>>> adapter is actually enabled or not. However, Windows
>>>> Vista+ (minimum JDK8+ supported Windows) include an API
>>>> that can be used to examine whether an adapter is
>>>> currently enabled, and also return its DNS servers. So
>>>> I've created this patch to update the name server
>>>> lookup to use this technique. I can confirm that now
>>>> only name servers from enabled adapters are loaded. A
>>>> side effect is the previous approach could only read
>>>> IPv4 - now IPv6 DNS servers are also loaded. The unix
>>>> implementation seems to do this too, so I don't think
>>>> this should cause issues but I can filter to only IPv4
>>>> to be more conservative if desired.
>>>>
>>>> I have also cleaned some low hanging fruit in what
>>>> seems to be very old code
>>>>
>>>> - Use ArrayList instead of LinkedList since it can be
>>>> accurately preallocated and is not mutated
>>>> - Use nanoTime instead of currentTimeMillis for refresh
>>>> timer to not cause problems during OS time changes.
>>>> - Simplify tokenizer to only tokenize on space, there
>>>> is never a comma separated list passed to it as we
>>>> create the list in our JNI code
>>>>
>>>> This is my first patch for OpenJDK - happy to accept
>>>> any feedback.
>>>>
>>>> Thanks for the consideration.
>>>>
>>>> Inlined patch follows (also attached but I've had
>>>> attached patch scrubbed when submitting to jmh-dev
>>>> before...)
>>>>
>>>> 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..dde871cf19 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,10 @@
>>>>
>>>> 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 +51,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;
>>>> + private static ArrayList<String> searchlist;
>>>> + private static ArrayList<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<>();
>>>> + // Parse string that consists of token delimited
>>>> by space
>>>> + // and return ArrayList
>>>> + private ArrayList<String> stringToList(String str) {
>>>> + ArrayList<String> l =
>>>> allocateListForDelimitedString(str);
>>>>
>>>> // comma and space are valid delimiters
>>>> - StringTokenizer st = new StringTokenizer(str,
>>>> ", ");
>>>> + StringTokenizer st = new StringTokenizer(str,
>>>> " ");
>>>> while (st.hasMoreTokens()) {
>>>> String s = st.nextToken();
>>>> - if (!ll.contains(s)) {
>>>> - ll.add(s);
>>>> + if (!l.contains(s)) {
>>>> + l.add(s);
>>>> }
>>>> }
>>>> - return ll;
>>>> + return l;
>>>> + }
>>>> +
>>>> + // Parse string that consists of token delimited
>>>> by space
>>>> + // and return ArrayList. Converts IPv6 addresses
>>>> to BSD-style.
>>>> + private ArrayList<String> addressesToList(String
>>>> str) {
>>>> + ArrayList<String> l =
>>>> allocateListForDelimitedString(str);
>>>> +
>>>> + // comma and space are valid delimiters
>>>> + StringTokenizer st = new StringTokenizer(str,
>>>> " ");
>>>> + while (st.hasMoreTokens()) {
>>>> + String s = st.nextToken();
>>>> + if (!s.isEmpty()) {
>>>> + if (s.indexOf(':') >= 0 && s.charAt(0)
>>>> != '[') {
>>>> + // Not BSD style
>>>> + s = '[' + s + ']';
>>>> + }
>>>> + if (!l.contains(s)) {
>>>> + l.add(s);
>>>> + }
>>>> + }
>>>> + }
>>>> + return l;
>>>> + }
>>>> +
>>>> + private ArrayList<String>
>>>> allocateListForDelimitedString(String str) {
>>>> + int num = 0;
>>>> + for (int i = 0; i < str.length(); i++) {
>>>> + char c = str.charAt(i);
>>>> + // String is space separated list of items
>>>> + if (c == ' ') {
>>>> + num++;
>>>> + }
>>>> + }
>>>> + // Actual num is number of delimiters + 1
>>>> + return new ArrayList<String>(num + 1);
>>>> }
>>>>
>>>> // Load DNS configuration from OS
>>>> @@ -88,8 +124,8 @@ public class ResolverConfigurationImpl
>>>> changed = false;
>>>> } else {
>>>> if (lastRefresh >= 0) {
>>>> - long currTime =
>>>> System.currentTimeMillis();
>>>> - if ((currTime - lastRefresh) < TIMEOUT) {
>>>> + long currTime = System.nanoTime();
>>>> + if ((currTime - lastRefresh) <
>>>> TIMEOUT_NANOS) {
>>>> return;
>>>> }
>>>> }
>>>> @@ -100,9 +136,9 @@ public class ResolverConfigurationImpl
>>>> //
>>>> loadDNSconfig0();
>>>>
>>>> - lastRefresh = System.currentTimeMillis();
>>>> + 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..83100aa9ad 100644
>>>> ---
>>>> a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> +++
>>>> b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c
>>>> @@ -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
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/net-dev/attachments/20191206/52ae0897/attachment-0001.html>
More information about the net-dev
mailing list