v2ray-core icon indicating copy to clipboard operation
v2ray-core copied to clipboard

Add Hysteria2 Protocol

Open JimmyHuang454 opened this issue 1 year ago • 26 comments

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

JimmyHuang454 avatar Oct 22 '23 06:10 JimmyHuang454

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.

:exclamation: 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%) :arrow_up:
...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%) :arrow_down:
transport/internet/quic/congestion/utils.go 0.00% <0.00%> (ø)
transport/internet/quic/dialer.go 55.72% <63.33%> (-2.40%) :arrow_down:
... and 8 more

... and 6 files with indirect coverage changes

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov-commenter avatar Oct 24 '23 03:10 codecov-commenter

I had merged newest commit and fixed go-lint.

JimmyHuang454 avatar Oct 26 '23 04:10 JimmyHuang454

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 avatar Oct 28 '23 19:10 xiaokangwang

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 avatar Oct 29 '23 14:10 xiaokangwang

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

xiaokangwang avatar Oct 29 '23 14:10 xiaokangwang

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 avatar Oct 30 '23 11:10 JimmyHuang454

Hi, I tried to add a QUIC-based HTTP3 tranpsort which required by Hysteria, and it works. I use the code from here. So it's possible to add Hysteria proxy protocol to V2ray. I can take responsibility for maintenance if you want.

Assumed configuration:

  1. Compatible with the original hy2
  {
    "tag": "demo1",
    "protocol": "hysteria2",
    "settings": {},
    "streamSettings": {
      "transport": "hysteria2",
      "transportSettings": {
        "congestion": {
          "type": "brutal",
          "download_mbps": 200,
          "upload_mbps": 200,

          "password": "password"
        }
      },
      "security": "tls",
      "securitySettings": {}
    }
  }
  1. As a transport layer.
   {
    "tag": "demo2",
    "protocol": "vmess",
    "settings": {},
    "streamSettings": {
      "transport": "hysteria2",
      "transportSettings": {
        "congestion": {
          "type": "bbr",
          "password": "" // empty means no password.
        }
      },
      "security": "tls",
      "securitySettings": {}
    }
  }

What do you think? @xiaokangwang

JimmyHuang454 avatar Nov 14 '23 08:11 JimmyHuang454

Hi, I tried to add a QUIC-based HTTP3 tranpsort which required by Hysteria, and it works. I use the code from here. So it's possible to add Hysteria proxy protocol to V2ray. I can take responsibility for maintenance if you want.

Assumed configuration:

1. Compatible with the original hy2
  {
    "tag": "demo1",
    "protocol": "hysteria2",
    "settings": {},
    "streamSettings": {
      "transport": "hysteria2",
      "transportSettings": {
        "congestion": {
          "type": "brutal",
          "download_mbps": 200,
          "upload_mbps": 200,

          "password": "password"
        }
      },
      "security": "tls",
      "securitySettings": {}
    }
  }
2. As a transport layer.
   {
    "tag": "demo2",
    "protocol": "vmess",
    "settings": {},
    "streamSettings": {
      "transport": "hysteria2",
      "transportSettings": {
        "congestion": {
          "type": "bbr",
          "password": "" // empty means no password.
        }
      },
      "security": "tls",
      "securitySettings": {}
    }
  }

What do you think? @xiaokangwang

I think it should be fine so long it can be selectively compiled and don't interference with existing quic related features. This means it is expected that existing code rely on quic like dns or quic transports are not impacted by this change. So long as this requirement is satisfied, I am happy to merge it so long as there is someone ready to maintain Hysteria stack in the future.

xiaokangwang avatar Nov 19 '23 00:11 xiaokangwang

Hi, I tried to add a QUIC-based HTTP3 tranpsort which required by Hysteria, and it works. I use the code from here. So it's possible to add Hysteria proxy protocol to V2ray. I can take responsibility for maintenance if you want. Assumed configuration:

1. Compatible with the original hy2
  {
    "tag": "demo1",
    "protocol": "hysteria2",
    "settings": {},
    "streamSettings": {
      "transport": "hysteria2",
      "transportSettings": {
        "congestion": {
          "type": "brutal",
          "download_mbps": 200,
          "upload_mbps": 200,

          "password": "password"
        }
      },
      "security": "tls",
      "securitySettings": {}
    }
  }
2. As a transport layer.
   {
    "tag": "demo2",
    "protocol": "vmess",
    "settings": {},
    "streamSettings": {
      "transport": "hysteria2",
      "transportSettings": {
        "congestion": {
          "type": "bbr",
          "password": "" // empty means no password.
        }
      },
      "security": "tls",
      "securitySettings": {}
    }
  }

