I don't understand why getaddrinfo
is not returning a valid IPv6 address.
On my system the code below is printing 22:B8:00:00:00:00:00:00:00:00:00:00:00:00
, but I expected a 01
somewhere, since localhost
should resolve to ::1
.
At the same time, sa_data
is only 14 bytes, whereas IPv6 addresses are 16 bytes, so it seems that the last couple of bytes are always chopped off, and the function can't return an IPv6 address?
Can someone explain what's going on? How am I supposed to use this function with IPv6?
#include <stdio.h>
#include <WinSock2.h>
#include <WS2TCPIP.h>
#pragma comment(lib, "WS2_32")
int main(int argc, char *argv[])
{
WSADATA wsadata;
WSAStartup(0x0002, &wsadata);
addrinfo addr_hints = { 0, PF_INET6, SOCK_DGRAM, IPPROTO_UDP }, *addrs_out;
getaddrinfo("localhost", "8888", &addr_hints, &addrs_out);
fprintf(stderr,
"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 0]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 1]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 2]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 3]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 4]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 5]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 6]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 7]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 8]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 9]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[10]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[11]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[12]),
static_cast<unsigned char>(addrs_out->ai_addr->sa_data[13]));
freeaddrinfo(addrs_out);
return 0;
}
sockaddr
struct definitions for reference:
struct sockaddr {
ushort sa_family;
char sa_data[14];
};
struct sockaddr_in6 {
short sin6_family;
u_short sin6_port;
u_long sin6_flowinfo;
struct in6_addr sin6_addr;
u_long sin6_scope_id;
};
When ai_family == AF_INET6
ai_addr
actually points to a struct sockaddr_in6
. The first few bytes you are printing are sin6_port
and sin6_flowinfo
. The IPv6 address comes after.
Edit to add:
You can use ai_addr
directly with functions like bind()
and getnameinfo()
. You typically won't need to dig down into the struct definition details. For example, I would use getnameinfo()
with NI_NUMERICHOST
to get a printable address.