在一篇题为《CNAME记录和A记录,哪个先出现?`的文章中,Cloudflare解释了由于RFC规范不明确,导致其广受欢迎的1.1.1.1服务出现了故障。在发现了这一问题以及旧版DNS标准中关于记录顺序的模糊规定后,Cloudflare提出了一套更为明确的规范。

1月8日,对DNS服务进行的一次常规更新改变了CNAME记录在响应中的显示顺序,这使得一些DNS客户端在解析域名时出现了故障,因为这些客户端原本期望别名记录会排在首位。虽然大多数现代软件都认为DNS响应中记录的顺序并不重要,但Cloudflare团队发现,某些实现方式确实要求CNAME记录必须出现在所有其他类型的记录之前。

当这种顺序发生变化后,DNS解析功能开始出现故障,从而导致广受欢迎的1.1.1.1 DNS服务出现了大规模的服务中断。Cloudflare的系统工程师Sebastiaan Neuteboom解释了这一变化的原因及实施时间:

在为降低我们缓存实现的内存占用进行一些优化时,我们对CNAME记录的显示顺序做了一个细微的调整。这一变更于2025年12月2日首次被应用到测试环境中,2026年1月7日正式开始在生产环境中部署。

当DNS解析器使用CNAME记录来查询一个域名时,它会看到一系列将原始域名与最终地址关联起来的别名记录,而这些记录都会被缓存下来,每条记录都带有自己的过期时间。Cloudflare指出,如果这些记录链中的某些部分已经在缓存中过期了,解析器只会重新获取那些过期的部分,然后将其与仍然有效的部分结合起来,从而形成最终的响应结果。

Neuteboom进一步补充道:

之前,代码会创建一个新的列表,将现有的CNAME记录序列添加进去,然后再添加新的记录。但为了节省内存和减少复制操作,代码后来被修改为直接将CNAME记录添加到现有的响应列表中。因此,1.1.1.1服务返回的响应结果中,有时CNAME记录会出现在最后,位于最终解析得到的地址之后。

;; 查询部分:
;; www.example.com. IN A

;; 响应部分:
cdn.example.com. 300 IN A 198.51.100.1
www.example.com. 3600 IN CNAME cdn.example.com.

虽然许多DNS客户端的实现并不依赖记录的顺序,但有些实现方式确实会按照一定的顺序来处理这些记录。例如systemd-resolved库,以及glibc中的getaddrinfo函数,都会在解析过程中按照预期的顺序来处理这些记录序列,确保CNAME记录会出现在所有其他响应结果之前。在Reddit上,有一位用户发表了这样的评论:

一方面,我确实非常钦佩他们在事后分析中展现出的细致程度以及他们所达到的高水准的工程能力;但另一方面,我不禁认为他们并没有建立起适当的测试机制(也没有相应的文化氛围),因此无法真正了解他们的行为在全球范围内会产生什么样的影响。

一个备受关注的Hacker News讨论帖中,许多用户都在探讨:这个RFC文件本身是否存在表述不清的地方——尤其是在描述“RRsets”与“RRs”之间的区别时;还是Cloudflare的开发者们误解了其含义。Patrick May则给出了不同的看法:

这正是“海勒姆定律”的一个典型例子:“只要有一种API被足够多的用户使用,那么你在合同中承诺什么其实并不重要——因为你的系统的所有可观察行为最终都会被某些人用来作为判断依据。”而这一现象,恰恰与“波特尔定律”相违背:“在发送数据时应该保守一些,在接收数据时则应该开放一些。”

在一份即将提交给IETF讨论的互联网草案中,Cloudflare提出了一项RFC建议,明确规定了如何在DNS响应中正确处理CNAME记录。

根据公布的实施时间表,Cloudflare于1月7日开始在全球范围内推广这一变更,到1月8日17:40 UTC时,已有90%的服务器完成了相关配置调整。该公司在发现问题后立即采取了措施,于1月8日18:27 UTC开始恢复原有的设置,并在19:55 UTC之前完成了全部回滚工作。

Comments are closed.