github.com/tumi8/quic-go@v0.37.4-tum/integrationtests/self/zero_rtt_oldgo_test.go (about) 1 //go:build !go1.21 2 3 package self_test 4 5 import ( 6 "context" 7 "crypto/tls" 8 "fmt" 9 "io" 10 mrand "math/rand" 11 "net" 12 "sync" 13 "sync/atomic" 14 "time" 15 16 "github.com/tumi8/quic-go" 17 quicproxy "github.com/tumi8/quic-go/integrationtests/tools/proxy" 18 "github.com/tumi8/quic-go/noninternal/protocol" 19 "github.com/tumi8/quic-go/noninternal/wire" 20 "github.com/tumi8/quic-go/logging" 21 22 . "github.com/onsi/ginkgo/v2" 23 . "github.com/onsi/gomega" 24 ) 25 26 var _ = Describe("0-RTT", func() { 27 rtt := scaleDuration(5 * time.Millisecond) 28 29 runCountingProxy := func(serverPort int) (*quicproxy.QuicProxy, *uint32) { 30 var num0RTTPackets uint32 // to be used as an atomic 31 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 32 RemoteAddr: fmt.Sprintf("localhost:%d", serverPort), 33 DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration { 34 for len(data) > 0 { 35 if !wire.IsLongHeaderPacket(data[0]) { 36 break 37 } 38 hdr, _, rest, err := wire.ParsePacket(data) 39 Expect(err).ToNot(HaveOccurred()) 40 if hdr.Type == protocol.PacketType0RTT { 41 atomic.AddUint32(&num0RTTPackets, 1) 42 break 43 } 44 data = rest 45 } 46 return rtt / 2 47 }, 48 }) 49 Expect(err).ToNot(HaveOccurred()) 50 51 return proxy, &num0RTTPackets 52 } 53 54 dialAndReceiveSessionTicket := func(serverConf *quic.Config) (*tls.Config, *tls.Config) { 55 tlsConf := getTLSConfig() 56 if serverConf == nil { 57 serverConf = getQuicConfig(nil) 58 } 59 serverConf.Allow0RTT = true 60 ln, err := quic.ListenAddrEarly( 61 "localhost:0", 62 tlsConf, 63 serverConf, 64 ) 65 Expect(err).ToNot(HaveOccurred()) 66 defer ln.Close() 67 68 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 69 RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 70 DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration { return rtt / 2 }, 71 }) 72 Expect(err).ToNot(HaveOccurred()) 73 defer proxy.Close() 74 75 // dial the first connection in order to receive a session ticket 76 done := make(chan struct{}) 77 go func() { 78 defer GinkgoRecover() 79 defer close(done) 80 conn, err := ln.Accept(context.Background()) 81 Expect(err).ToNot(HaveOccurred()) 82 <-conn.Context().Done() 83 }() 84 85 clientConf := getTLSClientConfig() 86 gets := make(chan string, 100) 87 puts := make(chan string, 100) 88 clientConf.ClientSessionCache = newClientSessionCache(tls.NewLRUClientSessionCache(100), gets, puts) 89 conn, err := quic.DialAddr( 90 context.Background(), 91 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 92 clientConf, 93 getQuicConfig(nil), 94 ) 95 Expect(err).ToNot(HaveOccurred()) 96 Eventually(puts).Should(Receive()) 97 // received the session ticket. We're done here. 98 Expect(conn.CloseWithError(0, "")).To(Succeed()) 99 Eventually(done).Should(BeClosed()) 100 return tlsConf, clientConf 101 } 102 103 transfer0RTTData := func( 104 ln *quic.EarlyListener, 105 proxyPort int, 106 connIDLen int, 107 clientTLSConf *tls.Config, 108 clientConf *quic.Config, 109 testdata []byte, // data to transfer 110 ) { 111 // accept the second connection, and receive the data sent in 0-RTT 112 done := make(chan struct{}) 113 go func() { 114 defer GinkgoRecover() 115 conn, err := ln.Accept(context.Background()) 116 Expect(err).ToNot(HaveOccurred()) 117 str, err := conn.AcceptStream(context.Background()) 118 Expect(err).ToNot(HaveOccurred()) 119 data, err := io.ReadAll(str) 120 Expect(err).ToNot(HaveOccurred()) 121 Expect(data).To(Equal(testdata)) 122 Expect(str.Close()).To(Succeed()) 123 Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) 124 <-conn.Context().Done() 125 close(done) 126 }() 127 128 if clientConf == nil { 129 clientConf = getQuicConfig(nil) 130 } 131 var conn quic.EarlyConnection 132 if connIDLen == 0 { 133 var err error 134 conn, err = quic.DialAddrEarly( 135 context.Background(), 136 fmt.Sprintf("localhost:%d", proxyPort), 137 clientTLSConf, 138 clientConf, 139 ) 140 Expect(err).ToNot(HaveOccurred()) 141 } else { 142 addr, err := net.ResolveUDPAddr("udp", "localhost:0") 143 Expect(err).ToNot(HaveOccurred()) 144 udpConn, err := net.ListenUDP("udp", addr) 145 Expect(err).ToNot(HaveOccurred()) 146 defer udpConn.Close() 147 tr := &quic.Transport{ 148 Conn: udpConn, 149 ConnectionIDLength: connIDLen, 150 } 151 defer tr.Close() 152 conn, err = tr.DialEarly( 153 context.Background(), 154 &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: proxyPort}, 155 clientTLSConf, 156 clientConf, 157 ) 158 Expect(err).ToNot(HaveOccurred()) 159 } 160 defer conn.CloseWithError(0, "") 161 str, err := conn.OpenStream() 162 Expect(err).ToNot(HaveOccurred()) 163 _, err = str.Write(testdata) 164 Expect(err).ToNot(HaveOccurred()) 165 Expect(str.Close()).To(Succeed()) 166 <-conn.HandshakeComplete() 167 Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) 168 io.ReadAll(str) // wait for the EOF from the server to arrive before closing the conn 169 conn.CloseWithError(0, "") 170 Eventually(done).Should(BeClosed()) 171 Eventually(conn.Context().Done()).Should(BeClosed()) 172 } 173 174 check0RTTRejected := func( 175 ln *quic.EarlyListener, 176 proxyPort int, 177 clientConf *tls.Config, 178 ) { 179 conn, err := quic.DialAddrEarly( 180 context.Background(), 181 fmt.Sprintf("localhost:%d", proxyPort), 182 clientConf, 183 getQuicConfig(nil), 184 ) 185 Expect(err).ToNot(HaveOccurred()) 186 str, err := conn.OpenUniStream() 187 Expect(err).ToNot(HaveOccurred()) 188 _, err = str.Write(make([]byte, 3000)) 189 Expect(err).ToNot(HaveOccurred()) 190 Expect(str.Close()).To(Succeed()) 191 Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) 192 193 // make sure the server doesn't process the data 194 ctx, cancel := context.WithTimeout(context.Background(), scaleDuration(50*time.Millisecond)) 195 defer cancel() 196 serverConn, err := ln.Accept(ctx) 197 Expect(err).ToNot(HaveOccurred()) 198 Expect(serverConn.ConnectionState().Used0RTT).To(BeFalse()) 199 _, err = serverConn.AcceptUniStream(ctx) 200 Expect(err).To(Equal(context.DeadlineExceeded)) 201 Expect(serverConn.CloseWithError(0, "")).To(Succeed()) 202 Eventually(conn.Context().Done()).Should(BeClosed()) 203 } 204 205 // can be used to extract 0-RTT from a packetTracer 206 get0RTTPackets := func(packets []packet) []protocol.PacketNumber { 207 var zeroRTTPackets []protocol.PacketNumber 208 for _, p := range packets { 209 if p.hdr.Type == protocol.PacketType0RTT { 210 zeroRTTPackets = append(zeroRTTPackets, p.hdr.PacketNumber) 211 } 212 } 213 return zeroRTTPackets 214 } 215 216 for _, l := range []int{0, 15} { 217 connIDLen := l 218 219 It(fmt.Sprintf("transfers 0-RTT data, with %d byte connection IDs", connIDLen), func() { 220 tlsConf, clientTLSConf := dialAndReceiveSessionTicket(nil) 221 222 tracer := newPacketTracer() 223 ln, err := quic.ListenAddrEarly( 224 "localhost:0", 225 tlsConf, 226 getQuicConfig(&quic.Config{ 227 Allow0RTT: true, 228 Tracer: newTracer(tracer), 229 }), 230 ) 231 Expect(err).ToNot(HaveOccurred()) 232 defer ln.Close() 233 234 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 235 defer proxy.Close() 236 237 transfer0RTTData( 238 ln, 239 proxy.LocalPort(), 240 connIDLen, 241 clientTLSConf, 242 getQuicConfig(nil), 243 PRData, 244 ) 245 246 var numNewConnIDs int 247 for _, p := range tracer.getRcvdLongHeaderPackets() { 248 for _, f := range p.frames { 249 if _, ok := f.(*logging.NewConnectionIDFrame); ok { 250 numNewConnIDs++ 251 } 252 } 253 } 254 if connIDLen == 0 { 255 Expect(numNewConnIDs).To(BeZero()) 256 } else { 257 Expect(numNewConnIDs).ToNot(BeZero()) 258 } 259 260 num0RTT := atomic.LoadUint32(num0RTTPackets) 261 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 262 Expect(num0RTT).ToNot(BeZero()) 263 zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets()) 264 Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10)) 265 Expect(zeroRTTPackets).To(ContainElement(protocol.PacketNumber(0))) 266 }) 267 } 268 269 // Test that data intended to be sent with 1-RTT protection is not sent in 0-RTT packets. 270 It("waits for a connection until the handshake is done", func() { 271 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 272 273 zeroRTTData := GeneratePRData(5 << 10) 274 oneRTTData := PRData 275 276 tracer := newPacketTracer() 277 ln, err := quic.ListenAddrEarly( 278 "localhost:0", 279 tlsConf, 280 getQuicConfig(&quic.Config{ 281 Allow0RTT: true, 282 Tracer: newTracer(tracer), 283 }), 284 ) 285 Expect(err).ToNot(HaveOccurred()) 286 defer ln.Close() 287 288 // now accept the second connection, and receive the 0-RTT data 289 go func() { 290 defer GinkgoRecover() 291 conn, err := ln.Accept(context.Background()) 292 Expect(err).ToNot(HaveOccurred()) 293 str, err := conn.AcceptUniStream(context.Background()) 294 Expect(err).ToNot(HaveOccurred()) 295 data, err := io.ReadAll(str) 296 Expect(err).ToNot(HaveOccurred()) 297 Expect(data).To(Equal(zeroRTTData)) 298 str, err = conn.AcceptUniStream(context.Background()) 299 Expect(err).ToNot(HaveOccurred()) 300 data, err = io.ReadAll(str) 301 Expect(err).ToNot(HaveOccurred()) 302 Expect(data).To(Equal(oneRTTData)) 303 Expect(conn.CloseWithError(0, "")).To(Succeed()) 304 }() 305 306 proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 307 defer proxy.Close() 308 309 conn, err := quic.DialAddrEarly( 310 context.Background(), 311 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 312 clientConf, 313 getQuicConfig(nil), 314 ) 315 Expect(err).ToNot(HaveOccurred()) 316 firstStr, err := conn.OpenUniStream() 317 Expect(err).ToNot(HaveOccurred()) 318 _, err = firstStr.Write(zeroRTTData) 319 Expect(err).ToNot(HaveOccurred()) 320 Expect(firstStr.Close()).To(Succeed()) 321 322 // wait for the handshake to complete 323 Eventually(conn.HandshakeComplete()).Should(BeClosed()) 324 str, err := conn.OpenUniStream() 325 Expect(err).ToNot(HaveOccurred()) 326 _, err = str.Write(PRData) 327 Expect(err).ToNot(HaveOccurred()) 328 Expect(str.Close()).To(Succeed()) 329 <-conn.Context().Done() 330 331 // check that 0-RTT packets only contain STREAM frames for the first stream 332 var num0RTT int 333 for _, p := range tracer.getRcvdLongHeaderPackets() { 334 if p.hdr.Header.Type != protocol.PacketType0RTT { 335 continue 336 } 337 for _, f := range p.frames { 338 sf, ok := f.(*logging.StreamFrame) 339 if !ok { 340 continue 341 } 342 num0RTT++ 343 Expect(sf.StreamID).To(Equal(firstStr.StreamID())) 344 } 345 } 346 fmt.Fprintf(GinkgoWriter, "received %d STREAM frames in 0-RTT packets\n", num0RTT) 347 Expect(num0RTT).ToNot(BeZero()) 348 }) 349 350 It("transfers 0-RTT data, when 0-RTT packets are lost", func() { 351 var ( 352 num0RTTPackets uint32 // to be used as an atomic 353 num0RTTDropped uint32 354 ) 355 356 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 357 358 tracer := newPacketTracer() 359 ln, err := quic.ListenAddrEarly( 360 "localhost:0", 361 tlsConf, 362 getQuicConfig(&quic.Config{ 363 Allow0RTT: true, 364 Tracer: newTracer(tracer), 365 }), 366 ) 367 Expect(err).ToNot(HaveOccurred()) 368 defer ln.Close() 369 370 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 371 RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 372 DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration { 373 if wire.IsLongHeaderPacket(data[0]) { 374 hdr, _, _, err := wire.ParsePacket(data) 375 Expect(err).ToNot(HaveOccurred()) 376 if hdr.Type == protocol.PacketType0RTT { 377 atomic.AddUint32(&num0RTTPackets, 1) 378 } 379 } 380 return rtt / 2 381 }, 382 DropPacket: func(_ quicproxy.Direction, data []byte) bool { 383 if !wire.IsLongHeaderPacket(data[0]) { 384 return false 385 } 386 hdr, _, _, err := wire.ParsePacket(data) 387 Expect(err).ToNot(HaveOccurred()) 388 if hdr.Type == protocol.PacketType0RTT { 389 // drop 25% of the 0-RTT packets 390 drop := mrand.Intn(4) == 0 391 if drop { 392 atomic.AddUint32(&num0RTTDropped, 1) 393 } 394 return drop 395 } 396 return false 397 }, 398 }) 399 Expect(err).ToNot(HaveOccurred()) 400 defer proxy.Close() 401 402 transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, PRData) 403 404 num0RTT := atomic.LoadUint32(&num0RTTPackets) 405 numDropped := atomic.LoadUint32(&num0RTTDropped) 406 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets. Dropped %d of those.", num0RTT, numDropped) 407 Expect(numDropped).ToNot(BeZero()) 408 Expect(num0RTT).ToNot(BeZero()) 409 Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).ToNot(BeEmpty()) 410 }) 411 412 It("retransmits all 0-RTT data when the server performs a Retry", func() { 413 var mutex sync.Mutex 414 var firstConnID, secondConnID *protocol.ConnectionID 415 var firstCounter, secondCounter protocol.ByteCount 416 417 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 418 419 countZeroRTTBytes := func(data []byte) (n protocol.ByteCount) { 420 for len(data) > 0 { 421 hdr, _, rest, err := wire.ParsePacket(data) 422 if err != nil { 423 return 424 } 425 data = rest 426 if hdr.Type == protocol.PacketType0RTT { 427 n += hdr.Length - 16 /* AEAD tag */ 428 } 429 } 430 return 431 } 432 433 tracer := newPacketTracer() 434 ln, err := quic.ListenAddrEarly( 435 "localhost:0", 436 tlsConf, 437 getQuicConfig(&quic.Config{ 438 RequireAddressValidation: func(net.Addr) bool { return true }, 439 Allow0RTT: true, 440 Tracer: newTracer(tracer), 441 }), 442 ) 443 Expect(err).ToNot(HaveOccurred()) 444 defer ln.Close() 445 446 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 447 RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 448 DelayPacket: func(dir quicproxy.Direction, data []byte) time.Duration { 449 connID, err := wire.ParseConnectionID(data, 0) 450 Expect(err).ToNot(HaveOccurred()) 451 452 mutex.Lock() 453 defer mutex.Unlock() 454 455 if zeroRTTBytes := countZeroRTTBytes(data); zeroRTTBytes > 0 { 456 if firstConnID == nil { 457 firstConnID = &connID 458 firstCounter += zeroRTTBytes 459 } else if firstConnID != nil && *firstConnID == connID { 460 Expect(secondConnID).To(BeNil()) 461 firstCounter += zeroRTTBytes 462 } else if secondConnID == nil { 463 secondConnID = &connID 464 secondCounter += zeroRTTBytes 465 } else if secondConnID != nil && *secondConnID == connID { 466 secondCounter += zeroRTTBytes 467 } else { 468 Fail("received 3 connection IDs on 0-RTT packets") 469 } 470 } 471 return rtt / 2 472 }, 473 }) 474 Expect(err).ToNot(HaveOccurred()) 475 defer proxy.Close() 476 477 transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, GeneratePRData(5000)) // ~5 packets 478 479 mutex.Lock() 480 defer mutex.Unlock() 481 Expect(firstCounter).To(BeNumerically("~", 5000+100 /* framing overhead */, 100)) // the FIN bit might be sent extra 482 Expect(secondCounter).To(BeNumerically("~", firstCounter, 20)) 483 zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets()) 484 Expect(len(zeroRTTPackets)).To(BeNumerically(">=", 5)) 485 Expect(zeroRTTPackets[0]).To(BeNumerically(">=", protocol.PacketNumber(5))) 486 }) 487 488 It("doesn't reject 0-RTT when the server's transport stream limit increased", func() { 489 const maxStreams = 1 490 tlsConf, clientConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ 491 MaxIncomingUniStreams: maxStreams, 492 })) 493 494 tracer := newPacketTracer() 495 ln, err := quic.ListenAddrEarly( 496 "localhost:0", 497 tlsConf, 498 getQuicConfig(&quic.Config{ 499 MaxIncomingUniStreams: maxStreams + 1, 500 Allow0RTT: true, 501 Tracer: newTracer(tracer), 502 }), 503 ) 504 Expect(err).ToNot(HaveOccurred()) 505 defer ln.Close() 506 proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 507 defer proxy.Close() 508 509 conn, err := quic.DialAddrEarly( 510 context.Background(), 511 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 512 clientConf, 513 getQuicConfig(nil), 514 ) 515 Expect(err).ToNot(HaveOccurred()) 516 str, err := conn.OpenUniStream() 517 Expect(err).ToNot(HaveOccurred()) 518 _, err = str.Write([]byte("foobar")) 519 Expect(err).ToNot(HaveOccurred()) 520 Expect(str.Close()).To(Succeed()) 521 // The client remembers the old limit and refuses to open a new stream. 522 _, err = conn.OpenUniStream() 523 Expect(err).To(HaveOccurred()) 524 Expect(err.Error()).To(ContainSubstring("too many open streams")) 525 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 526 defer cancel() 527 _, err = conn.OpenUniStreamSync(ctx) 528 Expect(err).ToNot(HaveOccurred()) 529 Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) 530 Expect(conn.CloseWithError(0, "")).To(Succeed()) 531 }) 532 533 It("rejects 0-RTT when the server's stream limit decreased", func() { 534 const maxStreams = 42 535 tlsConf, clientConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ 536 MaxIncomingStreams: maxStreams, 537 })) 538 539 tracer := newPacketTracer() 540 ln, err := quic.ListenAddrEarly( 541 "localhost:0", 542 tlsConf, 543 getQuicConfig(&quic.Config{ 544 MaxIncomingStreams: maxStreams - 1, 545 Allow0RTT: true, 546 Tracer: newTracer(tracer), 547 }), 548 ) 549 Expect(err).ToNot(HaveOccurred()) 550 defer ln.Close() 551 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 552 defer proxy.Close() 553 check0RTTRejected(ln, proxy.LocalPort(), clientConf) 554 555 // The client should send 0-RTT packets, but the server doesn't process them. 556 num0RTT := atomic.LoadUint32(num0RTTPackets) 557 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 558 Expect(num0RTT).ToNot(BeZero()) 559 Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty()) 560 }) 561 562 It("rejects 0-RTT when the ALPN changed", func() { 563 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 564 565 // now close the listener and dial new connection with a different ALPN 566 clientConf.NextProtos = []string{"new-alpn"} 567 tlsConf.NextProtos = []string{"new-alpn"} 568 tracer := newPacketTracer() 569 ln, err := quic.ListenAddrEarly( 570 "localhost:0", 571 tlsConf, 572 getQuicConfig(&quic.Config{ 573 Allow0RTT: true, 574 Tracer: newTracer(tracer), 575 }), 576 ) 577 Expect(err).ToNot(HaveOccurred()) 578 defer ln.Close() 579 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 580 defer proxy.Close() 581 582 check0RTTRejected(ln, proxy.LocalPort(), clientConf) 583 584 // The client should send 0-RTT packets, but the server doesn't process them. 585 num0RTT := atomic.LoadUint32(num0RTTPackets) 586 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 587 Expect(num0RTT).ToNot(BeZero()) 588 Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty()) 589 }) 590 591 It("rejects 0-RTT when the application doesn't allow it", func() { 592 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 593 594 // now close the listener and dial new connection with a different ALPN 595 tracer := newPacketTracer() 596 ln, err := quic.ListenAddrEarly( 597 "localhost:0", 598 tlsConf, 599 getQuicConfig(&quic.Config{ 600 Allow0RTT: false, // application rejects 0-RTT 601 Tracer: newTracer(tracer), 602 }), 603 ) 604 Expect(err).ToNot(HaveOccurred()) 605 defer ln.Close() 606 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 607 defer proxy.Close() 608 609 check0RTTRejected(ln, proxy.LocalPort(), clientConf) 610 611 // The client should send 0-RTT packets, but the server doesn't process them. 612 num0RTT := atomic.LoadUint32(num0RTTPackets) 613 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 614 Expect(num0RTT).ToNot(BeZero()) 615 Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty()) 616 }) 617 618 DescribeTable("flow control limits", 619 func(addFlowControlLimit func(*quic.Config, uint64)) { 620 tracer := newPacketTracer() 621 firstConf := getQuicConfig(&quic.Config{Allow0RTT: true}) 622 addFlowControlLimit(firstConf, 3) 623 tlsConf, clientConf := dialAndReceiveSessionTicket(firstConf) 624 625 secondConf := getQuicConfig(&quic.Config{ 626 Allow0RTT: true, 627 Tracer: newTracer(tracer), 628 }) 629 addFlowControlLimit(secondConf, 100) 630 ln, err := quic.ListenAddrEarly( 631 "localhost:0", 632 tlsConf, 633 secondConf, 634 ) 635 Expect(err).ToNot(HaveOccurred()) 636 defer ln.Close() 637 proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 638 defer proxy.Close() 639 640 conn, err := quic.DialAddrEarly( 641 context.Background(), 642 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 643 clientConf, 644 getQuicConfig(nil), 645 ) 646 Expect(err).ToNot(HaveOccurred()) 647 str, err := conn.OpenUniStream() 648 Expect(err).ToNot(HaveOccurred()) 649 written := make(chan struct{}) 650 go func() { 651 defer GinkgoRecover() 652 defer close(written) 653 _, err := str.Write([]byte("foobar")) 654 Expect(err).ToNot(HaveOccurred()) 655 Expect(str.Close()).To(Succeed()) 656 }() 657 658 Eventually(written).Should(BeClosed()) 659 660 serverConn, err := ln.Accept(context.Background()) 661 Expect(err).ToNot(HaveOccurred()) 662 rstr, err := serverConn.AcceptUniStream(context.Background()) 663 Expect(err).ToNot(HaveOccurred()) 664 data, err := io.ReadAll(rstr) 665 Expect(err).ToNot(HaveOccurred()) 666 Expect(data).To(Equal([]byte("foobar"))) 667 Expect(serverConn.ConnectionState().Used0RTT).To(BeTrue()) 668 Expect(serverConn.CloseWithError(0, "")).To(Succeed()) 669 Eventually(conn.Context().Done()).Should(BeClosed()) 670 671 var processedFirst bool 672 for _, p := range tracer.getRcvdLongHeaderPackets() { 673 for _, f := range p.frames { 674 if sf, ok := f.(*logging.StreamFrame); ok { 675 if !processedFirst { 676 // The first STREAM should have been sent in a 0-RTT packet. 677 // Due to the flow control limit, the STREAM frame was limit to the first 3 bytes. 678 Expect(p.hdr.Type).To(Equal(protocol.PacketType0RTT)) 679 Expect(sf.Length).To(BeEquivalentTo(3)) 680 processedFirst = true 681 } else { 682 Fail("STREAM was shouldn't have been sent in 0-RTT") 683 } 684 } 685 } 686 } 687 }, 688 Entry("doesn't reject 0-RTT when the server's transport stream flow control limit increased", func(c *quic.Config, limit uint64) { c.InitialStreamReceiveWindow = limit }), 689 Entry("doesn't reject 0-RTT when the server's transport connection flow control limit increased", func(c *quic.Config, limit uint64) { c.InitialConnectionReceiveWindow = limit }), 690 ) 691 692 for _, l := range []int{0, 15} { 693 connIDLen := l 694 695 It(fmt.Sprintf("correctly deals with 0-RTT rejections, for %d byte connection IDs", connIDLen), func() { 696 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 697 // now dial new connection with different transport parameters 698 tracer := newPacketTracer() 699 ln, err := quic.ListenAddrEarly( 700 "localhost:0", 701 tlsConf, 702 getQuicConfig(&quic.Config{ 703 MaxIncomingUniStreams: 1, 704 Tracer: newTracer(tracer), 705 }), 706 ) 707 Expect(err).ToNot(HaveOccurred()) 708 defer ln.Close() 709 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 710 defer proxy.Close() 711 712 conn, err := quic.DialAddrEarly( 713 context.Background(), 714 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 715 clientConf, 716 getQuicConfig(nil), 717 ) 718 Expect(err).ToNot(HaveOccurred()) 719 // The client remembers that it was allowed to open 2 uni-directional streams. 720 firstStr, err := conn.OpenUniStream() 721 Expect(err).ToNot(HaveOccurred()) 722 written := make(chan struct{}, 2) 723 go func() { 724 defer GinkgoRecover() 725 defer func() { written <- struct{}{} }() 726 _, err := firstStr.Write([]byte("first flight")) 727 Expect(err).ToNot(HaveOccurred()) 728 }() 729 secondStr, err := conn.OpenUniStream() 730 Expect(err).ToNot(HaveOccurred()) 731 go func() { 732 defer GinkgoRecover() 733 defer func() { written <- struct{}{} }() 734 _, err := secondStr.Write([]byte("first flight")) 735 Expect(err).ToNot(HaveOccurred()) 736 }() 737 738 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 739 defer cancel() 740 _, err = conn.AcceptStream(ctx) 741 Expect(err).To(MatchError(quic.Err0RTTRejected)) 742 Eventually(written).Should(Receive()) 743 Eventually(written).Should(Receive()) 744 _, err = firstStr.Write([]byte("foobar")) 745 Expect(err).To(MatchError(quic.Err0RTTRejected)) 746 _, err = conn.OpenUniStream() 747 Expect(err).To(MatchError(quic.Err0RTTRejected)) 748 749 _, err = conn.AcceptStream(ctx) 750 Expect(err).To(Equal(quic.Err0RTTRejected)) 751 752 newConn := conn.NextConnection() 753 str, err := newConn.OpenUniStream() 754 Expect(err).ToNot(HaveOccurred()) 755 _, err = newConn.OpenUniStream() 756 Expect(err).To(HaveOccurred()) 757 Expect(err.Error()).To(ContainSubstring("too many open streams")) 758 _, err = str.Write([]byte("second flight")) 759 Expect(err).ToNot(HaveOccurred()) 760 Expect(str.Close()).To(Succeed()) 761 Expect(conn.CloseWithError(0, "")).To(Succeed()) 762 763 // The client should send 0-RTT packets, but the server doesn't process them. 764 num0RTT := atomic.LoadUint32(num0RTTPackets) 765 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 766 Expect(num0RTT).ToNot(BeZero()) 767 Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty()) 768 }) 769 } 770 771 It("queues 0-RTT packets, if the Initial is delayed", func() { 772 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 773 774 tracer := newPacketTracer() 775 ln, err := quic.ListenAddrEarly( 776 "localhost:0", 777 tlsConf, 778 getQuicConfig(&quic.Config{ 779 Allow0RTT: true, 780 Tracer: newTracer(tracer), 781 }), 782 ) 783 Expect(err).ToNot(HaveOccurred()) 784 defer ln.Close() 785 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 786 RemoteAddr: ln.Addr().String(), 787 DelayPacket: func(dir quicproxy.Direction, data []byte) time.Duration { 788 if dir == quicproxy.DirectionIncoming && wire.IsLongHeaderPacket(data[0]) && data[0]&0x30>>4 == 0 { // Initial packet from client 789 return rtt/2 + rtt 790 } 791 return rtt / 2 792 }, 793 }) 794 Expect(err).ToNot(HaveOccurred()) 795 defer proxy.Close() 796 797 transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, PRData) 798 799 Expect(tracer.getRcvdLongHeaderPackets()[0].hdr.Type).To(Equal(protocol.PacketTypeInitial)) 800 zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets()) 801 Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10)) 802 Expect(zeroRTTPackets[0]).To(Equal(protocol.PacketNumber(0))) 803 }) 804 })