diff --git a/integrationtests/self/handshake_drop_test.go b/integrationtests/self/handshake_drop_test.go index 6b9e6b3a..574df4b6 100644 --- a/integrationtests/self/handshake_drop_test.go +++ b/integrationtests/self/handshake_drop_test.go @@ -14,6 +14,7 @@ import ( "github.com/quic-go/quic-go" quicproxy "github.com/quic-go/quic-go/integrationtests/tools/proxy" "github.com/quic-go/quic-go/internal/protocol" + "github.com/quic-go/quic-go/internal/wire" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -273,5 +274,25 @@ var _ = Describe("Handshake drop tests", func() { } } }) + + It("establishes a connection when the ClientHello is larger than 1 MTU (e.g. post-quantum)", func() { + origAdditionalTransportParametersClient := wire.AdditionalTransportParametersClient + defer func() { + wire.AdditionalTransportParametersClient = origAdditionalTransportParametersClient + }() + b := make([]byte, 2500) // the ClientHello will now span across 3 packets + mrand.New(mrand.NewSource(GinkgoRandomSeed())).Read(b) + wire.AdditionalTransportParametersClient = map[uint64][]byte{ + uint64(27 + 31*mrand.Intn(100)): b, + } + + startListenerAndProxy(func(d quicproxy.Direction, _ []byte) bool { + if d == quicproxy.DirectionOutgoing { + return false + } + return mrand.Intn(3) == 0 + }, false, false, version) + clientSpeaksFirst.run(version) + }) } }) diff --git a/internal/wire/transport_parameter_test.go b/internal/wire/transport_parameter_test.go index 813ffeef..f4c39603 100644 --- a/internal/wire/transport_parameter_test.go +++ b/internal/wire/transport_parameter_test.go @@ -125,6 +125,22 @@ var _ = Describe("Transport Parameters", func() { Expect(p.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize)) }) + It("marshals additional transport parameters (used for testing large ClientHellos)", func() { + origAdditionalTransportParametersClient := AdditionalTransportParametersClient + defer func() { + AdditionalTransportParametersClient = origAdditionalTransportParametersClient + }() + AdditionalTransportParametersClient = map[uint64][]byte{1337: []byte("foobar")} + + result := quicvarint.Append([]byte{}, 1337) + result = quicvarint.Append(result, 6) + result = append(result, []byte("foobar")...) + + params := &TransportParameters{} + Expect(bytes.Contains(params.Marshal(protocol.PerspectiveClient), result)).To(BeTrue()) + Expect(bytes.Contains(params.Marshal(protocol.PerspectiveServer), result)).To(BeFalse()) + }) + It("doesn't marshal a retry_source_connection_id, if no Retry was performed", func() { data := (&TransportParameters{ StatelessResetToken: &protocol.StatelessResetToken{}, diff --git a/internal/wire/transport_parameters.go b/internal/wire/transport_parameters.go index a64638cb..2cef88db 100644 --- a/internal/wire/transport_parameters.go +++ b/internal/wire/transport_parameters.go @@ -17,6 +17,12 @@ import ( "github.com/quic-go/quic-go/quicvarint" ) +// AdditionalTransportParametersClient are additional transport parameters that will be added +// to the client's transport parameters. +// This is not intended for production use, but _only_ to increase the size of the ClientHello beyond +// the usual size of less than 1 MTU. +var AdditionalTransportParametersClient map[uint64][]byte + const transportParameterMarshalingVersion = 1 func init() { @@ -402,6 +408,15 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte { if p.MaxDatagramFrameSize != protocol.InvalidByteCount { b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize)) } + + if pers == protocol.PerspectiveClient && len(AdditionalTransportParametersClient) > 0 { + for k, v := range AdditionalTransportParametersClient { + b = quicvarint.Append(b, k) + b = quicvarint.Append(b, uint64(len(v))) + b = append(b, v...) + } + } + return b }