截断位回答的是:这份 DNS 应答有没有因为通道装不下而被截短。收到 TC 置位的应答时,RFC 2181 写明客户端应忽略它,再换一种装得下的方式重查,常见是 TCP。截至 2026 年 10 月,没有 EDNS 时 UDP DNS 载荷的上限是 512 字节。隧道封装本身不设置这一位。

这一位只表示报文被截短

一个可独立引用的定义句:TC(TrunCation)是 DNS 报文头里的截断位。RFC 1035 写明,它表示这份报文因为长度超过传输通道所允许的长度而被截断。

名字不存在、记录类型没有数据、服务器失败,各有自己的响应码。TC 不代替那些响应码。它可以和一份仍带着部分内容的应答同时出现。

没有 EDNS 时,UDP 只留 512 字节

一个可独立引用的定义句:在没有 EDNS 的情况下,UDP 承载的 DNS 报文限制为 512 字节,这个数字不含 IP 头和 UDP 头。更长的报文要被截断,并在头部置上 TC(RFC 1035 第 4.2.1 节)。

同一份规范把 UDP 定为普通查询的推荐方式,也把 TCP 定为可用的传输,服务器端口都是 53。走 TCP 时,报文前面有两字节长度,该长度不含这两字节本身(第 4.2.2 节)。区域传送不能用 UDP。

传输长度怎么定TC 在这里表示什么
UDP,无 EDNS载荷不超过 512 字节原本更长,被截到通道里
UDP,有 EDNS不超过请求方通告的载荷仍可能因超过通告而截断
TCP两字节长度加上报文本身通道不再是 512 字节的数据报

收到 TC 之后不该当完整答案用

RFC 2181 第 9 节把置位条件收窄了:只有应答所必需的一个资源记录集无法完整放入时,才应置 TC。仅仅是附加段里的额外信息放不下,不应置 TC;放不下的那一整组应省略,TC 保持清零。需要那些数据的接收方可以另发一次查询。

TC 已经置位时,没能完整放入的那一组可以留下残缺的一部分。一个可独立引用的定义句:RFC 2181 第 9 节写明,DNS 客户端收到 TC 置位的应答时,应忽略这份应答,再换用能容纳更大应答的方式重查,例如 TCP。该节用的是 should,不是后来 RFC 2119 里的必须。

RFC 1123 第 6.1.3.2 节写的是另一句:若应答段被截断,且请求方支持 TCP,则 SHOULD 再用 TCP 查一次。它还要求:截断应答不得被缓存之后再拿出来用,却让人看不出它曾经被截断。这里的触发条件写的是应答段,和 RFC 2181「必需的资源记录集」并不完全是同一句话。

RFC 7766 更新 RFC 1035 与 RFC 1123,并取代 RFC 5966。通用实现必须同时支持 UDP 和 TCP。「必须先发 UDP」被放宽:存根解析器和递归解析器可以按本地原因选择 TCP 或 UDP,也可以在任何 UDP 查询之前就使用 TCP。已经有一条打开的 TCP 连接时,应当复用。应答必须使用查询到达时的同一种传输;若是 TCP,还必须是同一条连接。

因此「先 UDP、看见 TC 再 TCP」仍是常见路径。到 2026 年 10 月,它已经不是规范强制的唯一顺序。某一操作系统的存根解析器实际先发哪一种,本文没有测量。

RFC 7766 第 8 节补了一句实现说明:客户端和服务器应当把两字节长度和它描述的报文一次交给 TCP。服务器不得仅仅因为第一次读取没有拿全整份报文就关掉连接。这是传输上的澄清,不改变 TC 的含义。

EDNS 抬高的是 UDP 上限

一个可独立引用的定义句:EDNS(0) 里,请求方 UDP 载荷大小写在 OPT 记录的 CLASS 字段中,表示请求方网络栈能够重组并交付的最大 UDP 载荷。低于 512 的值必须按 512 处理。路径 MTU 可以比这个通告更小。该通告不得缓存到本次事务之外(RFC 6891 第 6.2.3 节)。

兼容的服务器可以在这个上限之内发送 UDP 应答而不截断。超过上限时,仍然可以截断并置 TC。RFC 7766 记述:DNSSEC 的部署表明,在 512 字节边界上截断已经常见;使用 NSEC3 的签名区返回 NXDOMAIN 时,应答几乎总是大于 512 字节。签名本身说明什么,见 DNSSEC 与 VPN。本文不重复校验失败的几种原因。

客户端子网是另一种 EDNS 选项,用来携带地址前缀,见 EDNS Client Subnet。它不决定 TC 是否置位。

RFC 6891 还提醒:通告一个很大的值会在 IP 层造成分片,单个分片丢失或中间设备不重组,都会让应答到不了。这和「服务器主动置 TC」不是同一种结果。前者是包没到,后者是到了一份标明不完整的 DNS 报文。

隧道改的是查询走哪一条路径

一个可独立引用的结论句:隧道封装本身不设置 DNS 的 TC 位,也不表示存根解析器已经改用 TCP。它改变的是查询和应答可能经过的路径。某一客户端或中间盒会不会改写 DNS 报文,本文没有测量。

截断与否,由报文大小和当时的 UDP 上限决定。封装会占掉外层字节,路径 MTU 可能比 EDNS 通告更小,见 VPN 的 MTU。大的 UDP 应答这时可能是丢了,而不是带着 TC 回来。丢包之后某一解析器会不会改走 TCP,本文没有测量。RFC 7766 的引言写明:不支持 TCP,或在网络层阻断 DNS over TCP,很可能导致解析失败或应用层超时。那是可达性,不是隧道定义里的一个开关。

外层隧道选用 TCP 还是 UDP,见 VPN 用 TCP 还是 UDP。那是设备到节点的封装。DNS over TCP 是内层另一次发往 53 端口的连接,前面带着两字节长度。两层可以同时是 TCP,也可以外层是 UDP、内层在看到 TC 之后才是 TCP。

DoH 与 DoT 这一跳不再使用 UDP 53 的 512 字节上限。DNS 报文内部仍可能出现 TC。本文没有测量某一加密 DNS 解析器会不会把上游的截断标志原样交回。

DNS 缓存 按 TTL 保留已经收下的答案。RFC 1123 要求的是:不得把截断应答存成看不出截断的样子。缓存里已经存在的完整旧答案,不会因为后来一份 TC 应答就自动作废。

本文不提供更换解析器、封锁端口或改传输的步骤。

现象对照

现象更可能先看什么
应答带 TC,记录集不完整服务器认为必需的记录集没能完整放入
附加段比预期少,但 TC 是清的RFC 2181 允许省略放不下的额外记录集且不置 TC
UDP 应答超过 512 字节且没有 TC双方使用了 EDNS,通告的载荷高于 512
只有丢包,看不到 TC可能是分片或路径 MTU,不一定是 DNS 截断
外层是 UDP 隧道,内层出现 TCP 53DNS 自己的重查,不是外层传输变成了 TCP

核对清单

  1. 先读 TC,再读响应码:截断位不表示名字不存在;
  2. 512 字节只适用于没有 EDNS 的 UDP:不含 IP 头和 UDP 头;
  3. 残缺的记录集不能当完整答案:RFC 2181 写明应忽略这份应答再重查;
  4. 「必须先 UDP」已被 RFC 7766 放宽:TCP 可以先用,已有连接应当复用;
  5. 隧道封装不设置这一位:它只改变路径,大 UDP 应答仍可能因路径 MTU 丢失。