getaddrinfo sorting IPv4 before IPv6 for localhost

2019-07-10 11:31发布

问题:

I wrote a very simple test program for getaddrinfo:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>

int main() {
    struct addrinfo hints;
    struct addrinfo *res, *rp;
    char hoststr[64], servstr[8];

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    getaddrinfo(NULL, "9998", &hints, &res);
    for (rp = res; rp != NULL; rp = rp->ai_next) {
        getnameinfo(rp->ai_addr, rp->ai_addrlen, hoststr, sizeof(hoststr),
                servstr, sizeof(servstr), NI_NUMERICHOST | NI_NUMERICSERV);
        printf("%s:%s\n", hoststr, servstr);
    }
}

When I compile and run this program, it's giving the IPv4 address before the IPv6 address:

# gcc -o getaddrinfo getaddrinfo.c
# ./getaddrinfo 
0.0.0.0:9998
:::9998

As far as I can tell from other sources, IPv6 addresses are supposed to be preferred over IPv4. I'm using the default /etc/gai.conf which implies that IPv6 should be preferred over IPv4. So why is getaddrinfo sorting this way?

# ip addr show lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

回答1:

From the man page:

If the AI_PASSIVE flag is specified in hints.ai_flags, and node is NULL, then the returned socket addresses will be suitable for bind(2)ing a socket that will accept(2) connections. The returned socket address will contain the "wildcard address" (INADDR_ANY for IPv4 addresses, IN6ADDR_ANY_INIT for IPv6 address). The wildcard address is used by applications (typically servers) that intend to accept connections on any of the host's network addresses. If node is not NULL, then the AI_PASSIVE flag is ignored.

The behavior you're describing is for when you use getaddrinfo() to look up a name in preparation to make an outgoing connection. Because you're doing the reverse, looking up a local address to bind for a service, the order the addresses are presented is irrelevant.