Reading view

There are new articles available, click to refresh the page.

谈一谈阿里云香港的宕机

2022 年 12 月 18 日,阿里云香港服务出现了异常。本站所用的香港服务器也中招,由于本人不正确的报警配置,导致部分域名没有正确切换解析,造成了一小部分用户最长半小时的不可用。然而,阿里云香港机房出现问题的时间远不止一个小时。根据我这里的监控,自北京时间 10:49 开始,我跑在香港阿里云上的 HTTP、HTTPS 服务就完全不可用了,直至 20:46 才恢复,共计宕机时间 10 小时。

事故回顾

本人是在早上起床后就发现阿里云香港服务器不可用。一开始以为是被神秘力量封锁了,但是看到报警邮件后发现,香港服务器在国外其他地区也不可用。

然后我就测了一下,发现主机能 ping,但无法 SSH 上去,HTTP/HTTPS 服务亦不可用。此外,yangxi.tech 网站服务也受到了影响。然后我登录了 AWS 中国区的 Route 53 去查看报警,结果发现 Route 53 上没有任何报警(我的 guozeyu.com 和 yangxi.tech 都在用中国区 Route 53)。查看最近的监控,发现我在 Route 53 上有一处配置错误,导致程序实际上没有在监控香港阿里云……于是修改了监测规则。此时我登录了 AWS 国际区,发现国际区的阿里云香港监控是在正常报警,发现是从 10:49 开始,全球所有监测点均不可用。

由于此时 AWS 中国区的报警已经被我改成正确的了,所以已经根据规则,在 DNS 层面进行自动宕机切换了;而且,我之前配置的 DNS TTL 也仅有 120 秒,所以我的所有网站应该在 11:20 前就已经完全恢复正常了。如果没有错误的报警规则,我的网站总共宕机时间也不会超过 5 分钟。

然后我登录了我自建的 Observium 监控,不出意外的看到了阿里云香港的机器已经宕机了。但我发现在宕机前,服务器的 CPU 是 100%。我就怀疑这是不是我自己服务器上某个程序卡死了,占用了所有资源,导致看起来 HTTP/HTTPS/SSH 服务都不可用了。

Observium 监控

此时已经 11:30 了,我还觉得这个是我自己的问题,毕竟我也没收到阿里云任何邮件、电话提醒。于是我登录了阿里云后台,尝试进行重启。此时我没有选择强制关机。结果,关机指令已经执行了 10 分钟,机器仍未关闭。平时我使用 GCP 时,如果关机指令执行超过两分钟,那么就会自动执行强制关机,所以此时执行了 10 分钟的关机就很离谱。然后我就尝试发工单,但没能进入到工单,被转到了在线客服。我向在线客服描述了问题后,无人回复。然后我又尝试发工单,结果工单也是无人回复。只是得到了机器人回复,说在关机时,Windows 会执行系统更新,有时需要 10-15 分钟。请在等待 20 分钟后联系客服。

大概又过了半个小时,机器终于成功关闭了,但在尝试多次后,机器无法启动。即便我点了启动,机器也会在一段时间后变成 “已停止” 状态。由于此时我还是以为是我自己的问题,不是阿里云的问题,我以为是刚刚强制关机导致系统损坏了,于是尝试给现有云盘打快照,尝试回滚。但离谱的事又发生了,我发现我根本无法打快照!快照的进度一直是 0%。

在 11:55,我终于收到了工单的回复:“您好!阿里云监控发现香港地域某机房设备异常,影响香港地域可用区C的云服务器ECS、云数据库polardb等云产品使用,阿里云工程师已在紧急处理中,非常抱歉给您的使用带来不便,若您有任何问题,请随时联系我们”。此时我才知道,这次的宕机可能不是我自己的问题,我放弃了自己尝试恢复服务。

该回复没有提供解决方案,也没有预计的恢复时间,可以说无非就是告诉了我 “这个是我们阿里云的问题”,对于恢复服务没有实质性帮助。

无力吐槽阿里云

本次事件最值得吐槽的地方是,我从未收到阿里云发来的有关通知。直至现在,我在邮箱、短信、站内信中没有收到任何阿里云关于此次服务宕机的提醒。我相信阿里云是有很多监控的,我坚信阿里云早在我发现我的服务出现问题之前,就已经知道了我的服务,以及其他人的服务器出现了问题了。但我却没有收到任何通知。唯一告知我阿里云存在问题的还是我发工单自己问出来的。

我觉得阿里云有必要向所有受影响的,以及可能受影响的客户发送相关提醒。在连续宕机了 8 小时,且仍未恢复的情况下,阿里云仍不主动通知客户,我实在是难以怀疑阿里云是否是故意不做通知,试图掩盖问题。

那还用阿里云吗?

会的。作为中国第一大,以及全球也能排的上前几的云服务商,我不怀疑阿里云的技术实力。我现在用阿里云主要是为了阿里云香港的 CN2 精品网,用于数据跨境(价格为 3元/GB)。目前在这方面也没有什么可替代的方案。专线也考虑过,太贵了,买不起。

但是,我不会把核心业务放在阿里云上了。放在 AWS 上我更安心一些。本次阿里云香港宕机只影响了我的网站一小会儿,也正是因为我没有把核心业务放在阿里云上。

本站是如何做到高可用的?

很简单,本站在四个地区,使用了四个不同服务商的服务器:

  • 德国 OVH
  • 北京 AWS
  • 香港 阿里云
  • 美国 Google Cloud

而且本站是纯静态网站。本站会在构建后,将构建产物分别同步到四个服务器上,没有主服务器的概念。本站通过 GeoDNS,将访客解析到最近的服务器,以降低延迟。在阿里云香港服务器宕机后,只需要停止响应解析即可。原本亚太地区解析到香港,现在亚洲会解析到北京,澳洲会解析到美国,这部分用户就被分流到可用的服务器上了。

本站还使用了 Route 53 的 Health Check 功能,可以实现接近实时的监控主机运行状态,在发现运行状态异常时,自动停止响应解析。目前,我的网站会在出现异常后一分钟内检测并识别到,并停止响应解析。相关 DNS 记录的时间设置在了 120 秒,因此服务发生不可用时,用户影响的时间不会超过 3 分钟。

从零开始建立自己的域名和企业邮箱

本文将带领你注册属于自己的域名,并获得以自己的域名结尾的专属邮箱。全程仅需不到 10 分钟[1]。你只需要一台可以上网的设备,支付方式(微信/PayPal/银行卡)和一个现有邮箱。通过本文提到的域名注册商注册的 .com 域名价格为 CN¥79.20/年,并且续费不涨价。该域名注册商免费提供企业邮箱服务,因此不需要额外付费。

[1]:由于全球 DNS 服务器同步需要时间,可能需要 24-72 小时后域名上的服务才能够使用。若注册 .cn 等中国域名还需要进行实名认证,需要额外的时间。其他国际域名(如 .com)则不需要实名认证。

注册域名

首先,你需要注册一个属于自己的域名。域名的注册门槛很低,基本在几分钟内就可以完成注册,并且包括 .com 在内的众多域名后缀均不需要进行实名登记。通常,大多数域名都是按年进行购买。

本文推荐的是 氧熙域名注册 (原 TlOxygen)。该注册商是本站站长亲自建立,是全球第 7 大的域名注册商 PDR Ltd. 的最高级代理之一,提供更多的支付方式和更低的价格。从这里购买域名可以帮助本站持续发展。并且本站域名注册提供了域名删除与退款服务、免费企业邮箱和域名锁等服务。

首先,前往 氧熙域名注册主页(也可以浏览器地址输入 yangxi.tech 前往),进行域名搜索。比如,如果想要注册 guozeyu.com,只需要在搜索框里输入这个域名并点击搜索。如果你不确定想要注册什么后缀,那么也可以不输入后缀,如 guozeyu。如果你更习惯英语界面,或者需要以美元计费的结算方式,请前往 International Version

在首页搜索想要注册的域名查看搜索结果

可以看到,咱们心仪的域名已经被注册了。但是页面下方可以看到更多的 “其他可注册的匹配域名”。

选择一个域名

我们这里选择 guozeyu.online。注意划线价为域名续费的价格,为了可以方便地给域名续费,建议选择续费价格较低的域名。比如 .com 域名续费只需 CN¥79.20/年(国际版为 US$12.59/年),而 .online 的续费价为 CN¥270.00。我对域名的价格一向非常透明,我承认这绝不是市面上最低的价格。下表列出了一些注册商 .com 域名的续费价格

注册商美元/年人民币/年
氧熙/TlOxygen13.7987.60
阿里云万网 [2]10.9979.00
DNSPod [2]-72.00
NameCheap14.58-
GoDaddy19.99-
Cloudflare Registrar [3]9.15
NameSilo10.95
Google12.00

[2]:阿里云万网/DNSPod 注册 .com 域名需要实名认证,可能需要几天后域名才能够正常使用
[3]:Cloudflare Registrar 上注册的域名不支持修改 DNS 解析商、NS 记录,以及粘附记录(Glue Record)

完整的价格列表:中国大陆(人民币)International Version (USD)

注意,本文后续的内容仅适用于在氧熙注册的域名。在其他注册商注册的域名配置有所不同。此外,并不是所有注册商都免费提供 DNS、企业邮箱和域名转发服务。

然后进行结账。结账时建议选择免费的 “隐私保护” 功能,这样你的注册信息(包括邮箱、手机号、地址)就不会公开:

开启 “隐私保护” 功能,并选择 “创建账户”

然后填写注册信息。请确保注册信息是有效的(可以通过电子邮件联系到你),否则域名注册可能会失败。注册完成后即可选择支付方式了。目前支持的支付方式有微信支付、银行卡、PayPal

使用英文填写注册信息选择支付方式,这里以微信支付为例

付款完毕后,会自动跳转到支付成功页,点击 “继续管理订单” 进入后台管理页面。

支付成功

此时,你就可以看到你新注册的域名了。

点击你刚刚注册的域名

配置 DNS

点击你刚刚注册的域名,然后前往 DNS 管理菜单,点击 “管理DNS” 以激活 DNS:

点击 “管理DNS” 以激活 DNS

如果你看到 “您即将提交的信息不安全” 提示,请选择 “仍然发送”。随后看到如下页面即说明已经激活了:

DNS 管理界面

配置企业邮箱

此时我们已经拥有了域名,但该域名下还没有任何服务。我们首先配置企业邮箱,实现任何发往 @guozeyu.online 的邮件都转发到自己的邮箱里。这样有很多好处,比如你可以在注册微博的时候使用 weibo@guozeyu.online,在注册 GitHub 时使用 github@guozeyu.online,这样可以区分不同服务商发来的邮件;也可知道是谁卖了自己的邮箱信息,给自己发送垃圾邮件。

前往电子邮件菜单,点击 “管理电子邮件” 以激活企业邮箱:

点击 “管理电子邮件” 以激活企业邮箱

如果看到 “待验证域所有权 (Pending Domain Ownership Verification)”,则说明 DNS 尚未完成激活,请在 24-72 小时后尝试。新注册的域名默认使用我们提供的 DNS 服务器,邮件记录已经自动配置好了,所以无需手动添加记录。同时,你也可以点击 “设置 (Settings)”,选择 “修改语言偏好 (Modify Language Preference)” 然后选择 “Chinese (Simplified)” 以切换语言到简体中文。此外,如果你知道自己在做什么,也可以将域名换到其他 DNS 服务商,手动配置 DNS 记录。

待 24-72 小时,完成域名所有权验证后,你将看到如下页面,这时我们选择 “添加只转发帐户”:

选择 “添加只转发帐户”

这里我们用户名输入字母 i,“转发至” 输入自己的邮箱。这里只是拿我的邮箱演示。

填写必要转发信息

添加成功后,发往 i@guozeyu.online 的邮件就会转发到你刚刚配置的 “转发至” 邮箱了。但发往其他用户名的邮件依然会被拒收。此时我们需要配置 Catch-All:

点击 “邮件” 菜单中的 “管理 Catch-All”

然后选择 “转发到以下用户/账户”,并输入刚刚设置的用户名 i,然后点击 “应用” 即可。

配置 Catch-All

配置域名转发

目前,浏览器里的网站是无法访问的,因为我们还没有配置用于 Web 的服务器,也没有建立自己的网站。但我们可以配置域名转发,将访问到域名的的流量跳转到其他 URL。比如,你可以设置跳转到自己的微博、GitHub 等网站。具体操作如下:

前往域名转发菜单,点击 “管理域名转发” 以激活域名转发:

点击 “管理域名转发” 以激活域名转发

此时,你可以配置要转发的域名和要转发到的地址:

这里以跳转到我的 GitHub 页面为例

同时,也可以选择高级设置。我建议关闭 “URL掩蔽 / 重定向 / URL隐藏”。

建议关闭 “URL掩蔽 / 重定向 / URL隐藏”

同样,该配置需要 24-72 小时后才能生效。

总结

本文介绍了如何注册属于自己的域名,建立以自己域名结尾的的企业邮箱,以及配置域名转发。后续的文章将会更新如何建立属于自己的个人网站。可以点击页面顶部的关于按钮订阅本网站,这样就不会错过后续的内容啦~

Azure DNS、NS1、Constellix,三家海外 GeoDNS 服务商对比

最近 DNSPod 的解析服务器宕机了一段时间,导致许多 DNSPod 用户的网站无法访问。本文将推荐几个提供 100% SLA 的海外 GeoDNS 服务,可用于替代不稳定的 DNSPod。并介绍一下使用多家 DNS 提供商来提高服务可用性的方法。

本文包括 Azure DNS、NS1、Constellix 的全面对比。

简介

这次推荐的三家 DNS 均是海外的支持 GeoDNS 的服务商,并都支持 Anycast。其中的 Azure DNS 和 NS1 在国内的速度都非常好,是直接走的香港/亚洲线路,平均延迟能够在 50ms 以内,不输国内 DNS 服务商。而这三家的海外速度都是极快的,可以秒杀 DNSPod、CloudXNS、阿里云解析等国内提供商。

关于 GeoDNS,精细度最好的是 Constellix:支持国家、省、市(包括中国的省、市),甚至是 AS 号(可以实现分运营商解析)、IP 段。NS1 支持国家、美国的州,也支持 AS 号、IP 段。至于 Azure DNS,通过使用 Traffic Manager,可以支持国家、部分国家的州、IP 段。由于都支持 IP 段,所以理论上支持任意精度的 GeoDNS 了。

至于价格,NS1 提供了免费额度(每月 500k 请求),对于小流量网站而言是够用的,可一旦超出这个免费额度,那么收费是很高的:**$8/百万个请求**。相比而言,Azure DNS 和 Constellix 的价格都很便宜了,其中 Constellix 有 $5/月 的起价。

使用多家 DNS 服务商

同时使用多家 DNS 服务商是可行的,只要使用服务商的 DNS 记录保持相同即可。这要求所使用的服务商能够配置主域名的 NS 记录(建议但不是必须)。这次介绍的 Azure DNS、NS1、Constellix 三家,以及以前介绍过的 Route 53、Google Cloud DNS、Rage4、阿里云解析均可配置主域名的 NS 记录(其中阿里云解析和 Azure DNS 只能额外添加第三方记录;其他几家可以完全自定义 NS 记录)。而 Cloudflare 以及国内的 DNSPod、CloudXNS、阿里云解析由于不能配置主域名下的 NS 记录,意味着你不能很好的进行 DNS 混用。

要使用多家 DNS,有两种实现方法:主服务商和从服务商方式以及两个主服务商方式。完成配置后,将多家的 NS 服务器配置到权威 NS 记录以及域名注册商下的 NS 列表。

使用两家服务商会增加配置难度,但可以提高 DNS 服务的稳定性。如最近的 DNSPod 宕机以及 2016 年的 Dyn 宕机所导致的众多网站无法访问,均是因为众多网站仅使用了一家 DNS 提供商。如果使用了多家 DNS 提供商,则网站仅会在所使用的所有服务商均发生宕机事故时才会无法访问,而这显然发生概率很小。

主服务商和从服务商

要想这样配置,需要从服务商支持使用 AXFR 从主服务商获取记录,还需要主服务商也支持 AXFR 传输。其中,NS1、Constellix 均可作为主服务商或从服务商,意味着你可以同时使用这两家,并选择任何一家作为主服务商,另一家作为从服务商。

两个主服务商

你也可以使用两个主服务商,并保持所有的记录(包括主域名下的 NS 记录)相同(建议,但不是必须)。建议也将 SOA 的序列号同步。

样例

github.com. 这个域名就同时使用了 Route 53 和 DYN 的服务。这可以使用 dig 工具验证。

$ dig github.com ns +short  ns1.p16.dynect.net.  ns2.p16.dynect.net.  ns3.p16.dynect.net.  ns4.p16.dynect.net.  ns-1283.awsdns-32.org.  ns-421.awsdns-52.com.  ns-1707.awsdns-21.co.uk.  ns-520.awsdns-01.net.

经检验,在两家 DNS 服务商也配置了相同的记录。

$ dig @ns1.p16.dynect.net. github.com a +short  13.229.188.59  13.250.177.223  52.74.223.119  $ dig @ns-1283.awsdns-32.org. github.com a +short  13.229.188.59  13.250.177.223  52.74.223.119  

下面逐个介绍一下这三家 DNS 提供商。

所有 DNS 测评一览(还包括 CloudXNS、Route 53、Cloudflare、Google Cloud DNS、Rage4 以及阿里云解析)

Azure DNS

微软 Azure 产品线下的 DNS 服务。使用 Anycast 技术,并且国内能够直接连接到香港/亚洲节点,所以速度很快。

值得注意的是,类似 Route 53,Azure 所分配的四个服务器使用的是不同的网段、不同的线路,可能有更高的可用性。

注意:Azure 的 DNS 的分区解析可能不兼容 IPv6,这意味的解析结果可能会被 Fallback 到默认线路。

  • 国外速度:★★★★☆,36 ms
  • 北美速度:★★★★☆,27 ms
  • 亚洲速度:★★★★☆,39 ms
  • 欧洲速度:★★★★☆,29 ms
  • 国内速度:★★★★☆,49 ms
  • 最短 TTL:0s
  • 国内分区解析:★★★★★,支持配置到中国,支持 IP 段配置(配合 Traffic Manager)
  • 国外分区解析:★★★★★,支持配置到大州、国家以及部分国家的州,支持 IP 段配置(配合 Traffic Manager)
  • DNSSEC:不支持
  • IPv6:支持
  • 记录类型:支持 A、AAAA、CNAME、NS、MX、TXT、SRV、CAA、PTR。
  • 根域名 CNAME 优化:不支持
  • 优先级:支持(配合 Traffic Manager)
  • 自定义 NS:仅支持添加额外的 NS
  • 价格:每个域名 $0.5/月,**$0.4/百万个请求**
  • 用例 A 价格:**$0.90**
  • 用例 B 价格:**$10.50**
  • SLA:100%

NS1

NS1 也使用了 Anycast 技术,并且国内能够直接连接到香港/亚洲节点,所以速度很快。

  • 国外速度:★★★★★,23 ms
  • 北美速度:★★★★★,9 ms
  • 亚洲速度:★★★★☆,40 ms
  • 欧洲速度:★★★★★,20 ms
  • 国内速度:★★★☆☆,65 ms
  • 最短 TTL:0s
  • 国内分区解析:★★★★★,支持配置到中国,支持 IP 段配置。
  • 国外分区解析:★★★★★,支持配置到大州、国家、美国的州,支持 AS 号、IP 段配置。
  • DNSSEC:支持
  • IPv6:不支持
  • 记录类型:支持 A、AAAA、AFSDB、CAA、CERT、CNAME、DS、HINFO、MX、NAPTR、NS、PTR、RP、SPF、SRV、TXT。
  • 根域名 CNAME 优化:支持
  • 优先级:支持(配合 Traffic Manager)
  • 自定义 NS:仅支持添加额外的 NS
  • 价格:每月前 500k 请求免费,超出部分 $8.0/百万个请求
  • 用例 A 价格:**$4**
  • 用例 B 价格:**$156**
  • 用例 C 价格:**$156**
  • SLA:100%

