diff --git a/docs/configuration/inbound/hysteria2.md b/docs/configuration/inbound/hysteria2.md new file mode 100644 index 00000000..af7e864f --- /dev/null +++ b/docs/configuration/inbound/hysteria2.md @@ -0,0 +1,89 @@ +### Structure + +```json +{ + "type": "hysteria2", + "tag": "hy2-in", + + ... // Listen Fields + + "up_mbps": 100, + "down_mbps": 100, + "obfs": { + "type": "salamander", + "password": "cry_me_a_r1ver" + }, + "users": [ + { + "name": "tobyxdd", + "password": "goofy_ahh_password" + } + ], + "ignore_client_bandwidth": false, + "masquerade": "", + "tls": {} +} +``` + +!!! warning "Compatibility issues with the official client" + + The use case of `fastOpen=false` or UDP MTU >= 1200 is not supported when using the official client. + +!!! warning "" + + QUIC, which is required by Hysteria2 is not included by default, see [Installation](/#installation). + +### Listen Fields + +See [Listen Fields](/configuration/shared/listen) for details. + +### Fields + +#### up_mbps, down_mbps + +Max bandwidth, in Mbps. + +Not limited if empty. + +Conflict with `ignore_client_bandwidth`. + +#### obfs.type + +QUIC traffic obfuscator type, only available with `salamander`. + +Disabled if empty. + +#### obfs.password + +QUIC traffic obfuscator password. + +#### users + +Hysteria2 users + +#### users.password + +Authentication password + +#### ignore_client_bandwidth + +Commands the client to use the BBR flow control algorithm instead of Hysteria CC. + +Conflict with `up_mbps` and `down_mbps`. + +#### masquerade + +HTTP3 server behavior when authentication fails. + +| Scheme | Example | Description | +|--------------|-------------------------|--------------------| +| `file` | `file:///var/www` | As a file server | +| `http/https` | `http://127.0.0.1:8080` | As a reverse proxy | + +A 404 page will be returned if empty. + +#### tls + +==Required== + +TLS configuration, see [TLS](/configuration/shared/tls/#inbound). \ No newline at end of file diff --git a/docs/configuration/inbound/hysteria2.zh.md b/docs/configuration/inbound/hysteria2.zh.md new file mode 100644 index 00000000..e5a8e5ea --- /dev/null +++ b/docs/configuration/inbound/hysteria2.zh.md @@ -0,0 +1,87 @@ +### 结构 + +```json +{ + "type": "hysteria2", + "tag": "hy2-in", + + ... // 监听字段 + + "up_mbps": 100, + "down_mbps": 100, + "obfs": { + "type": "salamander", + "password": "cry_me_a_r1ver" + }, + "users": [ + { + "name": "tobyxdd", + "password": "goofy_ahh_password" + } + ], + "ignore_client_bandwidth": false, + "masquerade": "", + "tls": {} +} +``` + +!!! warning "与官方客户端的兼容性问题" + + 当使用原始客户端时,不支持 `fastOpen=false` 或者 UDP MTU >= 1200 的用例。 + +!!! warning "" + + 默认安装不包含被 Hysteria2 依赖的 QUIC,参阅 [安装](/zh/#_2)。 + +### 监听字段 + +参阅 [监听字段](/zh/configuration/shared/listen/)。 + +### 字段 + +#### up_mbps, down_mbps + +支持的速率,默认不限制。 + +与 `ignore_client_bandwidth` 冲突。 + +#### obfs.type + +QUIC 流量混淆器类型,仅可设为 `salamander`。 + +如果为空则禁用。 + +#### obfs.password + +QUIC 流量混淆器密码. + +#### users + +Hysteria 用户 + +#### users.password + +认证密码。 + +#### ignore_client_bandwidth + +命令客户端使用 BBR 流量控制算法而不是 Hysteria CC。 + +与 `up_mbps` 和 `down_mbps` 冲突。 + +#### masquerade + +HTTP3 服务器认证失败时的行为。 + +| Scheme | 示例 | 描述 | +|--------------|-------------------------|---------| +| `file` | `file:///var/www` | 作为文件服务器 | +| `http/https` | `http://127.0.0.1:8080` | 作为反向代理 | + +如果为空,则返回 404 页。 + +#### tls + +==必填== + +TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 \ No newline at end of file diff --git a/docs/configuration/inbound/index.md b/docs/configuration/inbound/index.md index 88cdb1aa..830d86a9 100644 --- a/docs/configuration/inbound/index.md +++ b/docs/configuration/inbound/index.md @@ -27,6 +27,8 @@ | `naive` | [Naive](./naive) | X | | `hysteria` | [Hysteria](./hysteria) | X | | `shadowtls` | [ShadowTLS](./shadowtls) | TCP | +| `tuic` | [TUIC](./tuic) | X | +| `hysteria2` | [Hysteria2](./hysteria2) | X | | `vless` | [VLESS](./vless) | TCP | | `tun` | [Tun](./tun) | X | | `redirect` | [Redirect](./redirect) | X | diff --git a/docs/configuration/inbound/index.zh.md b/docs/configuration/inbound/index.zh.md index e32be645..5b3592f6 100644 --- a/docs/configuration/inbound/index.zh.md +++ b/docs/configuration/inbound/index.zh.md @@ -26,6 +26,10 @@ | `trojan` | [Trojan](./trojan) | TCP | | `naive` | [Naive](./naive) | X | | `hysteria` | [Hysteria](./hysteria) | X | +| `shadowtls` | [ShadowTLS](./shadowtls) | TCP | +| `tuic` | [TUIC](./tuic) | X | +| `hysteria2` | [Hysteria2](./hysteria2) | X | +| `vless` | [VLESS](./vless) | TCP | | `tun` | [Tun](./tun) | X | | `redirect` | [Redirect](./redirect) | X | | `tproxy` | [TProxy](./tproxy) | X | diff --git a/docs/configuration/outbound/hysteria2.md b/docs/configuration/outbound/hysteria2.md new file mode 100644 index 00000000..8d01bb3b --- /dev/null +++ b/docs/configuration/outbound/hysteria2.md @@ -0,0 +1,82 @@ +### Structure + +```json +{ + "type": "hysteria2", + "tag": "hy2-out", + + "server": "127.0.0.1", + "server_port": 1080, + "up_mbps": 100, + "down_mbps": 100, + "obfs": { + "type": "salamander", + "password": "cry_me_a_r1ver" + }, + "password": "goofy_ahh_password", + "network": "tcp", + "tls": {}, + + ... // Dial Fields +} +``` + +!!! warning "Compatibility issues with the official server" + + The use case of UDP MTU >= 1200 is not supported when using the official server. + +!!! warning "" + + QUIC, which is required by Hysteria2 is not included by default, see [Installation](/#installation). + +### Fields + +#### server + +==Required== + +The server address. + +#### server_port + +==Required== + +The server port. + +#### up_mbps, down_mbps + +Max bandwidth, in Mbps. + +If empty, the BBR congestion control algorithm will be used instead of Hysteria CC. + +#### obfs.type + +QUIC traffic obfuscator type, only available with `salamander`. + +Disabled if empty. + +#### obfs.password + +QUIC traffic obfuscator password. + +#### password + +Authentication password. + +#### network + +Enabled network + +One of `tcp` `udp`. + +Both is enabled by default. + +#### tls + +==Required== + +TLS configuration, see [TLS](/configuration/shared/tls/#outbound). + +### Dial Fields + +See [Dial Fields](/configuration/shared/dial) for details. diff --git a/docs/configuration/outbound/hysteria2.zh.md b/docs/configuration/outbound/hysteria2.zh.md new file mode 100644 index 00000000..cc3a2f2b --- /dev/null +++ b/docs/configuration/outbound/hysteria2.zh.md @@ -0,0 +1,83 @@ +### 结构 + +```json +{ + "type": "hysteria2", + "tag": "hy2-out", + + "server": "127.0.0.1", + "server_port": 1080, + "up_mbps": 100, + "down_mbps": 100, + "obfs": { + "type": "salamander", + "password": "cry_me_a_r1ver" + }, + "password": "goofy_ahh_password", + "network": "tcp", + "tls": {}, + + ... // 拨号字段 +} +``` + +!!! warning "与官方服务器的兼容性问题" + + 当使用原始服务器时,不支持 UDP MTU >= 1200 的用例。 + +!!! warning "" + + 默认安装不包含被 Hysteria2 依赖的 QUIC,参阅 [安装](/zh/#_2)。 + +### 字段 + +#### server + +==必填== + +服务器地址。 + +#### server_port + +==必填== + +服务器端口。 + +#### up_mbps, down_mbps + +最大带宽。 + +如果为空,将使用 BBR 流量控制算法而不是 Hysteria CC。 + +#### obfs.type + +QUIC 流量混淆器类型,仅可设为 `salamander`。 + +如果为空则禁用。 + +#### obfs.password + +QUIC 流量混淆器密码. + +#### password + +认证密码。 + +#### network + +启用的网络协议。 + +`tcp` 或 `udp`。 + +默认所有。 + +#### tls + +==必填== + +TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。 + + +### 拨号字段 + +参阅 [拨号字段](/zh/configuration/shared/dial/)。 diff --git a/docs/configuration/outbound/index.md b/docs/configuration/outbound/index.md index 83320971..3fcd636d 100644 --- a/docs/configuration/outbound/index.md +++ b/docs/configuration/outbound/index.md @@ -29,6 +29,8 @@ | `shadowsocksr` | [ShadowsocksR](./shadowsocksr) | | `vless` | [VLESS](./vless) | | `shadowtls` | [ShadowTLS](./shadowtls) | +| `tuic` | [TUIC](./tuic) | +| `hysteria2` | [Hysteria2](./hysteria2) | | `tor` | [Tor](./tor) | | `ssh` | [SSH](./ssh) | | `dns` | [DNS](./dns) | diff --git a/docs/configuration/outbound/index.zh.md b/docs/configuration/outbound/index.zh.md index e54a1d95..3b950e4d 100644 --- a/docs/configuration/outbound/index.zh.md +++ b/docs/configuration/outbound/index.zh.md @@ -28,6 +28,9 @@ | `hysteria` | [Hysteria](./hysteria) | | `shadowsocksr` | [ShadowsocksR](./shadowsocksr) | | `vless` | [VLESS](./vless) | +| `shadowtls` | [ShadowTLS](./shadowtls) | +| `tuic` | [TUIC](./tuic) | +| `hysteria2` | [Hysteria2](./hysteria2) | | `tor` | [Tor](./tor) | | `ssh` | [SSH](./ssh) | | `dns` | [DNS](./dns) | diff --git a/mkdocs.yml b/mkdocs.yml index 93dfc972..24d5133c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -87,6 +87,7 @@ nav: - ShadowTLS: configuration/inbound/shadowtls.md - VLESS: configuration/inbound/vless.md - TUIC: configuration/inbound/tuic.md + - Hysteria2: configuration/inbound/hysteria2.md - Tun: configuration/inbound/tun.md - Redirect: configuration/inbound/redirect.md - TProxy: configuration/inbound/tproxy.md @@ -105,6 +106,7 @@ nav: - ShadowsocksR: configuration/outbound/shadowsocksr.md - VLESS: configuration/outbound/vless.md - TUIC: configuration/outbound/tuic.md + - Hysteria2: configuration/outbound/hysteria2.md - Tor: configuration/outbound/tor.md - SSH: configuration/outbound/ssh.md - DNS: configuration/outbound/dns.md diff --git a/test/clash_test.go b/test/clash_test.go index af9e80b4..4ade42f1 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -32,7 +32,8 @@ const ( ImageTrojan = "trojangfw/trojan:latest" ImageNaive = "pocat/naiveproxy:client" ImageBoringTun = "ghcr.io/ntkme/boringtun:edge" - ImageHysteria = "tobyxdd/hysteria:latest" + ImageHysteria = "teddysun/hysteria:1.3.5" + ImageHysteria2 = "teddysun/hysteria:latest" ImageNginx = "nginx:stable" ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest" ImageShadowsocksR = "teddysun/shadowsocks-r:latest" @@ -50,6 +51,7 @@ var allImages = []string{ ImageNaive, ImageBoringTun, ImageHysteria, + ImageHysteria2, ImageNginx, ImageShadowTLS, ImageShadowsocksR, @@ -376,7 +378,7 @@ func testLargeDataWithPacketConnSize(t *testing.T, port uint16, chunkSize int, p rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)} - times := 50 + times := 2 pingCh, pongCh, test := newLargeDataPair() writeRandData := func(pc net.PacketConn, addr net.Addr) (map[int][]byte, error) { diff --git a/test/config/hysteria2-client.yml b/test/config/hysteria2-client.yml new file mode 100644 index 00000000..403451a0 --- /dev/null +++ b/test/config/hysteria2-client.yml @@ -0,0 +1,12 @@ +server: 127.0.0.1:10000 +auth: password +fastOpen: true +socks5: + listen: 127.0.0.1:10001 +tls: + sni: example.org + ca: /etc/hysteria/ca.pem +obfs: + type: salamander + salamander: + password: cry_me_a_r1ver \ No newline at end of file diff --git a/test/config/hysteria2-server.yml b/test/config/hysteria2-server.yml new file mode 100644 index 00000000..9b4b1b13 --- /dev/null +++ b/test/config/hysteria2-server.yml @@ -0,0 +1,13 @@ +listen: 127.0.0.1:10000 +auth: + type: password + password: password +fastOpen: true +tls: + sni: example.org + cert: /etc/hysteria/cert.pem + key: /etc/hysteria/key.pem +obfs: + type: salamander + salamander: + password: cry_me_a_r1ver \ No newline at end of file diff --git a/test/hysteria2_test.go b/test/hysteria2_test.go index 22e9c164..06284d1e 100644 --- a/test/hysteria2_test.go +++ b/test/hysteria2_test.go @@ -95,3 +95,92 @@ func testHysteria2Self(t *testing.T, salamanderPassword string) { }) testSuit(t, clientPort, testPort) } + +func TestHysteria2Inbound(t *testing.T) { + caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeHysteria2, + Hysteria2Options: option.Hysteria2InboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Obfs: &option.Hysteria2Obfs{ + Type: hysteria2.ObfsTypeSalamander, + Password: "cry_me_a_r1ver", + }, + Users: []option.Hysteria2User{{ + Password: "password", + }}, + TLS: &option.InboundTLSOptions{ + Enabled: true, + ServerName: "example.org", + CertificatePath: certPem, + KeyPath: keyPem, + }, + }, + }, + }, + }) + startDockerContainer(t, DockerOptions{ + Image: ImageHysteria2, + Ports: []uint16{serverPort, clientPort}, + Cmd: []string{"hysteria", "client", "-c", "/etc/hysteria/config.yml", "--disable-update-check", "--log-level", "debug"}, + Bind: map[string]string{ + "hysteria2-client.yml": "/etc/hysteria/config.yml", + caPem: "/etc/hysteria/ca.pem", + }, + }) + testSuit(t, clientPort, testPort) +} + +func TestHysteria2Outbound(t *testing.T) { + _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") + startDockerContainer(t, DockerOptions{ + Image: ImageHysteria2, + Ports: []uint16{testPort}, + Cmd: []string{"hysteria", "server", "-c", "/etc/hysteria/config.yml", "--disable-update-check", "--log-level", "debug"}, + Bind: map[string]string{ + "hysteria2-server.yml": "/etc/hysteria/config.yml", + certPem: "/etc/hysteria/cert.pem", + keyPem: "/etc/hysteria/key.pem", + }, + }) + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeHysteria2, + Hysteria2Options: option.Hysteria2OutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + Obfs: &option.Hysteria2Obfs{ + Type: hysteria2.ObfsTypeSalamander, + Password: "cry_me_a_r1ver", + }, + Password: "password", + TLS: &option.OutboundTLSOptions{ + Enabled: true, + ServerName: "example.org", + CertificatePath: certPem, + }, + }, + }, + }, + }) + testSuitSimple1(t, clientPort, testPort) +}