Quel est le but de l'indicateur AI_V4MAPPED dans getaddrinfo?
-
05-07-2019 - |
Question
L'appel getaddrinfo comporte de nombreux drapeaux intéressants. Je me demande quel est l'objectif de l'indicateur AI_V4MAPPED. Sur aucun système, il semble que je ne puisse obtenir que getaddrinfo produise les adresses de formulaire :: ffff: n.n.n.n comme je l’attendrais lorsque je mets ce drapeau. Est-ce que je m'attends à la mauvaise chose? Est-ce que je vois des insectes?
En particulier, si je demande les adresses de la famille AF_INET6 et que je spécifie AI_V4MAPPED, je m'attendrais à voir les adresses :: ffff: n.n.n.n pour les hôtes qui possèdent uniquement des enregistrements DNS A (adresse IPv4). Et je m'attendrais aussi généralement à ce que si je spécifiais AI_ALL, j'obtiendrais à la fois les enregistrements DNS AAAA (adresse IPv6) et les enregistrements DNS A d'un hôte sous la forme :: ffff: n.n.n.n.
Encore une fois, est-ce que j'attends toutes les mauvaises choses ici?
J'ai testé cela sur Fedora 11 - glibc 2.10.1 et OS X 10.4.
La solution
J'obtiens exactement ce que vous espérez obtenir sur Debian Lenny (glibc 2.7) - à une exception près - si je spécifie AI_V4MAPPED
sans AI_ALL
, et le nom d'hôte. Je regarde CNAME pointant sur A records, je ne les récupère pas. Cela fonctionne correctement si AI_ALL
est également spécifié ou si le nom d’hôte est directement associé aux enregistrements A.
Je ne sais pas pourquoi - c'est peut-être un bug de la glibc?
Voici mon programme de test:
#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;
}
Autres conseils
D'après mon expérience, AI_V4MAPPED
ne fonctionne pas sous Mac OS X 10.6. Si vous fournissez hints.ai_family = AF_INET6
et hints.ai_flags = AI_V4MAPPED
, il retournera toujours EAI_NONAME
et gai_strerror ()
imprime "nodename ni nom serveur fourni ou inconnu".
Cela fonctionne correctement sous OS X 10.7.
Afficher ceci ici au cas où cela pourrait aider quelqu'un, même si vous êtes sur Fedora.