Reassemble non-contiguous QUIC CRYPTO frames for TLS parsing - #18
Merged
thearossman merged 3 commits intoJul 24, 2026
Merged
Conversation
Chrome splits its QUIC ClientHello across multiple CRYPTO frames at non-contiguous cryptostream offsets, interleaved with PING/PADDING and spread over several Initial packets. The previous reassembly used a flat per-direction buffer with a strict in-order expected_offset and returned MissingCryptoFrames on the first offset gap, so the embedded TLS handshake never parsed for these connections. Replace the flat buffers with per-direction sparse cryptostream maps (client_crypto/server_crypto: BTreeMap<u64, Vec<u8>>) plus client_consumed/server_consumed offset counters. parse_frames now returns each CRYPTO chunk paired with its absolute offset; the caller drops chunks into the map and feeds the TLS parser the longest contiguous [consumed..N) prefix as bytes accumulate across packets, tolerating Incomplete and skipping (rather than erroring on) a failed message so one bad parse can't block the connection. Verified offline against a captured Chrome->google.com QUIC trace: SNI extraction goes from empty to www.google.com (matching Wireshark's reassembly), with no regression on single-frame ClientHellos.
Collaborator
|
Thank you so much, Nikita! Can you run |
Contributor
Author
|
No worries, should be good now! |
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.
Chrome splits its QUIC ClientHello across multiple CRYPTO frames at non-contiguous cryptostream offsets, interleaved with PING/PADDING and spread over several Initial packets. The previous reassembly used a flat per-direction buffer with a strict in-order expected_offset and returned MissingCryptoFrames on the first offset gap, so the embedded TLS handshake never parsed for these connections.
Replace the flat buffers with per-direction sparse cryptostream maps (client_crypto/server_crypto: BTreeMap<u64, Vec>) plus client_consumed/server_consumed offset counters. parse_frames now returns each CRYPTO chunk paired with its absolute offset; the caller drops chunks into the map and feeds the TLS parser the longest contiguous [consumed..N) prefix as bytes accumulate across packets, tolerating Incomplete and skipping (rather than erroring on) a failed message so one bad parse can't block the connection.
Verified offline against a captured Chrome->google.com QUIC trace: SNI extraction goes from empty to www.google.com (matching Wireshark's reassembly), with no regression on single-frame ClientHellos.
Here is a pcap that shows that crypto frames are interleaved with ping and padding frames in Chrome:
pcap.zip