Qual é o propósito da bandeira AI_V4MAPPED em getaddrinfo?
-
05-07-2019 - |
Pergunta
A chamada getaddrinfo tem muitas bandeiras interessantes. Eu estou querendo saber qual é o propósito da bandeira AI_V4MAPPED é. Em nenhum sistema que eu parecem ser capazes de obter getaddrinfo para produzir :: ffff: endereços de formulário n.n.n.n como seria de esperar quando eu definir esta bandeira. Estou esperando a coisa errada? Estou vendo bugs?
Em particlar, se eu pedir para endereços familiares AF_INET6 e especificar AI_V4MAPPED eu esperaria ver :: ffff: endereços n.n.n.n para os anfitriões que têm somente os registros DNS A (endereço IPv4). E eu também geralmente esperar que se eu especificado AI_ALL que eu iria receber dois (endereço IPv6) registros de um host DNS AAAA e registros DNS A na :: ffff:. Forma n.n.n.n
Mais uma vez, estou esperando todas as coisas erradas aqui?
Eu testei isso no Fedora 11 -. Glibc 2.10.1 e OS X 10.4
Solução
Eu obter exatamente o que você está esperando para começar, no Debian Lenny (glibc 2.7) - com uma exceção - se eu especificar AI_V4MAPPED
sem AI_ALL
, eo hostname Eu olho para cima tem CNAMEs apontando para registros A, eu não sei obter esses devolvidos. Ele funciona muito bem se AI_ALL
também for especificado, ou se o nome do host está diretamente associado com registros A.
Eu não sei por quê? - talvez isso seja um bug glibc
Aqui está o meu programa de teste:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
struct addrinfo hints = { 0 };
struct addrinfo *res, *res_c;
int err;
char name[INET6_ADDRSTRLEN];
if (argc < 2)
{
return 1;
}
hints.ai_family = AF_INET6;
hints.ai_flags = AI_V4MAPPED | AI_ALL;
err = getaddrinfo(argv[1], NULL, &hints, &res);
if (err)
{
printf("getaddrinfo: %s\n", gai_strerror(err));
return 1;
}
for (res_c = res; res_c; res_c = res_c->ai_next)
{
const void *addr;
int port;
struct protoent *proto;
switch (res_c->ai_family)
{
case AF_INET6:
addr = &((struct sockaddr_in6 *)(res_c->ai_addr))->sin6_addr;
port = ((struct sockaddr_in6 *)(res_c->ai_addr))->sin6_port;
printf("AF_INET6\t");
break;
case AF_INET:
addr = &((struct sockaddr_in *)(res_c->ai_addr))->sin_addr;
port = ((struct sockaddr_in *)(res_c->ai_addr))->sin_port;
printf("AF_INET\t");
break;
default:
addr = NULL;
printf("(%d)\t", res_c->ai_family);
}
proto = getprotobynumber(res_c->ai_protocol);
if (proto)
{
printf("%s\t", proto->p_name);
}
else
{
printf("(%d)\t", res_c->ai_protocol);
}
switch (res_c->ai_socktype)
{
case SOCK_STREAM:
printf("SOCK_STREAM\t");
break;
case SOCK_DGRAM:
printf("SOCK_DGRAM\t");
break;
default:
printf("(?socktype?)\t");
break;
}
if (addr && inet_ntop(res_c->ai_family, addr, name, sizeof name))
printf("addr = %s", name);
if (addr)
printf(",%d", port);
printf("\n");
}
return 0;
}
Outras dicas
Na minha experiência, AI_V4MAPPED
não funciona em Mac OS X 10.6. Se você fornecer hints.ai_family = AF_INET6
e hints.ai_flags = AI_V4MAPPED
ele sempre retornará EAI_NONAME
e gai_strerror()
impressões "nodename nem servname fornecido, ou não conhecida".
Ele funciona corretamente no OS X 10.7.
postando isso aqui no caso de ajuda alguém, mesmo que você está no Fedora.