srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/PLAN.md
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2026-05-26 09:16:00 +0200
committersrdusr <[email protected]>2026-05-26 09:16:00 +0200
commitc098f1742bb04fbe41fc6cf492cd334efef734eb (patch)
tree8af2c79ec321357d2766fdab03d6a870ff7ceb6c /PLAN.md
parent2d010c9f851ea4eb851179db012c8977ce6e4bd5 (diff)
downloadpacketeer-c098f1742bb04fbe41fc6cf492cd334efef734eb.tar.gz
packeteer-c098f1742bb04fbe41fc6cf492cd334efef734eb.zip
Add deeper TLS (ServerHello, ALPN); fix a QUIC/TCP false-positive bug
TLS: ServerHello now reports the negotiated version and cipher suite alongside the existing ClientHello SNI support, plus ClientHello's ALPN extension. ServerHello's version prefers the supported_versions extension over legacy_version when present - TLS 1.3 always sets legacy_version to 0x0303 for middlebox compatibility, so reading only that field would misreport every real TLS 1.3 connection as 1.2. Cipher suite names are hardcoded only for TLS 1.3's five suites (a small closed set); everything else reports as raw hex rather than a guessed name from a "common suites" list. Live-verifying that against a real Cloudflare TLS 1.3 handshake surfaced a real, unrelated bug in the QUIC dissector added earlier: it was also being tried against TCP port-443 payloads (a side effect of the earlier L7Registry port-sharing fix), and produced false "QUIC" labels on TLS ciphertext continuation fragments - large encrypted records split across multiple TCP segments, each fed to the parser independently since this project doesn't reassemble by default, so a later fragment's effectively random bytes occasionally passed as a plausible QUIC header. Fixed in two layers: parse_quic() now enforces RFC 9000's real 20-byte cap on connection ID lengths, closing most of the long-header false- positive surface; and L7Dissector gained a transport() method (defaulting to kAny, so every other dissector's behavior is unchanged) so QuicDissector can declare itself UDP-only - necessary because the length cap alone can't touch QUIC's short-header form, which by design has no structural signal beyond one bit once header protection can't be removed without connection state. Re-verified against the identical live scenario afterward: zero false QUIC labels on the same Cloudflare TCP handshake, and a repeat of the earlier real HTTP/3 capture confirmed genuine QUIC still decodes correctly on UDP.
Diffstat (limited to 'PLAN.md')
-rw-r--r--PLAN.md40
1 files changed, 40 insertions, 0 deletions
diff --git a/PLAN.md b/PLAN.md
index a4db288..9837ebb 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -587,3 +587,43 @@ None currently open.
correctly decoded a real RTP video stream (payload type 96,
incrementing sequence numbers, one consistent SSRC across the whole
stream) and a real RTCP Sender Report ffmpeg sent alongside it.
+- Deeper TLS: ServerHello (negotiated version, cipher suite) alongside
+ the existing ClientHello (SNI) support, plus ClientHello's ALPN
+ extension. Both hellos share almost all of their wire structure, so
+ the record/handshake header parsing was factored into one shared
+ detail::read_tls_handshake() rather than duplicated a second time.
+ ServerHello's negotiated_version prefers the supported_versions
+ extension over legacy_version when present: TLS 1.3 always sets
+ legacy_version to 0x0303 (TLS 1.2) for middlebox compatibility, so
+ reading only that field would misreport every real TLS 1.3
+ connection as 1.2. Cipher suite names are hardcoded only for TLS
+ 1.3's five suites (RFC 8446 B.4, a small closed set) - everything
+ else is reported as a raw hex value rather than guessed at from a
+ curated "common suites" list, which would be more misleading than a
+ plain number for the suites it didn't happen to cover.
+ Live-verified against a real Cloudflare TLS 1.3 handshake on
+ wlp1s0: "TLS ServerHello version=TLS1.3 cipher=TLS_AES_256_GCM_SHA384"
+ from cloudflare.com's actual production server, confirming both the
+ supported_versions override and the cipher-suite naming.
+ That same live capture surfaced a real, unrelated bug in the QUIC
+ dissector added earlier this session: QuicDissector was also being
+ tried against *TCP* port-443 payloads (a side effect of the
+ L7Registry fix that let QUIC and TLS share port 443 at all), and
+ produced real false "QUIC" labels on TLS 1.3 ciphertext continuation
+ fragments - large encrypted records split across multiple TCP
+ segments, each fed to the parser independently since this project
+ doesn't reassemble by default, so a later fragment's effectively
+ random bytes occasionally passed as a plausible QUIC header. Fixed
+ in two layers: (1) parse_quic() now enforces RFC 9000 17.2's real
+ 20-byte cap on connection ID lengths, closing most of the
+ long-header false-positive surface; (2) L7Dissector gained a
+ transport() method (default kAny, preserving every other
+ dissector's exact current behavior unchanged) so QuicDissector could
+ declare itself UDP-only - necessary because layer (1) alone
+ couldn't touch QUIC's short-header form at all, which by design has
+ no structural signal beyond one bit once header protection can't be
+ removed without connection state. Re-verified against the identical
+ live scenario: zero false QUIC labels on the same Cloudflare TCP
+ handshake afterward, and a repeat of the earlier real HTTP/3 capture
+ against google.com confirmed genuine QUIC traffic still decodes
+ correctly on UDP.