According to https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551:
This statement in the POSIX specification also implies that if the AI_PASSIVE flag is specified without a hostname, then the IPv6 wildcard address (IN6ADDR_ANY_INIT or 0::0) should be returned as a sockaddr_in6 structure, along with the IPv4 wildcard address (INADDR_ANY or 0.0.0.0), which is returned as a sockaddr_in structure. It also makes sense to return the IPv6 wildcard address first because we will see in Section 12.2 that an IPv6 server socket can handle both IPv6 and IPv4 clients on a dual-stack host.
However, if I try to set the AI_PASSIVE
flag (and having null
hostname of course), as is a case for passive servers, then I will get first IPv4
and not IPv6
as book suggest:
#include <netdb.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#define HOSTLEN 128
#define PORTLEN 16
int main()
{
int retcode;
struct addrinfo hints, *res;
char output[HOSTLEN], portbuf[PORTLEN];
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
//exmaple of socktype to be SOCK_STREAM
hints.ai_socktype = SOCK_STREAM;
//example port "ftp"
if ((retcode = getaddrinfo(NULL, "ftp", &hints, &res)) != 0)
{
printf("getaddrinfo error: %s\n", gai_strerror(retcode));
}
do
{
switch (res->ai_family)
{
case AF_INET:;
struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
inet_ntop(res->ai_family, &sin->sin_addr, output, HOSTLEN);
snprintf(portbuf, PORTLEN, ":%d", ntohs(sin->sin_port));
strcat(output, portbuf);
break;
case AF_INET6:;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
output[0] = '[';
inet_ntop(res->ai_family, &sin6->sin6_addr, output + 1, HOSTLEN - 1);
snprintf(portbuf, PORTLEN, "]:%d", ntohs(sin6->sin6_port));
strcat(output, portbuf);
break;
}
printf("address returned from getaddrinfo: %s\n", output);
} while ((res = res->ai_next) != NULL);
}
output:
address returned from getaddrinfo: 0.0.0.0:21
address returned from getaddrinfo: [::]:21
So I can see, the first address retuned from getaddrinfo()
, is sockaddr_in
(ipv4) and not sockaddr_in6
(ipv6). So is the book incorrect or is it just because of some configutation?
The reason I ask is becuase it causes problem when trying to connect client, that specifies IPv6 address for the server (which has address returned from getaddrinfo()
, set AI_PASSIVE) and returning 0.0.0.0 instead if 0::0 and thus the client will never connect. So how to make getaddrinfo to return 0::0 instead of 0.0.0.0 when AI_PASSIVE is set?