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

(uncompleted) SplitHTTP: Client HTTP/3 #3543

Merged
merged 3 commits into from
Jul 17, 2024
Merged

(uncompleted) SplitHTTP: Client HTTP/3 #3543

merged 3 commits into from
Jul 17, 2024

Conversation

ll11l1lIllIl1lll
Copy link
Contributor

@ll11l1lIllIl1lll ll11l1lIllIl1lll commented Jul 16, 2024

有人推荐我如此做,所以我这样做了。
但请注意这个 h3 目前不足够与配置适配(例如,目前不通过 uTLS 进行指纹伪装)。

@ll11l1lIllIl1lll ll11l1lIllIl1lll changed the title (WIP) SpiltHTTP: Support HTTP/3 (uncompleted) SpiltHTTP: Support HTTP/3 Jul 16, 2024
@yuhan6665
Copy link
Member

Any suggestions are welcome @mmmray

@Fangliding
Copy link
Member

Fangliding commented Jul 16, 2024

		quicConfig := &quic.Config{
			HandshakeIdleTimeout: 10 * time.Second,
			MaxIdleTimeout:       30 * time.Second,
			KeepAlivePeriod:      3 * time.Second,
		}
		dest.Network = 3
		roundTripper := &http3.RoundTripper{
			TLSClientConfig: gotlsConfig,
			QUICConfig:      quicConfig,
			Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
				conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
				if err != nil {
					return nil, err
				}
				return quic.DialEarly(ctx, conn.(net.PacketConn), dest.RawNetAddr(), tlsCfg, cfg)
			},
		}
		downloadTransport = roundTripper
		uploadTransport = roundTripper

看了一眼quic-go的代码照着kcp随便糊的 还没测试 这样应该就可以正常调用ray自己的连接机制设置连接目标和sockopt了 不知道能不能用

@ll11l1lIllIl1lll ll11l1lIllIl1lll changed the title (uncompleted) SpiltHTTP: Support HTTP/3 (uncompleted) SpiltHTTP: Client Support HTTP/3 Jul 16, 2024
@ll11l1lIllIl1lll
Copy link
Contributor Author

		quicConfig := &quic.Config{
			HandshakeIdleTimeout: 10 * time.Second,
			MaxIdleTimeout:       30 * time.Second,
			KeepAlivePeriod:      3 * time.Second,
		}
		dest.Network = 3
		roundTripper := &http3.RoundTripper{
			TLSClientConfig: gotlsConfig,
			QUICConfig:      quicConfig,
			Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
				conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
				if err != nil {
					return nil, err
				}
				return quic.DialEarly(ctx, conn.(net.PacketConn), dest.RawNetAddr(), tlsCfg, cfg)
			},
		}
		downloadTransport = roundTripper
		uploadTransport = roundTripper

看了一眼quic-go的代码照着kcp随便糊的 还没测试 这样应该就可以正常调用ray自己的连接机制设置连接目标和sockopt了 不知道能不能用

It works! thanks.

@Fangliding
Copy link
Member

Fangliding commented Jul 16, 2024

嗯 我自己测了一下 发现dest是domain的话会炸 回来看好像已经解决了 这里要不要把resolve提到dialer前面 毕竟如果不止一个记录的话两个dest可能不一样不知道不知道会出问题
还有就是log会报错一个
connection doesn't allow setting of receive buffer size. Not a *net.UDPConn?. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.
不知道对性能影响多大 一些相关的界面 v2fly/v2ray-core#1024 v2fly/v2ray-core#1404 可能需要把这个方法抄过来什么的

@mmmray
Copy link
Collaborator

mmmray commented Jul 16, 2024

In client.go, in SendUploadRequest, there is a check for isH2. It needs to be changed to isH2 || isH3. Otherwise the upload will run over HTTP/1.1.

It should be noted that utls is not implemented.

Other than that, it looks good to me!

@mmmray
Copy link
Collaborator

mmmray commented Jul 16, 2024

Fixes #3456 (but properly, instead of browser dialer)

@mmmray
Copy link
Collaborator

mmmray commented Jul 17, 2024

It looks good to me. @Fangliding is there anything left to be done? I don't know much about the dialling parts.

Any ideas on how to add a test?

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

既然又要发新版不妨等这个完成,所以这个没把 SplitHTTP Browser Dialer 改炸吧

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

所以现在的逻辑是怎样的,自动使用 HTTP/3?

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

但我又想了一下,鉴于 QUIC 类存活现状(虽然我们是套 CDN)以及现在还不支持 uquic,时机尚未成熟,再写写可以放 v1.9

@Fangliding
Copy link
Member

It looks fine

It looks good to me. @Fangliding is there anything left to be done? I don't know much about the dialling parts.

Any ideas on how to add a test?

It looks fine

所以现在的逻辑是怎样的,自动使用 HTTP/3?

逻辑和原来相同 要启用h3需要在alpn手动设置为h3

@mmmray
Copy link
Collaborator

mmmray commented Jul 17, 2024

To recap:

  • h1 is used if the config is not TLS
  • h2 is used if the config is TLS
  • h1 is used if the ALPN was explicitly set to http/1.1
  • h3 is used if the ALPN was explicitly set to h3

