forked from quic-go/quic-go
handle gQUIC and IETF QUIC packets separately in the server
This commit is contained in:
51
server.go
51
server.go
@@ -247,7 +247,7 @@ func (s *server) serve() {
|
||||
return
|
||||
}
|
||||
data = data[:n]
|
||||
if err := s.handlePacket(s.conn, remoteAddr, data); err != nil {
|
||||
if err := s.handlePacket(remoteAddr, data); err != nil {
|
||||
s.logger.Errorf("error handling packet: %s", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func (s *server) Addr() net.Addr {
|
||||
return s.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet []byte) error {
|
||||
func (s *server) handlePacket(remoteAddr net.Addr, packet []byte) error {
|
||||
rcvTime := time.Now()
|
||||
|
||||
r := bytes.NewReader(packet)
|
||||
@@ -308,6 +308,13 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
|
||||
hdr.Raw = packet[:len(packet)-r.Len()]
|
||||
packetData := packet[len(packet)-r.Len():]
|
||||
|
||||
if hdr.IsPublicHeader {
|
||||
return s.handleGQUICPacket(hdr, packetData, remoteAddr, rcvTime)
|
||||
}
|
||||
return s.handleIETFQUICPacket(hdr, packetData, remoteAddr, rcvTime)
|
||||
}
|
||||
|
||||
func (s *server) handleIETFQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error {
|
||||
if hdr.IsLongHeader {
|
||||
if protocol.ByteCount(len(packetData)) < hdr.PayloadLen {
|
||||
return fmt.Errorf("packet payload (%d bytes) is smaller than the expected payload length (%d bytes)", len(packetData), hdr.PayloadLen)
|
||||
@@ -327,6 +334,29 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
|
||||
session, sessionKnown := s.sessions[string(hdr.DestConnectionID)]
|
||||
s.sessionsMutex.RUnlock()
|
||||
|
||||
if sessionKnown && session == nil {
|
||||
// Late packet for closed session
|
||||
return nil
|
||||
}
|
||||
if !sessionKnown {
|
||||
s.logger.Debugf("Received %s packet for unknown connection %s.", hdr.Type, hdr.DestConnectionID)
|
||||
return nil
|
||||
}
|
||||
|
||||
session.handlePacket(&receivedPacket{
|
||||
remoteAddr: remoteAddr,
|
||||
header: hdr,
|
||||
data: packetData,
|
||||
rcvTime: rcvTime,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) handleGQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error {
|
||||
s.sessionsMutex.RLock()
|
||||
session, sessionKnown := s.sessions[string(hdr.DestConnectionID)]
|
||||
s.sessionsMutex.RUnlock()
|
||||
|
||||
if sessionKnown && session == nil {
|
||||
// Late packet for closed session
|
||||
return nil
|
||||
@@ -340,9 +370,8 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
|
||||
|
||||
// If we don't have a session for this connection, and this packet cannot open a new connection, send a Public Reset
|
||||
// This should only happen after a server restart, when we still receive packets for connections that we lost the state for.
|
||||
// TODO(#943): implement sending of IETF draft style stateless resets
|
||||
if !sessionKnown && (!hdr.VersionFlag && hdr.Type != protocol.PacketTypeInitial) {
|
||||
_, err = pconn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), remoteAddr)
|
||||
if !sessionKnown && !hdr.VersionFlag {
|
||||
_, err := s.conn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), remoteAddr)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -357,29 +386,30 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
|
||||
// since the client send a Public Header (only gQUIC has a Version Flag), we need to send a gQUIC Version Negotiation Packet
|
||||
if hdr.VersionFlag && !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) {
|
||||
// drop packets that are too small to be valid first packets
|
||||
if len(packet) < protocol.MinClientHelloSize+len(hdr.Raw) {
|
||||
if len(packetData) < protocol.MinClientHelloSize {
|
||||
return errors.New("dropping small packet with unknown version")
|
||||
}
|
||||
s.logger.Infof("Client offered version %s, sending Version Negotiation Packet", hdr.Version)
|
||||
_, err := pconn.WriteTo(wire.ComposeGQUICVersionNegotiation(hdr.SrcConnectionID, s.config.Versions), remoteAddr)
|
||||
_, err := s.conn.WriteTo(wire.ComposeGQUICVersionNegotiation(hdr.SrcConnectionID, s.config.Versions), remoteAddr)
|
||||
return err
|
||||
}
|
||||
|
||||
if !sessionKnown {
|
||||
// This is (potentially) a Client Hello.
|
||||
// Make sure it has the minimum required size before spending any more ressources on it.
|
||||
if !sessionKnown && len(packet) < protocol.MinClientHelloSize+len(hdr.Raw) {
|
||||
if len(packetData) < protocol.MinClientHelloSize {
|
||||
return errors.New("dropping small packet for unknown connection")
|
||||
}
|
||||
|
||||
if !sessionKnown {
|
||||
version := hdr.Version
|
||||
if !protocol.IsSupportedVersion(s.config.Versions, version) {
|
||||
return errors.New("Server BUG: negotiated version not supported")
|
||||
}
|
||||
|
||||
s.logger.Infof("Serving new connection: %s, version %s from %v", hdr.DestConnectionID, version, remoteAddr)
|
||||
var err error
|
||||
session, err = s.newSession(
|
||||
&conn{pconn: pconn, currentAddr: remoteAddr},
|
||||
&conn{pconn: s.conn, currentAddr: remoteAddr},
|
||||
version,
|
||||
hdr.DestConnectionID,
|
||||
s.scfg,
|
||||
@@ -396,6 +426,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
|
||||
|
||||
s.runHandshakeAndSession(session, hdr.DestConnectionID)
|
||||
}
|
||||
|
||||
session.handlePacket(&receivedPacket{
|
||||
remoteAddr: remoteAddr,
|
||||
header: hdr,
|
||||
|
||||
@@ -171,7 +171,7 @@ var _ = Describe("Server", func() {
|
||||
})
|
||||
|
||||
It("creates new sessions", func() {
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
sess := serv.sessions[string(connID)].(*mockSession)
|
||||
@@ -232,7 +232,7 @@ var _ = Describe("Server", func() {
|
||||
acceptedSess, err = serv.Accept()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}()
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
sess := serv.sessions[string(connID)].(*mockSession)
|
||||
@@ -249,7 +249,7 @@ var _ = Describe("Server", func() {
|
||||
serv.Accept()
|
||||
accepted = true
|
||||
}()
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
sess := serv.sessions[string(connID)].(*mockSession)
|
||||
@@ -259,9 +259,9 @@ var _ = Describe("Server", func() {
|
||||
})
|
||||
|
||||
It("assigns packets to existing sessions", func() {
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = serv.handlePacket(nil, nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01})
|
||||
err = serv.handlePacket(nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
Expect(serv.sessions[string(connID)].(*mockSession).connectionID).To(Equal(connID))
|
||||
@@ -272,7 +272,7 @@ var _ = Describe("Server", func() {
|
||||
serv.deleteClosedSessionsAfter = time.Second // make sure that the nil value for the closed session doesn't get deleted in this test
|
||||
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, connID, protocol.VersionWhatever)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = serv.handlePacket(nil, nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...))
|
||||
err = serv.handlePacket(nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
Expect(serv.sessions[string(connID)]).ToNot(BeNil())
|
||||
@@ -287,7 +287,7 @@ var _ = Describe("Server", func() {
|
||||
serv.deleteClosedSessionsAfter = 25 * time.Millisecond
|
||||
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, connID, protocol.VersionWhatever)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = serv.handlePacket(nil, nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...))
|
||||
err = serv.handlePacket(nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
Expect(serv.sessions).To(HaveKey(string(connID)))
|
||||
@@ -313,7 +313,7 @@ var _ = Describe("Server", func() {
|
||||
|
||||
It("ignores packets for closed sessions", func() {
|
||||
serv.sessions[string(connID)] = nil
|
||||
err := serv.handlePacket(nil, nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01})
|
||||
err := serv.handlePacket(nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
Expect(serv.sessions[string(connID)]).To(BeNil())
|
||||
@@ -364,7 +364,7 @@ var _ = Describe("Server", func() {
|
||||
})
|
||||
|
||||
It("ignores delayed packets with mismatching versions", func() {
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1))
|
||||
b := &bytes.Buffer{}
|
||||
@@ -372,7 +372,7 @@ var _ = Describe("Server", func() {
|
||||
data := []byte{0x09, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}
|
||||
utils.BigEndian.WriteUint32(b, uint32(protocol.SupportedVersions[0]+1))
|
||||
data = append(append(data, b.Bytes()...), 0x01)
|
||||
err = serv.handlePacket(nil, nil, data)
|
||||
err = serv.handlePacket(nil, data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// if we didn't ignore the packet, the server would try to send a version negotiation packet, which would make the test panic because it doesn't have a udpConn
|
||||
Expect(conn.dataWritten.Bytes()).To(BeEmpty())
|
||||
@@ -381,7 +381,7 @@ var _ = Describe("Server", func() {
|
||||
})
|
||||
|
||||
It("errors on invalid public header", func() {
|
||||
err := serv.handlePacket(nil, nil, nil)
|
||||
err := serv.handlePacket(nil, nil)
|
||||
Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidPacketHeader))
|
||||
})
|
||||
|
||||
@@ -396,12 +396,12 @@ var _ = Describe("Server", func() {
|
||||
Version: versionIETFFrames,
|
||||
}
|
||||
Expect(hdr.Write(b, protocol.PerspectiveClient, versionIETFFrames)).To(Succeed())
|
||||
err := serv.handlePacket(nil, nil, append(b.Bytes(), make([]byte, 456)...))
|
||||
err := serv.handlePacket(nil, append(b.Bytes(), make([]byte, 456)...))
|
||||
Expect(err).To(MatchError("packet payload (456 bytes) is smaller than the expected payload length (1000 bytes)"))
|
||||
})
|
||||
|
||||
It("cuts packets at the payload length", func() {
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
b := &bytes.Buffer{}
|
||||
hdr := &wire.Header{
|
||||
@@ -413,18 +413,18 @@ var _ = Describe("Server", func() {
|
||||
Version: versionIETFFrames,
|
||||
}
|
||||
Expect(hdr.Write(b, protocol.PerspectiveClient, versionIETFFrames)).To(Succeed())
|
||||
err = serv.handlePacket(nil, nil, append(b.Bytes(), make([]byte, 456)...))
|
||||
err = serv.handlePacket(nil, append(b.Bytes(), make([]byte, 456)...))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(2))
|
||||
Expect(serv.sessions[string(connID)].(*mockSession).handledPackets[1].data).To(HaveLen(123))
|
||||
})
|
||||
|
||||
It("ignores Public Resets", func() {
|
||||
err := serv.handlePacket(nil, nil, firstPacket)
|
||||
err := serv.handlePacket(nil, firstPacket)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1))
|
||||
err = serv.handlePacket(nil, nil, wire.WritePublicReset(connID, 1, 1337))
|
||||
err = serv.handlePacket(nil, wire.WritePublicReset(connID, 1, 1337))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serv.sessions).To(HaveLen(1))
|
||||
Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1))
|
||||
@@ -442,7 +442,8 @@ var _ = Describe("Server", func() {
|
||||
}
|
||||
hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */)
|
||||
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)) // add a fake CHLO
|
||||
err := serv.handlePacket(conn, nil, b.Bytes())
|
||||
serv.conn = conn
|
||||
err := serv.handlePacket(nil, b.Bytes())
|
||||
Expect(conn.dataWritten.Bytes()).ToNot(BeEmpty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
@@ -458,7 +459,8 @@ var _ = Describe("Server", func() {
|
||||
}
|
||||
hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */)
|
||||
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize-1)) // this packet is 1 byte too small
|
||||
err := serv.handlePacket(conn, udpAddr, b.Bytes())
|
||||
serv.conn = conn
|
||||
err := serv.handlePacket(udpAddr, b.Bytes())
|
||||
Expect(err).To(MatchError("dropping small packet with unknown version"))
|
||||
Expect(conn.dataWritten.Len()).Should(BeZero())
|
||||
})
|
||||
@@ -628,6 +630,27 @@ var _ = Describe("Server", func() {
|
||||
Consistently(func() int { return conn.dataWritten.Len() }).Should(BeZero())
|
||||
})
|
||||
|
||||
It("ignores non-Initial Long Header packets for unknown connections", func() {
|
||||
connID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}
|
||||
b := &bytes.Buffer{}
|
||||
hdr := wire.Header{
|
||||
Type: protocol.PacketTypeHandshake,
|
||||
IsLongHeader: true,
|
||||
DestConnectionID: connID,
|
||||
SrcConnectionID: connID,
|
||||
PacketNumber: 0x55,
|
||||
Version: protocol.VersionTLS,
|
||||
}
|
||||
err := hdr.Write(b, protocol.PerspectiveClient, protocol.VersionTLS)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
conn.dataToRead <- b.Bytes()
|
||||
conn.dataReadFrom = udpAddr
|
||||
ln, err := Listen(conn, testdata.GetTLSConfig(), config)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer ln.Close()
|
||||
Consistently(func() int { return conn.dataWritten.Len() }).Should(BeZero())
|
||||
})
|
||||
|
||||
It("sends a PublicReset for new connections that don't have the VersionFlag set", func() {
|
||||
conn.dataReadFrom = udpAddr
|
||||
conn.dataToRead <- []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01}
|
||||
|
||||
Reference in New Issue
Block a user