Jump to content

getaddrinfo

В программировании на языке C функции доменные getaddrinfo() и getnameinfo() преобразуют имена , имена хостов и IP-адреса в удобочитаемые текстовые представления и структурированные двоичные форматы для сетевого API операционной системы . Обе функции содержатся в POSIX . стандартном интерфейсе прикладного программирования (API) [1]

getaddrinfo и getnameinfo являются обратными функциями друг друга. Они не зависят от сетевых протоколов и поддерживают как IPv4 , так и IPv6 . Это рекомендуемый интерфейс для разрешения имен при создании независимых от протокола приложений и для перехода устаревшего кода IPv4 в Интернет IPv6.

Внутри функции могут использовать различные методы разрешения, не ограничиваясь системой доменных имен (DNS). Переключатель службы имен обычно используется в Unix-подобных системах и влияет на большую часть реализации этой пары, как и в случае с их предшественниками эпохи BSD-сокетов . [2]

структура адреса

[ редактировать ]

Структура данных C , используемая для представления адресов и имен хостов в сетевом API, следующая:

struct addrinfo {
    int       ai_flags;
    int       ai_family;
    int       ai_socktype;
    int       ai_protocol;
    socklen_t ai_addrlen;
    struct    sockaddr* ai_addr;
    char*     ai_canonname;      /* canonical name */
    struct    addrinfo* ai_next; /* this struct can form a linked list */
};

В некоторых старых системах типом ai_addrlen является size_t вместо socklen_t . Большинство функций сокетов, таких как Accept() и getpeername() , требуют, чтобы параметр имел тип socklen_t * , и программисты часто передают адрес элементу структуры ai_addrlen addrinfo . Если типы несовместимы, например, в 64-битной системе Solaris 9 , где size_t равен 8 байтам, а socklen_t равен 4 байтам, могут возникнуть ошибки во время выполнения.

Структура содержит структуры ai_family и sockaddr со своим собственным полем sa_family . В некоторых реализациях им присваиваются одни и те же значения, когда структура создается с помощью функции getaddrinfo .

getaddrinfo() преобразует удобочитаемые текстовые строки, представляющие имена хостов или IP-адреса, в динамически выделяемый связанный список структур struct addrinfo. Прототип функции для этой функции указан следующим образом:

int getaddrinfo(const char* hostname,
                const char* service,
                const struct addrinfo* hints,
                struct addrinfo** res);
имя хоста
может быть либо именем домена, например «example.com», строкой адреса, например «127.0.0.1», либо NULL, и в этом случае адрес 0.0.0.0 или 127.0.0.1 назначается в зависимости от флагов подсказок.
услуга
может быть номером порта, переданным в виде строки, например «80», или именем службы, например «echo». В последнем случае типичная реализация использует getservbyname() для запроса файла /etc/services для сопоставления службы с номером порта.
намеки
может иметь значение NULL или структуру addrinfo с типом запрошенной службы.
рез
— это указатель, указывающий на новую структуру addrinfo с информацией, запрошенной после успешного завершения функции. [3] Функция возвращает 0 в случае успеха и ненулевое значение ошибки в случае неудачи. [1]

Хотя реализации различаются на разных платформах, функция сначала пытается получить номер порта, обычно путем перехода на сервис . Если строковое значение является числом, оно преобразуется в целое число и вызывает htons() . Если это имя службы, например www , служба ищется с помощью getservbyname() , используя протокол, полученный изhints->ai_socktype, в качестве второго параметра этой функции. Затем, если имя хоста задано (не NULL), его разрешает вызов gethostbyname() адрес 0.0.0.0 , в противном случае используется , если дляhints->ai_flags установлено значение AI_PASSIVE , и 127.0.0.1 в противном случае. В одном из этих условий он выделил новую структуру addrinfo, заполненную соответствующим sockaddr_in , а также добавил к ней порт, полученный в начале. Наконец, параметр **res разыменовывается, чтобы он указывал на вновь выделенную структуру addrinfo . [4] В некоторых реализациях, таких как версия Unix для Mac OS, подсказки->ai_protocol переопределяют значение подсказок->ai_socktype, в то время как в других оно противоположно, поэтому оба должны быть определены с эквивалентными значениями, чтобы код мог работать с несколькими платформы.

