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 searchlist; - private static LinkedList nameservers; + private static ArrayList searchlist; + private static ArrayList nameservers; - // Parse string that consists of token delimited by space or commas - // and return LinkedHashMap - private LinkedList stringToList(String str) { - LinkedList ll = new LinkedList<>(); + // Parse string that consists of token delimited by space + // and return ArrayList + private ArrayList stringToList(String str) { + ArrayList 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 addressesToList(String str) { + ArrayList 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 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(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 #include #include +#include #include #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