Skip to content

Conversation

@kitty-eu-org
Copy link

Description

This PR implements a complete Hysteria2 client following the official https://github.com/apernet/hysteria/blob/master/PROTOCOL.md. The implementation is based on the official Go client and includes full support for TCP proxy, UDP relay, congestion control (BBR/Brutal), and Fast Open.

Features Implemented

Core Protocol:

  • ✅ HTTP/3 authentication flow with proper header validation
  • ✅ TCP proxy with request/response framing
  • ✅ UDP relay with fragmentation support
  • ✅ QUIC varint encoding/decoding
  • ✅ Protocol constants defined in dedicated module

Advanced Features:

  • ✅ BBR congestion control (bandwidth detection)
  • ✅ Brutal congestion control (fixed rate)
  • ✅ TCP Fast Open for reduced latency
  • ✅ UDP session management with cleanup

Code Quality:

  • ✅ 32 comprehensive unit tests (all passing)
  • ✅ Boundary value testing for varint encoding
  • ✅ Address format variations (IPv4, IPv6, hostnames)
  • ✅ Authentication validation tests

Changes

  • Add hysteria2_protocol.rs: Protocol constants and header names
  • Add hysteria2_client.rs: Full client implementation (~1900 LOC)
  • Update hysteria2_server.rs: Improved auth validation, UDP fixes
  • Update config support: Hysteria2 client configuration
  • Add SOCKS5 UDP relay: For testing UDP functionality

Protocol Compliance

This implementation follows the official https://github.com/apernet/hysteria/blob/master/PROTOCOL.md:

  • Authentication via HTTP/3 POST to /auth with host hysteria
  • TCP requests use frame type 0x401
  • UDP datagrams with fragmentation support
  • Congestion control negotiation via Hysteria-CC-RX header

Copy link
Owner

@cfal cfal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I'd love to revisit this in a future release. Ideally, I'm hoping for a more general client solution for QUIC protocols rather than something Hysteria2-specific with full support for chaining. In the meantime, I've added SOCKS5 UDP associate support and fixed UDP routing in the 0.2.5 release.

let socks_udp_relay = SocksUdpRelay::new(udp_socket);

return Ok(TcpServerSetupResult::MultiDirectionalUdp {
stream: Box::new(socks_udp_relay),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that server_stream ends up dropped here - it needs to stick around until UDP proxying is completed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your reply. I have resolved all the conflicts. Please review it again.

Copy link
Author

@kitty-eu-org kitty-eu-org Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cfal Thank you for your feedback! I understand your requirements.

I will refactor the code as follows:

Maintain/enhance the generic QUIC client support in SocketConnectorImpl (the current TransportConfig::Quic)
Extract the QUIC endpoint creation logic into a reusable common module.
Allow Hysteria2SocketConnector to add protocol-specific layers (HTTP/3 authentication, frame encapsulation, etc.) on top of the generic QUIC client.
This way, other protocols (such as the TUIC client) can also reuse the generic QUIC client capabilities. Do you think this approach is acceptable?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kitty-eu-org thanks for taking the time in this PR. there is no need for protocol-specific layers. we should have generic QUIC support through SocketConnectorImpl instead of protocol == hysteria2 - as well as through the client proxy chain, as TCP/UDP does.

right now, you can specify eg a client chain of shadowsocks followed by vless, and TCP will connect through both (proxy TCP through shadowsocks to vless, proxy TCP through vless), and UDP connections will connect through both (proxy TCP through shadowsocks to vless, proxy UDP-over-TCP through vless). and you can have different rules + chains for different hostnames/IPs.

i have not looked into this yet as well because i'm considering switching to tokio-quiche, and i think this is can be a complex change. i don't want to discourage you from working on this, but getting this fully working might not be easy and require some time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants