golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/conn_id_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import ( 10 "bytes" 11 "crypto/tls" 12 "fmt" 13 "net/netip" 14 "strings" 15 "testing" 16 ) 17 18 func TestConnIDClientHandshake(t *testing.T) { 19 tc := newTestConn(t, clientSide) 20 // On initialization, the client chooses local and remote IDs. 21 // 22 // The order in which we allocate the two isn't actually important, 23 // but test is a lot simpler if we assume. 24 if got, want := tc.conn.connIDState.srcConnID(), testLocalConnID(0); !bytes.Equal(got, want) { 25 t.Errorf("after initialization: srcConnID = %x, want %x", got, want) 26 } 27 dstConnID, _ := tc.conn.connIDState.dstConnID() 28 if got, want := dstConnID, testLocalConnID(-1); !bytes.Equal(got, want) { 29 t.Errorf("after initialization: dstConnID = %x, want %x", got, want) 30 } 31 32 // The server's first Initial packet provides the client with a 33 // non-transient remote connection ID. 34 tc.writeFrames(packetTypeInitial, 35 debugFrameCrypto{ 36 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 37 }) 38 dstConnID, _ = tc.conn.connIDState.dstConnID() 39 if got, want := dstConnID, testPeerConnID(0); !bytes.Equal(got, want) { 40 t.Errorf("after receiving Initial: dstConnID = %x, want %x", got, want) 41 } 42 43 wantLocal := []connID{{ 44 cid: testLocalConnID(0), 45 seq: 0, 46 }} 47 if got := tc.conn.connIDState.local; !connIDListEqual(got, wantLocal) { 48 t.Errorf("local ids: %v, want %v", fmtConnIDList(got), fmtConnIDList(wantLocal)) 49 } 50 wantRemote := []remoteConnID{{ 51 connID: connID{ 52 cid: testPeerConnID(0), 53 seq: 0, 54 }, 55 }} 56 if got := tc.conn.connIDState.remote; !remoteConnIDListEqual(got, wantRemote) { 57 t.Errorf("remote ids: %v, want %v", fmtRemoteConnIDList(got), fmtRemoteConnIDList(wantRemote)) 58 } 59 } 60 61 func TestConnIDServerHandshake(t *testing.T) { 62 tc := newTestConn(t, serverSide) 63 // On initialization, the server is provided with the client-chosen 64 // transient connection ID, and allocates an ID of its own. 65 // The Initial packet sets the remote connection ID. 66 tc.writeFrames(packetTypeInitial, 67 debugFrameCrypto{ 68 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial][:1], 69 }) 70 if got, want := tc.conn.connIDState.srcConnID(), testLocalConnID(0); !bytes.Equal(got, want) { 71 t.Errorf("after initClient: srcConnID = %q, want %q", got, want) 72 } 73 dstConnID, _ := tc.conn.connIDState.dstConnID() 74 if got, want := dstConnID, testPeerConnID(0); !bytes.Equal(got, want) { 75 t.Errorf("after initClient: dstConnID = %q, want %q", got, want) 76 } 77 78 // The Initial flight of CRYPTO data includes transport parameters, 79 // which cause us to allocate another local connection ID. 80 tc.writeFrames(packetTypeInitial, 81 debugFrameCrypto{ 82 off: 1, 83 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial][1:], 84 }) 85 wantLocal := []connID{{ 86 cid: testPeerConnID(-1), 87 seq: -1, 88 }, { 89 cid: testLocalConnID(0), 90 seq: 0, 91 }, { 92 cid: testLocalConnID(1), 93 seq: 1, 94 }} 95 if got := tc.conn.connIDState.local; !connIDListEqual(got, wantLocal) { 96 t.Errorf("local ids: %v, want %v", fmtConnIDList(got), fmtConnIDList(wantLocal)) 97 } 98 wantRemote := []remoteConnID{{ 99 connID: connID{ 100 cid: testPeerConnID(0), 101 seq: 0, 102 }, 103 }} 104 if got := tc.conn.connIDState.remote; !remoteConnIDListEqual(got, wantRemote) { 105 t.Errorf("remote ids: %v, want %v", fmtRemoteConnIDList(got), fmtRemoteConnIDList(wantRemote)) 106 } 107 108 // The client's first Handshake packet permits the server to discard the 109 // transient connection ID. 110 tc.writeFrames(packetTypeHandshake, 111 debugFrameCrypto{ 112 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 113 }) 114 wantLocal = []connID{{ 115 cid: testLocalConnID(0), 116 seq: 0, 117 }, { 118 cid: testLocalConnID(1), 119 seq: 1, 120 }} 121 if got := tc.conn.connIDState.local; !connIDListEqual(got, wantLocal) { 122 t.Errorf("local ids: %v, want %v", fmtConnIDList(got), fmtConnIDList(wantLocal)) 123 } 124 } 125 126 func connIDListEqual(a, b []connID) bool { 127 if len(a) != len(b) { 128 return false 129 } 130 for i := range a { 131 if a[i].seq != b[i].seq { 132 return false 133 } 134 if !bytes.Equal(a[i].cid, b[i].cid) { 135 return false 136 } 137 } 138 return true 139 } 140 141 func remoteConnIDListEqual(a, b []remoteConnID) bool { 142 if len(a) != len(b) { 143 return false 144 } 145 for i := range a { 146 if a[i].seq != b[i].seq { 147 return false 148 } 149 if !bytes.Equal(a[i].cid, b[i].cid) { 150 return false 151 } 152 if a[i].resetToken != b[i].resetToken { 153 return false 154 } 155 } 156 return true 157 } 158 159 func fmtConnIDList(s []connID) string { 160 var strs []string 161 for _, cid := range s { 162 strs = append(strs, fmt.Sprintf("[seq:%v cid:{%x}]", cid.seq, cid.cid)) 163 } 164 return "{" + strings.Join(strs, " ") + "}" 165 } 166 167 func fmtRemoteConnIDList(s []remoteConnID) string { 168 var strs []string 169 for _, cid := range s { 170 strs = append(strs, fmt.Sprintf("[seq:%v cid:{%x} token:{%x}]", cid.seq, cid.cid, cid.resetToken)) 171 } 172 return "{" + strings.Join(strs, " ") + "}" 173 } 174 175 func TestNewRandomConnID(t *testing.T) { 176 cid, err := newRandomConnID(0) 177 if len(cid) != connIDLen || err != nil { 178 t.Fatalf("newConnID() = %x, %v; want %v bytes", cid, connIDLen, err) 179 } 180 } 181 182 func TestConnIDPeerRequestsManyIDs(t *testing.T) { 183 // "An endpoint SHOULD ensure that its peer has a sufficient number 184 // of available and unused connection IDs." 185 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.1-4 186 // 187 // "An endpoint MAY limit the total number of connection IDs 188 // issued for each connection [...]" 189 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.1-6 190 // 191 // Peer requests 100 connection IDs. 192 // We give them 4 in total. 193 tc := newTestConn(t, serverSide, func(p *transportParameters) { 194 p.activeConnIDLimit = 100 195 }) 196 tc.ignoreFrame(frameTypeAck) 197 tc.ignoreFrame(frameTypeCrypto) 198 199 tc.writeFrames(packetTypeInitial, 200 debugFrameCrypto{ 201 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 202 }) 203 tc.wantFrame("provide additional connection ID 1", 204 packetType1RTT, debugFrameNewConnectionID{ 205 seq: 1, 206 connID: testLocalConnID(1), 207 token: testLocalStatelessResetToken(1), 208 }) 209 tc.wantFrame("provide additional connection ID 2", 210 packetType1RTT, debugFrameNewConnectionID{ 211 seq: 2, 212 connID: testLocalConnID(2), 213 token: testLocalStatelessResetToken(2), 214 }) 215 tc.wantFrame("provide additional connection ID 3", 216 packetType1RTT, debugFrameNewConnectionID{ 217 seq: 3, 218 connID: testLocalConnID(3), 219 token: testLocalStatelessResetToken(3), 220 }) 221 tc.wantIdle("connection ID limit reached, no more to provide") 222 } 223 224 func TestConnIDPeerProvidesTooManyIDs(t *testing.T) { 225 // "An endpoint MUST NOT provide more connection IDs than the peer's limit." 226 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.1-4 227 tc := newTestConn(t, serverSide) 228 tc.handshake() 229 tc.ignoreFrame(frameTypeAck) 230 231 tc.writeFrames(packetType1RTT, 232 debugFrameNewConnectionID{ 233 seq: 2, 234 connID: testLocalConnID(2), 235 }) 236 tc.wantFrame("peer provided 3 connection IDs, our limit is 2", 237 packetType1RTT, debugFrameConnectionCloseTransport{ 238 code: errConnectionIDLimit, 239 }) 240 } 241 242 func TestConnIDPeerTemporarilyExceedsActiveConnIDLimit(t *testing.T) { 243 // "An endpoint MAY send connection IDs that temporarily exceed a peer's limit 244 // if the NEW_CONNECTION_ID frame also requires the retirement of any excess [...]" 245 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.1-4 246 tc := newTestConn(t, serverSide) 247 tc.handshake() 248 tc.ignoreFrame(frameTypeAck) 249 250 tc.writeFrames(packetType1RTT, 251 debugFrameNewConnectionID{ 252 retirePriorTo: 2, 253 seq: 2, 254 connID: testPeerConnID(2), 255 }, debugFrameNewConnectionID{ 256 retirePriorTo: 2, 257 seq: 3, 258 connID: testPeerConnID(3), 259 }) 260 tc.wantFrame("peer requested we retire conn id 0", 261 packetType1RTT, debugFrameRetireConnectionID{ 262 seq: 0, 263 }) 264 tc.wantFrame("peer requested we retire conn id 1", 265 packetType1RTT, debugFrameRetireConnectionID{ 266 seq: 1, 267 }) 268 } 269 270 func TestConnIDPeerRetiresConnID(t *testing.T) { 271 // "An endpoint SHOULD supply a new connection ID when the peer retires a connection ID." 272 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.1-6 273 for _, side := range []connSide{ 274 clientSide, 275 serverSide, 276 } { 277 t.Run(side.String(), func(t *testing.T) { 278 tc := newTestConn(t, side) 279 tc.handshake() 280 tc.ignoreFrame(frameTypeAck) 281 282 tc.writeFrames(packetType1RTT, 283 debugFrameRetireConnectionID{ 284 seq: 0, 285 }) 286 tc.wantFrame("provide replacement connection ID", 287 packetType1RTT, debugFrameNewConnectionID{ 288 seq: 2, 289 retirePriorTo: 1, 290 connID: testLocalConnID(2), 291 token: testLocalStatelessResetToken(2), 292 }) 293 }) 294 } 295 } 296 297 func TestConnIDPeerWithZeroLengthConnIDSendsNewConnectionID(t *testing.T) { 298 // "An endpoint that selects a zero-length connection ID during the handshake 299 // cannot issue a new connection ID." 300 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.1-8 301 tc := newTestConn(t, clientSide, func(p *transportParameters) { 302 p.initialSrcConnID = []byte{} 303 }) 304 tc.peerConnID = []byte{} 305 tc.ignoreFrame(frameTypeAck) 306 tc.uncheckedHandshake() 307 308 tc.writeFrames(packetType1RTT, 309 debugFrameNewConnectionID{ 310 seq: 1, 311 connID: testPeerConnID(1), 312 }) 313 tc.wantFrame("invalid NEW_CONNECTION_ID: previous conn id is zero-length", 314 packetType1RTT, debugFrameConnectionCloseTransport{ 315 code: errProtocolViolation, 316 }) 317 } 318 319 func TestConnIDPeerRequestsRetirement(t *testing.T) { 320 // "Upon receipt of an increased Retire Prior To field, the peer MUST 321 // stop using the corresponding connection IDs and retire them with 322 // RETIRE_CONNECTION_ID frames [...]" 323 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.2-5 324 tc := newTestConn(t, clientSide) 325 tc.handshake() 326 tc.ignoreFrame(frameTypeAck) 327 328 tc.writeFrames(packetType1RTT, 329 debugFrameNewConnectionID{ 330 seq: 2, 331 retirePriorTo: 1, 332 connID: testPeerConnID(2), 333 }) 334 tc.wantFrame("peer asked for conn id 0 to be retired", 335 packetType1RTT, debugFrameRetireConnectionID{ 336 seq: 0, 337 }) 338 if got, want := tc.lastPacket.dstConnID, testPeerConnID(1); !bytes.Equal(got, want) { 339 t.Fatalf("used destination conn id {%x}, want {%x}", got, want) 340 } 341 } 342 343 func TestConnIDPeerDoesNotAcknowledgeRetirement(t *testing.T) { 344 // "An endpoint SHOULD limit the number of connection IDs it has retired locally 345 // for which RETIRE_CONNECTION_ID frames have not yet been acknowledged." 346 // https://www.rfc-editor.org/rfc/rfc9000#section-5.1.2-6 347 tc := newTestConn(t, clientSide) 348 tc.handshake() 349 tc.ignoreFrame(frameTypeAck) 350 tc.ignoreFrame(frameTypeRetireConnectionID) 351 352 // Send a number of NEW_CONNECTION_ID frames, each retiring an old one. 353 for seq := int64(0); seq < 7; seq++ { 354 tc.writeFrames(packetType1RTT, 355 debugFrameNewConnectionID{ 356 seq: seq + 2, 357 retirePriorTo: seq + 1, 358 connID: testPeerConnID(seq + 2), 359 }) 360 // We're ignoring the RETIRE_CONNECTION_ID frames. 361 } 362 tc.wantFrame("number of retired, unacked conn ids is too large", 363 packetType1RTT, debugFrameConnectionCloseTransport{ 364 code: errConnectionIDLimit, 365 }) 366 } 367 368 func TestConnIDRepeatedNewConnectionIDFrame(t *testing.T) { 369 // "Receipt of the same [NEW_CONNECTION_ID] frame multiple times 370 // MUST NOT be treated as a connection error. 371 // https://www.rfc-editor.org/rfc/rfc9000#section-19.15-7 372 tc := newTestConn(t, clientSide) 373 tc.handshake() 374 tc.ignoreFrame(frameTypeAck) 375 376 for i := 0; i < 4; i++ { 377 tc.writeFrames(packetType1RTT, 378 debugFrameNewConnectionID{ 379 seq: 2, 380 retirePriorTo: 1, 381 connID: testPeerConnID(2), 382 }) 383 } 384 tc.wantFrame("peer asked for conn id to be retired", 385 packetType1RTT, debugFrameRetireConnectionID{ 386 seq: 0, 387 }) 388 tc.wantIdle("repeated NEW_CONNECTION_ID frames are not an error") 389 } 390 391 func TestConnIDForSequenceNumberChanges(t *testing.T) { 392 // "[...] if a sequence number is used for different connection IDs, 393 // the endpoint MAY treat that receipt as a connection error 394 // of type PROTOCOL_VIOLATION." 395 // https://www.rfc-editor.org/rfc/rfc9000#section-19.15-8 396 tc := newTestConn(t, clientSide) 397 tc.handshake() 398 tc.ignoreFrame(frameTypeAck) 399 tc.ignoreFrame(frameTypeRetireConnectionID) 400 401 tc.writeFrames(packetType1RTT, 402 debugFrameNewConnectionID{ 403 seq: 2, 404 retirePriorTo: 1, 405 connID: testPeerConnID(2), 406 }) 407 tc.writeFrames(packetType1RTT, 408 debugFrameNewConnectionID{ 409 seq: 2, 410 retirePriorTo: 1, 411 connID: testPeerConnID(3), 412 }) 413 tc.wantFrame("connection ID for sequence 0 has changed", 414 packetType1RTT, debugFrameConnectionCloseTransport{ 415 code: errProtocolViolation, 416 }) 417 } 418 419 func TestConnIDRetirePriorToAfterNewConnID(t *testing.T) { 420 // "Receiving a value in the Retire Prior To field that is greater than 421 // that in the Sequence Number field MUST be treated as a connection error 422 // of type FRAME_ENCODING_ERROR. 423 // https://www.rfc-editor.org/rfc/rfc9000#section-19.15-9 424 tc := newTestConn(t, serverSide) 425 tc.handshake() 426 tc.ignoreFrame(frameTypeAck) 427 428 tc.writeFrames(packetType1RTT, 429 debugFrameNewConnectionID{ 430 retirePriorTo: 3, 431 seq: 2, 432 connID: testPeerConnID(2), 433 }) 434 tc.wantFrame("invalid NEW_CONNECTION_ID: retired the new conn id", 435 packetType1RTT, debugFrameConnectionCloseTransport{ 436 code: errFrameEncoding, 437 }) 438 } 439 440 func TestConnIDAlreadyRetired(t *testing.T) { 441 // "An endpoint that receives a NEW_CONNECTION_ID frame with a 442 // sequence number smaller than the Retire Prior To field of a 443 // previously received NEW_CONNECTION_ID frame MUST send a 444 // corresponding RETIRE_CONNECTION_ID frame [...]" 445 // https://www.rfc-editor.org/rfc/rfc9000#section-19.15-11 446 tc := newTestConn(t, clientSide) 447 tc.handshake() 448 tc.ignoreFrame(frameTypeAck) 449 450 tc.writeFrames(packetType1RTT, 451 debugFrameNewConnectionID{ 452 seq: 4, 453 retirePriorTo: 3, 454 connID: testPeerConnID(4), 455 }) 456 tc.wantFrame("peer asked for conn id to be retired", 457 packetType1RTT, debugFrameRetireConnectionID{ 458 seq: 0, 459 }) 460 tc.wantFrame("peer asked for conn id to be retired", 461 packetType1RTT, debugFrameRetireConnectionID{ 462 seq: 1, 463 }) 464 tc.writeFrames(packetType1RTT, 465 debugFrameNewConnectionID{ 466 seq: 2, 467 retirePriorTo: 0, 468 connID: testPeerConnID(2), 469 }) 470 tc.wantFrame("NEW_CONNECTION_ID was for an already-retired ID", 471 packetType1RTT, debugFrameRetireConnectionID{ 472 seq: 2, 473 }) 474 } 475 476 func TestConnIDRepeatedRetireConnectionIDFrame(t *testing.T) { 477 tc := newTestConn(t, clientSide) 478 tc.handshake() 479 tc.ignoreFrame(frameTypeAck) 480 481 for i := 0; i < 4; i++ { 482 tc.writeFrames(packetType1RTT, 483 debugFrameRetireConnectionID{ 484 seq: 0, 485 }) 486 } 487 tc.wantFrame("issue new conn id after peer retires one", 488 packetType1RTT, debugFrameNewConnectionID{ 489 retirePriorTo: 1, 490 seq: 2, 491 connID: testLocalConnID(2), 492 token: testLocalStatelessResetToken(2), 493 }) 494 tc.wantIdle("repeated RETIRE_CONNECTION_ID frames are not an error") 495 } 496 497 func TestConnIDRetiredUnsent(t *testing.T) { 498 // "Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number 499 // greater than any previously sent to the peer MUST be treated as a 500 // connection error of type PROTOCOL_VIOLATION." 501 // https://www.rfc-editor.org/rfc/rfc9000#section-19.16-7 502 tc := newTestConn(t, clientSide) 503 tc.handshake() 504 tc.ignoreFrame(frameTypeAck) 505 506 tc.writeFrames(packetType1RTT, 507 debugFrameRetireConnectionID{ 508 seq: 2, 509 }) 510 tc.wantFrame("invalid NEW_CONNECTION_ID: previous conn id is zero-length", 511 packetType1RTT, debugFrameConnectionCloseTransport{ 512 code: errProtocolViolation, 513 }) 514 } 515 516 func TestConnIDUsePreferredAddressConnID(t *testing.T) { 517 // Peer gives us a connection ID in the preferred address transport parameter. 518 // We don't use the preferred address at this time, but we should use the 519 // connection ID. (It isn't tied to any specific address.) 520 // 521 // This test will probably need updating if/when we start using the preferred address. 522 cid := testPeerConnID(10) 523 tc := newTestConn(t, serverSide, func(p *transportParameters) { 524 p.preferredAddrV4 = netip.MustParseAddrPort("0.0.0.0:0") 525 p.preferredAddrV6 = netip.MustParseAddrPort("[::0]:0") 526 p.preferredAddrConnID = cid 527 p.preferredAddrResetToken = make([]byte, 16) 528 }) 529 tc.uncheckedHandshake() 530 tc.ignoreFrame(frameTypeAck) 531 532 tc.writeFrames(packetType1RTT, 533 debugFrameNewConnectionID{ 534 seq: 2, 535 retirePriorTo: 1, 536 connID: []byte{0xff}, 537 }) 538 tc.wantFrame("peer asked for conn id 0 to be retired", 539 packetType1RTT, debugFrameRetireConnectionID{ 540 seq: 0, 541 }) 542 if got, want := tc.lastPacket.dstConnID, cid; !bytes.Equal(got, want) { 543 t.Fatalf("used destination conn id {%x}, want {%x} from preferred address transport parameter", got, want) 544 } 545 } 546 547 func TestConnIDPeerProvidesPreferredAddrAndTooManyConnIDs(t *testing.T) { 548 // Peer gives us more conn ids than our advertised limit, 549 // including a conn id in the preferred address transport parameter. 550 cid := testPeerConnID(10) 551 tc := newTestConn(t, serverSide, func(p *transportParameters) { 552 p.preferredAddrV4 = netip.MustParseAddrPort("0.0.0.0:0") 553 p.preferredAddrV6 = netip.MustParseAddrPort("[::0]:0") 554 p.preferredAddrConnID = cid 555 p.preferredAddrResetToken = make([]byte, 16) 556 }) 557 tc.uncheckedHandshake() 558 tc.ignoreFrame(frameTypeAck) 559 560 tc.writeFrames(packetType1RTT, 561 debugFrameNewConnectionID{ 562 seq: 2, 563 retirePriorTo: 0, 564 connID: testPeerConnID(2), 565 }) 566 tc.wantFrame("peer provided 3 connection IDs, our limit is 2", 567 packetType1RTT, debugFrameConnectionCloseTransport{ 568 code: errConnectionIDLimit, 569 }) 570 } 571 572 func TestConnIDPeerWithZeroLengthIDProvidesPreferredAddr(t *testing.T) { 573 // Peer gives us more conn ids than our advertised limit, 574 // including a conn id in the preferred address transport parameter. 575 tc := newTestConn(t, serverSide, func(p *transportParameters) { 576 p.initialSrcConnID = []byte{} 577 p.preferredAddrV4 = netip.MustParseAddrPort("0.0.0.0:0") 578 p.preferredAddrV6 = netip.MustParseAddrPort("[::0]:0") 579 p.preferredAddrConnID = testPeerConnID(1) 580 p.preferredAddrResetToken = make([]byte, 16) 581 }, func(cids *newServerConnIDs) { 582 cids.srcConnID = []byte{} 583 }, func(tc *testConn) { 584 tc.peerConnID = []byte{} 585 }) 586 587 tc.writeFrames(packetTypeInitial, 588 debugFrameCrypto{ 589 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 590 }) 591 tc.wantFrame("peer with zero-length connection ID tried to provide another in transport parameters", 592 packetTypeInitial, debugFrameConnectionCloseTransport{ 593 code: errProtocolViolation, 594 }) 595 } 596 597 func TestConnIDInitialSrcConnIDMismatch(t *testing.T) { 598 // "Endpoints MUST validate that received [initial_source_connection_id] 599 // parameters match received connection ID values." 600 // https://www.rfc-editor.org/rfc/rfc9000#section-7.3-3 601 testSides(t, "", func(t *testing.T, side connSide) { 602 tc := newTestConn(t, side, func(p *transportParameters) { 603 p.initialSrcConnID = []byte("invalid") 604 }) 605 tc.ignoreFrame(frameTypeAck) 606 tc.ignoreFrame(frameTypeCrypto) 607 tc.writeFrames(packetTypeInitial, 608 debugFrameCrypto{ 609 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 610 }) 611 if side == clientSide { 612 // Server transport parameters are carried in the Handshake packet. 613 tc.writeFrames(packetTypeHandshake, 614 debugFrameCrypto{ 615 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 616 }) 617 } 618 tc.wantFrame("initial_source_connection_id transport parameter mismatch", 619 packetTypeInitial, debugFrameConnectionCloseTransport{ 620 code: errTransportParameter, 621 }) 622 }) 623 } 624 625 func TestConnIDsCleanedUpAfterClose(t *testing.T) { 626 testSides(t, "", func(t *testing.T, side connSide) { 627 tc := newTestConn(t, side, func(p *transportParameters) { 628 if side == clientSide { 629 token := testPeerStatelessResetToken(0) 630 p.statelessResetToken = token[:] 631 } 632 }) 633 tc.handshake() 634 tc.ignoreFrame(frameTypeAck) 635 tc.writeFrames(packetType1RTT, 636 debugFrameNewConnectionID{ 637 seq: 2, 638 retirePriorTo: 1, 639 connID: testPeerConnID(2), 640 token: testPeerStatelessResetToken(0), 641 }) 642 tc.wantFrame("peer asked for conn id 0 to be retired", 643 packetType1RTT, debugFrameRetireConnectionID{ 644 seq: 0, 645 }) 646 tc.writeFrames(packetType1RTT, debugFrameConnectionCloseTransport{}) 647 tc.conn.Abort(nil) 648 tc.wantFrame("CONN_CLOSE sent after user closes connection", 649 packetType1RTT, debugFrameConnectionCloseTransport{}) 650 651 // Wait for the conn to drain. 652 // Then wait for the conn loop to exit, 653 // and force an immediate sync of the connsMap updates 654 // (normally only done by the endpoint read loop). 655 tc.advanceToTimer() 656 <-tc.conn.donec 657 tc.endpoint.e.connsMap.applyUpdates() 658 659 if got := len(tc.endpoint.e.connsMap.byConnID); got != 0 { 660 t.Errorf("%v conn ids in endpoint map after closing, want 0", got) 661 } 662 if got := len(tc.endpoint.e.connsMap.byResetToken); got != 0 { 663 t.Errorf("%v reset tokens in endpoint map after closing, want 0", got) 664 } 665 }) 666 }