Просмотр разрешения доменного имени Java из исходного кода JDK

Java задняя часть Операционная система Tomcat
Просмотр разрешения доменного имени Java из исходного кода JDK

предисловие

Коммуникация в Интернете требует IP-адресов для определения местонахождения хостов, а IP-адреса состоят из множества чисел, людям трудно запомнить определенные комбинации цифр, поэтому для удобства запоминания определенного адреса вводятся имена хостов и доменные имена.

Количество машин в ранней сети было очень небольшим, и было легко выполнить сопоставление между именами хостов и IP-адресами через файл hosts.Этот метод требует, чтобы пользователи поддерживали отношения сопоставления всех хостов в сети. Позже, с быстрым развитием Интернета, метод файлов хостов перестал быть адекватным, поэтому была введена система доменных имен (DNS) для устранения сопоставления между именами хостов и IP-адресами.

Имя, обычно используемое для представления IP-адреса в локальной сети, больше называется именем хоста, а имя, используемое для представления IP-адреса в Интернете, больше называется доменным именем. Основное содержание одинаковое, все решают сопоставление между именами и IP-адресами.

Java предоставляет множество интерфейсов, связанных с операциями с именами хостов и адресами в Интернете.Теперь давайте взглянем на реализацию функций, связанных с разрешением доменных имен, в JDK. На самом деле внутри класса InetAddress есть внутренний интерфейс NameService для реализации сопоставления между доменными именами и IP-адресами.

Для JDK в основном используются две схемы разрешения сопоставления: одна — файловый механизм hosts, а другая — схема разрешения, поставляемая с операционной системой.

Связанные классы

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

Схема выбора JDK

Как JDK выбрал два вышеуказанных механизма сопоставления IP-адресов имен хостов? На самом деле, согласноjdk.net.hosts.fileсистемные свойства, по умолчанию используется схема PlatformNameService на базе ОС, и если настроеноjdk.net.hosts.fileСистемные свойства используют схему HostsFileNameService на основе файла hosts, например параметры можно настроить при запуске-Djdk.net.hosts.file=/etc/hosts. Соответствующий логический код выглядит следующим образом:

    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;
    }

Определение интерфейса

private interface NameService {

InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException;

String getHostByAddr(byte[] addr) throws UnknownHostException;

}

Интерфейс NameService в основном определяет два метода получения IP-адреса, соответствующего имени хоста, и имени хоста, соответствующего IP-адресу.

Класс HostsFileNameService

Класс определяется следующим образом:

private static final class HostsFileNameService implements NameService

Этот класс представляет собой инкапсуляцию файловой схемы hosts, в основном рассматривая два основных метода:

метод lookupAllHostAddr

Этот метод реализует схему поиска IP-адресов на основе файлов хостов на основе имен хостов. Логика, которую он хочет завершить, выглядит следующим образом:

  • Сканирует каждую строку по указанному пути к файлу hosts и создает исключение FileNotFoundException, если файл не существует.
  • Просмотрите содержимое каждой строки, если оно начинается со знака #, это означает содержание комментария к строке, игнорируйте его напрямую, в противном случае продолжайте.
  • В стандартном случае содержимое может быть127.0.0.1 localhost #local, после # — это содержимое комментария, поэтому вызовите метод removeComments, чтобы удалить его.#local, метод больше не публикуется.
  • Обработанный контент127.0.0.1 localhost, а затем проверьте, включено ли входящее имя хоста. Если да, это означает, что это IP-адрес, сопоставленный с именем хоста. Извлеките IP-адрес с помощью метода extractHostAddr. Значение равно127.0.0.1, метод больше не публикуется.
  • Обработанный контент127.0.0.1String, вам нужно вызвать createAddressByteArray, чтобы преобразовать его в массив байтов, чтобы получить объект InetAddress, этот метод больше не публикуется.
  • Добавьте результат в объект ArrayList, наконец, преобразуйте в массив InetAddress и верните.
  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;
  }

метод getHostByAddr

