Skip to content

Commit a16e170

Browse files
return an Err0RTTRejected when the server rejects a 0-RTT connection
1 parent 0ebc7ba commit a16e170

File tree

5 files changed

+169
-4
lines changed

5 files changed

+169
-4
lines changed

integrationtests/self/zero_rtt_test.go

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,22 @@ import (
2121
)
2222

2323
var _ = Describe("0-RTT", func() {
24-
const rtt = 50 * time.Millisecond
24+
rtt := scaleDuration(5 * time.Millisecond)
25+
2526
for _, v := range protocol.SupportedVersions {
2627
version := v
2728

2829
Context(fmt.Sprintf("with QUIC version %s", version), func() {
30+
runDelayProxy := func(serverPort int) *quicproxy.QuicProxy {
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 { return rtt / 2 },
34+
})
35+
Expect(err).ToNot(HaveOccurred())
36+
37+
return proxy
38+
}
39+
2940
runCountingProxy := func(serverPort int) (*quicproxy.QuicProxy, *uint32) {
3041
var num0RTTPackets uint32 // to be used as an atomic
3142
proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
@@ -105,6 +116,34 @@ var _ = Describe("0-RTT", func() {
105116
Eventually(done).Should(BeClosed())
106117
}
107118

119+
check0RTTRejected := func(
120+
ln quic.EarlyListener,
121+
proxyPort int,
122+
clientConf *tls.Config,
123+
) {
124+
sess, err := quic.DialAddrEarly(
125+
fmt.Sprintf("localhost:%d", proxyPort),
126+
clientConf,
127+
getQuicConfig(&quic.Config{Versions: []protocol.VersionNumber{version}}),
128+
)
129+
Expect(err).ToNot(HaveOccurred())
130+
str, err := sess.OpenUniStream()
131+
Expect(err).ToNot(HaveOccurred())
132+
_, err = str.Write(make([]byte, 3000))
133+
Expect(err).ToNot(HaveOccurred())
134+
Expect(str.Close()).To(Succeed())
135+
Expect(sess.ConnectionState().TLS.Used0RTT).To(BeFalse())
136+
137+
// make sure the server doesn't process the data
138+
ctx, cancel := context.WithTimeout(context.Background(), scaleDuration(50*time.Millisecond))
139+
defer cancel()
140+
serverSess, err := ln.Accept(ctx)
141+
Expect(err).ToNot(HaveOccurred())
142+
Expect(serverSess.ConnectionState().TLS.Used0RTT).To(BeFalse())
143+
_, err = serverSess.AcceptUniStream(ctx)
144+
Expect(err).To(Equal(context.DeadlineExceeded))
145+
}
146+
108147
It("transfers 0-RTT data", func() {
109148
ln, err := quic.ListenAddrEarly(
110149
"localhost:0",
@@ -354,7 +393,7 @@ var _ = Describe("0-RTT", func() {
354393
Expect(err).ToNot(HaveOccurred())
355394
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
356395
defer proxy.Close()
357-
transfer0RTTData(ln, proxy.LocalPort(), clientConf, PRData, false)
396+
check0RTTRejected(ln, proxy.LocalPort(), clientConf)
358397

359398
// The client should send 0-RTT packets, but the server doesn't process them.
360399
num0RTT := atomic.LoadUint32(num0RTTPackets)
@@ -374,7 +413,9 @@ var _ = Describe("0-RTT", func() {
374413
)
375414
Expect(err).ToNot(HaveOccurred())
376415

377-
clientConf := dialAndReceiveSessionTicket(ln, ln.Addr().(*net.UDPAddr).Port)
416+
delayProxy := runDelayProxy(ln.Addr().(*net.UDPAddr).Port)
417+
defer delayProxy.Close()
418+
clientConf := dialAndReceiveSessionTicket(ln, delayProxy.LocalPort())
378419

379420
// now close the listener and dial new connection with a different ALPN
380421
Expect(ln.Close()).To(Succeed())
@@ -391,7 +432,91 @@ var _ = Describe("0-RTT", func() {
391432
Expect(err).ToNot(HaveOccurred())
392433
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
393434
defer proxy.Close()
394-
transfer0RTTData(ln, proxy.LocalPort(), clientConf, PRData, false)
435+
436+
check0RTTRejected(ln, proxy.LocalPort(), clientConf)
437+
438+
// The client should send 0-RTT packets, but the server doesn't process them.
439+
num0RTT := atomic.LoadUint32(num0RTTPackets)
440+
fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
441+
Expect(num0RTT).ToNot(BeZero())
442+
})
443+
444+
It("correctly deals with 0-RTT rejections", func() {
445+
tlsConf := getTLSConfig()
446+
ln, err := quic.ListenAddrEarly(
447+
"localhost:0",
448+
tlsConf,
449+
getQuicConfig(&quic.Config{
450+
Versions: []protocol.VersionNumber{version},
451+
MaxIncomingUniStreams: 2,
452+
AcceptToken: func(_ net.Addr, _ *quic.Token) bool { return true },
453+
}),
454+
)
455+
Expect(err).ToNot(HaveOccurred())
456+
457+
delayProxy := runDelayProxy(ln.Addr().(*net.UDPAddr).Port)
458+
defer delayProxy.Close()
459+
clientConf := dialAndReceiveSessionTicket(ln, delayProxy.LocalPort())
460+
// now close the listener and dial new connection with different transport parameters
461+
Expect(ln.Close()).To(Succeed())
462+
ln, err = quic.ListenAddrEarly(
463+
"localhost:0",
464+
tlsConf,
465+
getQuicConfig(&quic.Config{
466+
Versions: []protocol.VersionNumber{version},
467+
MaxIncomingUniStreams: 1,
468+
}),
469+
)
470+
Expect(err).ToNot(HaveOccurred())
471+
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
472+
defer proxy.Close()
473+
474+
done := make(chan struct{})
475+
go func() {
476+
defer GinkgoRecover()
477+
defer close(done)
478+
sess, err := ln.Accept(context.Background())
479+
Expect(err).ToNot(HaveOccurred())
480+
str, err := sess.AcceptUniStream(context.Background())
481+
Expect(err).ToNot(HaveOccurred())
482+
data, err := ioutil.ReadAll(str)
483+
Expect(err).ToNot(HaveOccurred())
484+
Expect(string(data)).To(Equal("second flight"))
485+
}()
486+
487+
sess, err := quic.DialAddrEarly(
488+
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
489+
clientConf,
490+
getQuicConfig(&quic.Config{Versions: []protocol.VersionNumber{version}}),
491+
)
492+
Expect(err).ToNot(HaveOccurred())
493+
// The client remembers that it was allowed to open 2 uni-directional streams.
494+
for i := 0; i < 2; i++ {
495+
str, err := sess.OpenUniStream()
496+
Expect(err).ToNot(HaveOccurred())
497+
go func() {
498+
defer GinkgoRecover()
499+
_, err = str.Write([]byte("first flight"))
500+
Expect(err).ToNot(HaveOccurred())
501+
}()
502+
}
503+
504+
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
505+
defer cancel()
506+
_, err = sess.AcceptStream(ctx)
507+
Expect(err).To(Equal(quic.Err0RTTRejected))
508+
509+
newSess := sess.NextSession()
510+
str, err := newSess.OpenUniStream()
511+
Expect(err).ToNot(HaveOccurred())
512+
_, err = newSess.OpenUniStream()
513+
Expect(err).To(HaveOccurred())
514+
Expect(err.Error()).To(ContainSubstring("too many open streams"))
515+
_, err = str.Write([]byte("second flight"))
516+
Expect(err).ToNot(HaveOccurred())
517+
Expect(str.Close()).To(Succeed())
518+
519+
Eventually(done).Should(BeClosed())
395520

396521
// The client should send 0-RTT packets, but the server doesn't process them.
397522
num0RTT := atomic.LoadUint32(num0RTTPackets)

interface.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ type EarlySession interface {
215215
// Data sent before completion of the handshake is encrypted with 1-RTT keys.
216216
// Note that the client's identity hasn't been verified yet.
217217
HandshakeComplete() context.Context
218+
219+
NextSession() Session
218220
}
219221

220222
// Config contains all configuration data needed for a QUIC server or client.

internal/mocks/quic/early_session.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mock_quic_session_test.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

session.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,10 @@ func (s *session) dropEncryptionLevel(encLevel protocol.EncryptionLevel) {
14581458
if s.tracer != nil {
14591459
s.tracer.DroppedEncryptionLevel(encLevel)
14601460
}
1461+
if encLevel == protocol.Encryption0RTT {
1462+
s.streamsMap.ResetFor0RTT()
1463+
s.connFlowController.Reset()
1464+
}
14611465
}
14621466

14631467
// is called for the client, when restoring transport parameters saved for 0-RTT
@@ -1884,3 +1888,9 @@ func (s *session) getPerspective() protocol.Perspective {
18841888
func (s *session) GetVersion() protocol.VersionNumber {
18851889
return s.version
18861890
}
1891+
1892+
func (s *session) NextSession() Session {
1893+
<-s.HandshakeComplete().Done()
1894+
s.streamsMap.UseResetMaps()
1895+
return s
1896+
}

0 commit comments

Comments
 (0)