diff --git a/internal/wire/transport_parameter_test.go b/internal/wire/transport_parameter_test.go index 1103755c..3ebb5fb1 100644 --- a/internal/wire/transport_parameter_test.go +++ b/internal/wire/transport_parameter_test.go @@ -26,6 +26,12 @@ var _ = Describe("Transport Parameters", func() { var token [16]byte + addInitialSourceConnectionID := func(b *bytes.Buffer) { + utils.WriteVarInt(b, uint64(initialSourceConnectionIDParameterID)) + utils.WriteVarInt(b, 6) + b.Write([]byte("foobar")) + } + It("has a string representation", func() { p := &TransportParameters{ InitialMaxStreamDataBidiLocal: 1234, @@ -36,12 +42,13 @@ var _ = Describe("Transport Parameters", func() { MaxUniStreamNum: 7331, MaxIdleTimeout: 42 * time.Second, OriginalDestinationConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + InitialSourceConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad}, AckDelayExponent: 14, MaxAckDelay: 37 * time.Millisecond, StatelessResetToken: &[16]byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}, ActiveConnectionIDLimit: 123, } - Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00}")) + Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: 0xdeadbeef, InitialSourceConnectionID: 0xdecafbad, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00}")) }) It("has a string representation, if there's no stateless reset token", func() { @@ -54,11 +61,12 @@ var _ = Describe("Transport Parameters", func() { MaxUniStreamNum: 7331, MaxIdleTimeout: 42 * time.Second, OriginalDestinationConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + InitialSourceConnectionID: protocol.ConnectionID{}, AckDelayExponent: 14, MaxAckDelay: 37 * time.Second, ActiveConnectionIDLimit: 89, } - Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89}")) + Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: 0xdeadbeef, InitialSourceConnectionID: (empty), InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89}")) }) It("marshals and unmarshals", func() { @@ -75,6 +83,7 @@ var _ = Describe("Transport Parameters", func() { DisableActiveMigration: true, StatelessResetToken: &token, OriginalDestinationConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, + InitialSourceConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad}, AckDelayExponent: 13, MaxAckDelay: 42 * time.Millisecond, ActiveConnectionIDLimit: getRandomValue(), @@ -93,6 +102,7 @@ var _ = Describe("Transport Parameters", func() { Expect(p.DisableActiveMigration).To(Equal(params.DisableActiveMigration)) Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken)) Expect(p.OriginalDestinationConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef})) + Expect(p.InitialSourceConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad})) Expect(p.AckDelayExponent).To(Equal(uint8(13))) Expect(p.MaxAckDelay).To(Equal(42 * time.Millisecond)) Expect(p.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit)) @@ -127,7 +137,12 @@ var _ = Describe("Transport Parameters", func() { utils.WriteVarInt(b, uint64(statelessResetTokenParameterID)) utils.WriteVarInt(b, 16) b.Write(token[:]) - Expect((&TransportParameters{}).Unmarshal(b.Bytes(), protocol.PerspectiveServer)).To(MatchError("TRANSPORT_PARAMETER_ERROR: expected original_destination_connection_id")) + addInitialSourceConnectionID(b) + Expect((&TransportParameters{}).Unmarshal(b.Bytes(), protocol.PerspectiveServer)).To(MatchError("TRANSPORT_PARAMETER_ERROR: missing original_destination_connection_id")) + }) + + It("errors when the initial_source_connection_id is missing", func() { + Expect((&TransportParameters{}).Unmarshal([]byte{}, protocol.PerspectiveClient)).To(MatchError("TRANSPORT_PARAMETER_ERROR: missing initial_source_connection_id")) }) It("errors when the max_ack_delay is too large", func() { @@ -206,8 +221,8 @@ var _ = Describe("Transport Parameters", func() { val := uint64(0xdeadbeef) Expect(utils.VarIntLen(val)).ToNot(BeEquivalentTo(2)) utils.WriteVarInt(b, val) - p := &TransportParameters{} - err := p.Unmarshal(b.Bytes(), protocol.PerspectiveServer) + addInitialSourceConnectionID(b) + err := (&TransportParameters{}).Unmarshal(b.Bytes(), protocol.PerspectiveServer) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("TRANSPORT_PARAMETER_ERROR: inconsistent transport parameter length")) }) @@ -218,6 +233,7 @@ var _ = Describe("Transport Parameters", func() { utils.WriteVarInt(b, uint64(maxAckDelayParameterID)) utils.WriteVarInt(b, uint64(utils.VarIntLen(val))) utils.WriteVarInt(b, val) + addInitialSourceConnectionID(b) p := &TransportParameters{} Expect(p.Unmarshal(b.Bytes(), protocol.PerspectiveClient)).To(Succeed()) Expect(p.MaxAckDelay).To(BeNumerically(">", 290*365*24*time.Hour)) @@ -237,6 +253,7 @@ var _ = Describe("Transport Parameters", func() { utils.WriteVarInt(b, uint64(initialMaxStreamDataBidiRemoteParameterID)) utils.WriteVarInt(b, uint64(utils.VarIntLen(0x42))) utils.WriteVarInt(b, 0x42) + addInitialSourceConnectionID(b) p := &TransportParameters{} Expect(p.Unmarshal(b.Bytes(), protocol.PerspectiveClient)).To(Succeed()) Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(protocol.ByteCount(0x1337))) @@ -257,8 +274,8 @@ var _ = Describe("Transport Parameters", func() { utils.WriteVarInt(b, uint64(initialMaxStreamDataBidiLocalParameterID)) utils.WriteVarInt(b, uint64(utils.VarIntLen(0x1337))) utils.WriteVarInt(b, 0x1337) - p := &TransportParameters{} - err := p.Unmarshal(b.Bytes(), protocol.PerspectiveClient) + addInitialSourceConnectionID(b) + err := (&TransportParameters{}).Unmarshal(b.Bytes(), protocol.PerspectiveClient) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("received duplicate transport parameter")) }) diff --git a/internal/wire/transport_parameters.go b/internal/wire/transport_parameters.go index 2fe056d8..6b3cb000 100644 --- a/internal/wire/transport_parameters.go +++ b/internal/wire/transport_parameters.go @@ -40,6 +40,7 @@ const ( disableActiveMigrationParameterID transportParameterID = 0xc preferredAddressParameterID transportParameterID = 0xd activeConnectionIDLimitParameterID transportParameterID = 0xe + initialSourceConnectionIDParameterID transportParameterID = 0xf ) // PreferredAddress is the value encoding in the preferred_address transport parameter @@ -73,9 +74,11 @@ type TransportParameters struct { PreferredAddress *PreferredAddress - StatelessResetToken *[16]byte OriginalDestinationConnectionID protocol.ConnectionID - ActiveConnectionIDLimit uint64 + InitialSourceConnectionID protocol.ConnectionID + + StatelessResetToken *[16]byte + ActiveConnectionIDLimit uint64 } // Unmarshal the transport parameters @@ -94,6 +97,7 @@ func (p *TransportParameters) unmarshal(data []byte, sentBy protocol.Perspective readAckDelayExponent bool readMaxAckDelay bool readOriginalDestinationConnectionID bool + readInitialSourceConnectionID bool ) r := bytes.NewReader(data) @@ -164,23 +168,31 @@ func (p *TransportParameters) unmarshal(data []byte, sentBy protocol.Perspective } p.OriginalDestinationConnectionID, _ = protocol.ReadConnectionID(r, int(paramLen)) readOriginalDestinationConnectionID = true + case initialSourceConnectionIDParameterID: + p.InitialSourceConnectionID, _ = protocol.ReadConnectionID(r, int(paramLen)) + readInitialSourceConnectionID = true default: r.Seek(int64(paramLen), io.SeekCurrent) } } } - if sentBy == protocol.PerspectiveServer && !fromSessionTicket && !readOriginalDestinationConnectionID { - return errors.New("expected original_destination_connection_id") - } - if !readAckDelayExponent { - p.AckDelayExponent = protocol.DefaultAckDelayExponent - } - if !readMaxAckDelay { - p.MaxAckDelay = protocol.DefaultMaxAckDelay - } - if p.MaxUDPPayloadSize == 0 { - p.MaxUDPPayloadSize = protocol.MaxByteCount + if !fromSessionTicket { + if sentBy == protocol.PerspectiveServer && !readOriginalDestinationConnectionID { + return errors.New("missing original_destination_connection_id") + } + if !readAckDelayExponent { + p.AckDelayExponent = protocol.DefaultAckDelayExponent + } + if !readMaxAckDelay { + p.MaxAckDelay = protocol.DefaultMaxAckDelay + } + if p.MaxUDPPayloadSize == 0 { + p.MaxUDPPayloadSize = protocol.MaxByteCount + } + if !readInitialSourceConnectionID { + return errors.New("missing initial_source_connection_id") + } } // check that every transport parameter was sent at most once @@ -360,9 +372,13 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte { b.Write(p.PreferredAddress.StatelessResetToken[:]) } } - // active_connection_id_limit p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit) + // initial_source_connection_id + utils.WriteVarInt(b, uint64(initialSourceConnectionIDParameterID)) + utils.WriteVarInt(b, uint64(p.InitialSourceConnectionID.Len())) + b.Write(p.InitialSourceConnectionID.Bytes()) + return b.Bytes() } @@ -424,8 +440,8 @@ func (p *TransportParameters) ValidFor0RTT(tp *TransportParameters) bool { // String returns a string representation, intended for logging. func (p *TransportParameters) String() string { - logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialMaxStreamDataBidiLocal: %d, InitialMaxStreamDataBidiRemote: %d, InitialMaxStreamDataUni: %d, InitialMaxData: %d, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, MaxIdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d" - logParams := []interface{}{p.OriginalDestinationConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit} + logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialSourceConnectionID: %s, InitialMaxStreamDataBidiLocal: %d, InitialMaxStreamDataBidiRemote: %d, InitialMaxStreamDataUni: %d, InitialMaxData: %d, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, MaxIdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d" + logParams := []interface{}{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit} if p.StatelessResetToken != nil { // the client never sends a stateless reset token logString += ", StatelessResetToken: %#x" logParams = append(logParams, *p.StatelessResetToken)