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 ? Не понимаю почему ?
второй вопрос: где я могу найти значение этих ints (40,2,1,6 и т. д.) ? Я читал, но там ничего об этом.
Я также хотел знать, можно ли дать адрес IPv6 (например:1) и функция возвращает имя : имя localhost ?
Спасибо большое !!
4 ответов
@jwodder и @onteria_ хорошо покрыли часть IPv6, поэтому я просто займусь цифры часть:
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
это семейные протоколом, inet, inet6, apx, unix и т. д.:
ai_family -> 2
bits/socket.h:78:#define PF_INET 2 /* IP protocol family. */
bits/socket.h:119:#define AF_INET PF_INET
это тип сокета, поток, dgram, пакет, rdm, seqpacket:
ai_socktype -> 1
bits/socket.h:42: SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
более высокий уровень протокол, TCP, UDP, TCP6, UDP6, UDPlite, ospf, icmp и т. д.:
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.
что касается целых полей в struct addrinfo
, они соответствуют предопределенным константам со значениями, определенными реализацией, а сами целочисленные значения не представляют общего интереса. Если вы хотите знать, что означает данное поле, сравните его с константами, которые могут присваивается этому полю (SOCK_STREAM
, SOCK_DGRAM
, etc. для ai_socktype
; IPPROTO_TCP
, IPPROTO_UDP
, etc. для 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()
; учитывая адрес сокета, он возвращает имя строки.