Constellix

此 DNS 以 GeoDNS 优势著称,使用了 Anycast 保证最低的延迟。

Constellix 三组有六个 DNS 服务器,每一组使用了不太相同的线路。

  • 国外速度:★★★★☆,31.51 ms
  • 北美速度:★★★★★,9.81 ms
  • 亚洲速度:★★★★☆,48.87 ms
  • 欧洲速度:★★★★★,23.77 ms
  • 国内速度:★★☆☆☆,108.9 ms
  • 最短 TTL:0s
  • 国内分区解析:★★★★★,可以精确到每一个省、市,可以配置 ASN 以实现运营商分区解析。
  • 国外分区解析:★★★★★,精确到了各个国家、省、市
  • DNSSEC:不支持
  • IPv6:支持
  • 记录类型:更加齐全,只支持 A、AAAA、CNAME、NS、MX、TXT、SRV、HINFO、NAPTR、CAA、CERT、PTR、RP、SPF。
  • 根域名 CNAME 优化:支持
  • 优先级:支持
  • 自定义 NS:支持
  • 价格:第一个域名 $5/月,此后每个域名 $0.5/月。**$0.4/百万个请求**。分区解析 $0.6/百万个请求
  • 用例 A 价格:**$5.39**
  • 用例 B 价格:**$14.90**
  • 用例 C 价格:**$19.30**
  • 统计功能:支持,可以看到每个国家、城市的请求数。甚至还可以启用日志,看到每一个请求的客户端 IP、IP 数据包类型等等。
  • SLA:100%

DNSSEC 简介,签名的工作原理

续之前的域名解析系统详解——基础篇,DNSSEC 是一组使域名解析系统(DNS)更加安全的解决方案。1993 年,IETF 展开了一个关于如何使 DNS 更加可信的公开讨论,最终决定了一个 DNS 的扩展——DNSSEC,并于 2005 年正式发布。然而,实际推行 DNSSEC 是一件非常难的事情,本文将讨论一下现有 DNS 系统所存在的一些不安全性,以及 DNSSEC 是如何解决这些问题的。

基础

传统 DNS 的问题

上一篇文章中已经知道,在你访问一个网站,比如 www.example.com 时,浏览器发送一个 DNS 消息到一个 DNS 缓存服务器上去查询,由于 DNS 系统的庞大,这中间还需要经过好几层 DNS 缓存服务器。想要正确访问到这个网站,就需要这所有的缓存服务器都要正确的响应。

DNS 的中间人攻击

DNS 查询是明文传输的,也就是说中间人可以在传输的过程中对其更改,甚至是去自动判断不同的域名然后去做特殊处理。即使是使用其他的 DNS 缓存服务器,如 Google 的 8.8.8.8,中间人也可以直接截获 IP 包去伪造响应内容。由于我所在的国家就面临着这个问题,所以我可以轻松的给大家演示一下被中间人攻击之后是什么个情况:

$ dig +short @4.0.0.0 facebook.com243.185.187.39

向一个没有指向任何服务器的 IP 地址:4.0.0.0 发送一个 DNS 请求,应该得不到任何响应。可是实际上在我所处的国家却返回了一个结果,很明显数据包在传输过程中“被做了手脚”。所以如果没有中间人攻击,效果是这样的:

$ dig +short @4.0.0.0 facebook.com;; connection timed out; no servers could be reached

DNS 系统就是这么脆弱,和其他任何互联网服务一样,网络服务提供商、路由器管理员等均可以充当“中间人”的角色,来对客户端与服务器之间传送的数据包进行收集,甚至替换修改,从而导致客户端得到了不正确的信息。然而,通过一定的加密手段,可以防止中间人看到在互联网上传输的数据内容,或者可以知道原始的数据数据是否被中间人修改。

从密码学开始

讲到 DNSSEC,就不得不讲到一些密码学的知识。这里从最基本的密码学开始讲起。 密码学主要分为三大类,这里也列出每一列常用的加密算法:

  • 对称密码学:AES、DES
  • 公钥密码学:RSA、ECC
  • 数据完整性的算法:SHA、MD5

在 DNSSEC 中,主要使用到的是公钥密码学和数据完整性算法两种加密学。

公钥密码学实现数字签名

公钥密码主要是与对称密码进行区分:对称密码的加密与解密使用相同的密钥;而公钥密码使用的加密密钥叫做公钥,解密密钥叫做私钥——两种密钥相对独立,不能替代对方的位置,而且知道公钥无法推出私钥。这两种密码学都必须是可逆的(所以解密算法可以看作加密算法的逆)。以函数的形式表达的话如下:

对称密码

  • 密文 = 加密算法(密钥, 原文)

  • 原文 = 解密算法(密钥, 密文)

公钥密码

  • 密文 = 加密算法(公钥, 原文)

  • 原文 = 解密算法(私钥, 密文)

当然,如果私钥充当公钥,公钥充当私钥,那么就是这样的:

  • 密文 = 加密算法(私钥, 原文)

  • 原文 = 解密算法(公钥, 密文)

假如服务器要向客户端发送一段消息,服务器有私钥,客户端有公钥。服务器使用私钥对文本进行加密,然后传送给客户端,客户端使用公钥对其解密。由于只有服务器有私钥,所以只有服务器可以加密文本,因此加密后的文本可以认证是谁发的,并且能保证数据完整性,这样加密就相当于给记录增加了**数字签名**。但是需要注意的是,由于公钥是公开的,所以数据只是不能被篡改,但可以被监听。 此处的服务器如果是充当 DNS 服务器,那么就能给 DNS 服务带来这个特性,然而一个问题就出现了,如何传输公钥?如果公钥是使用明文传输,那么攻击者可以直接将公钥换成自己的,然后对数据篡改。

中间人攻击

所以,一个解决的方法是使用一个被公认的公钥服务器,客户端的操作系统中在本地先存好这个公钥服务器自身的公钥。当与服务器通信时,客户端从这个被公认的公钥服务器通信,用户使用操作系统中内置的公钥来解密获得服务器的公钥,然后再与服务器通信。

公钥服务器

然而 DNS 是一个庞大的系统,在这个系统中根域名服务器充当了被公认的公钥服务器,其中每一个一级域名服务器也是一个子公钥服务器。最后一张图,就是 DNSSEC 的基本雏形了。

公钥服务器系统

数据完整性算法,减轻公钥密码的运算压力

在密码学中,还存在一种检查数据完整性的算法,其 “加密” 无须密钥,密文不可逆(或很难求逆),而且密文与原文不是一一对应的关系。而且,通过此算法算出的密文通常是一个固定长度的内容。通过此算法算出的密文叫做哈希值。在 DNSSEC 里所运用到它的特性是:原文一旦修改,密文就会发生变化。 公钥密码学存在的一个很重要的问题:加密和解密的速度相对于对称密码太慢了。所以想要提高性能,就需要减短需要加密和解密的文本。如果只是对文本的哈希值加密,由于长度的减短,加密速度就能大大提高。在服务器传送时,同时传送明文的文本和使用私钥加密的文本哈希值;客户端只需要先算出收到的明文文本的哈希值,然后再用公钥解密密文,验证两个值是否相等,依然能够防止篡改。 在 DNSSEC 中就运用了这种方法,无论是对密钥还是记录的加密。

DNSSEC

DNSSEC 这一个扩展可以为 DNS 记录添加验证信息,于是缓存服务器和客户端上的软件能够验证所获得的数据,可以得到 DNS 结果是真是假的结论。上一篇文章讲到过 DNS 解析是从根域名服务器开始,再一级一级向下解析,这与 DNSSEC 的信任链完全相同。所以部署 DNSSEC 也必须从根域名服务器开始。本文也就从根域名服务器讲起。

与 HTTPS 的区别

DNSSEC 和 HTTPS 是两个完全不同的东西,但是这里只是对其加密方式对比。即 DNSSEC 的加密方式与 TLS 进行对比。

信任链机制的不同

在配置 DNSSEC 的时候,如果与 HTTPS 比较,可以看出来:证书和私钥全部都是在自己的服务器上直接生成的,也就意味着这是 “自签名的”,不需要任何 “根证书颁发商”。二级域名所有者向一级域名注册商提交自己的公钥的哈希值,然后一级域名注册商就会给你的哈希值进行签名,从而也能形成一道信任链,远比 HTTPS 的信任链简单,操作系统也再不用内置那么多个 CA 证书,只需要一个根域名的 DS 记录即可。个人认为这是一个更先进的模式,但是它需要客户端一级一级的去依次解析,于是受到了速度的影响;HTTPS 则是直接由一个服务器返回整条证书链,与服务器进行 HTTPS 的连接时只需要与一个服务器通信。不过,DNS 记录是可以被缓存的,所以能够一定程度上的减少 DNSSEC 的延迟。

只签名,不加密

你发往 DNS 服务器的请求是明文的,DNS 服务器返回的请求是带签名的明文。这样 DNSSEC 只是保证了 DNS 不可被篡改,但是可以被监听,所以 DNS 不适合传输敏感信息,然而实际上的 DNS 记录几乎都不是敏感信息。HTTPS 的话会同时签名和双向加密,这样就能够传输敏感信息。 DNSSEC 的只签名,不加密主要是因为 DNSSEC 是 DNS 的一个子集,使用的是同一个端口,所以是为了兼容 DNS 而作出的东西,而 DNS 是不需要客户端与服务器建立连接的,只是客户端向服务器发一个请求,服务器再向客户端返回结果这么简单,所以 DNS 都可以使用 UDP 来传输,不需要 TCP 的握手,速度非常快。HTTPS 不是 HTTP 的子集,所以它使用的是另一个端口,为了做到加密,需要先与浏览器协商密钥,这之间进行了好几次的握手,延迟也上去了。

在哪里验证?

刚才所讲述的所有情况,都是在没有 DNS 缓存服务器的情况下。如果有 DNS 缓存服务器呢? 实际上,一些 DNS 缓存服务器就已经完成了 DNSSEC 验证,即使客户端不支持。在缓存服务器上验证失败,就直接不返回解析结果。在缓存服务器进行 DNSSEC 验证,几乎不会增加多少延迟。 但这也存在问题,如果缓存服务器到客户端之间的线路不安全呢?所以最安全的方法是在客户端上也进行一次验证,但这就会增加延迟了

DNSSEC 的时效性和缓存

DNSSEC 相比 HTTPS 的一个特性就是 DNSSEC 是可以被缓存的,而且即使是缓存了也能验证信息的真实性,任何中间人也无法篡改。然而,既然能够缓存,就应该规定一个缓存的时长,并且这个时长也是无法篡改的。 签名是有时效性的,这样客户端才能够知道自己获得到的是最新的记录,而不是以前的记录。假如没有时效性,你的域名解析到的 IP 从 A 换到了 B,在更换之前任何人都可以轻易拿到 A 的签名。攻击者可以将 A 的签名保存下来,当你更换了 IP 后,攻击者可以继续篡改响应的 IP 为 A,并继续使用原本 A 的签名,客户端也不会察觉,这并不是所期望的。 然而在实际的 RRSIG 签名中,会包含一个时间戳(并非 UNIX 时间戳,而是一个便于阅读的时间戳),比如 20170215044626,就代表着 UTC 2017-02-15 04:46:26,这个时间戳是指这个记录的失效时间,这意味着在这个时间之后,这个签名就是无效的了。时间戳会被加进加密内容中去参与签名的计算,这样攻击者就无法更改这个时间戳。由于时间戳的存在,就限制了一个 DNS 响应可以被缓存的时长(时长就是失效时间戳减去当前时间戳)。然而,在有 DNSSEC 之前,控制缓存时长是由 TTL 决定的,所以为了确保兼容性,这两个时长应该是完全一样的。 通过这样做,即能够兼容现有的 DNS 协议,有能够保证安全,还能够利用缓存资源加快客户端的请求速度,是一个比较完美的解决方案。

DNSSEC 的实际部署

其实,即使完全不了解,或者没看懂上面的内容,也不影响你去部署 DNSSEC,只不过你应当非常仔细的对待它,稍有不慎可能导致用户无法解析的情况。

使用第三方 DNS(Managed DNS)部署 DNSSEC

由于是使用第三方的 DNS,部署 DNSSEC 就必须需要第三方支持。常见的支持 DNSSEC 的第三方 DNS 有 Cloudflare、Rage4、Google Cloud DNS(需要申请)、DynDNS 等。开启 DNSSEC 前首先需要在第三方服务上激活 DNSSEC,这样第三方 DNS 才会返回关于 DNSSEC 的记录。 在第三方的 DNS 上激活了 DNSSEC 之后,第三方会给你一个 DS 记录,大概长这样:

tlo.xyz. 3600 IN DS 2371 13 2 913f95fd6716594b19e68352d6a76002fdfa595bb6df5caae7e671ee028ef346

此时,你就需要前往域名注册商,给你的域名提供这个 DS 记录(有些域名注册商可能不支持添加 DS 记录,此时你可以考虑转移到本站的域名注册商或者其他支持 DS 记录的注册商。此外,一些域名后缀也不支持添加 DS 记录,建议你使用主流后缀,如 .com 等,此处就以本站的域名注册商为例):

在域名注册商配置 DNSSEC

添加然后保存,一切就 OK 了。注意关键标签(Key Tag)就是 DS 记录里的第一项(此处对应的是 2371),算法(Algorithm)就是第二项(此处对应的是 13),算法类型(Digest Type)就是第三项(此处对应的是 2),整理分类(Digest)就是最后一项。剩下的内容不需要填写。 有的第三方 DNS(比如 Rage4)会给你一下子提供多个 DS 记录(相同的关键标签但是不同的算法和算法类型),然而你不需要都填写上。我建议只填写使用算法 13 与类型 2 或者算法 8 类型与类型 2 的 DS。这两个分别是 Cloudflare 推荐的参数和根域名目前所使用的参数。填写多个 DS 记录不会给你带来多少的安全性提升,但可能会增大客户端的计算量。

使用自建 DNS 部署 DNSSEC

使用自建 DNS 首先需要先生成一对密钥对,然后将其添加到 DNS 服务中去。我已经介绍了关于 PowerDNS 的添加 DNSSEC 的方法。 在此之后,你需要生成 DS 记录,通常你生成 DS 记录也是很多个,和第三方 DNS 一样,我建议只向域名注册商提交使用算法 13 与类型 2 或者算法 8 类型与类型 2 的 DS。

参考资料

安全性相关记录

在 DNS 中,有一些是安全性相关的记录,比如 DS、TLSA、CAA、SSHFP、IPSEC、以及一些通过 TXT 记录来实现的记录等。安全性相关的记录类型十分建议包含签名,也就是说安全性相关的记录应该使用 DNSSEC。此外,当一个域名下不包含这种记录类型时,也必须返回 NSEC 记录并签名。之前一篇文章中所介绍的 DS 就是一个例子。除了 DS 外,还有这些记录类型:

TLSA - DANE 相关

DANE 可以用于绑定某个域名下的某个服务的证书,也就是说可以让一些原本被客户端信任的证书不被信任,证书颁发商未经网站管理人授权签发的证书可以不被信任,可以实现和 Certificate Transparency 类似的效果。这容易与 HPKP Pin 混淆。HPKP Pin 后者只能使用于 HTTPS 服务,且只有成功且没有劫持的访问过才有效果(所以为了使 HPKP Pin 达到真正安全,必须需要建立一个受信任的中央服务器去 Preload 这些记录,类似 HSTS);DANE 即使是在第一次访问也无法被劫持,而且可以用于 Mail 等域名相关的 SSL 服务,不只限于 HTTPS。 我认为 DANE 的真正有意思的地方是在于它可以让客户端去有选择的信任自签名的证书,也就是说可以让一些原本不被客户端信任的证书被信任:通过 DNS 的方式向浏览器告知这个网站自签名证书的公钥,由于包含了签名,浏览器就能够知道这是域名所有者的公钥,就能够在这个域名下信任这个自签名的证书。这打破了目前常用的 CA 机制,网站管理者也再也不用去向 CA 花钱或者是不花钱的申请证书,而是直接使用自签名证书甚至是自己管理的 CA 签发的证书,操作系统也不再需要选择去信任哪些根证书,也能避免传统证书签发商系统存在结构性缺陷(比如证书签发商通过自己签发证书来进行 HTTPS 中间人等)。然而实现这一步首先需要客户端的支持,已经开始有程序开始支持,然而却还没有看到浏览器去支持的迹象。 使用了自签名证书的 HTTPS 且配合了 DANE 的站点与常规 HTTPS 站点的信任链对比:

  • DANE 自签名 (dane-self-ca.tloxygen.com):内置的 DS 记录 -> 根域名(.)-> 一级域名(.com)-> 二级域名(tloxygen.com)-> 自签名证书(dane-self-ca.tloxygen.com)
  • 证书颁发商签名(dane-trusted-ca.tloxygen.com):内置的根证书(DST Root CA X3)-> 中间证书(Let’s Encrypt Authority X3)-> 域名证书(dane-trusted-ca.tloxygen.com)

注:域名 tloxygen.com 只是在本地环境中进行的测试,公网无法访问

实现 DANE 的方式主要是通过 TLSA 记录: TLSA 记录包含了证书的哈希值,或者是某一个中间证书的哈希值(或者也可以是完整的证书)。同时,它可以针对不同的协议和端口配置不同的 TLSA 记录。我认为,TLSA 是最安全的一种 DANE 的方式。 你可以在这个网站生成一个 TLSA 记录,我的 dane-trusted-ca.tloxygen.com 站点绑定了 Let’s Encrypt 的中间证书,设置的 TLSA 记录是这样的:

_443._tcp.dane-trusted-ca.tloxygen.com. 604800 IN TLSA 0 0 1 25847D668EB4F04FDD40B12B6B0740C567DA7D024308EB6C2C96FE41D9DE218D

这里记录中的第一项(这里是 0)代表着 PKIX-TA,TA 意味着这个根证书或是中间证书必须在这个域名所使用的证书链中,也就是说这个域名只能使用某一个证书颁发商颁发的证书。如果第一项填写 1,代表着 PKIX-EE,EE 意味着这个证书必须是域名所使用的证书,也就是说每次更换证书后都得修改这个记录。PKIX 意味着这个证书链是受操作系统信任的,在使用证书颁发商颁发的证书时(如 Let’s Encrypt),应该使用 PKIX。 当第一项为 2 和 3 时,一切就变的有意思多了,2 代表着 DANE-TA,代表着绑定一个自签名的根证书,我的 dane-self-ca.tloxygen.com 站点就绑定了一个自签名的 Root,设置的 TLSA 是这样的:

_443._tcp.dane-trusted-ca.tloxygen.com. 604800 IN TLSA 0 0 1 25847D668EB4F04FDD40B12B6B0740C567DA7D024308EB6C2C96FE41D9DE218D

所以如果客户端支持了 DANE,那么这个自签名的根证书在这个域名下就是被信任的。 当第一项为 3 时,代表着 DANE-EE,这可以直接绑定域名证书,意味着不但可以使用自签名的证书,连证书链都免去了,我的 dane-self-signed.tloxygen.com 就直接使用了一个自签名的证书,设置的 TLSA 是这样的:

_443._tcp.dane-self-signed.tloxygen.com. 604800 IN TLSA 3 0 1 BF617DDCC4F39BD0C9228FC0C1EAD5E96252F36FB3FB5AB0CBB9B9B09C3CFE21

