Provided by: manpages-ru-dev_4.27.0-1_all bug

НАИМЕНОВАНИЕ

       getaddrinfo, freeaddrinfo, gai_strerror - трансляция сетевого адреса и службы

БИБЛИОТЕКА

       Стандартная библиотека языка C (libc, -lc)

ОБЗОР

       #include <sys/types.h>
       #include <sys/socket.h>
       #include <netdb.h>

       int getaddrinfo(const char *restrict node,
                       const char *restrict service,
                       const struct addrinfo *restrict hints,
                       struct addrinfo **restrict res);

       void freeaddrinfo(struct addrinfo *res);

       const char *gai_strerror(int errcode);

   Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

       getaddrinfo(), freeaddrinfo(), gai_strerror():
           Начиная с glibc 2.22:
               _POSIX_C_SOURCE >= 200112L
           glibc 2.21 и ранее:
               _POSIX_C_SOURCE

ОПИСАНИЕ

       По  заданным  node  и  service,  определяющим  узел и службу Интернета, getaddrinfo() возвращает одну или
       несколько структур addrinfo, каждая из которых содержит Интернет-адрес, который можно передавать в  вызов
       bind(2)   или   connect(2).  Функция  getaddrinfo()  объединяет  возможности,  предоставляемые  функциями
       gethostbyname(3) и getservbyname(3) в одном интерфейсе, но  в  отличие  от  этих  функций,  getaddrinfo()
       реентерабельна и позволяет программам не зависеть от IPv4 или IPv6.

       Структура addrinfo, используемая в getaddrinfo(), содержит следующие поля:

           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;
               struct addrinfo *ai_next;
           };

       Аргумент  hints  указывает  на  структуру  addrinfo,  которая  определяет критерии выбора структур адреса
       сокета, возвращаемых в списке, указанном в res. Если hints не является NULL, то он указывает на структуру
       addrinfo. В ней с помощью ai_family, ai_socktype  и  ai_protocol  определяются  критерии,  ограничивающие
       набор адресов сокета, возвращаемых getaddrinfo():

       ai_family
              Это  поле  определяет  предпочитаемое  семейство  адресов  для  возвращаемых  адресов. Правильными
              значениями для данного поля могут быть AF_INET и  AF_INET6.  Значение  AF_UNSPEC  отображает,  что
              getaddrinfo()  должна  возвращать адреса сокета для любого семейства адресов (например, либо IPv4,
              либо IPv6), которые в дальнейшем могут быть использованы вместе с node и service.

       ai_socktype
              Это поле определяет предпочитаемы тип сокета, например, SOCK_STREAM или SOCK_DGRAM.  Если  в  этом
              поле указан 0, то это означает, что getaddrinfo() может вернуть адреса сокета любого типа.

       ai_protocol
              Это  поле  определяет  протокол для возвращаемых адресов сокета. Если в этом поле указан 0, то это
              означает, что getaddrinfo() может вернуть адрес сокета с любым протоколом.

       ai_flags
              В этом поле задаются дополнительные параметры, описываемые ниже. Несколько  флагов  указываются  с
              логическим ИЛИ.

       Все остальные поля структуры, указываемой hints, должны содержать 0 или указатель null, соответственно.

       Указание  в  hints  значения  NULL  эквивалентно установке ai_socktype и ai_protocol равными 0; ai_family
       присваивается AF_UNSPEC; ai_flags присваивается (AI_V4MAPPED | AI_ADDRCONFIG)  (в  POSIX  указаны  другие
       значения по умолчанию для ai_flags; смотрите ЗАМЕЧАНИЯ). В node задаётся либо числовой сетевой адрес (для
       IPv4   это   цифро-точечная   нотация,   которую   поддерживает  inet_aton(3);  для  IPv6  это  строка  в
       шестнадцатеричном формате, который поддерживает inet_pton(3)), либо сетевое  имя  узла,  для  которого  в
       дальнейшем  определяется  адрес.  Если в hints.ai_flags содержится флаг AI_NUMERICHOST, тогда node должен
       иметь цифровой формат сетевого адреса. При AI_NUMERICHOST любые возможные преобразования сетевого  адреса
       узла подавляются.

       Если  в  hints.ai_flags  указан  флаг  AI_PASSIVE  и node равно NULL, то возвращаемые адреса сокета будут
       пригодны для bind(2) сокета, который принимает соединение с помощью accept(2). Возвращаемый адрес  сокета
       будет  содержать  «шаблонный  адрес»  (INADDR_ANY  для  адресов  IPv4, IN6ADDR_ANY_INIT для адреса IPv6).
       Шаблонный адрес используется в приложениях (обычно, серверах),  которым  нужно  принимать  подключения  с
       любых сетевых адресов узлов. Если node не равно NULL, то флаг AI_PASSIVE игнорируется.

       Если  флаг  AI_PASSIVE  отсутствует  в  hints.ai_flags,  то возвращаемые адреса сокета будут пригодны для
       использоваться в connect(2), sendto(2), или sendmsg(2). Если node равно NULL, то  сетевому  адресу  будет
       назначен  адрес кольцевого интерфейса (loopback) (INADDR_LOOPBACK для адресов IPv4, IN6ADDR_LOOPBACK_INIT
       для адреса IPv6); это используется в приложениях, которым нужно связываться с партнёрами, запущенными  на
       том же узле.

       В  service  задаётся  порт  для  каждой  возвращаемой адресной структуры. Если этот аргумент — имя службы
       (смотрите services(5)), то он транслируется в соответствующий номер порта. Также, данный  параметр  может
       быть  указан  в виде десятичного числа, которое просто преобразуется в двоичную форму. Если service равно
       NULL, то номер порта возвращаемых сокетных адресов остаётся неинициализированным. Если  в  hints.ai_flags
       указан  флаг  AI_NUMERICSERV  и  service  не равно NULL, то значение service должно указывать на строку с
       числовым номером порта. Данный флаг  используется  для  запрета  вызова  службы  определения  имён,  если
       известно, что она не требуется.

       Либо node, либо service (но не оба одновременно) могут быть равны NULL.

       Функция  getaddrinfo()  выделяет  место  и  инициализирует  связный список структур addrinfo, по одной на
       каждый сетевой адрес, который совпадает  с  node  и  service,  в  соответствии  с  любыми  ограничениями,
       наложенными hints, и возвращает указатель на начало списка в res. Элементы в связном списке связаны через
       поле ai_next.

       Существует  несколько  причин того, почему связный список может содержать более одной структуры addrinfo:
       сетевой узел имеет несколько адресов, доступен по нескольким протоколам (например, AF_INET  и  AF_INET6);
       служба  доступна  через  несколько  типов  сокетов  (например,  один  её  адрес — SOCK_STREAM, а второй —
       SOCK_DGRAM). Обычно, приложение должно стараться  использовать  адреса  в  том  порядке,  в  котором  они
       получены.  Функция  сортировки,  используемая  в  getaddrinfo(), определена в RFC 3484; в системе порядок
       может быть изменён через файл /etc/gai.conf (доступен, начиная с glibc 2.5).

       Если в hints.ai_flags выставлен флаг AI_CANONNAME, то в поле ai_canonname  первой  из  структур  addrinfo
       возвращаемого списка задаётся указатель официального имени узла.

       Остальные поля каждой возвращаемой структуры addrinfo инициализируются следующим образом:

       •  В  полях  ai_family, ai_socktype и ai_protocol возвращаются параметры создания сокета (т. е., эти поля
          имеют те же значения, что и соответствующие  аргументы  в  socket(2)).  Например,  в  ai_family  может
          вернуться  AF_INET  или  AF_INET6;  в  ai_socktype  может  вернуться  SOCK_DGRAM  или  SOCK_STREAM;  в
          ai_protocol возвращается протокол сокета.

       •  Указатель на адрес сокета помещается в поле ai_addr, а длина адреса сокета  (в  байтах)  помещается  в
          поле ai_addrlen.

       Если  в  hints.ai_flags  содержится флаг AI_ADDRCONFIG, то адреса IPv4, возвращаются в списке, на который
       указывает res, только, если в локальной системе настроен, как минимум, один адрес  IPv4,  и  адреса  IPv6
       возвращаются  только,  если  в  локальной  системе  настроен,  как  минимум,  один  адрес IPv6. Кольцевой
       (loopback) адрес в этом случае не учитывается как настроенный.  Этот  флаг  полезен,  например  в  только
       IPv4-системах,  чтобы  getaddrinfo()  не  возвращал сокетные адреса IPv6, с которыми невозможно выполнить
       connect(2) или bind(2).

       Если в hints.ai_flags содержится флаг AI_V4MAPPED и  в  hints.ai_family  задан  AF_INET6,  и  не  найдено
       подходящих  адресов  IPv6,  то  в списке, на который указывает res, возвращаются IPv6 адреса отображённых
       адресов IPv4. Если в hints.ai_flags указаны и AI_V4MAPPED, и AI_ALL, то в списке,  на  который  указывает
       res, возвращаются и адреса IPv6 и IPv6 адреса отображённых адресов IPv4. Флаг AI_ALL игнорируется, если с
       ним не задан AI_V4MAPPED.

       Функция freeaddrinfo() освобождает память, которая была выделена для динамического связного списка res.

   Расширения getaddrinfo() для интернациональных доменных имён
       Начиная  с  glibc  2.3.4,  getaddrinfo()  был расширен для выборочного прозрачного разрешения исходящих и
       входящих адресов в формате интернациональных доменных имен (IDN, см. RFC 3490, Internationalizing  Domain
       Names in Applications (IDNA)). Было определено четыре новых флага:

       AI_IDN Если  указан  этот  флаг,  то,  в  случае  необходимости,  имя  узла,  указанного  в  node,  будет
              преобразовано в IDN-формат. Исходной кодировкой будет текущая локаль.

              Если имя на входе содержит символы не-ASCII, то будет задействовано кодирование IDN.  Части  имени
              узла  (разделенные точками), которые содержат символы не-ASCII, будут закодированы с помощью ASCII
              Compatible Encoding (ACE) прежде, чем будут переданы функциям преобразования имен

       AI_CANONIDN
              При указанном  флаге  AI_CANONNAME  после  успешного  преобразования  имени  getaddrinfo()  вернет
              каноничное  имя  узла  согласно  значению  структуры  addrinfo. Возвращаемое значение будет точной
              копией значения, возвращенного функцией разрешения имени.

              Если имя закодировано с  помощью  ACE,  то  оно  будет  содержать  префикс  xn--  для  каждого  из
              закодированных  компонентов  имени.  Чтобы  преобразовать  эти компоненты в читаемый вид, вместе с
              флагом AI_CANONNAME следует передать AI_CANONIDN. Итоговая  строка  будет  кодирована  при  помощи
              текущей локали.

       AI_IDN_ALLOW_UNASSIGNED
       AI_IDN_USE_STD3_ASCII_RULES
              Установка  этих  флагов  включает  IDNA_ALLOW_UNASSIGNED  (разрешать  не назначенные кодовые точки
              Юникода)  и  IDNA_USE_STD3_ASCII_RULES  (проверять  вывод  на  соответствие   имени   узла   STD3)
              соответственно для возможности работы с IDNA.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

       В случае успеха getaddrinfo() возвращает 0, либо один из следующие ненулевых кодов ошибки:

       EAI_ADDRFAMILY
              У указанного сетевого узла нет сетевых адресов в запрашиваемом семействе адресов.

       EAI_AGAIN
              Сервер имен вернул временную ошибку. Попробуйте позднее.

       EAI_BADFLAGS
              hints.ai_flags contains invalid flags; or, hints.ai_flags included AI_CANONNAME and node was NULL.

       EAI_FAIL
              Сервер имен вернул постоянную ошибку.

       EAI_FAMILY
              Запрашиваемое семейство адресов не поддерживается.

       EAI_MEMORY
              Не хватает памяти.

       EAI_NODATA
              Указанный сетевой узел существует, однако не имеет ни одного определенного сетевого адреса.

       EAI_NONAME
              node  или service неизвестно; либо и node, и service равны NULL; либо в hints.ai_flags указан флаг
              AI_NUMERICSERV, а service не является числовой строкой порта.

       EAI_SERVICE
              Запрошенная служба не доступна для запрошенного типа сокета. Она может быть доступна через  другой
              тип  сокета.  Например,  эта  ошибка  может  возникнуть,  если  в  service указан «shell» (служба,
              доступная только для потоковых  сокетов)  при  указанном  в  hints.ai_protocol  IPPROTO_UDP,  либо
              указанном  в  hints.ai_socktype  SOCK_DGRAM.  Также ошибка может возникнуть, если service не равно
              NULL, а в hints.ai_socktype указано значение SOCK_RAW (тип сокета, для  которого  концепция  служб
              неприменима).

       EAI_SOCKTYPE
              Запрашиваемый тип сокетов не поддерживается. Такая ошибка может возникнуть, если hints.ai_socktype
              и hints.ai_protocol противоречат друг другу (например, SOCK_DGRAM и IPPROTO_TCP соответственно).

       EAI_SYSTEM
              Other system error; errno is set to indicate the error.

       Функция gai_strerror() транслирует эти коды ошибок в читаемый формат, подходящий для сообщений об ошибке.

