一次奇妙深刻的域名在海外解析失败问题排查之旅
作者介绍:Eli Gao,ByteDance Web Infra 团队成员,目前主要负责 Serverless 方向底层基础设施建设
起因
上个月, 有个同事提到,有用户反应 我们的内网服务域名 goofy.app 及其子域名在新加坡办公室无法访问,但是我从新加坡的家里用企业虚拟专用网络(办公 VPN)一直可以访问,其他中国区办公室的同学表示也都可以访问。
排查
回到新加坡的办公室后,我开始排查问题,随便挑了一个 https://foo.goofy.app/ 测试, 确实打不开:
$> curl https://foo.goofy.app/
curl: (6) Could not resolve host: foo.goofy.app
直接看到的问题是,foo.goofy.app 的 DNS 无法解析。那直接用 IP 访问网络通不通呢?
➜ ~ curl -i 10.*.*.* -H "host: foo.goofy.app"
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 31 Aug 2021 10:39:20 GMT
Content-Type: text/html; charset=utf-8
...
是可以的,那么在稍稍做了一些尝试之后,目前知道的情况是:
✅ 中国办公网可以访问 ✅ 新加坡办公 VPN 可以访问 ❌ 新加坡办公室不可以访问 ✅ 网络层链路通 ❌ DNS 无法解析 ❌ 新加坡公网不可以访问 ❌ 网络层链路不通(服务使用内网IP,符合预期) ❌ DNS 无法解析
非常明显,如果新加坡办公室 DNS 可以正确解析域名,理论上网站就可以正常打开。那我们就从 DNS 入手。
猜想 0:内网 DNS 配置有误
既然这个域名指向的都是内网服务,是不是这个域名在内网的解析配置有错误呢?
询问这个域名的管理员后发现,其实这个域名并不是内网域名,在公网就可以解析,只不过都是指向的内网地址。
这里我们找一个在线 DNS 测试站点解析一下 A 记录:https://ping.sx/dig?t=foo.goofy.app
从ping.sx的全球各个第三方测试节点返回的结果表明,foo.goofy.app 确实是可以在公网解析的,不过也是只有中国大陆可以解析。
📌小知识:
在很多情况下,内网域名不需要在公网解析,此时为了安全与速度,很可能会在内网 DNS 中直接返回解析结果,而不需要查询上游公网 DNS。
猜想 1:GeoDNS
那么,是不是 DNS 平台通过 GeoDNS 配置使得 DNS 只能在中国大陆解析呢?
问了一下 DNS 的负责同学,并没有开启相关的设置。实际上用 EDNS Subnet 也可以验证这一点:
(随便假装了个在中国大陆的 IP 段)
➜ ~ dig foo.goofy.app @8.8.8.8 +subnet=114.114.114.0/24 +short
(空结果)
📌小知识:
GeoDNS 是一种 DNS 扩展,可以使得 DNS 服务器根据用户所在的不同区域解析出不同的结果。它通过 EDNS(Extension Mechanisms for DNS) 实现。
猜想 2:跨境链路问题
托管在中国大陆境内的域名不能在境外解析,可不可能是跨境网络抖动呢?让我们 dig + trace 一下看看再说
trace 可以一路 trace 到 CNAME
再试试 dig 一下 NS:
中国区以外也是空的,看样子是这些 DNS 不约而同地在从 .app
查 goofy.app
的 NS 时候就掉链子了。
可是.app
的 NS ns-tld1.charlestonroadregistry.com
不在中国大陆,并没有跨境,所以应该不是这个原因。
📌小知识:
dig
命令除了常规解析域名的用法外,还可以通过+trace
选项使它在本地完整执行DNS迭代查询并输出日志,以便排查问题
📌小知识:
域名的
NS
记录代表 Name Server,它指向的是托管这个域名子域名的服务器地址。比如:dig bytedance.com ns +short
的返回值为:vip4.alidns.com.
vip3.alidns.com.
说明如果要查询bytedance.com
的子域名,请联系vip4.alidns.com
或者vip3.alidns.com
猜想 3:.app TLD NS 故障
运维同学表示可能是.app
TLD 的 NS 坏了,不过我随便找了个 get.app 域名测试没有问题(那是当然的了):
➜ ~ dig get.app ns @8.8.8.8 +short
ns4.zdns.google.
ns1.zdns.google.
ns3.zdns.google.
ns2.zdns.google.
📌小知识:
TLD指Top Level Domain,顶级域。比如常见的
.com
,.cn
,.net
都是顶级域。在DNS查询中,终究会迭代查询到顶级域的NS服务器。如果它故障了,会导致这个顶级域下的几乎所有域名大规模无法解析。
猜想 4:DNSSEC 配置错误
此时问题似乎陷入僵局,有没有什么情况下,可能导致部分用户解析结果为空呢?
有。
如果对 DNS 比较熟悉的同学可能听说过 DNSSEC,这是一个用于保证 DNS 解析不被劫持的安全扩展。
如果 DNSSEC 的配置出错,可能会导致解析结果被认作无效并丢弃,就像 HTTPS 的证书配置有误会导致网站无法打开一样。
我们去在线 Google DNS 解析一下试试,这里解析可以给出比较详细的解析结果:
https://dns.google/query?name=goofy.app&rr_type=A
这里错误就很明显了,DNSSEC validation failure
,DNSSEC 验证失败。
关掉 DNSSEC 验证后,可以正确解析:
点开解析失败结果中的链接,可以看到更详细的解析过程:https://dnsviz.net/d/goofy.app/dnssec/
可以看到这里 DNSSEC 有报错。
https://dnssec-analyzer.verisignlabs.com/goofy.app 的结果也类似。
问题解决
DNS 运维同学帮忙看了一下 DNS 管理后台,里面有一个不知道哪里来的 sha256 的 key,删除后问题解决
All Green!👏🏻👏🏻👏🏻
复盘分析
发生了啥?
一句话解释:DNSSEC 配置错误导致全球大部分 DNS 服务器都丢弃了解析结果,解析失败。
那为什么之前只在中国大陆能解析,而境外 DNS 全军覆没?
因为中国大陆 DNS 服务器绝大多数都关闭了 DNSSEC 校验 即使 DNSSEC 配置歪了,只要不校验就不会丢弃结果 这是一个不幸的巧合,负负得正 而海外 DNS 基本上都默认开启了 DNSSEC 校验,所以国际(几乎)清一色解析失败 少数海外 DNS 没开 DNSSEC 校验,所以恰巧能解析
那具体是哪里配坏了?
域名的DS
记录中配置了一条错误的 Hashed KSK(SHA-256 key),导致 DNSSEC 信任链被破坏。
这条错误的记录可能是在我们把域名从最开始的托管方 get.app 处迁移到目前 DNS 时候一并迁移过来的。
而删除这条DS
记录等同于告诉下游 resolver 这个域名不需要 DNSSEC 校验,所以删了就好了。
📌小知识:
DNS 的 DS 记录(Delegation Signer) 是 DNSSEC 信任链的一部分,用于把每一层域名的 NS 串联起来(与 HTTPS 证书链原理类似)
排查过程能否更有效?
可以:
一开始就可以用 https://dns.google 测试,可以直接发现问题 其实 dig 命令中一开始就返回了SERVFAIL。而根据DNSSEC的标准,这就是DNSSEC验证失败的返回值。
有没有考虑过其他修复方案?
有:
尝试本地编辑 hosts 文件 治标不治本,而且*.goofy.app多如牛毛,不可能全加上 在纯内网 DNS 解析 运维同学表示.app是一个新的顶级域,需要单独支持,代价太大 开启 DNSSEC 并正确配置 理论上可行,但是由于 DNS 递归请求到 .app 的 NS 需要跨境,要是签名过的请求被干扰则小概率导致解析失败。 先跑起来再说
扩展阅读:DNSSEC 工作原理
DNSSEC 如何运作 https://www.cloudflare.com/zh-cn/dns/dnssec/how-dnssec-works/ DNSSEC 原理和分析 https://blog.thecjw.me/?p=1221 保护网站访问安全--阿里云 DNS 正式支持 DNSSEC https://zhuanlan.zhihu.com/p/107552714