你可以在这个网站找到更多的不同种类的支持 TLSA 的网站。 那么问题就来了,为什么现有的浏览器都不支持 TLSA 呢?我认为主要原因如下:

  1. 会给浏览器带来一个额外的 DNS 查询时间,为了最高的安全性,浏览器应该在开始加载 HTTPS 页面(建立握手后)之前就先查询 TLSA 记录,这样才能够匹配证书是否该被信任,这样无疑增加了所有 HTTPS 页面的加载时长。
  2. 现有的 DNS 是一个不是足够稳定的东西,何况 DNSSEC 的记录类型不被一些 DNS 递归服务器所支持等,经常会由于因为种种原因遇到查询失败的问题,按照规则,TLSA 记录查询失败的话客户端也应该不加载页面。这样无疑增加了 HTTPS 页面加载的出错率,这样无疑会导致很多原本没有被中间人的网站也无法加载。
  3. DNS 污染,在一些情况下,客户端所处的是被 DNS 污染的环境,特点就是将服务器解析到了错误的 IP 地址。然而此时中间人为了仍能够让用户访问到 HTTPS 网站,会进行类似 SNI Proxy 的操作,此时的客户端访问网站仍是比较安全的。然而显然,DANE 在 DNS 被污染后,会直接拒绝加载页面,这样被 DNS 污染的环境会有大量站点无法加载
  4. DNSSEC 本身的安全性,现在仍有一些 DNSSEC 的 ZSK 或者是 KSK 在使用 1024-bit 的 RSA,在证书系统中,1024-bit 的 RSA 已经基本不被信任,而 RFC 却建议使用 1024-bit 直到 2022 年。而这不是主要问题,越来越多的域名服务器,尤其是根域名和一级域名,都已经使用了 2048-bit 的 RSA 甚至是 256 位的 ECDSA,客户端可以直接拒绝接受 1024-bit RSA。

然而我认为这些都不是什么问题。为了解决 DNS 的问题,可以使用 Google DNS-over-HTTPS,这样的话就能避免很多 DNS 污染的问题,而且由于 DNSSEC 本身包含签名,Google 是无法对返回内容篡改的。那么直至现在,TLSA 就只存在最后一个问题:为了获取 TLSA 记录而增加的加载延迟。而这也可以完美解决,OCSP 就是一个例子,现在传统的 CA 为了实现吊销机制,也都有 OCSP:

OCSP(Online Certificate Status Protocol,在线证书状态协议)是用来检验证书合法性的在线查询服务,一般由证书所属 CA 提供。为了真正的安全,客户端会在 TLS 握手阶段进一步协商时,实时查询 OCSP 接口,并在获得结果前阻塞后续流程。OCSP 查询本质是一次完整的 HTTP 请求,导致最终建立 TLS 连接时间变得更长。

这样,在开始正式开始加载页面,客户端也需要进行一次 HTTP 请求去查询 OCSP。OCSP 也会十分影响页面加载速度,也同样会增加加载页面出错的可能。而 OCSP 有了 OCSP Stapling,这样的话 Web 服务器会预先从 CA 获取好 OCSP 的内容,在与 Web 服务器进行 HTTPS 连接时,这个内容直接返回给客户端。由于 OCSP 内容包含了签名,Web 服务器是无法造假的,所以这一整个过程是安全的。同理,TLSA 记录也可以被预存储在 Web 服务器中,在 TLS 握手阶段直接发送给客户端。这就是 DNSSEC/DANE Chain Stapling,这个想法已经被很多人提出,然而直至现在还未被列入规范。也许浏览器未来会支持 TLSA,但至少还需要很长一段时间。

传统 CA 机制所特有的优势

传统的证书配合了现在的 Certificate Transparency,即使不需要 TLSA 记录,也能一定程度上保证了证书签发的可靠性。此外,传统证书也可以使用 TLSA,其本身的安全性不比 DANE 自签名差。 此外,传统 CA 签发的证书还有自签名证书做不到的地方:

  • OV 以及 EV 证书:DANE 自签名的证书其实就相当于 CA 签发的 DV 证书,只要是域名所有者,就能够拥有这种证书。然而很多 CA 同时还签发 OV 和 EV 证书,OV 证书可以在证书内看到证书颁发给的组织名称,EV 则是更突出的显示在浏览器上:在 Chrome 的地址栏左侧和 HTTPS 绿锁的右侧显示组织名称;Safari 则甚至直接不显示域名而直接显示组织名称。OV 和 EV 的特点就是,你甚至都不用去思考这个域名到底是不是某个组织的,而直接看证书就能保证域名的所有者。而 DV 证书可能需要通过可靠的途径验证一下这个域名到底是不是某个组织的。比如在你找一家企业官网的时候,有可能会碰到冒牌域名的网站,而你不能通过网站是否使用了 HTTPS 而判断网站是否是冒牌的——因为冒牌的网站也可以拿到 DV 证书。而当你发现这个企业使用了 OV 或 EV 证书后,你就不用再去考虑域名是否正确,因为冒牌的网站拿不到 OV 或 EV 证书。在申请 OV 或 EV 证书时,需要向 CA 提交来自组织的申请来验证组织名称,而由于 DANE 证书是自签发的,自然也不能有 OV 或 EV 的效果。
  • IP 证书:CA 可以给 IP 颁发证书(尽管这很罕见),这样就可以直接访问 HTTPS 的 IP。而 DANE 基于域名系统,所以不能实现这一点

CAA - 证书颁发相关

CAA 比较简单,它相当于是公开声明这个域名允许了哪些证书颁发商颁发的证书。CAA 不需要 DNSSEC,写在这里只是和 TLSA 区分一下,但开启 DNSSEC 无疑能够使 CAA 更可信。 比如在域名添加了如下记录,就相当于限制了仅允许 Let’s Encrypt 签发证书,其他证书签发商则不再给这个域名签发证书。在 CAA 记录刚推出时受到以下因素限制:

  • 只有在使用支持 CAA 的证书颁发商,添加 CAA 才有意义
  • 证书颁发商并没有必要 CAA,也就是说即是添加了 CAA 记录后仍可能可以被其他你没有允许的证书颁发商颁发。所以这是需要其他证书颁发商自觉地不再给这个域名办法证书。

但是从 2017 年底开始,所有证书颁发商被强制要求遵守域名的 CAA 记录。来源 CAA 的副作用最小,你也可以添加多个 CAA 记录来允许多个证书颁发商去签发,以增加灵活性。 google.com 就使用了 CAA(但是没有开启 DNSSEC):

$ dig google.com caa;; ANSWER SECTION:google.com.86399INCAA0 issue "symantec.com"

如果要将一个域名绑定在某个证书颁发商下,建议同时使用 TLSA 和 CAA。如果是长期的绑定,可以考虑一下 HPKP Pin。

SSHFP - 认证主机相关

在使用 SSH 首次连接一个主机时,SSH 通常会询问是否信任服务器的指纹(fingerprint):

$ ssh guozeyu.comThe authenticity of host 'guozeyu.com (104.199.138.99)' can't be established.ECDSA key fingerprint is SHA256:TDDVGvTLUIYr6NTZQbXITcr7mjI5eGCpqWFpXjJLUkA.Are you sure you want to continue connecting (yes/no)?

这个指纹告诉你了你连接到的是这个服务器,而不是别的服务器。你需要确认这个指纹与自己所要连接到的服务器匹配时,才应该进行连接,不然你就会连接到别的服务器(攻击者可以让服务器允许任何来源的 SSH,于是你就成功登陆到了攻击者的服务器。这样你所执行的代码,甚至是通过 SSH 提交的 Git,都能被获取到)。 那些允许公开的 SSH 连接的服务器,如 GitHub,会在网站上公开自己的指纹,用户需到在它们的官方文档中找到指纹。而 SSHFP 则是一种更简单且通用的的公开这个指纹的方式,这个功能甚至都集成到了 SSH 中去,当检测到指纹匹配时就会自动登陆,跳过询问指纹的步骤。 然而,假如攻击者同时控制了网络中的 DNS 和 SSH,那么 SSHFP 反而是更加不安全的。所以客户端仅应该信任使用了 DNSSEC 的 SSHFP 记录。 编辑 ~/.ssh/config ,添加这一行即可实现验证 SSHFP 记录:

VerifyHostKeyDNS=ask

如果将 ask 换为 yes,那么会默认信任 SSHFP 记录。

参考资料

具体实现

前面我们介绍了 DNSSEC 的基本原理,这一篇文章中将会介绍给你 DNSSEC 的具体实现方法,我来使用 dig 程序为大家分析 DNSSEC 的实现过程

根域名

我有一个域名 tlo.xyz 长期部署了 DNSSEC,所以本文就拿这个域名作为例子讲解。首先,需要明确的是如何让 dig 程序去显示关于 DNSSEC 的资源类型,幸运的是这很简单,只需要加上 +dnssec 参数即可。 在之前的文章中,我们已经知道了根域名公开了 13 个服务器的 IP 地址。此外,其实根域名还公开了一组 DS 记录,这段记录可以在这里获得

.172800INDS19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5.172800INDS20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
  • DS 记录:DNSSEC Delegation Signer,用于鉴定 DNSSEC 已授权_区域的签名密钥(Zone-signing-key)_,相当于公钥的哈希值

第二条记录是 2016 年 10 月份生成,并在 2018 年 10 月完成切换。 现在我们利用这个地址查询根域名自身,结果如下(部分无关内容已经被删掉):

$ dig @a.root-servers.net. . any +dnssec;; ANSWER SECTION:.518400INNSa.root-servers.net.;; 这里省略剩下 12 个根域名服务器.518400INRRSIGNS 8 0 518400 20170227170000 20170214160000 61045 . HnSVXyC8UZuXnpOsZOv1/GP2byJFG9Y9ch4q0eUw/6CMEJ403spJ67Oo JiAGhdiE6xlONAMQN0Q7LpA7/bgCf29mmVJDcG76b/qaVnmRjKErBwep 68K831Uph2V+Rixcw8mx5XYWuMDyKDiRWlrPyY/bT0a7Us7dTnhkNJ+D g25E0lqXNKY9XgroVoTlwc5tCIe6L8GhoDU+LTLtBySBgQa3kEAI7WUQ CT4l47BCu3zzh8sJtdKGEXnXD0e22pB4ZaYF80iVWL1cRgghn2HphlN0 1kFJr3WuuIKP9r4vZFIjKiinV1KJdBBW2fciGAx+nZbP5sSUlOdiz/56 BZKM3g==.86400INNSECaaa. NS SOA RRSIG NSEC DNSKEY.86400INRRSIGNSEC 8 0 86400 20170227170000 20170214160000 61045 . JQQEDSGFolKu38MmdvvDj7Zi2AstqZc2cwhPQE+RRwTBVl3SWQOQ4FaS Wta+CdbhbaRAKQ9dUiOif95LLarewJDF9e4O2zTDsLt5MlgXLGZr3xd4 9HhDkEzjRk4Zro2qquvWmsHUjn+fbru4FsO6sZyS/FWjfh0XImlIYfh4 D50IplgRwv6awu4mO2RzJ0VL94l4WMMnV42vPSfWiNpL+9g7PHmaWkwe EqH7RamPDzw/M3bmts5yWp+cEI4IzE25kmZAHwN9EQHNNtDL3qKtAzrY wj6e8VVw0rI/XJ3DMI5aRk3xB+ac13dQv8cWtQZRImw76A5/N6clBXJS ZpmT+w==.172800INDNSKEY256 3 8 AwEAAYvgWbYkpeGgdPKaKTJU3Us4YSTRgy7+dzvfArIhi2tKoZ/WR1Df w883SOU6Uw7tpVRkLarN0oIMK/xbOBD1DcXnyfElBwKsz4sVVWmfyr/x +igD/UjrcJ5zEBUrUmVtHyjar7ccaVc1/3ntkhZjI1hcungAlOhPhHlk MeX+5Azx6GdX//An5OgrdyH3o/JmOPMDX1mt806JI/hf0EwAp1pBwo5e 8SrSuR1tD3sgNjr6IzCdrKSgqi92z49zcdis3EaY199WFW60DCS7ydu+ +T5Xa+GyOw1quagwf/JUC/mEpeBQYWrnpkBbpDB3sy4+P2i8iCvavehb RyVm9U0MlIc=.172800INDNSKEY257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq QxA+Uk1ihz0=.172800INRRSIGDNSKEY 8 0 172800 20170303000000 20170210000000 19036 . KHz7GVvg5DxUv70bUhSjRy1JO5soL+h6M08g8bSKecd+4NmZI87Sn20p uZNRuiASbnG63i89Z2S45NBAR8KtqB6N5CrRhLhfxZcRo5k3Ts6zsC1E J58upPKzFtu/sJBsPDjcRJJKbXlB4hLukQwVhn/MbsXxZdZGI57WoLFx bbR49NlFJrlrbTi2gieRR1SCLfT9aiBGsJA3T4jXap9FIsikNf1DJA8H cnQTW7hFi8l/O2ni2hbjsIE4S3GRTMypqDR/s7piy/qukfWwSknk6YZT bzld6ZgbZK+oOhRgj/W6XW78bJl0onov0F1wD0NQsec+sk2P+JNMc4xg vQmn9g==.86400INSOAa.root-servers.net. nstld.verisign-grs.com. 2017021401 1800 900 604800 86400.86400INRRSIGSOA 8 0 86400 20170227170000 20170214160000 61045 . A5CqIucYyfFTzp03EuajDjp5Vw6dd3Oxip60AI7MCs/2xfBu1red4ZvF GfIEGHstG61iAxf7S3WlycHX9xKyfIOUPmMxuvkI9/NXMUHuvjUjv9KW TTkc1HV6PuUB1sv9gsuQ6GFnHCXAgMKXZs9YofRDlBi2jxAvJVc5U7nG sd8UqQs4WcinMHNvFV9+gwfax0Cr9KFDmDUbS+S2wYmNs+SGOn+CbFrD 8gs34GiYao8i0QGw7RVGTVJiuVOuUkeYe4iSXnJjNjeIlm8liq6PRXgM nI+ndPDogA/a8JATfyzQ97VDRwe/FucoTbe5qd2cHxqh1ZxxPkA3K3Fj 8Jv3kg==;; ADDITIONAL SECTION:a.root-servers.net.518400INA198.41.0.4a.root-servers.net.518400INAAAA2001:503:ba3e::2:30;; 这里省略剩下 12 个根域名服务器

可以看到,此时没有再返回 DS 记录,因为 DS 记录总是由一个区域的上一级区域的权威服务器返回,之后还会再次提到这个问题。此处的 DNSKEY、RRSIG、NSEC 是三个关于 DNSSEC 的记录类型:

  • DNSKEY 记录:用于 DNSSEC 的记录,内容是一个公钥
  • NSEC 和 NSEC3 记录:用于说明该域名下有哪些记录,从而可以用排除法证明该域名下没有哪些记录。
  • RRSIG 记录:记录集的数字签名,相当于是使用私钥加密后的内容。用于给除去自身外所有的记录集签名。下文有些地方直接将此记录叫做了签名。

可以看到,上方查询的 DNSKEY 记录有两条,这两条的内容的第一项分别是 256 和 257。256 是 ZSK(zone-signing keys),257 是 KSK(key-signing keys)。其中 KSK 是专门用于签名 DNSKEY 记录集(就是 ZSK 与 KSK),而 ZSK 是用于签名该区域下的其他记录集。 仔细观察,就可以看出,每一种记录后面就对应着一个用于签名该种类记录的 RRSIG 记录,比如上面查询结果中的 NS、NSEC、DNSKEY、SOA 记录的后面都跟着一个 RRSIG 记录。 举个例子,客户端解析并验证根域名的 SOA 记录的方法大概如下:

  1. 解析A:使用根域名服务器解析根域名自身下的 DNSKEY 和 SOA 记录,并要求返回签名
  2. 验证1:使用已知的 DS 记录验证 DNSKEY 中的 KSK
  3. 验证2:使用 KSK 及其签名验证 DNSKEY 记录集
  4. 验证3:使用 ZSK 和 SOA 的签名验证 SOA 记录

但是值得注意的是,根域名服务器所返回的 Glue 记录却没有数字签名,那是因为这是不必要的。就算 Glue 记录被篡改成了别的服务器,那个服务器在解析根域名时也不能篡改任何权威记录(在 ANSWER SECTION 下)。

一级域名和二级域名

然后,我们来使用根域名服务器解析一级域名:

$ dig @a.root-servers.net. xyz. any +dnssec;; AUTHORITY SECTION:xyz.172800INNSx.nic.xyz.;; 这里省略剩下 3 个服务器xyz.86400INDS3599 8 2 B9733869BC84C86BB59D102BA5DA6B27B2088552332A39DCD54BC4E8 D66B0499xyz.86400INDS3599 8 1 3FA3B264F45DB5F38BEDEAF1A88B76AA318C2C7Fxyz.86400INRRSIGDS 8 1 86400 20170227170000 20170214160000 61045 . gXpaapTu67jlkfOeujL455lFDGLmLkFpnI+f8VNLMehozA7qWQD71oso SXJxkOB6o/ldXqoLGIo1khsYS8SMltOCMisJ6eA2cLokB7Ybzsaw8GWZ rkx64u2JbELWMbwGnY3PnZHGlBT77oAt49KNDfpxhgm3k1Yrcrua25D8 PL4fz6IQYQIMXWiHM/V2jH6E2Vu1Ynrjiu0lPEMf0TnGsK/URnCGE9uZ caT41mNz9kri/wkuQR11XtHjsN/qZgmcxZK+Tf4VQfOOdcfey4wAa1CM HRQ3Pm4mLo4LQwiESeMuqFyriizdMG4piNP7NLuI54GqWCGNSyDYbOdL X0n2Aw==;; ADDITIONAL SECTION:x.nic.xyz.172800INA194.169.218.42x.nic.xyz.172800INAAAA2001:67c:13cc::1:42;; 这里省略剩下 3 个服务器

这里返回的 DS 记录,虽然是两个,但是其 Key Tag(即第一项,为 3599)是相同的,后面两项算法有所不同,这其实就是同一个 KSK 的两种不同的哈希值算法,这个是为了提高兼容性和有限的安全性。这与刚才根域名的情况不一样,根域名下面的是完全两个不同的 KSK 的不同的 DS。 此时我们发现了不仅是 Glue 记录,NS 记录下也没有签名,这是因为这里返回的 NS 记录是属于委托记录(在 AUTHORITY SECTION 下),也不需要签名,xyz. 下 NS 记录的签名应该有 xyz. 的解析服务器来完成(而 DS 记录是例外)。我们来使用一级域名服务器来解析其自身:

