github.com/tumi8/quic-go@v0.37.4-tum/integrationtests/self/stateless_reset_test.go (about) 1 package self_test 2 3 import ( 4 "context" 5 "crypto/rand" 6 "fmt" 7 "net" 8 "sync/atomic" 9 "time" 10 11 "github.com/tumi8/quic-go" 12 quicproxy "github.com/tumi8/quic-go/integrationtests/tools/proxy" 13 14 15 . "github.com/onsi/ginkgo/v2" 16 . "github.com/onsi/gomega" 17 ) 18 19 var _ = Describe("Stateless Resets", func() { 20 connIDLens := []int{0, 10} 21 22 for i := range connIDLens { 23 connIDLen := connIDLens[i] 24 25 It(fmt.Sprintf("sends and recognizes stateless resets, for %d byte connection IDs", connIDLen), func() { 26 var statelessResetKey quic.StatelessResetKey 27 rand.Read(statelessResetKey[:]) 28 29 c, err := net.ListenUDP("udp", nil) 30 Expect(err).ToNot(HaveOccurred()) 31 tr := &quic.Transport{ 32 Conn: c, 33 StatelessResetKey: &statelessResetKey, 34 ConnectionIDLength: connIDLen, 35 } 36 defer tr.Close() 37 ln, err := tr.Listen(getTLSConfig(), getQuicConfig(nil)) 38 Expect(err).ToNot(HaveOccurred()) 39 serverPort := ln.Addr().(*net.UDPAddr).Port 40 41 closeServer := make(chan struct{}) 42 43 go func() { 44 defer GinkgoRecover() 45 conn, err := ln.Accept(context.Background()) 46 Expect(err).ToNot(HaveOccurred()) 47 str, err := conn.OpenStream() 48 Expect(err).ToNot(HaveOccurred()) 49 _, err = str.Write([]byte("foobar")) 50 Expect(err).ToNot(HaveOccurred()) 51 <-closeServer 52 Expect(ln.Close()).To(Succeed()) 53 Expect(tr.Close()).To(Succeed()) 54 }() 55 56 var drop atomic.Bool 57 proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 58 RemoteAddr: fmt.Sprintf("localhost:%d", serverPort), 59 DropPacket: func(quicproxy.Direction, []byte) bool { 60 return drop.Load() 61 }, 62 }) 63 Expect(err).ToNot(HaveOccurred()) 64 defer proxy.Close() 65 66 addr, err := net.ResolveUDPAddr("udp", "localhost:0") 67 Expect(err).ToNot(HaveOccurred()) 68 udpConn, err := net.ListenUDP("udp", addr) 69 Expect(err).ToNot(HaveOccurred()) 70 defer udpConn.Close() 71 cl := &quic.Transport{ 72 Conn: udpConn, 73 ConnectionIDLength: connIDLen, 74 } 75 defer cl.Close() 76 conn, err := cl.Dial( 77 context.Background(), 78 &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: proxy.LocalPort()}, 79 getTLSClientConfig(), 80 getQuicConfig(&quic.Config{MaxIdleTimeout: 2 * time.Second}), 81 ) 82 Expect(err).ToNot(HaveOccurred()) 83 str, err := conn.AcceptStream(context.Background()) 84 Expect(err).ToNot(HaveOccurred()) 85 data := make([]byte, 6) 86 _, err = str.Read(data) 87 Expect(err).ToNot(HaveOccurred()) 88 Expect(data).To(Equal([]byte("foobar"))) 89 90 // make sure that the CONNECTION_CLOSE is dropped 91 drop.Store(true) 92 close(closeServer) 93 time.Sleep(100 * time.Millisecond) 94 95 // We need to create a new Transport here, since the old one is still sending out 96 // CONNECTION_CLOSE packets for (recently) closed connections). 97 tr2 := &quic.Transport{ 98 Conn: c, 99 ConnectionIDLength: connIDLen, 100 StatelessResetKey: &statelessResetKey, 101 } 102 defer tr2.Close() 103 ln2, err := tr2.Listen(getTLSConfig(), getQuicConfig(nil)) 104 Expect(err).ToNot(HaveOccurred()) 105 drop.Store(false) 106 107 acceptStopped := make(chan struct{}) 108 go func() { 109 defer GinkgoRecover() 110 _, err := ln2.Accept(context.Background()) 111 Expect(err).To(HaveOccurred()) 112 close(acceptStopped) 113 }() 114 115 // Trigger something (not too small) to be sent, so that we receive the stateless reset. 116 // If the client already sent another packet, it might already have received a packet. 117 _, serr := str.Write([]byte("Lorem ipsum dolor sit amet.")) 118 if serr == nil { 119 _, serr = str.Read([]byte{0}) 120 } 121 Expect(serr).To(HaveOccurred()) 122 Expect(serr).To(BeAssignableToTypeOf(&quic.StatelessResetError{})) 123 Expect(ln2.Close()).To(Succeed()) 124 Eventually(acceptStopped).Should(BeClosed()) 125 }) 126 } 127 })