Hi all, Apologies for the spam. I made one more tweak to follow up the previous, and removed the default value of -1 for lastRefresh. Now that there is no semantic meaning to -1, I think unspecified default (effectively zero) is more appropriate and easy to reason about.
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..aefe44e9b3 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. @@ -42,38 +42,64 @@ public class ResolverConfigurationImpl // Resolver options private final Options opts; - // Addresses have changed - private static boolean changed = false; + // Addresses have changed. We default to true to make sure we + // resolve the first time it is requested. + private static boolean changed = true; // Time of last refresh. - private static long lastRefresh = -1; + private static long lastRefresh; // 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 (!s.isEmpty() && !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 (!s.isEmpty() && !l.contains(s)) { + l.add(s); + } + } + } + l.trimToSize(); + return l; } // Load DNS configuration from OS @@ -81,28 +107,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 { - if (lastRefresh >= 0) { - long currTime = System.currentTimeMillis(); - if ((currTime - lastRefresh) < TIMEOUT) { - return; - } + // Otherwise we refresh if TIMEOUT_NANOS has passed since last + // load. + long currTime = System.nanoTime(); + // lastRefresh will always have been set once because we start with + // changed = true. + 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..e830b8e70b 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,17 +24,15 @@ */ #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 +#define MAX_STR_LEN 1024 #define STS_NO_CONFIG 0x0 /* no configuration found */ #define STS_SL_FOUND 0x1 /* search list found */ @@ -48,9 +46,11 @@ 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" + * Utility routine to append s2 to s1 with a comma delimiter. + * strappend(s1="abc", "def") => "abc,def" * strappend(s1="", "def") => "def */ void strappend(char *s1, char *s2) { @@ -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,128 +103,74 @@ 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; } /* - * Initialize JNI field IDs. + * Initialize JNI field IDs and classes. */ JNIEXPORT void JNICALL Java_sun_net_dns_ResolverConfigurationImpl_init0(JNIEnv *env, jclass cls) @@ -260,7 +197,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 @@ -272,8 +209,6 @@ Java_sun_net_dns_ResolverConfigurationImpl_loadDNSconfig0(JNIEnv *env, jclass cl obj = (*env)->NewStringUTF(env, nameservers); CHECK_NULL(obj); (*env)->SetStaticObjectField(env, cls, nameserversID, obj); - } else { - JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); } } On Fri, Jan 10, 2020 at 12:17 AM Anuraag Agrawal <anura...@gmail.com> wrote: > Hi Daniel, > > Thanks for the review! > > On Thu, Jan 9, 2020 at 9:04 PM Daniel Fuchs <daniel.fu...@oracle.com> > wrote: > >> Hi, >> >> Two small remarks: >> >> ResolverConfigurationImpl.java: >> >> 71 if (!l.contains(s)) { >> >> Maybe empty strings should be skipped here too. >> > > Makes sense, added the check. > > >> >> I believe it would be more correct to change this line: >> >> 117 if (lastRefresh >= 0) { >> >> to >> >> 117 if (lastRefresh != -1) { >> >> as System.nanoTime() can return negative values. >> > > Had never realized nanoTime can return negative values, I have to check > all my other code for bugs now ;) I have gone ahead and removed this check > altogether, instead defaulting "changed" to true so we always load on the > first time through. I think this should be the most precise. > > 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..0f161ea4a8 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. > @@ -42,38 +42,64 @@ public class ResolverConfigurationImpl > // Resolver options > private final Options opts; > > - // Addresses have changed > - private static boolean changed = false; > + // Addresses have changed. We default to true to make sure we > + // resolve the first time it is requested. > + private static boolean changed = true; > > // Time of last refresh. > private static long lastRefresh = -1; > > // 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 (!s.isEmpty() && !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 (!s.isEmpty() && !l.contains(s)) { > + l.add(s); > + } > + } > + } > + l.trimToSize(); > + return l; > } > > // Load DNS configuration from OS > @@ -81,28 +107,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 { > - if (lastRefresh >= 0) { > - long currTime = System.currentTimeMillis(); > - if ((currTime - lastRefresh) < TIMEOUT) { > - return; > - } > + // Otherwise we refresh if TIMEOUT_NANOS has passed since last > + // load. > + long currTime = System.nanoTime(); > + // lastRefresh will always have been set once because we > start with > + // changed = true. > + 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..e830b8e70b 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,17 +24,15 @@ > */ > > #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 > +#define MAX_STR_LEN 1024 > > #define STS_NO_CONFIG 0x0 /* no configuration found */ > #define STS_SL_FOUND 0x1 /* search list found */ > @@ -48,9 +46,11 @@ > 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" > + * Utility routine to append s2 to s1 with a comma delimiter. > + * strappend(s1="abc", "def") => "abc,def" > * strappend(s1="", "def") => "def > */ > void strappend(char *s1, char *s2) { > @@ -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,128 +103,74 @@ 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; > } > > > /* > - * Initialize JNI field IDs. > + * Initialize JNI field IDs and classes. > */ > JNIEXPORT void JNICALL > Java_sun_net_dns_ResolverConfigurationImpl_init0(JNIEnv *env, jclass cls) > @@ -260,7 +197,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 > @@ -272,8 +209,6 @@ > Java_sun_net_dns_ResolverConfigurationImpl_loadDNSconfig0(JNIEnv *env, > jclass cl > obj = (*env)->NewStringUTF(env, nameservers); > CHECK_NULL(obj); > (*env)->SetStaticObjectField(env, cls, nameserversID, obj); > - } else { > - JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); > } > } > > > >> >> >> best regards, >> >> -- daniel >> >> >> On 09/01/2020 00:54, Aleks Efimov wrote: >> > Got the testing results: the CI is happy with the last patch - no JNDI >> > test failures observed >> > >> > Kind Regards, >> > Aleksei >> >
windows-dns.patch
Description: Binary data