Эта функция освобождает память, выделенную функцией getaddrinfo() . Поскольку результатом последнего является связанный список структур addrinfo, начинающийся с адреса ai , функция freeaddrinfo() проходит по списку и освобождает каждую из них по очереди.

void freeaddrinfo(struct addrinfo *ai);

получитьимяинформация()

[ редактировать ]

Функция getnameinfo() преобразует внутреннее двоичное представление IP-адреса в форме указателя на структуру sockaddr в текстовые строки, состоящие из имени хоста или, если адрес не может быть преобразован в имя, в текстовое представление IP-адреса, как а также имя или номер порта службы. Прототип функции указан следующим образом:

int getnameinfo(const struct sockaddr* sa, socklen_t salen,
                char* host, size_t hostlen,
                char* serv, size_t servlen,
                int flags);

В следующем примере метод getaddrinfo() используется для разрешения доменного имени www.example.com в его списке адресов, а затем вызывается метод getnameinfo() для каждого результата, чтобы вернуть каноническое имя адреса. Как правило, это создает исходное имя хоста , если конкретный адрес не имеет несколько имен, и в этом случае каноническое возвращается имя. В этом примере имя домена печатается три раза, по одному для каждого из трех полученных результатов.

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

#ifndef   NI_MAXHOST
#define   NI_MAXHOST 1025
#endif

int main(void)
{
    struct addrinfo* result;
    struct addrinfo* res;
    int error;

    /* resolve the domain name into a list of addresses */
    error = getaddrinfo("www.example.com", NULL, NULL, &result);
    if (error != 0) {   
        if (error == EAI_SYSTEM) {
            perror("getaddrinfo");
        } else {
            fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
        }   
        exit(EXIT_FAILURE);
    }

    /* loop over all returned results and do inverse lookup */
    for (res = result; res != NULL; res = res->ai_next) {   
        char hostname[NI_MAXHOST];
        error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 
        if (error != 0) {
            fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
            continue;
        }
        if (*hostname != '\0')
            printf("hostname: %s\n", hostname);
    }

    freeaddrinfo(result);
    return 0;
}

Безопасность

[ редактировать ]

16 февраля 2016 г. было объявлено об ошибке безопасности в реализации glibc функции getaddrinfo(), использующей технику переполнения буфера , которая может позволить злоумышленнику выполнить произвольный код. [5]

См. также

[ редактировать ]
  1. ^ Перейти обратно: а б «freeaddrinfo, getaddrinfo — получить информацию об адресе» . Базовые спецификации открытой группы, выпуск 7, издание 2018 г. (POSIX.1-2017) . Открытая группа . Проверено 5 марта 2022 г.
  2. ^ «nss — раздел 5 страниц руководства: Форматы файлов» . docs.oracle.com .
  3. ^ Стивенс Р., Феннер, Рудофф [2003] Сетевое программирование UNIX®, том 1, третье издание: API сетевых сокетов. Издатель: Addison-Wesley Professional. Паб. Дата: 14 ноября 2003 г. с. 256
  4. ^ Хаджиму УМЕМОТО [2000] getaddrinfo.c Доступ по адресу: https://opensource.apple.com/source/passwordserver_sasl/passwordserver_sasl-14/cyrus_sasl/lib/getaddrinfo.c
  5. ^ «CVE-2015-7547: переполнение буфера стека Glibc getaddrinfo» .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 38fedf70f1153958f4f3c50a25a2f633__1681786680
URL1:https://arc.ask3.ru/arc/aa/38/33/38fedf70f1153958f4f3c50a25a2f633.html
Заголовок, (Title) документа по адресу, URL1:
getaddrinfo - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)