$ dig @x.nic.xyz. xyz. any +dnssec;; ANSWER SECTION:xyz.172800INNSx.nic.xyz.xyz.172800INNSy.nic.xyz.xyz.172800INNSz.nic.xyz.xyz.172800INNSgenerationxyz.nic.xyz.xyz.172800INRRSIGNS 8 1 172800 20170525152637 20170425162314 47496 xyz. p57paKPWMyhwmz5IkkbZOMC/dIfxyANZ6QzRbEBiOff5JXnrdpKEX4YT zPMzF4SSNHPuK53uuJTtt2E4W3Xd2VjGVUx7V2mP7Hxs0nQblCDbQa51 zr6kYoXEOcdwVx23GyLe0baPELtEkQZHeKx5eWyZTUDCri4DBCZZv9m+ Lbk=xyz.3600INSOAns0.centralnic.net. hostmaster.centralnic.net. 3000288446 900 1800 6048000 3600xyz.3600INRRSIGSOA 8 1 3600 20170606000517 20170506113911 47496 xyz. oanexcZRLZ+NEPvSGhl0qyi6LH/3ubP+0JWjlNvcduZWUp7oQt4VWfy/ w0T2Y2/610u7mvcxRty2p6cZq1arVMLOci7ZzMpPHkNDxXHcNRxlMNL1 6mwLgKzOlxp0acEGhqQBhj/XQ2icScf8PMChC7uRsFOz9nqAxelcgJgY D9I=xyz.3600INDNSKEY257 3 8 AwEAAbYRTzkgLg4oxcFb/+oFQMvluEut45siTtLiNL7t5Fim/ZnYhkxa l6TiCUywnfgiycJyneNmtC/3eoTcz5dlrlRB5dwDehcqiZoFiqjaXGHc ykHGFBDynD0/sRcEAQL+bLMv2qA+o2L7pDPHbCGJVXlUq57oTWfS4esb GDIa+1Bs8gDVMGUZcbRmeeKkc/MH2Oq1ApE5EKjH0ZRvYWS6afsWyvlX D2NXDthS5LltVKqqjhi6dy2O02stOt41z1qwfRlU89b3HXfDghlJ/L33 DE+OcTyK0yRJ+ay4WpBgQJL8GDFKz1hnR2lOjYXLttJD7aHfcYyVO6zY sx2aeHI0OYM=xyz.3600INDNSKEY256 3 8 AwEAAaAxrInKa1BlzuJsfT/gWfrUUH5OP7IJquNOLRU7LVbKwJEv655b kBBbW53wVXmnWJfPxykrMme8a91FFqXTYepvVN5vJe9QuCfiW/C64jSo 0HNXhbSUkV1ZDcy+zgAmMriPm8g5ki7KJ7KRs+YRoL2NwCm5fJVsAchr WalFB4z3xyz.3600INDNSKEY256 3 8 AwEAAdNAEAD8rebFpKuiLr0BwTNQoECMnfJjiZ54ZCCke208h9eX7ui7 WFFz9hjmvAgIFavN5vVhR5SnDTRvD5iDsMKvefXbnz4Qeu4GILwJuTqC QAcqw6RUp1+U1KEkwRP/noqA4fSkmnInbQwW+Yq+bxohGQVatZiAiO/G ppSggZX3xyz.3600INRRSIGDNSKEY 8 1 3600 20170520002252 20170419140553 3599 xyz. h5TV5pu/QAAUal72x8Dm8tgqBzRvDSznaDrRqV0Fu8ponhfXQFjdG3p1 2/IVdkNLtLZq4I2aUMwJeTZcyq5gRcWOror0V6uChW5fgIkH7abj1CYL tSRv3M7mVBduGNIzMuITJu5Pn1BVXiF9FsTw1ks+wDjdPn2OLe5BKRmj d+6GgwwBhg4V2efFcb+peRBCRpk+i3S1dlMyILCCgAvnAaGbh3k+vaKN 2wb528jSvH0QVIXP8PTAxLw86IfFlvLm8Lxo1e8hweI+4hgECNX7UzeG epXE+LpOiZwkhf7JncytOcxw6YzSAQETYJfcK1MlMcH5zNzjhFTNoMV3 M4QTLQ==;; ADDITIONAL SECTION:x.nic.xyz.172800INA194.169.218.42y.nic.xyz.172800INA185.24.64.42z.nic.xyz.172800INA212.18.248.42generationxyz.nic.xyz.172800INA212.18.249.42x.nic.xyz.172800INAAAA2001:67c:13cc::1:42y.nic.xyz.172800INAAAA2a04:2b00:13cc::1:42z.nic.xyz.172800INAAAA2a04:2b00:13ee::42generationxyz.nic.xyz.172800INAAAA2a04:2b00:13ff::42

可以看到, xyz. 下的解析服务器就返回了 NS 记录的签名。 然而,xyz. 下却有两个 ZSK,这大概是因为 xyz. 下有两个私钥,这样的话每一个签名可以使用两个私钥中的任何一个签,灵活性更高。此外,我们也看出来了区分 KSK 和 ZSK 的意义:KSK 和 ZSK 的数量可以不相等。 然后,我们来使用一级域名的服务器来解析我的二级域名:

$ dig @x.nic.xyz. tlo.xyz. any +dnssec;; AUTHORITY SECTION:tlo.xyz.3600INNSkami.ns.cloudflare.com.tlo.xyz.3600INNSgordon.ns.cloudflare.com.tlo.xyz.3600INDS2371 13 2 913F95FD6716594B19E68352D6A76002FDFA595BB6DF5CAAE7E671EE 028EF346tlo.xyz.3600INRRSIGDS 8 2 3600 20170303035908 20170201045318 7558 xyz. b69lhRaZM8lWN44qaQCCm4+479ATwt+OlRWD770jmLJnai2ob/0CWPEZ pFQ+y/k6n/X8VPZa2IVwxB6qUTtirtOolBHVA4gmPQffXiYiTbP1dDT9 G7BwNMdOCGkH0bySW9rFpi3zKYvOieNQLlV/i61ox78AgxQeX4k800QN gEE=

由于 NS 记录属于委托记录,所以 NS 下也没有签名。 由于这个域名使用的 NS 是 kami.ns.cloudflare.com. ,不属于 xyz. 之下,所以没有任何 Glue 记录,于是这需要再按照流程再重头解析一遍 kami.ns.cloudflare.com. ,这里就省略了。 最后,我们来使用我二级域名服务器来解析二级域名自身:

$ dig @kami.ns.cloudflare.com. tlo.xyz. any +dnssec;; ANSWER SECTION:tlo.xyz.60INA52.84.21.12tlo.xyz.60INA52.84.21.243tlo.xyz.60INA52.84.21.67tlo.xyz.60INA52.84.21.107tlo.xyz.60INA52.84.21.4tlo.xyz.60INA52.84.21.46tlo.xyz.60INA52.84.21.29tlo.xyz.60INA52.84.21.224tlo.xyz.60INRRSIGA 13 2 60 20170507145606 20170505125606 35273 tlo.xyz. tcMNEbUGrnCoTK1Z7Xmo15k+pLyZJ+m28nKt/o5s+/ezrcMsgFv1C0bY ABs9M8cqjw+0Ld8DTtAwTQVwpAUe+g==tlo.xyz.60INAAAA2600:9000:203a:1000:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:7e00:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:e400:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:a200:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:4800:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:3000:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:1a00:b:fe0:fc00:93a1tlo.xyz.60INAAAA2600:9000:203a:a000:b:fe0:fc00:93a1tlo.xyz.60INRRSIGAAAA 13 2 60 20170507145630 20170505125630 35273 tlo.xyz. QV5gEUO9NK3W2G4aF/dTZrmsGURyVAiU3eyyuR4lp4YJ7jxGjmCQArPB 4CYz6laN+V6Kd78gi7v50gaf+WCeDQ==tlo.xyz.3600INSOAgordon.ns.cloudflare.com. dns.cloudflare.com. 2024522030 10000 2400 604800 3600tlo.xyz.3600INRRSIGSOA 13 2 3600 20170507145653 20170505125653 35273 tlo.xyz. KnJkiBfvb0xhw3mAjKxnWPSMptc+eoN7Qh50HJQYnmycvV1K9ADFKYyq RwhKzWEOFHXtsn8Pxh+d/EY0x4EVEw==tlo.xyz.86400INNSgordon.ns.cloudflare.com.tlo.xyz.86400INNSkami.ns.cloudflare.com.tlo.xyz.86400INRRSIGNS 13 2 86400 20170507145712 20170505125712 35273 tlo.xyz. vQDzeIteIeVdbPS7nxNXCVeGD97+ePvEHdPK263oocoDPY59tVOG6V+a s7k8GHSFJ8KKu8edoWcUayi3aNFY7g==tlo.xyz.86400INTXT"v=spf1 include:email.freshdesk.com include:\_spf.myorderbox.com include:amazonses.com -all"tlo.xyz.86400INRRSIGTXT 13 2 86400 20170507145729 20170505125729 35273 tlo.xyz. NDFDF9PHFSSvQu7oF17cNWIrQUrfaPA/019i6hCvj7JJiA21DWp0w5J3 BlxDEN6wIGq4Nzb4IVE0uf+zmdTb0w==tlo.xyz.3600INDNSKEY257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0dxCjjnopKl+GqJxpVXckHAeF+ KkxLbxILfDLUT0rAK9iUzy1L53eKGQ==tlo.xyz.3600INDNSKEY256 3 13 koPbw9wmYZ7ggcjnQ6ayHyhHaDNMYELKTqT+qRGrZpWSccr/lBcrm10Z 1PuQHB3Azhii+sb0PYFkH1ruxLhe5g==tlo.xyz.3600INRRSIGDNSKEY 13 2 3600 20170529092807 20170330092807 2371 tlo.xyz. SDm3eGWVamR+GIZ8TEcYDeik73gMUVyX6TGGtkir6A6TIY+2zvXwtfrN HEvkygTfiOuEn+/Ipj08o8+NyZeAZw==

下面总结一下解析并验证 tlo.xyz. 下的全部 A 记录的方法,DNS 在实际解析过程中会尝试尽可能跳过不必要的请求:

  1. 解析A:使用根域名服务器解析根域名下的 DNSKEY 记录,并要求签名
  2. 验证1:使用已知的根域名 DS 记录验证根域名的 KSK
  3. 验证2:使用根域名的 KSK 及其签名验证 DNSKEY 记录集
  4. 解析B:使用根域名服务器解析 tlo.xyz. ,返回的是 xyz. 下的 NS 和 DS 记录,包含了签名
  5. 验证3:使用根域名的 ZSK 和 DS 的签名验证 xyz. 的 DS 记录
  6. 解析A:使用 xyz. 服务器解析 xyz. 下的 DNSKEY 记录,并要求签名
  7. 验证1:使用 xyz. 的 DS 记录验证 xyz. 的 KSK
  8. 验证2:使用 xyz. 的 KSK 及其签名验证 DNSKEY 记录集
  9. 解析B:使用 xyz. 服务器解析 tlo.xyz. 下的 NS 和 DS 记录,并要求签名
  10. 验证3:使用 xyz. 的 ZSK 和 DS 的签名验证 tlo.xyz. 的 DS 记录
  11. 解析A:使用 tlo.xyz. 服务器解析 tlo.xyz. 下的 DNSKEY 和 A 记录,并要求签名
  12. 验证1:使用 tlo.xyz. 的 DS 记录验证 tlo.xyz. 的 KSK
  13. 验证2:使用 tlo.xyz. 的 ZSK 和 A 的签名验证 tlo.xyz. 的 A 记录

为了做区分,我把解析分为了两类,验证分为了三类:

  • 解析A:解析权威记录并要求签名
  • 解析B:解析委托记录并要求 DS 记录的签名
  • 验证1:根据 DS 验证 KSK
  • 验证2:根据 KSK 验证 ZSK
  • 验证3:根据 ZSK 验证解析记录

NSEC 记录

NSEC 记录比较特殊,所以单独的讲一下。 在全面普及 DNSSEC 之前,仍然有不少域名并不支持 DNSSEC,此时如何让已经支持 DNSSEC 的网站进行签名认证,拒绝解析签名错误的请求,又同时让没有 DNSSEC 的域名无视签名正常解析呢?HTTPS 的推进是区分了协议:以 https:// 开头的网站进行签名认证,以 http:// 开头的网站不进行签名认证,在 HSTS Preload 里的域名则强制进行签名验证。而实际上,HTTP 和 HTTPS 是两种不同的协议,而支持 DNSSEC 的 DNS 与普通的 DNS 是同一种协议,前者是后者的子集。只有域名下有 DS 记录时,才会进行签名认证,否则还是按照普通的处理。 那么试想,攻击人可以在解析 tlo.xyz. 时的第九步做手脚:删除 DS 记录以及 DS 的签名,这样不就相当于移除了这个域名的 DNSSEC 了吗?(有些类似于 HTTPS 降级攻击),或者直接删除某个域名下的 A 记录,客户端能知道这个域名下是真的没有 A 记录还是被恶意删除了?实际上这样做手脚是没用的,当开启了 DNSSEC 的权威服务器收到了一个不存在的记录的请求时(这可以是不存在的子域名,也可以是某个域名下不存在的一些记录类型),不是返回空的内容,而是返回一个 NSEC 记录去声明这个域名下没有这种记录,同时也将这个记录签名。综上所述,开启了 DNSSEC 后对于该区域下的所有的 DNS 请求都会签名,从来不会返回空的内容。 根据这里公开的数据,我们来尝试一下解析第一个不支持 DNSSEC 的一级域名:ae. 的 DS 记录的结果

$ dig @a.root-servers.net. ae. ds +dnssec;; AUTHORITY SECTION:.86400INSOAa.root-servers.net. nstld.verisign-grs.com. 2017021401 1800 900 604800 86400.86400INRRSIGSOA 8 0 86400 20170227170000 20170214160000 61045 . A5CqIucYyfFTzp03EuajDjp5Vw6dd3Oxip60AI7MCs/2xfBu1red4ZvF GfIEGHstG61iAxf7S3WlycHX9xKyfIOUPmMxuvkI9/NXMUHuvjUjv9KW TTkc1HV6PuUB1sv9gsuQ6GFnHCXAgMKXZs9YofRDlBi2jxAvJVc5U7nG sd8UqQs4WcinMHNvFV9+gwfax0Cr9KFDmDUbS+S2wYmNs+SGOn+CbFrD 8gs34GiYao8i0QGw7RVGTVJiuVOuUkeYe4iSXnJjNjeIlm8liq6PRXgM nI+ndPDogA/a8JATfyzQ97VDRwe/FucoTbe5qd2cHxqh1ZxxPkA3K3Fj 8Jv3kg==ae.86400INNSECaeg. NS RRSIG NSECae.86400INRRSIGNSEC 8 1 86400 20170227170000 20170214160000 61045 . B03J+aJuEA5r5Va8QiecBHZUucisWgdC8b14Q4MU5oGSdgmK9PmHLKMS mUiGj/OzH51P1l0G6zxG6bxU56tZ4gSME+rcpIntdKyiWU4QLpkiPa32 aApHFmu0pzugGSDWnQUmNDmCig7jJ2J61xlOzx19ni0eJazAthRtGWuK WI9bCVt9Yb7Bd21AedC0gugQWY+LKj7HR3zRhZ5dywpcTQUc78BrJDvh P8UxWprUJozcMYdVDqA5TvSlRHz8aLOnkD/olVsE5cU6qSvCX32E7WuQ IeFfhf1J940hly/3f960Dvm5kwX8l6CkNW083yLCnG8e7zArEUBRthvA a90SJw==

注意新增的 NSEC 记录,这个记录首先声明了一级域名 ae. 下只有 NS RRSIG NSEC 这三种记录,也就是说没有 DS 记录。此外,它还说明了 ae. 之后的一个一级域名是 aeg. ,所以通过这个记录,可以轻松的证明不存在 aea.aeb.aec. …… 这些一级域名。 那么,如果请求 aea. 这个不存在的一级域名,会发生什么情况?

$ dig @a.root-servers.net. aea. any +dnssec;; AUTHORITY SECTION:ae.86400INNSECaeg. NS RRSIG NSECae.86400INRRSIGNSEC 8 1 86400 20170228050000 20170215040000 61045 . U2e52sVPmIup4pSfWzg7hupPZb63NdYdsiNEqr2ygDBQrgOQ6rT2SZkP xZVvHc7ZtfggUV1iT6kels8+d3beURz0Vf58x6up+PUF6svaFOmx2Bpu 42owq6wYQH6ll8GLOKiIC/35omIXja0VFj4ueG1HsbHbWVxUcL5bsDrt UWRUU9Hp1ySp36+H7M5NE+YPNk8soH2xyANe+STkymH661m8jJqXbG2X atbCEEOtuXuplvS7Rm/YRS+UEtsamC3A9bDBnus/OiL3KS1ztuvrxQfS 6a1z45UtL0PBBQ5DzNiVd9QHHhSpsaxFUqg0iw21CB6MZaK10EB7EJCQ EWkRkg==.86400INNSECaaa. NS SOA RRSIG NSEC DNSKEY.86400INRRSIGNSEC 8 0 86400 20170228050000 20170215040000 61045 . fnA/PW3QvSzI4MXZ+ylGhv/Z+F+u6YdAWnSz1DfbwSZkcpzwZoO1/uiY QtYhYU5GF/dbTk7oGEjStA0dWVzyyf+7opW+DS1+R9pn5N/LynyqZ6Et Swk85MQl04gu5LxLrnn6Nind2ozRMha4Nn7tNlYG59GLH3hXkaQ6xYmE hD0Ya+UE6h2vcQ8Y8m3ccifDO2rBukdsUJ13dZLAScNAVJU6/2YxlyyX fYY7G0Ktqu5Tq10YvfJazZ5VraBzw+bkEzM8UEPGNNfX9FTB7zxhjyhU h1u87Z/nKMoIznzVu6Xk9AC5JM1lU/OIHyYHCp+XzMGuUdjwNZH706ND MGq/rQ==.86400INSOAa.root-servers.net. nstld.verisign-grs.com. 2017021500 1800 900 604800 86400.86400INRRSIGSOA 8 0 86400 20170228050000 20170215040000 61045 . Nj7xEVPJ5DtBFRP9Zy0GCIwY/ax3v9n9JV0EsKyAeHPYDw4PBMpXQRxa banAl7DVyytO+xLz1NxY3iYTSPtyFjbAzkipC5BJT0EFovbQJ7VJOS4P nZBFaVltjGnzzrC8+hWESyhcwn2DdsNw94JqlkVPEtbT+u6vgXbIv5lD 1/YJMRcvWR74FzBC/bYyk+s0WWVNWDenioI2F7NCRgKSYm1+6qXK4on7 MFAmJE9TYYyZFFRiQurS1wH+d3/xQTtjd93GYOhpWVND0NyN/t4nkxhT spHrofo9GvzTIcGTcwT4Pp1bdBXL6dS0P+JIDXTKQN7u/3RwoJj/6jPm FOSEKw==

通过请求 aea. ,从请求的结果可以得出两个结论:

  1. ae.aeg. 是两个相邻的一级域名(这也就相当于声明了不存在 aea. 这个一级域名),此外也说明了 ae. 下只有 NS SOA RRSIG NSEC DNSKEY 这些记录。
  2. 根域名之后的一个一级域名是 aaa. ,此外也说明了根域名下只有 NS SOA RRSIG NSEC DNSKEY 这些记录。

注意,相邻的域名排序是包含该区域所有子域名的,也就是说所有的子域名都参加到了排序,刚才得出的 “ae.aeg. 是两个相邻的一级域名” 其实并不准确,而应该是根域名区域下 ae.aeg. 是两个相邻的子域名,因为 NSEC 结果还相当于说明了 a.ae. 这样的二级域名在根域名区域下也不存在。 如果 NSEC 是最后一个记录,那么它的下一个就又是区域自身了。 然而,可以发现,通过这个方法可以轻松的获得已经存在的记录:比如我只是试了一下 aea. 这个一级域名,却一下子就知道了根域名下还有 aaa.ae.aeg. 三个一级域名,通过这样一直往下遍历,就能搜索到一个区域下的所有子域名。 知道所有的一级域名对于根域名服务器无所谓,因为一级域名的列表本来就是公开的。可是,这个功能也许不是我们所期望的,有的时候,想要在自己的域名下放置一些只有自己知道的子域名,这些子域名也许就是自己源站服务器的 IP,如果 DNSSEC 就这样实现的话,这就让其他人很容易就能遍历出来你所有的子域名。所以,在 DNSSEC 中,响应记录不存在的话还有两种解决方案,一种是对 NSEC 的 Hack,还有一种是 NSEC3:

NSEC 的 Hack

