这是我的密码。
#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;
}
这是输出。
$ 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)
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)
输出结果表明,第一项和第三项完全相同。同样,第二项和第四项完全相同。为什么我们要在结果中得到这些副本呢?
如果我们从代码中注释或删除下面一行,那么重复的条目就会消失。
/* 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: 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
开头的行被注释掉,那么重复条目实际上就消失了。
$ 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
中的/etc/hosts
条目会导致重复条目,即使只使用hints.ai_family = AF_INET
来选择IPv4条目。
发布于 2016-09-16 19:34:10
这是一个由来已久的bug/功能的glibc。当您在您的IPv6文件中有一个hosts
本地主机条目时,如
::1 localhost
它自动用于AF_INET
名称解析。2006年11月,Ulrich Drepper提出了这一行为,并发表了以下评论:
nss/nss_files/files-hosts.c (LINE_PARSER):如果可以映射IPv4查询,支持IPv6 6风格的地址。
有些人认为这是错误,虽然至少有两个bug报告对这个主题进行了长时间的讨论(第一个和第二个),但没有人真正解释为什么会做出这种更改,所以我想唯一能够做到这一点的人就是Ulrich本人。但是它可能在某些场景中很有用,因为尽管Ulrich自2012年5月起就不再使用glibc,但这段代码仍然存在于glibc的每个现代版本中。
如果您不喜欢这种行为,可以对hosts
文件进行调优,使其不具有localhost
名称作为IPv6回送地址,使用其他名称,例如:
::1 localhost6
或者使用一些发行版,当人们认为它是一个bug时,实际上正在维护glibc包,比如openSUSE (可能还有SLES/SLED),也就是纠正这种行为。
发布于 2016-09-14 06:24:16
检查静态表查找文件中的主机名(/etc/host)。
当有两行具有相同的canonical_hostname 'localhost‘时,getaddrinfo将返回重复的addrinfo。
您的/etc/主机可能如下所示:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost
https://stackoverflow.com/questions/39482704
复制相似问题