fix: openvpn handshake must not inherit the per-dial timeout#2925
fix: openvpn handshake must not inherit the per-dial timeout#2925Easy-Ez wants to merge 1 commit into
Conversation
An OpenVPN server that performs push-peer-info / PAM / client-connect checks needs longer to finish the control-channel handshake than the single connection's dial timeout (C.DefaultTCPTimeout, 5s) that happens to trigger it. handshakeContext was derived from that dial context, so the 30s DefaultHandshakeTimeout was effectively capped at ~5s and the handshake (key-method-2 exchange + PUSH_REPLY) timed out before it could finish — even with correct credentials and peer-info. - Run the handshake under the outbound's run context with the full handshake timeout, since the tunnel is shared infrastructure reused by every connection rather than owned by the dial that triggers it. - After the tunnel is established, refresh the dial deadline so the very first request (which paid for the one-time handshake) is not failed for exhausting its own budget. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
We believe that servers unable to complete a handshake within 5 seconds are not worth using. In light of this, |
|
Hi @wwqgtxx,先谢谢你帮忙合了 #2926 🙏 也理解你对握手超时这块的考虑。 不过我这边遇到个有点尴尬的情况,想跟你说一下,看有没有别的办法。 我连的是公司的 OpenVPN 网关,它用 push-peer-info 做设备准入(就是 现在 Alpha 上,握手是跟着单次拨号的超时走的( 我在本地试着把这次握手单独给个超时(不跟拨号超时绑),它 7 秒左右就握手成功了,之后走这条隧道的请求都很快,基本 0.1s: 我自己的一点小想法(不一定对哈):握手其实是建隧道时的一次性开销,隧道建好之后所有连接都复用同一条,所以这 7 秒整个会话就花一次,后面都不受影响。所以想问问你,这种情况下能不能让握手用它自己的超时跑、不继承单次拨号的 deadline? 当然完全尊重你们的判断,要是觉得不合适我也理解,那我就自己在本地维护一份补丁。如果你觉得这么改 OK,我很乐意提个最小改动的 PR。再次感谢你维护 mihomo 🙏 |
Problem
The OpenVPN outbound establishes its control-channel tunnel lazily — on the first connection that needs it. The handshake context, however, was derived from that triggering dial's context:
Because
ctxalready carries the per-dial deadline (C.DefaultTCPTimeout, 5s), the effective handshake timeout wasmin(5s, 30s) = 5s— the 30sDefaultHandshakeTimeoutnever actually applied. Any OpenVPN server whose control-channel handshake takes longer than ~5s (TLS-auth, PAM /--client-connectscripts, a largePUSH_REPLY, slow links) fails the handshake before it can finish, even with correct credentials.Fix
o.runCtx) with the fullDefaultHandshakeTimeout, instead of inheriting the triggering dial's short deadline. The tunnel is shared, long-lived infrastructure reused by every connection — its one-time handshake should not be bounded by whichever single dial happens to trigger it.afterRunContext) so the first request — which paid for the one-time handshake — is not failed for having spent its own short budget building shared infrastructure.Notes
This is an independent, pre-existing bug, not tied to any specific feature. It was discovered while implementing custom peer-info support (#2926), but it affects any slow OpenVPN handshake. Submitted as its own PR per the one-change-per-PR guideline.
go build ./adapter/outbound/passes.问题
OpenVPN 出站的控制信道隧道是惰性建立的 —— 由第一条需要它的连接触发。但握手 context 继承自那条触发拨号的 context:
由于
ctx已经带着单次拨号的 deadline(C.DefaultTCPTimeout,5s),实际握手超时是min(5s, 30s) = 5s—— 30s 的DefaultHandshakeTimeout从未真正生效。任何控制信道握手耗时超过 ~5s 的服务端(TLS-auth、PAM /--client-connect脚本、较大的PUSH_REPLY、慢链路)都会在握手完成前超时,即使账密完全正确。修复
o.runCtx)跑满完整的DefaultHandshakeTimeout,不再继承触发拨号的短 deadline。隧道是被所有连接复用的、长生命周期的共享资源,它的一次性握手不应被「恰好触发它的那条拨号」的超时所限制。afterRunContext),使「为一次性握手买单」的首个请求,不因把自己的短预算花在建设共享设施上而失败。说明
这是一个独立的、早已存在的 bug,与任何具体功能无关。它是在实现自定义 peer-info(#2926)时发现的,但影响任何慢速 OpenVPN 握手。按「一个 PR 只做一件事」的规范,单独成 PR 提交。
go build ./adapter/outbound/通过。🤖 Generated with Claude Code