feat: respond to the June-2026 TSPU block (PQ fronting-domain marker + SYN REJECT mode)#375
Merged
Merged
Conversation
Since the night of 4->5 June 2026 the TSPU blocks iOS MTProto clients (and everyone sharing their NAT egress IP) when the `tls_domain` negotiates only classical x25519 and not the post-quantum hybrid X25519MLKEM768. The signal is a property of the domain: the censor probes the SNI out-of-band for PQ support, so echoing a 0x11ec ServerHello does not buy it back — only choosing a PQ-capable domain does, which our FakeTLS then mimics via the existing 0x11ec key_share echo. fronting_domain.zig now probes the domain as a modern client would (`-groups X25519MLKEM768:X25519`), adds a `.pq_capable` verdict, and warns when a domain does only classical x25519 (the marker) or an HRR. A legacy x25519-only fallback probe avoids false alarms when the local OpenSSL predates 3.5. Guidance flipped accordingly in config.zig, config.toml.example, THREAT_MODEL.md and ARCHITECTURE.md: prefer a domain that negotiates single-round X25519MLKEM768; classical-x25519-only is now the dangerous class. Note this collides with `tls_domain` immutability — an existing deploy on a now-marked domain cannot migrate without invalidating every share link.
The kernel SYN limiter dropped over-limit SYNs silently, which is correct for pure flood defense but makes a throttled client wait a full TCP retransmit (~20s to connect). When the limiter is used to survive the June-2026 TSPU parallel-connect block instead of a flood, an RST lets the client retry immediately (~5s), as the community fix found. Add `--reject` / `--drop`: `--reject` switches the over-limit target to `REJECT --reject-with tcp-reset`; DROP stays the default. The target is baked into the generated script via an ACTION variable, the rule-landed check and the counter are generalized to match either target, and the summary box shows the action. Combine with `--rate 54/minute --burst 1` for the article's ~1.1s per-source-IP sweet spot.
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.
Context
The Telegraph doc documents the RKN/TSPU block of MTProto proxies that started the night of 4→5 June 2026. It describes two independent attacks; this PR responds to both where mtproto.zig can.
1. The X25519MLKEM768 domain marker (the important one)
Even past any SYN limit, iOS clients — and everyone sharing their NAT egress IP — get blocked when the
tls_domainnegotiates only classical x25519 (no post-quantum X25519MLKEM768). The signal is a property of the domain: the censor probes the SNI out-of-band for PQ support (evidence: the community fix is "change the domain",@Sni_checker_botchecks a domain, a self-signed backend needs OpenSSL 3.5+, and one domain's two IPs can score differently). So our existing 0x11ec ServerHello echo — which fixes the connection-level downgrade tell — does not address this; only choosing a PQ-capabletls_domaindoes, which our FakeTLS then mimics via that same echo.This inverts the project's prior doctrine ("prefer single-round x25519 domains, e.g. rutube.ru") — that class is now exactly what gets iOS flagged.
Changes:
fronting_domain.zignow probes as a modern client (-groups X25519MLKEM768:X25519), adds a.pq_capableverdict, and warns when a domain does only classical x25519 (the marker) or an HRR. A legacy x25519-only fallback probe avoids false alarms when the local OpenSSL predates 3.5.config.zig,config.toml.example,THREAT_MODEL.md,ARCHITECTURE.md: prefer single-round X25519MLKEM768; classical-x25519-only is now the dangerous class. Documented the collision withtls_domainimmutability — an existing deploy on a now-marked domain cannot migrate without invalidating every share link.2. The parallel-connect / SYN block
TSPU flags >1 parallel TLS attempt to the server within <1s (non-iOS only, and only behind TSPU hosts). The community fix is a per-source-IP SYN limit that REJECTs with tcp-reset rather than DROPs — a silent DROP makes a throttled client wait a full TCP retransmit (~20s to connect) vs ~5s for an RST.
Our
#363kernel SYN limiter is the samehashlimit srcipmechanism but hard-coded toDROP(correct for its anti-flood purpose). This PR adds a--reject/--dropoption:--rejectswitches the over-limit target toREJECT --reject-with tcp-reset; DROP stays the default. Combine with--rate 54/minute --burst 1for the article's ~1.1s per-IP sweet spot.Not included (deliberate)
0x11eccombiner.opensslprobe /@Sni_checker_botinstead.Testing
classifyOpenSslOutputfor the PQ and classical-x25519 cases;renderScript uses REJECT tcp-reset;overLimitTarget maps the reject flag.-Dtarget=x86_64-linux) is clean. (Native macOS build fails pre-existing onbench.zig/tui.zig/ipv6hop.zignanosleep— unrelated to this change.)Follow-ups
0x11ecand pin down the exact TSPU detection model (out-of-band SNI probe vs observed key share).