networking - ¿Cuál es el propósito de la bandera AI_V4MAPPED en getaddrinfo?
network-programming ipv6 (2)
En mi experiencia, AI_V4MAPPED
no funciona en Mac OS X 10.6. Si proporciona hints.ai_family = AF_INET6
y hints.ai_flags = AI_V4MAPPED
, siempre devolverá EAI_NONAME
, y gai_strerror()
imprimirá "nodename o servname provided, o no known".
Funciona correctamente en OS X 10.7.
Publicando esto aquí en caso de que ayude a alguien, incluso si estás en Fedora.
La llamada getaddrinfo tiene muchas banderas interesantes. Me pregunto cuál es el propósito de la bandera AI_V4MAPPED. En ningún sistema, parece que soy capaz de hacer que getaddrinfo produzca :: ffff: nnnn las direcciones de formulario que esperaría cuando configuro este indicador. ¿Estoy esperando lo equivocado? ¿Estoy viendo errores?
En particular, si solicito direcciones de familia AF_INET6 y especifico AI_V4MAPPED esperaría ver direcciones :: ffff: nnnn para hosts que solo tienen registros DNS A (dirección IPv4). Y generalmente también esperaría que si especificara AI_ALL obtendría los registros DNS AAAA (dirección IPv6) de un host y los registros DNS A en formato :: ffff: nnnn.
Nuevamente, ¿estoy esperando todas las cosas equivocadas aquí?
He probado esto en Fedora 11 - glibc 2.10.1 y OS X 10.4.
Obtuve exactamente lo que esperaba obtener en Debian Lenny (glibc 2.7) - con una excepción - si especifico AI_V4MAPPED
sin AI_ALL
, y el nombre de host que busco tiene CNAME apuntando a los registros A, no los devuelvo . Funciona bien si también se especifica AI_ALL
o si el nombre de host está directamente asociado con los registros A.
No sé por qué, quizás sea un error glibc.
Aquí está mi programa de prueba:
#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;
}