forked from quic-go/quic-go
qlog stateless resets
This commit is contained in:
@@ -98,7 +98,8 @@ var _ = Describe("Stateless Resets", func() {
|
|||||||
if serr == nil {
|
if serr == nil {
|
||||||
_, serr = str.Read([]byte{0})
|
_, 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())
|
Expect(ln2.Close()).To(Succeed())
|
||||||
Eventually(acceptStopped).Should(BeClosed())
|
Eventually(acceptStopped).Should(BeClosed())
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -15,6 +15,16 @@ import (
|
|||||||
"github.com/lucas-clemente/quic-go/internal/wire"
|
"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.
|
// The packetHandlerMap stores packetHandlers, identified by connection ID.
|
||||||
// It is used:
|
// It is used:
|
||||||
// * by the server to store sessions
|
// * by the server to store sessions
|
||||||
@@ -285,7 +295,7 @@ func (h *packetHandlerMap) maybeHandleStatelessReset(data []byte) bool {
|
|||||||
copy(token[:], data[len(data)-16:])
|
copy(token[:], data[len(data)-16:])
|
||||||
if sess, ok := h.resetTokens[token]; ok {
|
if sess, ok := h.resetTokens[token]; ok {
|
||||||
h.logger.Debugf("Received a stateless reset with token %#x. Closing session.", token)
|
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 true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -233,7 +233,11 @@ var _ = Describe("Packet Handler Map", func() {
|
|||||||
packet := append([]byte{0x40} /* short header packet */, make([]byte, 50)...)
|
packet := append([]byte{0x40} /* short header packet */, make([]byte, 50)...)
|
||||||
packet = append(packet, token[:]...)
|
packet = append(packet, token[:]...)
|
||||||
destroyed := make(chan struct{})
|
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)
|
close(destroyed)
|
||||||
})
|
})
|
||||||
conn.dataToRead <- packet
|
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([]byte{0x40} /* short header packet */, make([]byte, 50)...)
|
||||||
packet = append(packet, token[:]...)
|
packet = append(packet, token[:]...)
|
||||||
destroyed := make(chan struct{})
|
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)
|
close(destroyed)
|
||||||
})
|
})
|
||||||
conn.dataToRead <- packet
|
conn.dataToRead <- packet
|
||||||
|
|||||||
@@ -138,6 +138,19 @@ func (e eventRetryReceived) MarshalJSONObject(enc *gojay.Encoder) {
|
|||||||
enc.ObjectKey("header", e.Header)
|
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 {
|
type eventPacketBuffered struct {
|
||||||
PacketType PacketType
|
PacketType PacketType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type Tracer interface {
|
|||||||
SentPacket(hdr *wire.ExtendedHeader, packetSize protocol.ByteCount, ack *wire.AckFrame, frames []wire.Frame)
|
SentPacket(hdr *wire.ExtendedHeader, packetSize protocol.ByteCount, ack *wire.AckFrame, frames []wire.Frame)
|
||||||
ReceivedRetry(*wire.Header)
|
ReceivedRetry(*wire.Header)
|
||||||
ReceivedPacket(hdr *wire.ExtendedHeader, packetSize protocol.ByteCount, frames []wire.Frame)
|
ReceivedPacket(hdr *wire.ExtendedHeader, packetSize protocol.ByteCount, frames []wire.Frame)
|
||||||
|
ReceivedStatelessReset(token *[16]byte)
|
||||||
BufferedPacket(PacketType)
|
BufferedPacket(PacketType)
|
||||||
DroppedPacket(PacketType, protocol.ByteCount, PacketDropReason)
|
DroppedPacket(PacketType, protocol.ByteCount, PacketDropReason)
|
||||||
UpdatedMetrics(rttStats *congestion.RTTStats, cwnd protocol.ByteCount, bytesInFLight protocol.ByteCount, packetsInFlight int)
|
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) {
|
func (t *tracer) BufferedPacket(packetType PacketType) {
|
||||||
t.recordEvent(&eventPacketBuffered{PacketType: packetType})
|
t.recordEvent(&eventPacketBuffered{PacketType: packetType})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,6 +309,17 @@ var _ = Describe("Tracer", func() {
|
|||||||
Expect(ev).ToNot(HaveKey("frames"))
|
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() {
|
It("records buffered packets", func() {
|
||||||
tracer.BufferedPacket(PacketTypeHandshake)
|
tracer.BufferedPacket(PacketTypeHandshake)
|
||||||
entry := exportAndParseSingle()
|
entry := exportAndParseSingle()
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ const (
|
|||||||
PacketTypeVersionNegotiation
|
PacketTypeVersionNegotiation
|
||||||
// PacketType1RTT is a 1-RTT packet
|
// PacketType1RTT is a 1-RTT packet
|
||||||
PacketType1RTT
|
PacketType1RTT
|
||||||
|
// PacketTypeStatelessReset is a stateless reset
|
||||||
|
PacketTypeStatelessReset
|
||||||
// PacketTypeNotDetermined is the packet type when it could not be determined
|
// PacketTypeNotDetermined is the packet type when it could not be determined
|
||||||
PacketTypeNotDetermined
|
PacketTypeNotDetermined
|
||||||
)
|
)
|
||||||
@@ -106,6 +108,8 @@ func (t PacketType) String() string {
|
|||||||
return "0RTT"
|
return "0RTT"
|
||||||
case PacketTypeVersionNegotiation:
|
case PacketTypeVersionNegotiation:
|
||||||
return "version_negotiation"
|
return "version_negotiation"
|
||||||
|
case PacketTypeStatelessReset:
|
||||||
|
return "stateless_reset"
|
||||||
case PacketType1RTT:
|
case PacketType1RTT:
|
||||||
return "1RTT"
|
return "1RTT"
|
||||||
case PacketTypeNotDetermined:
|
case PacketTypeNotDetermined:
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ var _ = Describe("Types", func() {
|
|||||||
Expect(PacketTypeHandshake.String()).To(Equal("handshake"))
|
Expect(PacketTypeHandshake.String()).To(Equal("handshake"))
|
||||||
Expect(PacketType0RTT.String()).To(Equal("0RTT"))
|
Expect(PacketType0RTT.String()).To(Equal("0RTT"))
|
||||||
Expect(PacketType1RTT.String()).To(Equal("1RTT"))
|
Expect(PacketType1RTT.String()).To(Equal("1RTT"))
|
||||||
|
Expect(PacketTypeStatelessReset.String()).To(Equal("stateless_reset"))
|
||||||
Expect(PacketTypeRetry.String()).To(Equal("retry"))
|
Expect(PacketTypeRetry.String()).To(Equal("retry"))
|
||||||
Expect(PacketTypeVersionNegotiation.String()).To(Equal("version_negotiation"))
|
Expect(PacketTypeVersionNegotiation.String()).To(Equal("version_negotiation"))
|
||||||
Expect(PacketTypeNotDetermined.String()).To(BeEmpty())
|
Expect(PacketTypeNotDetermined.String()).To(BeEmpty())
|
||||||
|
|||||||
@@ -1149,6 +1149,9 @@ func (s *session) handleCloseError(closeErr closeError) {
|
|||||||
if closeErr.err == nil {
|
if closeErr.err == nil {
|
||||||
closeErr.err = qerr.NewApplicationError(0, "")
|
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 quicErr *qerr.QuicError
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|||||||
Reference in New Issue
Block a user