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

SplitHTTP client: Raise idle timeout to 5 minutes #3624

Merged
merged 4 commits into from
Aug 10, 2024

Conversation

mmmray
Copy link
Collaborator

@mmmray mmmray commented Aug 2, 2024

Copy the settings from QUIC transport. See
#3565 (comment) -- Tested with CDN and it seems better than before (fewer reconnections)

Keep-alive packets are still turned off, so the original concern of that PR should still be resolved.

Copy the settings from QUIC transport. See
XTLS#3565 (comment) --
Tested with CDN and it seems better than before (fewer reconnections)

keep-alive packets are still turned off, so the original concern should
be resolved.
@RPRX
Copy link
Member

RPRX commented Aug 2, 2024

我觉得这项改动是合理的,因为 *ray 的默认超时就是五分钟,虽然这何尝不是一种特征

但应只留 MaxIdleTimeout,把另外两个删掉,默认即可,握手五秒已经够用了

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 2, 2024

I looked at wireshark yesterday to figure out if it is very obvious, but the h2/h3 connection reuse makes it a bit too difficult, and CDN's own idle timeout interferes as well. I think what is needed is a randomized keepalive, but maybe in another layer (in vless or mux.cool?) so that it is solved for all transports. There were also some users who complained that their SSH session does not survive for more than a few minutes, so they should be happy about this as well. Anyway, for another time.

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 2, 2024

Actually, quic-go's default quic config and the default quic config in http3 are different. Here is the actual default config for http3 package

So in practice, this PR changes the following settings, because it sets an explicit QUICConfig:

  • MaxIdleTimeout is raised from 30 seconds to 5 minutes
  • KeepAlivePeriod is set from 10 seconds to 0 (disable keepalive)
  • MaxIncomingStreams is set from -1 to 100

anyway, it still seems reasonable to me. works on my machine but somebody please review and test again.

@RPRX
Copy link
Member

RPRX commented Aug 2, 2024

MaxIncomingStreams: -1, // don't allow the server to create bidirectional streams

对这个有点感兴趣,这是指服务端可以发起双向流吗,不过看起来这是 QUIC 层而不是 H3 层的东西所以有点鸡肋

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 2, 2024

I think it's mostly because quic config is used for both server and client applications. It makes a bit more sense on the server. I don't think server-initiated streams are useful, even if CDN supports full quic forwarding. It's only interesting that there are bidirectional streams, not that a stream is initiated by the server. But not 100% sure.

@RPRX
Copy link
Member

RPRX commented Aug 2, 2024

I don't think server-initiated streams are useful, even if CDN supports full quic forwarding. It's only interesting that there are bidirectional streams, not that a stream is initiated by the server. But not 100% sure.

因为确实错了,比如说 CDN 不支持 streaming request 是怕客户端攻击,但若 bidirectional stream 是服务端发起的就不会是攻击了

@RPRX
Copy link
Member

RPRX commented Aug 2, 2024

Actually, quic-go's default quic config and the default quic config in http3 are different. Here is the actual default config for http3 package

So in practice, this PR changes the following settings, because it sets an explicit QUICConfig:

* MaxIdleTimeout is raised from 30 seconds to 5 minutes

* KeepAlivePeriod is set from 10 seconds to 0 (disable keepalive)

* MaxIncomingStreams is set from -1 to 100

anyway, it still seems reasonable to me. works on my machine but somebody please review and test again.

所以说其实现在还是有 KeepAlive 的,只是从 3 秒改成了 10 秒,而且我修好 H3 复用连接后 KeepAlive 应该是一整个大连接共用吧

我觉得除了 MaxIdleTimeout,其它两个先和 quic-go H3 默认值保持一致吧,不然就成了 quic-go H3 特征但没有 KeepAlive 包?

@RPRX
Copy link
Member

RPRX commented Aug 3, 2024

发现 MaxIncomingStreams 为 0 时会被 quic-go H3 自动设成 -1:

https://github.com/quic-go/quic-go/blob/b8ea5c798155950fb5bbfdd06cad1939c9355878/http3/roundtrip.go#L196-L225

@RPRX
Copy link
Member

RPRX commented Aug 3, 2024

不过我觉得还是三个都写上吧更直观,记得注释,还有 H2 和 H1 的 timeout 你看看要不要一起改,还有服务端有没有设 timeout

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 3, 2024

I was under the impression that populateConfig is called, which will overwrite 0 with DefaultMaxIncomingStreams: https://github.com/quic-go/quic-go/blob/b8ea5c798155950fb5bbfdd06cad1939c9355878/config.go#L59

I will take another look in a few days and see if I understand all the defaults correctly.

So actually there is still KeepAlive, but it has been changed from 3 seconds to 10 seconds.

Where did you find this? I did not find the number 3 at all.


revisiting h1 and h2 also makes sense

@Fangliding
Copy link
Member

MaxIncomingStreams: -1, // don't allow the server to create bidirectional streams

对这个有点感兴趣,这是指服务端可以发起双向流吗,不过看起来这是 QUIC 层而不是 H3 层的东西所以有点鸡肋

这是http3的规定 不允许服务器发起双向流 (RFC 9114 6.1)

@RPRX
Copy link
Member

RPRX commented Aug 3, 2024

