github.com/tumi8/quic-go@v0.37.4-tum/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/tumi8/quic-go"
    12  	quicproxy "github.com/tumi8/quic-go/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  		serverConfig.RequireAddressValidation = func(net.Addr) bool { return true }
    59  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
    60  		Expect(err).ToNot(HaveOccurred())
    61  		defer ln.Close()
    62  
    63  		runProxy(ln.Addr())
    64  		startTime := time.Now()
    65  		conn, err := quic.DialAddr(
    66  			context.Background(),
    67  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
    68  			getTLSClientConfig(),
    69  			getQuicConfig(nil),
    70  		)
    71  		Expect(err).ToNot(HaveOccurred())
    72  		defer conn.CloseWithError(0, "")
    73  		expectDurationInRTTs(startTime, 2)
    74  	})
    75  
    76  	It("establishes a connection in 1 RTT when the server doesn't require a token", func() {
    77  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
    78  		Expect(err).ToNot(HaveOccurred())
    79  		defer ln.Close()
    80  
    81  		runProxy(ln.Addr())
    82  		startTime := time.Now()
    83  		conn, err := quic.DialAddr(
    84  			context.Background(),
    85  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
    86  			getTLSClientConfig(),
    87  			getQuicConfig(nil),
    88  		)
    89  		Expect(err).ToNot(HaveOccurred())
    90  		defer conn.CloseWithError(0, "")
    91  		expectDurationInRTTs(startTime, 1)
    92  	})
    93  
    94  	It("establishes a connection in 2 RTTs if a HelloRetryRequest is performed", func() {
    95  		serverTLSConfig.CurvePreferences = []tls.CurveID{tls.CurveP384}
    96  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
    97  		Expect(err).ToNot(HaveOccurred())
    98  		defer ln.Close()
    99  
   100  		runProxy(ln.Addr())
   101  		startTime := time.Now()
   102  		conn, err := quic.DialAddr(
   103  			context.Background(),
   104  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
   105  			getTLSClientConfig(),
   106  			getQuicConfig(nil),
   107  		)
   108  		Expect(err).ToNot(HaveOccurred())
   109  		defer conn.CloseWithError(0, "")
   110  		expectDurationInRTTs(startTime, 2)
   111  	})
   112  
   113  	It("receives the first message from the server after 2 RTTs, when the server uses ListenAddr", func() {
   114  		ln, err := quic.ListenAddr("localhost:0", serverTLSConfig, serverConfig)
   115  		Expect(err).ToNot(HaveOccurred())
   116  		go func() {
   117  			defer GinkgoRecover()
   118  			conn, err := ln.Accept(context.Background())
   119  			Expect(err).ToNot(HaveOccurred())
   120  			str, err := conn.OpenUniStream()
   121  			Expect(err).ToNot(HaveOccurred())
   122  			_, err = str.Write([]byte("foobar"))
   123  			Expect(err).ToNot(HaveOccurred())
   124  			Expect(str.Close()).To(Succeed())
   125  		}()
   126  		defer ln.Close()
   127  
   128  		runProxy(ln.Addr())
   129  		startTime := time.Now()
   130  		conn, err := quic.DialAddr(
   131  			context.Background(),
   132  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
   133  			getTLSClientConfig(),
   134  			getQuicConfig(nil),
   135  		)
   136  		Expect(err).ToNot(HaveOccurred())
   137  		defer conn.CloseWithError(0, "")
   138  		str, err := conn.AcceptUniStream(context.Background())
   139  		Expect(err).ToNot(HaveOccurred())
   140  		data, err := io.ReadAll(str)
   141  		Expect(err).ToNot(HaveOccurred())
   142  		Expect(data).To(Equal([]byte("foobar")))
   143  		expectDurationInRTTs(startTime, 2)
   144  	})
   145  
   146  	It("receives the first message from the server after 1 RTT, when the server uses ListenAddrEarly", func() {
   147  		ln, err := quic.ListenAddrEarly("localhost:0", serverTLSConfig, serverConfig)
   148  		Expect(err).ToNot(HaveOccurred())
   149  		go func() {
   150  			defer GinkgoRecover()
   151  			conn, err := ln.Accept(context.Background())
   152  			Expect(err).ToNot(HaveOccurred())
   153  			// Check the ALPN now. This is probably what an application would do.
   154  			// It makes sure that ConnectionState does not block until the handshake completes.
   155  			Expect(conn.ConnectionState().TLS.NegotiatedProtocol).To(Equal(alpn))
   156  			str, err := conn.OpenUniStream()
   157  			Expect(err).ToNot(HaveOccurred())
   158  			_, err = str.Write([]byte("foobar"))
   159  			Expect(err).ToNot(HaveOccurred())
   160  			Expect(str.Close()).To(Succeed())
   161  		}()
   162  		defer ln.Close()
   163  
   164  		runProxy(ln.Addr())
   165  		startTime := time.Now()
   166  		conn, err := quic.DialAddr(
   167  			context.Background(),
   168  			fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
   169  			getTLSClientConfig(),
   170  			getQuicConfig(nil),
   171  		)
   172  		Expect(err).ToNot(HaveOccurred())
   173  		defer conn.CloseWithError(0, "")
   174  		str, err := conn.AcceptUniStream(context.Background())
   175  		Expect(err).ToNot(HaveOccurred())
   176  		data, err := io.ReadAll(str)
   177  		Expect(err).ToNot(HaveOccurred())
   178  		Expect(data).To(Equal([]byte("foobar")))
   179  		expectDurationInRTTs(startTime, 1)
   180  	})
   181  })