ФАЙЛЫ

       /etc/gai.conf

АТРИБУТЫ

       Описание терминов данного раздела смотрите в attributes(7).
       ┌───────────────────────────────────────────────────────────┬──────────────────────┬────────────────────┐
       │ ИнтерфейсАтрибутЗначение           │
       ├───────────────────────────────────────────────────────────┼──────────────────────┼────────────────────┤
       │ getaddrinfo()                                             │ Безвредность в нитях │ MT-Safe env locale │
       ├───────────────────────────────────────────────────────────┼──────────────────────┼────────────────────┤
       │ freeaddrinfo(), gai_strerror()                            │ Безвредность в нитях │ MT-Safe            │
       └───────────────────────────────────────────────────────────┴──────────────────────┴────────────────────┘

ВЕРСИИ

       According  to  POSIX.1,  specifying  hints  as  NULL should cause ai_flags to be assumed as 0.  The GNU C
       library instead assumes a value of (AI_V4MAPPED | AI_ADDRCONFIG) for  this  case,  since  this  value  is
       considered an improvement on the specification.

СТАНДАРТЫ

       POSIX.1-2008.

       getaddrinfo()
              RFC 2553.

ИСТОРИЯ

       POSIX.1-2001.

       AI_ADDRCONFIG
       AI_ALL
       AI_V4MAPPED
              glibc 2.3.3.

       AI_NUMERICSERV
              glibc 2.3.4.

