首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用ipv6时getaddrinfo()只返回AF_UNSPEC

使用ipv6时getaddrinfo()只返回AF_UNSPEC
EN

Stack Overflow用户
提问于 2019-04-11 07:53:39
回答 1查看 1.5K关注 0票数 1

当我想连接到服务器(在本地运行)而不知道应用程序是否使用ipv4、ipv6或两者时,我应该调用getaddrinfo()两次,一次用AF_INET,一次用AF_INET6,然后尝试所有返回的地址?

一些上下文:getaddrinfo()为ipv6 4/ipv6 6提供了一种方法--不可知的主机名解析。在网上,我发现了一个关于连接到服务器的通用算法的指导方针是使用getaddrinfo()和一个AF_UNSPEC提示,并尝试列表中返回的地址。

但是,在我的设置中,getaddrinfo() 只在使用AF_UNSPEC (主机为"localhost" )时返回ipv6条目。另一方面,如果我显式地请求IPv4,getaddrinfo()确实返回IPv4地址。

这个例子用AF_UNSPEC调用一次AF_UNSPEC,用AF_INET调用一次,然后遍历返回的列表并打印条目的地址族:

代码语言:javascript
运行
复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>

const char* family_to_string(int family) {
    switch (family) {
        case AF_INET:
            return "AF_INET";
        case AF_INET6:
            return "AF_INET6";
        case AF_UNSPEC:
            return "AF_UNSPEC";
        default:
            return "UNKNOWN";
    }
}

int main(void) {
    struct addrinfo hints;
    struct addrinfo *res, *it;
    static const char* host = "localhost";
    static const char* port = "42420";

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
    hints.ai_family = AF_UNSPEC;
    printf("getaddrinfo(.. %s ..):\n", family_to_string(hints.ai_family));
    int ret = getaddrinfo(host, port, &hints, &res);
    if (ret != 0) {
        return 1;
    }

    for (it = res; it != NULL; it = it->ai_next) {
        printf("entry for %s\n", family_to_string(it->ai_family));
    }
    printf("\n");
    freeaddrinfo(res);

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
    hints.ai_family = AF_INET;
    printf("getaddrinfo(.. %s ..):\n", family_to_string(hints.ai_family));
    ret = getaddrinfo(host, port, &hints, &res);
    if (ret != 0) {
        return 1;
    }

    for (it = res; it != NULL; it = it->ai_next) {
        printf("entry for %s\n", family_to_string(it->ai_family));
    }
    printf("\n");
    freeaddrinfo(res);

    return 0;
}

当我收到这个输出时,我感到非常惊讶:

代码语言:javascript
运行
复制
getaddrinfo(.. AF_UNSPEC ..):
entry for AF_INET6

getaddrinfo(.. AF_INET ..):
entry for AF_INET

在深入研究了getaddrinfo()的行为之后,它似乎首先在/etc/hosts中检查条目,如果它找到匹配的条目,它只返回这些条目,并且不会尝试以不同的方式解析主机名。

因为我的/etc/hosts文件只包含localhost的一个ipv6条目,所以只返回给AF_UNSPEC。对于AF_INET,条目被认为是不合格的,localhost被正确地解析为127.0.0.1

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-04-11 08:34:24

这的确是一个有趣的问题:

这种情况是由glibc的nss-files模块专门处理的;如果发出了对带有地址族AF_INET的localhost的请求,并且解析了/etc/host的v6 localhost条目,则它将被隐式转换为带有address 127.0.0.1的v4 localhost条目。

请参见nss/nss_files/files-hosts.c (第70行),其中执行此转换:

代码语言:javascript
运行
复制
else if (IN6_IS_ADDR_LOOPBACK (entdata->host_addr))
  {
    in_addr_t localhost = htonl (INADDR_LOOPBACK);
    memcpy (entdata->host_addr, &localhost, sizeof (localhost));
  }

当请求AF_UNSPEC时,这个分支不会被占用,所以只有在/etc/hosts中有一个显式条目时,您才会解析一个v4本地主机地址。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55627377

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档