Merge pull request #1350 from lucas-clemente/split-packet-handling

split packet handling for gQUIC and IETF QUIC packets
This commit is contained in:
Marten Seemann
2018-05-09 13:22:54 +09:00
committed by GitHub
6 changed files with 149 additions and 97 deletions

View File

@@ -245,7 +245,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())
}
}
@@ -295,7 +295,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)
@@ -306,6 +306,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)
@@ -325,6 +332,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
@@ -332,25 +362,14 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
// ignore all Public Reset packets
if hdr.ResetFlag {
if sessionKnown {
var pr *wire.PublicReset
pr, err = wire.ParsePublicReset(r)
if err != nil {
s.logger.Infof("Received a Public Reset for connection %s. An error occurred parsing the packet.", hdr.DestConnectionID)
} else {
s.logger.Infof("Received a Public Reset for connection %s, rejected packet number: 0x%x.", hdr.DestConnectionID, pr.RejectedPacketNumber)
}
} else {
s.logger.Infof("Received Public Reset for unknown connection %s.", hdr.DestConnectionID)
}
s.logger.Infof("Received unexpected Public Reset for connection %s.", hdr.DestConnectionID)
return nil
}
// 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
}
@@ -365,29 +384,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
}
// 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) {
return errors.New("dropping small packet for unknown connection")
}
if !sessionKnown {
// This is (potentially) a Client Hello.
// Make sure it has the minimum required size before spending any more ressources on it.
if len(packetData) < protocol.MinClientHelloSize {
return errors.New("dropping small packet for unknown connection")
}
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,
@@ -404,6 +424,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
s.runHandshakeAndSession(session, hdr.DestConnectionID)
}
session.handlePacket(&receivedPacket{
remoteAddr: remoteAddr,
header: hdr,