【问题标题】:What is the purpose of the AI_V4MAPPED flag in getaddrinfo?getaddrinfo 中 AI_V4MAPPED 标志的用途是什么?
【发布时间】:2010-11-27 08:09:21
【问题描述】:

getaddrinfo 调用有许多有趣的标志。我想知道 AI_V4MAPPED 标志的目的是什么。在没有系统上,我似乎能够让 getaddrinfo 生成 ::ffff:n.n.n.n 表单地址,正如我在设置此标志时所期望的那样。我期待错了吗?我看到错误了吗?

特别是,如果我询问 AF_INET6 系列地址并指定 AI_V4MAPPED,我希望看到仅具有 DNS A(IPv4 地址)记录的主机的 ::ffff:n.n.n.n 地址。而且我通常还期望,如果我指定 AI_ALL,我将同时获得主机的 DNS AAAA(IPv6 地址)记录和 DNS A 记录,格式为 ::ffff:n.n.n.n。

再一次,我是不是在期待所有错误的事情?

我已经在 Fedora 11 - glibc 2.10.1 和 OS X 10.4 上对此进行了测试。

【问题讨论】:

    标签: networking network-programming ipv6


    【解决方案1】:

    在 Debian Lenny (glibc 2.7) 上,我得到了您所期望的结果 - 除了一个例外 - 如果我指定 AI_V4MAPPED 而不指定 AI_ALL,并且我查找的主机名有指向 A 记录的 CNAME,我不让那些退回。如果还指定了AI_ALL,或者主机名与 A 记录直接关联,则可以正常工作。

    我不知道为什么 - 也许这是一个 glibc 错误?

    这是我的测试程序:

    #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;
    }
    

    【讨论】:

    • 我对此进行了大量研究。 getaddrinfo 似乎被许多错误所困扰,部分原因是它有很多奇怪的案例来解决对 AAAA 请求的错误处理。
    • 您的答案最接近真实答案,因此您将获得答案。
    • 没有 AI_ALL 的 AI_V4MAPPED 是一个 glibc 错误,请参阅 bugs.debian.org/cgi-bin/bugreport.cgi?bug=503912
    【解决方案2】:

    根据我的经验,AI_V4MAPPED 不适用于 Mac OS X 10.6。如果您提供hints.ai_family = AF_INET6hints.ai_flags = AI_V4MAPPED,它将始终返回EAI_NONAME,并且gai_strerror() 打印“提供节点名或服务名,或未知”。

    它可以在 OS X 10.7 上正常运行。

    在这里发布它以防它对某人有所帮助,即使您使用的是 Fedora。

    【讨论】:

      猜你喜欢
      • 2017-08-08
      • 2019-07-17
      • 2010-10-03
      • 2014-10-31
      • 2017-01-31
      • 2012-06-07
      • 1970-01-01
      • 2012-09-08
      相关资源
      最近更新 更多