【发布时间】:2018-01-04 17:49:33
【问题描述】:
在/etc/hosts 我有:
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
一个测试程序:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
const char* family_to_string(int family)
{
return family == AF_INET ? "AF_INET"
: family == AF_INET6 ? "AF_INET6"
: "<unknown>";
}
const char* socktype_to_string(int socktype)
{
return socktype == SOCK_STREAM ? "SOCK_STREAM"
: socktype == SOCK_DGRAM ? "SOCK_DGRAM"
: "<unknown>";
}
const char* protocol_to_string(int protocol)
{
return protocol == IPPROTO_TCP ? "IPPROTO_TCP"
: protocol == IPPROTO_UDP ? "IPPROTO_UDP"
: "<unknown>";
}
void print_addrinfo(struct addrinfo *ai)
{
int r;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
r = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (r)
{
fputs("getnameinfo\n", stderr);
exit(EXIT_FAILURE);
}
const char *family = family_to_string(ai->ai_family);
const char *socktype = socktype_to_string(ai->ai_socktype);
const char *protocol = protocol_to_string(ai->ai_protocol);
const char *family2 = family_to_string(ai->ai_addr->sa_family);
printf("flags=%i, family=%s, socktype=%s, protocol=%s, family=%s, host=%s, serv=%s\n",
ai->ai_flags, family, socktype, protocol, family2, hbuf, sbuf);
}
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
int r;
struct addrinfo hints;
struct addrinfo *result, *ai;
memset(&hints, 0, sizeof(struct addrinfo));
// hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
r = getaddrinfo("localhost", "8000", &hints, &result);
if (r)
{
fputs("getaddrinfo\n", stderr);
exit(EXIT_FAILURE);
}
ai = result;
while (ai)
{
print_addrinfo(ai);
ai = ai->ai_next;
}
exit(EXIT_SUCCESS);
}
当我不设置hints.ai_family时,如预期:
$ gcc -Wall -Wextra -Werror -pedantic -pedantic-errors -g -gdwarf-2 -g3 % && ./a.out
flags=0, family=AF_INET6, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET6, host=::1, serv=8000
flags=0, family=AF_INET, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET, host=127.0.0.1, serv=8000
使用hints.ai_family,它返回两个相同的addrinfo 结构:
flags=0, family=AF_INET, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET, host=127.0.0.1, serv=8000
flags=0, family=AF_INET, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET, host=127.0.0.1, serv=8000
你能解释一下发生了什么吗?我认为hints 充当过滤器。也就是说,这种情况下只返回一个结果。
UPD /etc/nsswitch.conf
# Begin /etc/nsswitch.conf
passwd: compat mymachines systemd
group: compat mymachines systemd
shadow: compat
publickey: files
hosts: files mymachines resolve [!UNAVAIL=return] dns myhostname
networks: files
protocols: files
services: files
ethers: files
rpc: files
netgroup: files
# End /etc/nsswitch.conf
/etc/resolv.conf:
# Generated by resolvconf
search Dlink
nameserver 192.168.0.1
192.168.0.1 是我的路由器。我的 IP 地址是192.168.0.39。
【问题讨论】:
-
我无法在此处重现此内容。您看到的是什么操作系统和解析器库?旁注:为了便于携带,这需要
#include <netinet/in.h>用于IPPROTO_*。 -
Arch Linux,
glibc-2.26. -
而
resolv.conf直接指向上游解析器,或者您是否运行存根解析器,例如systemd-resolved或类似的? -
systemd-resolved服务未启动/启用。在问题中添加了信息。不确定什么是存根解析器。因此,如果我有一个,它是由其他软件安装的。这不太可能。 -
存根解析器是本地 DNS 服务器,仅将 DNS 查询转发到其他服务器。 systemd-resolved 就是其中之一。您没有启用一个,您的系统正在直接查询您的路由器(如您的
resolv.conf所示)。鉴于查询,根本不应该涉及任何 DNS 流量,因为localhost可以从/etc/hosts解析。另外:我没有猜测。
标签: c getaddrinfo