Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Hysteria2 Protocol #2721

Open
wants to merge 78 commits into
base: master
Choose a base branch
from
Open

Add Hysteria2 Protocol #2721

wants to merge 78 commits into from

Conversation

JimmyHuang454
Copy link

Use hysteria's quic-go to support BBR and brutal congestion algorithm

Same as hysteria, BBR and Brutal congestion algorithm can improve performance.

Usage:

  1. send_mbps is needed when congestion's type is brutal, meaning the max bandwidth of current network can use to send.
{
  "transport":"quic",
  "transportSettings":{
      "congestion": {"type":"brutal", "send_mbps": 200}
  },
  "security":"tls",
  "securitySettings":{}
}
  1. If user don't know how to config brutal, it's just ok to use bbr in both client and server side.
{
  "transport":"quic",
  "transportSettings":{
      "congestion": {"type":"bbr"}
  },
  "security":"tls",
  "securitySettings":{}
}

Fix vprotogen bug and update all Protobuf data

vprotogen can not work, because it failed to recognize new version of protoc, so that we can not add new feature to v2ray.

Update go version to 1.21

fix #2701 #2644

@codecov-commenter
Copy link

codecov-commenter commented Oct 24, 2023

Codecov Report

Attention: 1048 lines in your changes are missing coverage. Please review.

Comparison is base (cb84b28) 37.79% compared to head (0b7f037) 36.78%.
Report is 5 commits behind head on master.

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2721      +/-   ##
==========================================
- Coverage   37.79%   36.78%   -1.01%     
==========================================
  Files         654      664      +10     
  Lines       38723    39771    +1048     
==========================================
- Hits        14636    14631       -5     
- Misses      22477    23524    +1047     
- Partials     1610     1616       +6     
Files Coverage Δ
app/dns/nameserver_quic.go 70.94% <ø> (ø)
common/protocol/quic/sniff.go 44.87% <ø> (ø)
config.pb.go 29.34% <ø> (ø)
transport/internet/quic/conn.go 58.00% <ø> (ø)
transport/internet/quic/hub.go 75.34% <100.00%> (+2.61%) ⬆️
...ransport/internet/quic/congestion/bbr/bandwidth.go 0.00% <0.00%> (ø)
transport/internet/quic/congestion/bbr/clock.go 0.00% <0.00%> (ø)
transport/internet/grpc/dial.go 3.27% <0.00%> (-0.06%) ⬇️
transport/internet/quic/congestion/utils.go 0.00% <0.00%> (ø)
transport/internet/quic/dialer.go 55.72% <63.33%> (-2.40%) ⬇️
... and 8 more

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@JimmyHuang454
Copy link
Author

I had merged newest commit and fixed go-lint.

@xiaokangwang xiaokangwang added the Extensive Review Required Require an extensive review from organization owner, cannot be merged without owner approval label Oct 28, 2023
@xiaokangwang
Copy link
Contributor

Hi! Thanks for your contribution. Since this merge request includes switching the dependency, it will be a longer review process, however I will try my best to expatiate the process.

@xiaokangwang
Copy link
Contributor

Hi, after some interal discuss, it seems there is no active maintainer within V2Ray could take over the maintaince of hysteria transport. Is it possible for you to refactor this code, so that the original quic transport is left as is, and make the necessary change to make hysteria a new transport that can be disabled when something goes wrong by removing the import line in https://github.com/v2fly/v2ray-core/blob/master/main/distro/all/all.go .

@xiaokangwang
Copy link
Contributor

I am happy to merge it after the usage of forked quic from hysteria is isolated from main quic.

@JimmyHuang454
Copy link
Author

I am happy to merge it after the usage of forked quic from hysteria is isolated from main quic.

Thanks. I will dig into it later. But I have been very busy lately, and I may reply very late. Anyway, I will try my best.

@JimmyHuang454
Copy link
Author

Hi @xiaokangwang,

Apologies for the delay. I'm ready for the code review.

Here's what I've accomplished:

Added Hysteria2 transport to V2ray, utilizing QUIC and HTTP3

Now, any proxy protocol in V2ray can utilize Hy2 as a transport layer, such as trojan + hysteria2. You can review some transport tests for further details.

Implemented Hysteria2 proxy compatible with the official version

It functions well with the ordinary server I use. However, UDP requires additional testing. You can also examine some proxy tests for more insight.

Provided some real configuration examples

I'm uncertain about the appropriate location for these examples. They're mainly for testing purposes, so they might be subject to change.

Added documentation

For more detailed information, including special features, you can refer to the documentation.

}
newError("tunneling request to ", destination, " via ", server.Destination().NetAddr()).WriteToLog(session.ExportIDToError(ctx))

hyConn, IsHy2Transport := conn.(*hy2_transport.HyConn)
Copy link
Contributor

Choose a reason for hiding this comment

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

If traffic stat is enabled, conn is *internet.StatCouterConnection but not *hysteria2.HyConn, this type assertion will fail.

Copy link
Author

Choose a reason for hiding this comment

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

Sorry, I don't handle any traffic statistics. Is it necessary? Because I need to expose the WritePacket() method of the transport connection to the proxy layer. If so, I believe I'll need to implement it more aggressively.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is just a reminder and I don't know how widely it is used. Maybe usually some GUIs have traffic stats function?

By doing this

iConn := conn
if statConn, ok := conn.(*internet.StatCouterConnection); ok {
	iConn = statConn.Connection
}
hyConn, IsHy2Transport := iConn.(*hy2_transport.HyConn)

