getaddrinfo и IPv6



Я пытаюсь понять, что возвращает функция getaddrinfo:



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

int main (int argc, char *argv[])
{


struct addrinfo *res = 0 ;

getaddrinfo("localhost", NULL ,NULL,&res);
printf("ai_flags -> %in", res->ai_flags) ;
printf("ai_family -> %in", res->ai_family) ;
printf("ai_socktype -> %in", res->ai_socktype) ;
printf("ai_protocol -> %in", res->ai_protocol) ;
printf("ai_addrlen -> %in", res->ai_addrlen) ;
struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
printf("ai_addr hostname -> %sn", inet_ntoa(saddr->sin_addr));

freeaddrinfo(res);

return 0 ;
}


Результаты :



ai_flags -> 40
ai_family -> 2
ai_socktype -> 1
ai_protocol -> 6
ai_addrlen -> 16
ai_addr hostname -> 127.0.0.1


В файле/etc / hosts у меня есть:



127.0.0.1 localhost    
::1 localhost


Getaddrinfo возвращает только 127.0.0.1, а не :: 1 ? Я не понимаю, почему ?



Второй вопрос заключается в том, где я могу найти значение этих интов (40,2,1,6 и т. д.)? Я читал этого человека, но там ничего об этом нет.

Я также хотел узнать, можно ли дать IPv6-адрес (например :: 1), и функция возвращает название: localhost ?



Большое спасибо !!

602   4  

4 ответов:

@jwodder и @onteria_ хорошо покрыли часть IPv6, поэтому я просто займусь частью numbers :

ai_flags -> 40

Вероятно, это будет сумма следующих двух в /usr/include/netdb.h:

# define AI_V4MAPPED    0x0008  /* IPv4 mapped addresses are acceptable.  */
# define AI_ADDRCONFIG  0x0020  /* Use configuration of this host to choose

Это семейные протокола, инет, inet6, арх, Unix и др.:

ai_family -> 2

bits/socket.h:78:#define    PF_INET     2   /* IP protocol family.  */
bits/socket.h:119:#define   AF_INET     PF_INET

Это тип сокета , stream, dgram, packet, rdm, seqpacket:

ai_socktype -> 1

bits/socket.h:42:  SOCK_STREAM = 1,     /* Sequenced, reliable, connection-based

Более высокого уровня протокол, TCP или UDP, TCP6, UDP6, UDPlite, протокол OSPF, ICMP-пакеты, etc:

ai_protocol -> 6

Довольно забавно, в /etc/protocols:

tcp 6   TCP     # transmission control protocol

Размер struct sockaddr. (Отличается в зависимости от адреса семьи! Тьфу.)

ai_addrlen -> 16

Это потому, что вы получаете обратно struct sockaddr_in, см. linux/in.h:

#define __SOCK_SIZE__   16      /* sizeof(struct sockaddr)  */
struct sockaddr_in {
  sa_family_t       sin_family; /* Address family       */
  __be16        sin_port;   /* Port number          */
  struct in_addr    sin_addr;   /* Internet address     */

  /* Pad to size of `struct sockaddr'. */
  unsigned char     __pad[__SOCK_SIZE__ - sizeof(short int) -
            sizeof(unsigned short int) - sizeof(struct in_addr)];
};

И последний, из /etc/hosts :)

ai_addr hostname ->  127.0.0.1

res также содержит поле struct addrinfo *ai_next;, которое является указателем на дополнительные записи, найденные getaddrinfo, или NULL, если других записей не было. Если вы исследуете res->ai_next, Вы должны найти запись IPv6.

Что касается целых полей в A struct addrinfo, то они соответствуют предопределенным константам с определенными реализацией значениями, А сами целочисленные значения не представляют общего интереса. Если вы хотите знать, что означает данное поле, сравните его с константами, которые могут быть присвоены этому полю. поле (SOCK_STREAM, SOCK_DGRAM, и т.д. ибо ai_socktype; IPPROTO_TCP, IPPROTO_UDP, и т.д. для ai_protocol; и так далее) или, для ai_flags, проверить каждый бит, соответствующий предопределенной константе (например, if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); }).

extern struct sockaddr_in6 create_socket6(int port, const char * address) {

    struct addrinfo hints, *res, *resalloc;
    struct sockaddr_in6 input_socket6;
    int errcode;

    /* 0 out our structs to be on the safe side */
    memset (&hints, 0, sizeof (hints));
    memset (&input_socket6, 0, sizeof(struct sockaddr_in6));

    /* We only care about IPV6 results */
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_DEFAULT;

    errcode = getaddrinfo (address, NULL, &hints, &res);
    if (errcode != 0)
    {
     perror ("[ERROR] getaddrinfo ");
     return input_socket6;
    }

    resalloc = res;

    while (res)
    {
        /* Check to make sure we have a valid AF_INET6 address */
        if(res->ai_family == AF_INET6) {
                /* Use memcpy since we're going to free the res variable later */
                        memcpy (&input_socket6, res->ai_addr, res->ai_addrlen);

                       /* Here we convert the port to network byte order */
                        input_socket6.sin6_port = htons (port);
                        input_socket6.sin6_family = AF_INET6;
               break;
        }

        res = res->ai_next;
    }

    freeaddrinfo(resalloc);

    return input_socket6;
}

Вот некоторый код, который объясняет это. В принципе, если вы не дадите getaddrinfo несколько подсказок, чтобы он работал только с IPV6, он также даст результаты IPV4. Вот почему вы должны пройти через результаты, как показано на рисунке.

На большинство частей были даны другие ответы, но чтобы ответить на эту заключительную часть:

Я также хотел узнать, можно ли дать IPv6-адрес (например :: 1), и функция возвращает имя : localhost ?

Функция, которую вы хотите, есть getnameinfo(); при заданном адресе сокета она возвращает строковое имя.

Comments

    Ничего не найдено.