Как стать автором
Обновить

Альтернативный способ записи IP-адресов (версия 2)

Время на прочтение 4 мин
Количество просмотров 1.2K
Прочитав в сентябре заметку Альтернативный способ записи IP-адресов, подумал интересно, какие же умные бывают программы, и забыл.

Недавно пришлось устанавливать mpi для локальной разработки. Попробовал и MS MPI и MPICH, оба завершались с неочевидной ошибкой сети 10051, как гласит MSDN, это означает, что сеть не доступна. Долго пытался ее побороть, думал уже и на ОС и на сами программные пакеты, пересоздавал сетевые интерфейсы. Но вышло все немного по другому…

Потом случайно вспомнил о заметке про IP адреса и меня осенило, имя компьютеру я дал необычное: 0x0A0D. Опасения подтвердились, это имя сразу преобразовывалось к IP адресу и программы mpi не могли подсоеденится к диспетчеру.

OC Windows


И так, неужели все программы такие умные? Для начала посмотрим, как системная утилита ping ОС MS Windows разрешает входящий параметр в IP адрес. Делается это с помощью POSIX-совместимой функции getaddrinfo библиотеки WinSock. Происходит это примерно так:
  struct addrinfo hints;
  ZeroMemory( &hints, sizeof(hints) );
  hints.ai_flags = AI_NUMERICHOST;

  dwRetval = getaddrinfo(argv[1], NULL, &hints, &result);
  if ( dwRetval != 0 ) {
    hints.ai_flags = AI_CANONNAME;
    dwRetval = getaddrinfo(argv[1], NULL, &hints, &result);
    if ( dwRetval != 0 ) {
      printf("getaddrinfo failed with error: %d\n", dwRetval);
      WSACleanup();
      return 1;
    }
  }


* This source code was highlighted with Source Code Highlighter.

Вот ее описание:
int WSAAPI getaddrinfo(
 __in  const char *nodename,
 __in  const char *servname,
 __in  const struct addrinfo *hints,
 __out struct addrinfo **res
);

* This source code was highlighted with Source Code Highlighter.

Самым интересным параметром является hints, который служит подсказкой для интерпретации входной строки nodename. Поле ai_flags может принимать несколько значений от которых зависит логика преобразования входящей строки в адрес. В утилите ping, как и во многих других программах, сначала осуществляется попытка прямого преобразования строки в IP адрес, а только потом это повторяется через подсистему DNS. Это вполне логично и рационально.

И так, что происходит, когда мы принуждаем осуществить прямое преобразование? В недрах кода winsock проходит множество преобразований и проверок, но в конце концов поток исполнения доходит до функции RtlIpv4StringToAddressW библиотеки Ntdll.dll. Кстати, эта функция абсолютно независима от сетевой подсистемы и может быть использована без явной инициализации WinSock. Она как раз и осуществляет интерпретацию всевозможных вариантов записи IP адреса. В MSDN говорится о всех форматах, но почему именно они?

ОС Linux


С этой операционной сиситемой все значительно проще, так как открыты исходники ее и ее многих утилит. Найдя первый исходник утилиты ping для Linux, можно увидить, как в ней происходит преобразование строки в IP адрес:
  bzero((char *)&whereto, sizeof(struct sockaddr) );
  to->sin_family = AF_INET;
  to->sin_addr.s_addr = inet_addr(av[0]);
  if(to->sin_addr.s_addr != (unsigned)-1) {
    strcpy(hnamebuf, av[0]);
    hostname = hnamebuf;
  } else {
    hp = gethostbyname(av[0]);
    if (hp) {
      to->sin_family = hp->h_addrtype;
      bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
      hostname = hp->h_name;
    } else {
      printf("%s: unknown host %sn", argv[0], av[0]);
      exit(1);
    }
  }


* This source code was highlighted with Source Code Highlighter.

Как видно, код отличается, но определив назначения функций, можно понять, что алгоритмы идентичные. Почитав man inet_addr, становится ясным, что эта функция аналогична RtlIpv4StringToAddressW ОС Windows. Также в ее описании упоминается загадочный стандарт POSIX.1-2001.

Стандарт POSIX.1-2001


И так стандарт гласит, функция должна принимать строку в одном из следующих форматов:
  • a.b.c.d — Когда указаны 4 части, каждая часть должна быть проинтепретирована как байт данных и присвоен слева направо четырем байтам IP адреса
  • a.b.c — Когда указаны 3 части, третья часть интерпретируется как 16-битная величина и присваивается правым двум байтам IP адреса. Таким образом можно кратко записывать адреса в сетях класса B
  • a.b — Когда указаны 2 части, вторая часть интерпретируется как 24-битное значение и используется для краткой записи адресов класса A
  • a — Когда указана одна часть, она должна быть непосредственно преобразована в IP адрес без перестановок

Все части точечной нотации IP адреса должны быть числами в десятичной, восьмеричной или шестнадцетиричной системах счисления согласно стандарту ISO C.

Выводы


  1. Нужно выбирать сетевое имя компьютера, которое нельзя напрямую преобразовать в адрес, иначе компьютер может быть недоступен по имени
  2. Преобразование IP4 адресов никак не связано с записью адресов IPv6 или форматом URL, но адреса IP4 являются подмножеством адресов IPv6
  3. Это работает только в POSIX совместимых системах и только в программах, которые сначала пытаются напрямую преобразовать адрес (на некоторых Linux адрес типа a не воспринимается)
  4. Для локальных соединения лучше использовать имя localhost, а не имя компьютера :)


Ссылки


Альтернативный способ записи IP-адресов
The Ping Page
inet_addr IEEE Std 1003.1
Теги:
Хабы:
+6
Комментарии 4
Комментарии Комментарии 4

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн