Nil*_*ann 39 domain-name-system linux ipv6 glibc
... 以补偿我们无法控制的损坏的 DNS 服务器。
我们的问题:我们部署了嵌入式设备,这些设备在各个站点(主要是仅支持 IPv4 的站点)收集传感器数据。一些站点的网络维护不善,例如错误配置或以其他方式损坏的 DNS 缓存和/或防火墙,它们要么完全忽略 AAAA 查询,要么以损坏的回复(例如错误的源 IP!)响应它们。作为设施部门的外部供应商,我们对(有时是不情愿的)IT 部门几乎没有影响。他们很快修复 DNS 服务器/防火墙的机会微乎其微。
对我们设备的影响是,对于每个 gethostbyname(),进程必须等到 AAAA 查询超时,此时某些进程已经完全超时了它们的连接尝试。
我正在寻找解决方案...
最明显的解决方案是配置解析器库,例如通过 /etc/{ resolv , nsswitch , gai }.conf 不查询 AAAA 记录。中resolv.conf选项no-inet6
建议作为这里会正是我所期待的。不幸的是,它没有实现,至少在我们的系统上没有实现(Debian 7 上的 libc6-2.13-38+deb7u4;Ubuntu 14.04 上的 libc6-2.19-0ubuntu6.3)
那怎么办呢?有人发现在 SF 和其他地方建议使用以下方法,但它们都不起作用:
sysctl -w net.ipv6.conf.all.disable_ipv6=1
. (出于好奇:为什么解析器要求禁用 IPv6 的 AAAA?)options inet6
从 /etc/resolv.conf 中删除。它一开始并不存在,inet6
现在只是默认启用。options single-request
在 /etc/resolv.conf 中设置。这只能确保 A 和 AAAA 查询按顺序完成,而不是并行完成precedence
在 /etc/gai.conf 中更改。这不会影响 DNS 查询,只会影响多个回复的处理方式。替代丑陋的想法:
请注意,SE 上也有类似的相关问题。我的问题在详细说明我试图解决的实际问题方面有所不同,因为它列出了明确的要求,因为它将一些经常建议的非工作解决方案列入黑名单,并且因为它不是特定于单个应用程序。在此讨论之后,我发布了我的问题。
Mic*_*ton 12
停止使用gethostbyname()
。你应该使用它getaddrinfo()
,而且应该已经使用了很多年了。手册页甚至会警告您这一点。
gethostbyname*()、gethostbyaddr*()、herror() 和 hstrerror() 函数已过时。应用程序应改用 getaddrinfo(3)、getnameinfo(3) 和 gai_strerror(3)。
这是一个 C 语言的快速示例程序,它演示了仅查找名称的 A 记录,以及显示仅A 记录查找通过网络进行的 Wireshark 捕获。
特别是,如果您只想完成 A 记录查找ai_family
,AF_INET
则需要设置为。此示例程序仅打印返回的 IP 地址。有关getaddrinfo()
如何建立传出连接的更完整示例,请参阅手册页。
在Wireshark的抓包中,172.25.50.3是本地DNS解析器;捕获是在那里进行的,因此您还可以看到其传出的查询和响应。请注意,仅请求了 A 记录。从未进行过 AAAA 查找。
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <stdio.h>
int main(void) {
struct addrinfo hints;
struct addrinfo *result, *rp;
int s;
char host[256];
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
s = getaddrinfo("www.facebook.com", NULL, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
printf("%s\n", host);
}
freeaddrinfo(result);
}
Run Code Online (Sandbox Code Playgroud)
如有疑问,请查看源代码!那么,让我们看看... gethostbyname()看起来很有趣;这准确地描述了我们所看到的情况:首先尝试 IPv6,如果没有得到您想要的答案,则返回到 IPv4。这面旗帜是什么RES_USE_INET6
?追溯到它,它来自res_setoptions()。这是resolv.conf
读入的地方。
而且...那是我的想法。我完全不清楚RES_USE_INET6
如果不在 中,它是如何设置的resolv.conf
。
您是否尝试设置 PDNS-recursor,将其设置在 /etc/resolv.conf 中并拒绝其中的“AAAA”查找?使用类似的东西query-local-address6=