github.com/MerlinKodo/quic-go@v0.39.2/internal/wire/transport_parameter_test.go (about) 1 package wire 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "net" 8 "time" 9 10 "golang.org/x/exp/rand" 11 12 "github.com/MerlinKodo/quic-go/internal/protocol" 13 "github.com/MerlinKodo/quic-go/internal/qerr" 14 "github.com/MerlinKodo/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: net.IPv4(127, 0, 0, 1), 429 IPv4Port: 42, 430 IPv6: net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, 431 IPv6Port: 13, 432 ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 433 StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 434 } 435 }) 436 437 It("marshals and unmarshals", func() { 438 data := (&TransportParameters{ 439 PreferredAddress: pa, 440 StatelessResetToken: &protocol.StatelessResetToken{}, 441 ActiveConnectionIDLimit: 2, 442 }).Marshal(protocol.PerspectiveServer) 443 p := &TransportParameters{} 444 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) 445 Expect(p.PreferredAddress.IPv4.String()).To(Equal(pa.IPv4.String())) 446 Expect(p.PreferredAddress.IPv4Port).To(Equal(pa.IPv4Port)) 447 Expect(p.PreferredAddress.IPv6.String()).To(Equal(pa.IPv6.String())) 448 Expect(p.PreferredAddress.IPv6Port).To(Equal(pa.IPv6Port)) 449 Expect(p.PreferredAddress.ConnectionID).To(Equal(pa.ConnectionID)) 450 Expect(p.PreferredAddress.StatelessResetToken).To(Equal(pa.StatelessResetToken)) 451 }) 452 453 It("errors if the client sent a preferred_address", func() { 454 b := quicvarint.Append(nil, uint64(preferredAddressParameterID)) 455 b = quicvarint.Append(b, 6) 456 b = append(b, []byte("foobar")...) 457 p := &TransportParameters{} 458 Expect(p.Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{ 459 ErrorCode: qerr.TransportParameterError, 460 ErrorMessage: "client sent a preferred_address", 461 })) 462 }) 463 464 It("errors on zero-length connection IDs", func() { 465 pa.ConnectionID = protocol.ParseConnectionID([]byte{}) 466 data := (&TransportParameters{ 467 PreferredAddress: pa, 468 StatelessResetToken: &protocol.StatelessResetToken{}, 469 }).Marshal(protocol.PerspectiveServer) 470 p := &TransportParameters{} 471 Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{ 472 ErrorCode: qerr.TransportParameterError, 473 ErrorMessage: "invalid connection ID length: 0", 474 })) 475 }) 476 477 It("errors on EOF", func() { 478 raw := []byte{ 479 127, 0, 0, 1, // IPv4 480 0, 42, // IPv4 Port 481 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, // IPv6 482 13, 37, // IPv6 Port, 483 4, // conn ID len 484 0xde, 0xad, 0xbe, 0xef, 485 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, // stateless reset token 486 } 487 for i := 1; i < len(raw); i++ { 488 b := quicvarint.Append(nil, uint64(preferredAddressParameterID)) 489 b = append(b, raw[:i]...) 490 p := &TransportParameters{} 491 Expect(p.Unmarshal(b, protocol.PerspectiveServer)).ToNot(Succeed()) 492 } 493 }) 494 }) 495 496 Context("saving and retrieving from a session ticket", func() { 497 It("saves and retrieves the parameters", func() { 498 params := &TransportParameters{ 499 InitialMaxStreamDataBidiLocal: protocol.ByteCount(getRandomValue()), 500 InitialMaxStreamDataBidiRemote: protocol.ByteCount(getRandomValue()), 501 InitialMaxStreamDataUni: protocol.ByteCount(getRandomValue()), 502 InitialMaxData: protocol.ByteCount(getRandomValue()), 503 MaxBidiStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), 504 MaxUniStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), 505 ActiveConnectionIDLimit: 2 + getRandomValueUpTo(math.MaxInt64-2), 506 MaxDatagramFrameSize: protocol.ByteCount(getRandomValueUpTo(int64(protocol.MaxDatagramFrameSize))), 507 } 508 Expect(params.ValidFor0RTT(params)).To(BeTrue()) 509 b := params.MarshalForSessionTicket(nil) 510 var tp TransportParameters 511 Expect(tp.UnmarshalFromSessionTicket(bytes.NewReader(b))).To(Succeed()) 512 Expect(tp.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal)) 513 Expect(tp.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote)) 514 Expect(tp.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni)) 515 Expect(tp.InitialMaxData).To(Equal(params.InitialMaxData)) 516 Expect(tp.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum)) 517 Expect(tp.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum)) 518 Expect(tp.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit)) 519 Expect(tp.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize)) 520 }) 521 522 It("rejects the parameters if it can't parse them", func() { 523 var p TransportParameters 524 Expect(p.UnmarshalFromSessionTicket(bytes.NewReader([]byte("foobar")))).ToNot(Succeed()) 525 }) 526 527 It("rejects the parameters if the version changed", func() { 528 var p TransportParameters 529 data := p.MarshalForSessionTicket(nil) 530 b := quicvarint.Append(nil, transportParameterMarshalingVersion+1) 531 b = append(b, data[quicvarint.Len(transportParameterMarshalingVersion):]...) 532 Expect(p.UnmarshalFromSessionTicket(bytes.NewReader(b))).To(MatchError(fmt.Sprintf("unknown transport parameter marshaling version: %d", transportParameterMarshalingVersion+1))) 533 }) 534 535 Context("rejects the parameters if they changed", func() { 536 var p TransportParameters 537 saved := &TransportParameters{ 538 InitialMaxStreamDataBidiLocal: 1, 539 InitialMaxStreamDataBidiRemote: 2, 540 InitialMaxStreamDataUni: 3, 541 InitialMaxData: 4, 542 MaxBidiStreamNum: 5, 543 MaxUniStreamNum: 6, 544 ActiveConnectionIDLimit: 7, 545 MaxDatagramFrameSize: 1000, 546 } 547 548 BeforeEach(func() { 549 p = *saved 550 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 551 }) 552 553 It("rejects the parameters if the InitialMaxStreamDataBidiLocal was reduced", func() { 554 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal - 1 555 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 556 }) 557 558 It("doesn't reject the parameters if the InitialMaxStreamDataBidiLocal was increased", func() { 559 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal + 1 560 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 561 }) 562 563 It("rejects the parameters if the InitialMaxStreamDataBidiRemote was reduced", func() { 564 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote - 1 565 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 566 }) 567 568 It("doesn't reject the parameters if the InitialMaxStreamDataBidiRemote was increased", func() { 569 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote + 1 570 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 571 }) 572 573 It("rejects the parameters if the InitialMaxStreamDataUni was reduced", func() { 574 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni - 1 575 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 576 }) 577 578 It("doesn't reject the parameters if the InitialMaxStreamDataUni was increased", func() { 579 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni + 1 580 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 581 }) 582 583 It("rejects the parameters if the InitialMaxData was reduced", func() { 584 p.InitialMaxData = saved.InitialMaxData - 1 585 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 586 }) 587 588 It("doesn't reject the parameters if the InitialMaxData was increased", func() { 589 p.InitialMaxData = saved.InitialMaxData + 1 590 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 591 }) 592 593 It("rejects the parameters if the MaxBidiStreamNum was reduced", func() { 594 p.MaxBidiStreamNum = saved.MaxBidiStreamNum - 1 595 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 596 }) 597 598 It("accepts the parameters if the MaxBidiStreamNum was increased", func() { 599 p.MaxBidiStreamNum = saved.MaxBidiStreamNum + 1 600 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 601 }) 602 603 It("rejects the parameters if the MaxUniStreamNum changed", func() { 604 p.MaxUniStreamNum = saved.MaxUniStreamNum - 1 605 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 606 }) 607 608 It("accepts the parameters if the MaxUniStreamNum was increased", func() { 609 p.MaxUniStreamNum = saved.MaxUniStreamNum + 1 610 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 611 }) 612 613 It("rejects the parameters if the ActiveConnectionIDLimit changed", func() { 614 p.ActiveConnectionIDLimit = 0 615 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 616 }) 617 618 It("accepts the parameters if the MaxDatagramFrameSize was increased", func() { 619 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1 620 Expect(p.ValidFor0RTT(saved)).To(BeTrue()) 621 }) 622 623 It("rejects the parameters if the MaxDatagramFrameSize reduced", func() { 624 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1 625 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) 626 }) 627 }) 628 629 Context("client checks the parameters after successfully sending 0-RTT data", func() { 630 var p TransportParameters 631 saved := &TransportParameters{ 632 InitialMaxStreamDataBidiLocal: 1, 633 InitialMaxStreamDataBidiRemote: 2, 634 InitialMaxStreamDataUni: 3, 635 InitialMaxData: 4, 636 MaxBidiStreamNum: 5, 637 MaxUniStreamNum: 6, 638 ActiveConnectionIDLimit: 7, 639 MaxDatagramFrameSize: 1000, 640 } 641 642 BeforeEach(func() { 643 p = *saved 644 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 645 }) 646 647 It("rejects the parameters if the InitialMaxStreamDataBidiLocal was reduced", func() { 648 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal - 1 649 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 650 }) 651 652 It("doesn't reject the parameters if the InitialMaxStreamDataBidiLocal was increased", func() { 653 p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal + 1 654 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 655 }) 656 657 It("rejects the parameters if the InitialMaxStreamDataBidiRemote was reduced", func() { 658 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote - 1 659 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 660 }) 661 662 It("doesn't reject the parameters if the InitialMaxStreamDataBidiRemote was increased", func() { 663 p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote + 1 664 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 665 }) 666 667 It("rejects the parameters if the InitialMaxStreamDataUni was reduced", func() { 668 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni - 1 669 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 670 }) 671 672 It("doesn't reject the parameters if the InitialMaxStreamDataUni was increased", func() { 673 p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni + 1 674 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 675 }) 676 677 It("rejects the parameters if the InitialMaxData was reduced", func() { 678 p.InitialMaxData = saved.InitialMaxData - 1 679 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 680 }) 681 682 It("doesn't reject the parameters if the InitialMaxData was increased", func() { 683 p.InitialMaxData = saved.InitialMaxData + 1 684 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 685 }) 686 687 It("rejects the parameters if the MaxBidiStreamNum was reduced", func() { 688 p.MaxBidiStreamNum = saved.MaxBidiStreamNum - 1 689 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 690 }) 691 692 It("doesn't reject the parameters if the MaxBidiStreamNum was increased", func() { 693 p.MaxBidiStreamNum = saved.MaxBidiStreamNum + 1 694 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 695 }) 696 697 It("rejects the parameters if the MaxUniStreamNum reduced", func() { 698 p.MaxUniStreamNum = saved.MaxUniStreamNum - 1 699 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 700 }) 701 702 It("doesn't reject the parameters if the MaxUniStreamNum was increased", func() { 703 p.MaxUniStreamNum = saved.MaxUniStreamNum + 1 704 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 705 }) 706 707 It("rejects the parameters if the ActiveConnectionIDLimit reduced", func() { 708 p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit - 1 709 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 710 }) 711 712 It("doesn't reject the parameters if the ActiveConnectionIDLimit increased", func() { 713 p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit + 1 714 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 715 }) 716 717 It("rejects the parameters if the MaxDatagramFrameSize reduced", func() { 718 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1 719 Expect(p.ValidForUpdate(saved)).To(BeFalse()) 720 }) 721 722 It("doesn't reject the parameters if the MaxDatagramFrameSize increased", func() { 723 p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1 724 Expect(p.ValidForUpdate(saved)).To(BeTrue()) 725 }) 726 }) 727 }) 728 })