如何禁用AAAA查找?

…来弥补我们无法控制的破损的DNS服务器。

我们的问题:我们部署embedded式设备,收集各种传感器数据,主要是纯IPv4站点。 有些网站的networking维护能力较差,例如configuration不当或以其他方式破坏的DNScaching和/或防火墙,或者完全忽略AAAA查询,或者以破坏的应答(例如,错误的源IP)对其进行响应。 作为设施部门的外部供应商,我们几乎不会影响(有时是不情愿的)IT部门。 他们很快修复DNS服务器/防火墙的机会很小。

对我们的设备的影响是,对于每个gethostbyname(),进程必须等待,直到AAAA查询超时,此时一些进程已经完成超时连接尝试。

我正在寻找解决scheme,是…

  • 全系统。 我无法单独重新configuration几十个应用程序
  • 非永久的和可configuration的。 我们需要(重新)启用IPv6的地方/当它被固定/推出。 重新启动即可。
  • 如果一个解决scheme需要像glibc这样的核心库被replace,那么应该从一个已知维护良好的库(如Debian Testing,Ubuntu universe,EPEL)中提供replace库包。 自我build设不是一个可select的原因,我甚至不知道从哪里开始,所以我根本就没有列出它们。

最明显的解决scheme是configurationparsing器库,例如通过/ etc / { resolv , nsswitch , gai } .conf来不查询AAAAlogging。 像这里build议的resolv.conf选项no-inet6正是我正在寻找的。 不幸的是,它并没有实现,至less在我们的系统上(Debian 7上的libc6-2.13-38 + deb7u4; Ubuntu 14.04上的libc6-2.19-0ubuntu6.3)

那么怎么样? 人们发现在SF和其他地方提出了以下方法,但是它们不工作:

  • 禁用IPv6,例如将/etc/modprobe.d/中的ipv6 LKM或sysctl -w net.ipv6.conf.all.disable_ipv6=1列入黑名单。 ( 出于好奇:为什么parsing器要求禁用IPv6的AAAA?
  • 从/etc/resolv.conf中删除options inet6 。 这不是第一个, inet6现在只是默认启用。
  • 在/etc/resolv.conf中设置options single-request 。 这只能确保A和AAAA查询顺序而不是并行地完成
  • 改变/etc/gai.conf中的precedence 。 这不会影响DNS查询,只会处理多个答复。
  • 使用外部parsing器(或运行绕过破坏的DNS服务器的本地parsing器守护进程)将会有所帮助,但是通常被公司的防火墙策略所禁止。 它可以使内部资源无法访问。

另类丑陋的想法:

  • 在本地主机上运行DNScaching。 将其configuration为转发所有非AAAA查询,但使用NOERROR或NXDOMAIN(取决于相应的A查询的结果)响应AAAA查询。 我不知道DNScaching能够做到这一点,虽然。
  • 使用一些聪明的iptables u32匹配,或者Ondrej Caletka的iptables DNS模块来匹配AAAA查询,以便icmp拒绝它们(parsing器lib如何对此作出反应?),或者将它们redirect到本地DNS服务器,以响应所有的东西都用空的NOERROR。

请注意,SE上也有类似的相关问题。 我的问题在阐述我试图解决的实际问题方面有所不同,因为它列出了明确的要求,因为它列出了一些经常提出的非工作解决scheme,并且因为它不是特定于单个应用程序。 在这个讨论之后 ,我发布了我的问题。

  • IPv6 DNS查找
  • 当我没有IPv6地址时如何禁用请求的AAAAlogging?
  • 禁用libcurl中的AAAA查找

停止使用gethostbyname() 。 您应该使用getaddrinfo() ,而应该已经有多年了。 手册页甚至提醒你这一点。

gethostbyname *(),gethostbyaddr *(),herror()和hstrerror()函数已经过时。 应用程序应该使用getaddrinfo(3),getnameinfo(3)和gai_strerror(3)。

下面是C语言中的一个快速示例程序,它演示了查找Alogging的名称和Wireshark捕获,显示只有 Alogging查找通过networking。

尤其是,如果只需要Alogging查找,则需要将ai_family设置为AF_INET 。 本示例程序仅打印返回的IP地址。 有关如何进行传出连接的更完整示例,请参阅getaddrinfo()手册页。

在Wireshark捕获中 ,172.25.50.3是本地DNSparsing器; 捕获在那里,所以你也看到它的外向查询和答复。 请注意只有一个Alogging被请求。 没有做过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); } 

如有疑问,请转到源代码! 所以,让我们看看… gethostbyname()看起来很有趣。 这个描述了我们所看到的:先尝试IPv6,然后回到IPv4,如果你没有得到你喜欢的答案的话。 这是什么RES_USE_INET6标志? 追溯它,它来自res_setoptions() 。 这是读取resolv.conf地方。

而….这是我的想法。 如果不是在resolv.conf ,我完全不清楚RES_USE_INET6是如何设置的。

您可以使用BIND作为本地parsing器,它有一个选项来过滤AAAA:

https://kb.isc.org/article/AA-00576/0/Filter-AAAA-option-in-BIND-9-.html

您是否尝试设置PDNS-recursor,将其设置在/etc/resolv.conf中,并拒绝“AAAA”查找? 使用诸如query-local-address6=