Java domain name resolution from JDK source code

Foreword

Communication over the Internet requires the use of IP addresses to locate hosts, and IP addresses are made up of many numbers. It is difficult for humans to remember certain combinations of numbers, so the host name and domain name are introduced to make it easier for everyone to remember an address.

The number of machines in the early network is very small, and it is convenient to map the host name and IP address through the hosts file. This method requires the user to maintain the mapping relationship of all hosts on the network. Later, the Internet developed rapidly and the hosts file method was no longer sufficient. Therefore, the Domain Name System (DNS) was introduced to resolve the mapping between host names and IP addresses.

The names commonly used in LANs to indicate IP addresses are more commonly referred to as host names, and the names used to represent IP addresses on the Internet are more commonly referred to as domain names. The core content is the same, both to resolve the mapping between names and IP addresses.

Java provides a lot of interfaces related to Internet host name and address operations. Now let's take a look at the JDK internal implementation of domain name resolution related functions. In fact, there is a NameService internal interface inside the InetAddress class for mapping domain names and IPs.

For the JDK, two mapping resolution schemes are mainly used, one is the hosts file mechanism, and the other is the resolution scheme that comes with the operating system.

Related class

--java.lang.Object
  --java.net.InetAddress$HostsFileNameService
  --java.net.InetAddress$PlatformNameService
Copy code

JDK selected solution

What are the JDK options for the above two host name IP mapping mechanisms? In fact, it is based onjdk.net.hosts.fileSystem properties to determine, by default, the operating system-based PlatformNameService scheme is used, and if configuredjdk.net.hosts.fileSystem properties use the HostsFileNameService scheme based on the hosts file, such as the ability to configure parameters at startup-Djdk.net.hosts.file=/etc/hosts. The corresponding logic code is as follows:

    private static NameService createNameService() {
        String hostsFileName =
                GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file");
        NameService theNameService;
        if (hostsFileName != null) {
            theNameService = new HostsFileNameService(hostsFileName);
        } else {
            theNameService = new PlatformNameService();
        }
        return theNameService;
    }
Copy code

Interface definition

private interface NameService {

InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException;

String getHostByAddr(byte[] addr) throws UnknownHostException;

}
Copy code

The NameService interface defines two methods for obtaining the IP address corresponding to the host name and the host name corresponding to the IP address.

HostsFileNameService class

The class is defined as follows:

private static final class HostsFileNameService implements NameService
Copy code

This class is a package based on the hosts file scheme, mainly looking at the two core methods.

lookupAllHostAddr method

This method implements a host file-based IP address lookup scheme based on the host name. The logic it has to accomplish is as follows:

  • Scans each line according to the specified hosts file path, throwing a FileNotFoundException if there are no files.
  • Iterate through each line of content. If it starts with a # sign, it indicates the content of the comment, and ignores it directly, otherwise it continues.
  • Under standard circumstances, the content can be127.0.0.1 localhost #local, ## is followed by the comment content, so call the removeComments method to remove#local, the method is no longer posted.
  • The processed content is127.0.0.1 localhostThen, if you see if the host name passed in is included, it means that the IP address of the host name is mapped, and the IP address is extracted by the extractHostAddr method.127.0.0.1, the method is no longer posted.
  • The processed content is127.0.0.1String, which needs to be called createAddressByteArray to convert it to a byte array to get the InetAddress object, which is no longer posted.
  • Add the resulting to the ArrayList object, eventually convert to an InetAddress array and return.
  public InetAddress[] lookupAllHostAddr(String host)
          throws UnknownHostException {
      String hostEntry;
      String addrStr = null;
      InetAddress[] res = null;
      byte addr[] = new byte[4];
      ArrayList<InetAddress> inetAddresses = null;
      
      try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) {
          while (hostsFileScanner.hasNextLine()) {
              hostEntry = hostsFileScanner.nextLine();
              if (!hostEntry.startsWith("#")) {
                  hostEntry = removeComments(hostEntry);
                  if (hostEntry.contains(host)) {
                      addrStr = extractHostAddr(hostEntry, host);
                      if ((addrStr != null) && (!addrStr.equals(""))) {
                          addr = createAddressByteArray(addrStr);
                          if (inetAddresses == null) {
                              inetAddresses = new ArrayList<>(1);
                          }
                          if (addr != null) {
                              inetAddresses.add(InetAddress.getByAddress(host, addr));
                          }
                      }
                  }
              }
          }
      } catch (FileNotFoundException e) {
          throw new UnknownHostException("Unable to resolve host " + host
                  + " as hosts file " + hostsFile + " not found ");
      }
      if (inetAddresses != null) {
          res = inetAddresses.toArray(new InetAddress[inetAddresses.size()]);
      } else {
          throw new UnknownHostException("Unable to resolve host " + host
                  + " in hosts file " + hostsFile);
      }
      return res;
  }
