Skip to content

Commit 298e3c5

Browse files
committed
feat: add hysteria (HY2) server
1 parent 46d5f8d commit 298e3c5

File tree

6 files changed

+600
-2
lines changed

6 files changed

+600
-2
lines changed

Cargo.lock

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent-docs/hysteria.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
目标:
44
- 按照官方文档在本机启动一个 Hysteria v2 服务端(用于联调)
55
- 在本项目实现 HY2 对应的 client protocol(Rust)
6+
- 在本项目实现 HY2 对应的 server protocol(Rust)
67
- 全程用 Markdown 跟踪进度与决策(本文件)
78

89
参考文档(上游):
@@ -18,6 +19,8 @@
1819
- [x] 3. 实现 HY2 client:QUIC + `/auth` + TCP CONNECT(stream)
1920
- [x] 4. 实现 HY2 client:UDP(datagram) + Salamander(可选)
2021
- [x] 5. 接入到 registry/feature,补最小测试与使用说明
22+
- [ ] 6. 实现 HY2 server:QUIC + HTTP/3 `/auth` + TCP/UDP 转发(进行中)
23+
- [ ] 7. 单测:server+client 联调(进行中)
2124

2225
---
2326

@@ -78,6 +81,7 @@
7881
- 2026-02-10:新增 `protocol/hysteria`:完成 HY2 `/auth` + TCP stream request 的最小实现(编译/单测通过)
7982
- 2026-02-10:`protocol/hysteria` 增加 UDP(datagram) 与 Salamander(传输层混淆) 支持(编译/单测通过)
8083
- 2026-02-10:本地联调验证:`rabbit-digger-pro` 通过 HY2(TCP) 成功代理访问本机 `python -m http.server`(socks5 -> rdp -> hysteria server -> localhost 目标)
84+
- 2026-02-11:新增 `protocol/hysteria` server(QUIC + H3 `/auth` + TCP/UDP 转发,编译通过)
8185

8286
---
8387

protocol/hysteria/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77
rd-interface = { path = "../../rd-interface", version = "0.4" }
88
tokio = { version = "1.49.0", features = ["full"] }
99
serde = "1.0"
10+
rd-std = { path = "../../rd-std", version = "0.1" }
1011

1112
quinn = { version = "0.11.9", default-features = false, features = ["runtime-tokio", "rustls-ring"] }
1213
h3 = "0.0.8"
@@ -20,6 +21,8 @@ blake2 = "0.10"
2021
rand = "0.8"
2122
parking_lot = "0.12"
2223
tokio-stream = { version = "0.1.18", features = ["sync"] }
24+
tracing = "0.1.44"
2325

2426
[dev-dependencies]
25-
rd-std = { path = "../../rd-std", version = "0.1" }
27+
rcgen = "0.13"
28+
tempfile = "3.24.0"

protocol/hysteria/src/codec.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,41 @@ pub(crate) fn write_varint(out: &mut Vec<u8>, mut x: u64) {
3232
}
3333
}
3434

35+
pub(crate) fn decode_varint(input: &[u8]) -> Option<(u64, usize)> {
36+
let first = *input.first()?;
37+
let tag = first >> 6;
38+
match tag {
39+
0b00 => Some(((first & 0b0011_1111) as u64, 1)),
40+
0b01 => {
41+
if input.len() < 2 {
42+
return None;
43+
}
44+
let b0 = input[0] & 0b0011_1111;
45+
let v = u16::from_be_bytes([b0, input[1]]) as u64;
46+
Some((v, 2))
47+
}
48+
0b10 => {
49+
if input.len() < 4 {
50+
return None;
51+
}
52+
let b0 = input[0] & 0b0011_1111;
53+
let v = u32::from_be_bytes([b0, input[1], input[2], input[3]]) as u64;
54+
Some((v, 4))
55+
}
56+
0b11 => {
57+
if input.len() < 8 {
58+
return None;
59+
}
60+
let b0 = input[0] & 0b0011_1111;
61+
let v = u64::from_be_bytes([
62+
b0, input[1], input[2], input[3], input[4], input[5], input[6], input[7],
63+
]);
64+
Some((v, 8))
65+
}
66+
_ => None,
67+
}
68+
}
69+
3570
pub(crate) fn write_tcp_request(out: &mut Vec<u8>, target: &Address) {
3671
write_varint(out, HY2_TCP_REQUEST);
3772
match target {

protocol/hysteria/src/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use client::{HysteriaNet, HysteriaNetConfig};
2-
use rd_interface::{registry::Builder, Net, Registry, Result};
2+
use rd_interface::{registry::Builder, Net, Registry, Result, Server};
3+
use server::{HysteriaServer, HysteriaServerConfig};
34

45
mod client;
56
mod codec;
67
mod salamander;
8+
mod server;
79
mod stream;
810
mod transport;
911
mod udp;
@@ -18,7 +20,18 @@ impl Builder<Net> for HysteriaNet {
1820
}
1921
}
2022

23+
impl Builder<Server> for HysteriaServer {
24+
const NAME: &'static str = "hysteria";
25+
type Config = HysteriaServerConfig;
26+
type Item = Self;
27+
28+
fn build(config: Self::Config) -> Result<Self> {
29+
HysteriaServer::new(config)
30+
}
31+
}
32+
2133
pub fn init(registry: &mut Registry) -> Result<()> {
2234
registry.add_net::<HysteriaNet>();
35+
registry.add_server::<server::HysteriaServer>();
2336
Ok(())
2437
}

0 commit comments

Comments
 (0)