C 为什么在getaddrinfo()返回的链表中会得到重复的addrinfo对象?

C 为什么在getaddrinfo()返回的链表中会得到重复的addrinfo对象?,c,sockets,ip,C,Sockets,Ip,这是我的密码 #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> int main() { struct addrinfo hints, *res, *p; int error; memset(&

这是我的密码

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

int main()
{
    struct addrinfo hints, *res, *p;
    int error;

    memset(&hints, 0, sizeof hints);

    /* If we comment or remove the following line, the duplicate entries
     * disappear */
    hints.ai_family = AF_INET;

    error = getaddrinfo("localhost", "http", &hints, &res);
    if (error != 0) {
        printf("Error %d: %s\n", error, gai_strerror(error));
        return 1;
    }

    for (p = res; p != NULL; p = p->ai_next)
    {
        if (p->ai_family == AF_INET) {
            struct sockaddr_in *addr = (struct sockaddr_in *) p->ai_addr;
            char ip[INET_ADDRSTRLEN];

            printf("ai_flags: %d; ai_family: %d; ai_socktype: %d; "
                   "ai_protocol: %2d; sin_family: %d; sin_port: %d; "
                   "sin_addr: %s; ai_canonname: %s\n",
                   p->ai_flags, p->ai_family, p->ai_socktype,
                   p->ai_protocol, addr->sin_family, ntohs(addr->sin_port),
                   inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN),
                   p->ai_canonname);
        } else if (p->ai_family == AF_INET6) {
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *) p->ai_addr;
            char ip[INET6_ADDRSTRLEN];

            printf("ai_flags: %d; ai_family: %d; ai_socktype: %d; "
                   "ai_protocol: %2d; sin6_family: %d; sin6_port: %d; "
                   "sin6_addr: %s; ai_canonname: %s\n",
                   p->ai_flags, p->ai_family, p->ai_socktype,
                   p->ai_protocol, addr->sin6_family, ntohs(addr->sin6_port),
                   inet_ntop(AF_INET6, &addr->sin6_addr, ip, INET6_ADDRSTRLEN),
                   p->ai_canonname);
        }
    }

    return 0;
}
输出显示第一个和第三个条目完全相同。类似地,第二和第四个条目完全相同。为什么我们会在结果中得到这些重复

如果我们在代码中注释或删除以下行,则重复条目将消失

    /* If we comment or remove the following line, the duplicate entries
     * disappear */
    /* hints.ai_family = AF_INET; */
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic bar.c && ./a.out
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
这是本例中的输出

$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic bar.c && ./a.out
ai_flags: 0; ai_family: 10; ai_socktype: 1; ai_protocol:  6; sin6_family: 10; sin6_port: 80; sin6_addr: ::1; ai_canonname: (null)
ai_flags: 0; ai_family: 10; ai_socktype: 2; ai_protocol: 17; sin6_family: 10; sin6_port: 80; sin6_addr: ::1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
这就是我的
/etc/hosts
的外观

$ cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       debian1

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
如果代码中存在
hints.ai_family=AF_INET
,但如果注释掉
/etc/hosts
中以
开头的行::1
,则重复条目确实会消失

    /* If we comment or remove the following line, the duplicate entries
     * disappear */
    /* hints.ai_family = AF_INET; */
$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic bar.c && ./a.out
ai_flags: 0; ai_family: 2; ai_socktype: 1; ai_protocol:  6; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)
ai_flags: 0; ai_family: 2; ai_socktype: 2; ai_protocol: 17; sin_family: 2; sin_port: 80; sin_addr: 127.0.0.1; ai_canonname: (null)

但是我仍然想知道为什么
/etc/hosts
中的IPv6条目会导致重复条目,即使
hints.ai_family=AF_INET
仅用于选择IPv4条目。

检查主机名(/etc/hosts)的静态表查找文件

当有两行具有相同的规范\u主机名“localhost”时,getaddrinfo将返回重复的addrinfo

您的/etc/主机可能如下所示:

 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
 ::1 localhost

