This page documents the implementation of TCP/TLS splitting strategies and TCB desynchronization attacks used for censorship circumvention in Firestack. The system employs two primary mechanisms: splitter for direct TCP/TLS splitting and overwriteSplitter for TCB desynchronization with TTL manipulation. These techniques target the first data segment of TCP connections to bypass Deep Packet Inspection (DPI) systems.
Key Components:
splitter — Direct TCP/TLS record splitting without content modification. intra/dialers/direct_split.go37-42overwriteSplitter — TCB desynchronization using fake payload and restricted TTL. intra/dialers/split_and_desync.go45-55tracert. intra/dialers/split_and_desync.go109-176ttlcache — Performance optimization for TTL storage using core.Sieve. intra/dialers/split_and_desync.go41SigCond — First-write coordination primitive for one-time state transitions (false -> true). intra/core/sigcond.go29-32Sources: intra/dialers/retrier.go1-120 intra/dialers/split_and_desync.go1-55 intra/dialers/direct_split.go1-45 intra/core/sigcond.go1-32
The splitting and desynchronization system consists of three main components wrapped around a standard net.TCPConn. The retrier orchestrates which implementation to use based on the settings.DialerOpts.
Diagram: Splitting and Desync Component Hierarchy
Key Design Points:
| Component | Responsibility | Interface |
|---|---|---|
retrier | Strategy selection, retry orchestration, connection lifecycle. intra/dialers/retrier.go73-117 | core.DuplexConn, core.RetrierConn intra/dialers/retrier.go119-120 |
splitter | Direct TCP/TLS splitting on first write. intra/dialers/direct_split.go37-42 | core.DuplexConn, core.RetrierConn intra/dialers/direct_split.go44-45 |
overwriteSplitter | TCB desynchronization with TTL manipulation. intra/dialers/split_and_desync.go45-55 | core.DuplexConn, core.RetrierConn intra/dialers/split_and_desync.go57-58 |
SigCond | First-write coordination between goroutines. intra/core/sigcond.go29-32 | One-time signal primitive |
Sources: intra/dialers/retrier.go73-120 intra/dialers/direct_split.go37-45 intra/dialers/split_and_desync.go45-58 intra/dialers/retrier.go119-120
splitterThe splitter type wraps a net.TCPConn and intercepts the first Write() call to split the data into multiple segments. This defeats DPI systems that rely on matching patterns in the first TCP segment.
Diagram: splitter Write Logic
The splitter ensures that only the first writer performs the split by using s.used.Signal(). intra/dialers/direct_split.go53-56 Subsequent writes or concurrent attempts that fail to signal (because the state already transitioned) fall back to a standard conn.Write(b). intra/dialers/direct_split.go58-59
Sources: intra/dialers/direct_split.go48-73
The splitter supports two direct splitting strategies via writeSplit():
SplitTCP Strategy: Calls writeTCPSplit(w, b) to split the buffer at an arbitrary position. intra/dialers/direct_split.go64-65SplitTCPOrTLS Strategy: Calls writeTCPOrTLSSplit(w, b) which attempts to parse TLS record headers. intra/dialers/direct_split.go66-67 If valid TLS is detected, it fragments the record into two segments by modifying the record length in the header.Sources: intra/dialers/direct_split.go61-73
overwriteSplitterThe overwriteSplitter implements a TCB (Transmission Control Block) desynchronization attack. It sends a "fake" packet with a low TTL that reaches the censor but not the destination, followed by the real packet. intra/dialers/split_and_desync.go43-55
Diagram: Desync Attack Workflow
Sources: intra/dialers/split_and_desync.go109-176 intra/dialers/split_and_desync.go183-258
The system estimates the TTL distance to the DPI middlebox using tracert(). intra/dialers/split_and_desync.go109-176
desync_max_ttl) to a range of destination ports. intra/dialers/split_and_desync.go156-174unix.Recvmsg with unix.MSG_ERRQUEUE to retrieve ICMP messages from the kernel error queue. intra/dialers/split_and_desync.go217-221unix.IP_RECVERR or unix.IPV6_RECVERR in socket control messages via exceedsTTL and exceedsHopLimit. intra/dialers/split_and_desync.go73-105Measured TTLs are stored in ttlcache, a core.Sieve[netip.Addr, int], for 30 seconds to avoid redundant traceroutes for the same destination. intra/dialers/split_and_desync.go35-41
Sources: intra/dialers/split_and_desync.go35-176 intra/dialers/split_and_desync.go216-258
The attack involves precise socket option manipulation:
unix.IP_TTL or unix.IPV6_UNICAST_HOPS to ensure the fake segment reaches the censor but is dropped before the destination. intra/dialers/split_and_desync.go162-165overwriteSplitter structure manages a payload that must be smaller than the first written packet to effectively desynchronize the TCB state. intra/dialers/split_and_desync.go53-55desync_http1_1str for HTTP-based desynchronization. intra/dialers/split_and_desync.go29SigCondBoth splitters use SigCond to ensure only one goroutine performs the split on the first write. intra/dialers/direct_split.go49-59 intra/dialers/split_and_desync.go48-49
Signal(): Atomically sets the condition to true and closes the internal channel to wake waiters. intra/core/sigcond.go70-76Cond(): Checks if the signal has already been fired. intra/core/sigcond.go41-43Wait(): Blocks until the condition is signaled. intra/core/sigcond.go47-52TryWait(timeout): Blocks with a timeout, returning true if signaled or false on timeout. intra/core/sigcond.go57-67rwext: Wraps a connection and extends read/write deadlines automatically on every I/O operation based on settings.DialerOpts. intra/rwconn.go21-24 intra/rwconn.go52-60 It also handles ReadFrom and WriteTo by disabling deadlines (extending forever) when zero-copy methods are used. intra/rwconn.go63-90ippPins: A core.Sieve that maintains a mapping between ip:port and successful dialer IDs to prioritize working paths in multi-dialer scenarios. intra/dialers/retrier.go68 intra/dialers/retrier.go177-196calcTimeout: Dynamically calculates retry timeouts based on RTT (SYN to SYNACK) to avoid unnecessary retries while maintaining responsiveness. intra/dialers/retrier.go134-142Sources: intra/core/sigcond.go29-76 intra/rwconn.go19-124 intra/dialers/retrier.go68-196 intra/dialers/retrier.go134-142
Refresh this wiki