Почему localhost разрешается в ::1, а не в 127.0.0.1

Отвечая по порядку:

  1. Он возвращает указатель на местоположение в виртуальной памяти, и адресное пространство виртуальной памяти выделяется, но файл никак не блокируется, если вы не заблокируете его явно (также обратите внимание, что блокировка память — это не то же самое, что блокировка региона в файле ). Эффективная реализация mmap ()на самом деле возможна только с практической точки зрения из-за подкачки и виртуальной памяти (, иначе потребовалось бы чтение всей области в память до завершения вызова ).
  2. Не совсем так, хотя это связано со следующим ответом, поэтому я расскажу об этом там.
  3. Вроде. Что на самом деле происходит в большинстве случаев, так это то, что mmap ()предоставляет копирование -на -доступ для записи к данным этого файла в кэше страницы. В результате применяются обычные ограничения кеша на время жизни данных (, если системе требуется место, страницы могут быть удалены (или сброшены на диск, если они грязные )из кеша и их нужно снова загрузить..
  4. Нет, из-за того, как работает виртуальная память. Каждый процесс имеет собственное виртуальное адресное пространство со своими виртуальными сопоставлениями. Каждая программа, которая хочет передать данные, должна будет вызывать mmap ()для того же файла (или сегмента общей памяти ), и все они должны использовать флаг MAP_SHARED.

Стоит отметить, что mmap ()работает не только с файлами, вы также можете делать с ним другие вещи, такие как:

  • Прямое сопоставление памяти устройства (, если у вас есть достаточные привилегии ). На самом деле это используется во многих встроенных системах, чтобы избежать необходимости писать драйверы режима ядра для нового оборудования.
  • Сопоставление сегментов общей памяти.
  • Явное сопоставление огромных страниц.
  • Выделение памяти, которую вы затем можете вызвать madvise (2 )на (, что, в свою очередь, позволяет вам делать полезные вещи, такие как предотвращение копирования данных в дочерний процесс на fork (2 ), или пометить данные для KSM (Функция дедупликации памяти Linux )).
5
19.07.2019, 11:09
1 ответ

Найти это было непросто (, но весело :)).

Краткий ответ

gethostbyname2 (), который использует __поиск _имя (), имеет некоторые жестко закодированные -значения для интерфейса loopback ('lo' ). Когда вы указываете «localhost» в команде «getent hosts», она в конечном итоге использует значение по умолчанию для IPv6, прежде чем попытается использовать IPv4, таким образом, вы получите ::1. Вы можете изменить код getent, чтобы получить 127.0.0.0. 0.1 вот так:

  1. Загрузите исходный код getent с github
  2. Закомментируйте -следующую строку (#329 )в hosts _keys ()под getent.c ://иначе, если ((host = gethostbyname2 (key[i], AF _INET6 ))== NULL)
  3. Скомпилируйте и запустите из исходного кода:

Результат:

$make clean && make &&./getent hosts localhost
rm -f *.o
rm -f getent
gcc -g -Wall -std=gnu99 -w -c getent.c -o getent.o
gcc  getent.o -Wall -lm -o getent
127.0.0.1       localhost

Подробнее

Инструмент getent использует функции, определенные и реализованные библиотекой musl . Когда мы запускаем команду

$getent hosts localhost

Инструмент вызывает функцию _ключей ()хостов в getent.c для разрешения предоставленного ключа. Функция пытается решить 4 метода:

  1. gethostbyaddr для IPv6 (не работает в этом случае ).
  2. gethostbyaddr для IPv4 (не работает в этом случае ).
  3. gethostbyname2 для IPv6 (всегда завершается успешно для localhost из-за жесткого -закодированного значения ).
  4. gethostbyname2 для IPv4 (не пытается выполнить попытку из-за успеха на #3 ).

Все функции musl реализованы в /src/network/, см. здесь . gethostbyname2()(реализовано в gethostbyname2.c )вызывает gethostbyname2 _r()(реализовано в gethostbyname2 _rc ), которое вызывает __поиск _имя()(в поиске _имя.c ). __поиск _имя (), опять же, как несколько вариантов разрешения имени хоста, первым из которых является имя _из _ноль (в том же файле):

static int name_from_null(struct address buf[static 2], const char *name, int family, int flags)
{
    int cnt = 0;
    if (name) return 0;
    if (flags & AI_PASSIVE) {
            if (family != AF_INET6)
                    buf[cnt++] = (struct address){.family = AF_INET };
            if (family != AF_INET)
                    buf[cnt++] = (struct address){.family = AF_INET6 };
    } else {
            if (family != AF_INET6)
                    buf[cnt++] = (struct address){.family = AF_INET,.addr = { 127,0,0,1 } };
            if (family != AF_INET)
                    buf[cnt++] = (struct address){.family = AF_INET6,.addr = { [15] = 1 } };
    }
    return cnt;
}

В самом конце мы видим, что когда family == AF _INET6, мы получим жестко закодированное -значение ::1. Так как getent пробует IPv6 до IPv4, это будет возвращаемое значение.. Как я показал выше, принудительное разрешение как IPv4 в getent приведет к жестко запрограммированному значению 127.0.0.1 из функции выше.

Если вы хотите изменить функциональность, чтобы возвращать IPv4-адрес для локального хоста, лучше всего сначала отправить/запросить исправление для getent для поиска IPv4.

Надеюсь, это поможет!

2
30.03.2020, 21:50

Теги

Похожие вопросы