如何禁用AAAA查找?


35

...来弥补无法控制的DNS服务器损坏。

我们的问题:我们部署了嵌入式设备,这些设备在各种(主要是纯IPv4的)站点上收集传感器数据。一些站点的网络维护不佳,例如配置错误或其他原因破坏了DNS缓存和/或防火墙,它们要么完全忽略AAAA查询,要么以破碎的响应(例如错误的源IP!)对它们进行响应。作为设施部门的外部供应商,我们几乎对(有时是勉强的)IT部门毫无影响。他们在不久的将来修复DNS服务器/防火墙的机会微乎其微。

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

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

  • 系统范围内。我无法单独重新配置数十个应用程序
  • 非永久性和可配置的。我们需要在修复/推出IPv6的地方/时间(重新)启用它。重新启动就可以了。
  • 如果解决方案需要替换glibc之类的核心库,则应该从一个维护良好的已知存储库(例如Debian Testing,Ubuntu Universe,EPEL)中获得替换库包。出于多种原因,甚至我都不知道从何开始,所以无法进行自我构建,因此我根本不列出它们。

最明显的解决方案是配置解析器库,例如通过/ etc / { resolvnsswitchgai } .conf而不查询AAAA记录。中resolv.conf选项no-inet6建议作为这里正是我所期待的。不幸的是,它没有实现,至少在我们的系统上没有实现(在Debian 7上为libc6-2.13-38 + deb7u4;在Ubuntu 14.04上为libc6-2.19-0ubuntu6.3)

那怎么办 人们发现了以下在SF和其他地方建议的方法,但它们都不起作用:

  • 完全禁用IPv6,例如通过将ipv6 LKM列入/etc/modprobe.d/或中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也有类似的相关问题。我的问题有所不同,因为它阐述了我要解决的实际问题,因为它列出了明确的要求,因为它将一些经常被建议的非工作解决方案列入了黑名单,并且它不是特定于单个应用程序的。在讨论之后,我发表了我的问题。


13
PS:与SF上的流行观点相反,即使在DNS有效的情况下,也有一些充分的理由在仅IPv4网络中的计算机上禁用IPv6 / AAAA。将DNS解析器的负载减少近50%;减少连接启动时间(特别是在DNS缓存比较滞后的情况下);遵循最佳实践来禁用非功能性功能,以增强安全性和稳定性。诚然,如果我忘记了IPv6可用后就重新启用它,那么我的系统将成为阻碍IPv6推出的IPv4传统镇流器。应该允许一个人权衡此弊。
尼尔斯·托德曼2014年

您为什么不在本地主机上运行完整的解析器的任何原因?这样,您就完全消除了对其他人(看似)不可靠的DNS解析器的依赖。
桑德·斯特凡2014年

@SanderSteffann公司的防火墙策略通常不允许这样做。但是在其他地方这是一个选择。稍后再将其添加到我的问题中。
尼尔斯·托德曼2014年

3
@joeqwerty我们对站点是否支持IPv6不做任何假设。尽管DNS服务器符合标准,但我们确实做出了假设。另外,不幸的,某些IT部门确实缺乏正确配置其基础架构的技能。对不起,对此感到抱歉。
尼尔斯·托德曼2014年

4
我明白你在说什么。您需要使他们的网络在他们的网络上正常工作,而这恰恰是您在这里要问的问题。当我们在IT领域责怪我们的客户并且不尊重他们时,我感到有些沮丧。它们是我们的面包和黄油。无论好坏,我们都必须尊重并尊重他们。客户不是我们业务的障碍,而是我们业务的原因。
joeqwerty 2014年

Answers:


9

停止使用gethostbyname()。您应该getaddrinfo()改为使用它,并且应该已经使用了多年。手册页甚至警告您。

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

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

特别是,如果只希望完成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);
}

有趣!我将调查哪些应用程序触发了AAAA请求。如果只是我们的,那么我会将您的建议转发给我们的开发人员。但是我很有预感,很多Debian / Ubuntu打包软件都在遭受这个困扰,我们不会修补那些。
尼尔斯·托德曼

您的应用程序可能是最重要的应用程序。即使您无法解决所有其他问题,也可能会改善这种情况。
迈克尔·汉普顿

4

如有疑问,请转到源代码!因此,让我们看看... gethostbyname()看起来很有趣;准确地描述了我们所看到的:首先尝试使用IPv6,然后在没有得到满意答案的情况下使用IPv4。这是什么RES_USE_INET6标志?追溯到此,它来自res_setoptions()。这是resolv.conf读入的位置。

还有..那是我的主意。我完全不清楚RES_USE_INET6如果没有设置它是如何设置的resolv.conf


可以通过options inet6in 设置RES_USE_INET6 resolv.conf。我想我的问题是,一旦在编译时设置就无法取消设置,这几天所有主要发行版似乎都在这样做(对吗?)。因此options no_inet6,我上面提到的功能要求。
Nils Toedtmann 2014年

1
不幸的是,正如您从代码中看到的那样,中似乎没有no_inet6选项res_setoptions()。但是,如您从(no-)所见ip6-dotint,添加起来很容易。为了测试您的发行版默认设置它的理论,我抓取了包源文件,并在“处女”之后对其进行了编译(以确认该包复制了行为),然后将:添加{ STRnLEN ("no-inet6"), 1, ~RES_USE_INET6 },options[]数组中,看看是否当您在中设置该选项时,问题就消失了resolv.conf
BMDan 2014年

1
最后:对于它的价值,我将通过在本地主机上运行DNS缓存来解决此问题(如您所引用的)。维护自己的被黑客入侵的DNS代理/缓存比维护核心系统库的被黑客入侵的版本要容易得多。
BMDan 2014年

3

您可以将BIND用作本地解析器,它可以过滤AAAA:

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


2
对于嵌入式设备而言,这是非常重要的。
迈克尔·汉普顿

谢谢,我不知道Bind的AAAA过滤器。正如Michael所提到的,由于Bind的足迹很大,因此这可能不是我们的解决方案。但是对于那些想要在其他情况下过滤掉AAAA响应的人,这可能是一种可行的方法。Ubuntu实际上至少在14.04上使用“ --enable-filter-aaaa”构建绑定。不确定Debian。-另请参阅ipamworldwide.blogspot.co.uk/2011/09/…–
尼尔斯·

1
我在14.04上,似乎此筛选选项不可用。
Zitrax

0

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


1
query-local-address6=做了一些不同的事情(从哪个IPv6地址发送查询-请注意,即使禁用了IPv6,AAAA请求仍将通过IPv4进行解析)。另外,我无法识别任何其他可以过滤AAAA查询的设置(doc.powerdns.com/html/built-in-recursor.html)。没有这些信息,您的答案将不是很有帮助:(
Nils Toedtmann 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.