V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
SukkaW
V2EX  ›  DNS

也来谈谈关于 CNAME 和 MX 冲突的一些事

  •  
  •   SukkaW · 2018-09-08 22:07:26 +08:00 · 5369 次点击
    这是一个创建于 2274 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文不是什么解决 CNAME 和 MX 冲突的教程贴。

    本文转载自我的博客: https://blog.suka.moe/post/about-cname-and-mx-conflicts/


    这本来是一个颇老生常谈、甚至是一个本应该盖棺定论的问题了。虽然 RFC 1034 早就给出了规范,但是 CNAME 和 MX 不能同时添加的问题之前 在 V2EX 再次出现,所以我打算也来谈一谈这个问题。

    缘由

    CDN 服务商的众多节点大多都是使用 GSLB 进行调控的,大部分 CDN 服务的 GSLB 又都是通过 CDN 服务商的权威 DNS 设施上部署的 GeoDNS 实现的(少数如 Cloudflare、Fastly、Stackpath、MaxCDN、Google Global Load Balancer 等 CDN 服务商使用了 Anycast、通过调整 BGP Route 实现 GSLB )。所以用户的网站如果需要接入 CDN 一般有两种方法,将用户的域名接入到 CDN 服务商的权威 DNS ( 360 网站卫士和百度云加速的 NS 接入),或者用户通过添加 CNAME 记录从而实现 CDN 服务商的权威 DNS 接管 GeoDNS。

    对于一些需要在根域(@)接入 CDN、同时需要添加域名邮箱所需的 MX 记录时,就会导致冲突问题。

    剖析问题

    毫无疑问,只要了解一些 DNS 的基础知识的都知道,CNAME 的意思是当前域名的解析结果应该全部、毫无保留的采用返回的 CNAME 域名的解析结果;递归 DNS 会直接向下追踪 CNAME 域名的解析记录、会直接无视其它解析结果。而且,因为 RFC 规范,权威 DNS 和递归 DNS 都不会允许 CNAME 和其它类型的解析结果同时、一起返回。

    常见的解决方案

    使用 CNAME,无非是因为 SLB、GSLB 由其它服务商提供,而且服务商在使用自己的权威 DNS 设施实现 SLB 和 GSLB。解决的方法也很简单,不使用 CNAME 而直接使用 A/AAAA 就可以和 MX 共存了。

    所以,最完美的解决方案,应该就是用户直接使用 NS 接入 CDN 服务商、直接使用 CDN 服务商的权威 DNS (如本文一开始就提到的 360 网站卫士、百度云加速,以及 Fatstly 和 Akamai 的定制版业务),不仅 GeoDNS 和使用 CNAME 一样精准,而且 CDN 服务商的权威 DNS 可以直接给 @ 返回 A/AAAA 记录,和 MX 记录并不冲突。

    另一个相对最完美的解决方案是在 CNAME 域名中返回 MX 记录。Cloudflare 的 CNAME Setup 就是采用这种解决方案。以使用 CNAME Setup 的 globalsign.com 为例,globalsign.com 对应的 CNAME 是 globalsign.com.cdn.cloudflare.net ,你们可以在终端里 dig 一下这个 CNAME 域名:

    $ dig globalsign.com.cdn.cloudflare.net
    
    ;; ANSWER SECTION:
    globalsign.com.cdn.cloudflare.net. 300 IN A     198.41.214.154
    globalsign.com.cdn.cloudflare.net. 300 IN A     198.41.215.154
    
    $ dig globalsign.com.cdn.cloudflare.net MX
    
    ;; ANSWER SECTION:
    globalsign.com.cdn.cloudflare.net. 300 IN MX    10 globalsign-com.mail.protection.outlook.com.
    

    这样如果 globalsign.com 的根域名添加了 globalsign.com.cdn.cloudflare.net 的 CNAME 记录,就不会导致找不到 MX 记录而丢失信件。

    然而,globalsign.com 是直接在 @ 添加了两条 A 记录( Cloudflare Anycast IP ),并不是直接添加 CNAME 而且,大部分 CDN 服务商内部的 GSLB 系统会导致多个 CNAME 递归,七牛这种卖二手 CDN 更会导致 CNAME 之间的递归。所以这种方案并不现实。

    还有相对不完美的解决方案。部分权威 DNS 服务商提供这样一种服务:由权威 DNS 的节点解析 CNAME 的 A/AAAA 的结果,然后权威 DNS 直接返回 A/AAAA 记录。这样的服务通常会被命名为 ALIAS ANAME Flatten CNAME 等。使用这类服务将 CNAME 变成 A/AAAA 的方案的确可以解决冲突的问题,但是 Flatten CNAME 又要保留 GeoDNS,就会高度依赖于权威 DNS 服务商的节点分布,所以最终得到的 GeoDNS 结果一定会~~非常~~不精确。

    DNSPod 的共存和 CloudXNS 的 LINK 记录

    接下来就是本文的重点了。之前 DNSPod 支持同时添加 CNAME 和 MX 记录(虽然添加时面板会提示可能导致问题)、CloudXNS 的面板不允许 CNAME 记录和 MX 记录共存,但是 CloudXNS 官方在他们的用户社区中发过使用 LINK 记录绕过这个限制的方法。

    前面说过,规范已经规定了 CNAME 和 MX 记录不能同时返回,那么 DNSPod 是怎么做的? DNSPod 自称他们是自研的架构而不是使用 BIND 这类成熟的程序。这并不是重点,重点在于 DNSPod 可以根据向他们的权威 DNS 节点的请求的不同 Type 返回不同的结果,说人话就是你向 DNSPod 请求 MX 记录他们就会返回 MX 记录,你向 DNSPod 请求 A/AAAA 这些就返回 CNAME。 但是,用户并不会直接请求 DNSPod 的权威 DNS 的——用户都是请求的递归 DNS,你不能保证所有用户都使用你 DNSPod 提供的公共 DNS 嘛。一旦递归 DNS 缓存了 CNAME 记录,就会沿着 CNAME 域名继续向下请求解析,就会导致邮件丢件。

    CloudXNS 的 LINK 也不是 Flatten CNAME 这类服务,而是一个便捷的管理多个 CNAME、减少 CNAME 递归次数的一个工具;如果你为 CDN CNAME 域名添加的 LINK 记录,最终依然会返回 CNAME 记录。使用 LINK 绕过 CNAME 和 MX 不能共存的限制,和 DNSPod 的允许在控制台中同时为 @ 添加 CNAME 和 MX 本质上并没有什么区别。 如果权威 DNS 支持 CNAME 和 MX 共存,那么为了防止邮件丢件,就应该尽可能少的让 CNAME 被缓存,这样 MX 依然有机会会被返回,也就是把 TTL 调整地尽可能短。但是,权威 DNS 服务商为了降低自己的服务的负载,会限制最短 TTL ;即使你成功缩短了权威 DNS 返回的 TTL,递归 DNS 也会为了降低自己的服务负载而篡改 TTL。所以这并不是一个可行的解决方案。

    最近 DNSPod 也开始禁止 CNAME 和 MX 共存 了,已经共存的会把 MX 暂停掉,看来 DNSPod 应该放弃他们的自研架构了。

    9 条回复    2018-09-10 10:54:56 +08:00
    HXM
        1
    HXM  
       2018-09-08 23:04:41 +08:00 via Android
    感谢科普
    CNAME 和 TXT 不能共存也是类似原因吧?
    博客现在扔在 Coding Page 上,但它不像 GitHub 可以通过 A 记录解析,必须用 CNAME,这就很难过了。。
    shansing
        2
    shansing  
       2018-09-08 23:28:35 +08:00
    前不久还遇到过京东云解析的不规范实现,在设置了 CNAME 的情况下,请求 TXT 并不会返回 CNAME,导致 acme.sh 的 alias-mode 使用失败。
    SukkaW
        3
    SukkaW  
    OP
       2018-09-08 23:34:49 +08:00   ❤️ 2
    @HXM #1 是的。不过 Coding Pages 就一堆 Zenlayer HK、没有 GeoDNS,配个 Flatten CNAME 就行了
    @shansing #2 一般“自研架构”都会有这种问题,比如之前 DNSPod 请求 CAA 时,不存在相关记录时不返回 SOA,导致很多 SSL 签发失败的问题
    Binarization
        4
    Binarization  
       2018-09-09 00:50:25 +08:00 via Android
    这样一想,将来 IPv6 很多,运营商都建 anycast 网络,CDN 都在 IP 后面,cname 就不要用了
    mason961125
        5
    mason961125  
       2018-09-09 02:31:13 +08:00 via iPhone
    我记得 Cloudflare 默认把 @的 CNAME 记录做了 flatten
    isCyan
        6
    isCyan  
       2018-09-09 11:55:44 +08:00 via Android
    很详细
    realpg
        7
    realpg  
       2018-09-09 15:01:18 +08:00
    想玩 CNAME 就抛弃空头 空头直接 301/302 redirect 到 www 就好了
    要么就换个域名做邮箱
    zhxhwyzh14
        8
    zhxhwyzh14  
       2018-09-09 17:39:18 +08:00 via Android
    这是因为标准中 CNAME 记录太过于霸道了吗😂,
    johnjiang85
        9
    johnjiang85  
       2018-09-10 10:54:56 +08:00
    DNSPod 前端禁止同时添加共存并不是改架构了,而是为了减少客户出现问题和减少对一线的反馈。其实 DNSPod 后台也是支持类似的 LINK 记录的,是 CNAME 加速的额外附加功能,当 CNAME 和 MX 共存时会尝试直接返回 A 记录,而不是返回 CNAME 记录,但是限制条件太多,并不实用,具体可以看这里: https://support.dnspod.cn/Kb/showarticle/tsid/246
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2737 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:37 · PVG 20:37 · LAX 04:37 · JFK 07:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.