Surge 中文白皮书 (草稿第二部分,连接类型与处理)

处理

在对连接进行处理之前,首先需要对被接管的网络连接进行分类,目前版本主要有四种类型:

1. HTTP 连接:由 Surge HTTP 代理服务接管的连接。在 Dashboard 中会显示请求的完整 URL 和 HTTP 方法名(GET、POST、HEAD、PUT、DELETE、TRACE、OPTIONS 等)
2. HTTPS 连接:由 Surge HTTP 代理服务接管的,且使用 CONNECT 方法转变为 TCP 数据流的连接。在 Dashboard 中会显示请求的目标主机名和端口号,方法显示为 HTTPS。
3. TCP 连接:由 Surge VIF、Surge SOCKS5 代理服务接管的 TCP 连接。在 Dashboard 中会显示请求的目标主机名和端口号,方法显示为 TCP 和 SOCKS。
4. UDP 会话:由 Surge VIF 接管的 UDP 数据包,发往同一个地址和端口号的数据包构成了一个 UDP 会话。

对于第一类连接,可使用 Surge 的各项能力对请求进行修改、转发和抓取。对于第二类连接,在使用 MITM 进行解密后即暴露为标准 HTTP 连接,也可以使用完整的能力。对于第三类连接,一般情况下只能进行转发。

  1. HTTP

上述第三类连接也有可能是一个 HTTP 连接,但是由于 Surge 并没有方法准确确认,所以不会主动使用 HTTP 引擎去进行处理,否则会由于无法处理导致连接中断。

有用户曾建议可对数据包进行识别去自动判断具体协议,出于以下两个原因 Surge 并没有这样的设计:

1. 虽然绝大多数基于 TCP 的协议都是由客户端发出第一个数据包,但是按照 TCP 协议标准这不是必须的,像 Telent 等少数协议就是由服务端先发出第一个数据包。

若 Surge 想要通过对数据包进行识别判断连接是否为 HTTP 协议,须等待客户端发出第一个数据包,如果遇上了服务器首先发数据包的协议,则会造成客户端一直等待。(虽然可以通过加入等待超时的方式去处理,但是很不优雅)

2. 存在着一些自定义协议,会发出带有 HTTP 请求头的数据包,但是后续数据并不按照 HTTP 规范进行,从 TCP 协议标准来说这是完全可接受的,但是如果交由 Surge HTTP 引擎处理则会引发异常。

所以,Surge 将选择权交给了用户,提供了 force-http-engine-hosts 参数,对于出现在该参数中的主机名,即使它是一个由 Surge VIF 或 Surge SOCKS5 所接管的第三类连接,也将强制使用 HTTP 引擎去进行处理,所有 HTTP 高级功能都可以被使用。但是如果该连接并非一个使用 HTTP 协议的连接,则会造成连接中断。

另外,如果 Surge 在一个 TCP 连接中发现了 HTTP 请求头或响应头,会在备注中标注:”HTTP request header found in the raw TCP connection.” 和 “HTTP response header found in the raw TCP connection.”,并提取请求和响应头,供简单分析。请注意该功能只会分析 TCP 数据流的双向首个数据包,由于 HTTP 协议通常会进行 TCP 连接复用,所以该功能看不到后续的 HTTP 请求,还是需要手动配置 force-http-engine-hosts 参数去开启完整的抓取。

2. HTTPS

由 HTTP 代理服务所接管的,使用 CONNECT 方法的连接,Surge 会判定为 HTTPS 连接,但其实该连接也可能是一个除 HTTPS 外的其他 TCP 协议连接。

所以,默认情况下 Surge 对此类连接仅进行单纯的 TCP 数据流转发,如果目标主机名出现在 [MITM] 的 hostname 配置中,Surge 则会进行 HTTPS 解密,关于 HTTPS 和 MITM 的具体说明请参见后续章节。

对 TCP 连接进行 MITM 解密

当配置 [MITM] 段中的 tcp-connection 选项开启时,如果第三类连接的主机名出现在 [MITM] 的 hostname 配置中,Surge 也会进行 HTTPS 解密,并交由 HTTP 引擎处理,可开启所有高级功能。

但是如果该连接并非 HTTPS 协议,则会造成连接中断。

Surge 所有的修改功能都是为 HTTP 协议所设计,未解密的 HTTPS 连接和 TCP 连接将会跳过该步骤。

目前 Surge 提供的修改能力包括:

  • 重定向(URL Rewrite,Map Remote)
  • 本地文件映射(Map Local,API Mock)
  • 请求头和响应头修改(Header Rewrite)
  • JavaScript 脚本修改

其中脚本修改的功能最为强大,可通过脚本间接实现其他几项能力。但是由于脚本编写繁琐,运行时开销略大,简单需求还是应该通过其他方式实现。

HTTP 相关词汇中英翻译对照

  • 请求:Request
  • 请求头:Request Header
  • 请求体:Request Body
  • 响应:Response
  • 响应头:Response Header
  • 响应体:Response Body
  • 头字段:Header Field

重定向(URL Rewrite,Map Remote)

Surge 提供两种进行 HTTP 重定向的实现方式:

1. 请求头修改:通过直接修改请求头内容实现,客户端程序对本次重定向无感知。为了保证重定向后的行为正确,URL 被修改后,Surge 会自动使用 URL 的主机名部分覆盖请求头的 Host 字段。脚本进行重定向时不会进行该行为。

2. 返回 302、307 响应:直接向 HTTP 连接返回一个状态码为 302 或 307 的完整 HTTP 响应,客户端需要支持 HTTP 重定向。

本地文件映射(Map Local,API Mock)

根据用途的不同,该功能在不同的软件中有不同的名称,如 Map Local,API Mock 等。但是实际指的都是同一类型的功能,即不进行真正的 HTTP 请求,直接返回一个预设的响应。

Surge 会根据本地文件的扩展名自动选择合适的 Content-Type 作为 HTTP 响应头字段,也可以自定义响应头字段覆盖该行为。

请求头和响应头修改(Header Rewrite)

该功能用于简单的修改请求头的字段,支持 add、del、replace 三种操作。

当使用 add 操作时,如果该字段名已经存在,会追加一个同名字段,这种行为是被 HTTP 标准所允许的,服务端应该将多个同名字段拼接后进行理解。但是由于部分 HTTP 服务器未正确遵循该规范,除非有特殊的需求,一般建议使用 del 和 add 组合操作,先删再加。

JavaScript 脚本修改

脚本修改提供最全面的修改能力,可以随意修改请求和响应的头字段和数据体,但是需要注意,目前 Surge 只支持对 UTF-8 编码的数据体进行脚本读取和修改。

关于脚本的详细使用方法请参见手册。

iOS Freelance Developer, Technical Advisor

iOS Freelance Developer, Technical Advisor