github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/integrationtests/self/handshake_rtt_test.go (about)

     1  package self_test
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"time"
    10  
    11  	"github.com/danielpfeifer02/quic-go-prio-packs"
    12  	quicproxy "github.com/danielpfeifer02/quic-go-prio-packs/integrationtests/tools/proxy"
    13  
    14  	. "github.com/onsi/ginkgo/v2"
    15  	. "github.com/onsi/gomega"
    16  )
    17  
    18  var _ = Describe("Handshake RTT tests", func() {
    19  	var (
    20  		proxy           *quicproxy.QuicProxy
    21  		serverConfig    *quic.Config
    22  		serverTLSConfig *tls.Config
    23  	)
    24  
    25  	const rtt = 400 * time.Millisecond
    26  
    27  	BeforeEach(func() {
    28  		serverConfig = getQuicConfig(nil)
    29  		serverTLSConfig = getTLSConfig()
    30  	})
    31  
    32  	AfterEach(func() {
    33  		Expect(proxy.Close()).To(Succeed())
    34  	})
    35  
    36  	runProxy := func(serverAddr net.Addr) {
    37  		var err error
    38  		// start the proxy
    39  		proxy, err = quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
    40  			RemoteAddr:  serverAddr.String(),
    41  			DelayPacket: func(_ quicproxy.Direction, _ []byte) time.Duration { return rtt / 2 },
    42  		})
    43  		Expect(err).ToNot(HaveOccurred())
    44  	}
    45  
    46  	expectDurationInRTTs := func(startTime time.Time, num int) {
    47  		testDuration := time.Since(startTime)
    48  		rtts := float32(testDuration) / float32(rtt)
    49  		Expect(rtts).To(SatisfyAll(
    50  			BeNumerically(">=", num),
    51  			BeNumerically("<", num+1),
    52  		))
    53  	}
    54  
    55  	// 1 RTT for verifying the source address
    56  	// 1 RTT for the TLS handshake
    57  	It("is forward-secure after 2 RTTs", func() {
    58  		laddr, err := net.ResolveUDPAddr("udp", "localhost:0")
    59  		Expect(err).ToNot(HaveOccurred())
    60  		udpConn, err := net.ListenUDP("udp", laddr)
    61  		Expect(err).ToNot(HaveOccurred())
    62  		defer udpConn.Close()
    63  		tr := &quic.Transport{
    64  			Conn:                     udpConn,
    65  			MaxUnvalidatedHandshakes: -1,
    66  		}
    67  		defer tr.Close()
    68  		ln, err := tr.Listen(serverTLSConfig, serverConfig)
    69  		Expect(err).ToNot(HaveOccurred())
    70  		defer ln.Close()
    71  
    72  		runProxy(ln.Addr())
    73  		startTime := time.Now()
    74  		conn, err := quic.DialAddr(
    75  			context.Background(),
    76  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
    77  			getTLSClientConfig(),
    78  			getQuicConfig(nil),
    79  		)
    80  		Expect(err).ToNot(HaveOccurred())
    81  		defer conn.CloseWithError(0, "")
    82  		expectDurationInRTTs(startTime, 2)
    83  	})
    84  
    85  	It("establishes a connection in 1 RTT when the server doesn't require a token", func() {
    86  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
    87  		Expect(err).ToNot(HaveOccurred())
    88  		defer ln.Close()
    89  
    90  		runProxy(ln.Addr())
    91  		startTime := time.Now()
    92  		conn, err := quic.DialAddr(
    93  			context.Background(),
    94  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
    95  			getTLSClientConfig(),
    96  			getQuicConfig(nil),
    97  		)
    98  		Expect(err).ToNot(HaveOccurred())
    99  		defer conn.CloseWithError(0, "")
   100  		expectDurationInRTTs(startTime, 1)
   101  	})
   102  
   103  	It("establishes a connection in 2 RTTs if a HelloRetryRequest is performed", func() {
   104  		serverTLSConfig.CurvePreferences = []tls.CurveID{tls.CurveP384}
   105  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
   106  		Expect(err).ToNot(HaveOccurred())
   107  		defer ln.Close()
   108  
   109  		runProxy(ln.Addr())
   110  		startTime := time.Now()
   111  		conn, err := quic.DialAddr(
   112  			context.Background(),
   113  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
   114  			getTLSClientConfig(),
   115  			getQuicConfig(nil),
   116  		)
   117  		Expect(err).ToNot(HaveOccurred())
   118  		defer conn.CloseWithError(0, "")
   119  		expectDurationInRTTs(startTime, 2)
   120  	})
   121  
   122  	It("receives the first message from the server after 2 RTTs, when the server uses ListenAddr", func() {
   123  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
   124  		Expect(err).ToNot(HaveOccurred())
   125  		go func() {
   126  			defer GinkgoRecover()
   127  			conn, err := ln.Accept(context.Background())
   128  			Expect(err).ToNot(HaveOccurred())
   129  			str, err := conn.OpenUniStream()
   130  			Expect(err).ToNot(HaveOccurred())
   131  			_, err = str.Write([]byte("foobar"))
   132  			Expect(err).ToNot(HaveOccurred())
   133  			Expect(str.Close()).To(Succeed())
   134  		}()
   135  		defer ln.Close()
   136  
   137  		runProxy(ln.Addr())
   138  		startTime := time.Now()
   139  		conn, err := quic.DialAddr(
   140  			context.Background(),
   141  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
   142  			getTLSClientConfig(),
   143  			getQuicConfig(nil),
   144  		)
   145  		Expect(err).ToNot(HaveOccurred())
   146  		defer conn.CloseWithError(0, "")
   147  		str, err := conn.AcceptUniStream(context.Background())
   148  		Expect(err).ToNot(HaveOccurred())
   149  		data, err := io.ReadAll(str)
   150  		Expect(err).ToNot(HaveOccurred())
   151  		Expect(data).To(Equal([]byte("foobar")))
   152  		expectDurationInRTTs(startTime, 2)
   153  	})
   154  
   155  	It("receives the first message from the server after 1 RTT, when the server uses ListenAddrEarly", func() {
   156  		ln, err := quic.ListenAddrEarly("localhost:0", serverTLSConfig, serverConfig)
   157  		Expect(err).ToNot(HaveOccurred())
   158  		go func() {
   159  			defer GinkgoRecover()
   160  			conn, err := ln.Accept(context.Background())
   161  			Expect(err).ToNot(HaveOccurred())
   162  			// Check the ALPN now. This is probably what an application would do.
   163  			// It makes sure that ConnectionState does not block until the handshake completes.
   164  			Expect(conn.ConnectionState().TLS.NegotiatedProtocol).To(Equal(alpn))
   165  			str, err := conn.OpenUniStream()
   166  			Expect(err).ToNot(HaveOccurred())
   167  			_, err = str.Write([]byte("foobar"))
   168  			Expect(err).ToNot(HaveOccurred())
   169  			Expect(str.Close()).To(Succeed())
   170  		}()
   171  		defer ln.Close()
   172  
   173  		runProxy(ln.Addr())
   174  		startTime := time.Now()
   175  		conn, err := quic.DialAddr(
   176  			context.Background(),
   177  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
   178  			getTLSClientConfig(),
   179  			getQuicConfig(nil),
   180  		)
   181  		Expect(err).ToNot(HaveOccurred())
   182  		defer conn.CloseWithError(0, "")
   183  		str, err := conn.AcceptUniStream(context.Background())
   184  		Expect(err).ToNot(HaveOccurred())
   185  		data, err := io.ReadAll(str)
   186  		Expect(err).ToNot(HaveOccurred())
   187  		Expect(data).To(Equal([]byte("foobar")))
   188  		expectDurationInRTTs(startTime, 1)
   189  	})
   190  })