Search code examples
socketsrustwebsockettungstenite

Detect the incoming protocol for TcpStream


My service collects and displays some statistics using socket communication. Some clients connect to it through web browsers using WebSocket protocol, while others use Windows services that use regular sockets.

I have created a single listening port this way:

let on = "0.0.0.0:8081";
let server = std::net::TcpListener::bind(on)?;

while let Ok((stream, _)) = server.accept() {
  let peer_adr = stream.peer_addr().unwrap();
  if peer_adr.to_string().starts_with("127.0.0") {
     // socket
  } else {
     // web socket
     let ws = tungstenite::accept(stream)?;
  }
}

I have tried an IP check to detect the type of client, which is not acceptable for production.

My questions are:

  1. Is there any better implementation?
  2. Is there any standard approach to detect each incoming stream's type? (something like stream.protocol.start_with("ws"))

Env

Rust version: `1.74 - stable`
Extra crate: `tungstenite = { version = "0.20" }`

Solution

  • There is no such thing as an "incoming" protocol. It's an application protocol and there are zillions of these. And while many begin with the client sending data (like in HTTP, SIP, ...) others instead expect the server to send the first application data (like in SMTP, FTP, IMAP, ...). This means to deal with arbitrary application protocols one cannot just listen for incoming data since none will come if the clients expects the peer to start sending first.

    Apart from that many protocols today use encryption at transit at the application level, typically using TLS. While some protocols will start without encryption and then later upgrade (like with STARTTLS in SMTP) many will instead directly start with the TLS handshake, which begins with the client sending a ClientHello. There are none or almost none indicators in the ClientHello which lets distinguish between protocol - there is the ALPN extension but this allows only very coarse detection of possible application protocols.

    In short: if you have only a very limited set of possible protocols then you might be able to write a custom detector based on this limited set. But only if these protocols are clearly distinguishable from the first data the client sends without the client expecting to send data to the server. So it really depends on your actual use case and there is no generic detection which covers all possible protocols.