|
| 1 | +# Hysteria v2 (HY2) server + client protocol integration |
| 2 | + |
| 3 | +目标: |
| 4 | +- 按照官方文档在本机启动一个 Hysteria v2 服务端(用于联调) |
| 5 | +- 在本项目实现 HY2 对应的 client protocol(Rust) |
| 6 | +- 在本项目实现 HY2 对应的 server protocol(Rust) |
| 7 | +- 全程用 Markdown 跟踪进度与决策(本文件) |
| 8 | + |
| 9 | +参考文档(上游): |
| 10 | +- Server Getting Started: `https://v2.hysteria.network/docs/getting-started/Server/` |
| 11 | +- Protocol Spec: `https://v2.hysteria.network/docs/developers/Protocol/` |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## 计划(会随进度更新) |
| 16 | + |
| 17 | +- [x] 1. 阅读 HY2 docs 并沉淀要点 |
| 18 | +- [x] 2. 添加本地 server 配置/脚本并启动验证 |
| 19 | +- [x] 3. 实现 HY2 client:QUIC + `/auth` + TCP CONNECT(stream) |
| 20 | +- [x] 4. 实现 HY2 client:UDP(datagram) + Salamander(可选) |
| 21 | +- [x] 5. 接入到 registry/feature,补最小测试与使用说明 |
| 22 | +- [x] 6. 实现 HY2 server:QUIC + HTTP/3 `/auth` + TCP/UDP 转发 |
| 23 | +- [x] 7. 单测:server+client 联调 |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## 协议要点摘录(用于实现) |
| 28 | + |
| 29 | +### 服务端配置(最小可用) |
| 30 | +- 官方模板(Own certificate)核心字段: |
| 31 | + - `listen`(可选,默认 `:443`;本地联调会改成非特权端口) |
| 32 | + - `tls.cert` / `tls.key` |
| 33 | + - `auth.type=password` + `auth.password` |
| 34 | + - `masquerade` 可选;不配置时 HTTP 请求会返回 404(不影响 `/auth` 成功与否取决于实现,但联调建议先不加 masquerade,问题更少) |
| 35 | + |
| 36 | +### 传输层(QUIC + 可选 Salamander) |
| 37 | +- HY2 基于 QUIC。 |
| 38 | +- 可选 “Salamander” 对 QUIC UDP 包做混淆:每个 UDP 包前加 8 字节 `salt`,计算 `BLAKE2b-256(key || salt)` 得到 32 字节 key stream,对 payload 做 XOR;发送为 `salt || xor(payload)`,接收反向处理。 |
| 39 | + |
| 40 | +### 认证(HTTP/3 `/auth`) |
| 41 | +- QUIC 建连后,client 必须发送 HTTP/3 `POST /auth`,并要求 `:host` 为 `hysteria`(本项目 client 发送 `https://hysteria/auth`)。 |
| 42 | +- 认证 header(规范):`Hysteria-Auth: <string>`。 |
| 43 | +- 兼容(非规范但常见):`Authorization: <password>` / `Authorization: Bearer <password>`(本项目 server 兼容三种)。 |
| 44 | +- 成功响应 HTTP status 为 `233`,并返回: |
| 45 | + - `Hysteria-UDP: true/false` |
| 46 | + - `Hysteria-CC-RX: <uint|auto>`(本项目 server 默认返回 `auto`) |
| 47 | + - `Hysteria-Padding: <string>`(随机 padding string,双方应忽略) |
| 48 | +- 可选请求 header: |
| 49 | + - `Hysteria-CC-RX: <uint>`(bytes/s;0 表示未知) |
| 50 | + - `Hysteria-Padding: <string>`(随机 padding string,双方应忽略) |
| 51 | +- 响应 header(用于能力判断): |
| 52 | + - `Hysteria-UDP`: `true/false` |
| 53 | + - `Hysteria-CC-RX`: server 接受的下行 bytes/s(或 `auto`) |
| 54 | + |
| 55 | +### TCP(双向 QUIC stream) |
| 56 | +- 每次 TCP 连接:打开一个双向 QUIC stream,写入 `TCPRequest`: |
| 57 | + - `varint(0x401)` (TCPRequest ID) |
| 58 | + - `varint(Address length)` + `Address string (host:port)` |
| 59 | + - `varint(Padding length)` + `Random padding` |
| 60 | +- server 必须先回 `TCPResponse`: |
| 61 | + - `uint8(Status)`:`0x00=OK`,`0x01=Error` |
| 62 | + - `varint(Message length)` + `Message string` |
| 63 | + - `varint(Padding length)` + `Random padding` |
| 64 | +- 只有在 response OK 后,双方才开始转发 TCP payload。 |
| 65 | + |
| 66 | +### UDP(QUIC datagram) |
| 67 | +- UDP 包通过 QUIC unreliable datagram 发送,格式 `UDPMessage`(双向一致): |
| 68 | + - `uint32 Session ID` |
| 69 | + - `uint16 Packet ID` |
| 70 | + - `uint8 Fragment ID` |
| 71 | + - `uint8 Fragment Count` |
| 72 | + - `varint Address length` + `Address string (host:port)` |
| 73 | + - `Payload bytes` |
| 74 | +- 分片要求:超过 `max_datagram_size` 必须分片或丢弃;丢任一分片则整包丢弃。 |
| 75 | + |
| 76 | +--- |
| 77 | + |
| 78 | +## 进度日志 |
| 79 | + |
| 80 | +- 2026-02-10:创建跟踪文档,完成协议/配置要点摘录(进行中) |
| 81 | +- 2026-02-10:新增本地联调用 server 配置与证书生成脚本:`agent-docs/hysteria/` |
| 82 | +- 2026-02-10:新增 `protocol/hysteria`:完成 HY2 `/auth` + TCP stream request 的最小实现(编译/单测通过) |
| 83 | +- 2026-02-10:`protocol/hysteria` 增加 UDP(datagram) 与 Salamander(传输层混淆) 支持(编译/单测通过) |
| 84 | +- 2026-02-10:本地联调验证:`rabbit-digger-pro` 通过 HY2(TCP) 成功代理访问本机 `python -m http.server`(socks5 -> rdp -> hysteria server -> localhost 目标) |
| 85 | +- 2026-02-11:新增 `protocol/hysteria` server(QUIC + H3 `/auth` + TCP/UDP 转发,编译通过) |
| 86 | +- 2026-02-11:新增联调单测:`protocol/hysteria/src/interop_tests.rs`(TCP + UDP) |
| 87 | +- 2026-02-11:兼容 `Authorization: Bearer <password>`;并将 rustls provider 选择收敛到统一入口(避免运行时 panic) |
| 88 | +- 2026-02-11:对齐官方 Protocol Spec:`Hysteria-Auth`/`TCPResponse`/`UDPMessage` 统一格式、Salamander(8-byte salt) |
| 89 | +- 2026-02-11:增强健壮性与测试:H3 drain、UDP session idle 回收、分片重组 TTL、codec/salamander/auth/interop 扩展测试 |
| 90 | +- 2026-02-11:与上游 `hysteria` v2.7.0 互通验证通过:官方 client → 本项目 server;本项目 client → 官方 server(TCP/HTTP 经 SOCKS5 验证) |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +## rabbit-digger-pro 配置示例(本地联调) |
| 95 | + |
| 96 | +前置:先用 `agent-docs/hysteria/README.md` 启动本地 hysteria server。 |
| 97 | + |
| 98 | +```yaml |
| 99 | +net: |
| 100 | + hy2_local: |
| 101 | + type: hysteria |
| 102 | + server: 127.0.0.1:18443 |
| 103 | + server_name: localhost |
| 104 | + auth: test-password |
| 105 | + ca_pem: agent-docs/hysteria/cert.pem |
| 106 | + # udp: true |
| 107 | + # salamander: my-shared-key |
| 108 | + |
| 109 | +server: |
| 110 | + mixed: |
| 111 | + type: http+socks5 |
| 112 | + bind: 127.0.0.1:1080 |
| 113 | + net: hy2_local |
| 114 | +``` |
| 115 | +
|
| 116 | +--- |
| 117 | +
|
| 118 | +## 覆盖范围与已知差异(实现完整性说明) |
| 119 | +
|
| 120 | +当前实现已按官方 Protocol Spec(Hysteria v2 / “v4” 协议)对齐并自测通过,覆盖: |
| 121 | +- QUIC 传输 + HTTP/3 `/auth`:`Hysteria-Auth`/`Hysteria-CC-RX`/`Hysteria-Padding`(client/server) |
| 122 | +- TCP:`TCPRequest(0x401)` + `TCPResponse` + 双向转发(client/server) |
| 123 | +- UDP:`UDPMessage`(双向同格式)+ 分片重组(client/server) |
| 124 | +- Salamander:8-byte salt + `BLAKE2b-256(key || salt)`(client/server) |
| 125 | +- 单测:真实端口联调(TCP echo + UDP echo)`protocol/hysteria/src/interop_tests.rs` |
| 126 | + |
| 127 | +仍未覆盖/可能影响“对抗探测/更强伪装/更复杂边界”的点: |
| 128 | +- HTTP/3 masquerade:当前只返回 404(未实现静态站点或反代上游站点)。 |
| 129 | +- 拥塞控制/带宽协商:`Hysteria-CC-RX` 目前按协议交互(client 发 uint;server 回 `auto`),未实现额外的应用层限速策略。 |
| 130 | +- 生命周期细节:auth 后 server 侧已保持 H3 连接持续驱动并对后续请求返回 404;更复杂的“伪装站点/反代”仍未实现。 |
0 commit comments