DNS 在代理中的解析行为
不使用代理情况下的 DNS 解析流程
浏览器和操作系统都有DNS缓存机制
- 浏览器从自身的 DNS 缓存机制寻找解析成果
- 解析失败,则通过系统的 getaddrinfo 方法向操作系统寻找解析成果
- 系统解析失败,则会根据系统设置的 DNS 地址向DNS服务器请求解析结果
设置代理并直连
场景:浏览器设置了 SOCKS5 代理,但没有远端服务器存在,此时浏览器不再需要从自己的 DNS 缓存中寻找 IP
- 浏览器直接将域名封装在 SOCKS5 协议中发往代理客户端
- 代理客户端从 SOCKS 流量中抽出域名,并设法解析。此时,代理客户端即可以使用系统的 getaddrinfo 方法,也可以使用自己实现的DNS解析方法
设置代理并将流量转发到远端服务器
场景:在上一步的基础上,代理会使用某种协议与远端服务器通信
- 浏览器直接将域名封装在 SOCKS5 协议中发往代理客户端
- 代理客户端从 SOCKS 流量中抽出域名
- 代理客户端使用某种协议将浏览器的 SOCKS 流量重组并发往远端服务器
- 远端服务器使用相同的某种协议解析并获得域名
- 远端服务器发起 DNS 解析请求解析域名(一般情况下使用系统的 DNS 解析方法)
该场景下,浏览器和代理客户端都没有进行 DNS 解析,而是由远端服务器进行解析。
设置代理并使用 IP 规则进行分流
- 浏览器将带有域名的 HTTPS 请求封装在 SOCKS5 流量之中发往代理客户端
- 代理客户端从 SOCKS 流量中抽出域名并进行 DNS 解析
- 代理客户端根据域名解析结果和 IP 规则,决定解析的 IP 是否需要走代理
- 如果不许要走代理,则执行 设置代理并直连 的剩余操作
- 如果需要走代理,则进行 设置代理并将流量转发到远端服务器 的剩余操作
使⽤ IP 规则分流,前提⾸先你得有⼀个 IP 拿来⽐较,所以代理客户端必须先进⾏⼀次 DNS 解析
只有在直连时,代理客户端才基本会复用这个 IP ;如果将流量交给远端服务器,那么远端服务器拿到的还是域名而不是 IP ,还需要再进行一次 DNS 解析。即 远端服务器连接的 IP 与代理客户端解析得到的 IP 毫⽆关系
设置代理并使用域名规则进行分流
- 浏览器将带有域名的 HTTPS 请求封装在 SOCKS5 流量之中发往代理客户端
- 代理客户端从 SOCKS 流量中抽出域名
- 代理客户端将域名与规则列表开始比较,决定是否需要走代理
- 如果不需要走代理,则执行 设置代理并直连 的剩余操作
- 如果需要走代理,则进行 设置代理并将流量转发到远端服务器 的剩余操作
除非域名命中直连规则,否则代理客户端无需进行 DNS 解析
使用 redir/tun2socks 实现全局流量经过代理
场景:对于不⽀持设置 SOCKS/HTTP(S) 代理的软件,Surge/Clash 等软件⼀般选择通过 TUN/TAP 或转发 redir 透明⽹关接管⽹络请求,从⽽拿到原始的 TCP/IP 连接。⽤户不再主动为每个应⽤程序设置代理。此时应⽤程序是不会感知到代理客户端的存在,它们会正常的发起 TCP 连接。由于 TCP/IP 协议,在拿到 DNS 解析结果之前,连接是不能建⽴的
redir : 一个简单的 TCP 端口重定向工具。它可以将网络流量从一个端口重定向到另一个端口或 IP 地址
tun2socks :可以将 TUN 接口上的 IP 流量转发到 SOCKS5 代理服务器上
TUN (网络隧道)接口:模拟一个三层(网络层)设备,即一个网络接口卡(NIC),它处理的是 IP 数据包。它的工作方式类似于一个虚拟的点对点设备,通常用于创建虚拟点对点连接
TAP (网络 tap)接口:模拟一个二层(数据链路层)设备,即一个以太网设备,它处理的是以太网帧。TAP 接口工作方式类似于一个虚拟交换机端口,用于创建虚拟局域网
- 浏览器从自身的 DNS 缓存机制寻找解析成果
- 解析失败,则通过系统的 getaddrinfo 方法向操作系统寻找解析成果。在系统的⽹络设置之中有设置上游 DNS 地址。代理客户端可能会修改系统设置中的 DNS 到 127.0.0.1 或者别的 IP ,也可能保留⽤户之前的设置。但不论如何,这个设置最终会使操作系统向代理客户端发起 DNS 请求
- 操作系统发出的 DNS 解析请求经过代理客户端并最终被截获
- 代理客户端可以将这个DNS解析请求原样发出去者使用⾃⼰实现的DNS解析方法,最终得到一个解析结果
- 代理客户端返回解析结果,操作系统将这个解析结果返回给浏览器
- 浏览器对这个解析结果的 IP 建⽴⼀个 TCP 连接并发送
- 这个 TCP 连接被代理客户端截获。由于之前代理客户端进⾏的 DNS 解析请求这⼀动作,代理客户端可以找到这个 IP 的 原来的⽬标域名
- 如果是⽀持 redir 的代理客户端,那么代理客户端就会直接将域名和 TCP 连接中的其它数
据封装成某种协议发给远端服务器;或者封装成 SOCKS5 后交给⽀持 SOCKS5 的代理
客户端
在设置透明代理的情况下,浏览器无需将流量封装成SOCKS5,而是正常地发起 TCP 连接
浏览器设置 SOCKS5 代理的话,可以不在代理客户端发起 DNS 解析请求就能将流量发送给远端服务器;⽽在透明代理模式下,不论是否需要 IP 规则分流都需要先进⾏⼀次 DNS 解析才能建⽴连接
TUN/TAP 接管DNS解析带来的问题
- DNS 污染:由于特殊的⽹络环境,通过你本机直接进⾏ DNS 解析得到的结果可能不可靠
- CDN 优化:如果要访问的⽬标⽹站使⽤了CDN,但却在本机进行DNS解析,则得到的IP可能并不是距离你的远端服务器最近的CDN节点
- 如果软件决定将域名转发给远端代理服务器,那么本机解析的IP地址没有任何作用,造成了额外的一次解析时间
在 redir/tun2socks 中使用 Fake IP
使用 Fake IP,代理客户端可以省掉一次DNS解析。其原理是代理客户端先不执行查询动作,而是丢一个 Fake IP 给浏览器,让其可以立刻建立连接
- 浏览器从自身的 DNS 缓存机制寻找解析成果
- 解析失败,则通过系统的 getaddrinfo 方法向操作系统寻找解析成果
- 在系统的⽹络设置之中有设置上游 DNS 地址。代理客户端可能会修改系统设置中的 DNS 到 127.0.0.1 或者别的 IP ,也可能保留⽤户之前的设置。不论如何,这个设置最终会使操作系统向代理客户端发起 DNS 请求
- 操作系统发出的 DNS 解析请求会经过代理客户端并最终被截获
- 代理客户端从解析请求中获得域名,从 Fake IP 池中选取⼀个 IP 建⽴映射
- 代理客户端返回 Fake IP ,操作系统拿到了这个 Fake IP 并返回给浏览器
- 浏览器以 Fake IP 为⽬标发起⽹络请求
- 该 TCP 连接被代理客户端截获。代理客户端抽取出 Fake IP 并反查出这个 TCP 连接中对应的域名
- 有了 TCP 连接和域名,代理客户端可以轻易地将其使⽤ SOSCKS5 或者 某种协议 进⾏封装
使用 Fake IP 后本机仍会进行DNS解析的情形
- 遇到了按照 IP 进⾏分流的规则时,代理客户端才需要进⾏⼀次解析拿到⼀个 IP ⽤于匹配分流
- 目标域名命中直连策略,此时代理客户端需要得到真实的目标IP
参考
[1]. 浅谈在代理环境中的 DNS 解析行为
[2]. 简析代理客户端导致的远端服务器流媒体 DNS 解锁失效的可能原因
[3]. 我有特别的DNS配置和使用技巧