Fall back to HTTP/2 when the edge rejects the QUIC handshake - #1744
Open
Shubham-Padkonde wants to merge 1 commit into
Open
Shubham-Padkonde wants to merge 1 commit into
Shubham-Padkonde wants to merge 1 commit into
Conversation
`--protocol auto` only leaves QUIC when `isQuicBroken` recognises the failure: an idle timeout, or a transport error caused by "operation not permitted". A handshake the peer rejects with a CRYPTO_ERROR -- for example TLS alert 120, no_application_protocol, from a middlebox that intercepts QUIC without offering the tunnel's ALPN -- matches neither, so `selectNextProtocol` keeps choosing the current protocol and the connection retries QUIC forever while the tunnel stays down. Treat a CRYPTO_ERROR raised by the peer as a broken QUIC transport, so the connection switches to the fallback protocol on the first failure like it does for the other unrecoverable cases. Fixes cloudflare#1736 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1736
Problem
With
--protocol auto, a QUIC handshake that the peer rejects (rather than blackholes) never triggers protocol fallback. The reporter's tunnel retried QUIC indefinitely with exponential backoff and never registered a connection:selectNextProtocolswitches protocol whenprotocolBackoff.ReachedMaxRetries()or whenisQuicBroken(cause)and a fallback exists.isQuicBrokenrecognises only two shapes today —*quic.IdleTimeoutError(UDP blackholed) and a*quic.TransportErrorwhose text containsoperation not permitted. A remote CRYPTO_ERROR matches neither, so theelsearm runs and reassigns the current protocol (still QUIC), and the loop retries QUIC forever.0x178is CRYPTO_ERROR for TLS alert 120,no_application_protocol: something on the path terminated the TLS handshake because it doesn't offer the ALPN cloudflared needs. No amount of QUIC retrying recovers from that, and HTTP/2 would work — which is exactly whatautoexists to do.Fix
Treat a CRYPTO_ERROR raised by the peer as a broken QUIC transport, next to the existing cases:
The check is deliberately narrow: only
Remoteerrors (the peer rejected us, so our own local crypto failures are unaffected) and only the CRYPTO_ERROR range (0x100–0x1ff). Users who pin--protocol quicstill have no fallback and keep retrying, sinceselectNextProtocolreturns early when the selector offers none.The second half of the issue — the
UDP Connectivityprecheck reportingstatus=passwhile these dials fail — is a separate code path and is not addressed here.Test
TestFallbackOnRemoteCryptoErrordrivesselectNextProtocolwith anEdgeQuicDialErrorwrapping a remoteTransportErrorof code0x178, exactly as the dial path reports it, and asserts the connection moves to HTTP/2 on the first failure.Before:
After:
go vetandgofmtare clean.TestHTTP2ConfigurationSetin theconnectionpackage fails identically on an unmodified tree in my environment, so it is unrelated.Disclosure: this change was written by Claude Code (Claude Opus 5) working as my agent, at my direction. The test, lint and reproduction output quoted above comes from real runs in my local environment; I am accountable for what is submitted here and will follow up on review feedback.
🤖 Generated with Claude Code