I don't know if maintainers will consider it "overfit".

Copy link
Author

Choose a reason for hiding this comment

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

OK, I will figure out a better solution, any other comments? Thanks.

func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
sid := session.ExportIDToError(ctx)

hyConn, IsHy2Transport := conn.(*hy2_transport.HyConn)
Copy link
Contributor

Choose a reason for hiding this comment

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

If traffic stat is enabled, conn is *internet.StatCouterConnection but not *hysteria2.HyConn, this type assertion will fail.


// ReadMultiBufferWithMetadata reads udp packet with destination
func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
_, data, dest, _ := r.HyConn.ReadPacket()
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
_, data, dest, _ := r.HyConn.ReadPacket()
_, data, dest, err := r.HyConn.ReadPacket()
if err != nil {
return nil, err
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Catch this error otherwise udp-disabled client will panic.

P.S. The whole code derived from trojan has many leftover that can be deleted.

Copy link
Author

Choose a reason for hiding this comment

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

I will fix it as you said. Thanks for the thorough review.

@dyhkwong
Copy link
Contributor

Can you let hy2 transport's client use v2ray system dialer? I think implementing a custom ConnFactory with v2ray's function (internet.ListenSystemPacket or internet.DialSystem) is enough.

@JimmyHuang454
Copy link
Author

Can you let hy2 transport's client use v2ray system dialer? I think implementing a custom ConnFactory with v2ray's function (internet.ListenSystemPacket or internet.DialSystem) is enough.

I don't really get you, please elaborate it. In my opinion, this PR will not use "net.ListenUDP()" in JimmyHuang454/hysteria, it will hijack all traffic into v2ray.

@dyhkwong
Copy link
Contributor

dyhkwong commented Apr 25, 2024

Android clients may use internet.UseAlternativeSystemDialer to replace v2ray system dialer (internet.DialSystem) to protect socket and prevent VPN traffic loopback. Currently hy2 does not comply with this.
(Nevermind I found QUIC transport doesn't comply with this too, see #1510. V2Ray just lacks a similar API for PacketConn. Maybe ignore this for now...) QUIC transport uses internet.ListenSystemPacket instead. It seems that internet.ListenSystemPacket can be protected by internet.RegisterListenerController.

I mean something like the below.

(I don't know why context.Background() is used here, just copy from QUIC code as is.)

--- a/transport/internet/hysteria2/dialer.go
+++ b/transport/internet/hysteria2/dialer.go
@@ -52,6 +52,14 @@ func InitAddress(dest net.Destination) (net.Addr, error) {
        return destAddr, nil
 }

+type connFactory struct {
+       NewFunc func(addr net.Addr) (net.PacketConn, error)
+}
+
+func (f *connFactory) New(addr net.Addr) (net.PacketConn, error) {
+       return f.NewFunc(addr)
+}
+
 func NewHyClient(dest net.Destination, streamSettings *internet.MemoryStreamConfig) (hy_client.Client, error) {
        tlsConfig, err := InitTLSConifg(streamSettings)
        if err != nil {
@@ -68,6 +76,18 @@ func NewHyClient(dest net.Destination, streamSettings *internet.MemoryStreamConf
                TLSConfig:  *tlsConfig,
                Auth:       config.GetPassword(),
                ServerAddr: serverAddr,
+               ConnFactory: &connFactory{
+                       NewFunc: func(addr net.Addr) (net.PacketConn, error) {
+                               rawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
+                                       IP:   []byte{0, 0, 0, 0},
+                                       Port: 0,
+                               }, streamSettings.SocketSettings)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               return rawConn.(*net.UDPConn), nil
+                       },
+               },
        })
        if err != nil {
                return nil, err

@JimmyHuang454
Copy link
Author

Android clients may use internet.UseAlternativeSystemDialer to replace v2ray system dialer (internet.DialSystem) to protect socket and prevent VPN traffic loopback. Currently hy2 does not comply with this. (Nevermind I found QUIC transport doesn't comply with this too, see #1510. V2Ray just lacks a similar API for PacketConn. Maybe ignore this for now...) QUIC transport uses internet.ListenSystemPacket instead. It seems that internet.ListenSystemPacket can be protected by internet.RegisterListenerController.

I mean something like the below.

Thanks, you are right. I forgot to handle that on the client side.

@CodingMoeButa
Copy link

建议保留brutal作为quic的一种流控算法选择,不必考虑它与hysteria的兼容性,反正hysteria已经被作为新的协议和传输层实现了。多一种选择不是坏事。

return int(quicvarint.Len(uint64(s)))
}

func (c *ConnWriter) writeTcpHeader() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be replaced by hyProtocol.WriteTCPRequest?

return newError("failed to send response").Base(err)
}

address := strings.Split(reqAddr, ":")
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't work for IPv6. Maybe use net.SplitHostPort instead.

func InitTLSConifg(streamSettings *internet.MemoryStreamConfig) (*hyClient.TLSConfig, error) {
tlsSetting := CheckTLSConfig(streamSettings, true)
if tlsSetting == nil {
tlsSetting = &tls.Config{
Copy link
Contributor

Choose a reason for hiding this comment

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

There are ConfigFromStreamSettings and GetTLSConfig in github.com/v2fly/v2ray-core/v5/transport/internet/tls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Extensive Review Required Require an extensive review from organization owner, cannot be merged without owner approval
Projects
None yet
Development

Successfully merging this pull request may close these issues.

quic-go@v0.33.0 can not be built on go 1.21
5 participants