anytls 0.2.3

A proxy protocol that attempts to mitigate the TLS in TLS fingerprinting problem
Documentation
# AnyTLS 代码架构与协议实现详解


本文档详细解析 AnyTLS 的代码结构与核心协议实现细节。

## 1. 总体架构


AnyTLS 是一个基于 TLS 1.3 的隧道代理工具,旨在将 SOCKS5 流量封装在标准的 TLS 连接中。其核心设计理念是**多路复用 (Multiplexing)**,即在一条物理 TLS 连接(Session)上承载多个逻辑数据流(Stream)。

### 核心组件

*   **Client (`bin/client`)**: 本地 SOCKS5 服务器,负责接收用户请求,通过 TLS 连接转发给 Server。
*   **Server (`bin/server`)**: 远程 TLS 服务器,负责解包 TLS 流量并转发到目标网站。
*   **Session (`proxy/session/inner.rs`)**: 管理一条物理 TLS 连接,负责帧(Frame)的读写、分发和心跳维护。
*   **Stream (`proxy/session/stream.rs`)**: 代表一个逻辑连接(如一次网页请求),提供类似 `TcpStream` 的读写接口。
*   **Pipe (`proxy/pipe`)**: 用于 Stream 与 Session 之间的高效异步数据缓冲通道。

---

## 2. 客户端流程 (`bin/client/main.rs`)


### 2.1 入口与初始化

*   程序启动后监听本地 SOCKS5 端口(默认 1080)。
*   初始化 `Client` 结构体 (`proxy/session/client.rs`),配置连接池参数(空闲超时、最小空闲数等)。
*   **TLS 配置**: 使用 `rustls`,并配置了一个“危险”的证书验证器 `AllowAnyCertVerifier`,允许连接自签名证书的服务器。

### 2.2 SOCKS5 握手

当浏览器发起连接时:
1.  `handle_connection` 处理标准的 SOCKS5 握手(无需认证)。
2.  解析目标地址(IPv4/IPv6/Domain)。
3.  **建立隧道**: 调用 `client.create_stream()` 获取一个虚拟流 (`Stream`)。
4.  **发送目标地址**: 将 SOCKS5 请求中的目标地址直接写入 `Stream`5.  **数据转发**: 启动两个异步任务 (`c2p`, `p2c`) 在本地 TCP 连接和虚拟 `Stream` 之间双向拷贝数据。

### 2.3 连接池管理 (`proxy/session/client.rs`)

这是客户端的核心优化逻辑:
*   **复用策略**:
    1.  优先从 `idle_sessions` 池中获取空闲会话。
    2.  其次尝试复用活跃但负载较低(Stream 数 < 3)的会话。
    3.  最后才建立新的 TLS 连接。
*   **空闲回收**: `spawn_idle_waiter` 监控会话状态,当会话所有流关闭后,将其放回空闲池以备下次秒开。

---

## 3. 服务端流程 (`bin/server/main.rs`)


### 3.1 监听与接收

*   监听 TCP 端口(默认 8443)。
*   使用 `mkcert` 动态生成自签名证书。
*   **TCP 优化**: 开启 `TCP_NODELAY``TCP_KEEPALIVE`,确保低延迟和死链检测。

### 3.2 握手与鉴权

1.  **TLS 握手**: 建立标准 TLS 1.3 连接。
2.  **应用层鉴权**:
    *   读取前 34 字节:32 字节密码哈希 (SHA256) + 2 字节 Padding 长度。
    *   验证密码,失败则断开。
    *   读取并丢弃指定长度的 Padding 数据(用于混淆流量特征)。
3.  **会话创建**: 创建 `Session::new_server`,并传入回调函数处理新流。

### 3.3 目标连接

当 Session 收到新流请求 (`CMD_SYN`):
1.  触发回调,读取流中的第一个数据包(包含 SOCKS5 目标地址)。
2.  `TcpStream::connect` 连接目标网站。
3.  **数据转发**: 在目标 TCP 连接和虚拟 `Stream` 之间双向拷贝数据。

---

## 4. 核心协议实现 (`proxy/session`)


### 4.1 帧结构 (`frame.rs`)

所有数据在 TLS 隧道中都被封装为“帧”:
```
+------+------+--------+------+
| CMD  | SID  | LEN    | DATA |
+------+------+--------+------+
| 1B   | 4B   | 2B     | Var  |
+------+------+--------+------+
```
*   **CMD (1B)**: 命令类型 (SYN, PSH, FIN, HEART_REQUEST 等)。
*   **SID (4B)**: 流 ID,用于区分不同的请求。
*   **LEN (2B)**: 数据载荷长度。
*   **DATA**: 实际数据。

### 4.2 会话管理 (`inner.rs`)

`Session` 是协议的心脏,负责多路复用:
*   **读循环 (`recv_loop`)**:
    *   从 TLS 连接读取字节流。
    *   解析帧头,提取 `CMD``SID`    *   **分发**:
        *   `CMD_PSH`: 找到对应的 `Stream`,将数据写入其 `Pipe`        *   `CMD_SYN`: (服务端) 创建新 `Stream` 并触发回调。
        *   `CMD_FIN`: 关闭对应 `Stream` 的写入端。
        *   `CMD_HEART_*`: 处理心跳,保持连接活跃。
