transport=tls: single-connection pump — completed-idle slot hold + silent multi-peer drop (3c.2 follow-up) #61

Open
opened 2026-07-13 05:39:26 +00:00 by vxfemboy · 0 comments
vxfemboy commented 2026-07-13 05:39:26 +00:00 (Migrated from github.com)

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=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).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
femboy/yip#61
No description provided.