如何禁用 AAAA 查找?

Nil*_*ann 39 domain-name-system linux ipv6 glibc

... 以补偿我们无法控制的损坏的 DNS 服务器。

我们的问题:我们部署了嵌入式设备,这些设备在各个站点(主要是仅支持 IPv4 的站点)收集传感器数据。一些站点的网络维护不善,例如错误配置或以其他方式损坏的 DNS 缓存和/或防火墙,它们要么完全忽略 AAAA 查询,要么以损坏的回复(例如错误的源 IP!)响应它们。作为设施部门的外部供应商,我们对(有时是不情愿的)IT 部门几乎没有影响。他们很快修复 DNS 服务器/防火墙的机会微乎其微。

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

我正在寻找解决方案...

  • 全系统。我无法单独重新配置数十个应用程序
  • 非永久性和可配置的。我们需要(重新)启用 IPv6,当它被修复/推出时。重启就OK了。
  • 如果解决方案需要替换像 glibc 这样的核心库,则替换库包应该可以从众所周知的维护良好的存储库(例如 Debian Testing、Ubuntu Universe、EPEL)中获得。自建不是一种选择,原因有很多,我什至不知道从哪里开始,所以我根本没有列出它们......

最明显的解决方案是配置解析器库,例如通过 /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 和其他地方建议使用以下方法,但它们都不起作用:

  • 完全禁用 IPv6,例如通过将 /etc/modprobe.d/ 中的 ipv6 LKM 列入黑名单,或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 查询,只会影响多个回复的处理方式。
  • 使用外部解析器(或运行绕过损坏的 DNS 服务器的本地解析器守护进程)会有所帮助,但通常被公司的防火墙策略所禁止。它可以使内部资源无法访问。

替代丑陋的想法:

  • 在本地主机上运行 DNS 缓存。将其配置为转发所有非 AAAA 查询,但使用 NOERROR 或 NXDOMAIN 响应 AAAA 查询(取决于相应 A 查询的结果)。我不知道 DNS 缓存能够做到这一点。
  • 使用一些巧妙的 iptables u32 匹配,或 Ondrej Caletka 的iptables DNS 模块来匹配 AAAA 查询,以便 icmp 拒绝它们(解析器库将如何对此做出反应?),或者将它们重定向到响应的本地 DNS 服务器一切都带有空的 NOERROR。

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

Mic*_*ton 12

停止使用gethostbyname()。你应该使用它getaddrinfo(),而且应该已经使用了很多年了。手册页甚至会警告您这一点。

gethostbyname*()、gethostbyaddr*()、herror() 和 hstrerror() 函数已过时。应用程序应改用 getaddrinfo(3)、getnameinfo(3) 和 gai_strerror(3)。

这是一个 C 语言的快速示例程序,它演示了查找名称的 A 记录,以及显示A 记录查找通过网络进行的 Wireshark 捕获。

特别是,如果您只想完成 A 记录查找ai_familyAF_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)

  • 有趣的!我将调查哪些应用程序触发 AAAA 请求。如果这只是我们的,那么我会将您的建议转达给我们的开发人员。但我有一种强烈的预感,很多 Debian/Ubuntu 打包的软件都受到这个问题的困扰,而我们不会修补它们。 (2认同)
  • 当调用 gethostbyname 位于您无法控制的代码中时,这没有帮助。 (2认同)
  • @MichaelHampton:“curl”和“wget”显然都受到了这个问题的影响。如果这些都不能可靠地工作,那么祝你好运,让一个中等复杂的 Linux 系统也能工作。 (2认同)

BMD*_*Dan 5

如有疑问,请查看源代码!那么,让我们看看... gethostbyname()看起来很有趣;这准确地描述了我们所看到的情况:首先尝试 IPv6,如果没有得到您想要的答案,则返回到 IPv4。这面旗帜是什么RES_USE_INET6?追溯到它,它来自res_setoptions()。这是resolv.conf读入的地方。

而且...那是我的想法。我完全不清楚RES_USE_INET6如果不在 中,它是如何设置的resolv.conf

  • 最后:对于它的价值,我会通过在本地主机上运行 DNS 缓存来解决这个问题(正如您在上面提到的)。维护自己的、被黑客攻击的 DNS 代理/缓存比维护核心系统库的被黑客攻击的版本要容易得多。 (2认同)

Glu*_*eon 0

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

  • `query-local-address6=` 做了一些不同的事情(从哪个 IPv6 地址发送查询 - 请注意,即使禁用 IPv6,AAAA 请求仍将通过 IPv4 解析)。另外,我无法识别任何其他可以过滤 AAAA 查询的设置(http://doc.powerdns.com/html/built-in-recursor.html)。如果没有这些信息,您的回答就没有多大帮助:( (2认同)