Этот метод реализует схему поиска имени хоста на основе файла hosts на основе IP-адресов. Логика, которую он хочет завершить, выглядит следующим образом:

  • Входящий параметр представляет собой байтовый массив IP-адресов, напримерnew byte[] {127, 0, 0, 1}, сначала вызовите метод addrToString, чтобы преобразовать его в строку «127.0.0.1», которая больше не публикуется.
  • Сканирует каждую строку по указанному пути к файлу hosts и создает исключение FileNotFoundException, если файл не существует.
  • Просмотрите содержимое каждой строки, если оно начинается со знака #, это означает содержание комментария к строке, игнорируйте его напрямую, в противном случае продолжайте.
  • В стандартном случае содержимое может быть127.0.0.1 localhost #local, после # — это содержимое комментария, поэтому вызовите метод removeComments, чтобы удалить его.#local, метод больше не публикуется.
  • Обработанный контент127.0.0.1 localhost, а затем проверьте, включен ли входящий IP-адрес.Если есть, это означает, что это имя хоста, соответствующее IP-адресу.Извлеките имя хоста с помощью метода extractHost.localhost, метод больше не публикуется.
  • Как только имя хоста найдено, он не переходит вниз, а выходит из цикла и возвращает имя хоста.
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;
        }

Класс PlatformNameService

Класс определяется следующим образом:

private static final class PlatformNameService implements NameService

Этот класс является инкапсуляцией схемы синтаксического анализа, поставляемой с операционной системой. Два основных метода следующие. Поскольку эти два метода связаны с операционной системой, соответствующие локальные методы вызываются через интерфейс InetAddressImpl. lookupAllHostAddr и getHostByAddr.

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

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

метод lookupAllHostAddr

Работа, которую необходимо выполнить в этом нативном методе, состоит в том, чтобы сначала получить соответствующий IP-адрес через интерфейс службы имен хостов, предоставляемый операционной системой, а затем сгенерировать массив объектов InetAddress, то есть сгенерировать структуру данных уровня Java. .

Код, реализованный Windows и unix-подобными операционными системами, относительно длинный и не будет здесь публиковаться Ядро состоит в использовании функции getaddrinfo для реализации разрешения имен и получения всех адресов, соответствующих имени хоста. Затем создайте массив объектов с помощью функции JNI NewObjectArray, затем создайте объект InetAddress с помощью функции JNI NewObject и установите значения свойств адреса и имени хоста, и, наконец, поместите объекты InetAddress в массив один за другим с помощью функции JNI SetObjectArrayElement.

Функция getaddrinfo используется для разрешения имен, которая может преобразовывать доменное имя в соответствующий IP-адрес и порт. Когда он ищет, он может обратиться к DNS-серверу, чтобы найти адрес, соответствующий указанному доменному имени, или он может быть в локальном файле hosts, или может быть в других службах имен. Как правило, каждому доменному имени соответствует несколько IP-адресов. Результат, полученный этой функцией, является указателем на структуру addrinfo.

структура параметр

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

Этот собственный метод используется для получения имени хоста на основе IP-адреса, входящий параметр — byte[], а возвращаемый — строка. Что ему нужно сделать, так это получить имя хоста через интерфейс службы имен хостов, предоставляемый операционной системой, а затем вернуть строку.

Коды, реализованные Windows и unix-подобными операционными системами, похожи.Здесь размещены только Windows.Основная логика: сначала получить входящие 4 байта через функцию GetByteArrayRegion JNI.Здесь, поскольку байты могут быть отрицательными числами, необходимо выполнить операцию Shift, затем получить имя хоста с помощью функции getnameinfo, наконец, поместить имя хоста в новый строковый объект с помощью функции JNI NewStringUTF.

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;
}

------------- Рекомендуем прочитать ------------

Резюме моей статьи за 2017 год — машинное обучение

Краткое изложение моих статей за 2017 год — Java и промежуточное ПО

Резюме моих статей 2017 года — глубокое обучение

Краткое изложение моих статей за 2017 год — исходный код JDK

Резюме моей статьи за 2017 год — обработка естественного языка

Резюме моих статей 2017 года — Java Concurrency

------------------рекламное время----------------

Меню официальной учетной записи было разделено на «распределенное», «машинное обучение», «глубокое обучение», «НЛП», «глубина Java», «ядро параллелизма Java», «исходный код JDK», «ядро Tomcat», и т.д. Там может быть один стиль, чтобы удовлетворить ваш аппетит.

Моя новая книга «Анализ дизайна ядра Tomcat» продана на Jingdong, и нуждающиеся друзья могут ее купить. Спасибо друзья.

Зачем писать «Анализ проектирования ядра Tomcat»

Добро пожаловать, чтобы следовать:

这里写图片描述