The getaddrinfo call has many interesting flags. I'm wondering what the purpose of the AI_V4MAPPED flag is. On no system do I seem to be able to get getaddrinfo to produce ::ffff:n.n.n.n form addresses as I would expect when I set this flag. Am I expecting the wrong thing? Am I seeing bugs?
In particlar, if I ask for AF_INET6 family addresses and specify AI_V4MAPPED I would expect to see ::ffff:n.n.n.n addresses for hosts that only have DNS A (IPv4 address) records. And I would also generally expect that if I specified AI_ALL that I would get both a host's DNS AAAA (IPv6 address) records and DNS A records in ::ffff:n.n.n.n form.
Again, am I expecting all the wrong things here?
I've tested this on Fedora 11 - glibc 2.10.1 and OS X 10.4.
I get exactly what you're expecting to get, on Debian Lenny (glibc 2.7) - with one exception - if I specify AI_V4MAPPED
without AI_ALL
, and the hostname I look up has CNAMEs pointing at A records, I don't get those returned. It works fine if AI_ALL
is also specified, or if the hostname is directly associated with A records.
I don't know why - perhaps that's a glibc bug?
Here's my test program:
#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;
}
In my experience, AI_V4MAPPED
does not work on Mac OS X 10.6. If you provide hints.ai_family = AF_INET6
and hints.ai_flags = AI_V4MAPPED
it will always return EAI_NONAME
, and gai_strerror()
prints "nodename nor servname provided, or not known".
It works properly on OS X 10.7.
Posting this here in case it helps someone, even though you're on Fedora.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With