So actually there is still KeepAlive, but it has been changed from 3 seconds to 10 seconds.

Where did you find this? I did not find the number 3 at all.

https://github.com/XTLS/Xray-core/pull/3565/files

@Fangliding
Copy link
Member

Fangliding commented Aug 3, 2024

我觉得除了 MaxIdleTimeout,其它两个先和 quic-go H3 默认值保持一致吧,不然就成了 quic-go H3 特征但没有 KeepAlive 包?

现阶段纠结这些好像意义不大毕竟以后都是要换成uQUIC的 手动学舌效果一般 顺便现在的uquic除了firefox esr其他的好像并不完美 然后这个quic指纹实际流量占比又少得可怜

@RPRX
Copy link
Member

RPRX commented Aug 3, 2024

我觉得除了 MaxIdleTimeout,其它两个先和 quic-go H3 默认值保持一致吧,不然就成了 quic-go H3 特征但没有 KeepAlive 包?

现阶段纠结这些好像意义不大毕竟以后都是要换成uQUIC的 手动学舌效果一般 顺便现在的uquic除了firefox esr其他的好像并不完美 然后这个quic指纹实际流量占比又少得可怜

我们摆明了用的就是 quic-go H3,又不是学它,尽量保持默认值即可,不然会变成 SplitHTTP 版 quic-go 然后被出个 detector

uQuic 现在基于旧版 quic-go 还有 performance 问题:#3550 (comment) ,所以等它 v0.1.0

@RPRX
Copy link
Member

RPRX commented Aug 3, 2024

所以我刚用 Wireshark 看了下 SplitHTTP 的 quic-go 大多数包都有 DCID,Hysteria 是魔改成了没有?所以是精准的 Hy2 detector?

@APT-ZERO
Copy link

APT-ZERO commented Aug 3, 2024

Isn't it better to use connIdle from Policy settings as idle timeout of splithttp?
https://xtls.github.io/config/policy.html

@Fangliding
Copy link
Member

Isn't it better to use connIdle from Policy settings as idle timeout of splithttp? https://xtls.github.io/config/policy.html

It should not be handled in the transport layer (actually, the design of the entire policy is not good)

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 5, 2024

@RPRX check if this logic makes sense to you. tested everything with wireshark. really, the keepalive setting should depend on fingerprint setting

@RPRX
Copy link
Member

RPRX commented Aug 7, 2024

really, the keepalive setting should depend on fingerprint setting

对吧,因为 keepAlive 包的长度也是很固定的,我还有个小疑问是这些 keepAlive 包是基于主连接还是子连接?

@@ -131,7 +151,8 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in
DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) {
return dialContext(ctxInner)
},
IdleConnTimeout: 90 * time.Second,
IdleConnTimeout: connIdleTimeout,
ReadIdleTimeout: h2KeepalivePeriod,
Copy link
Member

Choose a reason for hiding this comment

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

这里?

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 8, 2024

(deleted some comment, ignore)

Right, because the length of keepAlive packets is also very fixed. I still have a little question: Are these keepAlive packets based on main connections or sub-connections?

I tested again, yes the size is also constant. However, what I meant is that the keepalive interval (h2 ping, not TCP, to be clear) is different between browsers. So it is strange to set fp=firefox but use keepalive interval from chrome.

The keepalive packets happen every N seconds as observed on wireshark, so for the outer connection, opening more streams inside doesn't change it.

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 8, 2024

If there are no further comments I will merge this PR tomorrow.

@RPRX
Copy link
Member

RPRX commented Aug 9, 2024

I tested again, yes the size is also constant. However, what I meant is that the keepalive interval (h2 ping, not TCP, to be clear) is different between browsers. So it is strange to set fp=firefox but use keepalive interval from chrome.

这也是我想说的,并且如果不用 XTLS 的话其实多加密一次也很明显,而且小包不止这个,虽然用 XTLS 的话还得加自动指纹才完美

If there are no further comments I will merge this PR tomorrow.

ReadIdleTimeout: h2KeepalivePeriod,ReadIdleTimeout

@mmmray
Copy link
Collaborator Author

mmmray commented Aug 9, 2024

ReadIdleTimeout: h2KeepalivePeriod,, ReadIdleTimeout?

I don't understand the question

// ReadIdleTimeout is the timeout after which a health check using ping
// frame will be carried out if no frame is received on the connection.
// Note that a ping response will is considered a received frame, so if
// there is no other traffic on the connection, the health check will
// be performed every ReadIdleTimeout interval.
// If zero, no health check is performed.
ReadIdleTimeout [time](https://pkg.go.dev/time).[Duration](https://pkg.go.dev/time#Duration)

This is from http2 package. I think it's the right parameter. But the name "idle timeout" is strange to me, and in quic the equivalent is called KeepAlivePeriod, so I renamed the const to this.

@RPRX RPRX merged commit 85e2ebc into XTLS:main Aug 10, 2024
36 checks passed
@RPRX
Copy link
Member

RPRX commented Aug 10, 2024

终于合并了这个 PR

@yuhan6665 @Fangliding 以后 commit title 并列写多个 changes 就用 85e2ebc 的格式:英文逗号分隔,每一小段首字母大写

以前我喜欢用 & 来分隔,然而像 4a1c0d7 就会有歧义

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.

4 participants