Skip to content

fix: reconnect OpenVPN on server soft reset#2978

Merged
wwqgtxx merged 2 commits into
MetaCubeX:Alphafrom
freephilx:Alpha
Jul 16, 2026
Merged

fix: reconnect OpenVPN on server soft reset#2978
wwqgtxx merged 2 commits into
MetaCubeX:Alphafrom
freephilx:Alpha

Conversation

@freephilx

Copy link
Copy Markdown

OpenVPN servers can send P_CONTROL_SOFT_RESET_V1 to begin data-channel key renegotiation. After the initial handshake, mihomo no longer reads the control stream, so the reset remains queued and the outbound can stop forwarding traffic until ping-restart tears down the session.

Keep a post-handshake watcher on the raw control stream. When it receives a valid soft-reset packet for the current server session and a nonzero key epoch, close the client and TUN device; the existing lazy startup path performs a fresh handshake on the next request. Reading the raw stream is intentional because a new key epoch can reset message IDs, which the existing ordered control channel may otherwise treat as an old or duplicate message.

This is intentionally a reconnect fallback, not in-session key renegotiation. It restores the outbound without waiting for the keepalive timeout while keeping the change scoped to the existing session lifecycle. Existing connections can still be interrupted during the reconnect.

Tests:

  • go test ./...
  • go test ./transport/openvpn ./adapter/outbound
  • go test -race ./transport/openvpn
  • go vet ./transport/openvpn ./adapter/outbound

Coverage includes plain, tls-auth, and tls-crypt control channels, plus malformed, initial-key, and wrong-session reset packets.

@freephilx

freephilx commented Jul 15, 2026

Copy link
Copy Markdown
Author

Manual verification against the actual OpenVPN server:

  • Runtime: packaged alpha-51c873d9, which contains the same soft-reset reconnect path as this PR.
  • Observation window: 2026-07-16 00:24-06:56 CST (about 6.5 hours).
  • Server-initiated soft resets handled: 6.
  • ping-restart timeout: 0 (the previous process logged 3 timeouts during about 4.5 hours).
  • Soft-reset watcher errors: 0.
  • The next request routed through http-proxy / openvpn-1 appeared within 1.9-5.2 seconds after each reset.

This confirms that the reconnect fallback avoids the previous periodic blackhole until ping-restart. Existing in-flight connections can still fail during the short reconnect window, as expected for reconnect rather than in-session rekey.

The live package predates the validation hardening in PR head fd0153d6; the PR head's malformed-packet, session-ID, and key-ID handling is covered by the automated tests listed in the PR description.

@freephilx
freephilx marked this pull request as ready for review July 15, 2026 22:58
@wwqgtxx

wwqgtxx commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

I pushed a follow-up commit to keep the soft-reset lifecycle inside the OpenVPN client. Instead of exposing WaitForSoftReset to the outbound layer and reading control packets directly from PacketMux, I now consume post-handshake packets through ControlChannel. This preserves normal ACK, ordering, and pending-message bookkeeping, while intercepting a valid soft reset before the old epoch's message-ID ordering can reject its reset sequence.

I made this change because soft resets and control epochs are transport-level protocol details that the outbound should not need to manage. After the handshake, the client starts an internal control watcher; when it detects a new key epoch or the control channel terminates, it closes the mux. The existing outbound data loop then performs the usual TUN and session cleanup. I also added tests covering automatic shutdown, ordinary control-message ACKs, pending-state cleanup, malformed packets, and session/key validation.

@freephilx

freephilx commented Jul 16, 2026

Copy link
Copy Markdown
Author

Thanks for the follow-up. I rebuilt and deployed PR head aac5a8e1 against the actual OpenVPN server.

Observation window: 2026-07-16 14:03-16:42 CST (about 2 hours 39 minutes).

  • The same mihomo process remained running throughout the observation window.
  • Two link closures occurred at the expected server reset cadence: 14:58:46 and 15:58:03 CST.
  • ping-restart timeout: 0.
  • The next internal traffic routed through proxy-direct / proxy-openvpn-1 succeeded after approximately 5.9 seconds and 9.4 seconds, respectively.
  • No additional OpenVPN read/write or soft-reset watcher errors were logged.

This confirms in live use that the internal ControlChannel watcher and the existing outbound cleanup/reconnect path behave as intended. Thanks for the refactor.

@wwqgtxx

@wwqgtxx
wwqgtxx merged commit 0ee5841 into MetaCubeX:Alpha Jul 16, 2026
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.

2 participants