qlog stateless resets

This commit is contained in:
Marten Seemann 2020-03-26 16:29:54 +07:00
parent cf45659c49
commit a82d6bb910
9 changed files with 63 additions and 5 deletions

View file

@ -98,7 +98,8 @@ var _ = Describe("Stateless Resets", func() {
if serr == nil {
_, serr = str.Read([]byte{0})
}
Expect(serr).To(MatchError("INTERNAL_ERROR: received a stateless reset"))
Expect(serr).To(HaveOccurred())
Expect(serr.Error()).To(ContainSubstring("INTERNAL_ERROR: received a stateless reset"))
Expect(ln2.Close()).To(Succeed())
Eventually(acceptStopped).Should(BeClosed())

View file

@ -4,7 +4,7 @@ import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
"hash"
"net"
"sync"
@ -15,6 +15,16 @@ import (
"github.com/lucas-clemente/quic-go/internal/wire"
)
type statelessResetErr struct {
token *[16]byte
}
func (e statelessResetErr) StatelessResetToken() *[16]byte { return e.token }
func (e statelessResetErr) Error() string {
return fmt.Sprintf("received a stateless reset with token %x", *e.token)
}
// The packetHandlerMap stores packetHandlers, identified by connection ID.
// It is used:
// * by the server to store sessions
@ -285,7 +295,7 @@ func (h *packetHandlerMap) maybeHandleStatelessReset(data []byte) bool {
copy(token[:], data[len(data)-16:])
if sess, ok := h.resetTokens[token]; ok {
h.logger.Debugf("Received a stateless reset with token %#x. Closing session.", token)
go sess.destroy(errors.New("received a stateless reset"))
go sess.destroy(&statelessResetErr{token: &token})
return true
}
return false

View file

@ -233,7 +233,11 @@ var _ = Describe("Packet Handler Map", func() {
packet := append([]byte{0x40} /* short header packet */, make([]byte, 50)...)
packet = append(packet, token[:]...)
destroyed := make(chan struct{})
packetHandler.EXPECT().destroy(errors.New("received a stateless reset")).Do(func(error) {
packetHandler.EXPECT().destroy(gomock.Any()).Do(func(err error) {
Expect(err).To(HaveOccurred())
Expect(err).To(BeAssignableToTypeOf(&statelessResetErr{}))
Expect(err.Error()).To(ContainSubstring("received a stateless reset"))
Expect(*err.(*statelessResetErr).StatelessResetToken()).To(Equal(token))
close(destroyed)
})
conn.dataToRead <- packet
@ -248,7 +252,11 @@ var _ = Describe("Packet Handler Map", func() {
packet := append([]byte{0x40} /* short header packet */, make([]byte, 50)...)
packet = append(packet, token[:]...)
destroyed := make(chan struct{})
packetHandler.EXPECT().destroy(errors.New("received a stateless reset")).Do(func(error) {
packetHandler.EXPECT().destroy(gomock.Any()).Do(func(err error) {
Expect(err).To(HaveOccurred())
Expect(err).To(BeAssignableToTypeOf(&statelessResetErr{}))
Expect(err.Error()).To(ContainSubstring("received a stateless reset"))
Expect(*err.(*statelessResetErr).StatelessResetToken()).To(Equal(token))
close(destroyed)
})
conn.dataToRead <- packet

View file

@ -138,6 +138,19 @@ func (e eventRetryReceived) MarshalJSONObject(enc *gojay.Encoder) {
enc.ObjectKey("header", e.Header)
}
type eventStatelessResetReceived struct {
Token *[16]byte
}
func (e eventStatelessResetReceived) Category() category { return categoryTransport }
func (e eventStatelessResetReceived) Name() string { return "packet_received" }
func (e eventStatelessResetReceived) IsNil() bool { return false }
func (e eventStatelessResetReceived) MarshalJSONObject(enc *gojay.Encoder) {
enc.StringKey("packet_type", PacketTypeStatelessReset.String())
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", *e.Token))
}
type eventPacketBuffered struct {
PacketType PacketType
}

View file

@ -25,6 +25,7 @@ type Tracer interface {
SentPacket(hdr *wire.ExtendedHeader, packetSize protocol.ByteCount, ack *wire.AckFrame, frames []wire.Frame)
ReceivedRetry(*wire.Header)
ReceivedPacket(hdr *wire.ExtendedHeader, packetSize protocol.ByteCount, frames []wire.Frame)
ReceivedStatelessReset(token *[16]byte)
BufferedPacket(PacketType)
DroppedPacket(PacketType, protocol.ByteCount, PacketDropReason)
UpdatedMetrics(rttStats *congestion.RTTStats, cwnd protocol.ByteCount, bytesInFLight protocol.ByteCount, packetsInFlight int)
@ -205,6 +206,12 @@ func (t *tracer) ReceivedRetry(hdr *wire.Header) {
})
}
func (t *tracer) ReceivedStatelessReset(token *[16]byte) {
t.recordEvent(&eventStatelessResetReceived{
Token: token,
})
}
func (t *tracer) BufferedPacket(packetType PacketType) {
t.recordEvent(&eventPacketBuffered{PacketType: packetType})
}

View file

@ -309,6 +309,17 @@ var _ = Describe("Tracer", func() {
Expect(ev).ToNot(HaveKey("frames"))
})
It("records a received Retry packet", func() {
tracer.ReceivedStatelessReset(&[16]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), 10*time.Millisecond))
Expect(entry.Category).To(Equal("transport"))
Expect(entry.Name).To(Equal("packet_received"))
ev := entry.Event
Expect(ev).To(HaveKeyWithValue("packet_type", "stateless_reset"))
Expect(ev).To(HaveKeyWithValue("stateless_reset_token", "00112233445566778899aabbccddeeff"))
})
It("records buffered packets", func() {
tracer.BufferedPacket(PacketTypeHandshake)
entry := exportAndParseSingle()

View file

@ -90,6 +90,8 @@ const (
PacketTypeVersionNegotiation
// PacketType1RTT is a 1-RTT packet
PacketType1RTT
// PacketTypeStatelessReset is a stateless reset
PacketTypeStatelessReset
// PacketTypeNotDetermined is the packet type when it could not be determined
PacketTypeNotDetermined
)
@ -106,6 +108,8 @@ func (t PacketType) String() string {
return "0RTT"
case PacketTypeVersionNegotiation:
return "version_negotiation"
case PacketTypeStatelessReset:
return "stateless_reset"
case PacketType1RTT:
return "1RTT"
case PacketTypeNotDetermined:

View file

@ -24,6 +24,7 @@ var _ = Describe("Types", func() {
Expect(PacketTypeHandshake.String()).To(Equal("handshake"))
Expect(PacketType0RTT.String()).To(Equal("0RTT"))
Expect(PacketType1RTT.String()).To(Equal("1RTT"))
Expect(PacketTypeStatelessReset.String()).To(Equal("stateless_reset"))
Expect(PacketTypeRetry.String()).To(Equal("retry"))
Expect(PacketTypeVersionNegotiation.String()).To(Equal("version_negotiation"))
Expect(PacketTypeNotDetermined.String()).To(BeEmpty())

View file

@ -1149,6 +1149,9 @@ func (s *session) handleCloseError(closeErr closeError) {
if closeErr.err == nil {
closeErr.err = qerr.NewApplicationError(0, "")
}
if statelessReset, ok := closeErr.err.(interface{ StatelessResetToken() *[16]byte }); ok && s.qlogger != nil {
s.qlogger.ReceivedStatelessReset(statelessReset.StatelessResetToken())
}
var quicErr *qerr.QuicError
var ok bool