Copy code

getHostByAddr method

This method implements a host file-based host name lookup scheme based on the IP address. The logic it has to accomplish is as follows:

  • The argument passed in is a byte array of IP addresses, such asnew byte[] {127, 0, 0, 1}First, call the addrToString method to convert it to a "127.0.0.1" string, which is no longer posted.
  • Scans each line according to the specified hosts file path, throwing a FileNotFoundException if there are no files.
  • Iterate through each line of content. If it starts with a # sign, it indicates the content of the comment, and ignores it directly, otherwise it continues.
  • Under standard circumstances, the content can be127.0.0.1 localhost #local, ## is followed by the comment content, so call the removeComments method to remove#local, the method is no longer posted.
  • The processed content is127.0.0.1 localhostThen, see if it contains the incoming IP address, if it is the host name corresponding to the IP address, extract the host name by the extractHost method.localhost, the method is no longer posted.
  • Once the host name is found, it is no longer traversed, jumping out of the loop and returning the host name.
public String getHostByAddr(byte[] addr) throws UnknownHostException {
            String hostEntry;
            String host = null;

            String addrString = addrToString(addr);
            try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) {
                while (hostsFileScanner.hasNextLine()) {
                    hostEntry = hostsFileScanner.nextLine();
                    if (!hostEntry.startsWith("#")) {
                        hostEntry = removeComments(hostEntry);
                        if (hostEntry.contains(addrString)) {
                            host = extractHost(hostEntry, addrString);
                            if (host != null) {
                                break;
                            }
                        }
                    }
                }
            } catch (FileNotFoundException e) {
                throw new UnknownHostException("Unable to resolve address "
                        + addrString + " as hosts file " + hostsFile
                        + " not found ");
            }

            if ((host == null) || (host.equals("")) || (host.equals(" "))) {
                throw new UnknownHostException("Requested address "
                        + addrString
                        + " resolves to an invalid entry in hosts file "
                        + hostsFile);
            }
            return host;
        }
Copy code

PlatformNameService class

The class is defined as follows:

private static final class PlatformNameService implements NameService
Copy code

This class is the encapsulation of the resolution scheme that comes with the operating system. The two core methods are as follows. Because these two methods are related to the operating system, the corresponding local methods are called through the InetAddressImpl interface. The local methods are respectively lookupAllHostAddr. And getHostByAddr.

public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException{
    return impl.lookupAllHostAddr(host);
}

public String getHostByAddr(byte[] addr) throws UnknownHostException{
    return impl.getHostByAddr(addr);
}
Copy code

lookupAllHostAddr method

The main work to be done in this local method is to obtain the corresponding IP address through the host name service interface provided by the operating system, and then generate an array of InetAddress objects, that is, to generate the data structure of the Java layer.

The code implemented by Windows and unix-like operating system is relatively long. It is not posted here. The core is to implement name resolution through the getaddrinfo function to get all the addresses corresponding to the host name. Then create an array of objects through JNI's NewObjectArray function, then create an InetAddress object with JNI's NewObject function and set the property values ​​for the address and host name, and finally put the InetAddress object into the array one by one through JNI's SetObjectArrayElement function.

The getaddrinfo function is used for name resolution to convert a domain name to a corresponding IP address and port. When it looks up, it may go to the DNS server to find the address corresponding to the specified domain name, or it may be in the local hosts file, or it may be in other naming services. And generally each domain name will correspond to multiple IP addresses. The result obtained by this function is the addrinfo structure pointer.

structure parameter

typedef struct addrinfo {

int ai_flags;

int ai_family;

int ai_socktype;

int ai_protocol;

size_t ai_addrlen;

char* ai_canonname;

struct sockaddr* ai_addr;

struct addrinfo* ai_next;

}

ai_addrlen must be zero or a null pointer

ai_canonname must be zero or a null pointer

ai_addr must be zero or a null pointer

ai_next must be zero or a null pointer

ai_flags:AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST

ai_family: AF_INET,AF_INET6

ai_socktype:SOCK_STREAM,SOCK_DGRAM

ai_protocol:IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc.

getHostByAddr method

This local method is used to get the host name based on the IP address. The argument passed in is byte[], which is returned as a string. The job it does is to get the hostname through the hostname service interface provided by the operating system and then return the string.