Cloudflare 上就使用了对于 NSEC 的 Hack,这样就能避免其他人遍历你的所有子域名。举个例子,正常的 NSEC 去解析 a.tlo.xyz 可能是这个结果(假如我只有 www 这一个子域名):

$ dig @kami.ns.cloudflare.com. x.tlo.xyz. +dnssec;; AUTHORITY SECTION:tlo.xyz.3600INNSECwww.tlo.xyz. A MX TXT AAAA DNSKEY RRSIG NSEC; 省略一个 RRSIG 记录www.tlo.xyz.3600INNSECtlo.xyz. CNAME RRSIG NSEC; 省略一个 RRSIG 记录; 还省略了一个 SOA 以及 SOA 的 RRSIG 记录

通过观察 NSEC 记录,就可以直接看出这个域名下只有 www 一个子域名。 然而 Cloudflare 实际返回的结果是这样的:

$ dig @kami.ns.cloudflare.com. x.tlo.xyz. +dnssec;; AUTHORITY SECTION:tlo.xyz.3600INSOAgordon.ns.cloudflare.com. dns.cloudflare.com. 2023791623 10000 2400 604800 3600tlo.xyz.3600INRRSIGSOA 13 2 3600 20170216150135 20170214130135 35273 tlo.xyz. ARUYgesljY5azg1RqFgoKbTN6OOmAQUqTsLiQyTBXAMO4P/CecFGwTKY f1cVTI/s4euNahfGOvc0MnDb2R55TQ==x.tlo.xyz.3600INNSEC\\000.x.tlo.xyz. RRSIG NSECx.tlo.xyz.3600INRRSIGNSEC 13 3 3600 20170216150135 20170214130135 35273 tlo.xyz. y4g0Of3Ir/DqcbRT1ND5kwdGXlW++Zb+c9Cx0z60UAzbI+cpW2DDOmBB 4MMKi4zV9xEBg5Jq/8hwBGVo4ytDDg==

Cloudflare 这样则是告知了 x.tlo.xyz. 是存在的,但是只有 RRSIG 和 NSEC 记录,即相当于这个域名下没有任何记录。x.tlo.xyz. 之后的下一个域名是 \000.x.tlo.xyz. ,而实际上那个域名也是不存在的。这其实相当于 Cloudflare 撒了一个谎,并没有直接告知你这个域名的下一个域名。这虽然解决了问题,但是并不符合规范。

NSEC3

NSEC3 使用了在区域内的下一个记录内容的哈希值(按照哈希值的顺序排序)代替了原本的记录内容。从哈希值反推记录内容本身有一定的难度,于是就能够避免其他人遍历出所有的记录内容。(guozeyu.com 没有在生产环境中开启 DNSSEC,以下内容仅为测试结果)

$ dig @a.ns.guozeyu.com. ns.guozeyu.com +dnssec;; AUTHORITY SECTION:guozeyu.com.3600INSOAa.ns.guozeyu.com. ze3kr.icloud.com. 1 21600 3600 1209600 3600guozeyu.com.3600INRRSIGSOA 8 2 21600 20170411191942 20170403191942 52311 guozeyu.com. bHSh4a0zcaFEwS5dNEj/JT9Aosuy8Wdh+U2WaPou95iywqG6VhH85BXT EhYnjmeph/CABF5HC2OvUf9HhcnxjPF9NAQ2cfPTr6Ael9aNBGLFSejI 5VmCdp4Q1sYD6hS51k5BY22bJRyu9v8zWHNLYDRJSFBk4kR0RSV5n0CK 4pA=67uromrbachidk57be8035jf9gqnhmn1.guozeyu.com. 300IN NSEC3 1 0 1 F327CFB1FFD107F1 ENPCB7U0K7KFHLSCEOTOB7RAHS4TCH3V67uromrbachidk57be8035jf9gqnhmn1.guozeyu.com. 300IN RRSIG NSEC3 8 3 300 20170411191942 20170403191942 52311 guozeyu.com. MpV+6foWp+XQpwJnNCiIE0dqGigqX+2Z7XWuCFAd/TUS1sBHwnTRKmB5 Rl8Wf23ZMMfZh/oRHQbm4vE1RecMd78ZuvQM61iOmwAOmjIhJJh+LPSg 5KXMmYimTmtyd7/N437XYqmBREbz9EQ66ZqGucOahncPfxX2jhErvICN KDc=

标准的 NSEC 相比 NSEC3 的优点

标准的 NSEC 会暴露所有的子域名,而 NSEC3 不会,看起来 NSEC3 的优势明显。然而标准的 NSEC 相比 NSEC3 又有好处:子(Slave)DNS 服务器不需要拥有 DNS 的私钥,这样配置 Slave DNS 后就方便多了,和常规的 Slave 一样,只需要传送(Transer)整个区域即可,也能够正确的响应不存在的子域名。因为在标准的 NSEC 下 NSEC 和 RRSIG 的数量是有限的。而 NSEC3 或者 Hacked NSEC 都会根据不同的子域名返回不同的 NSEC(3) 记录,NSEC(3) 和 RRSIG 记录都是无限的。 举个例子,比如你现在可以下载到签名过的根域名的区域。其中包含了所有的 NSEC 记录,这样 RRSIG 可以在一台机器上生成,并将签名过的整个区域传送给其它子的根域名服务器上,这样能够有效的确保私钥安全。而用 NSEC3 或者 Hacked NSEC 的话,每一个子 DNS 服务器都需要有私钥。根域名服务器的数量众多,也由各种不同的组织管理着,所以很有必要保护好私钥。所以对于这种不怕被遍历到所有子域名的区域来说,使用标准的 NSEC 也未尝不可。

国内外几家全站 CDN 对比

配置全站 CDN 可以缓存 HTML 页面和加快页面首次加载所耗时间。本文重点讲述 WordPress 的全站缓存,国内外 CDN 混用的解决方案,以及让页面也在 CDN 上缓存的正确做法。本文主要介绍 CloudFront,同时也对 Cloudflare、又拍云、百度云加速、KeyCDN、Google Cloud CDN 这几家 CDN 进行对比。

全站 CDN 能在哪些地方加速?

我已经像你之前一样只缓存了图片、视频、CSS 和 JS 之类的静态资源,全站 CDN 有什么优点?

就算不缓存任何内容,全站 CDN 也是有他的优点的:

  1. SSL 卸载:源站到 CDN 之前走 HTTP 传输,CDN 到用户走 HTTPS 传输。这样,能减轻源站原本因为 SSL 所造成的硬件负担。然而,由于源站到 CDN 的传输是明文的,仅建议全程内网的情况,或线路可控的情况下使用,否则有很大的安全隐患。然而几乎所有的 CDN 也可以配置源站到 CDN 之间走 HTTPS 加密传输。
  2. 安全防护:所有的 CDN 都自带基于第一、二、三层网络的防护(防止 SYN 攻击),大多数还带了第七层的防护(防止 CC 攻击)。
  3. 减少延迟:建立 HTTP 连接之前需要先进行 TCP 和 HTTP 的 SSL 握手,这样会增加首次加载所需时间。而很多 CDN 都会与服务器进行预连接,而且 CDN 的服务器离用户较近,所以能减少首次加载所需时间,即使没有缓存页面。
  4. 缓存动态页面:所谓动态页面,其实大多数对于没有登录的用户来说内容其实是固定的(如 WordPress 的文章页),所以可以针对未登录的用户缓存。这需要 CDN 能自动根据 Cookie 判断用户有没有登录,这下就只剩 Cloudflare 企业版和 CloudFront 可以做到了。

使用 CloudFront 作为全站 CDN

CloudFront 有 Amazon 自建的网络,单价较高但是 0 元起步,适合中小客户。本文将重点介绍 CloudFront 和 WordPress 配合实现动静分离,缓存 HTML 页面。之后将对比其他的一些 CDN。

  • 国外速度:★★★★☆,节点数量众多,但相比 Cloudflare 要差一些,并且不支持 Anycast。
  • 国内速度:★★★☆☆,国内开始走亚洲节点,速度要比 Cloudflare 快
  • 可定制性:★★★★★,可以根据不同的路径回源使用不同的服务器,甚至回源到不同的服务器,且没有规则数量上限。此外,配合 Lambda@Edge 甚至可以将原本需要源站响应的动态内容交给缓存服务器做,只需使用 Node.js。
  • 廉价指数:★★★☆☆,从免费起,Pay-as-you-go,单价确实高,但是可以通过价格级别牺牲速度来换取更低廉的价格
  • 方便接入:★★☆☆☆,需要配置各种缓存参数才能使用,NS 接入并不直接,CNAME 接入相比 NS 更有难度。SSL 证书首次也需要手动申请,但自动续签。
  • 缓存命中:★★★★☆,支持 _Regional Edge Caches_,先缓存到全球的 9 个节点,再向下分发,大大提升缓存命中率
  • 动静分离:★★★★★,自动分离,一个服务下可以根据不同目录设置不同 Behaviors,甚至配置多个源站服务器,支持匹配 Cookie、GET、Header 规则缓存,支持禁用 POST 等提交方式
  • 缓存刷新:★★★★☆,支持单个 URL 刷新以及规则匹配刷新
  • 接入方式:NS/CNAME
  • 证书兼容性:默认仅限支持 SNI 的浏览器,可额外购买服务($600/月)以兼容所有浏览器。

CloudFront 作为全站 CDN 的特性:

  • 支持根域名
  • 缓存静态文件
  • 缓存页面
  • 页面更新自动清理缓存
  • 免费 SSL 证书
  • 可配置国内外 CDN 混用

使用方法

先去 CloudFront 控制面板,点击 “Create Distribution”,选择 “Web”,然后进行类似如下的配置。源站配置注意 Origin Domain Name 必须是完整域名,而且如果用了 HTTPS,那么那个域名下必须有配置有效证书。

CloudFront 基础配置截图

缓存配置,我把 Host 加入了 Header 白名单,Cookie 要添加 wordpress*wp* 到白名单。

CloudFront 详细配置截图

然后前端配置,证书点 “Request or Import a Certificate with ACM” 就能申请 Amazon 颁发的证书了。CNAMEs 下填写你的网站的域名。

CloudFront 前端配置截图

注意,创建后可能要等不到一小时才能被访问到。 为了根域名和 CloudFront 配合使用,我还得换 Route 53 这个 DNS 解析。由于这是精度非常高的 GeoDNS,是需要将解析服务器向各大 DNS 缓存服务器去提交,让这些缓存服务器去针对你的 DNS 缓存服务器加入到启用 EDNS Client Subnet 的白名单中。还好 Route 53 是最流行的 GeoDNS 之一,所以如果你用它给的 NS 记录,而不去自定义,就不用操心这个了。在配置根域名时,直接选择 A 记录,然后开启 Alias,填写 CloudFront 域名就行。如果想要支持 IPv6,那就再建一个 AAAA 记录即可。这样的话如果你从外部解析,你会直接解析到 A 记录和 AAAA 记录,而不是 CNAME 了!

CloudFront 配合 Route 53 使用截图

此时,CloudFront 就配置完了。现在 CloudFront 会自动缓存页面约一周的时间,所以需要配置文章更新时清理缓存。我写了一个插件,可以在有文章更新/主题修改/内核更新时清理所有缓存,新评论时清理文章页面,控制刷新频率为 10 分钟(这是由于 CloudFront 刷新缓存的速度是出奇的慢,而且刷新缓存只有前一千次免费)。欢迎使用我制作的插件。 不过,CloudFront 在国内的访问速度还不如我之前用的 GCE,这可怎么办?没关系,Route 53 可以 GeoDNS,我把中国和台湾还是解析到了原本的 GCE 上,这样速度其实只提不减。注意,若要这样做,原本的服务器也要有有效证书(同理,你要是域名已经备案,则可以设置为国内的 CDN 的 IP,达到国内外 CDN 混用的效果)。CloudFront 会影响 Let’s Encrypt 的签发,所以需要通过设置 Behaviors 和多个源站服务器,来继续实现 80 端口的文件认证。实际测试 Route 53 为中国解析的 IPv4 识别率为 100%,IPv6 的识别率欠佳。

CloudFront 配合 Route 53 使用截图 2

实际使用情况

GeoDNS 效果测试

国内解析情况:

$ dig @8.8.8.8 +short guozeyu.com a104.199.138.99$ dig @8.8.8.8 +short guozeyu.com aaaa2600:9000:2029:3c00:9:c41:b0c0:93a12600:9000:2029:9600:9:c41:b0c0:93a12600:9000:2029:2a00:9:c41:b0c0:93a12600:9000:2029:1600:9:c41:b0c0:93a12600:9000:2029:c00:9:c41:b0c0:93a12600:9000:2029:ce00:9:c41:b0c0:93a12600:9000:2029:6400:9:c41:b0c0:93a12600:9000:2029:ac00:9:c41:b0c0:93a1

国外解析情况:

$ dig @8.8.8.8 +short guozeyu.com a52.222.238.23652.222.238.22752.222.238.20752.222.238.10752.222.238.20852.222.238.7152.222.238.6852.222.238.67$ dig @8.8.8.8 +short guozeyu.com aaaa2600:9000:202d:5c00:9:c41:b0c0:93a12600:9000:202d:ec00:9:c41:b0c0:93a12600:9000:202d:7c00:9:c41:b0c0:93a12600:9000:202d:2a00:9:c41:b0c0:93a12600:9000:202d:9400:9:c41:b0c0:93a12600:9000:202d:c600:9:c41:b0c0:93a12600:9000:202d:f600:9:c41:b0c0:93a12600:9000:202d:6200:9:c41:b0c0:93a1

没错,CloudFront 分配给的 IP 数量就是多,让别人看了会感觉很厉害。

Ping 启动前后对比

这里只对比国外的速度

源站速度CDN 速度

HTTPs Get 启动前后对比

这里也是只对比国外的速度

源站速度CDN 速度

启动 CDN 后的 TTFB 几乎全面绿色,建立 TCP 和 TLS 的时间显著降低。

Amazon 的 SSL 证书

CloudFront 免费签发的 SSL 证书是多域名通配符证书(Wildcard SAN),并且主要名称是自定的,要比 Cloudflare 的共享证书高级。此类证书在 Cloudflare 上需要花费每月 10 美元。此类证书在市面上很难买到,而且价格取决于域名数量,在一年几千到几万不等。 然而,这个证书只能在 AWS 的 CloudFront 和负载均衡器上使用。

Amazon 证书

CloudFront 的证书链较长,会影响 TLS 时间,不过由于它同时也是 CDN,这样 TLS 时间几乎减少到了可以忽略不计的程度。主要还是因为 macOS 上还没有直接信任 Amazon Root CA,如果直接信任了,就用不着这样了。

其他 CDN 厂商对比

以下列出的所有提供商(或某一提供商的某些版本),均符合以下条件,如果不符合则单独列出:

  1. 是个 CDN 厂家
  2. 支持 HTTPS、HTTP/2
  3. 免费签发 SSL 证书,且自动续费
  4. 我现在正在使用,或曾经长期使用过,或深入了解过
  5. 可以给 WordPress 全站 CDN 加速

Cloudflare 免费版/专业版

有自建的网络,最快的速度、最低廉的价格,主要提供网站安全防护,当然还附带了 CDN。其提供的 NS 服务也是(国外)业界第一的速度。本站国外使用了 Cloudflare,欢迎直接测试本站国外的速度。

  • 国外速度:★★★★★,由于拥有众多的海外节点并支持 Anycast,给满分。速度指标指全球各地的 Ping 值,下同
  • 国内速度:★★☆☆☆,国内走美国西岸的节点,速度欠佳
  • 可定制性:★★★★★,需要使用 Page Rules 进行基础定制,还可以使用 Worker 进行编程定制。
  • 廉价指数:★★★★★,从免费起步,给满分
  • 方便接入:★★★★★,改完 NS 直接接入,自动签发 SSL 证书,无需服务器配置,还有比这更简单的吗?
  • 缓存命中:★★★★★,由于节点数量实在众多,于是在每一个地方都需要单独缓存,所以缓存命中率很低;但是如果开启了 Argo,那么就能够实现更高的缓存命中率,此外还能自动调配最优线路。Argo 需要每月额外的消费($5/mo + $0.10/GB)。
  • 动静分离:★★★☆☆,自动分离,它遵守 Cache-Control 规则,也可以设置 Page Rules 修改默认缓存规则。但是,默认不缓存 HTML 页面、Page Rules 只有 3 个的限制、以及没有开放匹配 Cookie 规则的缓存。
  • 缓存刷新:★★☆☆☆,仅支持刷新某个页面的 URL 和刷新全部内容,不支持规则刷新
  • 接入方式:NS(如果是 Partner 则可以有免费的 CNAME 接入)
  • 证书兼容性:仅限支持 SNI 的浏览器

Cloudflare 作为全站 CDN 的特性:

  • 支持根域名
  • 缓存静态文件
  • 不支持缓存页面
  • 免费 SSL 证书

有一点不同的是,Cloudflare 签发的是共享证书,证书样式如下:

Cloudflare 共享证书

我觉得 Cloudflare 签发共享证书有两个原因,一是历史遗留问题:Cloudflare 专业版的 SSL 证书服务是支持无 SNI 的客户端的,而为了支持无 SNI 的客户端,一个 IP 就只能配置一个证书,所以就使用了共享证书节约 IP 资源。而现在免费版也有了 SSL,虽然免费版使用了 SNI 技术,但是证书总不能比付费版本还要高级吧,于是还是使用了共享 SSL 证书;二是为了增加更多的增值服务,现在 Cloudflare 上可以购买 Dedicated SSL Certificates,实现独立的证书(如果是付费版本启用,不支持 SNI 的客户端仍然 Fall back 到共享证书,所以仍然兼容不支持 SNI 的设备)。

Cloudflare 企业版

简介同上,此版本适合大客户,流量越大越适合用。百度云加速是和 Cloudflare 深度整合的,其实基础设施完全一样,但百度云加速没有提供 API 接口。

  • 国外速度:★★★★★,同上
  • 国内速度:★★★★★,有众多的国内节点
  • 可定制性:★★★★★,同上,Page Rules 数量有所提升
  • 廉价指数:★★☆☆☆,每月固定的花销,不是按需付费,量越大越实惠
  • 方便接入:★★★★★,同上
  • 缓存命中:★★★★★,同上
  • 动静分离:★★★★☆,对于 WordPress 来说安装了官方插件就可以自动分离,相比免费版,他有更多的 _Page Rules_、支持匹配 Cookie 规则缓存,相比 CloudFront 差一些
  • 缓存刷新:★★★★☆,相比免费版,支持了 Cache-Tag 刷新规则,然而需要服务端的配置
  • 接入方式:NS/CNAME
  • 证书兼容性:所有浏览器

Cloudflare 企业版作为全站 CDN 的特性:

  • 支持根域名
  • 缓存静态文件
  • 支持缓存页面
  • 页面更新自动清理缓存(完美清理缓存)(由于百度云加速没有提供 API,所以云加速没有这个功能)
  • 强大的 DDOS 防御以及 WAF 功能
  • 免费 SSL 证书

UPYUN

