Skip to content

feat: implement TTFB measurement as default#9

Open
navidmafi wants to merge 2 commits intonoql-net:mainfrom
navidmafi:main
Open

feat: implement TTFB measurement as default#9
navidmafi wants to merge 2 commits intonoql-net:mainfrom
navidmafi:main

Conversation

@navidmafi
Copy link

Following the Iran-Israel war in June 2025, some implementations of the GFW (namely the IRGFW) have shifted TLS fingerprinting and sabotage to a more "passive" state.

Specifically, the TCP handshake and TLS ClientHello typically proceed without interruption — the server completes the handshake and even returns the ServerHello and related messages successfully. However, once the TLS session is established, any client-initiated PSH segment containing application data (e.g., an HTTP GET /) triggers silent packet drops and retransmissions, eventually leading to a timeout on any read operation on the socket.

This PR introduces a lightweight, and perhaps naive verification mechanism that issues a minimal HTTP GET / request over the established TLS channel and attempts to read a single response byte. If the connection remains usable (if a reply is received, be it a 200, 404, etc. ) then we assume passive blocking is not taking place. Otherwise, the observed behavior (no ACKs, repeated retransmissions) indicates that application data is being suppressed post-handshake, consistent with what we've seen recently.

Feedback is welcome.

@navidmafi
Copy link
Author

Previously H2 connections were being treated as http/1.1 resulting in false positives. The results make much more sense now.

Please review carefully, especially the assumptions made about a "successful handshake".

@navidmafi
Copy link
Author

Given today's relief on the IRGFW and after some testing, the results make sense and more importantly, found to be representative of real-world TLS usage.

@ranthe21
Copy link
Collaborator

ranthe21 commented Aug 8, 2025

Hi, thanks for the PR.
This is a nice feature.

A concern I have:
Does the TTFB test do its work separately from other tests?
If yes, good.
If no, please:

  1. Keep the default run focused on handshake analysis, and run the TTFB probe as a separate path in code so it does not alter baseline behavior.
  2. Expose granular timings like resolve_ms, connect_ms, tls_ms, first_byte_ms in the struct so tests can assert each stage independently.

@navidmafi
Copy link
Author

Thank you for reviewing this PR.

The changes do alter the current behavior intentionally, as I explained in my first comment regarding passive blocking. I strongly believe this should become the new behavior.

Regarding the second point, could you please clarify what the expected outcome should be? The current struct already exposes timings, so I’m not sure what else might be missing.

@ranthe21
Copy link
Collaborator

Ok.
The TTFB is good.
But, what do you think if we keep the previous TLS Handshake without the host, and add TTFB (with host) separately?
To detect if there are any differences and anomalies in IRGFW.

@navidmafi
Copy link
Author

Sorry for responding this late. To be honest, I've been seeing the "passive blocking" behavior again and decided to check back on this.

I believe that we already separate TLS and TTFP with two distinct columns. I have not conditionally "bound" a successful TLS handshake to TTFB. It's up to the user to interpret whether a sequence of "successful TLS handshake and then unconditional timeout" is passive blocking or not. Can you please check again?

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