forked from quic-go/quic-go
* use require in benchmark tests * translate the QLOGDIR test * translate handshake tests * translate the handshake RTT tests * translate the early data test * translate the MTU tests * translate the key update test * translate the stateless reset tests * translate the packetization test * translate the close test * translate the resumption test * translate the tracer test * translate the connection ID length test * translate the RTT tests * translate the multiplexing tests * translate the drop tests * translate the handshake drop tests * translate the 0-RTT tests * translate the hotswap test * translate the stream test * translate the unidirectional stream test * translate the timeout tests * translate the MITM test * rewrite the datagram tests * translate the cancellation tests * translate the deadline tests * translate the test helpers
125 lines
3.2 KiB
Go
125 lines
3.2 KiB
Go
package self_test
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"net"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/quic-go/quic-go"
|
|
quicproxy "github.com/quic-go/quic-go/integrationtests/tools/proxy"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStatelessResets(t *testing.T) {
|
|
t.Run("0 byte connection IDs", func(t *testing.T) {
|
|
testStatelessReset(t, 0)
|
|
})
|
|
t.Run("10 byte connection IDs", func(t *testing.T) {
|
|
testStatelessReset(t, 10)
|
|
})
|
|
}
|
|
|
|
func testStatelessReset(t *testing.T, connIDLen int) {
|
|
var statelessResetKey quic.StatelessResetKey
|
|
rand.Read(statelessResetKey[:])
|
|
|
|
c, err := net.ListenUDP("udp", nil)
|
|
require.NoError(t, err)
|
|
tr := &quic.Transport{
|
|
Conn: c,
|
|
StatelessResetKey: &statelessResetKey,
|
|
ConnectionIDLength: connIDLen,
|
|
}
|
|
defer tr.Close()
|
|
ln, err := tr.Listen(getTLSConfig(), getQuicConfig(nil))
|
|
require.NoError(t, err)
|
|
serverPort := ln.Addr().(*net.UDPAddr).Port
|
|
|
|
serverErr := make(chan error, 1)
|
|
go func() {
|
|
conn, err := ln.Accept(context.Background())
|
|
if err != nil {
|
|
serverErr <- err
|
|
return
|
|
}
|
|
str, err := conn.OpenStream()
|
|
if err != nil {
|
|
serverErr <- err
|
|
return
|
|
}
|
|
_, err = str.Write([]byte("foobar"))
|
|
if err != nil {
|
|
serverErr <- err
|
|
return
|
|
}
|
|
close(serverErr)
|
|
}()
|
|
|
|
var drop atomic.Bool
|
|
proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
|
|
RemoteAddr: fmt.Sprintf("localhost:%d", serverPort),
|
|
DropPacket: func(quicproxy.Direction, []byte) bool {
|
|
return drop.Load()
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
defer proxy.Close()
|
|
|
|
addr, err := net.ResolveUDPAddr("udp", "localhost:0")
|
|
require.NoError(t, err)
|
|
udpConn, err := net.ListenUDP("udp", addr)
|
|
require.NoError(t, err)
|
|
defer udpConn.Close()
|
|
cl := &quic.Transport{
|
|
Conn: udpConn,
|
|
ConnectionIDLength: connIDLen,
|
|
}
|
|
defer cl.Close()
|
|
conn, err := cl.Dial(
|
|
context.Background(),
|
|
&net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: proxy.LocalPort()},
|
|
getTLSClientConfig(),
|
|
getQuicConfig(&quic.Config{MaxIdleTimeout: 2 * time.Second}),
|
|
)
|
|
require.NoError(t, err)
|
|
str, err := conn.AcceptStream(context.Background())
|
|
require.NoError(t, err)
|
|
data := make([]byte, 6)
|
|
_, err = str.Read(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, []byte("foobar"), data)
|
|
|
|
// make sure that the CONNECTION_CLOSE is dropped
|
|
drop.Store(true)
|
|
require.NoError(t, ln.Close())
|
|
require.NoError(t, tr.Close())
|
|
require.NoError(t, <-serverErr)
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// We need to create a new Transport here, since the old one is still sending out
|
|
// CONNECTION_CLOSE packets for (recently) closed connections).
|
|
tr2 := &quic.Transport{
|
|
Conn: c,
|
|
ConnectionIDLength: connIDLen,
|
|
StatelessResetKey: &statelessResetKey,
|
|
}
|
|
defer tr2.Close()
|
|
ln2, err := tr2.Listen(getTLSConfig(), getQuicConfig(nil))
|
|
require.NoError(t, err)
|
|
drop.Store(false)
|
|
|
|
// Trigger something (not too small) to be sent, so that we receive the stateless reset.
|
|
// If the client already sent another packet, it might already have received a packet.
|
|
_, serr := str.Write([]byte("Lorem ipsum dolor sit amet."))
|
|
if serr == nil {
|
|
_, serr = str.Read([]byte{0})
|
|
}
|
|
require.Error(t, serr)
|
|
require.IsType(t, &quic.StatelessResetError{}, serr)
|
|
require.NoError(t, ln2.Close())
|
|
}
|