我该如何配置 Linux 以允许通过 TCP 进行 DNS 传输?
我们今天发现,我们使用的几台不同的 Linux 服务器无法解析响应中含有许多 IP 地址的 DNS 名称。这些响应数据包将超过 512 字节,因此服务器会发回一个设置了截断位的 UDP 数据包。服务器上的各种进程(在本例中为 Java 和 nslookup 命令)此时会停止解析名称。它们不会通过 TCP 发出相同的请求,我听说它们应该这样做。
这部分特定于 alpinelinux:在 alpine linux 上,我可以通过安装 bind-utils 包来启用 TCP 上的 dns 查找。这使得系统上的其他程序通过切换到 TCP 开始正确处理截断的响应。我不知道该特定包正在做什么来配置它,所以我留下了这个问题:
附加问题,是否可以只为 Java 启用此功能而不改变其他任何内容?
我们不仅在 Alpine 上看到了这种情况,但我们偶然发现了一个对 Alpine 有这种影响的软件包。
答案1
您现在可能已经解决了这个问题,但我最近在使用 Alpine Linux 和一系列 Ruby 应用程序时也遇到了同样的情况。
这里的问题是 musl libc 没有实现 DNS over TCP(请原谅我在这里使用外行术语)。通过安装 bind-tools 之类的软件包,您将获得带有自己的/不同的 DNS 解析器的二进制文件,因此它们能够通过 TCP 进行 DNS 通信。
我们通过在 Ruby 应用程序中使用支持 TCP 的自定义解析器解决了这个问题(这是 musl libc 维护者 Rich Felker 所鼓励的)。事实上,它随 Ruby 的标准库一起提供,因此这并不是什么大的变化。
大多数环境都实现了自己的求解器,因此您应该能够找到一个适合您所使用的语言/环境的求解器。
以下是一些资源:
答案2
正如所述https://www.rfc-editor.org/rfc/rfc5966:
In the absence of EDNS0 (Extension Mechanisms for DNS 0) (see below), the standard
behaviour of any DNS server needing to send a UDP response that would exceed the
512-byte limit is for the server to truncate the answer so that it fits within that
limit and then set the TC flag in the response header. When the client receives such
a response, it takes the TC flag as an indication that it should retry over TCP
instead.
其他 RFChttps://www.ietf.org/rfc/rfc2181.txt还进行了一些澄清,包括使用 TC(截断)标头位:
Where TC is set, the partial RRSet that would not completely fit may be left in the
response. When a DNS client receives a reply with TC set, it should ignore that
response, and query again, using a mechanism, such as a TCP connection, that will
permit larger replies.
客户端事先不知道响应会太大,因此它将通过 UDP 查询服务器,但区域传输查询除外,这些查询始终使用 TCP。服务器将通过 UDP 响应,并尽可能多地包含信息并设置截断的标头位。然后,客户端必须通过 TCP 重新发送请求并获取完整响应。因此,您无需配置任何内容来强制客户端始终使用 TCP 发送 DNS 请求,因为它们只会在收到设置了 TC 位的答案时这样做。
您只需确保没有任何防火墙阻止端口 53 上的 TCP 流量。您还可以检查您是否被某些错误感染。