So this didn’t change the SplitHTTP Browser Dialer?

If browser dialer is enabled, the entire logic is completely ignored, and it's up to the browser. The change related to browser dialer in this PR is ok, it removes some duplicated code.

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

* h1 is used if the ALPN was explicitly set to `http/1.1`

这个逻辑应该对浏览器指纹无效

* h3 is used if the ALPN was explicitly set to `h3`

这样的话先合了这个 PR 也不是不行,你们看一下还有哪些要改的,尽量在今天内弄完

Copy link
Collaborator

@mmmray mmmray left a comment

Choose a reason for hiding this comment

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

I think the questions of 1) what to do with h1 fingerprinting and 2) how to integrate with uquic can be answered at a later point in time, and the PR can be released as-is. It just needs good documentation.

@RPRX RPRX merged commit 90ae5f9 into XTLS:main Jul 17, 2024
36 checks passed
@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

那就先合了,感谢 PR,这下 Xray 不小心也有了基于 HTTP/3 的 QUIC 类代理@mmmray 麻烦研究下给下个版本加浏览器指纹

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

仔细看了下讨论发现应该把 @Fangliding@mmmray 列为 co-author

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

@Fangliding 帮我改一下最新 commit 的 message:

SpiltHTTP: Client supports HTTP/3 (#3543)

Closes https://github.com/XTLS/Xray-core/issues/3456

---------

Co-authored-by: Fangliding <[email protected]>
Co-authored-by: mmmray <[email protected]>

@mmmray
Copy link
Collaborator

mmmray commented Jul 17, 2024

it's ok if i don't get credit, I didn't really do anything except comment on the PR

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

@mmmray 你来改也行,主要是我有强迫症

mmmray added a commit to mmmray/Xray-core that referenced this pull request Jul 17, 2024
Closes XTLS#3456

Co-authored-by: Fangliding <[email protected]>
Co-authored-by: mmmray <[email protected]>
@mmmray
Copy link
Collaborator

mmmray commented Jul 17, 2024

it is done

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

* h1 is used if the ALPN was explicitly set to `http/1.1`

这个逻辑应该对浏览器指纹无效

补充一下,虽然不会改浏览器指纹,但适用于服务端 TLS 只支持 HTTP/1.1 的情况,这也是 @mmmray 当初加它的原因 ee2000f

@mmmray
Copy link
Collaborator

mmmray commented Jul 17, 2024

There is no need to send http/1.1 ALPN when the server does not support h2 anyway. This was just the easiest way to solve compatibility issues, but with regard to anti-censorship, a separate "send http/1.1" setting would be more appropriate (but it feels ugly). I thought this is what you meant, but translation issues

One day I hope this will be continued: refraction-networking/utls#74 or the code is migrated away from net/http

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

but with regard to anti-censorship, a separate "send http/1.1" setting would be more appropriate

其实我的意思是,Xray 选浏览器指纹时选 ALPN 也不会实际改,因为我不让,所以 ALPN 设 "http/1.1" 就相当于 "send http/1.1"

@mmmray
Copy link
Collaborator

mmmray commented Jul 17, 2024

oops, I didn't know. I guess that's good! how is it possible for websocket then? I thought it's possible to override the http/1.1 ALPN of websocket with h2 and it works for some CDN... I guess I should test more

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

how is it possible for websocket then?

// WebsocketHandshake basically calls UConn.Handshake inside it but it will only send
// http/1.1 in its ALPN.
func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error {
// Build the handshake state. This will apply every variable of the TLS of the
// fingerprint in the UConn
if err := c.BuildHandshakeState(); err != nil {
return err
}
// Iterate over extensions and check for utls.ALPNExtension
hasALPNExtension := false
for _, extension := range c.Extensions {
if alpn, ok := extension.(*utls.ALPNExtension); ok {
hasALPNExtension = true
alpn.AlpnProtocols = []string{"http/1.1"}
break
}
}
if !hasALPNExtension { // Append extension if doesn't exists
c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}})
}
// Rebuild the client hello and do the handshake
if err := c.BuildHandshakeState(); err != nil {
return err
}
return c.HandshakeContext(ctx)
}

I thought it's possible to override the http/1.1 ALPN of websocket with h2 and it works for some CDN...

至少 Cloudflare 不行 XTLS/Xray-docs-next#516 (comment)

@RPRX
Copy link
Member

RPRX commented Jul 17, 2024

这下 Xray 不小心也有了基于 HTTP/3 的 QUIC 类代理

而且还能套 CDN,前无古人,遥遥领先,总之就是赢!麻了

@Fangliding Fangliding changed the title (uncompleted) SpiltHTTP: Client Support HTTP/3 (uncompleted) SplitHTTP: Client Support HTTP/3 Jul 17, 2024
@ll11l1lIllIl1lll ll11l1lIllIl1lll changed the title (uncompleted) SplitHTTP: Client Support HTTP/3 (uncompleted) SplitHTTP: Client HTTP/3 Jul 18, 2024
@realartin
Copy link

so now we can use splitHttp using H3 alpn ?

@realartin
Copy link

please if it possible give me an inbound reference for SplitHttp Alpn H3
tnx

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.

6 participants