/* * Copyright (c) 2002, 2013, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include #include #include #include #include #include #include #include #include "jni_util.h" #define MAX_STR_LEN 256 #define STS_NO_CONFIG 0x0 /* no configuration found */ #define STS_SL_FOUND 0x1 /* search list found */ #define STS_NS_FOUND 0x2 /* name servers found */ #define STS_ERROR -1 /* error return lodConfig failed memory allccation failure*/ #define IS_SL_FOUND(sts) (sts & STS_SL_FOUND) #define IS_NS_FOUND(sts) (sts & STS_NS_FOUND) /* JNI ids */ static jfieldID searchlistID; static jfieldID nameserversID; /* * Utility routine to append s2 to s1 with a space delimiter. * strappend(s1="abc", "def") => "abc def" * strappend(s1="", "def") => "def */ void strappend(char *s1, char *s2) { size_t len; if (s2[0] == '\0') /* nothing to append */ return; len = strlen(s1)+1; if (s1[0] != 0) /* needs space character */ len++; if (len + strlen(s2) > MAX_STR_LEN) /* insufficient space */ return; if (s1[0] != 0) { 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. */ static int loadConfig(char *sl, char *ns) { IP_ADAPTER_INFO *adapterP; ULONG size; DWORD ret; DWORD dwLen; ULONG ulType; char result[MAX_STR_LEN]; HANDLE hKey; int gotSearchList = 0; /* * First see if there is a global suffix list specified. */ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, (PHKEY)&hKey); if (ret == ERROR_SUCCESS) { dwLen = sizeof(result); ret = RegQueryValueEx(hKey, "SearchList", NULL, &ulType, (LPBYTE)&result, &dwLen); if (ret == ERROR_SUCCESS) { 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); } /* * 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'; 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); strappend(ns, result); } /* * Finished with this registry key */ RegCloseKey(hKey); } /* * Onto the next adapeter */ curr = curr->Next; } } /* * Free the adpater structure */ if (adapterP) { free(adapterP); } return STS_SL_FOUND & STS_NS_FOUND; } /* * Initialize JNI field IDs. */ JNIEXPORT void JNICALL Java_sun_net_dns_ResolverConfigurationImpl_init0(JNIEnv *env, jclass cls) { searchlistID = (*env)->GetStaticFieldID(env, cls, "os_searchlist", "Ljava/lang/String;"); CHECK_NULL(searchlistID); nameserversID = (*env)->GetStaticFieldID(env, cls, "os_nameservers", "Ljava/lang/String;"); } /* * Class: sun_net_dns_ResolverConfgurationImpl * Method: loadConfig0 * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_net_dns_ResolverConfigurationImpl_loadDNSconfig0(JNIEnv *env, jclass cls) { char searchlist[MAX_STR_LEN]; char nameservers[MAX_STR_LEN]; jstring obj; searchlist[0] = '\0'; nameservers[0] = '\0'; if (loadConfig(searchlist, nameservers) != STS_ERROR) { /* * Populate static fields in sun.net.DefaultResolverConfiguration */ obj = (*env)->NewStringUTF(env, searchlist); CHECK_NULL(obj); (*env)->SetStaticObjectField(env, cls, searchlistID, obj); obj = (*env)->NewStringUTF(env, nameservers); CHECK_NULL(obj); (*env)->SetStaticObjectField(env, cls, nameserversID, obj); } else { JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); } } /* * Class: sun_net_dns_ResolverConfgurationImpl * Method: notifyAddrChange0 * Signature: ()I */ JNIEXPORT jint JNICALL Java_sun_net_dns_ResolverConfigurationImpl_notifyAddrChange0(JNIEnv *env, jclass cls) { OVERLAPPED ol; HANDLE h; DWORD rc, xfer; ol.hEvent = (HANDLE)0; rc = NotifyAddrChange(&h, &ol); if (rc == ERROR_IO_PENDING) { rc = GetOverlappedResult(h, &ol, &xfer, TRUE); if (rc != 0) { return 0; /* address changed */ } } /* error */ return -1; }