Surge 原理与实现

为了方便各位购买了 Surge 的用户更好的理解 Surge 的功能,能够自己通过灵活修改配置以应对不同的需求,我写了这篇中文的 Surge 原理与实现供各位参考。

从 Surge 的几大核心组件分别说起吧:

1. Surge Proxy Server

这是 Surge 最核心的部分,用于处理所有的 HTTP/HTTPS 请求。用 Proxy 去处理请求而不是用 TUN,有很多原因,主要是因为 TUN 是工作在 IP Layer 的:

  • Proxy 可以直接收到包含域名 / URL 的请求,从而使基于域名的规则过滤成为可能(甚至 URL,之后版本可能考虑加入支持)
  • Proxy 可以省略不必要的 DNS 请求,对首次访问的速度提升相当明显
  • Surge 的 Proxy 支持全局的 HTTP Connection Keep Alive 机制,极大的减少了 TCP 握手产生的开销(跨应用间也能共享一个 TCP Connection,但由于内存限制在 iOS 版本上超时时间很短,之后 Mac 版本上的效果会明显一些)
  • 准确的记录下每个请求的 header 和 body(从 TCP 层面直接抓,可能会有误)
  • 使得之后的高级功能(如修改 header,rewrite URL)成为可能
  • 减少了不必要的 IP Packet 相关开销
  • 这样 Surge iOS 版本与 Mac 版本可以共享核心代码

这是 Surge 中最复杂的组件,基本上等同于一个不带 cache 的 squid,其中的难点一方面是调度问题,另一方面是怎么样去判断一个 HTTP 请求是否完成(比如 chunked transfer encoding),本身 HTTP RFC 在这方面就有非常多的细节问题,再加上很多自制的 HTTP Server 不是特别的遵守规范,所以只能通过大量的时间去积累经验完成。

2. DNS Client

最早的版本中,Surge 也是使用 getaddrinfo 这类的系统调用去进行 DNS 解析的,但是后来越来越不能满足需求,所以就又造了个轮子,有这些好处:

  • 可以完全自定义 upstream DNS 服务器地址,无视系统设置
  • 可以并发的向多个 DNS 服务器发出 question
  • 可以自定义超时和重发的策略
  • getaddrinfo 等方法本身不支持 cache
  • 为之后的 Local DNS Map 功能提供了基础

这部分的功能差不多是个 mini 版本的 dnsmasq 吧。由于是自己实现的,以后要做 TCP DNS 或者非 53 端口的支持都是很简单的事。

3. Surge TUN Interface

最早的版本没有这个组件,但有部分应用使用的是 HTTP/HTTPS 以外的 TCP 协议 (如 SPDY、IMAP),没有遵从代理设置,因此无法被 Surge 接管流量。为了解决这个问题,才加入了这个组件。

核心原理就是通过一个 Surge 内部的 TCP stack,将 IP Packet 中的 TCP 数据提取出来,再重新用 Proxy 进行请求(或者直接连接对应的服务器),再将返回的数据重新封装成 IP Packet。

正如前面提到的,用 TUN 处理请求会有一些问题,最大的问题是,由 TUN Interface 处理的流量,DOMAIN 相关的 Rule 会无效,除非使用了 force-remote-dns 选项。

这是由 TCP/IP 协议的特性所决定的,App 会先发出一个 DNS question,获取要连接的服务器的 IP 地址,然后直接向这个 IP 地址发起连接,所以有了第 4 个组件。

4. IP Layer DNS Forwarder

这个组件配合 TUN Interface 使用,会将收到 DNS 的 IP Packet,进行简单改动后直接转发给 upstream DNS。

但是在转发前,该组件会检查需要解析的域名,是否匹配上了带有 force-remote-dns 选项的规则,如果是,不进行转发,直接返回一个 240.1.x.x 的 fake IP。当 TUN Interface 收到一个发往 240.1.x.x 的包的时候,反向查出真正的域名是什么,然后直接以域名的形式转交给 Proxy,避免本地的 DNS 查询动作。

force-remote-dns 选项主要是为了解决有些域名在本地查询会有障碍的问题(如公司内网域名),然而因为返回了一个 fake IP,且 Surge 没有权限去强制清除系统或者应用的 DNS cache,所以在 Surge 关闭后可能导致一些问题,所以请谨慎的只给确实需要的域名开启这个选项。

其余还有一系列的 homemade 小组件(如各个协议的 client),就不一一描述了,之后想到什么再补充。

所以,看起来 $9.99 超值吧(大雾)