XuLaLa.Tech

首页客户端下载Windows 使用V2Ray 教程SSR 教程Clash 教程

浅谈在科学上网代理环境中的 DNS 解析行为

2025.04.20
机场加速器梯子推荐:

优质SS/SSR/Trojan/Xray/V2Ray机场推荐 | IPLC/IEPL专线加速器梯子推荐 | 解锁奈飞Netflix/HBO/Hulu等国外流媒体

虽然 Fake IP 这个概念早在 2001 年就被提出来了,

但是到 Clash 提供 fake-ip 增强模式以后

,依然有很多人对 Fake IP 这个概念以及其作用知之甚少。

不使用代理

如果在不使用任何代理的情况下,打开一个没有命中 DNS 缓存的网站(比如 blog.skk.moe)的时候,浏览器和操作系统大概会执行这么一些操作:

以上是打开一个网页常见的 DNS 解析流程。

对于其它非 HTTP 的 TCP 连接(比如 SMTP)也都差不多是这个流程——由于 TCP/IP 的协议特性,在应用发起 TCP 连接时,会先发出一个 DNS question(发一个 IP Packet),获取要连接的服务器的 IP 地址,然后直接向这个 IP 地址发起连接。

设置代理并使用直连

现在,我们在应用程序(比如我们的浏览器、或者其它应用)中设置了代理,但是这个代理不涉及到任何远端服务器(直连模式)。之前由于获取解析结果是浏览器在操作,而大部分浏览器都会选择调用系统的 getaddrinfo 方法,因此如果你想要在 DNS 上做一些黑魔法就只能在操作系统层面实现。

比如在本机或者别处架设个带黑魔法的 DNS 服务器,然后你系统中设置使用这个 DNS 服务器。

现在 DNS 解析是由代理客户端执行,因此在代理客户端上就可以实现一些黑魔法。
比如 Surge 自己实现了一个 DNS Server 可以并发向多个上游同时发起查询、
比如 V2Ray 可以实现不同域名的查询分流,等等。
当然代理客户端也可以使用操作系统的 getaddrinfo 方法。

设置代理并将流量转发到远端服务器

现在在上一步的基础之上,我们为代理服务器设置了一个远端服务器,这个代理会使用 某种协议 和远端服务器通信,并且这种协议和 SOCKS5 一样支持将域名封装在传输中。浏览器和代理客户端之间依然使用 SOCKS5 通信。

这一次,不论是代理客户端还是你的浏览器都没有进行 DNS 解析,DNS 解析是在远端服务器上进行的。

因为某种协议支持封装域名,然后这一次和 blog.skk.moe 连接的是远端服务器,考虑到针对 CDN 优化,DNS 解析自然需要在远端服务器上执行。

现在我已经介绍了通过代理直连和通过代理发送给远端服务器了。但是毫无疑问,我相信本文所有的读者自己使用的上网方式都不会是全面直连或者全面代理。

设置代理并使用 IP 规则和域名规则进行分流

分流是一个麻烦事。一般情况下,你可能会需要使用域名进行分流(不论是白名单还是黑名单)。不过更多情况下你会使用到基于 IP 的规则来进行分流。

先来看第一个例子:使用域名规则进行分流。
现在来看第二个例子:使用 IP 规则分流。
使用 IP 规则分流,前提首先你得有一个 IP 拿来比较。所以代理客户端必须先进行一次 DNS 解析。使用什么方法进行 DNS 解析并不重要,之前已经说过代理客户端甚至可以使用自己的黑魔法,而我们只需要关心最终代理客户端拿到了一个 IP 并且可以用于规则判定。

此时需要注意的是,虽然代理客户端获得了一个 IP,但是你只有在直连的时候,代理客户端可能(并且基本上都会)复用这个 IP;如果是将流量交给远程服务器,由于 某种协议 支持封装域名,此远程服务器拿到的还是域名不是 IP、还需要进行一次解析。也就是说,远端服务器连接的 IP 与 代理客户端解析得到的 IP 毫无关系。


使用 redir / tun2socks 实现全局流量经过代理

在开始之前,我们先复习一下 TCP/IP 协议怎么说的——「在应用发起 TCP 连接时,会先发出一个 DNS question(发一个 IP Packet),获取要连接的服务器的 IP 地址,然后直接向这个 IP 地址发起连接」

全局流量代理可能会出现在路由器上或者 TUN/TAP 型的支持全局代理客户端上。用户不再主动为每个应用程序设置代理。此时应用程序是不会感知到代理客户端的存在,它们会正常的发起 TCP 连接,并且由于 TCP/IP 协议,在拿到 DNS 解析结果之前,连接是不能建立的。