The code implemented by Windows and unix-like operating system is similar. Only the Windows is posted here. The basic logic is: first get the incoming 4 bytes through JNI's GetByteArrayRegion function. Here, because the byte may be negative, you need The shift operation is performed; then the hostname is obtained by the getnameinfo function; finally, the hostname is placed in the newly created string object by JNI's NewStringUTF function.

JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
                                             jbyteArray addrArray) {
    jstring ret = NULL;
    char host[NI_MAXHOST + 1];
    jbyte caddr[4];
    jint addr;
    struct sockaddr_in sa;

    memset((char *)&sa, 0, sizeof(struct sockaddr_in));
    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
    addr = ((caddr[0] << 24) & 0xff000000);
    addr |= ((caddr[1] << 16) & 0xff0000);
    addr |= ((caddr[2] << 8) & 0xff00);
    addr |= (caddr[3] & 0xff);
    sa.sin_addr.s_addr = htonl(addr);
    sa.sin_family = AF_INET;

    if (getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in),
                    host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) {
        JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
    } else {
        ret = (*env)->NewStringUTF(env, host);
        if (ret == NULL) {
            JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
        }
    }

    return ret;
}
Copy code

-------------Recommended reading ------------

My 2017 article summary - machine learning articles

My 2017 article summary - Java and middleware

My 2017 article summary - deep learning articles

My 2017 article summary - JDK source code articles

My 2017 article summary - natural language processing articles

My 2017 article summary - Java concurrency articles

------------------commercial time----------------

The menu of the public number has been divided into "distributed", "machine learning", "deep learning", "NLP", "Java depth", "Java concurrent core", "JDK source code", "Tomcat kernel", etc., there may be one Suitable for your appetite.

The swearing new book "Tomcat Kernel Design Analysis" has been sold in Jingdong, and friends in need can buy it. Thank you friends.

Why write "Tomcat kernel design analysis"

Welcome attention:

Intelligent Recommendation

[JDK source code analysis] String.join () method resolution

Foreword Recently out of habit, easily point to open source String, String accidentally discovered a new method in JDK 8 join in. (I am ashamed, JDK 8 are released how long ...) Source String overload...

JDK source code resolution Reader, INPUTSTREAM, INPUTSTREAMREADER

JDK source code analysis The adaptation of Reader, InputStream (byte stream) is InputStreamReader InputStreamReader inherits Readers in Java.IO, the Inputer in Java.IO is achieved by the abstract unre...

LinkedList source code resolution (based on JDK 1.8)

Article catalog 1 member variable and node 2 constructor 3 preparation method 3.1 linkFirst 3.2 linkBefore 3.3 unlink 3.4 unlinkFirst 3.5 Others 4 add-related 4.1 add 4.2 addAll 4.3 offer 5 remove 6 g...

AtomicintegerfieldUpdater source code resolution (based on JDK 1.8)

Article catalog 1 Introduction 2 implementation 2.1 Some preparatory knowledge 2.2 Initialization 2.3 unsafe 3 actually use 3.1 Use atomicintegerfieldUpdater 3.2 Reflection.getCallerClass() 1 Introduc...

AtomicsTampedReference source code resolution (based on JDK 1.8)

Article catalog 1 Stamped and Markable comparison 2 introduction 3 other ways 4 code example In the Atomic package, there are three referen related classes: AtomicReference, AtomicStampedReference, At...

More Recommendation

Atomicinteger source code resolution (based on JDK 1.8)

Article catalog 1 Introduction 2 Initialization and GET / SET 3 atomic operation 1 Introduction Atomicinteger is an atomic class, increasing, and deleting atomic, avoiding the outside world directly u...

JDK dynamic agent source code resolution

Article catalog Proxy mode 1.1 What is proxy mode? 1.2 Structure of the agent mode 1.3 types 2. Static agent 2.1 instance 2.2 Excellent 3. Dynamic agent 3.1 Why can the zone code dynamically generate?...

Reader from JDK source code

Overview Reader is an abstract class for reading character streams. It abstracts some common read-related operations into this class, facilitating the implementation of various read-class classes. In ...

From the perspective of JDK source code

Another excellent mechanism provided by the concurrent framework in JDK is the lock acquisition timeout. When a large number of threads can lead to some threads, they can't get the lock in a long peri...

The fairness of java concurrency from the perspective of JDK source code

Java provides a number of concurrent tools for simplifying developer development, including various synchronizers. With JDK, we only need to learn to use the class API simply. But this does not mean t...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top