使用自己管理的机房,网络有些受限于中国的环境,单价业界最低。

  • 国外速度:★★☆☆☆,北美洲、欧洲、亚洲都有一定数量的节点,但速度欠佳。且 CNAME 接入所用的 NS 在国外没有节点,在解析速度上就牺牲很多。
  • 国内速度:★★★★★,国内节点很多,但是由于只能 CNAME 接入,需要多一次解析请求,花费时间
  • 可定制性:★★★★☆,可以设置很多个缓存规则,并且有自定义 Rewrite,可以实现比 Rewrite 更丰富的功能,但是函数功能受限。
  • 廉价指数:★★★★½,从免费起,Pay-as-you-go,价格也是一降再降,业界较低的标准
  • 方便接入:★★★☆☆,不需要配置多少参数,CNAME 接入相比 NS 更有难度。SSL 证书首次需要手动添加,自动续签。
  • 缓存命中:★★★★½,有源站资源迁移功能,首次访问后直接永久缓存。但是如果要删除文件,还需要用 API 手动删除,扣半分
  • 动静分离:★★★★☆,自动分离,可以配置不同目录的缓存规则,但是不支持Cookie 规则缓存
  • 缓存刷新:★★★★☆,支持单个 URL 刷新以及规则匹配刷新
  • 接入方式:CNAME,所以不能根域名使用
  • 证书兼容性:仅限支持 SNI 的浏览器

UPYUN 作为全站 CDN 的特性:

  • 不支持根域名
  • 缓存静态文件
  • 不支持缓存页面
  • 有 WAF 功能
  • 免费 SSL 证书
  • 可配置国内外 CDN 混用

UPYUN 和下面的 KeyCDN 签发的都是 Let’s Encrypt 的独立证书,但都是单域名证书,甚至有 www 和无 www 的都要单独申请。

Google Cloud CDN

有全球最密集的网络集群,最快的速度、较低的单价,主要提供负载均衡,SSL 卸载,当然还附带了 CDN。由于缓存命中率低,需要超大型访问量的网站才有效。正是因为这一点,Google 自己只是将用户量极大的搜索服务用上了这个 CDN 系统,其余的很多 CDN 用的是 Cloudflare 和 Fastly 的。Google 的网络和 Cloudflare 和 Fastly 的网络有内网链接。详细介绍看本站的这篇文章

  • 国外速度:★★★★★,由于拥有众多的海外节点并支持 Anycast,给满分。
  • 国内速度:★★★☆☆,国内直连香港节点,几乎是速度最快的香港网络的,与国内几大运营商都有接入,但毕竟没有国内节点,比不过一些国内的速度。(但是目前所分配到的一些 IP,联通会绕道至美西了)
  • 可定制性:★★☆☆☆,可以根据不同路径配置不同的服务器,然后,好想也没什么别的可定制的了。
  • 廉价指数:★★☆☆☆,由于占用了 IP 资源,每月需要花费 18 美元的固定价格,并还需要再为流量付费。流量的单价较低。
  • 方便接入:★☆☆☆☆,需要各种复杂的配置,但是一旦完成了配置,就同时有了负载均衡,弹性伸缩等等特性。
  • 缓存命中:★½☆☆☆,节点太多,小流量网站都很难遇到命中的情况。但可以利用跨区域负载均衡提高缓存命中率。
  • 动静分离:★★☆☆☆,自动分离,但不能配置任何规则。
  • 缓存刷新:★★★★☆,支持单个 URL 刷新以及规则匹配刷新
  • 接入方式:IP 绑定,它直接给你分配一个独立的 Anycast IP,只需要 A 记录解析即可。
  • 证书兼容性:所有浏览器
  • 不包含免费 SSL,需要自己购买

Google Cloud CDN 作为全站 CDN 的特性:

  • 支持根域名
  • 缓存静态文件
  • 不支持缓存页面
  • 免费 SSL 证书
  • 可配置国内外 CDN 混用

KeyCDN

他们是租用别人的独立服务器,提供一体化 CDN 服务,单价业界最低。

  • 国外速度:★★★★☆,和 CloudFront 有一拼,但是由于只能 CNAME 接入,需要多一次解析请求,花费时间
  • 国内速度:★☆☆☆☆,国内的话香港节点,但是狂绕道,反而比美国还慢
  • 廉价指数:★★★☆☆,有最低年费(相当于起步价)
  • 方便接入:★★★½☆,不需要配置多少参数,CNAME 接入相比 NS 更有难度。SSL 可以一键添加。
  • 缓存命中:★★★★☆,有类似 CloudFront Regional Edge Caches 的功能
  • 动静分离:★★☆☆☆,自动分离,但不能配置规则。支持针对 Cookie 的缓存配置,但不能匹配 Cookie 内容
  • 缓存刷新:★★★★☆,支持单个 URL 刷新、全部刷新、Cache-Tag 刷新
  • 接入方式:CNAME,所以不能根域名使用
  • 证书兼容性:仅限支持 SNI 的浏览器

KeyCDN 作为全站 CDN 的特性:

  • 不支持根域名
  • 缓存静态文件
  • 缓存页面
  • 页面更新自动清理缓存(完美清理缓存)
  • 免费 SSL 证书
  • 可配置国内外 CDN 混用

我为他写了一个插件可以实现完美清理缓存,详情见此

关于 WordPress 动静分离的新方法

WordPress 可以分别设置 Site URL 和 Home URL,对于 https://example.com 这个网站,这两栏就可以这样设置:

然后,直接给 Home URL 上 CDN,在 CDN 或者源站上配置忽略 Cookie 信息。Site URL 回源,用作 WordPress 后台管理即可。

DNS 域名解析系统详解——基础篇

