Skip to content

feat: respond to the June-2026 TSPU block (PQ fronting-domain marker + SYN REJECT mode)#375

Merged
sleep3r merged 2 commits into
mainfrom
feat/pq-fronting-domain-2026-06-block
Jul 7, 2026
Merged

feat: respond to the June-2026 TSPU block (PQ fronting-domain marker + SYN REJECT mode)#375
sleep3r merged 2 commits into
mainfrom
feat/pq-fronting-domain-2026-06-block

Conversation

@sleep3r

@sleep3r sleep3r commented Jul 7, 2026

Copy link
Copy Markdown
Owner

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_domain negotiates 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_bot checks 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-capable tls_domain does, 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.zig now probes as a modern client (-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 in 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 with tls_domain immutability — 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 #363 kernel SYN limiter is the same hashlimit srcip mechanism but hard-coded to DROP (correct for its anti-flood purpose). This PR adds a --reject / --drop option: --reject switches the over-limit target to REJECT --reject-with tcp-reset; DROP stays the default. Combine with --rate 54/minute --burst 1 for the article's ~1.1s per-IP sweet spot.

Not included (deliberate)

  • u32 iOS-SYN exemption (community V3). Not baking an unverified magic iOS-SYN byte pattern into a generated root firewall script — it needs a real iOS SYN capture to verify first.
  • Real ML-KEM-768 encapsulation for the 0x11ec share — std ships X-Wing, not the TLS 0x11ec combiner.
  • No hardcoded "vetted PQ-capable domain list" — sandbox has no outbound network to verify one; the tooling + docs point operators at the openssl probe / @Sni_checker_bot instead.

Testing

  • 58/58 ctl + 206/206 proxy unit tests pass. New tests: classifyOpenSslOutput for the PQ and classical-x25519 cases; renderScript uses REJECT tcp-reset; overLimitTarget maps the reject flag.
  • Linux cross-build (-Dtarget=x86_64-linux) is clean. (Native macOS build fails pre-existing on bench.zig / tui.zig / ipv6hop.zig nanosleep — unrelated to this change.)

Follow-ups

sleep3r added 2 commits July 7, 2026 16:56
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.
@sleep3r sleep3r merged commit 3ca5450 into main Jul 7, 2026
12 of 13 checks passed
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.

1 participant