ПРИМЕЧАНИЯ

       getaddrinfo() поддерживает нотацию address%scope-id для указания IPv6 scope-ID.

ПРИМЕРЫ

       Следующие   программы   демонстрируют   использование  getaddrinfo(),  gai_strerror(),  freeaddrinfo()  и
       getnameinfo(3). Это программы эхо-сервера и клиента UDP-дейтаграмм.

   Серверная программа

       #include <netdb.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/types.h>
       #include <unistd.h>

       #define BUF_SIZE 500

       int
       main(int argc, char *argv[])
       {
           int                      sfd, s;
           char                     buf[BUF_SIZE];
           ssize_t                  nread;
           socklen_t                peer_addrlen;
           struct addrinfo          hints;
           struct addrinfo          *result, *rp;
           struct sockaddr_storage  peer_addr;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s port\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           memset(&hints, 0, sizeof(hints));
           hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
           hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
           hints.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
           hints.ai_protocol = 0;          /* Any protocol */
           hints.ai_canonname = NULL;
           hints.ai_addr = NULL;
           hints.ai_next = NULL;

           s = getaddrinfo(NULL, argv[1], &hints, &result);
           if (s != 0) {
               fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
               exit(EXIT_FAILURE);
           }

           /* getaddrinfo() returns a list of address structures.
              Try each address until we successfully bind(2).
              If socket(2) (or bind(2)) fails, we (close the socket
              and) try the next address. */

           for (rp = result; rp != NULL; rp = rp->ai_next) {
               sfd = socket(rp->ai_family, rp->ai_socktype,
                            rp->ai_protocol);
               if (sfd == -1)
                   continue;

               if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
                   break;                  /* Success */

               close(sfd);
           }

           freeaddrinfo(result);           /* No longer needed */

           if (rp == NULL) {               /* No address succeeded */
               fprintf(stderr, "Could not bind\n");
               exit(EXIT_FAILURE);
           }

           /* Read datagrams and echo them back to sender. */

           for (;;) {
               char host[NI_MAXHOST], service[NI_MAXSERV];

               peer_addrlen = sizeof(peer_addr);
               nread = recvfrom(sfd, buf, BUF_SIZE, 0,
                                (struct sockaddr *) &peer_addr, &peer_addrlen);
               if (nread == -1)
                   continue;               /* Ignore failed request */

               s = getnameinfo((struct sockaddr *) &peer_addr,
                               peer_addrlen, host, NI_MAXHOST,
                               service, NI_MAXSERV, NI_NUMERICSERV);
               if (s == 0)
                   printf("Received %zd bytes from %s:%s\n",
                          nread, host, service);
               else
                   fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));

               if (sendto(sfd, buf, nread, 0, (struct sockaddr *) &peer_addr,
                          peer_addrlen) != nread)
               {
                   fprintf(stderr, "Error sending response\n");
               }
           }
       }

   Клиентская программа

       #include <netdb.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/types.h>
       #include <unistd.h>

       #define BUF_SIZE 500

       int
       main(int argc, char *argv[])
       {
           int              sfd, s;
           char             buf[BUF_SIZE];
           size_t           len;
           ssize_t          nread;
           struct addrinfo  hints;
           struct addrinfo  *result, *rp;

           if (argc < 3) {
               fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           /* Obtain address(es) matching host/port. */

           memset(&hints, 0, sizeof(hints));
           hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
           hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
           hints.ai_flags = 0;
           hints.ai_protocol = 0;          /* Any protocol */

           s = getaddrinfo(argv[1], argv[2], &hints, &result);
           if (s != 0) {
               fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
               exit(EXIT_FAILURE);
           }

           /* getaddrinfo() returns a list of address structures.
              Try each address until we successfully connect(2).
              If socket(2) (or connect(2)) fails, we (close the socket
              and) try the next address. */

           for (rp = result; rp != NULL; rp = rp->ai_next) {
               sfd = socket(rp->ai_family, rp->ai_socktype,
                            rp->ai_protocol);
               if (sfd == -1)
                   continue;

               if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
                   break;                  /* Success */

               close(sfd);
           }

           freeaddrinfo(result);           /* No longer needed */

           if (rp == NULL) {               /* No address succeeded */
               fprintf(stderr, "Could not connect\n");
               exit(EXIT_FAILURE);
           }

           /* Send remaining command-line arguments as separate
              datagrams, and read responses from server. */

           for (size_t j = 3; j < argc; j++) {
               len = strlen(argv[j]) + 1;
                       /* +1 for terminating null byte */

               if (len > BUF_SIZE) {
                   fprintf(stderr,
                           "Ignoring long message in argument %zu\n", j);
                   continue;
               }

               if (write(sfd, argv[j], len) != len) {
                   fprintf(stderr, "partial/failed write\n");
                   exit(EXIT_FAILURE);
               }

               nread = read(sfd, buf, BUF_SIZE);
               if (nread == -1) {
                   perror("read");
                   exit(EXIT_FAILURE);
               }

               printf("Received %zd bytes: %s\n", nread, buf);
           }

           exit(EXIT_SUCCESS);
       }

СМОТРИТЕ ТАКЖЕ

       getaddrinfo_a(3), gethostbyname(3), getnameinfo(3), inet(3), gai.conf(5), hostname(7), ip(7)

ПЕРЕВОД

       Русский перевод этой страницы  руководства  разработал(и)  Azamat  Hackimov  <azamat.hackimov@gmail.com>,
       Dmitry   Bolkhovskikh   <d20052005@yandex.ru>,   Vladislav   <ivladislavefimov@gmail.com>,   Yuri  Kozlov
       <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>

       Этот перевод является свободной программной документацией; он распространяется на условиях  общедоступной
       лицензии  GNU  (GNU  General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или
       более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

       Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите  об  этом
       разработчику(ам)   по   его(их)  адресу(ам)  электронной  почты  или  по  адресу  списка рассылки русских
       переводчиков.

Справочные страницы Linux 6.9.1                  15 июня 2024 г.                                  getaddrinfo(3)