摘要

  • Known-Answer Suppression 允许 mDNS 查询方把已缓存记录放进查询报文的 Answer Section。若其中的剩余 TTL 不低于响应方所知正确值的一半,响应方必须保持沉默;一旦低于一半,就必须发出新答案,避免查询方的缓存逼近过期。
  • 这组“答案”不具权威性,其他查询方不得据此写入自己的缓存。它只表示某一台主机在某一时刻的信念。因此,链路安静并不能单独证明服务不存在、记录仍然正确,或所有参与者拥有相同状态。

打开打印机选择窗口时,列表可以持续更新,却不会因为每一次查询就让所有设备把全部记录重新广播一遍。用户看见的是安静而及时的结果,协议面对的却是一项更难的任务:如何让多个自治设备共用一条本地链路,又不把重复响应堆成流量洪峰。

Multicast DNS 在本地链路上通过 UDP 5353 执行类似 DNS 的查询和响应。.local. 名称只有链路本地含义,同一个字符串到了另一条链路,并不自动指向同一个对象。这里没有一台传统 DNS 服务器替所有参与者作决定,而是多台主机共同监听、共同回答。

RFC 6762 的两位作者是 Stuart Cheshire 与 Marc Krochmal,Cheshire 名列首位。这份标准最精巧的地方,不是给缓存更多权力,而是让缓存只在一个极窄的范围内影响流量:它可以请求别人暂时别重复,却不能代表服务发布者发言,也不能让邻居继承自己的判断。

持续发现不能停在第一条答案

一次性名称查询可以在得到首个结果后结束。服务浏览不同。用户可能一直开着窗口,希望后来加入的打印机出现、离开的设备消失。一次响应不能关闭整个操作。

若查询方不断轮询,多个客户端会周期性地同时唤起多个响应方。RFC 因而要求前两次持续查询至少相隔一秒,后续间隔至少翻倍;间隔达到一小时后,可以稳定为每小时一次。首次查询还应加入随机延迟,避免很多主机因同一事件同时起步。

Known-Answer Suppression 是这种持续查询必须实现的一部分。查询方再次发问,是因为它可能漏掉了某个实例,或想知道是否出现了新实例,不是因为它需要已经收到的记录再来一份。

本地应用是否仍然关心某项记录,也是边界。若缓存过期不会影响任何程序或用户,查询方不得继续为它做维护查询。公共链路资源服务于正在发生的需求,而不是无止境保存一切曾经见过的东西。

查询方把自己的记忆交给响应方比较

Known-Answer Suppression 主要用于 Shared 记录。同名、同类型、同类别下可以有多个合法响应方;已经知道其中几项,不等于已经知道全部。Unique 记录通常代表完整答案,缓存里已有它时,查询方一般没有理由继续期待另一份不同答案。

查询报文于是携带已知记录。响应方逐项比较:如果自己准备发送的记录已经出现,而且报文所示剩余 RR TTL 至少等于正确值的一半,就必须不发送。查询方离过期还远,重复数据不会改善它的状态。

低于一半时,责任反转。响应方必须回答,让仍有兴趣的缓存及时续期。查询方也不应把这种记录继续塞进已知答案列表,因为它已经无法压下响应,只会占用报文空间。

“一半”不是可信度。记录不会因为消耗了 51% 生命周期就只剩 49% 的真实性。这个门槛只回答一个动作问题:此刻更值得节省一次组播,还是更值得交付一张更新的时间收据。

因此,response_count=0 不是完整观测。真正可复核的记录应保存问题的名称、类型与类别,查询里携带的资源记录、原始和剩余 TTL,响应方掌握的正确 TTL,Shared/Unique 属性,以及最终为何沉默或刷新。

Answer Section 里的内容仍只是信念

RFC 明确规定,其他查询方不得缓存从别人的 Known-Answer Section 里看见的资源记录。虽然字段叫 Answer,它在查询报文里不具权威性。发送者表达的是“我相信它仍然有效”,不是“它必然为真”。

原因很现实:记录可能来自一台已经离网的主机。如果旁观者继续复制,它就会从单机的陈旧缓存变成多人共享的陈旧状态。节流机制反而制造错误传播。

