mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
qlog stateless resets
This commit is contained in:
parent
cf45659c49
commit
a82d6bb910
9 changed files with 63 additions and 5 deletions
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue