forked from quic-go/quic-go
always allow sending of IETF QUIC Version Negotiation Packets
When receiving a packet with an IETF QUIC Header using an unsupported version, we should send a IETF QUIC Version Negotiation Packet, even if none of the supported versions is IETF QUIC.
This commit is contained in:
42
server.go
42
server.go
@@ -325,13 +325,19 @@ func (s *server) handlePacket(p *receivedPacket) {
|
|||||||
|
|
||||||
func (s *server) handlePacketImpl(p *receivedPacket) error {
|
func (s *server) handlePacketImpl(p *receivedPacket) error {
|
||||||
hdr := p.header
|
hdr := p.header
|
||||||
version := hdr.Version
|
|
||||||
|
|
||||||
|
if hdr.VersionFlag || hdr.IsLongHeader {
|
||||||
|
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||||
|
if !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) {
|
||||||
|
return s.sendVersionNegotiationPacket(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
if hdr.Type == protocol.PacketTypeInitial {
|
if hdr.Type == protocol.PacketTypeInitial {
|
||||||
go s.serverTLS.HandleInitial(p)
|
go s.serverTLS.HandleInitial(p)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(#943): send Stateless Reset, if this an IETF QUIC packet
|
||||||
if !hdr.VersionFlag {
|
if !hdr.VersionFlag {
|
||||||
_, err := s.conn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), p.remoteAddr)
|
_, err := s.conn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), p.remoteAddr)
|
||||||
return err
|
return err
|
||||||
@@ -343,23 +349,11 @@ func (s *server) handlePacketImpl(p *receivedPacket) error {
|
|||||||
return errors.New("dropping small packet for unknown connection")
|
return errors.New("dropping small packet for unknown connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
s.logger.Infof("Serving new connection: %s, version %s from %v", hdr.DestConnectionID, hdr.Version, p.remoteAddr)
|
||||||
// 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, version) {
|
|
||||||
s.logger.Infof("Client offered version %s, sending Version Negotiation Packet", version)
|
|
||||||
_, err := s.conn.WriteTo(wire.ComposeGQUICVersionNegotiation(hdr.DestConnectionID, s.config.Versions), p.remoteAddr)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
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, p.remoteAddr)
|
|
||||||
sess, err := s.newSession(
|
sess, err := s.newSession(
|
||||||
&conn{pconn: s.conn, currentAddr: p.remoteAddr},
|
&conn{pconn: s.conn, currentAddr: p.remoteAddr},
|
||||||
s.sessionRunner,
|
s.sessionRunner,
|
||||||
version,
|
hdr.Version,
|
||||||
hdr.DestConnectionID,
|
hdr.DestConnectionID,
|
||||||
s.scfg,
|
s.scfg,
|
||||||
s.tlsConf,
|
s.tlsConf,
|
||||||
@@ -374,3 +368,21 @@ func (s *server) handlePacketImpl(p *receivedPacket) error {
|
|||||||
sess.handlePacket(p)
|
sess.handlePacket(p)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *server) sendVersionNegotiationPacket(p *receivedPacket) error {
|
||||||
|
hdr := p.header
|
||||||
|
s.logger.Debugf("Client offered version %s, sending VersionNegotiationPacket", hdr.Version)
|
||||||
|
|
||||||
|
var data []byte
|
||||||
|
if hdr.Version.UsesIETFFrameFormat() {
|
||||||
|
var err error
|
||||||
|
data, err = wire.ComposeVersionNegotiation(hdr.SrcConnectionID, hdr.DestConnectionID, s.config.Versions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = wire.ComposeGQUICVersionNegotiation(hdr.DestConnectionID, s.config.Versions)
|
||||||
|
}
|
||||||
|
_, err := s.conn.WriteTo(data, p.remoteAddr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ var _ = Describe("Server", func() {
|
|||||||
DestConnectionID: connID,
|
DestConnectionID: connID,
|
||||||
PacketNumber: 1,
|
PacketNumber: 1,
|
||||||
PacketNumberLen: protocol.PacketNumberLen2,
|
PacketNumberLen: protocol.PacketNumberLen2,
|
||||||
|
Version: protocol.Version39 - 1,
|
||||||
}
|
}
|
||||||
Expect(hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */)).To(Succeed())
|
Expect(hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */)).To(Succeed())
|
||||||
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)) // add a fake CHLO
|
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)) // add a fake CHLO
|
||||||
@@ -411,7 +412,6 @@ var _ = Describe("Server", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("sends an IETF draft style Version Negotaion Packet, if the client sent a IETF draft style header", func() {
|
It("sends an IETF draft style Version Negotaion Packet, if the client sent a IETF draft style header", func() {
|
||||||
config.Versions = append(config.Versions, protocol.VersionTLS)
|
|
||||||
ln, err := Listen(conn, testdata.GetTLSConfig(), config)
|
ln, err := Listen(conn, testdata.GetTLSConfig(), config)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,11 @@ type tlsSession struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type serverTLS struct {
|
type serverTLS struct {
|
||||||
conn net.PacketConn
|
conn net.PacketConn
|
||||||
config *Config
|
config *Config
|
||||||
supportedVersions []protocol.VersionNumber
|
mintConf *mint.Config
|
||||||
mintConf *mint.Config
|
params *handshake.TransportParameters
|
||||||
params *handshake.TransportParameters
|
cookieGenerator *handshake.CookieGenerator
|
||||||
cookieGenerator *handshake.CookieGenerator
|
|
||||||
|
|
||||||
newSession func(connection, sessionRunner, protocol.ConnectionID, protocol.ConnectionID, protocol.ConnectionID, protocol.PacketNumber, *Config, *mint.Config, *handshake.TransportParameters, utils.Logger, protocol.VersionNumber) (quicSession, error)
|
newSession func(connection, sessionRunner, protocol.ConnectionID, protocol.ConnectionID, protocol.ConnectionID, protocol.PacketNumber, *Config, *mint.Config, *handshake.TransportParameters, utils.Logger, protocol.VersionNumber) (quicSession, error)
|
||||||
|
|
||||||
@@ -60,16 +59,15 @@ func newServerTLS(
|
|||||||
|
|
||||||
sessionChan := make(chan tlsSession)
|
sessionChan := make(chan tlsSession)
|
||||||
s := &serverTLS{
|
s := &serverTLS{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
config: config,
|
config: config,
|
||||||
supportedVersions: config.Versions,
|
mintConf: mconf,
|
||||||
mintConf: mconf,
|
sessionRunner: runner,
|
||||||
sessionRunner: runner,
|
sessionChan: sessionChan,
|
||||||
sessionChan: sessionChan,
|
cookieGenerator: cookieGenerator,
|
||||||
cookieGenerator: cookieGenerator,
|
params: params,
|
||||||
params: params,
|
newSession: newTLSServerSession,
|
||||||
newSession: newTLSServerSession,
|
logger: logger,
|
||||||
logger: logger,
|
|
||||||
}
|
}
|
||||||
return s, sessionChan, nil
|
return s, sessionChan, nil
|
||||||
}
|
}
|
||||||
@@ -99,16 +97,6 @@ func (s *serverTLS) handleInitialImpl(p *receivedPacket) (quicSession, protocol.
|
|||||||
if len(hdr.Raw)+len(p.data) < protocol.MinInitialPacketSize {
|
if len(hdr.Raw)+len(p.data) < protocol.MinInitialPacketSize {
|
||||||
return nil, nil, errors.New("dropping too small Initial packet")
|
return nil, nil, errors.New("dropping too small Initial packet")
|
||||||
}
|
}
|
||||||
// check version, if not matching send VNP
|
|
||||||
if !protocol.IsSupportedVersion(s.supportedVersions, hdr.Version) {
|
|
||||||
s.logger.Debugf("Client offered version %s, sending VersionNegotiationPacket", hdr.Version)
|
|
||||||
vnp, err := wire.ComposeVersionNegotiation(hdr.SrcConnectionID, hdr.DestConnectionID, s.supportedVersions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
_, err = s.conn.WriteTo(vnp, p.remoteAddr)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var cookie *handshake.Cookie
|
var cookie *handshake.Cookie
|
||||||
if len(hdr.Token) > 0 {
|
if len(hdr.Token) > 0 {
|
||||||
|
|||||||
@@ -41,22 +41,6 @@ var _ = Describe("Stateless TLS handling", func() {
|
|||||||
return hdr
|
return hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
It("sends a Version Negotiation Packet if it doesn't support the version", func() {
|
|
||||||
server.HandleInitial(&receivedPacket{
|
|
||||||
header: &wire.Header{
|
|
||||||
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
|
|
||||||
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
|
|
||||||
PacketNumberLen: protocol.PacketNumberLen1,
|
|
||||||
Version: 0x1337,
|
|
||||||
},
|
|
||||||
data: bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize),
|
|
||||||
})
|
|
||||||
Expect(conn.dataWritten.Len()).ToNot(BeZero())
|
|
||||||
hdr := parseHeader(conn.dataWritten.Bytes())
|
|
||||||
Expect(hdr.IsVersionNegotiation).To(BeTrue())
|
|
||||||
Expect(sessionChan).ToNot(Receive())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("drops too small packets", func() {
|
It("drops too small packets", func() {
|
||||||
server.HandleInitial(&receivedPacket{
|
server.HandleInitial(&receivedPacket{
|
||||||
header: &wire.Header{},
|
header: &wire.Header{},
|
||||||
|
|||||||
Reference in New Issue
Block a user