DNS(域名解析系统)的工作使命,就是服务于与域名相关的内容的底层。是域名(如:example.com)的核心组成部分。绝大多数与域名相关的东西,都离不开它。比如:

  • 访问一个网站,通常是输入一个域名(如 https://www.example.com
  • 发送邮件@ 后面是主机名,而主机名通常是个域名(如 webmaster@example.com

整个 DNS 具有复杂的层次,这对刚开始购买域名的人有很大的疑惑。本文将详尽的介绍 DNS 的工作原理,有助于更深刻的理解。本文将介绍:

  1. 在客户端上是如何解析一个域名的
  2. 在 DNS 缓存服务器上是如何逐级解析一个域名的

同时还包含:

  1. 域名的分类
  2. 什么是 Glue 记录
  3. 为什么 CNAME 不能设置在主域名上

先从本地的 DNS 开始讲起。

本地 DNS

本地的 DNS 相对于全球 DNS 要简单的多。所以先从本地 DNS 开始讲起。 127.0.0.1 常被用作环回 IP,也就可以作为本机用来访问自身的 IP 地址。通常,这个 IP 地址都对应着一个域名,叫 localhost。这是一个一级域名(也是顶级域名),所以和 com 同级。系统是如何实现将 localhost 对应到 127.0.0.1 的呢?其实就是通过 DNS。在操作系统中,通常存在一个 hosts 文件,这个文件定义了一组域名到 IP 的映射。常见的 hosts 文件内容如下:

127.0.0.1       localhost::1             localhost

它就定义了 localhost 域名对应 127.0.0.1 这个 IP(第二行是 IPv6 地址)。这样,当你从浏览器里访问这个域名,或者是在终端中执行 Ping 的时候,会自动的查询这个 hosts 文件,就从文件中得到了这个 IP 地址。此外,hosts 文件还可以控制其他域名所对应的 IP 地址,并可以 override 其在全球 DNS 或本地网络 DNS 中的值。但是,hosts 文件只能控制本地的域名解析。hosts 文件出现的时候,还没有 DNS,但它可以说是 DNS 的前身。 如果需要在一个网络中,公用同一个 DNS,那么就需要使用 IP 数据包向某个服务器去获取 DNS 记录。 在一个网络里(此处主要指本地的网络,比如家庭里一个路由器下连接的所有设备和这个路由器组成的网络),会有很多主机。在与这些主机通信的时候,使用域名会更加的方便。通常,连接到同一个路由器的设备会被设置到路由器自己的一个 DNS 服务器上。这样,解析域名就不仅可以从 hosts 去获取,还可以从这个服务器上去获取。从另一个 IP 上去获取 DNS 记录通过 DNS 查询,DNS 查询通常基于 UDP 或者 TCP 这种 IP 数据包,来实现远程的查询。我的个人电脑的网络配置如下,这是在我的电脑连接了路由器之后自动就设置上的:

网络配置截图

重点是在路由器和搜索域上。 我的电脑的主机名(也是电脑名)设置的是 ze3kr,这个内容在连接路由器时也被路由器知道了,于是路由器就给我的主机分配了一个域名 ze3kr.locallocal 这个一级域名专门供本地使用。在这个网络内所有主机通过访问 ze3kr.local 这个域名时,路由器(10.0.1.1)就会告知这个域名对应的 IP 地址,于是这些主机够获得到我的电脑的 IP 地址。至于搜索域的作用,其实是可以省去输入完整的域名,比如:

$ ping ze3krPING ze3kr.local (10.0.1.201): 56 data bytes64 bytes from 10.0.1.201: icmp_seq=0 ttl=64 time=0.053 ms--- ze3kr.local ping statistics ---1 packets transmitted, 1 packets received, 0.0% packet lossround-trip min/avg/max/stddev = 0.053/0.053/0.053/0.000 ms

当设置了搜索域时,当你去解析 ze3kr 这个一级域名时,便会先尝试去解析 ze3kr.local,当发现 ze3kr.local 存在对应的解析时,便停止进一步解析,直接使用 ze3kr.local 的地址。 现在你已经了解了本地 DNS 的工作方式。DNS 的基本工作方式就是:获取域名对应 IP,然后与这个 IP 进行通信。 当在本地去获取一个完整域名(FQDN)时(执行 getaddrbyhost),通常也是通过路由器自己提供的 DNS 进行解析的。当路由器收到一个完整域名请求且没有缓存时,会继续向下一级缓存 DNS 服务器(例如运营商提供的,或者是组织提供的,如 8.8.8.8)查询,下一级缓存 DNS 服务器也没有缓存时,就会通过全球 DNS 进行查询。具体的查询方式,在 “全球 DNS” 中有所介绍。

总结

在本地,先读取本地缓存查找记录,再读取 Hosts 文件,然后在搜索域中查找域名,最后再向路由器请求 DNS 记录。

全球 DNS

在全球 DNS 中,一个完整域名通常包含多级,比如 example.com. 就是个二级域名, www.example.com. 就是个三级域名。通常我们常见到的域名都是完整的域名。

全球 DNS 拓扑图

一级域名被分为以下三个部分:

  1. 普通域(gTLD):通常是三个字节或三个字节以上的域名后缀,或者是 Unicode 字符的后缀。这些域名分配给机构管理。
  2. 国家域(ccTLD):所有两个字节的域名都是国家代码,这些域名分配给国家管理。不少国家域都开放了注册,不过有的国家域仅允许当前国家的人去注册。
  3. arpa:用于将 IP 地址转换为对应的域名的根域。

我们通常所见到的域名都是普通域和国家域,而 arpa 域用作 IP 到域名的反向解析。 在本地 DNS 中,只存在域名对应 IP 这种映射关系。然而,在全球 DNS 中,有着更多的资源记录种类(RR),不只是域名对应 IP 的关系,下面将分别介绍一些最基本的资源记录种类:

  • A 记录:定义了一个 IP 地址。(AAAA 记录则是定义一个 IPv6 地址)(RFC 1035
  • NS 记录:域名服务器记录,说明一个域名下的的授权域名服务器记录。内容必须是一个域名。(RFC 1035

根域名

先从根域名开始,未命名根也可以作为 . 。你在接下来的部分所看到的很多域名都以 .结尾,以 .结尾的域名是特指的是根域名下的完整域名,然而不以 . 结尾的域名大都也是完整域名,实际使用时域名末尾的 .也常常省略。在本文中,我使用 dig 这一个常用的 DNS 软件来进行查询,我的电脑也已经连接到了互联网。 假设目前这个计算机能与互联网上的 IP 通信,但是完全没有 DNS 服务器。此时你需要知道根 DNS 服务器,以便自己获取某个域名的 IP 地址。根 DNS 服务器列表可以在这里下载到。文件内容如下:

;       This file holds the information on root name servers needed to;       initialize cache of Internet domain name servers;       (e.g. reference this file in the "cache  .  <file>";       configuration file of BIND domain name servers).;;       This file is made available by InterNIC;       under anonymous FTP as;           file                /domain/named.cache;           on server           FTP.INTERNIC.NET;       -OR-                    RS.INTERNIC.NET;;       last update:    October 20, 2016;       related version of root zone:   2016102001;; formerly NS.INTERNIC.NET;.                        3600000      NS    A.ROOT-SERVERS.NET.A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30;; FORMERLY NS1.ISI.EDU;.                        3600000      NS    B.ROOT-SERVERS.NET.B.ROOT-SERVERS.NET.      3600000      A     192.228.79.201B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:84::b;; FORMERLY C.PSI.NET;.                        3600000      NS    C.ROOT-SERVERS.NET.C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c;; FORMERLY TERP.UMD.EDU;.                        3600000      NS    D.ROOT-SERVERS.NET.D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d;; FORMERLY NS.NASA.GOV;.                        3600000      NS    E.ROOT-SERVERS.NET.E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e;; FORMERLY NS.ISC.ORG;.                        3600000      NS    F.ROOT-SERVERS.NET.F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f;; FORMERLY NS.NIC.DDN.MIL;.                        3600000      NS    G.ROOT-SERVERS.NET.G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d;; FORMERLY AOS.ARL.ARMY.MIL;.                        3600000      NS    H.ROOT-SERVERS.NET.H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53;; FORMERLY NIC.NORDU.NET;.                        3600000      NS    I.ROOT-SERVERS.NET.I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53;; OPERATED BY VERISIGN, INC.;.                        3600000      NS    J.ROOT-SERVERS.NET.J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30;; OPERATED BY RIPE NCC;.                        3600000      NS    K.ROOT-SERVERS.NET.K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1;; OPERATED BY ICANN;.                        3600000      NS    L.ROOT-SERVERS.NET.L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42;; OPERATED BY WIDE;.                        3600000      NS    M.ROOT-SERVERS.NET.M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35; End of file

这个文件中每一行分为 4 列,分别是完整域名、资源类型、生存时间(TTL,也就是可以缓存的时间)以及资源数据。通过这个文件就可以知道根域名所对应的 13 个根域名服务器的完整域名,还能知道这 13 个完整域名所对应的 IP 地址。这是因为 NS 记录只能设置为完整域名,所以为了告知 NS 所对应的 IP,还需要额外的数据去说明这 13 个完整域名对应的 IP(这些额外的数据叫做 Glue 记录)。这 13 个根域名服务器都是独立的且冗余的(但是所返回的内容应该是相同的),这样当其中的某个或某些服务器发生故障时,不会影响到解析。一旦无法解析根域名,那么所有的域名都将无法访问。

Glue 记录:如果 NS 记录对应的某个完整域名包含在那个域名之中,那么就需要添加一个 Glue 记录,来指定那个完整域名所对应的 IP。实际上任何完整域名都属于根域名之中,所以根域名就必须对这些 NS 记录设置对应的 IP 地址。Glue 记录实质上就是 A(或 AAAA)记录。(RFC 1033

我们假设你已经通过某种方法成功获取到了这个文件,那么下一步,就是使用这里的服务器对根域名以及一级域名进行解析。对根域名的解析实际上是不必要的,但是我们还是对其进行解析以便进一步分析,获得在互联网上最新、最全的数据。 在根域名上的记录,以从根域名服务器中所解析其根域名的数据为准,而不是刚才的那个文件中的内容。刚才的文件内容只是告知根域名服务器的列表,也就是只有 NS 记录和 NS 记录对应的完整域名的 IP 记录,而不是根域名下的所有记录。 我们先向 198.41.0.4 这个 IP 发送查询根域名的所有记录,any 代表显示任何类型的记录,为了看起来方便,一些无关的响应已经删除(如果只是解析根域名,这一步不能跳过。如果需要直接解析一级域名,那么这一步就可以跳过)。

$ dig @198.41.0.4 . any;; QUESTION SECTION:;.INANY;; ANSWER SECTION:.518400INNSa.root-servers.net..518400INNSb.root-servers.net..518400INNSc.root-servers.net..518400INNSd.root-servers.net..518400INNSe.root-servers.net..518400INNSf.root-servers.net..518400INNSg.root-servers.net..518400INNSh.root-servers.net..518400INNSi.root-servers.net..518400INNSj.root-servers.net..518400INNSk.root-servers.net..518400INNSl.root-servers.net..518400INNSm.root-servers.net..86400INSOAa.root-servers.net. nstld.verisign-grs.com. 2016122400 1800 900 604800 86400;; ADDITIONAL SECTION:a.root-servers.net.518400INA198.41.0.4b.root-servers.net.518400INA192.228.79.201c.root-servers.net.518400INA192.33.4.12d.root-servers.net.518400INA199.7.91.13e.root-servers.net.518400INA192.203.230.10f.root-servers.net.518400INA192.5.5.241g.root-servers.net.518400INA192.112.36.4h.root-servers.net.518400INA198.97.190.53i.root-servers.net.518400INA192.36.148.17j.root-servers.net.518400INA192.58.128.30k.root-servers.net.518400INA193.0.14.129l.root-servers.net.518400INA199.7.83.42m.root-servers.net.518400INA202.12.27.33a.root-servers.net.518400INAAAA2001:503:ba3e::2:30b.root-servers.net.518400INAAAA2001:500:84::bc.root-servers.net.518400INAAAA2001:500:2::cd.root-servers.net.518400INAAAA2001:500:2d::de.root-servers.net.518400INAAAA2001:500:a8::ef.root-servers.net.518400INAAAA2001:500:2f::fg.root-servers.net.518400INAAAA2001:500:12::d0dh.root-servers.net.518400INAAAA2001:500:1::53i.root-servers.net.518400INAAAA2001:7fe::53j.root-servers.net.518400INAAAA2001:503:c27::2:30k.root-servers.net.518400INAAAA2001:7fd::1l.root-servers.net.518400INAAAA2001:500:9f::42m.root-servers.net.518400INAAAA2001:dc3::35

其中,可以看到 TTL 与刚才文件中的内容不一样,此外还多了一个 SOA 记录,所以实际上是以这里的结果为准。这里还有一个 SOA 记录,SOA 记录是普遍存在的,具体请参考文档,在这里不做过多说明。

SOA 记录:指定有关 _DNS 区域_的权威性信息,包含主要名称服务器、域名管理员的电邮地址、域名的流水式编号、和几个有关刷新区域的定时器。(RFC 1035

_DNS 区域_:对于根域名来说,DNS 区域就是空的,也就是说它负责这互联网下所有的域名。而对于我的网站,DNS 区域就是 guozeyu.com.,管理着 guozeyu.com. 本身及其子域名的记录。

此处的 ADDITIONAL SECTION 其实就包含了 Glue 记录。

一级域名

根域名自身的 DNS 服务器服务器除了被用于解析根自身之外,还用于解析所有在互联网上的一级域名你会发现,几乎所有的 DNS 服务器,无论是否是根 DNS 服务器,都会解析其自身以及其下级域名。 从之前的解析结果中可以看出,根域名没有指定到任何 IP 地址,但是却给出了 NS 记录,于是我们就需要用这些 NS 记录来解析其下级的一级域名。下面,用所得到的根 NS 记录中的服务器其中之一来解析一个一级域名 com.

$ dig @198.41.0.4 com any;; QUESTION SECTION:;com.INANY;; AUTHORITY SECTION:com.172800INNSa.gtld-servers.net.com.172800INNSb.gtld-servers.net.com.172800INNSc.gtld-servers.net.com.172800INNSd.gtld-servers.net.com.172800INNSe.gtld-servers.net.com.172800INNSf.gtld-servers.net.com.172800INNSg.gtld-servers.net.com.172800INNSh.gtld-servers.net.com.172800INNSi.gtld-servers.net.com.172800INNSj.gtld-servers.net.com.172800INNSk.gtld-servers.net.com.172800INNSl.gtld-servers.net.com.172800INNSm.gtld-servers.net.;; ADDITIONAL SECTION:a.gtld-servers.net.172800INA192.5.6.30b.gtld-servers.net.172800INA192.33.14.30c.gtld-servers.net.172800INA192.26.92.30d.gtld-servers.net.172800INA192.31.80.30e.gtld-servers.net.172800INA192.12.94.30f.gtld-servers.net.172800INA192.35.51.30g.gtld-servers.net.172800INA192.42.93.30h.gtld-servers.net.172800INA192.54.112.30i.gtld-servers.net.172800INA192.43.172.30j.gtld-servers.net.172800INA192.48.79.30k.gtld-servers.net.172800INA192.52.178.30l.gtld-servers.net.172800INA192.41.162.30m.gtld-servers.net.172800INA192.55.83.30a.gtld-servers.net.172800INAAAA2001:503:a83e::2:30b.gtld-servers.net.172800INAAAA2001:503:231d::2:30

可以看到解析的结果和解析根域名的类似,com. 下也设置了 13 个域名服务器,但是这 13 个域名服务器与根域服务器完全不同

此处也存在 ADDITIONAL SECTION 包含的 Glue 记录,然而 gtld-servers.net. 却并不包含在 com. 下。然而实际上,com.net. 域名都是属于同一个所有者(Verisign),所以这样设置是可以的。

和根域名类似,此时解析到的内容只是 com. 的域名服务器,而并不是 com. 本身的记录,com. 上的记录,以从 com. 的域名服务器中所解析其 com. 域名的数据为准。 所以,下面再使用 com. 的域名服务器来解析 com. 自身,看情况如何(如果只是解析一级域名,这一步不能跳过。如果需要直接解析二级域名,那么这一步就可以跳过):

$ dig @192.5.6.30 com any;; QUESTION SECTION:;com.INANY;; ANSWER SECTION:com.900INSOAa.gtld-servers.net. nstld.verisign-grs.com. 1482571852 1800 900 604800 86400com.172800INNSe.gtld-servers.net.com.172800INNSm.gtld-servers.net.com.172800INNSi.gtld-servers.net.com.172800INNSk.gtld-servers.net.com.172800INNSb.gtld-servers.net.com.172800INNSj.gtld-servers.net.com.172800INNSa.gtld-servers.net.com.172800INNSd.gtld-servers.net.com.172800INNSg.gtld-servers.net.com.172800INNSc.gtld-servers.net.com.172800INNSh.gtld-servers.net.com.172800INNSf.gtld-servers.net.com.172800INNSl.gtld-servers.net.;; ADDITIONAL SECTION:e.gtld-servers.net.172800INA192.12.94.30m.gtld-servers.net.172800INA192.55.83.30i.gtld-servers.net.172800INA192.43.172.30k.gtld-servers.net.172800INA192.52.178.30b.gtld-servers.net.172800INA192.33.14.30b.gtld-servers.net.172800INAAAA2001:503:231d::2:30j.gtld-servers.net.172800INA192.48.79.30a.gtld-servers.net.172800INA192.5.6.30a.gtld-servers.net.172800INAAAA2001:503:a83e::2:30d.gtld-servers.net.172800INA192.31.80.30g.gtld-servers.net.172800INA192.42.93.30c.gtld-servers.net.172800INA192.26.92.30h.gtld-servers.net.172800INA192.54.112.30f.gtld-servers.net.172800INA192.35.51.30l.gtld-servers.net.172800INA192.41.162.30

也和根域名解析的情况类似,此时多了一个 SOA 类型的记录。

二级域名

和解析一级域名 com. 时类似,继续使用 com. 的域名服务器解析 guozeyu.com.

$ dig @192.5.6.30 guozeyu.com any;; QUESTION SECTION:;guozeyu.com.INANY;; AUTHORITY SECTION:guozeyu.com.172800INNSa.ns.guozeyu.com.guozeyu.com.172800INNSb.ns.guozeyu.com.guozeyu.com.172800INNSc.ns.guozeyu.com.;; ADDITIONAL SECTION:a.ns.guozeyu.com.172800INAAAA2001:4860:4802:38::6ca.ns.guozeyu.com.172800INA216.239.38.108b.ns.guozeyu.com.172800INAAAA2001:4860:4802:36::6cb.ns.guozeyu.com.172800INA216.239.36.108c.ns.guozeyu.com.172800INAAAA2001:4860:4802:34::6cc.ns.guozeyu.com.172800INA216.239.34.108

此处也存在 ADDITIONAL SECTION 包含的 Glue 记录,是因为 ns.guozeyu.com.guozeyu.com. 之下。 同样的,guozeyu.com. 上的记录,以从 guozeyu.com. 的域名服务器中所解析其 guozeyu.com. 域名的数据为准。此时这种解析就尤为必要了,因为 guozeyu.com. 上不只有 SOA 记录,同时也有 A 记录和其他重要的记录。 现在使用 guozeyu.com. 的域名服务器来解析 guozeyu.com.(如果只是解析二级域名,这一步不能跳过。如果需要解析三级域名,那么这一步可以跳过):

$ dig @216.239.38.108 guozeyu.com any;; QUESTION SECTION:;guozeyu.com.INANY;; ANSWER SECTION:guozeyu.com.21600INA104.199.138.99guozeyu.com.172800INNSa.ns.guozeyu.com.guozeyu.com.172800INNSb.ns.guozeyu.com.guozeyu.com.172800INNSc.ns.guozeyu.com.guozeyu.com.21600INSOAa.ns.guozeyu.com. support.tlo.xyz. 1 21600 3600 259200 300guozeyu.com.172800INMX100 us2.mx1.mailhostbox.com.guozeyu.com.172800INMX100 us2.mx2.mailhostbox.com.guozeyu.com.172800INMX100 us2.mx3.mailhostbox.com.;; ADDITIONAL SECTION:a.ns.guozeyu.com.604800INA216.239.38.108a.ns.guozeyu.com.604800INAAAA2001:4860:4802:38::6cb.ns.guozeyu.com.604800INA216.239.36.108b.ns.guozeyu.com.604800INAAAA2001:4860:4802:36::6cc.ns.guozeyu.com.604800INA216.239.34.108c.ns.guozeyu.com.604800INAAAA2001:4860:4802:34::6c

可以发现增加了 A、SOA 和 MX 记录。

  • MX 记录:邮件交换记录,让发送到一个域名的邮件由其他的主机去接受,用于与 A 记录共存。(RFC 1035

正是因为 MX 记录的存在,所以发往 username@guozeyu.com 的邮件不是指向 guozeyu.com. 对应的 IP 地址,而是使用 mailhostbox.com. 下的服务器。 当然,由于我是 guozeyu.com. 的所有者,所以我也可以控制 guozeyu.com. 下的三级或更高级的域名。比如 www.guozeyu.com.

$ dig @216.239.38.108 www.guozeyu.com any;; QUESTION SECTION:;guozeyu.com.INANY;; ANSWER SECTION:www.guozeyu.com.172800INCNAMEguozeyu.com.guozeyu.com.21600INA104.199.138.99guozeyu.com.172800INNSa.ns.guozeyu.com.guozeyu.com.172800INNSb.ns.guozeyu.com.guozeyu.com.172800INNSc.ns.guozeyu.com.guozeyu.com.21600INSOAa.ns.guozeyu.com. support.tlo.xyz. 1 21600 3600 259200 300guozeyu.com.172800INMX100 us2.mx1.mailhostbox.com.guozeyu.com.172800INMX100 us2.mx2.mailhostbox.com.guozeyu.com.172800INMX100 us2.mx3.mailhostbox.com.;; ADDITIONAL SECTION:a.ns.guozeyu.com.604800INA216.239.38.108a.ns.guozeyu.com.604800INAAAA2001:4860:4802:38::6cb.ns.guozeyu.com.604800INA216.239.36.108b.ns.guozeyu.com.604800INAAAA2001:4860:4802:36::6cc.ns.guozeyu.com.604800INA216.239.34.108c.ns.guozeyu.com.604800INAAAA2001:4860:4802:34::6c
  • CNAME 记录:规范名称记录,一个主机名字的别名。内容必须是一个域名。(RFC 1035

我的三级域名 www.guozeyu.com. 使用 CNAME 记录指向了 guozeyu.com.,这代表着 guozeyu.com.所有资源类型均与 guozeyu.com. 相同。这也是为什么 CNAME 不能和其他任何记录连用的原因,CNAME 的存在会取代任何其他的记录。由于主域名下常常也存在 SOA、NS 以及 MX 记录,所以主域名下不能使用 CNAME 解析。此外,我也可以设置在 guozeyu.com. 下的三级域名指向一个 NS 记录,这样我就可以把我的三级域名再给别人使用。

总结

  1. 如果需要解析一个根域名,使用根域名服务器解析根域名即可。
  2. 如果需要解析一个一级域名,需要先使用根域名服务器解析一级域名,获取到一级域名的域名服务器,然后用一级域名服务器解析一级域名自身。
  3. 如果需要解析一个二级域名,需要先使用根域名服务器解析一级域名,获取到一级域名的域名服务器,然后用一级域名服务器获取二级域名的域名服务器,然后用二级域名服务器解析二级域名自身。
  4. 如果需要解析一个三级域名,需要先使用根域名服务器解析一级域名,获取到一级域名的域名服务器,然后用一级域名服务器获取二级域名的域名服务器,然后用二级域名服务器解析三级域名,若三级域名下没有 NS、CNAME 记录,则解析结束,如果有 CNAME 记录则再通过正常的解析方式解析这个 CNAME 所指向的域名的记录,如果有 NS 记录,则用三级域名服务器解析三级域名自身。

DNS 缓存

通常,凡是解析过的记录,都会被解析服务器、路由器、客户端、软件缓存。这样可以大大减少请求次数。凡是被缓存的记录,其在 TTL 规定的时间内都不会再次去解析,而是直接从高速缓存中读取。正常情况下,服务器、路由器等都不应该扩大 TTL 值。被缓存的内容,TTL 值要在每秒减 1 。

$ dig guozeyu.com;; QUESTION SECTION:;guozeyu.com.INA;; ANSWER SECTION:guozeyu.com.21599INA104.199.138.99;; Query time: 514 msec;; SERVER: 10.0.1.1#53(10.0.1.1);; WHEN: Sat Dec 24 20:00:29 2016;; MSG SIZE  rcvd: 43$ dig guozeyu.com;; QUESTION SECTION:;guozeyu.com.INA;; ANSWER SECTION:guozeyu.com.21598INA104.199.138.99;; Query time: 45 msec;; SERVER: 10.0.1.1#53(10.0.1.1);; WHEN: Sat Dec 24 20:00:30 2016

这是我连续两次在我的电脑上直接通过路由器解析 guozeyu.com. 的结果。显然第一次解析没有命中高速缓存,路由器向运营商的 DNS 服务器查询,运营商的 DNS 再从根域名逐级解析 guozeyu.com.,总耗时 514 毫秒。然后 guozeyu.com. 就会同时在运营商的服务器上和路由器的 DNS 服务器上进行缓存。在第二次请求 guozeyu.com. 时,就命中了在路由器上的缓存,于是由路由器直接返回解析记录,总耗时 45 毫秒。两次查询时间相隔一秒,所以 TTL 值也被减去 1 。

arpa 反向解析

反向解析用于:给定一个 IP 地址,返回与该地址对应的域名。函数 gethostbyaddr 正是使用了这种方法获取 IP 对应的域名。 一级域名 arpa. 用于设置反向解析,对于我的网站的 IPv4 地址 104.199.138.99,其所对应的 arpa 完整域名是:99.138.199.104.in-addr.arpa.,通过获取这个域名的 PTR 记录,就可以得到这个域名所对应的完整域名域名。

$ host 104.199.138.9999.138.199.104.in-addr.arpa domain name pointer 99.138.199.104.bc.googleusercontent.com.$ dig 99.138.199.104.in-addr.arpa. ptr +short99.138.199.104.bc.googleusercontent.com.
  • PTR 记录:指针解析记录,内容是一个完整域名,定义一个 IP 所对应的域名。

可以看到,使用 host 命令获得 IP 地址的域名与使用 dig 获取的相同,均为 99.138.199.104.bc.googleusercontent.com. 。可以看出,这个 IP 是属于 Google 的。此外,需要注意的是 in-addr.arpa. 下的字域名正好与原 IPv4 地址排列相反。 这个记录通常可以由 IP 的所有者进行设置。然而,IP 的所有者可以将这项记录设置为任何域名,包括别人的域名。所以通过这种方法所判断其属于 Google 并不准确,所以,我们还需要对其验证:

$ dig 99.138.199.104.bc.googleusercontent.com a +short104.199.138.99

可以看到,这个域名又被解析到了原本的 IP,此时验证完毕,确认了这个 IP 属于 Google。所以,通过 gethostbyaddr 之后,还要继续 getaddrbyhost 验证。 然而,进行这种解析时解析服务器是由谁提供的呢?我们来看看 99.138.199.104.in-addr.arpa. 的上一级域名的解析记录:

$ dig 138.199.104.in-addr.arpa. any;; QUESTION SECTION:;138.199.104.in-addr.arpa.INANY;; ANSWER SECTION:138.199.104.in-addr.arpa. 21583INNSns-gce-public1.googledomains.com.138.199.104.in-addr.arpa. 21583INNSns-gce-public2.googledomains.com.138.199.104.in-addr.arpa. 21583INNSns-gce-public3.googledomains.com.138.199.104.in-addr.arpa. 21583INNSns-gce-public4.googledomains.com.138.199.104.in-addr.arpa. 21583INSOAns-gce-public1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 259200 300

可以看到,上一级 138.199.104.in-addr.arpa. 下配置了 Google 的域名服务器,所以 104.199.138.0/24104.196.123.0 - 104.196.123.255)都是属于 Google 的。然而,既然这个域名下的域名服务器可以设置为 Google 自己的,所以这个域名下就可以设置任何记录,不只是 PTR,所以也可以添加 A 记录把 arpa 域名当作网站! 我虽然没有那么大块的 IPv4 地址,但是我有这个 IPv6 地址:2001:470:f913::/48 并且能够设置在 arpa. 下的 NS 记录。这个 /48 的 IPv6 地址对应着 arpa. 反向解析的完整域名是 3.1.9.f.0.7.4.0.1.0.0.2.ip6.arpa. ,可以看到 IPv6 的反向解析在另一个二级域名 ip6.arpa. 下,此外其地址是将 IPv6 的每一个十六进制为拆开为一个字域并反向排列的。 我已把这个地址设置为了我自己可以控制的 NS,然后配置了 A 记录,瞬间这个反向解析域名就可以当作正常的解析使用了!

  • 3.1.9.f.0.7.4.0.1.0.0.2.ip6.arpa
  • ze3kr.3.1.9.f.0.7.4.0.1.0.0.2.ip6.arpa

如果你试图用浏览器访问这两个域名,会收到证书错误的报告,因为我还没给这个域名签发证书。

自建 PowerDNS 智能解析服务器

最近我越来越喜欢自建一些东西,比如 GitLab。今天我又把 DNS 服务器改成自建的了,分享一下经验(PS:现在为了实现根域名 CDN,我用换成了 Route 53):

本文的自建 DNS 是指的是权威 DNS,即给自己的域名配置的 DNS,而非在客户端配置的缓存 DNS。

优缺点

首先,我先说用自建 DNS 服务器的致命坏处

  1. 如果那天自己的服务器挂了,整个域名相关服务都会挂,即使你邮件收信服务器是用的是第三方的,你也不能收信了
  2. 基本上必须是开放端口,并有固定 IP(而且最好还需要至少两个 IP) 的 VPS(当然也可以是两个主机,只需要保证配置文件完全相同即可),对于服务提供商要求高
  3. 个人一般关于 DNS 运维经验不足,容易导致配置错误
  4. 第三方 DNS 提供商基本都有 DDOS 防御,而你的服务器可不一定有,攻击者可以直接通过 L7 DNS Flood 攻击掉你的服务器,然后又回到第一个问题上了

使用自建 DNS 服务器优点:

  1. 可 DIY 程度极大,各种 DNS 方面功能几乎都能配置,但却又都十分复杂
  2. 可以建在已有的服务器上,不用额外花钱

最终我还是选择了使用 PowerDNS 软件(这其实也是很多提供 DNS 服务的服务商所使用的),我安装它的最近才出的 4.0 版本,这个版本支持的一些特性:

  • EDNS Client Subnet
  • DNSSEC
  • GEODNS
  • IPv6

等等,以上只是我想到的。同时 PowerDNS 支持超多的解析记录种类(至少是我目前见过最多的):A、AAAA、AFSDB、ALIAS(也是 ANAME)、CAA、CERT、CDNSKEY、CDS、CNAME、DNSKEY、DNAME、DS、HINFO、KEY、LOC、MX、NAPTR、NS、NSEC、NSEC3、NSEC3PARAM、OPENPGPKEY、PTR、RP、RRSIG、SOA、SPF、SSHFP、SRV、TKEY、TSIG、TLSA、TXT、URI 等,还有不常用的没有列出来,见所有支持的记录。说实话有一些冷门的记录很多解析商都不支持,但我又需要用,比如 LOC、SSHFP 和 TLSA。不知道这一堆记录是干什么的?请见维基百科

简述安装过程

详情安装方法见官方文档,需要先安装 pdns-server ,然后再安装 pdns-backend-$backend 。Backend 是你可以自己选的,常用的有 BIND 和 Generic MySQL ,需要 GEODNS 可以用 GEOIP ,所有列表见此。如果想做网页版控制后台,使用 MySQL 的可能比较方便。如果只是通过文件形式控制,那么 BIND 和 GEOIP 都可以。 我使用 GEOIP 版本的,GEOIP 版本可拓展性强,使用 YAML 文件,更灵活、优雅,本文就讲讲 GEOIP 版本: 在 Ubuntu 上安装(系统软件源里就有):

$ sudo apt install pdns-server
$ sudo apt install pdns-backend-geoip

然后修改配置文件:

$ rm /etc/powerdns/pdns.d/* # 删除 Example

安装更新版本的 PowerDNS

很多特性,如 CAA 记录等,需要新版 PowerDNS。请前往官网配置软件源

安装地理位置数据库

注意,你应该已经有 MaxMind GeoIP Lite 数据库,如果没有,通过如下方式安装:

重要更新⚠️:2018 年 4 月 1 日起已经无法通过软件自动下载到 DAT 格式的 GeoIP 数据库,请前往官网手动下载对应数据库。需要的是 Binary 格式的。

创建文件 /etc/GeoIP.conf 内容是:

# The following UserId and LicenseKey are required placeholders:UserId 999999LicenseKey 000000000000# Include one or more of the following ProductIds:# * GeoLite2-City - GeoLite 2 City# * GeoLite2-Country - GeoLite2 Country# * GeoLite-Legacy-IPv6-City - GeoLite Legacy IPv6 City# * GeoLite-Legacy-IPv6-Country - GeoLite Legacy IPv6 Country# * 506 - GeoLite Legacy Country# * 517 - GeoLite Legacy ASN# * 533 - GeoLite Legacy CityProductIds 506 GeoLite-Legacy-IPv6-CountryDatabaseDirectory /usr/share/GeoIP

然后安装 geoipupdate,执行 sudo apt install geoipupdate && mkdir -p /usr/share/GeoIP && geoipupdate -v ,你的数据库就已经下载完毕了。

配置 PowerDNS

创建文件 /etc/powerdns/pdns.d/geoip.conf 内容是:

launch=geoipgeoip-database-files=/usr/share/GeoIP/GeoLiteCountry.dat /usr/share/GeoIP/GeoIPv6.dat # 选择 IPv4 和 IPv6 国家模块geoip-database-cache=memorygeoip-zones-file=/share/zone.yaml # 你的 YAML 配置文件的位置,随便哪个地方都行geoip-dnssec-keydir=/etc/powerdns/key

创建那个 YAML 文件,然后开始写 Zone,这是一个例子(IPv6 不是必须的,所有 IP 应该都填写外部 IP,本文以精确到国家举例,并列内容的顺序无所谓):

# @see: https://doc.powerdns.com/md/authoritative/backend-geoip/domains:- domain: example.com  ttl: 300 # 默认 TTL 时长  records:##### Default NS    ns1.example.com:      - a: # 你的服务器的第一个 IPv4 地址          content: 10.0.0.1          ttl: 86400      - aaaa: # 你的服务器的第一个 IPv6 地址          content: ::1          ttl: 86400    ns2.example.com: # 你的服务器的第二个 IPv4 地址(如果没有就和上面一样)      - a:          content: 10.0.0.2          ttl: 86400      - aaaa: # 你的服务器的第二个 IPv6 地址(如果没有就和上面一样)          content: ::2          ttl: 86400##### Root domain    example.com: # 根域名下的记录      - soa:          content: ns1.example.com. admin.example.com. 1 86400 3600 604800 10800          ttl: 7200      - ns:          content: ns1.example.com.          ttl: 86400      - ns:          content: ns2.example.com.          ttl: 86400      - mx:          content: 100 mx1.example.com. # 权重 [空格] 主机名          ttl: 7200      - mx:          content: 100 mx2.example.com.          ttl: 7200      - mx:          content: 100 mx3.example.com.          ttl: 7200      - a: 103.41.133.70 # 如果想使用默认 TTL,那就不用区分 content 和 ttl 字段      - aaaa: 2001:470:fa6b::1##### Servers list 你的服务器列表    beijing-server.example.com: &beijing      - a: 10.0.1.1      - aaaa: ::1:1    newyork-server.example.com: &newyork      - a: 10.0.2.1      - aaaa: ::2:1    japan-server.example.com: &japan      - a: 10.0.3.1      - aaaa: ::3:1    london-server.example.com: &uk      - a: 10.0.4.1      - aaaa: ::4:1    france-server.example.com: &france      - a: 10.0.5.1      - aaaa: ::5:1##### GEODNS 分区解析    # @see: https://php.net/manual/en/function.geoip-continent-code-by-name.php    # @see: https://en.wikipedia.org/wiki/ISO\_3166-1\_alpha-3    # unknown also is default    # %co.%cn.geo.example.com    # 默认    unknown.unknown.geo.example.com: *newyork # 默认解析到美国    # 洲    unknown.as.geo.example.com: *japan # 亚洲解析到日本    unknown.oc.geo.example.com: *japan # 大洋洲解析到日本    unknown.eu.geo.example.com: *france # 欧洲解析到法国    unknown.af.geo.example.com: *france # 非洲解析到法国    # 国家    chn.as.geo.example.com: *beijing # 中国解析北京    gbr.eu.geo.example.com: *uk # 英国解析到英国  services:    # GEODNS    www.example.com: [ '%co.%cn.geo.example.com', 'unknown.%cn.geo.example.com', 'unknown.unknown.geo.example.com']

这个配置,就相当于把 www.example.com 给分区解析,由于目前这个解析存在一些问题,导致不能同时在根域名和子域名下设置 GEODNS,这个 Bug 我已经提交反馈了。 如果你想只把解析精度设在洲级别,那么就直接 %cn.geo.example.com 这样少写一级就行了。如果你需要精确到城市,那么多写一级就行,但是需要在配置文件中添加 GeoIP 城市的数据库。然而免费的城市数据库的城市版本并不精准,你还需要去购买商业数据库,这又是一个额外开销。

配置域名

前往你的域名注册商,进入后台修改设置,给域名添加上子域名服务器记录,如图:

添加子域名服务器记录

由于要设置的 NS 是在自己服务器下的,所以务必要在域名注册商上向上级域名(如 .com)注册你的 NS 服务器 IP 地址,这样上级域名就能解析道 NS 的 IP,自建 DNS 才能使用,比如 icann.org 下就有一个属于自己的 NS:

$ dig icann.org ns +shorta.iana-servers.net.b.iana-servers.net.c.iana-servers.net.ns.icann.org.

然后再看它的上级域名 org:

$ dig org ns +shorta2.org.afilias-nst.info.b0.org.afilias-nst.org.d0.org.afilias-nst.org.c0.org.afilias-nst.info.a0.org.afilias-nst.info.b2.org.afilias-nst.org.

随便找一个服务器,查询权威记录(我就不用 +short 了):

$ dig @a0.org.afilias-nst.info icann.org ns;; QUESTION SECTION:;icann.org.INNS;; AUTHORITY SECTION:icann.org.86400INNSc.iana-servers.net.icann.org.86400INNSa.iana-servers.net.icann.org.86400INNSns.icann.org.icann.org.86400INNSb.iana-servers.net.;; ADDITIONAL SECTION:ns.icann.org.86400INA199.4.138.53ns.icann.org.86400INAAAA2001:500:89::53

可以看到,在这个 org 的 NS 服务器就已经把 ns.icann.org. 的记录返回来了,这也就是你需要在域名注册商填写 IP 地址的原因。然而你最好在你域名下的 DNS 服务器上也返回相同的 NS 和相同的 IP。 最后,不要忘了改域名的 NS 记录。

YAML 的一些高级写法

我刚才的 YAML 中其实就已经用到了 YAML 的高级写法,就是 &variable 设置变量,*variable 使用变量,这很像 CloudXNS 下的 LINK 记录,比如在 CloudXNS 下你可以这么写:

www.example.com    600   IN    A       10.0.0.1www.example.com    600   IN    A       10.0.0.2www.example.com    600   IN    AAAA    ::1www.example.com    600   IN    AAAA    ::2sub.example.com    600   IN    LINK    www.example.com

然后在你的 YAML 记录里就可以这么写:

www.example.com: &www  - a: 10.0.0.1  - a: 10.0.0.2  - aaaa: ::1  - aaaa: ::2sub.example.com: *www

这就是 YAML 的一种高级写法,不需要其他额外支持。

添加 DNSSEC 支持

详情可以参考文档,运行以下指令:

$ mkdir /etc/powerdns/key$ pdnsutil secure-zone example.com$ pdnsutil show-zone example.com

最后一个指令所返回的结果就是你需要在域名注册商设置的记录,不推荐都设置,只设置 ECDSAP256SHA256 - SHA256 digest 就行了。 最后在线检查设置即可 测试地址1 测试地址2,可能有几天缓存时间。 我的检查结果

其他一些有趣的东西

你可以在 YAML 里写上这个,为了方便你调试:

"*.ip.example.com":  - txt:      content: "IP%af: %ip, Continent: %cn, Country: %co, ASn: %as, Region: %re, Organisation: %na, City: %ci"      ttl: 0

这些变量都能作为你 GEODNS 的标准,也可以检查你的 GEOIP 数据库情况。 然后,正确检查的姿势:

$ random=`head -200 /dev/urandom  md5` ; dig ${random}.ip.example txt +short"IPv4: 42.83.200.23, Continent: as, Country: chn, ASn: unknown, Region: unknown, Organisation: unknown, City: unknown"

IP 地址就是 DNS 缓存服务器地址(如果你开启了 EDNS Client Subnet,且缓存服务器支持,那么就是自己的 IP,但是如果使用 8.8.8.8,那么会看到自己的 IP 最后一位是 0),如果你在本地指定了从你自己的服务器查,那就直接返回你自己的 IP 地址。由于我只安装了国家数据库,所以除了洲和国家之外其余都是 Unknown。

进阶使用

建立分布式 DNS

一般情况下,是一个 Master 和一个  Slave 的 DNS 解析服务器,但是这样的话对 DNSSEC 可能有问题,于是我就建立了两个 Master 服务器,自动同步记录,并设置了相同的 DNSSEC Private Key,好像并没有什么错误发生(毕竟包括 SOA 在内的所有记录也都是完全一样的),我的服务器目前的配置

$ dig @a.gtld-servers.net guozeyu.com;; QUESTION SECTION:;guozeyu.com.INA;; AUTHORITY SECTION:guozeyu.com.172800INNSa.geo.ns.tloxygen.net.guozeyu.com.172800INNSc.geo.ns.tloxygen.net.;; ADDITIONAL SECTION:a.geo.ns.tloxygen.net.172800INA198.251.90.65a.geo.ns.tloxygen.net.172800INAAAA2605:6400:10:6a9::2c.geo.ns.tloxygen.net.172800INA104.196.241.116c.geo.ns.tloxygen.net.172800INAAAA2605:6400:20:b5e::2

其中是两个 IPv4 两个 IPv6,其中 a.geo.ns.tloxygen.net. 是使用了 Anycast 技术的 IP 地址,其背后由三台服务器提供。c.geo.ns.tloxygen.net. 属于另一家服务商的主机,这样一个挂了之后还有备份,更加稳定。

Anycast or Unicast?

像我这种分布式的 DNS,其实是 Unicast 和 Anycast 的组合,这样存在的一个问题就是在一个地方连接其中一个会比较快,但是另一个会比较慢。只有在用支持异步查询,或者是带 GeoIP 的 DNS 缓存服务器,才有可能连接到最快的 DNS 权威服务器,其他情况下则是随机连接,而且如果一个服务器挂掉了,那么服务器对应的 IP 就废了。 Anycast 是一个 IP 对应多个主机,然而我却没有条件用,这个对于个人来说也许成本会比较高,要么你自己有 AS 号然后让主机商给你接入,要么你的主机商提供跨区域的 Load Balancing IP。我的 VPS 在两个不同的主机商,也没有 AS,就不能用 Anycast 了。我觉得 DNS 服务如果可能还是要用 Anycast,因为 DNS 服务器对应的 IP 不能 GEODNS(因为这是根域名给你解析的),使用 Anycast 后就基本能保障最快的连接速率,并且一个服务器挂了 IP 还能用。此外,DNS 必须要同时转发 TCP 和 UDP 的 53 端口。

宕机自动切换

如何实现宕机自动切换?实现这个的流程是: 监控服务发现宕机 -> 向服务器发送已经宕机的请求 -> 服务器对宕机处理,解析到备用 IP/暂停解析 监控服务发现服务正常 -> 向服务器发送服务正常的请求 -> 服务器对服务正常处理,恢复解析 可以建立两个 YAML file,一个是默认使用,一个是服务器宕机时使用的,当监控服务发现服务器宕机后,重新加载另一个 YAML file,然后这就是宕机模式了。

CloudXNS、Route 53、阿里云解析等 DNS 服务的全面对比

DNS(域名系统)是因特网的一项服务。它能够将域名指向一个 IP(服务器),这样你就可以通过域名来访问一个网站。能够通过域名访问的网站,都需要一个 DNS 服务器。这里指的是给站长的域名使用的权威 DNS 而并非缓存 DNS。本文包括 CloudXNS、Route 53、Cloudflare、Google Cloud DNS、Rage4 以及阿里云解析的全面对比。

CloudXNS

备注:CloudXNS 不支持 TCP。

国内免费 DNS 中最好用的,作为 DNS 服务来说其功能也算齐全。CloudXNS 的服务器国内有不少,但没有使用 Anycast 技术,所以谈任何国外的服务器都是白搭。

CloudXNS 通过 GeoDNS 对其 NS 服务器的域名进行分区解析,国内的解析到国内服务器,国外的解析到国外服务器。然而其根域名的 Glue Record 中的四个仍是国内的四个服务器,实际解析中会优先使用 Glue Record,所以并不会用上任何国外的服务器。

为什么不将这些国外服务器也添加到 Glue Record 上?因为 Glue Record 并不支持 GeoDNS,所以解析器将会随机选择服务器,所以如果这样的话会导致国内的一部分请求也走到美国服务器,反而减速。

  • 国外速度:★☆☆☆☆,248 ms
  • 北美速度:★☆☆☆☆,272 ms
  • 亚洲速度:★★☆☆☆,196 ms
  • 欧洲速度:★☆☆☆☆,283 ms
  • 国内速度:★★★★☆,32 ms
  • 最短 TTL:60s
  • 国内分区解析:★★★★★,精确到绝大多数的运营商和省
  • 国外分区解析:★★☆☆☆,精确到了大洲和一些国家,而没有城市
  • DNSSEC:不支持
  • IPv6:不支持
  • 记录类型:基本齐全,只支持 A、AAAA、CNAME、NS、MX、TXT、SRV。
  • 根域名 CNAME 优化:不支持
  • 优先级:支持,可以配置解析到不同的服务器的优先级
  • 自定义 NS:不支持,由于它不支持修改根域名下的 SOA 和 NS,所以这是做不到的
  • 价格:免费,按功能收费
  • 用例 A 价格:免费
  • 用例 B 价格:免费
  • 用例 C 价格:免费
  • 统计功能:支持,能精确到国家和省份、运营商
  • SLA:99.9%。(超出防护峰值或账户月解析量时降为98%)

Route 53

国外相当流行的 DNS 服务,必要的那些功能也算齐全。服务器都遍布全球,使用了 Anycast 保证最低的延迟。

  • 国外速度:★★★☆☆,84 ms
  • 北美速度:★★★☆☆,61 ms
  • 亚洲速度:★★★☆☆,79 ms
  • 欧洲速度:★★★☆☆,82 ms
  • 国内速度:☆☆☆☆☆,328 ms
  • 最短 TTL:0s
  • 国内分区解析:★★½☆☆,只能为中国这一个地区作单独设置,不支持省和运营商。若使用 Regional 智能解析,那么可以设置偏向于宁夏和北京的两个服务器。
  • 国外分区解析:★★★★★,精确到了各个国家,众多的国家还精确到了省/市
  • DNSSEC:不支持
  • IPv6:支持
  • 记录类型:更加齐全,支持 A、AAAA、CNAME、NS、MX、TXT、SRV、PTR、SPF、NAPTR、CAA。
  • 根域名 CNAME 优化:不支持
  • 优先级:支持
  • 自定义 NS:支持,同时也可以修改根域名下的 SOA 和 NS
  • 价格:每个域名 $0.5/月,**$0.4/百万**个请求,分区解析 $0.7/百万个请求
  • 用例 A 价格:**$0.90**
  • 用例 B 价格:**$10.50**
  • 用例 C 价格:**$16.50**
  • 统计功能:基本不支持,只有在每月最后结算的账单中看到
  • SLA:100%

Cloudflare

国外占有量相当大的免费 DNS,服务器都遍布全球,使用了 Anycast 保证最低的延迟。

  • 国外速度:★★★★★,13 ms
  • 北美速度:★★★★★,10 ms
  • 亚洲速度:★★★★☆,30 ms
  • 欧洲速度:★★★★★,8 ms
  • 国内速度:★★☆☆☆,193 ms
  • 最短 TTL:120s
  • 国内分区解析:☆☆☆☆☆,完全不支持国内的分区解析,国内的请求一般会被认作美国西岸。
  • 国外分区解析:★★★☆☆,如果购买了 Load Balancing 服务后,可以根据不同的区域配置分区解析。虽然没有按国家和城市区分,但是有时却比国家还精细(比如它支持为北美洲东西中部不同地区作分区解析)
  • DNSSEC:支持,同样支持 DNSSEC 特有的记录,包括 SSHFP、TLSA、DNSKEY、DS
  • IPv6:支持
  • 记录类型:更加齐全,支持 A、AAAA、CNAME、TXT、SRV、LOC、MX、NS、SPF、CERT、NAPTR、SMIMEA、URI
  • 根域名 CNAME 优化:支持
  • 优先级:支持,需要购买了 Load Balancing 服务
  • 自定义 NS:不支持,购买 $200/月的 Business 版本后才能支持
  • 价格:免费
  • 用例 A 价格:免费
  • 用例 B 价格:免费
  • 用例 C 价格:**$20.00**
  • 统计功能:部分支持,免费用户可以看到的统计有限
  • SLA:无(Business 和 Enterprise 版本有 100% 的 SLA 保障)

Google Cloud DNS

价格低廉,提供 100% 的 SLA,使用了 Anycast 保证最低的延迟。

  • 国外速度:★★★☆☆,60 ms
  • 北美速度:★★★☆☆,53 ms
  • 亚洲速度:★★★☆☆,95 ms
  • 欧洲速度:★★★★☆,30 ms
  • 国内速度:★★☆☆☆,171 ms
  • 最短 TTL:0s
  • 分区解析:☆☆☆☆☆,不支持
  • DNSSEC:支持,同样支持 DNSSEC 特有的记录,包括 IPSECKEY、SSHFP、TLSA、DNSKEY、DS
  • IPv6:支持
  • 记录类型:几乎完全齐全,支持 A、AAAA、CNAME、NS、MX、TXT、SRV、SPF、LOC、NAPTR、PTR、CAA 以及上方列出的 DNSSEC 相关记录。
  • 根域名 CNAME 优化:不支持
  • 自定义 NS:支持
  • 价格:每个域名 $0.2/月,**$0.4/百万个请求**。
  • 统计功能:基本不支持,只有在每月最后结算的账单中看到
  • SLA:100%

Rage4

同时支持 DNSSEC 和分区解析,使用了 Anycast 保证最低的延迟。

  • 国外速度:★★★★☆,30 ms
  • 北美速度:★★★★★,18 ms
  • 亚洲速度:★★★☆☆,59 ms
  • 欧洲速度:★★★★☆,26 ms
  • 国内速度:★★☆☆☆,153 ms
  • 最短 TTL:根据套餐情况而定
  • 国内分区解析:★★☆☆☆,只能为亚洲东部为中国配置解析
  • 国外分区解析:★★★★☆,可以根据不同的区域配置分区解析
  • DNSSEC:支持
  • IPv6:支持
  • 记录类型:更加齐全,支持 SOA、NS、A、AAAA、CNAME、TXT、MX、SRV、PTR、SPF、SSHFP、TLSA、LOC、NAPTR
  • 根域名 CNAME 优化:支持
  • 优先级:支持
  • 自定义 NS:支持,同时也可以修改根域名下的 SOA 和 NS
  • 价格:每个域名 €2/月 起,根据功能而非使用量定价
  • 用例 A 价格:€2
  • 用例 B 价格:€10
  • 用例 C 价格:€100
  • 统计功能:支持,能精确到国家
  • SLA:99.99%

阿里云解析

阿里云旗下产品,解析服务器全部使用阿里云机房,有速度保障。按照使用功能而非解析量收费。服务器国内有不少,但没有使用 Anycast 技术,所以国外速度很差。 测速基准:

ns1.alidns.com. 106.11.141.111

阿里云付费版与免费版线路有所不同,付费版含有海外线路,但由于没有 Anycast,所以最终线路是随机选择的,所以付费版与免费版相比,其在国外的响应时间稍短,在国内的解析时间稍长。 备注:阿里云 DNS 不支持 TCP。

  • 国外速度:★☆☆☆☆,238 ms
  • 北美速度:★☆☆☆☆,229 ms
  • 亚洲速度:★★☆☆☆,186 ms
  • 欧洲速度:★☆☆☆☆,251 ms
  • 国内速度:★★★★☆,33 ms
  • 最短 TTL:免费套餐:600s;付费套餐:1~120s
  • 国内分区解析:★★★★★,免费版支持运营商,付费版支持地域解析
  • 国外分区解析:★★★☆☆,免费版仅支持海外,付费版可以支持到洲、国家
  • DNSSEC:不支持
  • IPv6:不支持
  • 记录类型:支持 A、AAAA、CNAME、NS、MX、TXT、SRV。其中 CAA 仅限付费版。
  • 根域名 CNAME 优化:不支持
  • 优先级:支持
  • 自定义 NS:不支持
  • 价格:免费,按功能收费
  • 用例 A 价格:免费
  • 用例 B 价格:免费
  • 用例 C 价格:免费
  • 统计功能:仅限付费版
  • SLA:99.95%
❌