From 7a18b870e8b2bd0a927653e8975d9c7fbd8b774a Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 10 May 2017 00:00:45 +0800 Subject: [PATCH] add a quic.Config option to ask the server to truncate the connection ID --- Changelog.md | 1 + client.go | 7 ++++--- handshake/crypto_setup_client.go | 7 ++++++- handshake/crypto_setup_client_test.go | 20 +++++++++++++++++++- handshake/interface.go | 5 +++++ interface.go | 4 ++++ session.go | 12 +++++++++++- session_test.go | 14 ++++++++++++++ 8 files changed, 64 insertions(+), 6 deletions(-) diff --git a/Changelog.md b/Changelog.md index 52f1c5bc..3ed8d048 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,4 +3,5 @@ ## v0.6.0 (unreleased) - Add a `quic.Config` option for QUIC versions +- Add a `quic.Config` option to request truncation of the connection ID from a server - Various bugfixes diff --git a/client.go b/client.go index ed1253b1..574714f3 100644 --- a/client.go +++ b/client.go @@ -75,9 +75,10 @@ func populateClientConfig(config *Config) *Config { } return &Config{ - TLSConfig: config.TLSConfig, - ConnState: config.ConnState, - Versions: versions, + TLSConfig: config.TLSConfig, + ConnState: config.ConnState, + Versions: versions, + RequestConnectionIDTruncation: config.RequestConnectionIDTruncation, } } diff --git a/handshake/crypto_setup_client.go b/handshake/crypto_setup_client.go index d47e23a6..76ae41f7 100644 --- a/handshake/crypto_setup_client.go +++ b/handshake/crypto_setup_client.go @@ -51,6 +51,7 @@ type cryptoSetupClient struct { forwardSecureAEAD crypto.AEAD aeadChanged chan<- protocol.EncryptionLevel + params *TransportParameters connectionParameters ConnectionParametersManager } @@ -71,6 +72,7 @@ func NewCryptoSetupClient( tlsConfig *tls.Config, connectionParameters ConnectionParametersManager, aeadChanged chan<- protocol.EncryptionLevel, + params *TransportParameters, negotiatedVersions []protocol.VersionNumber, ) (CryptoSetup, error) { return &cryptoSetupClient{ @@ -86,6 +88,7 @@ func NewCryptoSetupClient( aeadChanged: aeadChanged, negotiatedVersions: negotiatedVersions, divNonceChan: make(chan []byte), + params: params, }, nil } @@ -428,10 +431,12 @@ func (h *cryptoSetupClient) getTags() (map[Tag][]byte, error) { binary.LittleEndian.PutUint32(versionTag, protocol.VersionNumberToTag(h.version)) tags[TagVER] = versionTag + if h.params.RequestConnectionIDTruncation { + tags[TagTCID] = []byte{0, 0, 0, 0} + } if len(h.stk) > 0 { tags[TagSTK] = h.stk } - if len(h.sno) > 0 { tags[TagSNO] = h.sno } diff --git a/handshake/crypto_setup_client_test.go b/handshake/crypto_setup_client_test.go index 8d6a2512..706ddfc0 100644 --- a/handshake/crypto_setup_client_test.go +++ b/handshake/crypto_setup_client_test.go @@ -105,7 +105,17 @@ var _ = Describe("Client Crypto Setup", func() { certManager = &mockCertManager{} version := protocol.Version36 aeadChanged = make(chan protocol.EncryptionLevel, 2) - csInt, err := NewCryptoSetupClient("hostname", 0, version, stream, nil, NewConnectionParamatersManager(protocol.PerspectiveClient, version), aeadChanged, nil) + csInt, err := NewCryptoSetupClient( + "hostname", + 0, + version, + stream, + nil, + NewConnectionParamatersManager(protocol.PerspectiveClient, version), + aeadChanged, + &TransportParameters{}, + nil, + ) Expect(err).ToNot(HaveOccurred()) cs = csInt.(*cryptoSetupClient) cs.certManager = certManager @@ -468,6 +478,14 @@ var _ = Describe("Client Crypto Setup", func() { Expect(tags[TagPDMD]).To(Equal([]byte("X509"))) Expect(tags[TagVER]).To(Equal([]byte("Q036"))) Expect(tags[TagCCS]).To(Equal(certManager.commonCertificateHashes)) + Expect(tags).ToNot(HaveKey(TagTCID)) + }) + + It("requests to truncate the connection ID", func() { + cs.params.RequestConnectionIDTruncation = true + tags, err := cs.getTags() + Expect(err).ToNot(HaveOccurred()) + Expect(tags).To(HaveKeyWithValue(TagTCID, []byte{0, 0, 0, 0})) }) It("adds the tags returned from the connectionParametersManager to the CHLO", func() { diff --git a/handshake/interface.go b/handshake/interface.go index 3f0b6c09..67fb4062 100644 --- a/handshake/interface.go +++ b/handshake/interface.go @@ -16,3 +16,8 @@ type CryptoSetup interface { GetSealer() (protocol.EncryptionLevel, Sealer) GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (Sealer, error) } + +// TransportParameters are parameters sent to the peer during the handshake +type TransportParameters struct { + RequestConnectionIDTruncation bool +} diff --git a/interface.go b/interface.go index 46ed38c5..a1d351d1 100644 --- a/interface.go +++ b/interface.go @@ -67,6 +67,10 @@ type Config struct { // If not set, it uses all versions available. // Warning: This API should not be considered stable and will change soon. Versions []protocol.VersionNumber + // Ask the server to truncate the connection ID sent in the Public Header. + // This saves 8 bytes in the Public Header in every packet. However, if the IP address of the server changes, the connection cannot be migrated. + // Currently only valid for the client. + RequestConnectionIDTruncation bool } // A Listener for incoming QUIC connections diff --git a/session.go b/session.go index cc39c6ff..55dd1394 100644 --- a/session.go +++ b/session.go @@ -175,7 +175,17 @@ func newClientSession( s.aeadChanged = aeadChanged cryptoStream, _ := s.OpenStream() var err error - s.cryptoSetup, err = handshake.NewCryptoSetupClient(hostname, connectionID, v, cryptoStream, config.TLSConfig, s.connectionParameters, aeadChanged, negotiatedVersions) + s.cryptoSetup, err = handshake.NewCryptoSetupClient( + hostname, + connectionID, + v, + cryptoStream, + config.TLSConfig, + s.connectionParameters, + aeadChanged, + &handshake.TransportParameters{RequestConnectionIDTruncation: config.RequestConnectionIDTruncation}, + negotiatedVersions, + ) if err != nil { return nil, err } diff --git a/session_test.go b/session_test.go index 113aab08..14bd3281 100644 --- a/session_test.go +++ b/session_test.go @@ -749,6 +749,20 @@ var _ = Describe("Session", func() { Expect(clientSess.Close(nil)).To(Succeed()) }) + It("passes the transport parameters to the cryptoSetup, as a client", func() { + s, err := newClientSession( + nil, + "hostname", + protocol.Version35, + 0, + func(Session, bool) {}, + populateClientConfig(&Config{RequestConnectionIDTruncation: true}), + nil, + ) + Expect(err).ToNot(HaveOccurred()) + Expect(*(*bool)(unsafe.Pointer(reflect.ValueOf(s.cryptoSetup).Elem().FieldByName("params").Elem().FieldByName("RequestConnectionIDTruncation").UnsafeAddr()))).To(BeTrue()) + }) + Context("updating the remote address", func() { It("sets the remote address", func() { remoteIP := &net.IPAddr{IP: net.IPv4(192, 168, 0, 100)}