github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/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/metacubex/quic-go" 17 quicproxy "github.com/metacubex/quic-go/integrationtests/tools/proxy" 18 "github.com/metacubex/quic-go/internal/protocol" 19 "github.com/metacubex/quic-go/internal/wire" 20 "github.com/metacubex/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, *atomic.Uint32) { 30 var num0RTTPackets atomic.Uint32 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 num0RTTPackets.Add(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 packetCounter 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 counter, 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 counter.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 := num0RTTPackets.Load() 261 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 262 Expect(num0RTT).ToNot(BeZero()) 263 zeroRTTPackets := get0RTTPackets(counter.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 counter, 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 counter.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 num0RTTPackets, num0RTTDropped atomic.Uint32 352 353 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 354 355 counter, tracer := newPacketTracer() 356 ln, err := quic.ListenAddrEarly( 357 "localhost:0", 358 tlsConf, 359 getQuicConfig(&quic.Config{ 360 Allow0RTT: true, 361 Tracer: newTracer(tracer), 362 }), 363 ) 364 Expect(err).ToNot(HaveOccurred()) 365 defer ln.Close() 366 367 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 368 RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 369 DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration { 370 if wire.IsLongHeaderPacket(data[0]) { 371 hdr, _, _, err := wire.ParsePacket(data) 372 Expect(err).ToNot(HaveOccurred()) 373 if hdr.Type == protocol.PacketType0RTT { 374 num0RTTPackets.Add(1) 375 } 376 } 377 return rtt / 2 378 }, 379 DropPacket: func(_ quicproxy.Direction, data []byte) bool { 380 if !wire.IsLongHeaderPacket(data[0]) { 381 return false 382 } 383 hdr, _, _, err := wire.ParsePacket(data) 384 Expect(err).ToNot(HaveOccurred()) 385 if hdr.Type == protocol.PacketType0RTT { 386 // drop 25% of the 0-RTT packets 387 drop := mrand.Intn(4) == 0 388 if drop { 389 num0RTTDropped.Add(1) 390 } 391 return drop 392 } 393 return false 394 }, 395 }) 396 Expect(err).ToNot(HaveOccurred()) 397 defer proxy.Close() 398 399 transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, PRData) 400 401 num0RTT := num0RTTPackets.Load() 402 numDropped := num0RTTDropped.Load() 403 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets. Dropped %d of those.", num0RTT, numDropped) 404 Expect(numDropped).ToNot(BeZero()) 405 Expect(num0RTT).ToNot(BeZero()) 406 Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).ToNot(BeEmpty()) 407 }) 408 409 It("retransmits all 0-RTT data when the server performs a Retry", func() { 410 var mutex sync.Mutex 411 var firstConnID, secondConnID *protocol.ConnectionID 412 var firstCounter, secondCounter protocol.ByteCount 413 414 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 415 416 countZeroRTTBytes := func(data []byte) (n protocol.ByteCount) { 417 for len(data) > 0 { 418 hdr, _, rest, err := wire.ParsePacket(data) 419 if err != nil { 420 return 421 } 422 data = rest 423 if hdr.Type == protocol.PacketType0RTT { 424 n += hdr.Length - 16 /* AEAD tag */ 425 } 426 } 427 return 428 } 429 430 counter, tracer := newPacketTracer() 431 ln, err := quic.ListenAddrEarly( 432 "localhost:0", 433 tlsConf, 434 getQuicConfig(&quic.Config{ 435 RequireAddressValidation: func(net.Addr) bool { return true }, 436 Allow0RTT: true, 437 Tracer: newTracer(tracer), 438 }), 439 ) 440 Expect(err).ToNot(HaveOccurred()) 441 defer ln.Close() 442 443 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 444 RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 445 DelayPacket: func(dir quicproxy.Direction, data []byte) time.Duration { 446 connID, err := wire.ParseConnectionID(data, 0) 447 Expect(err).ToNot(HaveOccurred()) 448 449 mutex.Lock() 450 defer mutex.Unlock() 451 452 if zeroRTTBytes := countZeroRTTBytes(data); zeroRTTBytes > 0 { 453 if firstConnID == nil { 454 firstConnID = &connID 455 firstCounter += zeroRTTBytes 456 } else if firstConnID != nil && *firstConnID == connID { 457 Expect(secondConnID).To(BeNil()) 458 firstCounter += zeroRTTBytes 459 } else if secondConnID == nil { 460 secondConnID = &connID 461 secondCounter += zeroRTTBytes 462 } else if secondConnID != nil && *secondConnID == connID { 463 secondCounter += zeroRTTBytes 464 } else { 465 Fail("received 3 connection IDs on 0-RTT packets") 466 } 467 } 468 return rtt / 2 469 }, 470 }) 471 Expect(err).ToNot(HaveOccurred()) 472 defer proxy.Close() 473 474 transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, GeneratePRData(5000)) // ~5 packets 475 476 mutex.Lock() 477 defer mutex.Unlock() 478 Expect(firstCounter).To(BeNumerically("~", 5000+100 /* framing overhead */, 100)) // the FIN bit might be sent extra 479 Expect(secondCounter).To(BeNumerically("~", firstCounter, 20)) 480 zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets()) 481 Expect(len(zeroRTTPackets)).To(BeNumerically(">=", 5)) 482 Expect(zeroRTTPackets[0]).To(BeNumerically(">=", protocol.PacketNumber(5))) 483 }) 484 485 It("doesn't use 0-RTT when Dial is used for the resumed connection", func() { 486 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 487 488 ln, err := quic.ListenAddrEarly( 489 "localhost:0", 490 tlsConf, 491 getQuicConfig(&quic.Config{Allow0RTT: true}), 492 ) 493 Expect(err).ToNot(HaveOccurred()) 494 defer ln.Close() 495 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 496 defer proxy.Close() 497 498 conn, err := quic.DialAddr( 499 context.Background(), 500 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 501 clientConf, 502 getQuicConfig(nil), 503 ) 504 Expect(err).ToNot(HaveOccurred()) 505 defer conn.CloseWithError(0, "") 506 Expect(conn.ConnectionState().TLS.DidResume).To(BeTrue()) 507 Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) 508 Expect(num0RTTPackets.Load()).To(BeZero()) 509 510 serverConn, err := ln.Accept(context.Background()) 511 Expect(err).ToNot(HaveOccurred()) 512 Expect(serverConn.ConnectionState().TLS.DidResume).To(BeTrue()) 513 Expect(serverConn.ConnectionState().Used0RTT).To(BeFalse()) 514 }) 515 516 It("doesn't reject 0-RTT when the server's transport stream limit increased", func() { 517 const maxStreams = 1 518 tlsConf, clientConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ 519 MaxIncomingUniStreams: maxStreams, 520 })) 521 522 ln, err := quic.ListenAddrEarly( 523 "localhost:0", 524 tlsConf, 525 getQuicConfig(&quic.Config{ 526 MaxIncomingUniStreams: maxStreams + 1, 527 Allow0RTT: true, 528 }), 529 ) 530 Expect(err).ToNot(HaveOccurred()) 531 defer ln.Close() 532 proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 533 defer proxy.Close() 534 535 conn, err := quic.DialAddrEarly( 536 context.Background(), 537 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 538 clientConf, 539 getQuicConfig(nil), 540 ) 541 Expect(err).ToNot(HaveOccurred()) 542 str, err := conn.OpenUniStream() 543 Expect(err).ToNot(HaveOccurred()) 544 _, err = str.Write([]byte("foobar")) 545 Expect(err).ToNot(HaveOccurred()) 546 Expect(str.Close()).To(Succeed()) 547 // The client remembers the old limit and refuses to open a new stream. 548 _, err = conn.OpenUniStream() 549 Expect(err).To(HaveOccurred()) 550 Expect(err.Error()).To(ContainSubstring("too many open streams")) 551 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 552 defer cancel() 553 _, err = conn.OpenUniStreamSync(ctx) 554 Expect(err).ToNot(HaveOccurred()) 555 Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) 556 Expect(conn.CloseWithError(0, "")).To(Succeed()) 557 }) 558 559 It("rejects 0-RTT when the server's stream limit decreased", func() { 560 const maxStreams = 42 561 tlsConf, clientConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ 562 MaxIncomingStreams: maxStreams, 563 })) 564 565 counter, tracer := newPacketTracer() 566 ln, err := quic.ListenAddrEarly( 567 "localhost:0", 568 tlsConf, 569 getQuicConfig(&quic.Config{ 570 MaxIncomingStreams: maxStreams - 1, 571 Allow0RTT: true, 572 Tracer: newTracer(tracer), 573 }), 574 ) 575 Expect(err).ToNot(HaveOccurred()) 576 defer ln.Close() 577 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 578 defer proxy.Close() 579 check0RTTRejected(ln, proxy.LocalPort(), clientConf) 580 581 // The client should send 0-RTT packets, but the server doesn't process them. 582 num0RTT := num0RTTPackets.Load() 583 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 584 Expect(num0RTT).ToNot(BeZero()) 585 Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty()) 586 }) 587 588 It("rejects 0-RTT when the ALPN changed", func() { 589 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 590 591 // now close the listener and dial new connection with a different ALPN 592 clientConf.NextProtos = []string{"new-alpn"} 593 tlsConf.NextProtos = []string{"new-alpn"} 594 counter, tracer := newPacketTracer() 595 ln, err := quic.ListenAddrEarly( 596 "localhost:0", 597 tlsConf, 598 getQuicConfig(&quic.Config{ 599 Allow0RTT: true, 600 Tracer: newTracer(tracer), 601 }), 602 ) 603 Expect(err).ToNot(HaveOccurred()) 604 defer ln.Close() 605 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 606 defer proxy.Close() 607 608 check0RTTRejected(ln, proxy.LocalPort(), clientConf) 609 610 // The client should send 0-RTT packets, but the server doesn't process them. 611 num0RTT := num0RTTPackets.Load() 612 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 613 Expect(num0RTT).ToNot(BeZero()) 614 Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty()) 615 }) 616 617 It("rejects 0-RTT when the application doesn't allow it", func() { 618 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 619 620 // now close the listener and dial new connection with a different ALPN 621 counter, tracer := newPacketTracer() 622 ln, err := quic.ListenAddrEarly( 623 "localhost:0", 624 tlsConf, 625 getQuicConfig(&quic.Config{ 626 Allow0RTT: false, // application rejects 0-RTT 627 Tracer: newTracer(tracer), 628 }), 629 ) 630 Expect(err).ToNot(HaveOccurred()) 631 defer ln.Close() 632 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 633 defer proxy.Close() 634 635 check0RTTRejected(ln, proxy.LocalPort(), clientConf) 636 637 // The client should send 0-RTT packets, but the server doesn't process them. 638 num0RTT := num0RTTPackets.Load() 639 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 640 Expect(num0RTT).ToNot(BeZero()) 641 Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty()) 642 }) 643 644 It("doesn't use 0-RTT, if the server didn't enable it", func() { 645 server, err := quic.ListenAddr("localhost:0", getTLSConfig(), getQuicConfig(nil)) 646 Expect(err).ToNot(HaveOccurred()) 647 defer server.Close() 648 649 gets := make(chan string, 100) 650 puts := make(chan string, 100) 651 cache := newClientSessionCache(tls.NewLRUClientSessionCache(10), gets, puts) 652 tlsConf := getTLSClientConfig() 653 tlsConf.ClientSessionCache = cache 654 conn1, err := quic.DialAddr( 655 context.Background(), 656 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 657 tlsConf, 658 getQuicConfig(nil), 659 ) 660 Expect(err).ToNot(HaveOccurred()) 661 defer conn1.CloseWithError(0, "") 662 var sessionKey string 663 Eventually(puts).Should(Receive(&sessionKey)) 664 Expect(conn1.ConnectionState().TLS.DidResume).To(BeFalse()) 665 666 serverConn, err := server.Accept(context.Background()) 667 Expect(err).ToNot(HaveOccurred()) 668 Expect(serverConn.ConnectionState().TLS.DidResume).To(BeFalse()) 669 670 conn2, err := quic.DialAddrEarly( 671 context.Background(), 672 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 673 tlsConf, 674 getQuicConfig(nil), 675 ) 676 Expect(err).ToNot(HaveOccurred()) 677 Expect(gets).To(Receive(Equal(sessionKey))) 678 Expect(conn2.ConnectionState().TLS.DidResume).To(BeTrue()) 679 680 serverConn, err = server.Accept(context.Background()) 681 Expect(err).ToNot(HaveOccurred()) 682 Expect(serverConn.ConnectionState().TLS.DidResume).To(BeTrue()) 683 Expect(serverConn.ConnectionState().Used0RTT).To(BeFalse()) 684 conn2.CloseWithError(0, "") 685 }) 686 687 DescribeTable("flow control limits", 688 func(addFlowControlLimit func(*quic.Config, uint64)) { 689 counter, tracer := newPacketTracer() 690 firstConf := getQuicConfig(&quic.Config{Allow0RTT: true}) 691 addFlowControlLimit(firstConf, 3) 692 tlsConf, clientConf := dialAndReceiveSessionTicket(firstConf) 693 694 secondConf := getQuicConfig(&quic.Config{ 695 Allow0RTT: true, 696 Tracer: newTracer(tracer), 697 }) 698 addFlowControlLimit(secondConf, 100) 699 ln, err := quic.ListenAddrEarly( 700 "localhost:0", 701 tlsConf, 702 secondConf, 703 ) 704 Expect(err).ToNot(HaveOccurred()) 705 defer ln.Close() 706 proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 707 defer proxy.Close() 708 709 conn, err := quic.DialAddrEarly( 710 context.Background(), 711 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 712 clientConf, 713 getQuicConfig(nil), 714 ) 715 Expect(err).ToNot(HaveOccurred()) 716 str, err := conn.OpenUniStream() 717 Expect(err).ToNot(HaveOccurred()) 718 written := make(chan struct{}) 719 go func() { 720 defer GinkgoRecover() 721 defer close(written) 722 _, err := str.Write([]byte("foobar")) 723 Expect(err).ToNot(HaveOccurred()) 724 Expect(str.Close()).To(Succeed()) 725 }() 726 727 Eventually(written).Should(BeClosed()) 728 729 serverConn, err := ln.Accept(context.Background()) 730 Expect(err).ToNot(HaveOccurred()) 731 rstr, err := serverConn.AcceptUniStream(context.Background()) 732 Expect(err).ToNot(HaveOccurred()) 733 data, err := io.ReadAll(rstr) 734 Expect(err).ToNot(HaveOccurred()) 735 Expect(data).To(Equal([]byte("foobar"))) 736 Expect(serverConn.ConnectionState().Used0RTT).To(BeTrue()) 737 Expect(serverConn.CloseWithError(0, "")).To(Succeed()) 738 Eventually(conn.Context().Done()).Should(BeClosed()) 739 740 var processedFirst bool 741 for _, p := range counter.getRcvdLongHeaderPackets() { 742 for _, f := range p.frames { 743 if sf, ok := f.(*logging.StreamFrame); ok { 744 if !processedFirst { 745 // The first STREAM should have been sent in a 0-RTT packet. 746 // Due to the flow control limit, the STREAM frame was limit to the first 3 bytes. 747 Expect(p.hdr.Type).To(Equal(protocol.PacketType0RTT)) 748 Expect(sf.Length).To(BeEquivalentTo(3)) 749 processedFirst = true 750 } else { 751 Fail("STREAM was shouldn't have been sent in 0-RTT") 752 } 753 } 754 } 755 } 756 }, 757 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 }), 758 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 }), 759 ) 760 761 for _, l := range []int{0, 15} { 762 connIDLen := l 763 764 It(fmt.Sprintf("correctly deals with 0-RTT rejections, for %d byte connection IDs", connIDLen), func() { 765 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 766 // now dial new connection with different transport parameters 767 counter, tracer := newPacketTracer() 768 ln, err := quic.ListenAddrEarly( 769 "localhost:0", 770 tlsConf, 771 getQuicConfig(&quic.Config{ 772 MaxIncomingUniStreams: 1, 773 Tracer: newTracer(tracer), 774 }), 775 ) 776 Expect(err).ToNot(HaveOccurred()) 777 defer ln.Close() 778 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 779 defer proxy.Close() 780 781 conn, err := quic.DialAddrEarly( 782 context.Background(), 783 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 784 clientConf, 785 getQuicConfig(nil), 786 ) 787 Expect(err).ToNot(HaveOccurred()) 788 // The client remembers that it was allowed to open 2 uni-directional streams. 789 firstStr, err := conn.OpenUniStream() 790 Expect(err).ToNot(HaveOccurred()) 791 written := make(chan struct{}, 2) 792 go func() { 793 defer GinkgoRecover() 794 defer func() { written <- struct{}{} }() 795 _, err := firstStr.Write([]byte("first flight")) 796 Expect(err).ToNot(HaveOccurred()) 797 }() 798 secondStr, err := conn.OpenUniStream() 799 Expect(err).ToNot(HaveOccurred()) 800 go func() { 801 defer GinkgoRecover() 802 defer func() { written <- struct{}{} }() 803 _, err := secondStr.Write([]byte("first flight")) 804 Expect(err).ToNot(HaveOccurred()) 805 }() 806 807 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 808 defer cancel() 809 _, err = conn.AcceptStream(ctx) 810 Expect(err).To(MatchError(quic.Err0RTTRejected)) 811 Eventually(written).Should(Receive()) 812 Eventually(written).Should(Receive()) 813 _, err = firstStr.Write([]byte("foobar")) 814 Expect(err).To(MatchError(quic.Err0RTTRejected)) 815 _, err = conn.OpenUniStream() 816 Expect(err).To(MatchError(quic.Err0RTTRejected)) 817 818 _, err = conn.AcceptStream(ctx) 819 Expect(err).To(Equal(quic.Err0RTTRejected)) 820 821 newConn := conn.NextConnection() 822 str, err := newConn.OpenUniStream() 823 Expect(err).ToNot(HaveOccurred()) 824 _, err = newConn.OpenUniStream() 825 Expect(err).To(HaveOccurred()) 826 Expect(err.Error()).To(ContainSubstring("too many open streams")) 827 _, err = str.Write([]byte("second flight")) 828 Expect(err).ToNot(HaveOccurred()) 829 Expect(str.Close()).To(Succeed()) 830 Expect(conn.CloseWithError(0, "")).To(Succeed()) 831 832 // The client should send 0-RTT packets, but the server doesn't process them. 833 num0RTT := num0RTTPackets.Load() 834 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 835 Expect(num0RTT).ToNot(BeZero()) 836 Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty()) 837 }) 838 } 839 840 It("queues 0-RTT packets, if the Initial is delayed", func() { 841 tlsConf, clientConf := dialAndReceiveSessionTicket(nil) 842 843 counter, tracer := newPacketTracer() 844 ln, err := quic.ListenAddrEarly( 845 "localhost:0", 846 tlsConf, 847 getQuicConfig(&quic.Config{ 848 Allow0RTT: true, 849 Tracer: newTracer(tracer), 850 }), 851 ) 852 Expect(err).ToNot(HaveOccurred()) 853 defer ln.Close() 854 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 855 RemoteAddr: ln.Addr().String(), 856 DelayPacket: func(dir quicproxy.Direction, data []byte) time.Duration { 857 if dir == quicproxy.DirectionIncoming && wire.IsLongHeaderPacket(data[0]) && data[0]&0x30>>4 == 0 { // Initial packet from client 858 return rtt/2 + rtt 859 } 860 return rtt / 2 861 }, 862 }) 863 Expect(err).ToNot(HaveOccurred()) 864 defer proxy.Close() 865 866 transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, PRData) 867 868 Expect(counter.getRcvdLongHeaderPackets()[0].hdr.Type).To(Equal(protocol.PacketTypeInitial)) 869 zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets()) 870 Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10)) 871 Expect(zeroRTTPackets[0]).To(Equal(protocol.PacketNumber(0))) 872 }) 873 874 It("sends 0-RTT datagrams", func() { 875 tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ 876 EnableDatagrams: true, 877 })) 878 879 counter, tracer := newPacketTracer() 880 ln, err := quic.ListenAddrEarly( 881 "localhost:0", 882 tlsConf, 883 getQuicConfig(&quic.Config{ 884 Allow0RTT: true, 885 EnableDatagrams: true, 886 Tracer: newTracer(tracer), 887 }), 888 ) 889 Expect(err).ToNot(HaveOccurred()) 890 defer ln.Close() 891 892 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 893 defer proxy.Close() 894 895 // second connection 896 sentMessage := GeneratePRData(100) 897 var receivedMessage []byte 898 received := make(chan struct{}) 899 go func() { 900 defer GinkgoRecover() 901 defer close(received) 902 conn, err := ln.Accept(context.Background()) 903 Expect(err).ToNot(HaveOccurred()) 904 receivedMessage, err = conn.ReceiveDatagram(context.Background()) 905 Expect(err).ToNot(HaveOccurred()) 906 Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) 907 }() 908 conn, err := quic.DialAddrEarly( 909 context.Background(), 910 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 911 clientTLSConf, 912 getQuicConfig(&quic.Config{ 913 EnableDatagrams: true, 914 }), 915 ) 916 Expect(err).ToNot(HaveOccurred()) 917 Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue()) 918 Expect(conn.SendDatagram(sentMessage)).To(Succeed()) 919 <-conn.HandshakeComplete() 920 <-received 921 922 Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) 923 Expect(receivedMessage).To(Equal(sentMessage)) 924 Expect(conn.CloseWithError(0, "")).To(Succeed()) 925 num0RTT := num0RTTPackets.Load() 926 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 927 Expect(num0RTT).ToNot(BeZero()) 928 zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets()) 929 Expect(zeroRTTPackets).To(HaveLen(1)) 930 }) 931 932 It("rejects 0-RTT datagrams when the server doesn't support datagrams anymore", func() { 933 tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ 934 EnableDatagrams: true, 935 })) 936 937 counter, tracer := newPacketTracer() 938 ln, err := quic.ListenAddrEarly( 939 "localhost:0", 940 tlsConf, 941 getQuicConfig(&quic.Config{ 942 Allow0RTT: true, 943 EnableDatagrams: false, 944 Tracer: newTracer(tracer), 945 }), 946 ) 947 Expect(err).ToNot(HaveOccurred()) 948 defer ln.Close() 949 950 proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) 951 defer proxy.Close() 952 953 // second connection 954 go func() { 955 defer GinkgoRecover() 956 conn, err := ln.Accept(context.Background()) 957 Expect(err).ToNot(HaveOccurred()) 958 _, err = conn.ReceiveDatagram(context.Background()) 959 Expect(err.Error()).To(Equal("datagram support disabled")) 960 <-conn.HandshakeComplete() 961 Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) 962 }() 963 conn, err := quic.DialAddrEarly( 964 context.Background(), 965 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 966 clientTLSConf, 967 getQuicConfig(&quic.Config{ 968 EnableDatagrams: true, 969 }), 970 ) 971 Expect(err).ToNot(HaveOccurred()) 972 // the client can temporarily send datagrams but the server doesn't process them. 973 Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue()) 974 Expect(conn.SendDatagram(make([]byte, 100))).To(Succeed()) 975 <-conn.HandshakeComplete() 976 977 Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse()) 978 Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) 979 Expect(conn.CloseWithError(0, "")).To(Succeed()) 980 num0RTT := num0RTTPackets.Load() 981 fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) 982 Expect(num0RTT).ToNot(BeZero()) 983 Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty()) 984 }) 985 })