Skip to content

Commit ffd97f5

Browse files
committed
Backoff handshake retransmit
1 parent 7ab1bc9 commit ffd97f5

2 files changed

Lines changed: 86 additions & 2 deletions

File tree

conn_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,89 @@ func TestPSKHintFail(t *testing.T) {
682682
assert.ErrorIs(t, <-clientErr, pskRejected, "TestPSK: Client should fail with pskRejected error")
683683
}
684684

685+
func TestPSKMismatchNoRetransmitLoop(t *testing.T) {
686+
lim := test.TimeOut(time.Second * 20)
687+
defer lim.Stop()
688+
689+
report := test.CheckRoutines(t)
690+
defer report()
691+
692+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
693+
defer cancel()
694+
695+
var serverWrites atomic.Int32
696+
var clientWrites atomic.Int32
697+
698+
ca, cb := dpipe.Pipe()
699+
defer func() {
700+
_ = ca.Close()
701+
}()
702+
defer func() {
703+
_ = cb.Close()
704+
}()
705+
706+
caCount := &connWithCallback{Conn: ca}
707+
caCount.onWrite = func([]byte) {
708+
clientWrites.Add(1)
709+
}
710+
cbCount := &connWithCallback{Conn: cb}
711+
cbCount.onWrite = func([]byte) {
712+
serverWrites.Add(1)
713+
}
714+
715+
clientErr := make(chan error, 1)
716+
serverErr := make(chan error, 1)
717+
718+
go func() {
719+
conf := &Config{
720+
PSK: func([]byte) ([]byte, error) {
721+
return []byte("client-psk"), nil
722+
},
723+
PSKIdentityHint: []byte("Client Identity"),
724+
CipherSuites: []CipherSuiteID{TLS_PSK_WITH_AES_128_CCM_8},
725+
}
726+
727+
c, err := testClient(ctx, dtlsnet.PacketConnFromConn(caCount), caCount.RemoteAddr(), conf, false)
728+
if c != nil {
729+
_ = c.Close() //nolint:contextcheck
730+
}
731+
clientErr <- err
732+
}()
733+
734+
go func() {
735+
conf := &Config{
736+
PSK: func([]byte) ([]byte, error) {
737+
return []byte("server-psk"), nil
738+
},
739+
CipherSuites: []CipherSuiteID{TLS_PSK_WITH_AES_128_CCM_8},
740+
}
741+
742+
s, err := testServer(ctx, dtlsnet.PacketConnFromConn(cbCount), cbCount.RemoteAddr(), conf, false)
743+
if s != nil {
744+
_ = s.Close() //nolint:contextcheck
745+
}
746+
serverErr <- err
747+
}()
748+
749+
serverErrRes := <-serverErr
750+
clientErrRes := <-clientErr
751+
752+
var serverHandshakeErr *HandshakeError
753+
var clientHandshakeErr *HandshakeError
754+
assert.ErrorAs(t, serverErrRes, &serverHandshakeErr)
755+
assert.ErrorAs(t, clientErrRes, &clientHandshakeErr)
756+
757+
serverCount := serverWrites.Load()
758+
clientCount := clientWrites.Load()
759+
760+
time.Sleep(2 * time.Second)
761+
762+
assert.Equal(t, serverCount, serverWrites.Load(), "Server should not retransmit after handshake failure")
763+
assert.Equal(t, clientCount, clientWrites.Load(), "Client should not retransmit after handshake failure")
764+
assert.LessOrEqual(t, serverCount, int32(20), "Server retransmit count too high for backoff")
765+
assert.LessOrEqual(t, clientCount, int32(20), "Client retransmit count too high for backoff")
766+
}
767+
685768
// Assert that ServerKeyExchange is only sent if Identity is set on server side.
686769
func TestPSKServerKeyExchange(t *testing.T) {
687770
// Limit runtime in case of deadlocks

handshaker.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,9 @@ func (s *handshakeFSM) wait(ctx context.Context, conn flightConn) (handshakeStat
290290
case state := <-conn.recvHandshake():
291291
if state.isRetransmit {
292292
close(state.done)
293-
294-
return handshakeSending, nil
293+
// ignore incoming retransmit hints, only rely on the timer-driven path below
294+
// https://github.com/pion/dtls/issues/758
295+
continue
295296
}
296297

297298
nextFlight, alert, err := parse(ctx, conn, s.state, s.cache, s.cfg)

0 commit comments

Comments
 (0)