mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-05 05:07:36 +03:00
move the DisableVersionNegotiationPackets flag to the Transport (#4047)
* move the DisableVersionNegotiationPackets flag to the Transport * add an integration test for DisableVersionNegotiationPackets
This commit is contained in:
parent
2797f85fc0
commit
d7334c16e7
7 changed files with 112 additions and 68 deletions
|
@ -128,7 +128,6 @@ func populateConfig(config *Config) *Config {
|
||||||
TokenStore: config.TokenStore,
|
TokenStore: config.TokenStore,
|
||||||
EnableDatagrams: config.EnableDatagrams,
|
EnableDatagrams: config.EnableDatagrams,
|
||||||
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
||||||
DisableVersionNegotiationPackets: config.DisableVersionNegotiationPackets,
|
|
||||||
Allow0RTT: config.Allow0RTT,
|
Allow0RTT: config.Allow0RTT,
|
||||||
Tracer: config.Tracer,
|
Tracer: config.Tracer,
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,6 @@ var _ = Describe("Config", func() {
|
||||||
Expect(c.MaxConnectionReceiveWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveConnectionFlowControlWindow))
|
Expect(c.MaxConnectionReceiveWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveConnectionFlowControlWindow))
|
||||||
Expect(c.MaxIncomingStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingStreams))
|
Expect(c.MaxIncomingStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingStreams))
|
||||||
Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingUniStreams))
|
Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingUniStreams))
|
||||||
Expect(c.DisableVersionNegotiationPackets).To(BeFalse())
|
|
||||||
Expect(c.DisablePathMTUDiscovery).To(BeFalse())
|
Expect(c.DisablePathMTUDiscovery).To(BeFalse())
|
||||||
Expect(c.GetConfigForClient).To(BeNil())
|
Expect(c.GetConfigForClient).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,8 +3,10 @@ package versionnegotiation
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
"github.com/quic-go/quic-go/integrationtests/tools/israce"
|
"github.com/quic-go/quic-go/integrationtests/tools/israce"
|
||||||
|
@ -113,7 +115,7 @@ var _ = Describe("Handshake tests", func() {
|
||||||
|
|
||||||
It("when the client supports more versions than the server supports", func() {
|
It("when the client supports more versions than the server supports", func() {
|
||||||
expectedVersion := protocol.SupportedVersions[0]
|
expectedVersion := protocol.SupportedVersions[0]
|
||||||
// the server doesn't support the highest supported version, which is the first one the client will try
|
// The server doesn't support the highest supported version, which is the first one the client will try,
|
||||||
// but it supports a bunch of versions that the client doesn't speak
|
// but it supports a bunch of versions that the client doesn't speak
|
||||||
serverTracer := &versionNegotiationTracer{}
|
serverTracer := &versionNegotiationTracer{}
|
||||||
serverConfig := &quic.Config{}
|
serverConfig := &quic.Config{}
|
||||||
|
@ -147,5 +149,45 @@ var _ = Describe("Handshake tests", func() {
|
||||||
Expect(serverTracer.serverVersions).To(Equal(serverConfig.Versions))
|
Expect(serverTracer.serverVersions).To(Equal(serverConfig.Versions))
|
||||||
Expect(serverTracer.clientVersions).To(BeEmpty())
|
Expect(serverTracer.clientVersions).To(BeEmpty())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("fails if the server disables version negotiation", func() {
|
||||||
|
// The server doesn't support the highest supported version, which is the first one the client will try,
|
||||||
|
// but it supports a bunch of versions that the client doesn't speak
|
||||||
|
serverTracer := &versionNegotiationTracer{}
|
||||||
|
serverConfig := &quic.Config{}
|
||||||
|
serverConfig.Versions = supportedVersions
|
||||||
|
serverConfig.Tracer = func(context.Context, logging.Perspective, quic.ConnectionID) logging.ConnectionTracer {
|
||||||
|
return serverTracer
|
||||||
|
}
|
||||||
|
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
tr := &quic.Transport{
|
||||||
|
Conn: conn,
|
||||||
|
DisableVersionNegotiationPackets: true,
|
||||||
|
}
|
||||||
|
ln, err := tr.Listen(getTLSConfig(), serverConfig)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
clientVersions := []protocol.VersionNumber{7, 8, 9, protocol.SupportedVersions[0], 10}
|
||||||
|
clientTracer := &versionNegotiationTracer{}
|
||||||
|
_, err = quic.DialAddr(
|
||||||
|
context.Background(),
|
||||||
|
fmt.Sprintf("localhost:%d", conn.LocalAddr().(*net.UDPAddr).Port),
|
||||||
|
getTLSClientConfig(),
|
||||||
|
maybeAddQLOGTracer(&quic.Config{
|
||||||
|
Versions: clientVersions,
|
||||||
|
Tracer: func(context.Context, logging.Perspective, quic.ConnectionID) logging.ConnectionTracer {
|
||||||
|
return clientTracer
|
||||||
|
},
|
||||||
|
HandshakeIdleTimeout: 100 * time.Millisecond,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
var nerr net.Error
|
||||||
|
Expect(errors.As(err, &nerr)).To(BeTrue())
|
||||||
|
Expect(nerr.Timeout()).To(BeTrue())
|
||||||
|
Expect(clientTracer.receivedVersionNegotiation).To(BeFalse())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -322,10 +322,6 @@ type Config struct {
|
||||||
// Path MTU discovery is only available on systems that allow setting of the Don't Fragment (DF) bit.
|
// Path MTU discovery is only available on systems that allow setting of the Don't Fragment (DF) bit.
|
||||||
// If unavailable or disabled, packets will be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
|
// If unavailable or disabled, packets will be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
|
||||||
DisablePathMTUDiscovery bool
|
DisablePathMTUDiscovery bool
|
||||||
// DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
|
|
||||||
// This can be useful if version information is exchanged out-of-band.
|
|
||||||
// It has no effect for a client.
|
|
||||||
DisableVersionNegotiationPackets bool
|
|
||||||
// Allow0RTT allows the application to decide if a 0-RTT connection attempt should be accepted.
|
// Allow0RTT allows the application to decide if a 0-RTT connection attempt should be accepted.
|
||||||
// Only valid for the server.
|
// Only valid for the server.
|
||||||
Allow0RTT bool
|
Allow0RTT bool
|
||||||
|
|
|
@ -59,6 +59,7 @@ type zeroRTTQueue struct {
|
||||||
type baseServer struct {
|
type baseServer struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
|
|
||||||
|
disableVersionNegotiation bool
|
||||||
acceptEarlyConns bool
|
acceptEarlyConns bool
|
||||||
|
|
||||||
tlsConf *tls.Config
|
tlsConf *tls.Config
|
||||||
|
@ -226,6 +227,7 @@ func newServer(
|
||||||
config *Config,
|
config *Config,
|
||||||
tracer logging.Tracer,
|
tracer logging.Tracer,
|
||||||
onClose func(),
|
onClose func(),
|
||||||
|
disableVersionNegotiation bool,
|
||||||
acceptEarly bool,
|
acceptEarly bool,
|
||||||
) (*baseServer, error) {
|
) (*baseServer, error) {
|
||||||
tokenGenerator, err := handshake.NewTokenGenerator(rand.Reader)
|
tokenGenerator, err := handshake.NewTokenGenerator(rand.Reader)
|
||||||
|
@ -249,6 +251,7 @@ func newServer(
|
||||||
tracer: tracer,
|
tracer: tracer,
|
||||||
logger: utils.DefaultLogger.WithPrefix("server"),
|
logger: utils.DefaultLogger.WithPrefix("server"),
|
||||||
acceptEarlyConns: acceptEarly,
|
acceptEarlyConns: acceptEarly,
|
||||||
|
disableVersionNegotiation: disableVersionNegotiation,
|
||||||
onClose: onClose,
|
onClose: onClose,
|
||||||
}
|
}
|
||||||
if acceptEarly {
|
if acceptEarly {
|
||||||
|
@ -383,7 +386,7 @@ func (s *baseServer) handlePacketImpl(p receivedPacket) bool /* is the buffer st
|
||||||
}
|
}
|
||||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||||
if !protocol.IsSupportedVersion(s.config.Versions, v) {
|
if !protocol.IsSupportedVersion(s.config.Versions, v) {
|
||||||
if s.config.DisableVersionNegotiationPackets {
|
if s.disableVersionNegotiation {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -357,7 +357,7 @@ var _ = Describe("Server", func() {
|
||||||
})
|
})
|
||||||
|
|
||||||
It("doesn't send a Version Negotiation packets if sending them is disabled", func() {
|
It("doesn't send a Version Negotiation packets if sending them is disabled", func() {
|
||||||
serv.config.DisableVersionNegotiationPackets = true
|
serv.disableVersionNegotiation = true
|
||||||
srcConnID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5})
|
srcConnID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5})
|
||||||
destConnID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6})
|
destConnID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6})
|
||||||
packet := getPacket(&wire.Header{
|
packet := getPacket(&wire.Header{
|
||||||
|
|
47
transport.go
47
transport.go
|
@ -57,6 +57,11 @@ type Transport struct {
|
||||||
// See section 10.3 of RFC 9000 for details.
|
// See section 10.3 of RFC 9000 for details.
|
||||||
StatelessResetKey *StatelessResetKey
|
StatelessResetKey *StatelessResetKey
|
||||||
|
|
||||||
|
// DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
|
||||||
|
// This can be useful if version information is exchanged out-of-band.
|
||||||
|
// It has no effect for clients.
|
||||||
|
DisableVersionNegotiationPackets bool
|
||||||
|
|
||||||
// A Tracer traces events that don't belong to a single QUIC connection.
|
// A Tracer traces events that don't belong to a single QUIC connection.
|
||||||
Tracer logging.Tracer
|
Tracer logging.Tracer
|
||||||
|
|
||||||
|
@ -95,28 +100,10 @@ type Transport struct {
|
||||||
// There can only be a single listener on any net.PacketConn.
|
// There can only be a single listener on any net.PacketConn.
|
||||||
// Listen may only be called again after the current Listener was closed.
|
// Listen may only be called again after the current Listener was closed.
|
||||||
func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) {
|
func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) {
|
||||||
if tlsConf == nil {
|
s, err := t.createServer(tlsConf, conf, false)
|
||||||
return nil, errors.New("quic: tls.Config not set")
|
|
||||||
}
|
|
||||||
if err := validateConfig(conf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t.mutex.Lock()
|
|
||||||
defer t.mutex.Unlock()
|
|
||||||
|
|
||||||
if t.server != nil {
|
|
||||||
return nil, errListenerAlreadySet
|
|
||||||
}
|
|
||||||
conf = populateServerConfig(conf)
|
|
||||||
if err := t.init(false); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s, err := newServer(t.conn, t.handlerMap, t.connIDGenerator, tlsConf, conf, t.Tracer, t.closeServer, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.server = s
|
|
||||||
return &Listener{baseServer: s}, nil
|
return &Listener{baseServer: s}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +111,14 @@ func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error)
|
||||||
// There can only be a single listener on any net.PacketConn.
|
// There can only be a single listener on any net.PacketConn.
|
||||||
// Listen may only be called again after the current Listener was closed.
|
// Listen may only be called again after the current Listener was closed.
|
||||||
func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) {
|
func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) {
|
||||||
|
s, err := t.createServer(tlsConf, conf, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &EarlyListener{baseServer: s}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transport) createServer(tlsConf *tls.Config, conf *Config, allow0RTT bool) (*baseServer, error) {
|
||||||
if tlsConf == nil {
|
if tlsConf == nil {
|
||||||
return nil, errors.New("quic: tls.Config not set")
|
return nil, errors.New("quic: tls.Config not set")
|
||||||
}
|
}
|
||||||
|
@ -141,12 +136,22 @@ func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListen
|
||||||
if err := t.init(false); err != nil {
|
if err := t.init(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s, err := newServer(t.conn, t.handlerMap, t.connIDGenerator, tlsConf, conf, t.Tracer, t.closeServer, true)
|
s, err := newServer(
|
||||||
|
t.conn,
|
||||||
|
t.handlerMap,
|
||||||
|
t.connIDGenerator,
|
||||||
|
tlsConf,
|
||||||
|
conf,
|
||||||
|
t.Tracer,
|
||||||
|
t.closeServer,
|
||||||
|
t.DisableVersionNegotiationPackets,
|
||||||
|
allow0RTT,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.server = s
|
t.server = s
|
||||||
return &EarlyListener{baseServer: s}, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial dials a new connection to a remote host (not using 0-RTT).
|
// Dial dials a new connection to a remote host (not using 0-RTT).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue