Summary
The transport=tls mimicry pump (bin/yipd/src/tls.rs, 3c.2) serves one TCP+TLS connection at a time (documented in the module header — Epoll watches exactly two fds; only peers.first() is served). PR #60-era review hardened the cheapest availability gap (a stalled handshake can no longer pin the slot — HANDSHAKE_TIMEOUT + both-role backoff, shipped in 3c.2), but two related limitations remain, both rooted in the single-connection design:
1. A completed-but-idle zero-auth TLS connection still holds the slot
Because the outer TLS is zero-auth by design, an attacker (or a random internet scanner on a public listen, especially once yip defaults to 443) can complete the TLS handshake and then never drive the inner Noise-IK handshake. pump() tears down only on I/O/framing errors, not on "inner handshake never completed" — so the connection sits in pump servicing ticks while the real peer is locked out. Severity is lower than the pre-fix stalled-handshake DoS (it costs the attacker a full TLS handshake per attempt, which backoff rate-limits) but it is still an availability gap unique to this transport (the QUIC sibling accepts many connections concurrently).
Fix directions: an inner-handshake-completion deadline in pump (drop the connection if PeerManager reports no established session within N seconds), and/or accept concurrently and let the inner handshake pick the winner.
2. Multi-peer transport=tls silently serves only the first peer
run_tls serves peers.first() and ignores the rest with no runtime warning (in-code TODO(3c.2 follow-up)). A config with >1 peer under transport=tls looks like it works but silently drops all but one peer.
Fix directions: one run_tls per peer on distinct threads/ports, or a multiplexing pump analogous to quic.rs's QuicEndpoint. At minimum, log a warning when peers.len() > 1.
Scope
Both fit a multi-connection TLS transport refactor (or the relay-tier REALITY milestone 3c.3), not the 3c.2 costume milestone. Filing to track; not a blocker for 3c.2 (opt-in, last-resort, single-peer-direct path).
Summary
The
transport=tlsmimicry pump (bin/yipd/src/tls.rs, 3c.2) serves one TCP+TLS connection at a time (documented in the module header —Epollwatches exactly two fds; onlypeers.first()is served). PR #60-era review hardened the cheapest availability gap (a stalled handshake can no longer pin the slot —HANDSHAKE_TIMEOUT+ both-role backoff, shipped in 3c.2), but two related limitations remain, both rooted in the single-connection design:1. A completed-but-idle zero-auth TLS connection still holds the slot
Because the outer TLS is zero-auth by design, an attacker (or a random internet scanner on a public
listen, especially once yip defaults to 443) can complete the TLS handshake and then never drive the inner Noise-IK handshake.pump()tears down only on I/O/framing errors, not on "inner handshake never completed" — so the connection sits inpumpservicing ticks while the real peer is locked out. Severity is lower than the pre-fix stalled-handshake DoS (it costs the attacker a full TLS handshake per attempt, which backoff rate-limits) but it is still an availability gap unique to this transport (the QUIC sibling accepts many connections concurrently).Fix directions: an inner-handshake-completion deadline in
pump(drop the connection ifPeerManagerreports no established session within N seconds), and/or accept concurrently and let the inner handshake pick the winner.2. Multi-peer
transport=tlssilently serves only the first peerrun_tlsservespeers.first()and ignores the rest with no runtime warning (in-codeTODO(3c.2 follow-up)). A config with >1 peer undertransport=tlslooks like it works but silently drops all but one peer.Fix directions: one
run_tlsper peer on distinct threads/ports, or a multiplexing pump analogous toquic.rs'sQuicEndpoint. At minimum, log a warning whenpeers.len() > 1.Scope
Both fit a multi-connection TLS transport refactor (or the relay-tier REALITY milestone 3c.3), not the 3c.2 costume milestone. Filing to track; not a blocker for 3c.2 (opt-in, last-resort, single-peer-direct path).