What do you think? @xiaokangwang

I think it should be fine so long it can be selectively compiled and don't interference with existing quic related features. This means it is expected that existing code rely on quic like dns or quic transports are not impacted by this change. So long as this requirement is satisfied, I am happy to merge it so long as there is someone ready to maintain Hysteria stack in the future.

Thanks. I think make it separately and will not affect others existing features.

JimmyHuang454 avatar Nov 19 '23 05:11 JimmyHuang454

Hi, packages like dns, common/protocol are still depended on newly introduced package. Could you have a look and make sure the hy2 fork of quic is not used outside its own transport and proxy implementaion, or justify it?

xiaokangwang avatar Nov 24 '23 00:11 xiaokangwang

Please let me know when you are ready for another review!

xiaokangwang avatar Nov 26 '23 10:11 xiaokangwang

Please let me know when you are ready for another review!

Thanks. Currently, I had restored to original quic-go and added a http3 transport that based on hysteria quic, supports brutal and bbr congestion algorithm.

I will add a hysteria2 proxy protocol in later so that it can work with the offical one.

But I am busy on my daily job, I plan to complete this PR in the Lunar New Year. I Will request another code review when I finished.

JimmyHuang454 avatar Nov 27 '23 03:11 JimmyHuang454

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.

JimmyHuang454 avatar Apr 08 '24 17:04 JimmyHuang454

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.

dyhkwong avatar Apr 25 '24 04:04 dyhkwong

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.

JimmyHuang454 avatar Apr 25 '24 10:04 JimmyHuang454

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

dyhkwong avatar Apr 25 '24 11:04 dyhkwong

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.

JimmyHuang454 avatar May 09 '24 09:05 JimmyHuang454

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

CodingMoeButa avatar May 10 '24 16:05 CodingMoeButa

A lock is needed for RunningClient map[net.Destination](hyClient.Client) (like those in quic, grpc and http). I encountered some concurrent map writes panics.

By the way, identifying clients only by net.Destination is not enough. This will cause multiple outbounds with the same destination but different streamSettings using a wrong dialer. This is a common issue for quic, grpc and http, not only this PR's hysteria though.

dyhkwong avatar Jun 19 '24 12:06 dyhkwong

A lock is needed for RunningClient map[net.Destination](hyClient.Client) (like those in quic, grpc and http). I encountered some concurrent map writes panics.

Ofcourse.

By the way, identifying clients only by net.Destination is not enough. This will cause multiple outbounds with the same destination but different streamSettings using a wrong dialer. This is a common issue for quic, grpc and http, not only this PR's hysteria though.

I have switched to using IP addresses to differentiate between different outbound connections. At the moment, it is indeed difficult to reuse a single port for multiple inbound connections.

JimmyHuang454 avatar Jun 24 '24 08:06 JimmyHuang454

Hi, I found that the values of congestion type, up_mbps and down_mbps are never used, so in fact it is always BBR no Brutal?

dyhkwong avatar Jul 23 '24 16:07 dyhkwong

Hi, I found that the values of congestion type, up_mbps and down_mbps are never used, so in fact it is always BBR no Brutal?

My bad. Use the Brutal congestion algorithm when both up_mbps and down_mbps are not zero.

JimmyHuang454 avatar Jul 24 '24 16:07 JimmyHuang454

Is that Mbps or MBps? The multiplier should be 1000*1000/8 not 1000*1000. Hysteria's case-insensitive conversation is confusing...

https://github.com/apernet/hysteria/blob/b563f3981fc63eadb6710f50eecb92922b8ae1ce/app/cmd/client.go#L317

https://github.com/apernet/hysteria/blob/master/app/internal/utils/bpsconv.go#L10-L53

dyhkwong avatar Jul 24 '24 17:07 dyhkwong

Is that Mbps or MBps? The multiplier should be 10001000/8 not 10001000. Hysteria's case-insensitive conversation is confusing...

https://github.com/apernet/hysteria/blob/b563f3981fc63eadb6710f50eecb92922b8ae1ce/app/cmd/client.go#L317

https://github.com/apernet/hysteria/blob/master/app/internal/utils/bpsconv.go#L10-L53

My bad again. It should be 1000*1000/8.

JimmyHuang454 avatar Jul 24 '24 19:07 JimmyHuang454

Hi! Is this merge request ready for another review?

xiaokangwang avatar Aug 19 '24 18:08 xiaokangwang