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  })