src/jdk.dns.client/windows/native/libresolve/DnsResolverConfiguration.c
branchaefimov-dns-client-branch
changeset 59100 b92aac38b046
parent 59099 fcdb8e7ead8f
child 59101 258033faefc9
equal deleted inserted replaced
59099:fcdb8e7ead8f 59100:b92aac38b046
     1 /*
       
     2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include <stdlib.h>
       
    27 #include <windows.h>
       
    28 #include <stdio.h>
       
    29 #include <stddef.h>
       
    30 #include <iprtrmib.h>
       
    31 #include <time.h>
       
    32 #include <assert.h>
       
    33 #include <iphlpapi.h>
       
    34 
       
    35 #include "jni_util.h"
       
    36 
       
    37 #define MAX_STR_LEN         256
       
    38 
       
    39 #define STS_NO_CONFIG       0x0             /* no configuration found */
       
    40 #define STS_SL_FOUND        0x1             /* search list found */
       
    41 #define STS_NS_FOUND        0x2             /* name servers found */
       
    42 #define STS_ERROR           -1              /* error return  lodConfig failed memory allccation failure*/
       
    43 
       
    44 #define IS_SL_FOUND(sts)    (sts & STS_SL_FOUND)
       
    45 #define IS_NS_FOUND(sts)    (sts & STS_NS_FOUND)
       
    46 
       
    47 /* JNI ids */
       
    48 static jfieldID searchlistID;
       
    49 static jfieldID nameserversID;
       
    50 
       
    51 /*
       
    52  * Utility routine to append s2 to s1 with a space delimiter.
       
    53  *  strappend(s1="abc", "def")  => "abc def"
       
    54  *  strappend(s1="", "def")     => "def
       
    55  */
       
    56 void strappend(char *s1, char *s2) {
       
    57     size_t len;
       
    58 
       
    59     if (s2[0] == '\0')                      /* nothing to append */
       
    60         return;
       
    61 
       
    62     len = strlen(s1)+1;
       
    63     if (s1[0] != 0)                         /* needs space character */
       
    64         len++;
       
    65     if (len + strlen(s2) > MAX_STR_LEN)     /* insufficient space */
       
    66         return;
       
    67 
       
    68     if (s1[0] != 0) {
       
    69         strcat(s1, " ");
       
    70     }
       
    71     strcat(s1, s2);
       
    72 }
       
    73 
       
    74 /*
       
    75  * Windows 2000/XP
       
    76  *
       
    77  * Use registry approach based on settings described in Appendix C
       
    78  * of "Microsoft Windows 2000 TCP/IP Implementation Details".
       
    79  *
       
    80  * DNS suffix list is obtained from SearchList registry setting. If
       
    81  * this is not specified we compile suffix list based on the
       
    82  * per-connection domain suffix.
       
    83  *
       
    84  * DNS name servers and domain settings are on a per-connection
       
    85  * basic. We therefore enumerate the network adapters to get the
       
    86  * names of each adapter and then query the corresponding registry
       
    87  * settings to obtain NameServer/DhcpNameServer and Domain/DhcpDomain.
       
    88  */
       
    89 static int loadConfig(char *sl, char *ns) {
       
    90     IP_ADAPTER_INFO *adapterP;
       
    91     ULONG size;
       
    92     DWORD ret;
       
    93     DWORD dwLen;
       
    94     ULONG ulType;
       
    95     char result[MAX_STR_LEN];
       
    96     HANDLE hKey;
       
    97     int gotSearchList = 0;
       
    98 
       
    99     /*
       
   100      * First see if there is a global suffix list specified.
       
   101      */
       
   102     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
       
   103                        "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
       
   104                        0,
       
   105                        KEY_READ,
       
   106                        (PHKEY)&hKey);
       
   107     if (ret == ERROR_SUCCESS) {
       
   108         dwLen = sizeof(result);
       
   109         ret = RegQueryValueEx(hKey, "SearchList", NULL, &ulType,
       
   110                              (LPBYTE)&result, &dwLen);
       
   111         if (ret == ERROR_SUCCESS) {
       
   112             assert(ulType == REG_SZ);
       
   113             if (strlen(result) > 0) {
       
   114                 strappend(sl, result);
       
   115                 gotSearchList = 1;
       
   116             }
       
   117         }
       
   118         RegCloseKey(hKey);
       
   119     }
       
   120 
       
   121     /*
       
   122      * Ask the IP Helper library to enumerate the adapters
       
   123      */
       
   124     size = sizeof(IP_ADAPTER_INFO);
       
   125     adapterP = (IP_ADAPTER_INFO *)malloc(size);
       
   126     if (adapterP == NULL) {
       
   127         return STS_ERROR;
       
   128     }
       
   129     ret = GetAdaptersInfo(adapterP, &size);
       
   130     if (ret == ERROR_BUFFER_OVERFLOW) {
       
   131         IP_ADAPTER_INFO *newAdapterP = (IP_ADAPTER_INFO *)realloc(adapterP, size);
       
   132         if (newAdapterP == NULL) {
       
   133             free(adapterP);
       
   134             return STS_ERROR;
       
   135         }
       
   136         adapterP = newAdapterP;
       
   137 
       
   138         ret = GetAdaptersInfo(adapterP, &size);
       
   139     }
       
   140 
       
   141     /*
       
   142      * Iterate through the list of adapters as registry settings are
       
   143      * keyed on the adapter name (GUID).
       
   144      */
       
   145     if (ret == ERROR_SUCCESS) {
       
   146         IP_ADAPTER_INFO *curr = adapterP;
       
   147         while (curr != NULL) {
       
   148             char key[MAX_STR_LEN];
       
   149 
       
   150             sprintf(key,
       
   151                 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
       
   152                 curr->AdapterName);
       
   153 
       
   154             ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
       
   155                                key,
       
   156                                0,
       
   157                                KEY_READ,
       
   158                                (PHKEY)&hKey);
       
   159             if (ret == ERROR_SUCCESS) {
       
   160                 DWORD enableDhcp = 0;
       
   161 
       
   162                 /*
       
   163                  * Is DHCP enabled on this interface
       
   164                  */
       
   165                 dwLen = sizeof(enableDhcp);
       
   166                 ret = RegQueryValueEx(hKey, "EnableDhcp", NULL, &ulType,
       
   167                                      (LPBYTE)&enableDhcp, &dwLen);
       
   168 
       
   169                 /*
       
   170                  * If we don't have the suffix list when get the Domain
       
   171                  * or DhcpDomain. If DHCP is enabled then Domain overides
       
   172                  * DhcpDomain
       
   173                  */
       
   174                 if (!gotSearchList) {
       
   175                     result[0] = '\0';
       
   176                     dwLen = sizeof(result);
       
   177                     ret = RegQueryValueEx(hKey, "Domain", NULL, &ulType,
       
   178                                          (LPBYTE)&result, &dwLen);
       
   179                     if (((ret != ERROR_SUCCESS) || (strlen(result) == 0)) &&
       
   180                         enableDhcp) {
       
   181                         dwLen = sizeof(result);
       
   182                         ret = RegQueryValueEx(hKey, "DhcpDomain", NULL, &ulType,
       
   183                                               (LPBYTE)&result, &dwLen);
       
   184                     }
       
   185                     if (ret == ERROR_SUCCESS) {
       
   186                         assert(ulType == REG_SZ);
       
   187                         strappend(sl, result);
       
   188                     }
       
   189                 }
       
   190 
       
   191                 /*
       
   192                  * Get DNS servers based on NameServer or DhcpNameServer
       
   193                  * registry setting. If NameServer is set then it overrides
       
   194                  * DhcpNameServer (even if DHCP is enabled).
       
   195                  */
       
   196                 result[0] = '\0';
       
   197                 dwLen = sizeof(result);
       
   198                 ret = RegQueryValueEx(hKey, "NameServer", NULL, &ulType,
       
   199                                      (LPBYTE)&result, &dwLen);
       
   200                 if (((ret != ERROR_SUCCESS) || (strlen(result) == 0)) &&
       
   201                     enableDhcp) {
       
   202                     dwLen = sizeof(result);
       
   203                     ret = RegQueryValueEx(hKey, "DhcpNameServer", NULL, &ulType,
       
   204                                           (LPBYTE)&result, &dwLen);
       
   205                 }
       
   206                 if (ret == ERROR_SUCCESS) {
       
   207                     assert(ulType == REG_SZ);
       
   208                     strappend(ns, result);
       
   209                 }
       
   210 
       
   211                 /*
       
   212                  * Finished with this registry key
       
   213                  */
       
   214                 RegCloseKey(hKey);
       
   215             }
       
   216 
       
   217             /*
       
   218              * Onto the next adapeter
       
   219              */
       
   220             curr = curr->Next;
       
   221         }
       
   222     }
       
   223 
       
   224     /*
       
   225      * Free the adpater structure
       
   226      */
       
   227     if (adapterP) {
       
   228         free(adapterP);
       
   229     }
       
   230 
       
   231     return STS_SL_FOUND & STS_NS_FOUND;
       
   232 }
       
   233 
       
   234 
       
   235 /*
       
   236  * Initialize JNI field IDs.
       
   237  */
       
   238 JNIEXPORT void JNICALL
       
   239 Java_jdk_dns_conf_DnsResolverConfiguration_init0(JNIEnv *env, jclass cls)
       
   240 {
       
   241     searchlistID = (*env)->GetStaticFieldID(env, cls, "os_searchlist",
       
   242                                       "Ljava/lang/String;");
       
   243     CHECK_NULL(searchlistID);
       
   244     nameserversID = (*env)->GetStaticFieldID(env, cls, "os_nameservers",
       
   245                                       "Ljava/lang/String;");
       
   246 }
       
   247 
       
   248 /*
       
   249  * Class:     jdk_dns_conf_DnsResolverConfguration
       
   250  * Method:    loadConfig0
       
   251  * Signature: ()V
       
   252  */
       
   253 JNIEXPORT void JNICALL
       
   254 Java_jdk_dns_conf_DnsResolverConfiguration_loadDNSconfig0(JNIEnv *env, jclass cls)
       
   255 {
       
   256     char searchlist[MAX_STR_LEN];
       
   257     char nameservers[MAX_STR_LEN];
       
   258     jstring obj;
       
   259 
       
   260     searchlist[0] = '\0';
       
   261     nameservers[0] = '\0';
       
   262 
       
   263     if (loadConfig(searchlist, nameservers) != STS_ERROR) {
       
   264 
       
   265         /*
       
   266          * Populate static fields in jdk.dns.conf.ResolverConfiguration
       
   267          */
       
   268         obj = (*env)->NewStringUTF(env, searchlist);
       
   269         CHECK_NULL(obj);
       
   270         (*env)->SetStaticObjectField(env, cls, searchlistID, obj);
       
   271 
       
   272         obj = (*env)->NewStringUTF(env, nameservers);
       
   273         CHECK_NULL(obj);
       
   274         (*env)->SetStaticObjectField(env, cls, nameserversID, obj);
       
   275     } else {
       
   276         JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
       
   277     }
       
   278 }
       
   279 
       
   280 
       
   281 /*
       
   282  * Class:     jdk_dns_conf_DnsResolverConfguration
       
   283  * Method:    notifyAddrChange0
       
   284  * Signature: ()I
       
   285  */
       
   286 JNIEXPORT jint JNICALL
       
   287 Java_jdk_dns_conf_DnsResolverConfiguration_notifyAddrChange0(JNIEnv *env, jclass cls)
       
   288 {
       
   289     OVERLAPPED ol;
       
   290     HANDLE h;
       
   291     DWORD rc, xfer;
       
   292 
       
   293     ol.hEvent = (HANDLE)0;
       
   294     rc = NotifyAddrChange(&h, &ol);
       
   295     if (rc == ERROR_IO_PENDING) {
       
   296         rc = GetOverlappedResult(h, &ol, &xfer, TRUE);
       
   297         if (rc != 0) {
       
   298             return 0;   /* address changed */
       
   299         }
       
   300     }
       
   301 
       
   302     /* error */
       
   303     return -1;
       
   304 }