所以,查询方拥有的是一次有边界的参与权。它可以告诉响应方:“针对我的这次问题,你暂时无需重复。”它不能替发布者确认身份,不能更新别人的缓存,也不能裁定名称归属。

沉默也继承同样的边界。响应方可能因为半 TTL 条件满足而不发包,也可能根本不在、没听见、被过滤或正在等待后续 TC 报文。没有周围状态,安静不是健康证明,更不是不存在证明。

已知答案太多时,时间让位给容量

当已知答案装不进一个报文,查询方先在带有问题的报文上设置 TC 位,再立即发送后续报文,把剩余记录补齐。

响应方看到 TC 后,会随机等待 400 至 500 毫秒。完整列表到达前,它不急着回答。后续报文若包含原计划发送的记录,响应方将它从待发集合中删除。

但还有一项重要例外:如果另一台主机也问了同一记录并正在等待,不能因为第一个查询方已经缓存就把答案压掉。一台设备的记忆只能影响自己的需求,不能消灭别人的需求。

持续到来的 TC 报文可以继续延长等待。RFC 承认,在理论上,一条连续报文流可能让响应无限延期。它选择在这种已经高度拥塞的场景里偏向谨慎:宁可让服务发现慢一些,也不在最缺容量时提前发出大量可能无用的答案。

这是一项公开的取舍,不是对所有延迟的免责。运营者仍要保存 TC 链、等待时长、其他查询方和最终发送决定,才能区分设计中的让步与真实故障。

过期机制让陈旧信念退出

每条资源记录都有 RR TTL。时间走完,记录就不再有效,应当从缓存删除。一次发现不能获得永久生命。

只要本地应用仍有兴趣,RFC 建议查询方在记录生命周期大约 80%、85%、90% 和 95% 时重新发问,并加入少量随机偏移。收到新答案后,TTL 重置;四次都没有回应,就在 100% 时删除记录。

这条退出路径与半 TTL 门槛共同工作。生命周期前半段偏向节流,后半段偏向刷新,终点则要求没有新证据的记录离场。查询方的信念可以暂时改变别人的发送行为,却不能无限期维持自身。

不再有本地客户关心时,维护本身也要停止。否则,协议会为了维护无用缓存而消耗它本来要保护的公共资源。

标准写下门槛,运行代码交付结果

Apple 的公开 mDNSResponder 仓库描述了一组仍在维护的 DNS Service Discovery 守护程序、工具与库。README 说明守护程序监听 5353 端口的组播流量,通过 mDNS 解析 .local.,在 macOS 上承担系统解析器角色,也可用于其他平台。

这证明存在可检查的公开实现面,却不能证明每个版本、设备、厂商分支或网络配置都正确执行半 TTL 比较。无线网络对组播的优化、VLAN 桥接、代理和接口选择,都可能改变谁听见同一条问题。

验证必须回到运行现场:已知列表是否准确,TTL 是否按同一记录比较,低于一半是否刷新,高于一半是否沉默,TC 等待是否有界,过期时是否真的删除,另一个仍在等待的主机是否获得答案。

Running-Code Primacy 在这里不是反标准口号。RFC 提供最小互操作规则;代码与链路决定规则有没有成为现实。一个漂亮的服务列表不能替代报文收据,一段规范原文也不能自动修好错误缓存。

对 Stuart Cheshire 的归因也必须守边界

RFC 6762 与 RFC 6763 都把 Stuart Cheshire 列在 Marc Krochmal 之前。这足以证明他深度参与了 Multicast DNS 与 DNS-Based Service Discovery 的 IETF 集体规范工作。

2026 年 8 月 30 日复核的 IETF Datatracker 资料列出 28 份 RFC,并将他列为 Congestion Control Working Group 的现任代表。这些角色会变化。它们不能证明个人独占发明、拥有 Bonjour、控制 Apple 产品实现,或应为任何运营者的本地组播域负责。

归因的纪律与协议的纪律相同:文档上的名字证明贡献,查询里的已知答案证明某台主机的缓存状态。把两者扩张成它们没有取得的权威,只会让原本可靠的证据失去价值。

来源