*   **写操作**:
    *   使用 `mpsc::channel` 接收各 `Stream` 发来的帧。
    *   通过 `tokio::io::split` 分离出的 `WriteHalf` 写入 TLS 连接。
    *   **关键优化**: 每次写入后强制 `flush()`,配合 `TCP_NODELAY` 消除缓冲延迟。

### 4.3 流抽象 (`stream.rs`)

`Stream` 模拟了标准的 `AsyncRead` / `AsyncWrite` 接口:
*   **写数据**: 将数据封装为 `CMD_PSH` 帧,通过 `frame_tx` 发送给 Session。
*   **读数据**: 从内部的 `PipeReader` 读取由 Session 分发来的数据。
*   **关闭**: 发送 `CMD_FIN` 帧。为防止死锁,发送操作在后台异步任务中执行。

### 4.4 管道机制 (`proxy/pipe/io_pipe.rs`)

为了解决异步读写中的死锁和数据竞争,实现了一个自定义的 `Pipe`:
*   **结构**: 包含一个 `mpsc` 通道(用于数据传输)和一个字节缓冲区(用于暂存未读完的数据)。
*   **死锁解决**:
    *   `read` 操作在等待数据时**不持有锁**    *   利用 `mpsc` 的关闭特性(Sender Drop -> Receiver Return None)来优雅地处理 EOF,确保所有缓冲数据被读完后再返回结束信号。

---

## 5. 关键技术细节总结


1.  **并发模型**: 使用 Tokio 的异步任务 (`tokio::spawn`) 处理每个连接和流,实现高并发。
2.  **死锁预防**:
    *   Session 的读写分离 (`split`)。
    *   Stream 发送控制帧(如 FIN)时的异步化。
    *   Pipe 读取时的锁释放机制。
3.  **性能优化**:
    *   **连接复用**: 减少 TLS 握手开销。
    *   **Zero Copy**: 在可能的情况下尽量减少内存拷贝(虽然 Frame 封装不可避免会有一次拷贝)。
    *   **即时发送**: 强制 Flush 避免 Nagle 算法和 TLS 缓冲带来的延迟。
4.  **健壮性**:
    *   **Keepalive**: 应用层心跳 + TCP 层 Keepalive 双重保障,快速检测死链。
    *   **优雅关闭**: 确保 Session 和 Stream 的状态在网络异常时能正确同步,防止僵尸连接。

---

## 6. 核心数据流向总结


以下图表展示了从用户发起请求到目标网站接收数据的完整流向:

```mermaid
sequenceDiagram
    participant User as User (Browser)
    participant C_Main as Client (Main)
    participant C_Stream as Client Stream
    participant C_Session as Client Session
    participant Network as TLS Network
    participant S_Session as Server Session
    participant S_Stream as Server Stream
    participant S_Main as Server (Main)
    participant Target as Target Website

    Note over User, C_Main: SOCKS5 协议
    User->>C_Main: 发送数据 (Plain)
    
    Note over C_Main, C_Stream: 写入虚拟流
    C_Main->>C_Stream: stream.write(data)
    
    Note over C_Stream, C_Session: 封装为帧 (Frame)
    C_Stream->>C_Session: frame_tx.send(CMD_PSH)
    
    Note over C_Session, Network: 加密并发送
    C_Session->>Network: TLS Write + Flush
    
    Note over Network, S_Session: 接收并解密
    Network->>S_Session: TLS Read
    
    Note over S_Session, S_Stream: 解析帧并分发
    S_Session->>S_Stream: stream.push_data(data) (写入 Pipe)
    
    Note over S_Stream, S_Main: 读取虚拟流
    S_Main->>S_Stream: stream.read(buf) (从 Pipe 读取)
    
    Note over S_Main, Target: 转发到目标
    S_Main->>Target: TCP Write
```

---

## 7. 多路复用 (Multiplexing) 原理


AnyTLS 使用单条 TLS 连接承载多个逻辑流(Stream),极大地减少了握手延迟并提高了传输效率。

```mermaid
graph LR
    subgraph Client_Side [Client Side]
        UA[User A] -->|Data| SA[Stream 1]
        UB[User B] -->|Data| SB[Stream 2]
        UC[User C] -->|Data| SC[Stream 3]
        
        SA -.->|Frame: ID=1| Mux["Client Session<br/>(Multiplexer)"]
        SB -.->|Frame: ID=2| Mux
        SC -.->|Frame: ID=3| Mux
    end

    Mux ==>|"TLS Tunnel<br/>Frames: [ID=1][ID=2][ID=1][ID=3]..."| Demux["Server Session<br/>(Demultiplexer)"]

    subgraph Server_Side [Server Side]
        Demux -.->|Frame: ID=1| SSA[Stream 1]
        Demux -.->|Frame: ID=2| SSB[Stream 2]
        Demux -.->|Frame: ID=3| SSC[Stream 3]
        
        SSA -->|Data| TA[Target A]
        SSB -->|Data| TB[Target B]
        SSC -->|Data| TC[Target C]
    end
    
    style Mux fill:#f96,stroke:#333,stroke-width:2px
    style Demux fill:#f96,stroke:#333,stroke-width:2px
```