From 06ea47b338c93656e95925f5890f08d6562af2e1 Mon Sep 17 00:00:00 2001 From: Pattayaguy Date: Sat, 26 Sep 2026 16:09:45 +0000 Subject: [PATCH] Add websocket listener to rendezvous-node (previously dial-only) The transport stack in swarm.rs builds ws_transport.or_transport(tcp_with_dns) (and .or_transport(tor_transport) for the onion variant), so the binary is fully capable of speaking websocket -- but main.rs only ever calls swarm.listen_on() once, with a bare /ip4/0.0.0.0/tcp/{port} address. libp2p-websocket's own listen_on (transports/websocket/src/framed.rs) requires the address to carry a /ws or /wss suffix or it returns MultiaddrNotSupported, so OrTransport always falls through to plain TCP. The ws half of the transport stack was wired up for dialing out (needed to redial the wss entries already in default_rendezvous_points()) but never had a listener of its own to accept anything inbound. Found this running our own instance behind an nginx + Cloudflare reverse proxy (TLS terminated at the proxy, forwarded to the binary as plain HTTP/ws): every wss handshake through it got reset. Fix: add a --ws-port flag (default 8889 -- a separate port from --port, since two listeners can't bind the same TCP port) and a second swarm.listen_on() call for /ip4/0.0.0.0/tcp/{ws_port}/ws. Kept it to plain /ws, not /wss -- this binary has never terminated its own TLS, and the natural place for that stays whatever reverse proxy sits in front of it, same as before. Verified on our own deployment: rebuilt, pointed nginx's proxy_pass at the new port, and ran an isolated DISCOVER query over wss straight at our public hostname -- it now returns our registered peer, which it never did before. (Testing/drafting assisted by Claude Code; the bug, fix and verification above are our own.) --- libp2p-rendezvous-node/src/main.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libp2p-rendezvous-node/src/main.rs b/libp2p-rendezvous-node/src/main.rs index ca3c3538cc..82347560c2 100644 --- a/libp2p-rendezvous-node/src/main.rs +++ b/libp2p-rendezvous-node/src/main.rs @@ -29,6 +29,10 @@ struct Cli { #[structopt(long, default_value = "8888")] port: u16, + /// Port used for listening on websocket (put a TLS-terminating reverse proxy in front for wss) + #[structopt(long, default_value = "8889")] + ws_port: u16, + /// Enable listening on Tor onion service #[structopt(long)] no_onion: bool, @@ -75,6 +79,17 @@ async fn main() -> Result<()> { ) .context("Failed to initialize listener")?; + // The transport stack tries the websocket transport before plain TCP, but only for + // addresses carrying a /ws suffix — without a dedicated listener here, inbound wss + // (e.g. through a TLS-terminating reverse proxy) never gets accepted. + swarm + .listen_on( + format!("/ip4/0.0.0.0/tcp/{}/ws", cli.ws_port) + .parse() + .expect("static string is valid MultiAddress"), + ) + .context("Failed to initialize websocket listener")?; + loop { match swarm.select_next_some().await { SwarmEvent::Behaviour(behaviour::BehaviourEvent::Server(