github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/wire/transport_parameter_test.go (about) 1 package wire 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "net/netip" 8 "time" 9 10 "golang.org/x/exp/rand" 11 12 "github.com/apernet/quic-go/internal/protocol" 13 "github.com/apernet/quic-go/internal/qerr" 14 "github.com/apernet/quic-go/quicvarint" 15 16 . "github.com/onsi/ginkgo/v2" 17 . "github.com/onsi/gomega" 18 ) 19 20 var _ = Describe("Transport Parameters", func() { 21 getRandomValueUpTo := func(max int64) uint64 { 22 maxVals := []int64{math.MaxUint8 / 4, math.MaxUint16 / 4, math.MaxUint32 / 4, math.MaxUint64 / 4} 23 m := maxVals[int(rand.Int31n(4))] 24 if m > max { 25 m = max 26 } 27 return uint64(rand.Int63n(m)) 28 } 29 30 getRandomValue := func() uint64 { 31 return getRandomValueUpTo(math.MaxInt64) 32 } 33 34 BeforeEach(func() { 35 rand.Seed(uint64(GinkgoRandomSeed())) 36 }) 37 38 appendInitialSourceConnectionID := func(b []byte) []byte { 39 b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID)) 40 b = quicvarint.Append(b, 6) 41 return append(b, []byte("foobar")...) 42 } 43 44 It("has a string representation", func() { 45 rcid := protocol.ParseConnectionID([]byte{0xde, 0xad, 0xc0, 0xde}) 46 p := &TransportParameters{ 47 InitialMaxStreamDataBidiLocal: 1234, 48 InitialMaxStreamDataBidiRemote: 2345, 49 InitialMaxStreamDataUni: 3456, 50 InitialMaxData: 4567, 51 MaxBidiStreamNum: 1337, 52 MaxUniStreamNum: 7331, 53 MaxIdleTimeout: 42 * time.Second, 54 OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 55 InitialSourceConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}), 56 RetrySourceConnectionID: &rcid, 57 AckDelayExponent: 14, 58 MaxAckDelay: 37 * time.Millisecond, 59 StatelessResetToken: &protocol.StatelessResetToken{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}, 60 ActiveConnectionIDLimit: 123, 61 MaxDatagramFrameSize: 876, 62 } 63 Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: decafbad, RetrySourceConnectionID: deadc0de, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00, MaxDatagramFrameSize: 876}")) 64 }) 65 66 It("has a string representation, if there's no stateless reset token, no Retry source connection id and no datagram support", func() { 67 p := &TransportParameters{ 68 InitialMaxStreamDataBidiLocal: 1234, 69 InitialMaxStreamDataBidiRemote: 2345, 70 InitialMaxStreamDataUni: 3456, 71 InitialMaxData: 4567, 72 MaxBidiStreamNum: 1337, 73 MaxUniStreamNum: 7331, 74 MaxIdleTimeout: 42 * time.Second, 75 OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 76 InitialSourceConnectionID: protocol.ParseConnectionID([]byte{}), 77 AckDelayExponent: 14, 78 MaxAckDelay: 37 * time.Second, 79 ActiveConnectionIDLimit: 89, 80 MaxDatagramFrameSize: protocol.InvalidByteCount, 81 } 82 Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: (empty), InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89}")) 83 }) 84 85 It("marshals and unmarshals", func() { 86 var token protocol.StatelessResetToken 87 rand.Read(token[:]) 88 rcid := protocol.ParseConnectionID([]byte{0xde, 0xad, 0xc0, 0xde}) 89 params := &TransportParameters{ 90 InitialMaxStreamDataBidiLocal: protocol.ByteCount(getRandomValue()), 91 InitialMaxStreamDataBidiRemote: protocol.ByteCount(getRandomValue()), 92 InitialMaxStreamDataUni: protocol.ByteCount(getRandomValue()), 93 InitialMaxData: protocol.ByteCount(getRandomValue()), 94 MaxIdleTimeout: 0xcafe * time.Second, 95 MaxBidiStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), 96 MaxUniStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), 97 DisableActiveMigration: true, 98 StatelessResetToken: &token, 99 OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 100 InitialSourceConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}), 101 RetrySourceConnectionID: &rcid, 102 AckDelayExponent: 13, 103 MaxAckDelay: 42 * time.Millisecond, 104 ActiveConnectionIDLimit: 2 + getRandomValueUpTo(math.MaxInt64-2), 105 MaxDatagramFrameSize: protocol.ByteCount(getRandomValue()), 106 } 107 data := params.Marshal(protocol.PerspectiveServer) 108 109 p := &TransportParameters{} 110 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) 111 Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal)) 112 Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote)) 113 Expect(p.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni)) 114 Expect(p.InitialMaxData).To(Equal(params.InitialMaxData)) 115 Expect(p.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum)) 116 Expect(p.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum)) 117 Expect(p.MaxIdleTimeout).To(Equal(params.MaxIdleTimeout)) 118 Expect(p.DisableActiveMigration).To(Equal(params.DisableActiveMigration)) 119 Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken)) 120 Expect(p.OriginalDestinationConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}))) 121 Expect(p.InitialSourceConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}))) 122 Expect(p.RetrySourceConnectionID).To(Equal(&rcid)) 123 Expect(p.AckDelayExponent).To(Equal(uint8(13))) 124 Expect(p.MaxAckDelay).To(Equal(42 * time.Millisecond)) 125 Expect(p.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit)) 126 Expect(p.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize)) 127 }) 128 129 It("marshals additional transport parameters (used for testing large ClientHellos)", func() { 130 origAdditionalTransportParametersClient := AdditionalTransportParametersClient 131 defer func() { 132 AdditionalTransportParametersClient = origAdditionalTransportParametersClient 133 }() 134 AdditionalTransportParametersClient = map[uint64][]byte{1337: []byte("foobar")} 135 136 result := quicvarint.Append([]byte{}, 1337) 137 result = quicvarint.Append(result, 6) 138 result = append(result, []byte("foobar")...) 139 140 params := &TransportParameters{} 141 Expect(bytes.Contains(params.Marshal(protocol.PerspectiveClient), result)).To(BeTrue()) 142 Expect(bytes.Contains(params.Marshal(protocol.PerspectiveServer), result)).To(BeFalse()) 143 }) 144 145 It("doesn't marshal a retry_source_connection_id, if no Retry was performed", func() { 146 data := (&TransportParameters{ 147 StatelessResetToken: &protocol.StatelessResetToken{}, 148 ActiveConnectionIDLimit: 2, 149 }).Marshal(protocol.PerspectiveServer) 150 p := &TransportParameters{} 151 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) 152 Expect(p.RetrySourceConnectionID).To(BeNil()) 153 }) 154 155 It("marshals a zero-length retry_source_connection_id", func() { 156 rcid := protocol.ParseConnectionID([]byte{}) 157 data := (&TransportParameters{ 158 RetrySourceConnectionID: &rcid, 159 StatelessResetToken: &protocol.StatelessResetToken{}, 160 ActiveConnectionIDLimit: 2, 161 }).Marshal(protocol.PerspectiveServer) 162 p := &TransportParameters{} 163 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) 164 Expect(p.RetrySourceConnectionID).ToNot(BeNil()) 165 Expect(p.RetrySourceConnectionID.Len()).To(BeZero()) 166 }) 167 168 It("errors when the stateless_reset_token has the wrong length", func() { 169 b := quicvarint.Append(nil, uint64(statelessResetTokenParameterID)) 170 b = quicvarint.Append(b, 15) 171 b = append(b, make([]byte, 15)...) 172 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 173 ErrorCode: qerr.TransportParameterError, 174 ErrorMessage: "wrong length for stateless_reset_token: 15 (expected 16)", 175 })) 176 }) 177 178 It("errors when the max_packet_size is too small", func() { 179 b := quicvarint.Append(nil, uint64(maxUDPPayloadSizeParameterID)) 180 b = quicvarint.Append(b, uint64(quicvarint.Len(1199))) 181 b = quicvarint.Append(b, 1199) 182 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 183 ErrorCode: qerr.TransportParameterError, 184 ErrorMessage: "invalid value for max_packet_size: 1199 (minimum 1200)", 185 })) 186 }) 187 188 It("errors when disable_active_migration has content", func() { 189 b := quicvarint.Append(nil, uint64(disableActiveMigrationParameterID)) 190 b = quicvarint.Append(b, 6) 191 b = append(b, []byte("foobar")...) 192 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 193 ErrorCode: qerr.TransportParameterError, 194 ErrorMessage: "wrong length for disable_active_migration: 6 (expected empty)", 195 })) 196 }) 197 198 It("errors when the server doesn't set the original_destination_connection_id", func() { 199 b := quicvarint.Append(nil, uint64(statelessResetTokenParameterID)) 200 b = quicvarint.Append(b, 16) 201 b = append(b, make([]byte, 16)...) 202 b = appendInitialSourceConnectionID(b) 203 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 204 ErrorCode: qerr.TransportParameterError, 205 ErrorMessage: "missing original_destination_connection_id", 206 })) 207 }) 208 209 It("errors when the initial_source_connection_id is missing", func() { 210 Expect((&TransportParameters{}).Unmarshal([]byte{}, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 211 ErrorCode: qerr.TransportParameterError, 212 ErrorMessage: "missing initial_source_connection_id", 213 })) 214 }) 215 216 It("errors when the max_ack_delay is too large", func() { 217 data := (&TransportParameters{ 218 MaxAckDelay: 1 << 14 * time.Millisecond, 219 StatelessResetToken: &protocol.StatelessResetToken{}, 220 }).Marshal(protocol.PerspectiveServer) 221 p := &TransportParameters{} 222 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 223 ErrorCode: qerr.TransportParameterError, 224 ErrorMessage: "invalid value for max_ack_delay: 16384ms (maximum 16383ms)", 225 })) 226 }) 227 228 It("doesn't send the max_ack_delay, if it has the default value", func() { 229 const num = 1000 230 var defaultLen, dataLen int 231 // marshal 1000 times to average out the greasing transport parameter 232 maxAckDelay := protocol.DefaultMaxAckDelay + time.Millisecond 233 for i := 0; i < num; i++ { 234 dataDefault := (&TransportParameters{ 235 MaxAckDelay: protocol.DefaultMaxAckDelay, 236 StatelessResetToken: &protocol.StatelessResetToken{}, 237 }).Marshal(protocol.PerspectiveServer) 238 defaultLen += len(dataDefault) 239 data := (&TransportParameters{ 240 MaxAckDelay: maxAckDelay, 241 StatelessResetToken: &protocol.StatelessResetToken{}, 242 }).Marshal(protocol.PerspectiveServer) 243 dataLen += len(data) 244 } 245 entryLen := quicvarint.Len(uint64(ackDelayExponentParameterID)) /* parameter id */ + quicvarint.Len(uint64(quicvarint.Len(uint64(maxAckDelay.Milliseconds())))) /*length */ + quicvarint.Len(uint64(maxAckDelay.Milliseconds())) /* value */ 246 Expect(float32(dataLen) / num).To(BeNumerically("~", float32(defaultLen)/num+float32(entryLen), 1)) 247 }) 248 249 It("errors when the active_connection_id_limit is too small", func() { 250 data := (&TransportParameters{ 251 ActiveConnectionIDLimit: 1, 252 StatelessResetToken: &protocol.StatelessResetToken{}, 253 }).Marshal(protocol.PerspectiveServer) 254 p := &TransportParameters{} 255 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 256 ErrorCode: qerr.TransportParameterError, 257 ErrorMessage: "invalid value for active_connection_id_limit: 1 (minimum 2)", 258 })) 259 }) 260 261 It("errors when the ack_delay_exponenent is too large", func() { 262 data := (&TransportParameters{ 263 AckDelayExponent: 21, 264 StatelessResetToken: &protocol.StatelessResetToken{}, 265 }).Marshal(protocol.PerspectiveServer) 266 p := &TransportParameters{} 267 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 268 ErrorCode: qerr.TransportParameterError, 269 ErrorMessage: "invalid value for ack_delay_exponent: 21 (maximum 20)", 270 })) 271 }) 272 273 It("doesn't send the ack_delay_exponent, if it has the default value", func() { 274 const num = 1000 275 var defaultLen, dataLen int 276 // marshal 1000 times to average out the greasing transport parameter 277 for i := 0; i < num; i++ { 278 dataDefault := (&TransportParameters{ 279 AckDelayExponent: protocol.DefaultAckDelayExponent, 280 StatelessResetToken: &protocol.StatelessResetToken{}, 281 }).Marshal(protocol.PerspectiveServer) 282 defaultLen += len(dataDefault) 283 data := (&TransportParameters{ 284 AckDelayExponent: protocol.DefaultAckDelayExponent + 1, 285 StatelessResetToken: &protocol.StatelessResetToken{}, 286 }).Marshal(protocol.PerspectiveServer) 287 dataLen += len(data) 288 } 289 entryLen := quicvarint.Len(uint64(ackDelayExponentParameterID)) /* parameter id */ + quicvarint.Len(uint64(quicvarint.Len(protocol.DefaultAckDelayExponent+1))) /* length */ + quicvarint.Len(protocol.DefaultAckDelayExponent+1) /* value */ 290 Expect(float32(dataLen) / num).To(BeNumerically("~", float32(defaultLen)/num+float32(entryLen), 1)) 291 }) 292 293 It("sets the default value for the ack_delay_exponent and max_active_connection_id_limit, when no values were sent", func() { 294 data := (&TransportParameters{ 295 AckDelayExponent: protocol.DefaultAckDelayExponent, 296 StatelessResetToken: &protocol.StatelessResetToken{}, 297 ActiveConnectionIDLimit: protocol.DefaultActiveConnectionIDLimit, 298 }).Marshal(protocol.PerspectiveServer) 299 p := &TransportParameters{} 300 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) 301 Expect(p.AckDelayExponent).To(BeEquivalentTo(protocol.DefaultAckDelayExponent)) 302 Expect(p.ActiveConnectionIDLimit).To(BeEquivalentTo(protocol.DefaultActiveConnectionIDLimit)) 303 }) 304 305 It("errors when the varint value has the wrong length", func() { 306 b := quicvarint.Append(nil, uint64(initialMaxStreamDataBidiLocalParameterID)) 307 b = quicvarint.Append(b, 2) 308 val := uint64(0xdeadbeef) 309 Expect(quicvarint.Len(val)).ToNot(BeEquivalentTo(2)) 310 b = quicvarint.Append(b, val) 311 b = appendInitialSourceConnectionID(b) 312 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 313 ErrorCode: qerr.TransportParameterError, 314 ErrorMessage: fmt.Sprintf("inconsistent transport parameter length for transport parameter %#x", initialMaxStreamDataBidiLocalParameterID), 315 })) 316 }) 317 318 It("errors if initial_max_streams_bidi is too large", func() { 319 b := quicvarint.Append(nil, uint64(initialMaxStreamsBidiParameterID)) 320 b = quicvarint.Append(b, uint64(quicvarint.Len(uint64(protocol.MaxStreamCount+1)))) 321 b = quicvarint.Append(b, uint64(protocol.MaxStreamCount+1)) 322 b = appendInitialSourceConnectionID(b) 323 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 324 ErrorCode: qerr.TransportParameterError, 325 ErrorMessage: "initial_max_streams_bidi too large: 1152921504606846977 (maximum 1152921504606846976)", 326 })) 327 }) 328 329 It("errors if initial_max_streams_uni is too large", func() { 330 b := quicvarint.Append(nil, uint64(initialMaxStreamsUniParameterID)) 331 b = quicvarint.Append(b, uint64(quicvarint.Len(uint64(protocol.MaxStreamCount+1)))) 332 b = quicvarint.Append(b, uint64(protocol.MaxStreamCount+1)) 333 b = appendInitialSourceConnectionID(b) 334 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 335 ErrorCode: qerr.TransportParameterError, 336 ErrorMessage: "initial_max_streams_uni too large: 1152921504606846977 (maximum 1152921504606846976)", 337 })) 338 }) 339 340 It("handles huge max_ack_delay values", func() { 341 val := uint64(math.MaxUint64) / 5 342 b := quicvarint.Append(nil, uint64(maxAckDelayParameterID)) 343 b = quicvarint.Append(b, uint64(quicvarint.Len(val))) 344 b = quicvarint.Append(b, val) 345 b = appendInitialSourceConnectionID(b) 346 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 347 ErrorCode: qerr.TransportParameterError, 348 ErrorMessage: "invalid value for max_ack_delay: 3689348814741910323ms (maximum 16383ms)", 349 })) 350 }) 351 352 It("skips unknown parameters", func() { 353 // write a known parameter 354 b := quicvarint.Append(nil, uint64(initialMaxStreamDataBidiLocalParameterID)) 355 b = quicvarint.Append(b, uint64(quicvarint.Len(0x1337))) 356 b = quicvarint.Append(b, 0x1337) 357 // write an unknown parameter 358 b = quicvarint.Append(b, 0x42) 359 b = quicvarint.Append(b, 6) 360 b = append(b, []byte("foobar")...) 361 // write a known parameter 362 b = quicvarint.Append(b, uint64(initialMaxStreamDataBidiRemoteParameterID)) 363 b = quicvarint.Append(b, uint64(quicvarint.Len(0x42))) 364 b = quicvarint.Append(b, 0x42) 365 b = appendInitialSourceConnectionID(b) 366 p := &TransportParameters{} 367 Expect(p.Unmarshal(b, protocol.PerspectiveClient)).To(Succeed()) 368 Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(protocol.ByteCount(0x1337))) 369 Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(protocol.ByteCount(0x42))) 370 }) 371 372 It("rejects duplicate parameters", func() { 373 // write first parameter 374 b := quicvarint.Append(nil, uint64(initialMaxStreamDataBidiLocalParameterID)) 375 b = quicvarint.Append(b, uint64(quicvarint.Len(0x1337))) 376 b = quicvarint.Append(b, 0x1337) 377 // write a second parameter 378 b = quicvarint.Append(b, uint64(initialMaxStreamDataBidiRemoteParameterID)) 379 b = quicvarint.Append(b, uint64(quicvarint.Len(0x42))) 380 b = quicvarint.Append(b, 0x42) 381 // write first parameter again 382 b = quicvarint.Append(b, uint64(initialMaxStreamDataBidiLocalParameterID)) 383 b = quicvarint.Append(b, uint64(quicvarint.Len(0x1337))) 384 b = quicvarint.Append(b, 0x1337) 385 b = appendInitialSourceConnectionID(b) 386 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 387 ErrorCode: qerr.TransportParameterError, 388 ErrorMessage: fmt.Sprintf("received duplicate transport parameter %#x", initialMaxStreamDataBidiLocalParameterID), 389 })) 390 }) 391 392 It("errors if there's not enough data to read", func() { 393 b := quicvarint.Append(nil, 0x42) 394 b = quicvarint.Append(b, 7) 395 b = append(b, []byte("foobar")...) 396 p := &TransportParameters{} 397 Expect(p.Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 398 ErrorCode: qerr.TransportParameterError, 399 ErrorMessage: "remaining length (6) smaller than parameter length (7)", 400 })) 401 }) 402 403 It("errors if the client sent a stateless_reset_token", func() { 404 b := quicvarint.Append(nil, uint64(statelessResetTokenParameterID)) 405 b = quicvarint.Append(b, uint64(quicvarint.Len(16))) 406 b = append(b, make([]byte, 16)...) 407 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 408 ErrorCode: qerr.TransportParameterError, 409 ErrorMessage: "client sent a stateless_reset_token", 410 })) 411 }) 412 413 It("errors if the client sent the original_destination_connection_id", func() { 414 b := quicvarint.Append(nil, uint64(originalDestinationConnectionIDParameterID)) 415 b = quicvarint.Append(b, 6) 416 b = append(b, []byte("foobar")...) 417 Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 418 ErrorCode: qerr.TransportParameterError, 419 ErrorMessage: "client sent an original_destination_connection_id", 420 })) 421 }) 422 423 Context("preferred address", func() { 424 var pa *PreferredAddress 425 426 BeforeEach(func() { 427 pa = &PreferredAddress{ 428 IPv4: netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 42), 429 IPv6: netip.AddrPortFrom(netip.AddrFrom16([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), 13), 430 ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 431 StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 432 } 433 }) 434 435 It("marshals and unmarshals", func() { 436 data := (&TransportParameters{ 437 PreferredAddress: pa, 438 StatelessResetToken: &protocol.StatelessResetToken{}, 439 ActiveConnectionIDLimit: 2, 440 }).Marshal(protocol.PerspectiveServer) 441 p := &TransportParameters{} 442 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) 443 Expect(p.PreferredAddress.IPv4).To(Equal(pa.IPv4)) 444 Expect(p.PreferredAddress.IPv6).To(Equal(pa.IPv6)) 445 Expect(p.PreferredAddress.ConnectionID).To(Equal(pa.ConnectionID)) 446 Expect(p.PreferredAddress.StatelessResetToken).To(Equal(pa.StatelessResetToken)) 447 }) 448 449 It("errors if the client sent a preferred_address", func() { 450 b := quicvarint.Append(nil, uint64(preferredAddressParameterID)) 451 b = quicvarint.Append(b, 6) 452 b = append(b, []byte("foobar")...) 453 p := &TransportParameters{} 454 Expect(p.Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 455 ErrorCode: qerr.TransportParameterError, 456 ErrorMessage: "client sent a preferred_address", 457 })) 458 }) 459 460 It("errors on zero-length connection IDs", func() { 461 pa.ConnectionID = protocol.ParseConnectionID([]byte{}) 462 data := (&TransportParameters{ 463 PreferredAddress: pa, 464 StatelessResetToken: &protocol.StatelessResetToken{}, 465 }).Marshal(protocol.PerspectiveServer) 466 p := &TransportParameters{} 467 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 468 ErrorCode: qerr.TransportParameterError, 469 ErrorMessage: "invalid connection ID length: 0", 470 })) 471 }) 472 473 It("errors on EOF", func() { 474 raw := []byte{ 475 127, 0, 0, 1, // IPv4 476 0, 42, // IPv4 Port 477 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, // IPv6 478 13, 37, // IPv6 Port, 479 4, // conn ID len 480 0xde, 0xad, 0xbe, 0xef, 481 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, // stateless reset token 482 } 483 for i := 1; i < len(raw); i++ { 484 b := quicvarint.Append(nil, uint64(preferredAddressParameterID)) 485 b = append(b, raw[:i]...) 486 p := &TransportParameters{} 487 Expect(p.Unmarshal(b, protocol.PerspectiveServer)).ToNot(Succeed()) 488 } 489 }) 490 }) 491 492 Context("saving and retrieving from a session ticket", func() { 493 It("saves and retrieves the parameters", func() { 494 params := &TransportParameters{ 495 InitialMaxStreamDataBidiLocal: protocol.ByteCount(getRandomValue()), 496 InitialMaxStreamDataBidiRemote: protocol.ByteCount(getRandomValue()), 497 InitialMaxStreamDataUni: protocol.ByteCount(getRandomValue()), 498 InitialMaxData: protocol.ByteCount(getRandomValue()), 499 MaxBidiStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), 500 MaxUniStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), 501 ActiveConnectionIDLimit: 2 + getRandomValueUpTo(math.MaxInt64-2), 502 MaxDatagramFrameSize: protocol.ByteCount(getRandomValueUpTo(int64(MaxDatagramSize))), 503 } 504 Expect(params.ValidFor0RTT(params)).To(BeTrue()) 505 b := params.MarshalForSessionTicket(nil) 506 var tp TransportParameters 507 Expect(tp.UnmarshalFromSessionTicket(bytes.NewReader(b))).To(Succeed()) 508 Expect(tp.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal)) 509 Expect(tp.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote)) 510 Expect(tp.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni)) 511 Expect(tp.InitialMaxData).To(Equal(params.InitialMaxData)) 512 Expect(tp.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum)) 513 Expect(tp.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum)) 514 Expect(tp.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit)) 515 Expect(tp.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize)) 516 }) 517 518 It("rejects the parameters if it can't parse them", func() { 519 var p TransportParameters 520 Expect(p.UnmarshalFromSessionTicket(bytes.NewReader([]byte("foobar")))).ToNot(Succeed()) 521 }) 522 523 It("rejects the parameters if the version changed", func() { 524 var p TransportParameters 525 data := p.MarshalForSessionTicket(nil) 526 b := quicvarint.Append(nil, transportParameterMarshalingVersion+1) 527 b = append(b, data[quicvarint.Len(transportParameterMarshalingVersion):]...) 528 Expect(p.UnmarshalFromSessionTicket(bytes.NewReader(b))).To(MatchError(fmt.Sprintf("unknown transport parameter marshaling version: %d", transportParameterMarshalingVersion+1))) 529 }) 530 531 Context("rejects the parameters if they changed", func() { 532 var p TransportParameters 533 saved := &TransportParameters{ 534 InitialMaxStreamDataBidiLocal: 1, 535 InitialMaxStreamDataBidiRemote: 2, 536 InitialMaxStreamDataUni: 3, 537 InitialMaxData: 4, 538 MaxBidiStreamNum: 5, 539 MaxUniStreamNum: 6, 540 ActiveConnectionIDLimit: 7, 541 MaxDatagramFrameSize: 1000, 542 } 543 544 BeforeEach(func() { 545 p = *saved 546 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 547 }) 548 549 It("rejects the parameters if the InitialMaxStreamDataBidiLocal was reduced", func() { 550 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal - 1 551 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 552 }) 553 554 It("doesn't reject the parameters if the InitialMaxStreamDataBidiLocal was increased", func() { 555 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal + 1 556 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 557 }) 558 559 It("rejects the parameters if the InitialMaxStreamDataBidiRemote was reduced", func() { 560 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote - 1 561 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 562 }) 563 564 It("doesn't reject the parameters if the InitialMaxStreamDataBidiRemote was increased", func() { 565 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote + 1 566 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 567 }) 568 569 It("rejects the parameters if the InitialMaxStreamDataUni was reduced", func() { 570 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni - 1 571 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 572 }) 573 574 It("doesn't reject the parameters if the InitialMaxStreamDataUni was increased", func() { 575 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni + 1 576 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 577 }) 578 579 It("rejects the parameters if the InitialMaxData was reduced", func() { 580 p.InitialMaxData = saved.InitialMaxData - 1 581 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 582 }) 583 584 It("doesn't reject the parameters if the InitialMaxData was increased", func() { 585 p.InitialMaxData = saved.InitialMaxData + 1 586 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 587 }) 588 589 It("rejects the parameters if the MaxBidiStreamNum was reduced", func() { 590 p.MaxBidiStreamNum = saved.MaxBidiStreamNum - 1 591 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 592 }) 593 594 It("accepts the parameters if the MaxBidiStreamNum was increased", func() { 595 p.MaxBidiStreamNum = saved.MaxBidiStreamNum + 1 596 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 597 }) 598 599 It("rejects the parameters if the MaxUniStreamNum changed", func() { 600 p.MaxUniStreamNum = saved.MaxUniStreamNum - 1 601 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 602 }) 603 604 It("accepts the parameters if the MaxUniStreamNum was increased", func() { 605 p.MaxUniStreamNum = saved.MaxUniStreamNum + 1 606 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 607 }) 608 609 It("rejects the parameters if the ActiveConnectionIDLimit changed", func() { 610 p.ActiveConnectionIDLimit = 0 611 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 612 }) 613 614 It("accepts the parameters if the MaxDatagramFrameSize was increased", func() { 615 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1 616 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 617 }) 618 619 It("rejects the parameters if the MaxDatagramFrameSize reduced", func() { 620 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1 621 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 622 }) 623 }) 624 625 Context("client checks the parameters after successfully sending 0-RTT data", func() { 626 var p TransportParameters 627 saved := &TransportParameters{ 628 InitialMaxStreamDataBidiLocal: 1, 629 InitialMaxStreamDataBidiRemote: 2, 630 InitialMaxStreamDataUni: 3, 631 InitialMaxData: 4, 632 MaxBidiStreamNum: 5, 633 MaxUniStreamNum: 6, 634 ActiveConnectionIDLimit: 7, 635 MaxDatagramFrameSize: 1000, 636 } 637 638 BeforeEach(func() { 639 p = *saved 640 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 641 }) 642 643 It("rejects the parameters if the InitialMaxStreamDataBidiLocal was reduced", func() { 644 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal - 1 645 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 646 }) 647 648 It("doesn't reject the parameters if the InitialMaxStreamDataBidiLocal was increased", func() { 649 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal + 1 650 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 651 }) 652 653 It("rejects the parameters if the InitialMaxStreamDataBidiRemote was reduced", func() { 654 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote - 1 655 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 656 }) 657 658 It("doesn't reject the parameters if the InitialMaxStreamDataBidiRemote was increased", func() { 659 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote + 1 660 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 661 }) 662 663 It("rejects the parameters if the InitialMaxStreamDataUni was reduced", func() { 664 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni - 1 665 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 666 }) 667 668 It("doesn't reject the parameters if the InitialMaxStreamDataUni was increased", func() { 669 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni + 1 670 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 671 }) 672 673 It("rejects the parameters if the InitialMaxData was reduced", func() { 674 p.InitialMaxData = saved.InitialMaxData - 1 675 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 676 }) 677 678 It("doesn't reject the parameters if the InitialMaxData was increased", func() { 679 p.InitialMaxData = saved.InitialMaxData + 1 680 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 681 }) 682 683 It("rejects the parameters if the MaxBidiStreamNum was reduced", func() { 684 p.MaxBidiStreamNum = saved.MaxBidiStreamNum - 1 685 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 686 }) 687 688 It("doesn't reject the parameters if the MaxBidiStreamNum was increased", func() { 689 p.MaxBidiStreamNum = saved.MaxBidiStreamNum + 1 690 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 691 }) 692 693 It("rejects the parameters if the MaxUniStreamNum reduced", func() { 694 p.MaxUniStreamNum = saved.MaxUniStreamNum - 1 695 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 696 }) 697 698 It("doesn't reject the parameters if the MaxUniStreamNum was increased", func() { 699 p.MaxUniStreamNum = saved.MaxUniStreamNum + 1 700 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 701 }) 702 703 It("rejects the parameters if the ActiveConnectionIDLimit reduced", func() { 704 p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit - 1 705 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 706 }) 707 708 It("doesn't reject the parameters if the ActiveConnectionIDLimit increased", func() { 709 p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit + 1 710 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 711 }) 712 713 It("rejects the parameters if the MaxDatagramFrameSize reduced", func() { 714 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1 715 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 716 }) 717 718 It("doesn't reject the parameters if the MaxDatagramFrameSize increased", func() { 719 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1 720 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 721 }) 722 }) 723 }) 724 })