如果代理客户端需要按照域名进行分流
一般会在第 6 步代理客户端解析出一个 IP 或者第 9 步代理客户端拿到域名以后。
FancySS、KoolSS、SSTap 的流程大抵都是如此。

和应用程序直接将流量封装成 SOCKS5 大有不同,在类似于透明代理的环境下浏览器和其它应用程序是正常地发起 TCP 连接。

因此除非得到一个 DNS 解析结果,否则 TCP 连接不会建立;代理客户端也会需要通过这个 DNS 查询动作,才能找到之后的 TCP 连接的域名。

你大概能够发现,浏览器、应用程序直接设置 SOCKS5 代理的话,可以不在代理客户端发起 DNS 解析请求就能将流量发送给远端服务器;而在透明代理模式下,不论是否需要 IP 规则分流都需要先进行一次 DNS 解析才能建立连接。

有没有办法能像直接设置 SOCKS5 代理一样省掉一次 DNS 解析呢?有!

在 redir / tun2socks 中使用 Fake IP

Fake IP 的定义出自 RFC3089。这个 RFC 定义了一种新的将 TCP 连接封装成 SOCKS 协议的方法。

有了 Fake IP,代理客户端无需进行 DNS 解析。最后不论是浏览器、代理客户端还是远端服务器都不会去和 Fake IP 进行连接,因为在代理客户端这里就已经完成了截获、重新封装。

即使按照域名规则分流,代理客户端都没有进行 DNS 解析的需要。只有在遇到了按照 IP 进行分流的规则时,代理客户端才需要进行一次解析拿到一个 IP 用于判断。即便如此,这个 IP 只用于分流规则的匹配,不会被用于实际的连接。

FancySS 和 Surge / Clash 的区别

FancySS 是使用的 redir
Surge 的增强模式使用的是 Fake IP
Clash 的增强模式既有 redir-host 也有 Fake IP。
首先把 FancySS 等路由器上常见的代理客户端和 Clash 的 redir-host 分为一类,Surge 的增强模式和 Clash 的 fake-ip 模式分为另一类。

路由器上常见的代理客户端一般内置了 dns2socks、dnscryp-proxy、PCap_DNSProxy 等等 DNS 方案、也支持按照一定的规则进行分流,但是都是用于答复应用程序的 DNS question 使其建立 TCP 连接的,除非直连,否则通过这些 DNS 方案拿到的解析结果的 IP 并不会被用上。

大部分路由器上的代理客户端,DNS 解析请求都是通过路由器本机发出(或转发到单一远端服务器进行解析),因此解析结果只能说「至少能用」(不一定是有 CDN 优化的,甚至有可能会有 DNS 污染),如果流量不经过代理客户端直接发往这些 IP 地址,一般也不会影响浏览器、应用程序的正常使用。因此路由器上的代理客户端可以实现通过 iptables 控制让某些端口、某些设备的流量不经过代理客户端。

而在 Fake IP 模式下,浏览器、应用程序都是对 Fake IP 发起连接,如果没有代理客户端对连接进行重新封转,那么这部分流量就不能被发往真实的目的 IP,因此所有流量都必须经过代理客户端,而根据端口、设备的分流就需要由代理客户端自己实现。

如果操作系统或者浏览器缓存了 DNS 解析结果

之前的透明代理的两个例子中,我们都假定浏览器和操作系统都没有缓存 DNS 解析结果。但是,如果操作系统或者应用程序缓存了 DNS 解析结果会发生什么?

我在这里留几个问题给大家思考一下:

如果使用了 Fake IP,代理客户端不论域名是否真实存在都会返回一个 Fake IP 给浏览器,那么浏览器在试图访问一个不存在的域名时,错误信息应该是什么样的?会不会出现 DNS 解析失败的错误信息?

如果操作系统或者浏览器缓存了 Fake IP,但是代理客户端中 Fake IP 和域名的映射表丢失以后,会出现什么状况?可能会出现什么错误信息?

第二个问题很有趣。因为如果你找到了第二个问题的答案,你就会意识到 Clash 在 Fake IP 模式下偶发的无法上网的原因了。

参考资料

HTTP 代理原理及实现(一) – 我的文章中举得都是 SOCKS5 的例子,如果想了解一下在 HTTP 代理中流量是如何被封装的,可以看看屈屈的这篇博客

Surge 原理与实现 – Surge 开发者写的 Surge 早期版本的工作原理,可以了解一下 Surge 是怎么处理各种协议的流量的

漫谈各种黑科技式 DNS 技术在代理环境中的应用 – Kitsunebi 开发者写的文章,详细地介绍了在不同的 V2Ray 配置下的 DNS 行为,同时还有对移动端网络栈的一些介绍

© 2010-2022 XuLaLa 保留所有权利 本站由 WordPress 强力驱动
请求次数:69 次,加载用时:0.665 秒,内存占用:32.19 MB