webrtc icon indicating copy to clipboard operation
webrtc copied to clipboard

DTLSListener gets stuck in accept when DTLS Handshake fails

Open feschber opened this issue 1 year ago • 2 comments

I'm not sure if this is intentional or not but the problem is in essence that DTLSConn::new() has no timeout within the accept() function. So whenever a handshake fails for various reasons, accept will not be able to return any new connection.

    async fn accept(&self) -> UtilResult<(Arc<dyn Conn + Send + Sync>, SocketAddr)> {
        let (conn, raddr) = self.parent.accept().await?;
        let dtls_conn = DTLSConn::new(conn, self.config.clone(), false, None)
            .await
            .map_err(util::Error::from_std)?;
        Ok((Arc::new(dtls_conn), raddr))
    }

This happens for example with my laptop, which has wifi and ethernet ports. Opening a DTLSListener on this device on 0.0.0.0:4242 accepts connections via WIFI and Ethernet (two separate ips), however the Ethernet port is preferred leading to response messages being sent only via the Ethernet port.

Connecting to the WIFI IP leads to self.parent.accept().await? returning successfully, however the DTLSConn::new() call blocks indefinitely since the Handshake fails. Therefore accept never returns, which leaves the DTLSListener in a broken state.

image

the attached image illustrates the problem: 192.168.178.189 is the wifi port on the laptop and 192.168.178.172 is the ethernet port. The Client Hello is sent to the WIFI port but the Helly Verify Request is received from the ethernet port. The last five lines show the (unsuccessful) attempt of connecting to the Ethernet IP.

Server log with log messages for the self.parent.accept() and DTLSCon::new()` calls:


listening 0.0.0.0:4242...
type 'exit' to shutdown gracefully
parent.accept() ...
DTLSConn::new() ...
dtls/src/handshaker.rs:223 [TRACE] 13:00:54.689740 - [handshake:server] Flight 0: Preparing
dtls/src/handshaker.rs:223 [TRACE] 13:00:54.689962 - [handshake:server] Flight 0: Sending
dtls/src/handshaker.rs:223 [TRACE] 13:00:54.690035 - [handshake:server] Flight 0: Waiting
dtls/src/conn/mod.rs:1034 [TRACE] 13:00:54.690300 - Recv [handshake:server] -> ClientHello (epoch: 0, seq: 0)
dtls/src/flight/flight0.rs:84 [DEBUG] 13:00:54.690673 - [handshake:server] use cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
dtls/src/handshaker.rs:364 [TRACE] 13:00:54.693901 - [handshake:server] Flight 0 -> Flight 2
dtls/src/handshaker.rs:223 [TRACE] 13:00:54.693935 - [handshake:server] Flight 2: Preparing
dtls/src/handshaker.rs:223 [TRACE] 13:00:54.693950 - [handshake:server] Flight 2: Sending
dtls/src/conn/mod.rs:568 [TRACE] 13:00:54.694004 - Send [handshake:server] -> HelloVerifyRequest (epoch: 0, seq: 0)
dtls/src/handshaker.rs:223 [TRACE] 13:00:54.694091 - [handshake:server] Flight 2: Waiting
dtls/src/flight/flight0.rs:84 [DEBUG] 13:00:55.690131 - [handshake:server] use cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
dtls/src/handshaker.rs:364 [TRACE] 13:00:55.690358 - [handshake:server] Flight 2 -> Flight 2
dtls/src/handshaker.rs:223 [TRACE] 13:00:55.690378 - [handshake:server] Flight 2: Preparing
dtls/src/handshaker.rs:223 [TRACE] 13:00:55.690394 - [handshake:server] Flight 2: Sending
dtls/src/conn/mod.rs:568 [TRACE] 13:00:55.690501 - Send [handshake:server] -> HelloVerifyRequest (epoch: 0, seq: 0)
dtls/src/handshaker.rs:223 [TRACE] 13:00:55.690669 - [handshake:server] Flight 2: Waiting
dtls/src/flight/flight0.rs:84 [DEBUG] 13:00:56.691253 - [handshake:server] use cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
dtls/src/handshaker.rs:364 [TRACE] 13:00:56.691384 - [handshake:server] Flight 2 -> Flight 2
dtls/src/handshaker.rs:223 [TRACE] 13:00:56.691423 - [handshake:server] Flight 2: Preparing
dtls/src/handshaker.rs:223 [TRACE] 13:00:56.691453 - [handshake:server] Flight 2: Sending
dtls/src/conn/mod.rs:568 [TRACE] 13:00:56.691561 - Send [handshake:server] -> HelloVerifyRequest (epoch: 0, seq: 0)
dtls/src/handshaker.rs:223 [TRACE] 13:00:56.691733 - [handshake:server] Flight 2: Waiting
dtls/src/flight/flight0.rs:84 [DEBUG] 13:00:57.692747 - [handshake:server] use cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
dtls/src/handshaker.rs:364 [TRACE] 13:00:57.692881 - [handshake:server] Flight 2 -> Flight 2
dtls/src/handshaker.rs:223 [TRACE] 13:00:57.692909 - [handshake:server] Flight 2: Preparing
dtls/src/handshaker.rs:223 [TRACE] 13:00:57.692931 - [handshake:server] Flight 2: Sending
dtls/src/conn/mod.rs:568 [TRACE] 13:00:57.693015 - Send [handshake:server] -> HelloVerifyRequest (epoch: 0, seq: 0)
dtls/src/handshaker.rs:223 [TRACE] 13:00:57.693131 - [handshake:server] Flight 2: Waiting
dtls/src/handshaker.rs:375 [TRACE] 13:00:58.694346 - [handshake:server] Flight 2 retransmit_timer
dtls/src/handshaker.rs:223 [TRACE] 13:00:58.694577 - [handshake:server] Flight 2: Waiting
dtls/src/handshaker.rs:375 [TRACE] 13:00:59.697032 - [handshake:server] Flight 2 retransmit_timer

^C

feschber avatar Sep 17 '24 11:09 feschber

Unfortunately we are facing the same problem. Sometimes connecting our NB-IoT devices via a CoAP Library fails due to packet loss. Afterwards no new handshakes are possible and we are forced to restart the server.

The mentioned library uses webrtc-rs for DTLS handshakes too

jofleck avatar Oct 09 '24 10:10 jofleck

The DTLSListener itself is not used anywhere in the project besides the DTLS example apparently.

@rainliu could you comment on this line? What was the plan here? The difference to the pion implementation seems to be that here the handshake is done in DTLSConn::new() whereas pion defers it until the first read / write request on the connection.

feschber avatar Oct 09 '24 15:10 feschber