最近我在访问一个论坛:www.ai2moe.org 的时候发现访问异常,排查后发现是 DNS 解析错误。
我平常用的 223.5.5.5 和 119.29.29.29 的 UDP DNS ,跑在 openclash 上。 然后我用把 openclash 关掉,在软路由上用 dig 和 nslookup 进行测试,测试结果如下:
详细结果如下四图: 223.5.5.5 测试 dig 正常而 nslookup 异常: https://img.chkaja.com/b98e8e559e1bfa8f.png
114DNS 测试 nslookup 正常: https://img.chkaja.com/ae9cab6d9b411af7.png
114DNS 测试 dig 正常: https://img.chkaja.com/9a0b19830aae75b9.png
运营商 dig 正常: https://img.chkaja.com/44e034a3964b1f20.png
运营商 DNS nslookup 正常: https://img.chkaja.com/42ac2f962d94a18e.png
并且根据此网站结果可得 223.5.5.5 解析是没有污染的: https://dig.ping.pe/www.ai2moe.org:A:223.5.5.5
而且运营商 DNS 解析正常说明这个问题也不是 DNS 劫持,不然直接用运营商 DNS 也无法访问才对。
然后我又测试了下换成阿里的 DoH 就又可以正常解析了。。玄学问题了。
求教坛友们这可能是出在什么问题上?实在排查不出来了。
1
Tianao 288 天前 12
权威解析给这个 CNAME 配的 A 记录太多了,dig 在请求的时候携带了 UDP payload size (比如我的 macOS 的默认是 4096), 所以 223.5.5.5 会直接使用 UDP 返回这个八百多字节的递归解析结果; nslookup 默认没有在请求里携带 UDP payload size 信息,223.5.5.5 默认按 512 对待,返回了 Truncated flag 置位,让客户端去用 TCP 再请求一次。
至于楼主的 nslookup 为什么没有成功通过 TCP 解析,就要检查 nslookup 的实现、DNS 客户端的配置和 TCP 的联通性了(比如 telnet 223.5.5.5 53 )。我的 macOS 的 nslookup 是会在这样输出之后正确显示最终的 A 记录的: nslookup www.ai2moe.org 223.5.5.5 ;; Truncated, retrying in TCP mode. 至于为什么阿里的 DoH 没问题,因为 DoH 和使用 53 端口的 DNS 是两个完全不同的协议,不存在这个默认最大 512 字节的限制。 至于为什么 119.29.29.29 和 114.114.114.114 和运营商 DNS 使用相同的 nslookup 和相同的 DNS 协议也没问题,因为它们直接无视了来自 DNS 客户端的 DNS 请求中携带的 UDP payload size, 偷偷把超长递归解析结果裁剪到不超过 512 字节(在本例中,是通过随机丢弃 A 记录的方式)通过 UDP 直接返回了。 |
2
CharonVIII OP @Tianao 大佬太厉害了,分析非常详细,感觉给我开辟了新大陆!
我刚才测试了下 telnet 223.5.5.5 53 ,显示空白页面,应该代表对 223.5.5.5 的 53 端口的 TCP 连接是通畅的。 然而我用电脑又试了下 nslookup www.ai2moe.org 223.5.5.5 ,结果显示: ———————————————————————— nslookup www.ai2moe.org 223.5.5.5 服务器: public1.alidns.com Address: 223.5.5.5 DNS request timed out. timeout was 2 seconds. *** 请求 public1.alidns.com 超时 ———————————————————————— 还是感觉原因不明啊。 其实这种事情也真是我上了这么多年网第一次遇到,太异常了。照理说 A 记录太多的网站肯定不止这一家... |
3
Tianao 287 天前 1
@CharonVIII #2 我测试下来,是 Windows 上的 nslookup 实现在通过 UDP 收到 Truncated 置位的应答、转而使用 TCP 并完成 TCP 的 3-way 握手后,会紧接着(也就是在这个 TCP 连接的第 4 个包)发送一个带有 PSH 置位的、仅有 2 bytes 的 TCP payload 的 TCP segment, 我不知道这个 2-byte 载荷的意义是什么(但猜测是用作一个什么出于性能或可用性目的的什么前导?),然后紧接着就收到了来自 223.5.5.5 的 TCP RST (我也不知道 223.5.5.5 为什么要 reset, 但是我猜测是 223.5.5.5 收到了这个不明所以的 TCP 分段,出于节省资源开销/防攻击的目的主动 reset 掉了这个 TCP 连接),然而按照 Windows nslookup 的预期(这一「预期」我使用了其他使用 Windows nslookup 可以正常解析的 DNS 服务器进行了验证),这第 5 个包本应是来自服务端的正常 ACK, 然后 nslookup 再紧接着发送可以和第 4 个包进行 TCP segment reassemble 从而组成一个完整 DNS 请求的 TCP 分段,但是此时 TCP 连接已经被 223.5.5.5 给 reset 掉了。
目前的判断:Windows 的 nslookup 实现和 223.5.5.5 的某些策略性表现在 TCP 解析时存在兼容性问题。 目前的建议:在 Windows 上,在 PowerShell 中使用 Resolve-DnsName 能够获得比 nslookup 更接近 Windows DNS 客户端真实表现的测试结果。换言之,在 Windows 上,仅是 nslookup 失败不代表浏览器等真实用户访问行为调用的 DNS 解析也会失败。 「照理说 A 记录太多的网站肯定不止这一家...」 对于一般 web 服务的 GSLB, 国内一般都是地理+运营商分区解析,每个分区最终的 A/AAAA 记录真的远没这么多;对于国际化服务,虽然会使用 anycast, 但是 ADNS 会控制每次返回给 recursive DNS 的权威结果数量,也不会一次性返回好几十个 anycast 地址的 A 记录。 |
4
CharonVIII OP @Tianao 感谢分析,我这边还没测试过直接在 windows 上设置 DNS 为 223.5.5.5 能否正常访问网站(估计不行),但是我测试过由跑在 openwrt 上的 openclash 来代为用 223.5.5.5 解析 DNS 的话是解析结果错误的。
看你的原因分析感觉非常有道理,确实如果是这个原因的话就说得通了。那么最好的办法要么在阿里、腾讯 DNS 之外再加个 114DNS 或者运营商 DNS ,要么就用阿里和腾讯的加密 DNS 。 我现在的解决方案就是 openclash 用阿里和腾讯的 DoT 来规避 UDP DNS 的 payload size limit 的问题(当然用 DoH 也行),目前情绪稳定。 |
5
jinqzzz 287 天前
关于为什么没有自动 fallback 到 tcp ,我指出两点可能的存在的线索,仅供楼主参考:
首先,看楼主是在 openwrt 上边测试,openclash 可能劫持了你发向 wan 的 dns 请求 其次,clash dns 服务器是不支持 tcp mode 的 |
6
jinqzzz 287 天前 1
dig 命令可以测试 dns 服务器是否支持 tcp ,比如 dig +tcp @127.0.0.1 -p 1053 www.baidu.com
|
7
465456 287 天前
同时使用运营商 DNS ,和 DNS-over-QUIC 就没问题
|
8
CharonVIII OP @jinqzzz 我测试都是关掉 openclash 再测试的。
刚才测试了下关闭 openclash 的情况下在 openwrt 上用命令 dig +tcp @223.5.5.5 -p 53 www.ai2moe.org ,返回结果正常,说明 openwrt 上是可以进行 TCP 的 UDP 查询的,得出结论:223.5.5.5 的 TCP 查询是没问题的。 我又把 PC 的 DNS 手动设置为 223.5.5.5 后测试访问 www.ai2moe.org ,结果竟然可以正常访问。而打开 openclash ( openclash 只设置一个 223.5.5.5 的 Nameserver )就无法正常访问 www.ai2moe.org 。 所以就是说 223.5.5.5 没问题,我电脑自己不管是用运营商 DNS 还是 223.5.5.5 访问网站都没问题,问题就出在过了 openclash 内核以后就寄了。。分析下来这可能更像是 openclash 内核的问题,我去反馈下看看。 谢谢各位大佬们的思路! |
9
fredcc 286 天前
|
10
CharonVIII OP |
11
465456 285 天前
@CharonVIII 为啥一定要用 udp ,用 DoH/DoT 不香吗?
|
12
johnjiang85 262 天前
这个还需要看 dns 服务端对 tcp 请求的兼容性问题,不是所有版本的 windows 的 nslookup 都有这个,只是部分版本的 nslookup 有这个问题。
当客户端发起 tcp 请求的时候,tcp 的 dns 请求是由 2 个字节的长度包+实际的 dns 请求组成的,部分较旧版本的 nslookup 会把两个部分分开发送,而 dig 和较新版本的 nslookup 会将两部分一起发送。 当 dns 服务端对 tcp 的 dns 请求数据不进行分段接收数据的支持处理的话,比如只支持一次性收到 2 字节的长度包,和完整的后续 dns 请求包,那么这些老版本的 nslookup 分 2 次发送的数据包,在 dns 服务端收到的数据和前 2 字节的数据包长度不匹配,就会校验失败,然后关闭 tcp 连接。 如果需要兼容此类客户端,需要在 dns 服务端进行修改,支持 tcp dns 请求的时候,没有一次性收到完整数据的场景,即需要自己对客户端的 tcp 连接和已收到部分数据做额外的管理,会复杂一些。 |
13
johnjiang85 262 天前
可以使用老版本 nslookup 或 nc 来模拟分段发送 dns 请求
|
14
johnjiang85 262 天前
{ echo -n -e "\x00\x2b";sleep 1; echo -n -e "\x69\x6f\x01\x20\x00\x01\x00\x00\x00\x00\x00\x01\x0a\x6c\x6f\x76\x65\x6c\x79\x70\x69\x6e\x67\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00"; } | nc 1.12.0.1 53
nc 模拟在同一个 tcp 连接中分段发送 DNS 请求的示例,此处是向 1.12.0.1 发送 tcp dns 请求域名 lovelyping.com 的 A 记录 |