有些小伙伴们会经常遇到一个问题,在当前主机记录已经存在 CNAME 类型的记录后再在当前主机记录下添加其他记录类型时会提示某某类型记录和 CNAME 记录可能存在冲突,甚至有些解析服务商会直接不允许添加,比较常见的就是将主域名解析至 CDN 服务商提供的 CNAME 记录,然后再添加 MX(邮箱服务记录)时会碰到这个问题,这是为什么,该如何解决呢?接下来就让我们一起来了解一下吧。

为什么会出现这个问题?

在 DNS 标准文件 RFC 1034 中,对 CNAME 记录的定义如下:

RFC 1034

Identifies the canonical name of an alias.

译文:标识别名的规范名称。

翻译起来很拗口,但简单的来说 CNAME 记录就是把一个域名托管给另一个域名,该域名的所有解析记录都会被托管给另外一个域名,包括 MX、TXT、AAAA、A 等。我们以ddnsip.cn这个域名为例,它的解析记录如下:

ddnsip.cn 的解析记录

在图中我们可以看到,ddnsip.cn这个域名通过 CNAME 记录指向了ddnsip.cn.eo.dnse3.com.,这也就意味着ddnsip.cn这个域名的所有解析记录都会被托管给ddnsip.cn.eo.dnse3.com.,无论我向权威服务器查询任何记录类型,都会返回ddnsip.cn.eo.dnse3.com.所对应的的解析结果,比如说我查询ddnsip.cn的 MX 记录:

MX 记录

可以看到,权威并没有返回ddnsip.cn的 MX 记录,而是返回了ddnsip.cn.eo.dnse3.com.这条 CNAME 记录,这也就是为什么在当前主机记录下添加其他记录时会提示某某类型记录和 CNAME 记录可能存在冲突的原因了,因为所有记录已经被托管给了ddnsip.cn.eo.dnse3.com.,所以无论你添加任何记录都不会生效。

下图是递归 DNS 的查询结果,在递归 DNS 解析过程中,也是如此,当我们查询ddnsip.cn的 MX 记录时,递归 DNS 服务器会先查询ddnsip.cn的 mx 记录,但由于你设置了 CNAME 记录,权威服务器会返回ddnsip.cn的 CNAME 记录ddnsip.cn.eo.dnse3.com.,这时递归 DNS 服务器会去查询ddnsip.cn.eo.dnse3.com.的 MX 记录,最后返回ddnsip.cn.eo.dnse3.com.的 MX 记录,也恰恰说明了这一点

递归 DNS 查询结果

如何解决这个问题?

目前解决这个问题方法除了把 CNAME 记录删除换成具体的 A/AAAA 记录外,还有一种方式就是使用 CNAME 展平,CNAME 展平的方式大概有以下几种,下面我们就一一来了解一下:

ALIAS 或 ANAME 记录

ALIAS 或 ANAME 记录是一种特殊的 CNAME 记录,它可以将 CNAME 转换为 A/AAAA 记录,并在递归查询时直接返回 IPv4/IPv6 地址,而不是返回 CNAME 记录,这样既可以解决冲突问题,又可以提高解析性能,流程如下图所示:

ALIAS 记录

详细示意如下:

ALIAS 记录

看起来虽然很完美,也解决了冲突的问题,但目前这种记录类型并没有被标准化,只有少数几家 DNS 服务商支持,比如 CloudFlare、NS1 等,国内支持厂商数量较少,此外由于 ALIAS 记录需要权威通过递归查询来获取最终的解析结果,由于是在权威服务器所在的网络环境中进行递归查询,所以会导致分区解析等失效,所以并不适用于 CDN 加速的场景。

选择性 CNAME 应答

这种方案通过对权威服务器的应答逻辑修改而实现的,其大致原理就是允许你同时添加 CNAME 记录和其他记录类型,但在解析其他记录类型时会优先返回其他记录类型的记录,而不是 CNAME 记录,只有当其他记录类型不存在时才会返回 CNAME,这样就可以解决冲突问题,比如下图:

选择性 CNAME 应答

从图中我们可以看到,CNAME 记录和 MX 类型记录同时存在,但在解析 MX 记录时,权威服务器会优先返回 MX 记录,而不是 CNAME 记录,这样就避免了递归服务器获取到 CNAME 记录后再去查询 CNAME 记录的 MX 记录,从而解决了冲突问题,而且也能支持分区域解析,但这种方案很容易受到 LocalDNS 的影响导致不稳定,而且也无法彻底的展平 CNAME,只能解决记录冲突的问题,目前国内支持的厂商比较少,常见的有阿里云。

记录映射

这种方案是在权威服务器中直接将 CNAME 记录映射为 A/AAAA 记录,无需通过递归查询来获取最终的解析结果,如下图:

记录映射

从图中我们可以看到,ddnsip.cn这个域名通过 CNAME 记录指向了cname.dnspod.cn.,当我们查询ddnsip.cn的 IP 地址时,由于我们已经进行了记录映射,所以权威服务器会直接返回cname.dnspod.cn.所对应的 IP 地址,而非 CNAME 记录。简单来说你虽然添加的是 CNAME 记录,但是映射后系统把cname.dnspod.cn所设置的A/AAAA记录放到了ddnsip.cn的解析记录中,并且相关的线路、TTL、状态、记录值等都与cname.dnspod.cn相同步,所以实际上相当于你添加的是 A/AAAA 记录,这样既可以解决冲突的问题,也可以支持分区解析,但前提需要你的域名和你 CNAME 指向的域名在同一个 DNS 服务商,否则无法实现,目前支持的厂商比较少,常见的有 AWS Route53、DNSPod 等。

总结

从上面的介绍我们可以看到,目前解决 CNAME 冲突的方案有很多,但是每种方案都有自己的优缺点,可以说没有任何一种方案是完美的,在实际的业务场景中,我们可以根据自己的需求来选择合适的方案,当然还是由衷的建议大家,还是尽量不要在根域使用 CNAME 记录,毕竟目前来看绝大多数的冲突问题都发生在根域,而且在根域使用 CNAME 也不符合相关的标准。
长久来看,CNAME 展平不是解决 CNAME 冲突的最佳方案,在不久的将来,随着 HTTPS/SVCB 记录类型的普及发展,这个问题也将会最终得到解决。

DNSPod CNAME 展平设置方法

DNSPod 已于近期支持了 CNAME 展平功能,该功能无需你手动开启,只需要你同时添加 CNAME 记录和其他记录类型记录即可,系统会自动尝试进行 CNAME 展平,如下图:

CNAME 展平

效果如下:

CNAME 展平

直接返回了对应的 A/AAAA 记录。

由于自身水平有限,文章中难免存在错误,欢迎大家批评指正,谢谢!

参考资料