检查静态表查找文件中的主机名(/etc/hosts)

当有两行具有相同的规范\u主机名“localhost”时,getaddrinfo将返回重复的addrinfo

您的/etc/主机可能如下所示:

 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
 ::1 localhost

这是glibc的一个长期缺陷/特性。当您的
hosts
文件中有IPv6本地主机条目时,如

::1 localhost
它自动用于
AF\u INET
名称解析。Ulrich Drepper于2006年11月介绍了这种行为,并发表了以下评论:

nss/nss_files/files hosts.c(LINE_PARSER):如果可以映射IPv4查询,则支持IPv6样式的地址

一些人认为这是bug,尽管至少有两个bug报告对此主题进行了长时间的讨论(和),但没有人真正解释为什么会做出这样的更改,所以我猜唯一能做到这一点的人是Ulrich本人。但它可能在某些场景中很有用,因为尽管Ulrich从2012年5月起就没有在glibc上工作,但这段代码仍然存在于glibc的每个现代版本中

如果您不喜欢这种行为,可以调整
主机
文件,使其不具有IPv6环回地址的
本地主机
名称,使用其他名称,如:

::1 localhost6

或者使用一些发行版,人们认为这是一个bug,实际上是在维护glibc包,比如openSUSE(可能还有SLES/SLED)。这是glibc的一个长期bug/功能。当您的
hosts
文件中有IPv6本地主机条目时,如

::1 localhost
它自动用于
AF\u INET
名称解析。Ulrich Drepper于2006年11月介绍了这种行为,并发表了以下评论:

nss/nss_files/files hosts.c(LINE_PARSER):如果可以映射IPv4查询,则支持IPv6样式的地址

一些人认为这是bug,尽管至少有两个bug报告对此主题进行了长时间的讨论(和),但没有人真正解释为什么会做出这样的更改,所以我猜唯一能做到这一点的人是Ulrich本人。但它可能在某些场景中很有用,因为尽管Ulrich从2012年5月起就没有在glibc上工作,但这段代码仍然存在于glibc的每个现代版本中

如果您不喜欢这种行为,可以调整
主机
文件,使其不具有IPv6环回地址的
本地主机
名称,使用其他名称,如:

::1 localhost6

或者使用一些发行版,人们认为这是一个bug,但实际上却在维护glibc包,比如openSUSE(可能还有SLES/SLED)。我的/etc/hosts确实与您的类似。我不明白为什么它应该返回重复的
addrinfo
s。第二项是IPv6地址
::1
。在我的代码中,我使用了
提示
专门选择IPv4地址。我添加了另一组输出,这表明当我从代码中删除
提示时没有重复的条目。ai_family=AF_INET
。仅当我在代码中选择仅包含提示的IPv4条目时,才会出现重复条目。@LoneLearner:尝试注释IPv6条目。它可能类似于,特定于发行版(或glibc版本?),因为在我的机器上没有这样的问题。@RomanKhimov如果
/etc/hosts
中以
:1
开头的行被注释掉,那么重复的条目确实会消失。@RomanKhimov您的评论似乎回答了这个问题。如果你能用Redhat Bugzilla的链接写下你自己的答案,我会接受它作为正确答案。我的/etc/hosts确实与你的类似。我不明白为什么它应该返回重复的
addrinfo
s。第二项是IPv6地址
::1
。在我的代码中,我使用了
提示
专门选择IPv4地址。我添加了另一组输出,这表明当我从代码中删除
提示时没有重复的条目。ai_family=AF_INET
。仅当我在代码中选择仅包含提示的IPv4条目时,才会出现重复条目。@LoneLearner:尝试注释IPv6条目。它可能类似于,特定于发行版(或glibc版本?),因为在我的机器上没有这样的问题。@RomanKhimov如果
/etc/hosts
中以
:1
开头的行被注释掉,那么重复的条目确实会消失。@RomanKhimov您的评论似乎回答了这个问题。如果你能用Redhat Bugzilla的链接写下你自己的答案,我会接受它作为正确答案。